[
  {
    "path": ".gitignore",
    "content": ".vs/\nobj/\nbin/\npackages/\n_packages/\ntests/\n\n*.obj\n*.log\n*.tlog\n*.VC.db\n*.cache\n*.pdb\n*.pch\n*.user\n\r\n_ReSharper.Caches/\r\n/**/x64-Debug\r\n"
  },
  {
    "path": "ClrPhlib/AssemblyInfo.cpp",
    "content": "using namespace System;\nusing namespace System::Reflection;\nusing namespace System::Runtime::CompilerServices;\nusing namespace System::Runtime::InteropServices;\nusing namespace System::Security::Permissions;\n\n//\n// Les informations générales relatives à un assembly dépendent de\n// l'ensemble d'attributs suivant. Changez les valeurs de ces attributs pour modifier les informations\n// associées à un assembly.\n//\n[assembly:AssemblyTitleAttribute(L\"ClrPhlib\")];\n[assembly:AssemblyDescriptionAttribute(L\"\")];\n[assembly:AssemblyConfigurationAttribute(L\"\")];\n[assembly:AssemblyCompanyAttribute(L\"\")];\n[assembly:AssemblyProductAttribute(L\"ClrPhlib\")];\n[assembly:AssemblyCopyrightAttribute(L\"Copyright (c)  2017\")];\n[assembly:AssemblyTrademarkAttribute(L\"\")];\n[assembly:AssemblyCultureAttribute(L\"\")];\n\n//\n// Les informations de version pour un assembly se composent des quatre valeurs suivantes :\n//\n//      Version principale\n//      Version secondaire\n//      Numéro de build\n//      Révision\n//\n// Vous pouvez spécifier toutes les valeurs ou indiquer les numéros de révision et de build par défaut\n// en utilisant '*', comme indiqué ci-dessous :\n\n[assembly:AssemblyVersionAttribute(\"1.10.*\")];\n\n[assembly:ComVisible(false)];\n\n[assembly:CLSCompliantAttribute(true)];"
  },
  {
    "path": "ClrPhlib/ClrPhlib.cpp",
    "content": "#include <ClrPhlib.h>\r\n\r\nusing namespace Dependencies;\r\n\r\nClrPh::CLRPH_ARCH ClrPh::Phlib::GetClrPhArch()\r\n{\r\n#if _WIN64\r\n\treturn ClrPh::CLRPH_ARCH::x64;\r\n#else\r\n\tif (PhIsExecutingInWow64())\r\n\t\treturn ClrPh::CLRPH_ARCH::WOW64;\r\n\t\r\n\treturn ClrPh::CLRPH_ARCH::x86;\r\n#endif // _WIN64\r\n}"
  },
  {
    "path": "ClrPhlib/ClrPhlib.manifest",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?>\n<assembly xmlns=\"urn:schemas-microsoft-com:asm.v1\" manifestVersion=\"1.0\">\n  <assemblyIdentity\n    name=\"ClrPhLib\"\n    processorArchitecture=\"*\"\n    version=\"1.7.0.0\"\n    type=\"win32\"\n  />\n  <description>CLR Process Hacker library</description>\n  <dependency>\n    <dependentAssembly>\n      <assemblyIdentity\n        type=\"win32\"\n        name=\"Microsoft.Windows.Common-Controls\"\n        version=\"6.0.0.0\"\n        processorArchitecture=\"*\"\n        publicKeyToken=\"6595b64144ccf1df\"\n        language=\"*\"\n      />\n    </dependentAssembly>\n  </dependency>\n  <trustInfo xmlns=\"urn:schemas-microsoft-com:asm.v3\">\n    <security>\n      <requestedPrivileges>\n        <requestedExecutionLevel level=\"asInvoker\" uiAccess=\"false\"/>\n      </requestedPrivileges>\n    </security>\n  </trustInfo>\n  <compatibility xmlns=\"urn:schemas-microsoft-com:compatibility.v1\">\n    <application>\n      <supportedOS Id=\"{e2011457-1546-43c5-a5fe-008deee3d3f0}\"/>\n      <supportedOS Id=\"{35138b9a-5d96-4fbd-8e2d-a2440225f93a}\"/>\n      <supportedOS Id=\"{4a2f28e3-53b9-4441-ba9c-d69d4a4a6e38}\"/>\n      <supportedOS Id=\"{1f676c76-80e1-4239-95bb-83d0f6d0da78}\"/>\n      <supportedOS Id=\"{8e0f7a12-bfb3-4fe8-b9a5-48fd50a15a9a}\"/>\n    </application>\n  </compatibility>\n  <asmv3:application xmlns:asmv3=\"urn:schemas-microsoft-com:asm.v3\">\n    <asmv3:windowsSettings xmlns=\"http://schemas.microsoft.com/SMI/2005/WindowsSettings\">\n      <dpiAware>true</dpiAware>\n    </asmv3:windowsSettings>\n    <asmv3:windowsSettings xmlns=\"http://schemas.microsoft.com/SMI/2016/WindowsSettings\">\n      <longPathAware>true</longPathAware>\n    </asmv3:windowsSettings>\n  </asmv3:application>\n</assembly>"
  },
  {
    "path": "ClrPhlib/ClrPhlib.vcxproj",
    "content": "﻿<?xml version=\"1.0\" encoding=\"utf-8\"?>\r\n<Project DefaultTargets=\"Build\" ToolsVersion=\"14.0\" xmlns=\"http://schemas.microsoft.com/developer/msbuild/2003\">\r\n  <ItemGroup Label=\"ProjectConfigurations\">\r\n    <ProjectConfiguration Include=\"Appx|Win32\">\r\n      <Configuration>Appx</Configuration>\r\n      <Platform>Win32</Platform>\r\n    </ProjectConfiguration>\r\n    <ProjectConfiguration Include=\"Appx|x64\">\r\n      <Configuration>Appx</Configuration>\r\n      <Platform>x64</Platform>\r\n    </ProjectConfiguration>\r\n    <ProjectConfiguration Include=\"Debug|Win32\">\r\n      <Configuration>Debug</Configuration>\r\n      <Platform>Win32</Platform>\r\n    </ProjectConfiguration>\r\n    <ProjectConfiguration Include=\"Release|Win32\">\r\n      <Configuration>Release</Configuration>\r\n      <Platform>Win32</Platform>\r\n    </ProjectConfiguration>\r\n    <ProjectConfiguration Include=\"Debug|x64\">\r\n      <Configuration>Debug</Configuration>\r\n      <Platform>x64</Platform>\r\n    </ProjectConfiguration>\r\n    <ProjectConfiguration Include=\"Release|x64\">\r\n      <Configuration>Release</Configuration>\r\n      <Platform>x64</Platform>\r\n    </ProjectConfiguration>\r\n  </ItemGroup>\r\n  <PropertyGroup Label=\"Globals\">\r\n    <ProjectGuid>{FC5FFCAF-982F-4A95-8FA6-2A95B1F7CDC8}</ProjectGuid>\r\n    <TargetFrameworkVersion>v4.6.1</TargetFrameworkVersion>\r\n    <Keyword>ManagedCProj</Keyword>\r\n    <RootNamespace>ClrPhlib</RootNamespace>\r\n    <WindowsTargetPlatformVersion>10.0</WindowsTargetPlatformVersion>\r\n  </PropertyGroup>\r\n  <Import Project=\"$(VCTargetsPath)\\Microsoft.Cpp.Default.props\" />\r\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Debug|Win32'\" Label=\"Configuration\">\r\n    <ConfigurationType>DynamicLibrary</ConfigurationType>\r\n    <UseDebugLibraries>true</UseDebugLibraries>\r\n    <PlatformToolset>v142</PlatformToolset>\r\n    <CLRSupport>true</CLRSupport>\r\n    <CharacterSet>Unicode</CharacterSet>\r\n    <SpectreMitigation>false</SpectreMitigation>\r\n  </PropertyGroup>\r\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Release|Win32'\" Label=\"Configuration\">\r\n    <ConfigurationType>DynamicLibrary</ConfigurationType>\r\n    <UseDebugLibraries>false</UseDebugLibraries>\r\n    <PlatformToolset>v142</PlatformToolset>\r\n    <CLRSupport>true</CLRSupport>\r\n    <CharacterSet>Unicode</CharacterSet>\r\n    <SpectreMitigation>false</SpectreMitigation>\r\n  </PropertyGroup>\r\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Appx|Win32'\" Label=\"Configuration\">\r\n    <ConfigurationType>DynamicLibrary</ConfigurationType>\r\n    <UseDebugLibraries>false</UseDebugLibraries>\r\n    <PlatformToolset>v142</PlatformToolset>\r\n    <CLRSupport>true</CLRSupport>\r\n    <CharacterSet>Unicode</CharacterSet>\r\n    <SpectreMitigation>false</SpectreMitigation>\r\n  </PropertyGroup>\r\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\" Label=\"Configuration\">\r\n    <ConfigurationType>DynamicLibrary</ConfigurationType>\r\n    <UseDebugLibraries>true</UseDebugLibraries>\r\n    <PlatformToolset>v142</PlatformToolset>\r\n    <CLRSupport>true</CLRSupport>\r\n    <CharacterSet>Unicode</CharacterSet>\r\n    <SpectreMitigation>false</SpectreMitigation>\r\n  </PropertyGroup>\r\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\" Label=\"Configuration\">\r\n    <ConfigurationType>DynamicLibrary</ConfigurationType>\r\n    <UseDebugLibraries>false</UseDebugLibraries>\r\n    <PlatformToolset>v142</PlatformToolset>\r\n    <CLRSupport>true</CLRSupport>\r\n    <CharacterSet>Unicode</CharacterSet>\r\n    <SpectreMitigation>false</SpectreMitigation>\r\n  </PropertyGroup>\r\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Appx|x64'\" Label=\"Configuration\">\r\n    <ConfigurationType>DynamicLibrary</ConfigurationType>\r\n    <UseDebugLibraries>false</UseDebugLibraries>\r\n    <PlatformToolset>v142</PlatformToolset>\r\n    <CLRSupport>true</CLRSupport>\r\n    <CharacterSet>Unicode</CharacterSet>\r\n    <SpectreMitigation>false</SpectreMitigation>\r\n  </PropertyGroup>\r\n  <Import Project=\"$(VCTargetsPath)\\Microsoft.Cpp.props\" />\r\n  <ImportGroup Label=\"ExtensionSettings\">\r\n  </ImportGroup>\r\n  <ImportGroup Label=\"Shared\">\r\n  </ImportGroup>\r\n  <ImportGroup Label=\"PropertySheets\" Condition=\"'$(Configuration)|$(Platform)'=='Debug|Win32'\">\r\n    <Import Project=\"$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props\" Condition=\"exists('$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props')\" Label=\"LocalAppDataPlatform\" />\r\n  </ImportGroup>\r\n  <ImportGroup Label=\"PropertySheets\" Condition=\"'$(Configuration)|$(Platform)'=='Release|Win32'\">\r\n    <Import Project=\"$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props\" Condition=\"exists('$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props')\" Label=\"LocalAppDataPlatform\" />\r\n  </ImportGroup>\r\n  <ImportGroup Condition=\"'$(Configuration)|$(Platform)'=='Appx|Win32'\" Label=\"PropertySheets\">\r\n    <Import Project=\"$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props\" Condition=\"exists('$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props')\" Label=\"LocalAppDataPlatform\" />\r\n  </ImportGroup>\r\n  <ImportGroup Label=\"PropertySheets\" Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">\r\n    <Import Project=\"$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props\" Condition=\"exists('$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props')\" Label=\"LocalAppDataPlatform\" />\r\n  </ImportGroup>\r\n  <ImportGroup Label=\"PropertySheets\" Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\">\r\n    <Import Project=\"$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props\" Condition=\"exists('$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props')\" Label=\"LocalAppDataPlatform\" />\r\n  </ImportGroup>\r\n  <ImportGroup Condition=\"'$(Configuration)|$(Platform)'=='Appx|x64'\" Label=\"PropertySheets\">\r\n    <Import Project=\"$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props\" Condition=\"exists('$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props')\" Label=\"LocalAppDataPlatform\" />\r\n  </ImportGroup>\r\n  <PropertyGroup Label=\"UserMacros\" />\r\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Debug|Win32'\">\r\n    <LinkIncremental>true</LinkIncremental>\r\n    <OutDir>$(SolutionDir)bin\\$(Configuration)$(PlatformArchitecture)\\</OutDir>\r\n    <IntDir>$(SolutionDir)obj\\$(ProjectName)\\$(Configuration)$(PlatformArchitecture)\\</IntDir>\r\n  </PropertyGroup>\r\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">\r\n    <LinkIncremental>true</LinkIncremental>\r\n    <OutDir>$(SolutionDir)bin\\$(Configuration)$(PlatformArchitecture)\\</OutDir>\r\n    <IntDir>$(SolutionDir)obj\\$(ProjectName)\\$(Configuration)$(PlatformArchitecture)\\</IntDir>\r\n  </PropertyGroup>\r\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Release|Win32'\">\r\n    <LinkIncremental>false</LinkIncremental>\r\n    <OutDir>$(SolutionDir)bin\\$(Configuration)$(PlatformArchitecture)\\</OutDir>\r\n    <IntDir>$(SolutionDir)obj\\$(ProjectName)\\$(Configuration)$(PlatformArchitecture)\\</IntDir>\r\n  </PropertyGroup>\r\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Appx|Win32'\">\r\n    <LinkIncremental>false</LinkIncremental>\r\n    <OutDir>$(SolutionDir)bin\\$(Configuration)$(PlatformArchitecture)\\</OutDir>\r\n    <IntDir>$(SolutionDir)obj\\$(ProjectName)\\$(Configuration)$(PlatformArchitecture)\\</IntDir>\r\n  </PropertyGroup>\r\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\">\r\n    <LinkIncremental>false</LinkIncremental>\r\n    <OutDir>$(SolutionDir)bin\\$(Configuration)$(PlatformArchitecture)\\</OutDir>\r\n    <IntDir>$(SolutionDir)obj\\$(ProjectName)\\$(Configuration)$(PlatformArchitecture)\\</IntDir>\r\n  </PropertyGroup>\r\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Appx|x64'\">\r\n    <LinkIncremental>false</LinkIncremental>\r\n    <OutDir>$(SolutionDir)bin\\$(Configuration)$(PlatformArchitecture)\\</OutDir>\r\n    <IntDir>$(SolutionDir)obj\\$(ProjectName)\\$(Configuration)$(PlatformArchitecture)\\</IntDir>\r\n  </PropertyGroup>\r\n  <ItemDefinitionGroup Condition=\"'$(Configuration)|$(Platform)'=='Debug|Win32'\">\r\n    <ClCompile>\r\n      <WarningLevel>Level3</WarningLevel>\r\n      <Optimization>Disabled</Optimization>\r\n      <PreprocessorDefinitions>WIN32;_DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>\r\n      <PrecompiledHeader>NotUsing</PrecompiledHeader>\r\n      <AdditionalIncludeDirectories>$(SolutionDir)third_party\\phnt\\include;$(SolutionDir)third_party\\phlib\\include;$(ProjectDir)include;$(SolutionDir)third_party\\llvm-demangle\\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>\r\n      <RuntimeLibrary>MultiThreadedDebugDLL</RuntimeLibrary>\r\n      <PrecompiledHeaderFile />\r\n      <TreatWarningAsError>true</TreatWarningAsError>\r\n    </ClCompile>\r\n    <Link>\r\n      <AdditionalDependencies>$(OutputPath)\\phlib.lib;$(OutputPath)\\demumble.lib;$(OutputPath)\\llvm-demangle.lib;bcrypt.lib;%(AdditionalDependencies)</AdditionalDependencies>\r\n      <GenerateDebugInformation>DebugFull</GenerateDebugInformation>\r\n      <CLRImageType>Default</CLRImageType>\r\n    </Link>\r\n  </ItemDefinitionGroup>\r\n  <ItemDefinitionGroup Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">\r\n    <ClCompile>\r\n      <WarningLevel>Level3</WarningLevel>\r\n      <Optimization>Disabled</Optimization>\r\n      <PreprocessorDefinitions>_DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>\r\n      <PrecompiledHeader>NotUsing</PrecompiledHeader>\r\n      <AdditionalIncludeDirectories>$(SolutionDir)third_party\\phnt\\include;$(SolutionDir)third_party\\phlib\\include;$(ProjectDir)include;$(SolutionDir)third_party\\llvm-demangle\\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>\r\n      <RuntimeLibrary>MultiThreadedDebugDLL</RuntimeLibrary>\r\n      <BasicRuntimeChecks>Default</BasicRuntimeChecks>\r\n      <PrecompiledHeaderFile />\r\n      <TreatWarningAsError>true</TreatWarningAsError>\r\n    </ClCompile>\r\n    <Link>\r\n      <AdditionalDependencies>$(OutputPath)\\phlib.lib;$(OutputPath)\\demumble.lib;$(OutputPath)\\llvm-demangle.lib;bcrypt.lib;%(AdditionalDependencies)</AdditionalDependencies>\r\n      <GenerateDebugInformation>DebugFull</GenerateDebugInformation>\r\n      <CLRImageType>Default</CLRImageType>\r\n    </Link>\r\n  </ItemDefinitionGroup>\r\n  <ItemDefinitionGroup Condition=\"'$(Configuration)|$(Platform)'=='Release|Win32'\">\r\n    <ClCompile>\r\n      <WarningLevel>Level3</WarningLevel>\r\n      <PreprocessorDefinitions>WIN32;NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>\r\n      <PrecompiledHeader>NotUsing</PrecompiledHeader>\r\n      <AdditionalIncludeDirectories>$(SolutionDir)third_party\\phnt\\include;$(SolutionDir)third_party\\phlib\\include;$(ProjectDir)include;$(SolutionDir)third_party\\llvm-demangle\\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>\r\n      <RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary>\r\n      <PrecompiledHeaderFile />\r\n      <TreatWarningAsError>true</TreatWarningAsError>\r\n    </ClCompile>\r\n    <Link>\r\n      <AdditionalDependencies>$(OutputPath)\\phlib.lib;$(OutputPath)\\demumble.lib;$(OutputPath)\\llvm-demangle.lib;bcrypt.lib;%(AdditionalDependencies)</AdditionalDependencies>\r\n      <CLRImageType>Default</CLRImageType>\r\n    </Link>\r\n  </ItemDefinitionGroup>\r\n  <ItemDefinitionGroup Condition=\"'$(Configuration)|$(Platform)'=='Appx|Win32'\">\r\n    <ClCompile>\r\n      <WarningLevel>Level3</WarningLevel>\r\n      <PreprocessorDefinitions>WIN32;NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>\r\n      <PrecompiledHeader>NotUsing</PrecompiledHeader>\r\n      <AdditionalIncludeDirectories>$(SolutionDir)third_party\\phnt\\include;$(SolutionDir)third_party\\phlib\\include;$(ProjectDir)include;$(SolutionDir)third_party\\llvm-demangle\\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>\r\n      <RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary>\r\n      <PrecompiledHeaderFile>\r\n      </PrecompiledHeaderFile>\r\n      <TreatWarningAsError>true</TreatWarningAsError>\r\n    </ClCompile>\r\n    <Link>\r\n      <AdditionalDependencies>$(OutputPath)\\phlib.lib;$(OutputPath)\\demumble.lib;$(OutputPath)\\llvm-demangle.lib;bcrypt.lib;%(AdditionalDependencies)</AdditionalDependencies>\r\n      <CLRImageType>Default</CLRImageType>\r\n    </Link>\r\n  </ItemDefinitionGroup>\r\n  <ItemDefinitionGroup Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\">\r\n    <ClCompile>\r\n      <WarningLevel>Level3</WarningLevel>\r\n      <PreprocessorDefinitions>NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>\r\n      <PrecompiledHeader>NotUsing</PrecompiledHeader>\r\n      <AdditionalIncludeDirectories>$(SolutionDir)third_party\\phnt\\include;$(SolutionDir)third_party\\phlib\\include;$(ProjectDir)include;$(SolutionDir)third_party\\llvm-demangle\\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>\r\n      <RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary>\r\n      <PrecompiledHeaderFile />\r\n      <TreatWarningAsError>true</TreatWarningAsError>\r\n    </ClCompile>\r\n    <Link>\r\n      <AdditionalDependencies>$(OutputPath)\\phlib.lib;$(OutputPath)\\demumble.lib;$(OutputPath)\\llvm-demangle.lib;bcrypt.lib;%(AdditionalDependencies)</AdditionalDependencies>\r\n      <CLRImageType>Default</CLRImageType>\r\n    </Link>\r\n  </ItemDefinitionGroup>\r\n  <ItemDefinitionGroup Condition=\"'$(Configuration)|$(Platform)'=='Appx|x64'\">\r\n    <ClCompile>\r\n      <WarningLevel>Level3</WarningLevel>\r\n      <PreprocessorDefinitions>NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>\r\n      <PrecompiledHeader>NotUsing</PrecompiledHeader>\r\n      <AdditionalIncludeDirectories>$(SolutionDir)third_party\\phnt\\include;$(SolutionDir)third_party\\phlib\\include;$(ProjectDir)include;$(SolutionDir)third_party\\llvm-demangle\\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>\r\n      <RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary>\r\n      <PrecompiledHeaderFile>\r\n      </PrecompiledHeaderFile>\r\n      <TreatWarningAsError>true</TreatWarningAsError>\r\n    </ClCompile>\r\n    <Link>\r\n      <AdditionalDependencies>$(OutputPath)\\phlib.lib;$(OutputPath)\\demumble.lib;$(OutputPath)\\llvm-demangle.lib;bcrypt.lib;%(AdditionalDependencies)</AdditionalDependencies>\r\n      <CLRImageType>Default</CLRImageType>\r\n    </Link>\r\n  </ItemDefinitionGroup>\r\n  <ItemGroup>\r\n    <Reference Include=\"System\" />\r\n    <Reference Include=\"System.Data\" />\r\n    <Reference Include=\"System.Xml\" />\r\n  </ItemGroup>\r\n  <ItemGroup>\r\n    <ClInclude Include=\"include\\ApiSet.h\" />\r\n    <ClInclude Include=\"include\\ClrPhlib.h\" />\r\n    <ClInclude Include=\"include\\ClrPhSymbolProvider.h\" />\r\n    <ClInclude Include=\"include\\NativeFile.h\" />\r\n    <ClInclude Include=\"include\\UnmanagedPh.h\" />\r\n    <ClInclude Include=\"include\\UnmanagedSymPrv.h\" />\r\n    <ClInclude Include=\"resource.h\" />\r\n  </ItemGroup>\r\n  <ItemGroup>\r\n    <ClCompile Include=\"AssemblyInfo.cpp\" />\r\n    <ClCompile Include=\"ClrPhlib.cpp\" />\r\n    <ClCompile Include=\"src\\managed\\NativeFile.cpp\" />\r\n    <ClCompile Include=\"src\\managed\\PE.cpp\" />\r\n    <ClCompile Include=\"src\\managed\\PeExport.cpp\" />\r\n    <ClCompile Include=\"src\\managed\\PeImport.cpp\" />\r\n    <ClCompile Include=\"src\\managed\\Phlib.cpp\" />\r\n    <ClCompile Include=\"src\\managed\\PhSymbolProvider.cpp\" />\r\n    <ClCompile Include=\"src\\unmanaged\\demangle.cpp\" />\r\n    <ClCompile Include=\"src\\unmanaged\\UnmanagedPE.cpp\" />\r\n    <ClCompile Include=\"src\\unmanaged\\UnmanagedSymPrv.cpp\" />\r\n  </ItemGroup>\r\n  <ItemGroup>\r\n    <Text Include=\"ReadMe.txt\" />\r\n  </ItemGroup>\r\n  <ItemGroup>\r\n    <ResourceCompile Include=\"app.rc\" />\r\n  </ItemGroup>\r\n  <ItemGroup>\r\n    <Image Include=\"app.ico\" />\r\n  </ItemGroup>\r\n  <ItemGroup>\r\n    <Manifest Include=\"ClrPhlib.manifest\" />\r\n  </ItemGroup>\r\n  <Import Project=\"$(VCTargetsPath)\\Microsoft.Cpp.targets\" />\r\n  <ImportGroup Label=\"ExtensionTargets\">\r\n  </ImportGroup>\r\n</Project>"
  },
  {
    "path": "ClrPhlib/ClrPhlib.vcxproj.filters",
    "content": "﻿<?xml version=\"1.0\" encoding=\"utf-8\"?>\r\n<Project ToolsVersion=\"4.0\" xmlns=\"http://schemas.microsoft.com/developer/msbuild/2003\">\r\n  <ItemGroup>\r\n    <Filter Include=\"Fichiers sources\">\r\n      <UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier>\r\n      <Extensions>cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx</Extensions>\r\n    </Filter>\r\n    <Filter Include=\"Fichiers d%27en-tête\">\r\n      <UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier>\r\n      <Extensions>h;hh;hpp;hxx;hm;inl;inc;xsd</Extensions>\r\n    </Filter>\r\n    <Filter Include=\"Fichiers de ressources\">\r\n      <UniqueIdentifier>{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}</UniqueIdentifier>\r\n      <Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms</Extensions>\r\n    </Filter>\r\n    <Filter Include=\"Fichiers sources\\Managed\">\r\n      <UniqueIdentifier>{e9536ddc-3c30-4ef3-99fa-0e7f44736ebb}</UniqueIdentifier>\r\n    </Filter>\r\n    <Filter Include=\"Fichiers sources\\Unmanaged\">\r\n      <UniqueIdentifier>{e79a5a25-1203-4753-8c5a-644629cfac1a}</UniqueIdentifier>\r\n    </Filter>\r\n  </ItemGroup>\r\n  <ItemGroup>\r\n    <ClInclude Include=\"resource.h\">\r\n      <Filter>Fichiers d%27en-tête</Filter>\r\n    </ClInclude>\r\n    <ClInclude Include=\"include\\ClrPhlib.h\">\r\n      <Filter>Fichiers d%27en-tête</Filter>\r\n    </ClInclude>\r\n    <ClInclude Include=\"include\\UnmanagedPh.h\">\r\n      <Filter>Fichiers d%27en-tête</Filter>\r\n    </ClInclude>\r\n    <ClInclude Include=\"include\\ApiSet.h\">\r\n      <Filter>Fichiers d%27en-tête</Filter>\r\n    </ClInclude>\r\n    <ClInclude Include=\"include\\NativeFile.h\">\r\n      <Filter>Fichiers d%27en-tête</Filter>\r\n    </ClInclude>\r\n    <ClInclude Include=\"include\\UnmanagedSymPrv.h\">\r\n      <Filter>Fichiers d%27en-tête</Filter>\r\n    </ClInclude>\r\n    <ClInclude Include=\"include\\ClrPhSymbolProvider.h\">\r\n      <Filter>Fichiers d%27en-tête</Filter>\r\n    </ClInclude>\r\n  </ItemGroup>\r\n  <ItemGroup>\r\n    <ClCompile Include=\"ClrPhlib.cpp\">\r\n      <Filter>Fichiers sources</Filter>\r\n    </ClCompile>\r\n    <ClCompile Include=\"AssemblyInfo.cpp\">\r\n      <Filter>Fichiers sources</Filter>\r\n    </ClCompile>\r\n    <ClCompile Include=\"src\\unmanaged\\UnmanagedPE.cpp\">\r\n      <Filter>Fichiers sources\\Unmanaged</Filter>\r\n    </ClCompile>\r\n    <ClCompile Include=\"src\\unmanaged\\UnmanagedSymPrv.cpp\">\r\n      <Filter>Fichiers sources\\Unmanaged</Filter>\r\n    </ClCompile>\r\n    <ClCompile Include=\"src\\managed\\PE.cpp\">\r\n      <Filter>Fichiers sources\\Managed</Filter>\r\n    </ClCompile>\r\n    <ClCompile Include=\"src\\managed\\PeExport.cpp\">\r\n      <Filter>Fichiers sources\\Managed</Filter>\r\n    </ClCompile>\r\n    <ClCompile Include=\"src\\managed\\PeImport.cpp\">\r\n      <Filter>Fichiers sources\\Managed</Filter>\r\n    </ClCompile>\r\n    <ClCompile Include=\"src\\managed\\Phlib.cpp\">\r\n      <Filter>Fichiers sources\\Managed</Filter>\r\n    </ClCompile>\r\n    <ClCompile Include=\"src\\managed\\PhSymbolProvider.cpp\">\r\n      <Filter>Fichiers sources\\Managed</Filter>\r\n    </ClCompile>\r\n    <ClCompile Include=\"src\\managed\\NativeFile.cpp\">\r\n      <Filter>Fichiers sources\\Managed</Filter>\r\n    </ClCompile>\r\n    <ClCompile Include=\"src\\unmanaged\\demangle.cpp\">\r\n      <Filter>Fichiers sources\\Unmanaged</Filter>\r\n    </ClCompile>\r\n  </ItemGroup>\r\n  <ItemGroup>\r\n    <Text Include=\"ReadMe.txt\" />\r\n  </ItemGroup>\r\n  <ItemGroup>\r\n    <ResourceCompile Include=\"app.rc\">\r\n      <Filter>Fichiers de ressources</Filter>\r\n    </ResourceCompile>\r\n  </ItemGroup>\r\n  <ItemGroup>\r\n    <Image Include=\"app.ico\">\r\n      <Filter>Fichiers de ressources</Filter>\r\n    </Image>\r\n  </ItemGroup>\r\n  <ItemGroup>\r\n    <Manifest Include=\"ClrPhlib.manifest\" />\r\n  </ItemGroup>\r\n</Project>"
  },
  {
    "path": "ClrPhlib/include/ApiSet.h",
    "content": "#pragma once\r\n#include <ph.h>\r\n\r\n#ifdef __cplusplus\r\nextern \"C\" {\r\n#endif\r\n\r\n///////////////////////////////////////////////////////////////////////////////\r\n// ApiSet v2\r\n\r\ntypedef struct _API_SET_VALUE_ENTRY_REDIRECTION_V2 {\r\n\tULONG  NameOffset;\r\n\tUSHORT NameLength;\r\n\tULONG  ValueOffset;\r\n\tUSHORT ValueLength;\r\n} API_SET_VALUE_ENTRY_REDIRECTION_V2, *PAPI_SET_VALUE_ENTRY_REDIRECTION_V2;\r\n\r\ntypedef struct _API_SET_VALUE_ENTRY_V2 {\r\n\tULONG NumberOfRedirections;\r\n\tAPI_SET_VALUE_ENTRY_REDIRECTION_V2 Redirections[ANYSIZE_ARRAY];\r\n} API_SET_VALUE_ENTRY_V2, *PAPI_SET_VALUE_ENTRY_V2;\r\n\r\ntypedef struct _API_SET_NAMESPACE_ENTRY_V2 {\r\n\tULONG NameOffset;\r\n\tULONG NameLength;\r\n\tULONG DataOffset; // ===> _API_SET_VALUE_ENTRY_V2\r\n} API_SET_NAMESPACE_ENTRY_V2, *PAPI_SET_NAMESPACE_ENTRY_V2;\r\n\r\ntypedef struct _API_SET_NAMESPACE_V2 { \r\n\tULONG Version; \r\n\tULONG Count; \r\n\tAPI_SET_NAMESPACE_ENTRY_V2 Array[ANYSIZE_ARRAY]; \r\n} API_SET_NAMESPACE_V2, *PAPI_SET_NAMESPACE_V2;\r\n\r\n///////////////////////////////////////////////////////////////////////////////\r\n// ApiSet v4\r\n\r\ntypedef struct _API_SET_VALUE_ENTRY_REDIRECTION_V4 {\r\n\tULONG Flags;\r\n\tULONG NameOffset;\r\n\tULONG NameLength;\r\n\tULONG ValueOffset;\r\n\tULONG ValueLength;\r\n} API_SET_VALUE_ENTRY_REDIRECTION_V4, *PAPI_SET_VALUE_ENTRY_REDIRECTION_V4;\r\n\r\ntypedef struct _API_SET_VALUE_ENTRY_V4 {\r\n\tULONG Flags;\r\n\tULONG NumberOfRedirections;\r\n\tAPI_SET_VALUE_ENTRY_REDIRECTION_V4 Redirections[ANYSIZE_ARRAY];\r\n} API_SET_VALUE_ENTRY_V4, *PAPI_SET_VALUE_ENTRY_V4;\r\n\r\ntypedef struct _API_SET_NAMESPACE_ENTRY_V4 {\r\n\tULONG Flags;\r\n\tULONG NameOffset;\r\n\tULONG NameLength;\r\n\tULONG AliasOffset;\r\n\tULONG AliasLength;\r\n\tULONG DataOffset; // ===> _API_SET_VALUE_ENTRY_V4\r\n} API_SET_NAMESPACE_ENTRY_V4, *PAPI_SET_NAMESPACE_ENTRY_V4;\r\n\r\ntypedef struct _API_SET_NAMESPACE_V4 { \r\n\tULONG Version; \r\n\tULONG Size; \r\n\tULONG Flags; \r\n\tULONG Count; \r\n\tAPI_SET_NAMESPACE_ENTRY_V4 Array[ANYSIZE_ARRAY];\r\n} API_SET_NAMESPACE_V4, *PAPI_SET_NAMESPACE_V4;\r\n\r\n///////////////////////////////////////////////////////////////////////////////\r\n// ApiSet v6\r\n\r\ntypedef struct _API_SET_HASH_ENTRY_V6 {\r\n\tULONG Hash;\r\n\tULONG Index;\r\n} API_SET_HASH_ENTRY_V6, *PAPI_SET_HASH_ENTRY_V6;\r\n\r\ntypedef struct _API_SET_NAMESPACE_ENTRY_V6 {\r\n\tULONG Flags;\r\n\tULONG NameOffset;\r\n\tULONG NameLength;\r\n\tULONG HashedLength;\r\n\tULONG ValueOffset;\r\n\tULONG ValueCount;\r\n} API_SET_NAMESPACE_ENTRY_V6, *PAPI_SET_NAMESPACE_ENTRY_V6;\r\n\r\ntypedef struct _API_SET_VALUE_ENTRY_V6 {\r\n\tULONG Flags;\r\n\tULONG NameOffset;\r\n\tULONG NameLength;\r\n\tULONG ValueOffset;\r\n\tULONG ValueLength;\r\n} API_SET_VALUE_ENTRY_V6, *PAPI_SET_VALUE_ENTRY_V6;\r\n\r\ntypedef struct _API_SET_NAMESPACE_V6 {\r\n\tULONG Version;\r\n\tULONG Size;\r\n\tULONG Flags;\r\n\tULONG Count;\r\n\tULONG EntryOffset;\r\n\tULONG HashOffset;\r\n\tULONG HashFactor;\r\n} API_SET_NAMESPACE_V6, *PAPI_SET_NAMESPACE_V6;\r\n\r\n///////////////////////////////////////////////////////////////////////////////\r\n\r\ntypedef struct _API_SET_NAMESPACE {\r\n\tunion\r\n\t{\r\n \t\tULONG Version;\r\n\t\tAPI_SET_NAMESPACE_V2 ApiSetNameSpaceV2;\r\n\t\tAPI_SET_NAMESPACE_V4 ApiSetNameSpaceV4;\r\n\t\tAPI_SET_NAMESPACE_V6 ApiSetNameSpaceV6;\r\n\t};\r\n} API_SET_NAMESPACE, *PAPI_SET_NAMESPACE;\r\n\r\n\r\n#ifdef __cplusplus\r\n}\r\n#endif"
  },
  {
    "path": "ClrPhlib/include/ClrPhSymbolProvider.h",
    "content": "#pragma once\n\n#include <ClrPhlib.h>\n#include <UnmanagedSymPrv.h>\n\nusing namespace Dependencies::ClrPh;\n\n// Symbol resolution and undecoration utility class\npublic ref class PhSymbolProvider\n{\npublic:\n    PhSymbolProvider();\n    ~PhSymbolProvider();\n    !PhSymbolProvider();\n\n    virtual Tuple<CLRPH_DEMANGLER, String^>^ UndecorateName(_In_ String ^DecoratedName);\n\nprotected:\n\n\tString^ UndecorateNameDemumble(_In_ String ^DecoratedName);\n\tString^ UndecorateNameLLVMItanium(_In_ String ^DecoratedName);\n\tString^ UndecorateNameLLVMMicrosoft(_In_ String ^DecoratedName);\n\tString^ UndecorateNamePh(_In_ String ^DecoratedName);\n\n\nprivate:\n\tString ^ UndecorateNamePrv(_In_ String ^DecoratedName, _In_ DemangleNameFn Demangler);\n\n    UnmanagedSymPrv *m_Impl;\n\n};"
  },
  {
    "path": "ClrPhlib/include/ClrPhlib.h",
    "content": "// ClrPhlib.h\r\n\r\n#pragma once\r\n\r\n#include <UnmanagedPh.h>\r\n#using <System.dll>\r\n\r\nusing namespace System;\r\nusing namespace Collections::Generic;\r\n\r\nnamespace Dependencies {\r\n\r\n    namespace ClrPh {\r\n\r\n\t\t#pragma region ENUMS\r\n\t\tpublic enum class CLRPH_ARCH\r\n\t\t{\r\n\t\t\tx86,\r\n\t\t\tx64,\r\n\t\t\tWOW64\r\n\t\t};\r\n\r\n\t\tpublic enum class CLRPH_DEMANGLER\r\n\t\t{\r\n\t\t\tNone,\r\n\t\t\tDemumble,\r\n\t\t\tLLVMItanium,\r\n\t\t\tLLVMMicrosoft,\r\n\t\t\tMicrosoft,\r\n\t\t\tDefault\t\t\t// Synthetic demangler using all the previous ones\r\n\t\t};\r\n\t\t#pragma endregion ENUMS\r\n\r\n\t\t#pragma region TYPES\r\n        public ref class ApiSetTarget : List<String^> {};\r\n\r\n        public ref class ApiSetSchema abstract\r\n        {\r\n        public:\r\n            virtual List<KeyValuePair<String^, ApiSetTarget^>>^ GetAll() = 0;\r\n            virtual ApiSetTarget^ Lookup(String^ name) = 0;\r\n        };\r\n\t\t#pragma endregion TYPES\r\n\r\n        public ref class Phlib {\r\n        public:\r\n\r\n\t\t\t// Return the arch is which ClrPhLib runs.\r\n\t\t\tstatic CLRPH_ARCH GetClrPhArch();\r\n\r\n            // Imitialize Process Hacker's phlib internal data\r\n            // Must be called before any other API (kinda like OleInitialize).\r\n            static bool InitializePhLib();\r\n\r\n            // Return the list of knwown dll for this system\r\n            static List<String^>^ GetKnownDlls(_In_ bool Wow64Dlls);\r\n\r\n            static List<String^>^ KnownDll64List;\r\n            static List<String^>^ KnownDll32List;\r\n\r\n            \r\n            // Return the Api Set schema:\r\n            // NB: Api set resolution rely on hash buckets who \r\n            // can contains more entries than this schema.\r\n            static ApiSetSchema^ GetApiSetSchema();\r\n        };\r\n\r\n        public ref struct PeImport {\r\n            UInt16 Hint;\r\n            UInt16 Ordinal;\r\n            String ^ Name;\r\n            String ^ ModuleName;\r\n            Boolean ImportByOrdinal;\r\n            Boolean DelayImport;\r\n\r\n            PeImport(const PPH_MAPPED_IMAGE_IMPORT_DLL importDll, size_t Index);\r\n            PeImport(const PeImport ^ other);\r\n            ~PeImport();\r\n\r\n        };\r\n\r\n        public ref struct PeImportDll {\r\n        public:\r\n            Int64 Flags;\r\n            String ^Name;\r\n            Int64 NumberOfEntries;\r\n            List<PeImport^>^ ImportList;\r\n\r\n            // constructors\r\n            PeImportDll(const PPH_MAPPED_IMAGE_IMPORTS &PvMappedImports, size_t ImportDllIndex);\r\n            PeImportDll(const PeImportDll ^ other);\r\n\r\n            // destructors\r\n            ~PeImportDll();\r\n\r\n            // getters\r\n            bool IsDelayLoad();\r\n\r\n        protected:\r\n            !PeImportDll();\r\n\r\n        private:\r\n            PPH_MAPPED_IMAGE_IMPORT_DLL ImportDll;\r\n        };\r\n\r\n        public ref struct PeExport {\r\n            UInt16 Ordinal;\r\n            String ^  Name; // may be NULL.\r\n            Boolean ExportByOrdinal;\r\n            Int64   VirtualAddress;\r\n            String ^  ForwardedName;\r\n\r\n\t\t\tPeExport();\r\n            PeExport(const PeExport ^ other);\r\n            ~PeExport();\r\n\r\n\t\t\tstatic PeExport^ FromMapimg(const UnmanagedPE& refPe, size_t Index);\r\n\r\n        };\r\n\r\n        public ref struct PeProperties {\r\n            Int16 Machine;\r\n            DateTime ^ Time;\r\n            Int16 Magic;\r\n\r\n\t\t\tInt64 ImageBase;\r\n            Int32  SizeOfImage;\r\n\t\t\tInt64 EntryPoint;\r\n\r\n\r\n            Int32 Checksum;\r\n            Boolean CorrectChecksum;\r\n\r\n            Int16 Subsystem;\r\n            Tuple<Int16, Int16> ^SubsystemVersion;\r\n\r\n            Int16 Characteristics;\r\n            Int16 DllCharacteristics;\r\n\r\n            UInt64 FileSize;\r\n        };\r\n\r\n\r\n        // C# visible class representing a parsed PE file\r\n        public ref class PE\r\n        {\r\n        public:\r\n            PE(_In_ String^ Filepath);\r\n            ~PE();\r\n\r\n            // Mapped the PE in memory and init infos\r\n            bool Load();\r\n\r\n            // Unmapped the PE from memory\r\n            void Unload();\r\n\r\n            // Check if the PE is 32-bit\r\n            bool IsWow64Dll();\r\n\r\n            // Check if the PE is 32-bit\r\n            bool IsArm32Dll();\r\n\r\n            // return the processorArchiture of PE\r\n            String^ GetProcessor();\r\n\r\n            // Return the ApiSetSchema\r\n            ApiSetSchema^ GetApiSetSchema();\r\n\r\n            // Return the list of functions exported by the PE\r\n            List<PeExport ^>^ GetExports();\r\n\r\n            // Return the list of functions imported by the PE, bundled by Dll name\r\n            List<PeImportDll ^>^ GetImports();\r\n\r\n            // Retrieve the manifest embedded within the PE\r\n            // Return an empty string if there is none.\r\n            String^ GetManifest();\r\n\r\n            // PE properties parsed from the NT header\r\n            PeProperties ^Properties;\r\n\r\n            // Check if the specified file has been successfully parsed as a PE file.\r\n            Boolean LoadSuccessful;\r\n\r\n            // Path to PE file.\r\n            String^ Filepath;\r\n\r\n        protected:\r\n            // Deallocate the native object on the finalizer just in case no destructor is called  \r\n            !PE();\r\n\r\n            // Initalize PeProperties struct once the PE has been loaded into memory\r\n            bool InitProperties();\r\n\r\n        private:\r\n            \r\n            // C++ part interfacing with phlib\r\n            UnmanagedPE * m_Impl;\r\n\r\n            // local cache for imports and exports list\r\n            List<PeImportDll ^>^ m_Imports;\r\n            List<PeExport ^>^  m_Exports;\r\n            bool m_ExportsInit;\r\n            bool m_ImportsInit;\r\n        };\r\n        \r\n    }\r\n\r\n}"
  },
  {
    "path": "ClrPhlib/include/NativeFile.h",
    "content": "// Native.h\n#pragma once\n\n#include <UnmanagedPh.h>\n#include <stdint.h>\n#using <System.dll>\n\nusing namespace System;\n\nnamespace Dependencies {\nnamespace ClrPh {\n\n\t// Partial rewrite of System.IO.File in order to circumvent the wow64 system folder redirection\n\t// that is not properly handled in .Net Core.\n\tpublic ref class NativeFile {\n    public:\n\n        // @return true if the path actually points to a file on the disk\n\t\tstatic bool Exists(_In_ String^ Path);\n        static bool Exists(_In_ String^ Path, bool IsFolder);\n\n        // Copy a filename to a new location\n        static void Copy(_In_ String^ sourceFileName, _In_ String^ destFileName);\n\n        // Hash the first FileSize bytes of a file, using SHA256.\n        static String^ GetPartialHashFile(_In_ String^ Path, _In_ size_t FileSize);\n\n\tprivate:\n\n\t\t// Hash buffer using bcrypt library\n\t\tstatic bool HashBuffer(_In_ uint8_t *Buffer, _In_ size_t BufferSize, _In_ wchar_t *HASH_ALGORITHM, _Outptr_ void **Hash, _Out_ size_t *HashSize);\n\t\t\n\t\t// @return a hex string representing the buffer values, kinda like Python's binascii.hexlify \n\t\tstatic String^ GetHexString(_In_ uint8_t *Buffer, _In_ size_t BufferSize);\n\t\t\t\n\t\t// Ignore system32 folder redirection since we may analyzing 64-bit binaries on a 32-bit Dependencies\n\t\tstatic bool DisableWow64FsRedirection();\n\n\t\t// revert redirection since it may have unpredictible results further down the line\n\t\tstatic bool RevertWow64FsRedirection();\n\t};\n\n} /* namespace ClrPh */\n} /* namespace System */\n"
  },
  {
    "path": "ClrPhlib/include/UnmanagedPh.h",
    "content": "#pragma once\n\n#include <ph.h>\n#include <mapimg.h>\n\n\n// C++ part of the PE class interfacing with phlib.\n// Responsible for mapping/unmapping the PE file in memory and\n// parse the NT headers and Directory entries.\nclass UnmanagedPE {\n\npublic:\n\n    UnmanagedPE();\n    ~UnmanagedPE();\n    \n    // Try to load the PE pointed by Filepath in memmory\n    bool LoadPE(LPWSTR Filepath);\n\n    // Unload the memory mapped PE in order to release the FS lock\n    void UnloadPE();\n    \n    // Extract the manifest embedded within the mapped PE\n    //\n    // /param  manifest variable pointing to the part of the mapped file holding the manifest (no allocations here)\n    // /param  manifestLen variable returning the length of the embedded binary manifest\n    // /return false if there is none\n    bool GetPeManifest(\n\t\t_Out_ BYTE* *manifest,\n        _Out_ INT  *manifestLen\n    );\n    \n\n    PH_MAPPED_IMAGE m_PvMappedImage;\n    PH_MAPPED_IMAGE_EXPORTS m_PvExports;\n    PH_MAPPED_IMAGE_IMPORTS m_PvImports;\n    PH_MAPPED_IMAGE_IMPORTS m_PvDelayImports;\n\n    union {\n        PIMAGE_LOAD_CONFIG_DIRECTORY32 m_PvConfig32;\n        PIMAGE_LOAD_CONFIG_DIRECTORY64 m_PvCconfig64;\n    };\n\nprivate:\n    bool            m_bImageLoaded;\n};\n"
  },
  {
    "path": "ClrPhlib/include/UnmanagedSymPrv.h",
    "content": "#pragma once\n\n#include <stdbool.h>\n\n#include <ph.h>\n#include <symprv.h>\n#include <ClrPhlib.h>\n\n\n// Native Symbol Provider class.\n// Allow the application to unmangle C and C++ mangled names.\nclass UnmanagedSymPrv {\n\npublic:\n\n\t// Initialize a new provider.\n\tstatic UnmanagedSymPrv* Create();\n\n\t// Attempt to demangle a C/C++ name. Return false if the name is not mangled.\n\tbool DemangleName(\n\t\t_In_ wchar_t* DecoratedName,\n\t\t_In_ size_t DecoratedNameLen,\n\t\t_Out_ wchar_t** UndecoratedName,\n\t\t_Out_ size_t* UndecoratedNameLen,\n\t\t_Out_ Dependencies::ClrPh::CLRPH_DEMANGLER *Demangler\n\t);\n\npublic:\n\tPPH_SYMBOL_PROVIDER m_SymbolProvider;\n};\n\n\n\n\ntypedef bool(__cdecl *DemangleNameFn)\t(UnmanagedSymPrv*, wchar_t*, size_t, wchar_t**, size_t*);\n\nbool DemumbleDemangleName(\n\t_In_ UnmanagedSymPrv* obj,\n\t_In_ wchar_t* DecoratedName,\n\t_In_ size_t DecoratedNameLen,\n\t_Out_ wchar_t** UndecoratedName,\n\t_Out_ size_t* UndecoratedNameLen\n);\n\nbool LLVMItaniumDemangleName(\n\t_In_ UnmanagedSymPrv* obj,\n\t_In_ wchar_t* DecoratedName,\n\t_In_ size_t DecoratedNameLen,\n\t_Out_ wchar_t** UndecoratedName,\n\t_Out_ size_t* UndecoratedNameLen\n);\n\nbool LLVMMicrosoftDemangleName(\n\t_In_ UnmanagedSymPrv* obj,\n\t_In_ wchar_t* DecoratedName,\n\t_In_ size_t DecoratedNameLen,\n\t_Out_ wchar_t** UndecoratedName,\n\t_Out_ size_t* UndecoratedNameLen\n);\n\nbool UndecorateSymbolDemangleName(\n\t_In_ UnmanagedSymPrv* obj,\n\t_In_ wchar_t* DecoratedName,\n\t_In_ size_t DecoratedNameLen,\n\t_Out_ wchar_t** UndecoratedName,\n\t_Out_ size_t* UndecoratedNameLen\n);\n\nconst DemangleNameFn Demanglers[] = {\n\tDemumbleDemangleName,\t\t\t\t// Undecorate name using demumble library\n\tLLVMItaniumDemangleName,\t\t\t// Undecorate name using llvm::itaniumDemangle library\n\tLLVMMicrosoftDemangleName,\t\t\t// Undecorate name using llvm::microsoftDemangle library\n\tUndecorateSymbolDemangleName\t\t// Undecorate name using UnDecorateSymbolNameW library\n};"
  },
  {
    "path": "ClrPhlib/resource.h",
    "content": "//{{NO_DEPENDENCIES}}\n// Microsoft Visual C++ generated include file.\n// Used by app.rc\n"
  },
  {
    "path": "ClrPhlib/src/managed/NativeFile.cpp",
    "content": "#include <NativeFile.h>\n#include <ClrPhLib.h>\n#include <phconfig.h>\n#include <vcclr.h> \n#include <bcrypt.h>\n\nusing namespace Dependencies;\nusing namespace ClrPh;\nusing namespace System::Text;\n\nstatic bool isCurrentProcessWow64 = CLRPH_ARCH::WOW64 == Phlib::GetClrPhArch();\nstatic PVOID FsRedirectionValue = NULL;\n#define WITH_WOW64_FS_REDIRECTION_DISABLED(action) do { \\\n    DisableWow64FsRedirection(); \\\n    action \\\n    RevertWow64FsRedirection(); \\\n} while (false)\n\nbool NativeFile::DisableWow64FsRedirection()\n{\n\tif (!isCurrentProcessWow64)\n\t\treturn true;\n\n\tBOOL bWow64RedirectionDisabled = Wow64DisableWow64FsRedirection(\n\t\t&FsRedirectionValue\n\t);\n\n\treturn (bWow64RedirectionDisabled == TRUE);\n}\n\nbool NativeFile::RevertWow64FsRedirection()\n{\n\tif (!isCurrentProcessWow64)\n\t\treturn true;\n\n\tBOOL bWow64RedirectionReverted = Wow64RevertWow64FsRedirection(\n\t\tFsRedirectionValue\n\t);\n\n\treturn (bWow64RedirectionReverted == TRUE);\n}\n\nbool NativeFile::Exists(_In_ String^ Path)\n{\n\treturn NativeFile::Exists(Path, false);\n}\n\nbool NativeFile::Exists(_In_ String^ Path, bool IsFolder)\n{\n    bool bFileExists = false;\n\tpin_ptr<const wchar_t> RawPath = PtrToStringChars(Path);\n\n\n    WITH_WOW64_FS_REDIRECTION_DISABLED({\n        \n        DWORD FileAttributes = GetFileAttributes(RawPath);\n\t\t//Console::WriteLine(\"FileAttributes: {0:x}\", FileAttributes);\n\t\t\n\t\tbFileExists = (FileAttributes != INVALID_FILE_ATTRIBUTES);\n\t\tif (!IsFolder)\n\t\t{\n\t\t\tbFileExists &= !(FileAttributes & FILE_ATTRIBUTE_DIRECTORY);\n\t\t}\n                     \n    });\n\n    return bFileExists;\n}\n\nvoid NativeFile::Copy(_In_ String^ sourceFileName, _In_ String^ destFileName)\n{\n    bool bFileExists = false;\n    PVOID OldRedirectionValue = NULL;\n    BOOLEAN isWow64 = PhIsExecutingInWow64();\n\tpin_ptr<const wchar_t> RawSourceFilepath = PtrToStringChars(sourceFileName);\n\tpin_ptr<const wchar_t> RawDestFilepath = PtrToStringChars(destFileName);\n\n    WITH_WOW64_FS_REDIRECTION_DISABLED({\n    \n        CopyFile(\n            RawSourceFilepath,\n            RawDestFilepath,\n            false\n        );\n    });\n}\n\nString^ NativeFile::GetPartialHashFile(_In_ String^ Path, _In_ size_t FileSize)\n{\n\tbool read_success = false;\n\tbool success = false;\n\tvoid* hash = NULL;\n\tsize_t hash_size = 0;\n\n\tHANDLE fileHandle = INVALID_HANDLE_VALUE;\n\tPVOID fileBuffer = NULL;\n\tULONG FileSizeRead = 0;\n\n    String^ PartialHash;\n    pin_ptr<const wchar_t> RawPath = PtrToStringChars(Path);\n\n\n\tWITH_WOW64_FS_REDIRECTION_DISABLED({\n\n\t\tfileHandle = CreateFile(\n\t\t\tRawPath,\n\t\t\tFILE_GENERIC_READ,\n\t\t\tFILE_SHARE_READ,\n\t\t\tNULL,\n\t\t\tOPEN_EXISTING,\n\t\t\tFILE_ATTRIBUTE_NORMAL,\n\t\t\tNULL\n\t\t);\n    });\n    \n    if ((INVALID_HANDLE_VALUE == fileHandle))\n        goto CleanupExit;\n\n\tif (!(fileBuffer = malloc(FileSize)))\n\t\tgoto CleanupExit;\n\n    if (!ReadFile(\n      fileHandle,\n      fileBuffer,\n      (DWORD) FileSize,\n      &FileSizeRead,\n      NULL\n    ))\n        goto CleanupExit;\n\n    if (FileSizeRead != FileSize)\n        goto CleanupExit;\n\n\t// hash it\n\tif (!HashBuffer((uint8_t *)fileBuffer, FileSize, BCRYPT_SHA256_ALGORITHM, &hash, &hash_size))\n\t\tgoto CleanupExit;\n\n\t// Convert to hex string\n    PartialHash = GetHexString((uint8_t *)hash, hash_size);\n    success = TRUE;\n\nCleanupExit:\n\n    if (fileBuffer)\n        free(fileBuffer);\n\n    if (fileHandle)\n        CloseHandle(fileHandle);\n    \n\tif (hash)\n\t\tfree(hash);\n\n    if (!success)\n    {\n        return gcnew String(\"\");\n    }\n\n    return PartialHash;\n}\n\n\nbool NativeFile::HashBuffer(_In_ uint8_t *Buffer, _In_ size_t BufferSize, _In_ wchar_t *HASH_ALGORITHM, _Outptr_ void **Hash, _Out_ size_t *HashSize)\n{\n\t\n\tNTSTATUS status;\n\tBCRYPT_ALG_HANDLE hashAlgHandle = NULL;\n\tBCRYPT_HASH_HANDLE hashHandle = NULL;\n\n\tPVOID hash = NULL;\n\tPVOID hashObject = NULL;\n\tULONG hashObjectSize = 0;\n\tULONG hashSize = 0;\n\tULONG querySize = 0;\n\n\t*Hash = NULL;\n\t*HashSize = 0;\n\tbool success = false;\n\n\tif (!NT_SUCCESS(status = BCryptOpenAlgorithmProvider(&hashAlgHandle, HASH_ALGORITHM, NULL, 0)))\n\t\tgoto CleanupExit;\n\n\tif (!NT_SUCCESS(status = BCryptGetProperty(hashAlgHandle, BCRYPT_OBJECT_LENGTH,\n\t\t(PUCHAR)&hashObjectSize, sizeof(ULONG), &querySize, 0)))\n\t\tgoto CleanupExit;\n\n\tif (!NT_SUCCESS(status = BCryptGetProperty(hashAlgHandle, BCRYPT_HASH_LENGTH, (PUCHAR)&hashSize,\n\t\tsizeof(ULONG), &querySize, 0)))\n\t\tgoto CleanupExit;\n\n\tif (!(hashObject = malloc(hashObjectSize)))\n\t\tgoto CleanupExit;\n\n\tif (!(hash = malloc(hashSize)))\n\t\tgoto CleanupExit;\n\n\tif (!NT_SUCCESS(status = BCryptCreateHash(\n\t\thashAlgHandle,\n\t\t&hashHandle,\n\t\t(PUCHAR)hashObject,\n\t\thashObjectSize,\n\t\tNULL,\n\t\t0,\n\t\t0\n\t)))\n\t\tgoto CleanupExit;\n\n\tif (!NT_SUCCESS(status = BCryptHashData(hashHandle, (PUCHAR)Buffer, (ULONG)BufferSize, 0)))\n\t\tgoto CleanupExit;\n\n\tif (!NT_SUCCESS(status = BCryptFinishHash(hashHandle, (PUCHAR)hash, hashSize, 0)))\n\t\tgoto CleanupExit;\n\n\t*Hash = hash;\n\t*HashSize = hashSize;\n\tsuccess = true;\n\nCleanupExit:\n\t\n\tif (!success)\n\t{\n\t\tif (hash)\n\t\t\tfree(hash);\n\t}\n\n\tif (hashHandle)\n\t\tBCryptDestroyHash(hashHandle);\n\n\tif (hashAlgHandle)\n\t\tBCryptCloseAlgorithmProvider(hashAlgHandle, 0);\n\n\tif (hashObject)\n\t\tfree(hashObject);\n\n\treturn success;\n}\n\nString^ NativeFile::GetHexString(_In_ uint8_t *Buffer, _In_ size_t BufferSize)\n{\n    ASCIIEncoding AsciiDecoder;\n    array<unsigned char> ^hexBuffer = gcnew array<unsigned char>(2 * (int)BufferSize);\n\n    for (ULONG i = 0; i < BufferSize; i++)\n    {\n        char hexNumber[2] = {0};\n        sprintf(hexNumber, \"%02X\", ((unsigned char*)Buffer)[i]);\n\n        hexBuffer[2*i] = hexNumber[0];\n        hexBuffer[2*i + 1] = hexNumber[1];\n    }\n\n   return AsciiDecoder.GetString(hexBuffer, 0, 2 * (int)BufferSize);\n}"
  },
  {
    "path": "ClrPhlib/src/managed/PE.cpp",
    "content": "#include <ClrPhlib.h>\n#include <UnmanagedPh.h>\n\nusing namespace Dependencies;\nusing namespace System::Text;\nusing namespace ClrPh;\nusing namespace Runtime::InteropServices;\n\nPE::PE(\n    _In_ String ^ Filepath\n)\n{\n    this->m_Impl = new UnmanagedPE();\n    this->Filepath = gcnew String(Filepath);\n    this->LoadSuccessful = false;\n\n    this->m_ExportsInit = false;\n    this->m_ImportsInit = false;\n}\n\nPE::~PE()\n{\n    Unload();\n    delete m_Impl;\n}\n\nPE::!PE() {\n    Unload();\n    delete m_Impl;\n}\n\nbool PE::Load()\n{\n    // Load PE as mapped section\n    wchar_t* PvFilepath = (wchar_t*)(Marshal::StringToHGlobalUni(Filepath)).ToPointer();\n    this->LoadSuccessful = m_Impl->LoadPE(PvFilepath);\n\tMarshal::FreeHGlobal(IntPtr((void*)PvFilepath));\n\n\tif (!LoadSuccessful) {\n\t\treturn false;\n\t}\n        \n\t// Parse PE\n\tLoadSuccessful &= InitProperties();\n\tif (!LoadSuccessful) {\n\t\tm_Impl->UnloadPE();\n\t\treturn false;\n\t}\n\n\n    return LoadSuccessful;\n}\n\nvoid PE::Unload()\n{\n    if (LoadSuccessful)\n        m_Impl->UnloadPE();\n}\n\nbool PE::InitProperties()\n{\n    LARGE_INTEGER time;\n    SYSTEMTIME systemTime;\n\n    PH_MAPPED_IMAGE PvMappedImage = m_Impl->m_PvMappedImage;\n    \n    Properties = gcnew PeProperties();\n    Properties->Machine = PvMappedImage.NtHeaders->FileHeader.Machine;\n    Properties->Magic = m_Impl->m_PvMappedImage.Magic;\n    Properties->Checksum = PvMappedImage.NtHeaders->OptionalHeader.CheckSum;\n    Properties->CorrectChecksum = (Properties->Checksum == PhCheckSumMappedImage(&PvMappedImage));\n\n    RtlSecondsSince1970ToTime(PvMappedImage.NtHeaders->FileHeader.TimeDateStamp, &time);\n    PhLargeIntegerToLocalSystemTime(&systemTime, &time);\n    Properties->Time = gcnew DateTime (systemTime.wYear, systemTime.wMonth, systemTime.wDay, systemTime.wHour, systemTime.wMinute, systemTime.wSecond, systemTime.wMilliseconds, DateTimeKind::Local);\n\n    if (PvMappedImage.Magic == IMAGE_NT_OPTIONAL_HDR32_MAGIC)\n    {\n        PIMAGE_OPTIONAL_HEADER32 OptionalHeader = (PIMAGE_OPTIONAL_HEADER32) &PvMappedImage.NtHeaders->OptionalHeader;\n        \n        Properties->ImageBase = (Int64) OptionalHeader->ImageBase;\n        Properties->SizeOfImage = OptionalHeader->SizeOfImage;\n        Properties->EntryPoint = (Int64) OptionalHeader->AddressOfEntryPoint;\n    }\n    else\n    {\n        PIMAGE_OPTIONAL_HEADER64 OptionalHeader = (PIMAGE_OPTIONAL_HEADER64)&PvMappedImage.NtHeaders->OptionalHeader;\n\n        Properties->ImageBase = (Int64)OptionalHeader->ImageBase;\n        Properties->SizeOfImage = OptionalHeader->SizeOfImage;\n        Properties->EntryPoint = (Int64)OptionalHeader->AddressOfEntryPoint;\n\n    }\n\n    Properties->Subsystem = PvMappedImage.NtHeaders->OptionalHeader.Subsystem;\n    Properties->SubsystemVersion = gcnew Tuple<Int16, Int16>(\n        PvMappedImage.NtHeaders->OptionalHeader.MajorSubsystemVersion,\n        PvMappedImage.NtHeaders->OptionalHeader.MinorSubsystemVersion);\n    Properties->Characteristics = PvMappedImage.NtHeaders->FileHeader.Characteristics;\n    Properties->DllCharacteristics = PvMappedImage.NtHeaders->OptionalHeader.DllCharacteristics;\n\n    Properties->FileSize = PvMappedImage.Size;\n\treturn true;\n}\n\nCollections::Generic::List<PeExport^> ^ PE::GetExports()\n{\n    if (m_ExportsInit)\n        return m_Exports;\n\n    m_ExportsInit = true;\n    m_Exports = gcnew Collections::Generic::List<PeExport^>();\n\n    if (!LoadSuccessful)\n        return m_Exports;\n\n    if (NT_SUCCESS(PhGetMappedImageExports(&m_Impl->m_PvExports, &m_Impl->m_PvMappedImage)))\n    {\n        for (size_t Index = 0; Index < m_Impl->m_PvExports.NumberOfEntries; Index++)\n        {\n\t\t\tPeExport^ exp = PeExport::FromMapimg(*m_Impl, Index);\n\n\t\t\tif (exp)\n\t\t\t{\n\t\t\t\tm_Exports->Add(exp);\n\t\t\t}\n\n        }\n    }\n\n    return m_Exports;\n}\n\n\nCollections::Generic::List<PeImportDll^> ^ PE::GetImports()\n{\n    if (m_ImportsInit)\n        return m_Imports;\n\n    m_ImportsInit = true;\n    m_Imports = gcnew Collections::Generic::List<PeImportDll^>();\n\n    if (!LoadSuccessful)\n        return m_Imports;\n\n    // Standard Imports\n    if (NT_SUCCESS(PhGetMappedImageImports(&m_Impl->m_PvImports, &m_Impl->m_PvMappedImage)))\n    {\n        for (size_t IndexDll = 0; IndexDll< m_Impl->m_PvImports.NumberOfDlls; IndexDll++)\n        {\n            m_Imports->Add(gcnew PeImportDll(&m_Impl->m_PvImports, IndexDll));\n        }\n    }\n\n    // Delayed Imports\n    if (NT_SUCCESS(PhGetMappedImageDelayImports(&m_Impl->m_PvDelayImports, &m_Impl->m_PvMappedImage)))\n    {\n        for (size_t IndexDll = 0; IndexDll< m_Impl->m_PvDelayImports.NumberOfDlls; IndexDll++)\n        {\n            m_Imports->Add(gcnew PeImportDll(&m_Impl->m_PvDelayImports, IndexDll));\n        }\n    }\n\n    return m_Imports;\n}\n\n\n\nString^ PE::GetManifest()\n{\n    if (!LoadSuccessful)\n        return gcnew String(\"\");\n\n    // Extract embedded manifest\n    INT  rawManifestLen;\n    BYTE* rawManifest;\n    if (!m_Impl->GetPeManifest(&rawManifest, &rawManifestLen))\n        return gcnew String(\"\");\n\n\n    // Converting to wchar* and passing it to a C#-recognized String object\n    UTF8Encoding Utf8Decoder;\n\n    array<unsigned char> ^buffer = gcnew array<unsigned char>(rawManifestLen + 1);\n    for (int i = 0; i < rawManifestLen; i++)\n    {\n        buffer[i] = rawManifest[i];\n    }\n    buffer[rawManifestLen] = 0;\n\n    return  Utf8Decoder.GetString(buffer, 0, rawManifestLen);\n}\n\nbool PE::IsWow64Dll() \n{\n    return ((Properties->Machine & 0xffff ) == IMAGE_FILE_MACHINE_I386);\n}\n\nbool PE::IsArm32Dll()\n{\n  return ((Properties->Machine & 0xffff) == IMAGE_FILE_MACHINE_ARMNT);\n}\n\nString^ PE::GetProcessor()\n{\n  if ((Properties->Machine & 0xffff) == IMAGE_FILE_MACHINE_I386)\n    return gcnew String(\"x86\");\n  if ((Properties->Machine & 0xffff) == IMAGE_FILE_MACHINE_ARMNT)\n    return gcnew String(\"arm\");\n  if ((Properties->Machine & 0xffff) == IMAGE_FILE_MACHINE_ARM64)\n    return gcnew String(\"arm64\");\n\n  return gcnew String(\"unknown\");\n}\n\n"
  },
  {
    "path": "ClrPhlib/src/managed/PeExport.cpp",
    "content": "#include <ClrPhlib.h>\n#include <UnmanagedPh.h>\n\n\nusing namespace Dependencies;\nusing namespace ClrPh;\nPeExport::PeExport(\n)\n{\n}\n\nPeExport^ PeExport::FromMapimg (\n\t_In_ const UnmanagedPE &refPe,\n\t_In_ size_t Index\n)\n{\n\tPH_MAPPED_IMAGE_EXPORT_ENTRY exportEntry;\n\tPH_MAPPED_IMAGE_EXPORT_FUNCTION exportFunction;\n\n\tPeExport^ exp = nullptr;\n\n\tif (\n\t\tNT_SUCCESS(PhGetMappedImageExportEntry((PPH_MAPPED_IMAGE_EXPORTS)&refPe.m_PvExports, (ULONG) Index, &exportEntry)) &&\n\t\tNT_SUCCESS(PhGetMappedImageExportFunction((PPH_MAPPED_IMAGE_EXPORTS)&refPe.m_PvExports, NULL, exportEntry.Ordinal, &exportFunction))\n\t\t)\n\t{\n\t\texp = gcnew PeExport();\n\n\t\texp->Ordinal = exportEntry.Ordinal;\n\t\texp->ExportByOrdinal = (exportEntry.Name == nullptr);\n\t\texp->Name = gcnew String(exportEntry.Name);\n\t\texp->ForwardedName = gcnew String(exportFunction.ForwardedName);\n\t\t\n\t\tif (exportEntry.Name == nullptr)\n\t\t\texp->VirtualAddress = (Int64)exportFunction.Function;\n\n\t\texp->VirtualAddress = (Int64) exportFunction.Function;\n\n\t}\n\n\treturn exp;\n}\n\nPeExport::PeExport(\n\t_In_ const PeExport ^ other\n)\n{\n\tthis->Ordinal = Ordinal;\n\tthis->ExportByOrdinal = ExportByOrdinal;\n\tthis->Name = String::Copy(other->Name);\n\tthis->ForwardedName = String::Copy(other->ForwardedName);\n\tthis->VirtualAddress = other->VirtualAddress;\n}\n\nPeExport::~PeExport()\n{\n\n}"
  },
  {
    "path": "ClrPhlib/src/managed/PeImport.cpp",
    "content": "#include <ClrPhlib.h>\n#include <UnmanagedPh.h>\n\n\nusing namespace Dependencies;\nusing namespace ClrPh;\n\n\nPeImport::PeImport(\n\t_In_ const PPH_MAPPED_IMAGE_IMPORT_DLL importDll,\n\t_In_ size_t Index\n)\n{\n\tPH_MAPPED_IMAGE_IMPORT_ENTRY importEntry;\n\n\tif (NT_SUCCESS(PhGetMappedImageImportEntry((PPH_MAPPED_IMAGE_IMPORT_DLL) importDll, (ULONG)Index, &importEntry)))\n\t{\n\t\tthis->Hint = importEntry.NameHint;\n\t\tthis->Ordinal = importEntry.Ordinal;\n\t\tthis->DelayImport = (importDll->Flags) & PH_MAPPED_IMAGE_DELAY_IMPORTS;\n\t\tthis->Name = gcnew String(importEntry.Name);\n\t\tthis->ModuleName = gcnew String(importDll->Name);\n\t\tthis->ImportByOrdinal = (importEntry.Name == nullptr);\n\t}\n\n\n}\n\nPeImport::PeImport(\n\t_In_ const PeImport ^ other\n)\n{\n\tthis->Hint = other->Hint;\n\tthis->Ordinal = other->Ordinal;\n\tthis->DelayImport = other->DelayImport;\n\tthis->Name = String::Copy(other->Name);\n\tthis->ModuleName = String::Copy(other->ModuleName);\n\tthis->ImportByOrdinal = other->ImportByOrdinal;\n}\n\nPeImport::~PeImport()\n{\n}\n\n\nPeImportDll::PeImportDll(\n\t_In_ const PPH_MAPPED_IMAGE_IMPORTS &PvMappedImports, \n\t_In_ size_t ImportDllIndex\n)\n: ImportDll (new PH_MAPPED_IMAGE_IMPORT_DLL)\n{\n\tImportList = gcnew Collections::Generic::List<PeImport^>();\n\n\tif (!NT_SUCCESS(PhGetMappedImageImportDll(PvMappedImports, (ULONG)ImportDllIndex, ImportDll)))\n\t{\n\t\tFlags = 0;\n\t\tName = gcnew String(\"## PeImportDll error: Invalid DllName ##\");\n\t\tNumberOfEntries = 0;\n\t\treturn;\n\t}\n\n\tFlags = ImportDll->Flags;\n\tName = gcnew String(ImportDll->Name);\n\tNumberOfEntries = ImportDll->NumberOfEntries;\n\n\tfor (size_t IndexImport = 0; IndexImport < (size_t) NumberOfEntries; IndexImport++)\n\t{\n\t\tImportList->Add(gcnew PeImport(ImportDll, IndexImport));\n\t}\n}\n\nPeImportDll::~PeImportDll()\n{\n\tdelete ImportDll;\n}\n\nPeImportDll::!PeImportDll()\n{\n\tdelete ImportDll;\n}\n\nPeImportDll::PeImportDll(\n\t_In_ const PeImportDll ^ other\n)\n: ImportDll(new PH_MAPPED_IMAGE_IMPORT_DLL)\n{\n\tImportList = gcnew Collections::Generic::List<PeImport^>();\n\n\tmemcpy(ImportDll, other->ImportDll, sizeof(PH_MAPPED_IMAGE_IMPORT_DLL));\n\n\tFlags = other->Flags;\n\tName = String::Copy(other->Name);\n\tNumberOfEntries = other->NumberOfEntries;\n\n\tfor (size_t IndexImport = 0; IndexImport < (size_t)NumberOfEntries; IndexImport++)\n\t{\n\t\tImportList->Add(gcnew PeImport(other->ImportList[(int) IndexImport]));\n\t}\n\n}\n\n\nbool PeImportDll::IsDelayLoad()\n{\n\treturn this->Flags & PH_MAPPED_IMAGE_DELAY_IMPORTS;\n}"
  },
  {
    "path": "ClrPhlib/src/managed/PhSymbolProvider.cpp",
    "content": "#include <ClrPhlib.h>\n#include <UnmanagedPh.h>\n#include <ClrPhSymbolProvider.h>\n\nusing namespace Dependencies;\nusing namespace ClrPh;\nusing namespace Runtime::InteropServices;\n\n\n\n\nPhSymbolProvider::PhSymbolProvider()\n:m_Impl(UnmanagedSymPrv::Create())\n{\n}\n\nPhSymbolProvider::~PhSymbolProvider()\n{\n\tif (m_Impl) {\n\t\tdelete m_Impl;\n\t}\n\t\t\n}\n\nPhSymbolProvider::!PhSymbolProvider()\n{\n\tif (m_Impl) {\n\t\tdelete m_Impl;\n\t}\n\n}\n\nString^ PhSymbolProvider::UndecorateNameDemumble(\n\t_In_ String ^DecoratedName\n)\n{\n\treturn UndecorateNamePrv(DecoratedName, DemumbleDemangleName);\n}\n\nString^ PhSymbolProvider::UndecorateNameLLVMItanium(_In_ String ^DecoratedName)\n{\n\treturn UndecorateNamePrv(DecoratedName, LLVMItaniumDemangleName);\n}\n\nString^ PhSymbolProvider::UndecorateNameLLVMMicrosoft(_In_ String ^DecoratedName)\n{\n\treturn UndecorateNamePrv(DecoratedName, LLVMMicrosoftDemangleName);\n}\n\nString^ PhSymbolProvider::UndecorateNamePh(_In_ String ^DecoratedName)\n{\n\treturn UndecorateNamePrv(DecoratedName, UndecorateSymbolDemangleName);\n}\n\nTuple<CLRPH_DEMANGLER, String^>^  PhSymbolProvider::UndecorateName(_In_ String ^DecoratedName)\n{\n\tString ^ManagedUndName;\n\twchar_t* UndecoratedName = NULL;\n\tsize_t UndecoratedNameLen = 0;\n\tCLRPH_DEMANGLER Demangler = CLRPH_DEMANGLER::None;\n\n\tif (!m_Impl || !DecoratedName || DecoratedName->Length == 0) {\n\t\treturn gcnew Tuple<CLRPH_DEMANGLER, String^> (Demangler, gcnew String(\"\"));\n\t}\n\n\twchar_t* PvDecoratedName = (wchar_t*)(Marshal::StringToHGlobalUni(DecoratedName)).ToPointer();\n\tsize_t PvDecoratedNameLen = wcslen(PvDecoratedName);\n\n\n\tif (m_Impl->DemangleName(\n\t\tPvDecoratedName,\n\t\tPvDecoratedNameLen,\n\t\t&UndecoratedName,\n\t\t&UndecoratedNameLen,\n\t\t&Demangler\n\t))\n\t{\n\t\tManagedUndName = gcnew String(UndecoratedName);\n\t}\n\telse\n\t{\n\t\tManagedUndName = gcnew String(\"\");\n\t}\n\n\tif (UndecoratedName)\n\t{\n\t\tfree(UndecoratedName);\n\t}\n\n\tif (PvDecoratedName)\n\t{\n\t\tMarshal::FreeHGlobal(IntPtr((void*)PvDecoratedName));\n\t}\n\n\n\treturn gcnew Tuple<CLRPH_DEMANGLER, String^>(Demangler, ManagedUndName);\n}\n\nString^ PhSymbolProvider::UndecorateNamePrv(\n\t_In_ String ^DecoratedName,\n\t_In_ DemangleNameFn Demangler\n\n)\n{\n\tString ^ManagedUndName;\n\twchar_t* UndecoratedName = NULL;\n\tsize_t UndecoratedNameLen = 0;\n\t\n\tif (!m_Impl || DecoratedName->Length == 0) {\n\t\treturn gcnew String(\"\");\n\t}\n\t\n\twchar_t* PvDecoratedName = (wchar_t*)(Marshal::StringToHGlobalUni(DecoratedName)).ToPointer();\n\tsize_t PvDecoratedNameLen = wcslen(PvDecoratedName);\n\t\n\n\tif (Demangler(\n\t\tthis->m_Impl,\n\t\tPvDecoratedName,\n\t\tPvDecoratedNameLen,\n\t\t&UndecoratedName,\n\t\t&UndecoratedNameLen\n\t))\n\t{\n\t\tManagedUndName = gcnew String(UndecoratedName);\n\t}\n\telse\n\t{\n\t\tManagedUndName = gcnew String(\"\");\n\t}\n\n\tif (UndecoratedName) \n\t{\t\n\t\tfree(UndecoratedName);\n\t}\n\n\tif (PvDecoratedName)\n\t{\n\t\tMarshal::FreeHGlobal(IntPtr((void*)PvDecoratedName));\n\t}\n\n\n\treturn ManagedUndName;\n}"
  },
  {
    "path": "ClrPhlib/src/managed/Phlib.cpp",
    "content": "#include <ClrPhlib.h>\r\n#include <UnmanagedPh.h>\r\n#include <ApiSet.h>\r\n\r\n\r\n#include <phnative.h>\r\n#include <ntpsapi.h>\r\n\r\n\r\nusing namespace Dependencies;\r\nusing namespace ClrPh;\r\n\r\n// Private : build the known dlls list\r\nList<String^>^ BuildKnownDllList(_In_ bool Wow64Dlls);\r\nstatic bool bInitializedPhLib = false;\r\n\r\n\r\nbool Phlib::InitializePhLib()\r\n{\r\n\t\r\n\r\n\tif (!bInitializedPhLib)\r\n\t{\r\n\t\tbInitializedPhLib = NT_SUCCESS(PhInitializePhLib());\r\n\t}\r\n\r\n\tKnownDll64List = BuildKnownDllList(false);\r\n\tKnownDll32List = BuildKnownDllList(true);\r\n\r\n\treturn bInitializedPhLib;\r\n}\r\n\r\nBOOLEAN NTAPI PhEnumDirectoryObjectsCallback(\r\n\t_In_ PPH_STRINGREF Name,\r\n    _In_ PPH_STRINGREF TypeName,\r\n    _In_opt_ PVOID Context\r\n)\r\n{\r\n\tstatic PH_STRINGREF SectionTypeName = PH_STRINGREF_INIT(L\"Section\");\r\n\tList<String^>^ ReturnList = ((List<String^>^*) Context)[0];\r\n\r\n\tif (!PhCompareStringRef(&SectionTypeName, TypeName, TRUE)) {\r\n\t\tReturnList->Add(gcnew String(Name->Buffer));\r\n\t}\r\n\r\n\treturn TRUE;\r\n}\r\n\r\nList<String^>^ BuildKnownDllList(_In_ bool Wow64Dlls)\r\n{\r\n\tList<String^>^ ReturnList = gcnew List<String^>();\r\n\r\n\tHANDLE KnownDllDir = INVALID_HANDLE_VALUE;\r\n\tOBJECT_ATTRIBUTES oa;\r\n\tUNICODE_STRING name;\r\n\tNTSTATUS status;\r\n\t\r\n\tconst PWCHAR KnownDllObjectName = (Wow64Dlls) ? L\"\\\\KnownDlls32\" : L\"\\\\KnownDlls\";\r\n\r\n\tname.Length = (USHORT) wcslen(KnownDllObjectName) * sizeof(wchar_t);\r\n\tname.MaximumLength = (USHORT) wcslen(KnownDllObjectName) * sizeof(wchar_t);\r\n\tname.Buffer = KnownDllObjectName;\r\n\t\r\n\r\n\tInitializeObjectAttributes(\r\n\t\t&oa,\r\n\t\t&name,\r\n\t\t0,\r\n\t\tNULL,\r\n\t\tNULL\r\n\t);\r\n\r\n\tstatus = NtOpenDirectoryObject(\r\n\t\t&KnownDllDir,\r\n\t\tDIRECTORY_QUERY,\r\n\t\t&oa\r\n\t);\r\n\r\n\r\n\tif (!NT_SUCCESS(status)) {\r\n\t\treturn ReturnList;\r\n\t}\r\n\r\n\tstatus = PhEnumDirectoryObjects(\r\n\t\tKnownDllDir,\r\n\t\t(PPH_ENUM_DIRECTORY_OBJECTS) PhEnumDirectoryObjectsCallback,\r\n\t\t(PVOID) &ReturnList\r\n\t);\r\n\r\n\tif (!NT_SUCCESS(status)) {\r\n\t\treturn ReturnList;\r\n\t}\r\n\r\n\tReturnList->Sort();\r\n\treturn ReturnList;\r\n}\r\n\r\nList<String^>^ Phlib::GetKnownDlls(_In_ bool Wow64Dlls)\r\n{\r\n\tif (Wow64Dlls){\r\n\t\treturn Phlib::KnownDll32List;\r\n\t}\r\n\r\n\treturn Phlib::KnownDll64List;\r\n}\r\n\r\n#ifdef __cplusplus\r\nextern \"C\" {\r\n#endif\r\n\r\nPAPI_SET_NAMESPACE GetApiSetNamespace()\r\n{\r\n\tULONG\tReturnLength;\r\n\tPROCESS_BASIC_INFORMATION ProcessInformation;\r\n\tPAPI_SET_NAMESPACE apiSetMap = NULL;\r\n\r\n\t//\tRetrieve PEB address\r\n\tif (!NT_SUCCESS(NtQueryInformationProcess(\r\n\t\tGetCurrentProcess(),\r\n\t\tProcessBasicInformation,\r\n\t\t&ProcessInformation,\r\n\t\tsizeof(PROCESS_BASIC_INFORMATION),\r\n\t\t&ReturnLength\r\n\t)))\r\n\t{\r\n\t\treturn NULL;\r\n\t}\r\n\r\n\t//\tParsing PEB structure and locating api set map\r\n\tPPEB peb = static_cast<PPEB>(ProcessInformation.PebBaseAddress);\r\n\tapiSetMap =  static_cast<PAPI_SET_NAMESPACE>(peb->ApiSetMap);\r\n\r\n\treturn apiSetMap;\r\n}\r\n\r\n#ifdef __cplusplus\r\n}\r\n#endif\r\n\r\nstruct ApiSetSchemaImpl\r\n{\r\n    static ApiSetSchema^ ParseApiSetSchema(API_SET_NAMESPACE const * apiSetMap);\r\n\r\nprivate:\r\n    // private implementation of ApiSet schema parsing\r\n    static ApiSetSchema^ GetApiSetSchemaV2(API_SET_NAMESPACE_V2 const * map);\r\n    static ApiSetSchema^ GetApiSetSchemaV4(API_SET_NAMESPACE_V4 const * map);\r\n    static ApiSetSchema^ GetApiSetSchemaV6(API_SET_NAMESPACE_V6 const * map);\r\n};\r\n\r\nprivate ref class EmptyApiSetSchema sealed : ApiSetSchema\r\n{\r\npublic:\r\n    List<KeyValuePair<String^, ApiSetTarget^>>^ GetAll() override { return gcnew List<KeyValuePair<String^, ApiSetTarget^>>(); }\r\n    ApiSetTarget^ Lookup(String^) override { return nullptr; }\r\n};\r\n\r\nprivate ref class V2V4ApiSetSchema sealed : ApiSetSchema\r\n{\r\npublic:\r\n    List<KeyValuePair<String^, ApiSetTarget^>>^ const All = gcnew List<KeyValuePair<String^, ApiSetTarget^>>();\r\n\r\n    List<KeyValuePair<String^, ApiSetTarget^>>^ GetAll() override { return All; }\r\n    ApiSetTarget^ Lookup(String^ name) override\r\n    {\r\n\t\t// TODO : check if ext- is not present on win7 and 8.1\r\n        if (!name->StartsWith(\"api-\", System::StringComparison::CurrentCultureIgnoreCase))\r\n            return nullptr;\r\n\r\n\t\t// Force lowercase name\r\n\t\tname = name->ToLower();\r\n\r\n\t\t// remove \"api-\" or \"ext-\" prefix\r\n\t\tname = name->Substring(4);\r\n\r\n        // Note: The list is initially alphabetically sorted!!!\r\n        auto min = 0;\r\n        auto max = All->Count - 1;\r\n\t\twhile (min <= max)\r\n\t\t{\r\n\t\t\tauto const cur = (min + max) / 2;\r\n\t\t\tauto pair = All[cur];\r\n\r\n\t\t\tif (name->StartsWith(pair.Key, System::StringComparison::CurrentCultureIgnoreCase))\r\n\t\t\t\treturn pair.Value;\r\n\r\n\t\t\tif (String::CompareOrdinal(name, pair.Key) < 0)\r\n\t\t\t\tmax = cur - 1;\r\n\t\t\telse\r\n\t\t\t\tmin = cur + 1;\r\n\t\t}\r\n        return nullptr;\r\n    }\r\n};\r\n\r\nApiSetSchema^ ApiSetSchemaImpl::GetApiSetSchemaV2(API_SET_NAMESPACE_V2 const * const map)\r\n{\r\n\tauto const base = reinterpret_cast<ULONG_PTR>(map);\r\n\tauto const schema = gcnew V2V4ApiSetSchema();\r\n\tfor (auto it = map->Array, eit = it + map->Count; it < eit; ++it)\r\n\t{\r\n\t\t// Retrieve DLLs names implementing the contract\r\n\t\tauto const targets = gcnew ApiSetTarget();\r\n\t\tauto const value_entry = reinterpret_cast<PAPI_SET_VALUE_ENTRY_V2>(base + it->DataOffset);\r\n\t\tfor (auto it2 = value_entry->Redirections, eit2 = it2 + value_entry->NumberOfRedirections; it2 < eit2; ++it2)\r\n\t\t{\r\n\t\t\tauto const value_buffer = reinterpret_cast<PWCHAR>(base + it2->ValueOffset);\r\n\t\t\tauto const value = gcnew String(value_buffer, 0, it2->ValueLength / sizeof(WCHAR));\r\n\t\t\ttargets->Add(value);\r\n\t\t}\r\n\r\n\t\t// Retrieve api min-win contract name\r\n\t\tauto const name_buffer = reinterpret_cast<PWCHAR>(base + it->NameOffset);\r\n\t\tauto const name = gcnew String(name_buffer, 0, it->NameLength / sizeof(WCHAR));\r\n\r\n\t\t// force storing lowercase variant for comparison\r\n\t\tauto const lower_name = name->ToLower();\r\n\r\n\t\tschema->All->Add(KeyValuePair<String^, ApiSetTarget^>(lower_name, targets));\r\n\t}\r\n\treturn schema;\r\n}\r\n\r\nApiSetSchema^ ApiSetSchemaImpl::GetApiSetSchemaV4(API_SET_NAMESPACE_V4 const * const map)\r\n{\r\n\tauto const base = reinterpret_cast<ULONG_PTR>(map);\r\n\tauto const schema = gcnew V2V4ApiSetSchema();\r\n\tfor (auto it = map->Array, eit = it + map->Count; it < eit; ++it)\r\n\t{\r\n\t\t// Retrieve DLLs names implementing the contract\r\n\t\tauto const targets = gcnew ApiSetTarget();\r\n\t\tauto const value_entry = reinterpret_cast<PAPI_SET_VALUE_ENTRY_V4>(base + it->DataOffset);\r\n\t\tfor (auto it2 = value_entry->Redirections, eit2 = it2 + value_entry->NumberOfRedirections; it2 < eit2; ++it2)\r\n\t\t{\r\n\t\t\tauto const value_buffer = reinterpret_cast<PWCHAR>(base + it2->ValueOffset);\r\n\t\t\tauto const value = gcnew String(value_buffer, 0, it2->ValueLength / sizeof(WCHAR));\r\n\t\t\ttargets->Add(value);\r\n\t\t}\r\n\r\n\t\t// Retrieve api min-win contract name\r\n\t\tauto const name_buffer = reinterpret_cast<PWCHAR>(base + it->NameOffset);\r\n\t\tauto const name = gcnew String(name_buffer, 0, it->NameLength / sizeof(WCHAR));\r\n\r\n\t\t// force storing lowercase variant for comparison\r\n\t\tauto const lower_name = name->ToLower();\r\n\r\n\t\tschema->All->Add(KeyValuePair<String^, ApiSetTarget^>(lower_name, targets));\r\n\t}\r\n\treturn schema;\r\n}\r\n\r\nprivate ref class V6ApiSetSchema sealed : ApiSetSchema\r\n{\r\npublic:\r\n    List<KeyValuePair<String^, ApiSetTarget^>>^ const All = gcnew List<KeyValuePair<String^, ApiSetTarget^>>();\r\n    List<KeyValuePair<String^, ApiSetTarget^>>^ HashedAll = gcnew List<KeyValuePair<String^, ApiSetTarget^>>();\r\n\r\n    List<KeyValuePair<String^, ApiSetTarget^>>^ GetAll() override { return All; }\r\n    ApiSetTarget^ Lookup(String^ name) override\r\n    {\r\n\t\t// Force lowercase name\r\n\t\tname = name->ToLower();\r\n\r\n        // Note: The list is initially alphabetically sorted!!!\r\n        auto min = 0;\r\n        auto max = HashedAll->Count - 1;\r\n        while (min <= max)\r\n        {\r\n            auto const cur = (min + max) / 2;\r\n            auto pair = HashedAll[cur];\r\n            \r\n\t\t\tif (name->StartsWith(pair.Key, System::StringComparison::CurrentCultureIgnoreCase))\r\n\t\t\t\treturn pair.Value;\r\n\r\n            if (String::CompareOrdinal(name, pair.Key) < 0)\r\n                max = cur - 1;\r\n            else\r\n                min = cur + 1;\r\n        }\r\n        return nullptr;\r\n    }\r\n};\r\n\r\nApiSetSchema^ ApiSetSchemaImpl::GetApiSetSchemaV6(API_SET_NAMESPACE_V6 const * const map)\r\n{\r\n\tauto const base = reinterpret_cast<ULONG_PTR>(map);\r\n\tauto const schema = gcnew V6ApiSetSchema();\r\n\tfor (auto it = reinterpret_cast<PAPI_SET_NAMESPACE_ENTRY_V6>(map->EntryOffset + base), eit = it + map->Count; it < eit; ++it)\r\n\t{\r\n\t\t// Iterate over all the host dll for this contract\r\n\t\tauto const targets = gcnew ApiSetTarget();\r\n\t\tfor (auto it2 = static_cast<_API_SET_VALUE_ENTRY_V6*const>(reinterpret_cast<PAPI_SET_VALUE_ENTRY_V6>(base + it->ValueOffset)), eit2 = it2 + it->ValueCount; it2 < eit2; ++it2)\r\n\t\t{\r\n\t\t\t// Retrieve DLLs name implementing the contract\r\n\t\t\tauto const value_buffer = reinterpret_cast<PWCHAR>(base + it2->ValueOffset);\r\n\t\t\tauto const value = gcnew String(value_buffer, 0, it2->ValueLength / sizeof(WCHAR));\r\n\t\t\ttargets->Add(value);\r\n\t\t}\r\n\r\n\t\t// Retrieve api min-win contract name\r\n\t\tauto const name_buffer = reinterpret_cast<PWCHAR>(base + it->NameOffset);\r\n\t\tauto const name = gcnew String(name_buffer, 0, it->NameLength / sizeof(WCHAR));\r\n\t\tauto const hash_name = gcnew String(name_buffer, 0, it->HashedLength / sizeof(WCHAR));\r\n\r\n\t\t// force storing lowercase variant for comparison\r\n\t\tauto const lower_name = name->ToLower();\r\n\t\tauto const lower_hash_name = hash_name->ToLower();\r\n\r\n\t\tschema->All->Add(KeyValuePair<String^, ApiSetTarget^>(lower_name, targets));\r\n\t\tschema->HashedAll->Add(KeyValuePair<String^, ApiSetTarget^>(lower_hash_name, targets));\r\n\t}\r\n\treturn schema;\r\n}\r\n\r\nApiSetSchema^ Phlib::GetApiSetSchema()\r\n{\r\n    // Api set schema resolution adapted from https://github.com/zodiacon/WindowsInternals/blob/master/APISetMap/APISetMap.cpp\r\n    // References :\r\n    // \t\t* Windows Internals v7\r\n    // \t\t* @aionescu's slides on \"Hooking Nirvana\" (RECON 2015)\r\n    //\t\t* Quarkslab blog posts : \r\n    // \t\t\t\thttps://blog.quarkslab.com/runtime-dll-name-resolution-apisetschema-part-i.html\r\n    // \t\t\t\thttps://blog.quarkslab.com/runtime-dll-name-resolution-apisetschema-part-ii.html\r\n    return ApiSetSchemaImpl::ParseApiSetSchema(GetApiSetNamespace());\r\n}\r\n\r\nApiSetSchema^ PE::GetApiSetSchema()\r\n{\r\n    PH_MAPPED_IMAGE mappedImage = m_Impl->m_PvMappedImage;\r\n    for (auto n = 0u; n < mappedImage.NumberOfSections; ++n)\r\n    {\r\n        IMAGE_SECTION_HEADER const & section = mappedImage.Sections[n];\r\n        if (strncmp(\".apiset\", reinterpret_cast<char const*>(section.Name), IMAGE_SIZEOF_SHORT_NAME) == 0)\r\n            return ApiSetSchemaImpl::ParseApiSetSchema(reinterpret_cast<PAPI_SET_NAMESPACE>(PTR_ADD_OFFSET(mappedImage.ViewBase, section.PointerToRawData)));\r\n    }\r\n    return gcnew EmptyApiSetSchema();\r\n}\r\n\r\nApiSetSchema^ ApiSetSchemaImpl::ParseApiSetSchema(API_SET_NAMESPACE const * const apiSetMap)\r\n{\r\n\t// Check the returned api namespace is correct\r\n\tif (!apiSetMap)\r\n\t\treturn gcnew EmptyApiSetSchema();\r\n\r\n\tswitch (apiSetMap->Version) \r\n\t{\r\n\t\tcase 2: // Win7\r\n\t\t\treturn GetApiSetSchemaV2(&apiSetMap->ApiSetNameSpaceV2);\r\n\r\n\t\tcase 4: // Win8.1\r\n\t\t\treturn GetApiSetSchemaV4(&apiSetMap->ApiSetNameSpaceV4);\r\n\r\n\t\tcase 6: // Win10\r\n\t\t\treturn GetApiSetSchemaV6(&apiSetMap->ApiSetNameSpaceV6);\r\n\r\n\t\tdefault: // unsupported\r\n\t\t\treturn gcnew EmptyApiSetSchema();\r\n\t}\r\n}"
  },
  {
    "path": "ClrPhlib/src/unmanaged/UnmanagedPE.cpp",
    "content": "#include <ClrPhlib.h>\r\n#include <UnmanagedPh.h>\r\n#include <phnt_ntdef.h>\r\n\r\nusing namespace System;\r\nusing namespace Dependencies::ClrPh;\r\n\r\n\r\nUnmanagedPE::UnmanagedPE()\r\n        :m_bImageLoaded(false)\r\n{\r\n    memset(&m_PvMappedImage, 0, sizeof(PH_MAPPED_IMAGE));\r\n}\r\n\r\nUnmanagedPE::~UnmanagedPE()\r\n{\r\n    UnloadPE();\r\n}\r\n\r\nbool UnmanagedPE::LoadPE(LPWSTR Filepath)\r\n{\r\n    if (m_bImageLoaded)\r\n    {\r\n        PhUnloadMappedImage(&m_PvMappedImage);\r\n    }\r\n\r\n    memset(&m_PvMappedImage, 0, sizeof(PH_MAPPED_IMAGE));\r\n\r\n    m_bImageLoaded = NT_SUCCESS(PhLoadMappedImage(\r\n        Filepath,\r\n        NULL,\r\n        TRUE,\r\n        &m_PvMappedImage\r\n    ));\r\n\r\n    return m_bImageLoaded;\r\n}\r\n\r\nvoid UnmanagedPE::UnloadPE()\r\n{\r\n    if (m_bImageLoaded)\r\n    {\r\n        PhUnloadMappedImage(&m_PvMappedImage);\r\n        m_bImageLoaded = false;\r\n    }\r\n}\r\n\r\n\r\nbool UnmanagedPE::GetPeManifest(\r\n\t_Out_ BYTE* *manifest,\r\n    _Out_ INT  *manifestLen \r\n)\r\n{\r\n    PH_MAPPED_IMAGE_RESOURCES resources;\r\n    bool manifestFound = false;\r\n\r\n    if (!m_bImageLoaded)\r\n        return false;\r\n\r\n    if (!NT_SUCCESS(PhGetMappedImageResources(&resources, &m_PvMappedImage)))\r\n        return false;\r\n\r\n    *manifest = NULL;\r\n    *manifestLen = 0;\r\n\r\n\r\n    for (ULONG i = 0; i < resources.NumberOfEntries; i++)\r\n    {\r\n        PH_IMAGE_RESOURCE_ENTRY entry;\r\n\r\n        entry = resources.ResourceEntries[i];\r\n        if (entry.Type == (ULONG_PTR) RT_MANIFEST)\r\n        {  \r\n            // Manifest entry is utf-8 only\r\n            *manifest = (BYTE*)entry.Data;\r\n            *manifestLen = entry.Size;\r\n\r\n\t\t\tmanifestFound = true;\r\n        }\r\n\r\n        // stops on first manifest found\r\n        if (manifestFound)\r\n            break;\r\n    }\r\n\r\n    PhFree(resources.ResourceEntries);\r\n    return manifestFound;\r\n}"
  },
  {
    "path": "ClrPhlib/src/unmanaged/UnmanagedSymPrv.cpp",
    "content": "#include <UnmanagedSymPrv.h>\n\n\nusing namespace System;\nusing namespace Dependencies::ClrPh;\n\n#define DBGHELP_RELPATH \n\nVOID PvpGetDefaultPathForDbgHelp(\n\t_Inout_ PWSTR DefaultDbgHelpPath\n)\n{\n\n#if _WIN64\n\twsprintf((LPWSTR)DefaultDbgHelpPath, L\"%s%s\", _wgetenv(L\"ProgramFiles\"), L\"\\\\Windows Kits\\\\10\\\\Debuggers\\\\x64\\\\dbghelp.dll\");\n#define DBGHELP_PATH _wgetenv(L\"ProgramFiles\") L\"\" DBGHELP_RELPATH \n#else\n\tif (PhIsExecutingInWow64())\n\t{\n\t\twsprintf((LPWSTR)DefaultDbgHelpPath, L\"%s%s\", _wgetenv(L\"ProgramFiles(x86)\"), L\"\\\\Windows Kits\\\\10\\\\Debuggers\\\\x86\\\\dbghelp.dll\");\n\t}\n\telse\n\t{\n\t\twsprintf((LPWSTR)DefaultDbgHelpPath, L\"%s%s\", _wgetenv(L\"ProgramFiles\"), L\"\\\\Windows Kits\\\\10\\\\Debuggers\\\\x86\\\\dbghelp.dll\");\n\t}\n#endif // _WIN64\n\n}\n\n/*!\n\t@brief PhLoadLibrarySafe prevents the loader from searching in an unsafe\n\t order by first requiring the loader try to load and resolve through\n\t System32. Then upping the loading flags until the library is loaded.\n\n\t@param[in] LibFileName - The file name of the library to load.\n\n\t@return HMODULE to the library on success, null on failure.\n*/\n_Ret_maybenull_\nPVOID\nPhLoadLibrarySafe(\n\t_In_ PCWSTR LibFileName\n)\n{\n\tPVOID baseAddress;\n\n\t//\n\t// Force LOAD_LIBRARY_SEARCH_SYSTEM32. If the library file name is a fully\n\t// qualified path this will succeed.\n\t//\n\tbaseAddress = LoadLibraryExW(LibFileName,\n\t\tNULL,\n\t\tLOAD_LIBRARY_SEARCH_SYSTEM32);\n\tif (baseAddress)\n\t{\n\t\treturn baseAddress;\n\t}\n\n\t//\n\t// Include the application directory now.\n\t//\n\treturn LoadLibraryExW(LibFileName,\n\t\tNULL,\n\t\tLOAD_LIBRARY_SEARCH_SYSTEM32 |\n\t\tLOAD_LIBRARY_SEARCH_APPLICATION_DIR);\n}\n\nVOID PvpLoadDbgHelpFromPath(\n    _In_ PWSTR DbgHelpPath\n)\n{\n    HMODULE dbghelpModule;\n\t\n\t// try to load from windows kits installed on the machine\n\tdbghelpModule = LoadLibrary(DbgHelpPath);\n\n\t// try system32, and then current dir\n\tif (!dbghelpModule)\n\t{\n\t\tdbghelpModule = (HMODULE) PhLoadLibrarySafe(L\"dbghelp.dll\");\n\t}\n\n\t// try to load symsrv.dll from the same folder as dbghelp.dll\n    if (dbghelpModule)\n    {\n        PPH_STRING fullDbghelpPath;\n        ULONG indexOfFileName;\n        PH_STRINGREF dbghelpFolder;\n        PPH_STRING symsrvPath;\n\n        fullDbghelpPath = PhGetDllFileName(dbghelpModule, &indexOfFileName);\n\n        if (fullDbghelpPath)\n        {\n            if (indexOfFileName != 0)\n            {\n                static PH_STRINGREF symsrvString = PH_STRINGREF_INIT(L\"\\\\symsrv.dll\");\n\n                dbghelpFolder.Buffer = fullDbghelpPath->Buffer;\n                dbghelpFolder.Length = indexOfFileName * sizeof(WCHAR);\n\n                symsrvPath = PhConcatStringRef2(&dbghelpFolder, &symsrvString);\n\n                LoadLibrary(symsrvPath->Buffer);\n\n                PhDereferenceObject(symsrvPath);\n            }\n\n            PhDereferenceObject(fullDbghelpPath);\n        }\n\n\t\tPhSymbolProviderCompleteInitialization(dbghelpModule);\n    }\n    //else\n    //{\n    //    dbghelpModule = LoadLibrary(L\"dbghelp.dll\");\n    //}\n\n    /*PhSymbolProviderCompleteInitialization(dbghelpModule);*/\n}\n\nBOOLEAN PvpLoadDbgHelp(\n    _Inout_ PPH_SYMBOL_PROVIDER *SymbolProvider\n)\n{\n    static UNICODE_STRING symbolPathVarName = RTL_CONSTANT_STRING(L\"_NT_SYMBOL_PATH\");\n    PPH_STRING symbolSearchPath;\n    PPH_SYMBOL_PROVIDER symbolProvider;\n    WCHAR buffer[MAX_PATH] = L\"\";\n    UNICODE_STRING symbolPathUs;\n\tconst wchar_t DefaultDbgHelpPath[MAX_PATH] = { 0 };\n\n    \n    symbolPathUs.Buffer = buffer;\n    symbolPathUs.Length = sizeof(buffer) - sizeof(UNICODE_NULL);\n    symbolPathUs.MaximumLength = sizeof(buffer);\n    \n\n    if (!PhSymbolProviderInitialization())\n        return FALSE;\n\n\tPvpGetDefaultPathForDbgHelp((PWSTR)DefaultDbgHelpPath);\n    PvpLoadDbgHelpFromPath((PWSTR)DefaultDbgHelpPath);\n\n    symbolProvider = PhCreateSymbolProvider(NULL);\n\n    // Load symbol path from _NT_SYMBOL_PATH if configured by the user.    \n    if (NT_SUCCESS(RtlQueryEnvironmentVariable_U(NULL, &symbolPathVarName, &symbolPathUs)))\n    {\n        symbolSearchPath = PhFormatString(L\"SRV*%s*http://msdl.microsoft.com/download/symbols\", symbolPathUs.Buffer);\n    }\n    else\n    {\n        symbolSearchPath = PhCreateString(L\"SRV**http://msdl.microsoft.com/download/symbols\");\n    }\n\n    PhSetSearchPathSymbolProvider(symbolProvider, symbolSearchPath->Buffer);\n    PhDereferenceObject(symbolSearchPath);\n\n    *SymbolProvider = symbolProvider;\n    return TRUE;\n}\n\n\nUnmanagedSymPrv* UnmanagedSymPrv::Create()\n{\n    UnmanagedSymPrv *Instance = new UnmanagedSymPrv;\n    \n    if (!PvpLoadDbgHelp(&Instance->m_SymbolProvider)) {\n        delete Instance;\n        return NULL;\n    }\n\n    return Instance;\n}"
  },
  {
    "path": "ClrPhlib/src/unmanaged/demangle.cpp",
    "content": "#include <UnmanagedSymPrv.h>\n#include <llvm/Demangle/Demangle.h>\n#include <stdlib.h>\n#using <System.dll>\n\nextern \"C\" {\n\tchar* __cxa_demangle(const char* mangled_name,\n\t\tchar* buf,\n\t\tsize_t* n,\n\t\tint* status);\n}\n\n#define DEMANGLER_DEBUGLOG_ON\t\t(false)\n#define DEMANGLER_DEBUGLOG_CAT (\"demangler\")\n#define DEMANGLER_DEBUGLOG_ONE (DemanglerDebugOneArg)\n#define DEMANGLER_DEBUGLOG_TWO (DemanglerDebugTwoArg)\n\nvoid DemanglerDebugOneArg(wchar_t *Format, wchar_t *Arg0)\n{\n\tif (!DEMANGLER_DEBUGLOG_ON)\n\t\treturn;\n\n\tdo\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\n\t{\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\n\t\tSystem::Diagnostics::Debug::WriteLine(\t\t\t\t\t\t\t\t\t\t\t\t\t\n\t\t\tSystem::String::Format(\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\n\t\t\t\tgcnew System::String(Format),\t\t\t\t\t\t\t\t\t\t\t\t\t\n\t\t\t\tgcnew System::String(Arg0)\n\t\t\t),\t\t\t\t\t\t\t\t\t\t\t\t\t\n\t\t\tgcnew System::String(DEMANGLER_DEBUGLOG_CAT)\n\t\t);\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\n\t} while (false);\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\n}\n\nvoid DemanglerDebugTwoArg(wchar_t *Format, wchar_t *Arg0, wchar_t *Arg1)\n{\n\tif (!DEMANGLER_DEBUGLOG_ON)\n\t\treturn;\n\n\tdo\n\t{\n\t\tSystem::Diagnostics::Debug::WriteLine(\n\t\t\tSystem::String::Format(\n\t\t\t\tgcnew System::String(Format),\n\t\t\t\tgcnew System::String(Arg0),\n\t\t\t\tgcnew System::String(Arg1)\n\t\t\t),\n\t\t\tgcnew System::String(DEMANGLER_DEBUGLOG_CAT)\n\t\t);\n\t} while (false);\n}\n\n\nbool DemumbleDemangleName(\n\t_In_ UnmanagedSymPrv* obj,\n\t_In_ wchar_t* DecoratedName,\n\t_In_ size_t DecoratedNameLen,\n\t_Out_ wchar_t** UndecoratedName,\n\t_Out_ size_t* UndecoratedNameLen\n)\n{\n\tsize_t NameLen;\n\tint status;\n\tsize_t MbstowcsStatus = 0;\n\tchar *AsciiUndecoratedName = NULL;\n\n\n\tchar *DecoratedNameAscii = (char*)malloc(DecoratedNameLen + 1);\n\tsprintf_s(DecoratedNameAscii, DecoratedNameLen + 1, \"%ws\", DecoratedName);\n\n\tif ((!UndecoratedName) || (!UndecoratedNameLen)) {\n\t\treturn false;\n\t}\n\n\t*UndecoratedNameLen = 0;\n\tNameLen = DecoratedNameLen;\n\n\tAsciiUndecoratedName = __cxa_demangle(\n\t\tDecoratedNameAscii,\n\t\tNULL,\n\t\t&NameLen,\n\t\t&status\n\t);\n\n\tif (!status) {\n\t\t*UndecoratedName = (wchar_t*)malloc(NameLen * sizeof(wchar_t) + sizeof(wchar_t));\n\n\t\tmbstowcs_s(\n\t\t\t&MbstowcsStatus,\n\t\t\t*UndecoratedName,\n\t\t\tNameLen,\n\t\t\tAsciiUndecoratedName,\n\t\t\tNameLen\n\t\t);\n\n\t\t*UndecoratedNameLen = NameLen * sizeof(wchar_t);\n\t}\n\n\tfree(DecoratedNameAscii);\n\n\t// UNIX-style error code\n\treturn status == 0;\n}\n\nbool LLVMItaniumDemangleName(\n\t_In_ UnmanagedSymPrv* obj,\n\t_In_ wchar_t* DecoratedName,\n\t_In_ size_t DecoratedNameLen,\n\t_Out_ wchar_t** UndecoratedName,\n\t_Out_ size_t* UndecoratedNameLen\n)\n{\n\tsize_t NameLen;\n\tint status;\n\tsize_t MbstowcsStatus = 0;\n\tchar *AsciiUndecoratedName = NULL;\n\n\n\tchar *DecoratedNameAscii = (char*)malloc(DecoratedNameLen + 1);\n\tsprintf_s(DecoratedNameAscii, DecoratedNameLen + 1, \"%ws\", DecoratedName);\n\n\tif ((!UndecoratedName) || (!UndecoratedNameLen)) {\n\t\treturn false;\n\t}\n\n\t*UndecoratedNameLen = 0;\n\tNameLen = DecoratedNameLen;\n\n\tAsciiUndecoratedName = llvm::itaniumDemangle(\n\t\tDecoratedNameAscii,\n\t\tnullptr,\n\t\t&NameLen,\n\t\t&status\n\t);\n\n\tif (!status) {\n\t\t*UndecoratedName = (wchar_t*)malloc(NameLen * sizeof(wchar_t) + sizeof(wchar_t));\n\n\t\tmbstowcs_s(\n\t\t\t&MbstowcsStatus,\n\t\t\t*UndecoratedName,\n\t\t\tNameLen,\n\t\t\tAsciiUndecoratedName,\n\t\t\tNameLen\n\t\t);\n\n\t\t*UndecoratedNameLen = NameLen * sizeof(wchar_t);\n\t}\n\t\n\tfree(DecoratedNameAscii);\n\n\t// UNIX-style error code\n\treturn status == 0;\n}\n\nbool LLVMMicrosoftDemangleName(\n\t_In_ UnmanagedSymPrv* obj,\n\t_In_ wchar_t* DecoratedName,\n\t_In_ size_t DecoratedNameLen,\n\t_Out_ wchar_t** UndecoratedName,\n\t_Out_ size_t* UndecoratedNameLen\n)\n{\n\tsize_t NameLen;\n\tint status;\n\tsize_t MbstowcsStatus = 0;\n\tchar *AsciiUndecoratedName = NULL;\n\n\n\tchar *DecoratedNameAscii = (char*)malloc(DecoratedNameLen + 1);\n\tsprintf_s(DecoratedNameAscii, DecoratedNameLen + 1, \"%ws\", DecoratedName);\n\n\tif ((!UndecoratedName) || (!UndecoratedNameLen)) {\n\t\treturn false;\n\t}\n\n\t*UndecoratedNameLen = 0;\n\tNameLen = DecoratedNameLen;\n\n\tAsciiUndecoratedName = llvm::microsoftDemangle(\n\t\tDecoratedNameAscii,\n\t\tnullptr,\n\t\t&NameLen,\n\t\t&status\n\t);\n\n\tif (!status) {\n\t\t*UndecoratedName = (wchar_t*)malloc(NameLen * sizeof(wchar_t) + sizeof(wchar_t));\n\n\t\tmbstowcs_s(\n\t\t\t&MbstowcsStatus,\n\t\t\t*UndecoratedName,\n\t\t\tNameLen, \n\t\t\tAsciiUndecoratedName,\n\t\t\tNameLen \n\t\t);\n\n\t\t*UndecoratedNameLen = NameLen * sizeof(wchar_t);\n\t}\n\n\tfree(DecoratedNameAscii);\n\n\t// UNIX-style error code\n\treturn status == 0;\n}\n\nbool UndecorateSymbolDemangleName(\n\t_In_ UnmanagedSymPrv* obj,\n\t_In_ wchar_t* DecoratedName,\n\t_In_ size_t DecoratedNameLen,\n\t_Out_ wchar_t** UndecoratedName,\n\t_Out_ size_t* UndecoratedNameLen\n)\n{\n\tPPH_STRING PhUndecoratedName = NULL;\n\twchar_t* Undname = NULL;\n\n\tif ((!UndecoratedName) || (!UndecoratedNameLen)) {\n\t\treturn false;\n\t}\n\n\tPhUndecoratedName = PhUndecorateNameW(\n\t\tobj->m_SymbolProvider,\n\t\tDecoratedName\n\t);\n\n\tif (!PhUndecoratedName)\n\t{\n\t\treturn false;\n\t}\n\n\tif (!wcsncmp(PhUndecoratedName->Buffer, DecoratedName, PhUndecoratedName->Length))\n\t{\n\t\tPhDereferenceObject(PhUndecoratedName);\n\t\treturn false;\n\t}\n\n\t\n\tUndname = (wchar_t*)calloc(PhUndecoratedName->Length + sizeof(wchar_t), 1);\n\tif (!Undname)\n\t{\n\t\tPhDereferenceObject(PhUndecoratedName);\n\t\treturn false;\n\t}\n\n\tmemcpy(Undname, PhUndecoratedName->Buffer, PhUndecoratedName->Length);\n\n\t*UndecoratedNameLen = PhUndecoratedName->Length;\n\t*UndecoratedName = Undname;\n\n\tPhDereferenceObject(PhUndecoratedName);\n\treturn true;\n}\n\nbool UnmanagedSymPrv::DemangleName(\n\t_In_ wchar_t* DecoratedName,\n\t_In_ size_t DecoratedNameLen,\n\t_Out_ wchar_t** UndecoratedName,\n\t_Out_ size_t* UndecoratedNameLen,\n\t_Out_ Dependencies::ClrPh::CLRPH_DEMANGLER *Demangler\n)\n{\n\n\t// try to undecorate GCC/LLVM symbols using demumble\n\tif (DemumbleDemangleName(\n\t\tthis,\n\t\tDecoratedName,\n\t\tDecoratedNameLen,\n\t\tUndecoratedName,\n\t\tUndecoratedNameLen\n\t)) {\n\t\t*Demangler = Dependencies::ClrPh::CLRPH_DEMANGLER::Demumble;\n\t\tDEMANGLER_DEBUGLOG_TWO(L\"Demumble {0:s} -> {1:s}\", DecoratedName, *UndecoratedName);\n\t\treturn true;\n\t}\n\n\t// try llvm-demangler. the heuristic is copied from .\\llvm-7.0.0.src\\lib\\DebugInfo\\Symbolize\\Symbolize.cpp: LLVMSymbolizer::DemangleName\n\tif (!_wcsnicmp(DecoratedName, L\"_Z\", 2))\n\t{ \n\t\tif (LLVMItaniumDemangleName(\n\t\t\tthis,\n\t\t\tDecoratedName,\n\t\t\tDecoratedNameLen,\n\t\t\tUndecoratedName,\n\t\t\tUndecoratedNameLen\n\t\t)) {\n\t\t\t*Demangler = Dependencies::ClrPh::CLRPH_DEMANGLER::LLVMItanium;\n\t\t\tDEMANGLER_DEBUGLOG_TWO(L\"LLVM Itanium {0:s} -> {1:s}\", DecoratedName, *UndecoratedName);\n\t\t\treturn true;\n\t\t}\n\t}\n\n\t// try to undecorate MSVC symbols using UndecorateName  \n\tif (UndecorateSymbolDemangleName(\n\t\tthis,\n\t\tDecoratedName,\n\t\tDecoratedNameLen,\n\t\tUndecoratedName,\n\t\tUndecoratedNameLen\n\t)) {\n\t\t*Demangler = Dependencies::ClrPh::CLRPH_DEMANGLER::Microsoft;\n\t\tDEMANGLER_DEBUGLOG_TWO(L\"Microsoft {0:s} -> {1:s}\", DecoratedName, *UndecoratedName);\n\t\treturn true;\n\t}\n\n\t// use llvm::microsoftDemangle as a last chance\n\tif (LLVMMicrosoftDemangleName(\n\t\tthis,\n\t\tDecoratedName,\n\t\tDecoratedNameLen,\n\t\tUndecoratedName,\n\t\tUndecoratedNameLen\n\t)) {\n\t\t*Demangler = Dependencies::ClrPh::CLRPH_DEMANGLER::LLVMMicrosoft;\n\t\tDEMANGLER_DEBUGLOG_TWO(L\"LLVM Microsoft {0:s} -> {1:s}\", DecoratedName, *UndecoratedName);\n\t\treturn true;\n\t}\n\t\n\n\t// Could not demangle name\n\t*UndecoratedNameLen =  0;\n\t*UndecoratedName = NULL;\n\t*Demangler = Dependencies::ClrPh::CLRPH_DEMANGLER::None;\n\tDEMANGLER_DEBUGLOG_ONE(L\"Could not demangle \\\"{0:s}\\\" properly\", DecoratedName);\n\treturn false;\n}\n\n"
  },
  {
    "path": "Dependencies/App.config",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\r\n<configuration>\r\n    <startup> \r\n        <supportedRuntime version=\"v4.0\" sku=\".NETFramework,Version=v4.6.1\"/>\r\n    </startup>\r\n</configuration>\r\n"
  },
  {
    "path": "Dependencies/Dependencies.csproj",
    "content": "﻿<?xml version=\"1.0\" encoding=\"utf-8\"?>\r\n<Project ToolsVersion=\"15.0\" xmlns=\"http://schemas.microsoft.com/developer/msbuild/2003\">\r\n  <Import Project=\"$(MSBuildExtensionsPath)\\$(MSBuildToolsVersion)\\Microsoft.Common.props\" Condition=\"Exists('$(MSBuildExtensionsPath)\\$(MSBuildToolsVersion)\\Microsoft.Common.props')\" />\r\n  <PropertyGroup>\r\n    <Configuration Condition=\" '$(Configuration)' == '' \">Debug</Configuration>\r\n    <Platform Condition=\" '$(Platform)' == '' \">AnyCPU</Platform>\r\n    <ProjectGuid>{5565A612-B250-4FE0-98DD-07C56916C194}</ProjectGuid>\r\n    <OutputType>Exe</OutputType>\r\n    <RootNamespace>Dependencies</RootNamespace>\r\n    <AssemblyName>Dependencies</AssemblyName>\r\n    <TargetFrameworkVersion>v4.6.1</TargetFrameworkVersion>\r\n    <FileAlignment>512</FileAlignment>\r\n    <AutoGenerateBindingRedirects>true</AutoGenerateBindingRedirects>\r\n    <TargetFrameworkProfile />\r\n  </PropertyGroup>\r\n  <PropertyGroup>\r\n    <StartupObject>Dependencies.Program</StartupObject>\r\n  </PropertyGroup>\r\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)' == 'Debug|x86'\">\r\n    <DebugSymbols>true</DebugSymbols>\r\n    <OutputPath>$(SolutionDir)bin\\$(Configuration)$(Platform)</OutputPath>\r\n    <IntermediateOutputPath>$(SolutionDir)obj\\$(ProjectName)\\$(Configuration)$(Platform)</IntermediateOutputPath>\r\n    <DefineConstants>DEBUG;TRACE</DefineConstants>\r\n    <DebugType>full</DebugType>\r\n    <PlatformTarget>x86</PlatformTarget>\r\n    <ErrorReport>prompt</ErrorReport>\r\n    <CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>\r\n  </PropertyGroup>\r\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)' == 'Release|x86'\">\r\n    <OutputPath>$(SolutionDir)bin\\$(Configuration)$(Platform)</OutputPath>\r\n    <IntermediateOutputPath>$(SolutionDir)obj\\$(ProjectName)\\$(Configuration)$(Platform)</IntermediateOutputPath>\r\n    <DefineConstants>TRACE</DefineConstants>\r\n    <Optimize>true</Optimize>\r\n    <DebugType>pdbonly</DebugType>\r\n    <PlatformTarget>x86</PlatformTarget>\r\n    <ErrorReport>prompt</ErrorReport>\r\n    <CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>\r\n    <Prefer32Bit>true</Prefer32Bit>\r\n  </PropertyGroup>\r\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)' == 'Debug|x64'\">\r\n    <DebugSymbols>true</DebugSymbols>\r\n    <OutputPath>$(SolutionDir)bin\\$(Configuration)$(Platform)</OutputPath>\r\n    <IntermediateOutputPath>$(SolutionDir)obj\\$(ProjectName)\\$(Configuration)$(Platform)</IntermediateOutputPath>\r\n    <DefineConstants>DEBUG;TRACE</DefineConstants>\r\n    <DebugType>full</DebugType>\r\n    <PlatformTarget>x64</PlatformTarget>\r\n    <ErrorReport>prompt</ErrorReport>\r\n    <CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>\r\n  </PropertyGroup>\r\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)' == 'Release|x64'\">\r\n    <OutputPath>$(SolutionDir)bin\\$(Configuration)$(Platform)</OutputPath>\r\n    <IntermediateOutputPath>$(SolutionDir)obj\\$(ProjectName)\\$(Configuration)$(Platform)</IntermediateOutputPath>\r\n    <DefineConstants>TRACE</DefineConstants>\r\n    <Optimize>true</Optimize>\r\n    <DebugType>pdbonly</DebugType>\r\n    <PlatformTarget>x64</PlatformTarget>\r\n    <ErrorReport>prompt</ErrorReport>\r\n    <CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>\r\n    <Prefer32Bit>true</Prefer32Bit>\r\n  </PropertyGroup>\r\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)' == 'Appx|x86'\">\r\n    <OutputPath>$(SolutionDir)bin\\$(Configuration)$(Platform)</OutputPath>\r\n    <IntermediateOutputPath>$(SolutionDir)obj\\$(ProjectName)\\$(Configuration)$(Platform)</IntermediateOutputPath>\r\n    <DefineConstants>TRACE</DefineConstants>\r\n    <Optimize>true</Optimize>\r\n    <DebugType>pdbonly</DebugType>\r\n    <PlatformTarget>x86</PlatformTarget>\r\n    <ErrorReport>prompt</ErrorReport>\r\n    <CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>\r\n    <Prefer32Bit>true</Prefer32Bit>\r\n  </PropertyGroup>\r\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)' == 'Appx|x64'\">\r\n    <OutputPath>$(SolutionDir)bin\\$(Configuration)$(Platform)</OutputPath>\r\n    <IntermediateOutputPath>$(SolutionDir)obj\\$(ProjectName)\\$(Configuration)$(Platform)</IntermediateOutputPath>\r\n    <DefineConstants>TRACE</DefineConstants>\r\n    <Optimize>true</Optimize>\r\n    <DebugType>pdbonly</DebugType>\r\n    <PlatformTarget>x64</PlatformTarget>\r\n    <ErrorReport>prompt</ErrorReport>\r\n    <CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>\r\n    <Prefer32Bit>true</Prefer32Bit>\r\n  </PropertyGroup>\r\n  <ItemGroup>\r\n    <Reference Include=\"Mono.Cecil, Version=0.11.4.0, Culture=neutral, PublicKeyToken=50cebf1cceb9d05e, processorArchitecture=MSIL\">\r\n      <HintPath>..\\packages\\Mono.Cecil.0.11.4\\lib\\net40\\Mono.Cecil.dll</HintPath>\r\n    </Reference>\r\n    <Reference Include=\"Mono.Cecil.Mdb, Version=0.11.4.0, Culture=neutral, PublicKeyToken=50cebf1cceb9d05e, processorArchitecture=MSIL\">\r\n      <HintPath>..\\packages\\Mono.Cecil.0.11.4\\lib\\net40\\Mono.Cecil.Mdb.dll</HintPath>\r\n    </Reference>\r\n    <Reference Include=\"Mono.Cecil.Pdb, Version=0.11.4.0, Culture=neutral, PublicKeyToken=50cebf1cceb9d05e, processorArchitecture=MSIL\">\r\n      <HintPath>..\\packages\\Mono.Cecil.0.11.4\\lib\\net40\\Mono.Cecil.Pdb.dll</HintPath>\r\n    </Reference>\r\n    <Reference Include=\"Mono.Cecil.Rocks, Version=0.11.4.0, Culture=neutral, PublicKeyToken=50cebf1cceb9d05e, processorArchitecture=MSIL\">\r\n      <HintPath>..\\packages\\Mono.Cecil.0.11.4\\lib\\net40\\Mono.Cecil.Rocks.dll</HintPath>\r\n    </Reference>\r\n    <Reference Include=\"NDesk.Options, Version=0.2.1.0, Culture=neutral, processorArchitecture=MSIL\">\r\n      <HintPath>..\\packages\\NDesk.Options.0.2.1\\lib\\NDesk.Options.dll</HintPath>\r\n    </Reference>\r\n    <Reference Include=\"Newtonsoft.Json, Version=13.0.0.0, Culture=neutral, PublicKeyToken=30ad4fe6b2a6aeed, processorArchitecture=MSIL\">\r\n      <HintPath>..\\packages\\Newtonsoft.Json.13.0.1\\lib\\net45\\Newtonsoft.Json.dll</HintPath>\r\n    </Reference>\r\n    <Reference Include=\"System\" />\r\n    <Reference Include=\"System.Core\" />\r\n    <Reference Include=\"System.Xml.Linq\" />\r\n    <Reference Include=\"System.Data.DataSetExtensions\" />\r\n    <Reference Include=\"Microsoft.CSharp\" />\r\n    <Reference Include=\"System.Data\" />\r\n    <Reference Include=\"System.Net.Http\" />\r\n    <Reference Include=\"System.Xml\" />\r\n  </ItemGroup>\r\n  <ItemGroup>\r\n    <Compile Include=\"Program.cs\" />\r\n    <Compile Include=\"Properties\\AssemblyInfo.cs\" />\r\n  </ItemGroup>\r\n  <ItemGroup>\r\n    <None Include=\"App.config\">\r\n      <SubType>Designer</SubType>\r\n    </None>\r\n    <None Include=\"packages.config\" />\r\n  </ItemGroup>\r\n  <ItemGroup>\r\n    <ProjectReference Include=\"..\\ClrPhlib\\ClrPhlib.vcxproj\">\r\n      <Project>{fc5ffcaf-982f-4a95-8fa6-2a95b1f7cdc8}</Project>\r\n      <Name>ClrPhlib</Name>\r\n    </ProjectReference>\r\n    <ProjectReference Include=\"..\\DependenciesLib\\DependenciesLib.csproj\">\r\n      <Project>{4a459493-14fc-4c87-9254-60e0959535da}</Project>\r\n      <Name>DependenciesLib</Name>\r\n    </ProjectReference>\r\n  </ItemGroup>\r\n  <ItemGroup>\r\n    <WCFMetadata Include=\"Connected Services\\\" />\r\n  </ItemGroup>\r\n  <Import Project=\"$(MSBuildToolsPath)\\Microsoft.CSharp.targets\" />\r\n</Project>"
  },
  {
    "path": "Dependencies/Program.cs",
    "content": "﻿using System;\nusing System.Collections.Generic;\nusing System.Xml.Linq;\nusing System.IO;\nusing System.Linq;\nusing System.Diagnostics;\n\nusing NDesk.Options;\nusing Newtonsoft.Json;\nusing Dependencies.ClrPh;\nusing Mono.Cecil;\n\nnamespace Dependencies\n{\n    \n    interface IPrettyPrintable\n    {\n        void PrettyPrint();\n    }\n\n    /// <summary>\n    /// Printable KnownDlls object\n    /// </summary>\n    class NtKnownDlls : IPrettyPrintable\n    {\n        public NtKnownDlls()\n        {\n            x64 = Phlib.GetKnownDlls(false);\n            x86 = Phlib.GetKnownDlls(true);\n        }\n\n        public void PrettyPrint()\n        {\n            Console.WriteLine(\"[-] 64-bit KnownDlls : \");\n\n            foreach (String KnownDll in this.x64)\n            {\n                string System32Folder = Environment.GetFolderPath(Environment.SpecialFolder.System);\n                Console.WriteLine(\"  {0:s}\\\\{1:s}\", System32Folder, KnownDll);\n            }\n\n            Console.WriteLine(\"\");\n\n            Console.WriteLine(\"[-] 32-bit KnownDlls : \");\n\n            foreach (String KnownDll in this.x86)\n            {\n                string SysWow64Folder = Environment.GetFolderPath(Environment.SpecialFolder.SystemX86);\n                Console.WriteLine(\"  {0:s}\\\\{1:s}\", SysWow64Folder, KnownDll);\n            }\n\n\n            Console.WriteLine(\"\");\n        }\n\n        public List<String> x64;\n        public List<String> x86;\n    }\n\n    /// <summary>\n    /// Printable ApiSet schema object\n    /// </summary>\n    class NtApiSet : IPrettyPrintable\n    {\n        public NtApiSet()\n        {\n            Schema = Phlib.GetApiSetSchema();\n        }\n\n        public NtApiSet(PE ApiSetSchemaDll)\n        {\n          Schema = ApiSetSchemaDll.GetApiSetSchema();\n        }\n\n        public void PrettyPrint()\n        {\n            Console.WriteLine(\"[-] Api Sets Map : \");\n\n            foreach (var ApiSetEntry in this.Schema.GetAll())\n            {\n                ApiSetTarget ApiSetImpl = ApiSetEntry.Value;\n                string ApiSetName = ApiSetEntry.Key;\n                string ApiSetImplStr = (ApiSetImpl.Count > 0) ? String.Join(\",\", ApiSetImpl.ToArray()) : \"\";\n\n                Console.WriteLine(\"{0:s} -> [ {1:s} ]\", ApiSetName, ApiSetImplStr);\n            }\n\n            Console.WriteLine(\"\");\n        }\n\n        public ApiSetSchema Schema;\n    }\n\n\n    class PEManifest : IPrettyPrintable\n    {\n\n        public PEManifest(PE _Application)\n        {\n            Application = _Application;\n            Manifest = Application.GetManifest();\n            XmlManifest = null;\n            Exception = \"\";\n\n            if (Manifest.Length != 0)\n            {\n                try\n                {\n                    // Use a memory stream to correctly handle BOM encoding for manifest resource\n                    using (var stream = new System.IO.MemoryStream(System.Text.Encoding.UTF8.GetBytes(Manifest)))\n                    {\n                        XmlManifest = SxsManifest.ParseSxsManifest(stream);\n                    }\n                    \n\n                }\n                catch (System.Xml.XmlException e)\n                {\n                    //Console.Error.WriteLine(\"[x] \\\"Malformed\\\" pe manifest for file {0:s} : {1:s}\", Application.Filepath, PeManifest);\n                    //Console.Error.WriteLine(\"[x] Exception : {0:s}\", e.ToString());\n                    XmlManifest = null;\n                    Exception = e.ToString();\n                }\n            }\n        }\n\n\n        public void PrettyPrint()\n        {\n            Console.WriteLine(\"[-] Manifest for file : {0}\", Application.Filepath);\n\n            if (Manifest.Length == 0)\n            {\n                Console.WriteLine(\"[x] No embedded pe manifest for file {0:s}\", Application.Filepath);\n                return;\n            }\n\n            if (Exception.Length != 0)\n            {\n                Console.Error.WriteLine(\"[x] \\\"Malformed\\\" pe manifest for file {0:s} : {1:s}\", Application.Filepath, Manifest);\n                Console.Error.WriteLine(\"[x] Exception : {0:s}\", Exception);\n                return;\n            }\n\n            Console.WriteLine(XmlManifest);\n        }\n\n        public string Manifest;\n        public XDocument XmlManifest;\n\n        // stays private in order not end up in the json output\n        private PE Application;\n        private string Exception;\n    }\n\n    class PEImports : IPrettyPrintable\n    {\n        public PEImports(PE _Application)\n        {\n            Application = _Application;\n            Imports = Application.GetImports();\n        } \n\n        public void PrettyPrint()\n        {\n            Console.WriteLine(\"[-] Import listing for file : {0}\", Application.Filepath);\n\n            foreach (PeImportDll DllImport in Imports)\n            {\n                Console.WriteLine(\"Import from module {0:s} :\", DllImport.Name);\n\n                foreach (PeImport Import in DllImport.ImportList)\n                {\n                    if (Import.ImportByOrdinal)\n                    {\n                        Console.Write(\"\\t Ordinal_{0:d} \", Import.Ordinal);\n                    }\n                    else\n                    {\n                        Console.Write(\"\\t Function {0:s}\", Import.Name);\n                    }\n                    if (Import.DelayImport)\n                        Console.WriteLine(\" (Delay Import)\");\n                    else\n                        Console.WriteLine(\"\");\n                }\n            }\n\n            Console.WriteLine(\"[-] Import listing done\");\n        }\n\n        public List<PeImportDll> Imports;\n        private PE Application;\n    }\n\n    class PEExports : IPrettyPrintable\n    {\n        public PEExports(PE _Application)\n        {\n            Application = _Application;\n            Exports =  Application.GetExports();\n        } \n\n        public void PrettyPrint()\n        {\n            Console.WriteLine(\"[-] Export listing for file : {0}\", Application.Filepath);\n\n            foreach (PeExport Export in Exports)\n            {\n                Console.WriteLine(\"Export {0:d} :\", Export.Ordinal);\n                Console.WriteLine(\"\\t Name : {0:s}\", Export.Name);\n                Console.WriteLine(\"\\t VA : 0x{0:X}\", (int)Export.VirtualAddress);\n                if (Export.ForwardedName.Length > 0)\n                    Console.WriteLine(\"\\t ForwardedName : {0:s}\", Export.ForwardedName);\n            }\n\n            Console.WriteLine(\"[-] Export listing done\");\n        }\n\n        public List<PeExport> Exports;\n        private PE Application;\n    }\n\n\n    class SxsDependencies : IPrettyPrintable\n    {\n        public SxsDependencies(PE _Application)\n        {\n            Application = _Application;\n            SxS = SxsManifest.GetSxsEntries(Application);\n        } \n\n        public void PrettyPrint()\n        {\n            Console.WriteLine(\"[-] sxs dependencies for executable : {0}\", Application.Filepath);\n            foreach (var entry in SxS)\n            {\n                if (entry.Path.Contains(\"???\"))\n                {\n                    Console.WriteLine(\"  [x] {0:s} : {1:s}\", entry.Name, entry.Path);\n                }\n                else\n                {\n                    Console.WriteLine(\"  [+] {0:s} : {1:s}\", entry.Name, Path.GetFullPath(entry.Path));\n                }\n            }\n        }\n\n        public SxsEntries SxS;\n        private PE Application;\n\n    }\n\n\n    // Basic custom exception used to be able to differentiate between a \"native\" exception\n    // and one that has been already catched, processed and rethrown\n    public class RethrownException : Exception\n    {\n        public RethrownException(Exception e)\n        :base(e.Message, e.InnerException)\n        {\n        }\n\n    }\n\n\n    internal class PEModuleReferences : IPrettyPrintable\n    {\n        public PEModuleReferences(PE _Application)\n        {\n            Application = _Application;\n\n            try\n            {\n                var PeAssembly = AssemblyDefinition.ReadAssembly(Application.Filepath);\n\n                ModuleReferences = PeAssembly.Modules.SelectMany(m => m.ModuleReferences)\n                    .Where(mr => mr.Name.Length > 0);\n            }\n            catch (BadImageFormatException)\n            {\n\n            }\n\n        }\n\n        public void PrettyPrint()\n        {\n            Console.WriteLine(\"[-] Module references listing for file : {0}\", Application.Filepath);\n\n            foreach (ModuleReference moduleReference in ModuleReferences)\n            {\n                Console.WriteLine(\"-{0:s}\", moduleReference.Name);\n            }\n\n            Console.WriteLine(\"[-] Import listing done\");\n        }\n\n        private PE Application;\n\n        public IEnumerable<ModuleReference> ModuleReferences { get; private set; } = new List<ModuleReference>();\n    }\n\n    internal class PEAssemblyReferences : IPrettyPrintable\n    {\n        public PEAssemblyReferences(PE _Application)\n        {\n            Application = _Application;\n\n            try\n            {\n                var PeAssembly = AssemblyDefinition.ReadAssembly(Application.Filepath);\n\n\t\t\t\tResolver = new DefaultAssemblyResolver();\n\t\t\t\tResolver.AddSearchDirectory(Path.GetDirectoryName(_Application.Filepath));\n\n\t\t\t\tAssemblyReferences = PeAssembly.Modules.SelectMany(m => m.AssemblyReferences);\n            }\n            catch (BadImageFormatException)\n            {\n            }\n        }\n\n        public void PrettyPrint()\n        {\n            Console.WriteLine(\"[-] Assembly references listing for file : {0}\", Application.Filepath);\n\n            foreach (AssemblyNameReference assemblyReference in AssemblyReferences)\n            {\n\t\t\t\tAssemblyDefinition definition;\n\t\t\t\ttry\n\t\t\t\t{\n\t\t\t\t\tdefinition = Resolver.Resolve(assemblyReference);\n\t\t\t\t\tConsole.WriteLine(\"-{0:s} : {1:s}\", assemblyReference.Name, definition);\n\t\t\t\t}\n\t\t\t\tcatch (AssemblyResolutionException)\n\t\t\t\t{\n\t\t\t\t\tConsole.WriteLine(\"-{0:s}\", assemblyReference.Name);\n\t\t\t\t}\n\n\t\t\t\t\n            }\n\n            Console.WriteLine(\"[-] Import listing done\");\n        }\n\n        private PE Application;\n\t\tprivate DefaultAssemblyResolver Resolver;\n\n\t\tpublic IEnumerable<AssemblyNameReference> AssemblyReferences { get; private set; } =\n            new List<AssemblyNameReference>();\n    }\n\n    class ImportDll\n    {\n        public string Name { get; private set; }\n\n        public static ImportDll From(PeImportDll i)\n        {\n            return new ImportDll\n            {\n                Name = i.Name\n            };\n        }\n        public static ImportDll From(ModuleReference m)\n        {\n            return new ImportDll\n            {\n                Name = m.Name\n            };\n        }\n    }\n\n    class PeDependencyItem : IPrettyPrintable\n    {\n\n        public PeDependencyItem(PeDependencies _Root, string _ModuleName,  string ModuleFilepath, ModuleSearchStrategy Strategy, int Level)\n        {\n            Action action = () =>\n            {\n                Root = _Root;\n                ModuleName = _ModuleName;\n\n\n    \t\t\tImports = new List<ImportDll>();\n    \t\t\tFilepath = ModuleFilepath;\n                SearchStrategy = Strategy;\n                RecursionLevel = Level;\n\n                DependenciesResolved = false;\n                FullDependencies = new List<PeDependencyItem>();\n    \t\t\tResolvedImports = new List<PeDependencyItem>();\n                ModuleReferences = new List<ImportDll>();\n                AssemblyReferences = new List<AssemblyNameReference>();\n            };\n\n            SafeExecutor(action);\n\t\t}\n\n\t\tpublic void LoadPe()\n\t\t{\n            Action action = () =>\n            {\n    \t\t\tif (Filepath != null)\n    \t\t\t{\n    \t\t\t\tPE Module = BinaryCache.LoadPe(Filepath);\n    \t\t\t\tImports = Module.GetImports().Select(i => ImportDll.From(i)).ToList();\n\n                    try\n                    {\n                        var PeAssembly = AssemblyDefinition.ReadAssembly(Filepath);\n\n                        ModuleReferences = PeAssembly.Modules.SelectMany(m => m.ModuleReferences).Where(mr => mr.Name.Length > 0).Select(m => ImportDll.From(m)).ToList();\n                        AssemblyReferences = PeAssembly.Modules.SelectMany(m => m.AssemblyReferences).ToList();\n                    } catch (BadImageFormatException)\n                    {\n                    }\n                }\n                else\n    \t\t\t{\n    \t\t\t\t//Module = null;\n    \t\t\t}\n            };\n\n            SafeExecutor(action);\n\t\t}\n\n        public void ResolveDependencies()\n        {\n            Action action = () =>\n            {\n                if (DependenciesResolved)\n                {\n                    return;\n                }\n\n                List<PeDependencyItem> NewDependencies = new List<PeDependencyItem>();\n\n                foreach (ImportDll DllImport in Imports.Concat(ModuleReferences))\n                {\n                    string ModuleFilepath = null;\n                    ModuleSearchStrategy Strategy;\n\n\n                    // Find Dll in \"paths\"\n                    Tuple<ModuleSearchStrategy, PE> ResolvedModule = Root.ResolveModule(DllImport.Name);\n                    Strategy = ResolvedModule.Item1;\n\n                    if (Strategy != ModuleSearchStrategy.NOT_FOUND)\n                    {\n                        ModuleFilepath = ResolvedModule.Item2?.Filepath;\n                    }\n\n\n\n                    bool IsAlreadyCached = Root.isModuleCached(DllImport.Name, ModuleFilepath);\n                    PeDependencyItem DependencyItem = Root.GetModuleItem(DllImport.Name, ModuleFilepath, Strategy, RecursionLevel + 1);\n\n                    // do not add twice the same imported module\n                    if (ResolvedImports.Find(ri => ri.ModuleName == DllImport.Name) == null)\n                    {\n                        ResolvedImports.Add(DependencyItem);\n                    }\n\n                    // Do not process twice a dependency. It will be displayed only once\n                    if (!IsAlreadyCached)\n                    {\n                        Debug.WriteLine(\"[{0:d}] [{1:s}] Adding dep {2:s}\", RecursionLevel, ModuleName, ModuleFilepath);\n                        NewDependencies.Add(DependencyItem);\n                    }\n\n                    FullDependencies.Add(DependencyItem);\n\n                }\n\n                DependenciesResolved = true;\n                if ((Root.MaxRecursion > 0) && ((RecursionLevel + 1) >= Root.MaxRecursion))\n                {\n                    return;\n                }\n\n\n                // Recursively resolve dependencies\n                foreach (var Dep in NewDependencies)\n                {\n                    Dep.LoadPe();\n                    Dep.ResolveDependencies();\n                }\n            };\n\n            SafeExecutor(action);\n        }\n\n        public bool IsNewModule()\n        {\n            return Root.VisitModule(this.ModuleName, this.Filepath);\n        }\n\n        public void PrettyPrint()\n        {\n            string Tabs = string.Concat(Enumerable.Repeat(\"|  \", RecursionLevel));\n            Console.WriteLine(\"{0:s}├ {1:s} ({2:s}) : {3:s} \", Tabs, ModuleName, SearchStrategy.ToString(), Filepath);\n\n            foreach (var Dep in ResolvedImports)\n            {\n                bool NeverSeenModule = Dep.IsNewModule();\n                Dep.RecursionLevel = RecursionLevel + 1;\n\n                if (NeverSeenModule)\n\t\t\t\t{\n\t\t\t\t\tDep.PrettyPrint();\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\tDep.BasicPrettyPrint();\n\t\t\t\t}\n\t\t\t\t\n            }\n        }\n\n\t\tpublic void BasicPrettyPrint(int? OverrideRecursionLevel = null)\n\t\t{\n            int localRecursionLevel = RecursionLevel;\n            if (OverrideRecursionLevel != null)\n            {\n                localRecursionLevel = (int) OverrideRecursionLevel;\n            }\n\n            string Tabs = string.Concat(Enumerable.Repeat(\"|  \", localRecursionLevel));\n\t\t\tConsole.WriteLine(\"{0:s}├ {1:s} ({2:s}) : {3:s} \", Tabs, ModuleName, SearchStrategy.ToString(), Filepath);\n\t\t}\n\n        private void SafeExecutor(Action action)\n        {\n            SafeExecutor(() => { action(); return 0; });\n        }\n\n        private T SafeExecutor<T>(Func<T> action)\n        {\n            try\n            {\n                return action();\n            }\n            catch (RethrownException rex)\n            {\n                Console.Error.WriteLine(\" - \\\"{0:s}\\\"\", Filepath);\n                throw rex;\n            }\n            catch (Exception ex)\n            {\n                Console.Error.WriteLine(\"[!] Unhandled exception occured while processing \\\"{1:s}\\\"\", RecursionLevel, Filepath);\n                Console.Error.WriteLine(\"Stacktrace:\\n{0:s}\\n\", ex.StackTrace);\n                Console.Error.WriteLine(\"Modules backtrace:\");\n                throw new RethrownException(ex);\n            }\n            finally\n            {\n                //\n                \n            }\n\n            // return default(T);\n        }\n\n        // Json exportable\n\t\tpublic string ModuleName;\n        public string Filepath;\n        public ModuleSearchStrategy SearchStrategy;\n        public List<PeDependencyItem> Dependencies\n        {\n            \n            get { return IsNewModule() ? FullDependencies : new List<PeDependencyItem>(); }\n        }\n\n\n        // not Json exportable\n        protected List<PeDependencyItem> FullDependencies;\n\t\tprotected List<PeDependencyItem> ResolvedImports;\n\t\tprotected List<ImportDll> Imports;\n        protected List<AssemblyNameReference> AssemblyReferences;\n        protected List<ImportDll> ModuleReferences;\n        protected PeDependencies Root;\n        protected int RecursionLevel;\n\n        private bool DependenciesResolved;\n    }\n\n\n    class ModuleCacheKey : Tuple<string, string>\n    {\n        public ModuleCacheKey(string Name, string Filepath)\n        : base(Name, Filepath)\n        {\n        }\n    }\n\n    class ModuleEntries : Dictionary<ModuleCacheKey, PeDependencyItem>, IPrettyPrintable\n    {\n        public void PrettyPrint()\n        {\n            foreach (var item in this.Values.OrderBy(module => module.SearchStrategy))\n            {\n                Console.WriteLine(\"[{0:s}] {1:s} : {2:s} \", item.SearchStrategy.ToString(), item.ModuleName, item.Filepath);\n            }\n            \n        }\n    }\n\n    class PeDependencies : IPrettyPrintable\n    {\n\t\tpublic PeDependencies(PE Application, int recursion_depth)\n        {\n            string RootFilename = Path.GetFileName(Application.Filepath);\n\n            RootPe = Application;\n            SxsEntriesCache = SxsManifest.GetSxsEntries(RootPe);\n            ModulesCache = new ModuleEntries();\n\t\t\tMaxRecursion = recursion_depth;\n\n            ModulesVisited = new Dictionary<ModuleCacheKey, bool>();\n\n            Root = GetModuleItem(RootFilename, Application.Filepath, ModuleSearchStrategy.ROOT, 0);\n\t\t\tRoot.LoadPe();\n\t\t\tRoot.ResolveDependencies();\n        }\n\n        public Tuple<ModuleSearchStrategy, PE> ResolveModule(string ModuleName)\n        {\n            return BinaryCache.ResolveModule(\n\t\t\t\tRootPe, \n\t\t\t\tModuleName /*DllImport.Name*/ \n\t\t\t);\n        }\n\n\t\tpublic bool isModuleCached(string ModuleName, string ModuleFilepath)\n\t\t{\n\t\t\t// Do not process twice the same item\n\t\t\tModuleCacheKey ModuleKey = new ModuleCacheKey(ModuleName, ModuleFilepath);\n\t\t\treturn ModulesCache.ContainsKey(ModuleKey);\n\t\t}\n\n\t\tpublic PeDependencyItem GetModuleItem(string ModuleName, string ModuleFilepath, ModuleSearchStrategy SearchStrategy, int RecursionLevel)\n        {\n            // Do not process twice the same item\n            ModuleCacheKey ModuleKey = new ModuleCacheKey(ModuleName, ModuleFilepath);\n            if (!ModulesCache.ContainsKey(ModuleKey))\n            {\n                ModulesCache[ModuleKey] = new PeDependencyItem(this, ModuleName, ModuleFilepath, SearchStrategy, RecursionLevel);\n            }\n\n            return ModulesCache[ModuleKey];\n        }\n\n        public void PrettyPrint()\n        {\n            ModulesVisited = new Dictionary<ModuleCacheKey, bool>();\n            Root.PrettyPrint();\n        }\n\n        public bool VisitModule(string ModuleName, string ModuleFilepath)\n        {\n            //ModuleCacheKey ModuleKey = new ModuleCacheKey(ModuleName, ModuleFilepath);\n            ModuleCacheKey ModuleKey = new ModuleCacheKey(\"\", ModuleFilepath);\n\n            // do not visit recursively the same node (in order to prevent stack overflow)\n            if (ModulesVisited.ContainsKey(ModuleKey))\n            {\n                return false;\n            }\n\n            ModulesVisited[ModuleKey] = true;\n            return true;\n        }\n\n\n\n        public ModuleEntries GetModules \n        {\n            get {return ModulesCache;}\n        }\n\n        public PeDependencyItem Root;\n\t\tpublic int MaxRecursion;\n\n\t\tprivate PE RootPe;\n\t\tprivate SxsEntries SxsEntriesCache;\n        private ModuleEntries ModulesCache;\n        private Dictionary<ModuleCacheKey, bool> ModulesVisited;\n    }\n\n \n\n    class Program\n    {\n        public static void PrettyPrinter(IPrettyPrintable obj)\n        {\n            obj.PrettyPrint();\n        }\n\n        public static void JsonPrinter(IPrettyPrintable obj)\n        {\n            JsonSerializerSettings Settings = new JsonSerializerSettings\n            {\n                ReferenceLoopHandling = ReferenceLoopHandling.Serialize,\n                //PreserveReferencesHandling = PreserveReferencesHandling.Objects,\n            };\n\n            Console.WriteLine(JsonConvert.SerializeObject(obj, Formatting.Indented, Settings));\n        }\n\n        public static void DumpKnownDlls(Action<IPrettyPrintable> Printer)\n        { \n            NtKnownDlls KnownDlls = new NtKnownDlls();\n            Printer(KnownDlls);\n        }\n\n        public static void DumpApiSets(Action<IPrettyPrintable> Printer)\n        {\n            NtApiSet ApiSet = new NtApiSet();\n            Printer(ApiSet);\n        }\n\n        public static void DumpApiSets(PE Application, Action<IPrettyPrintable> Printer, int recursion_depth = 0)\n        {\n          NtApiSet ApiSet = new NtApiSet(Application);\n          Printer(ApiSet);\n        }\n\n\t\tpublic static void DumpManifest(PE Application, Action<IPrettyPrintable> Printer, int recursion_depth = 0)\n        {\n            PEManifest Manifest = new PEManifest(Application);\n            Printer(Manifest);\n        }\n\n\t\tpublic static void DumpSxsEntries(PE Application, Action<IPrettyPrintable> Printer, int recursion_depth= 0)\n        {\n            SxsDependencies SxsDeps = new SxsDependencies(Application);\n            Printer(SxsDeps);\n        }\n\n\n        public static void DumpExports(PE Pe, Action<IPrettyPrintable> Printer, int recursion_depth = 0)\n        {\n            PEExports Exports = new PEExports(Pe);\n            Printer(Exports);\n        }\n\n        public static void DumpImports(PE Pe, Action<IPrettyPrintable> Printer, int recursion_depth = 0)\n        {\n            PEImports Imports = new PEImports(Pe);\n            Printer(Imports);\n        }\n        public static void DumpAssemblyReferences(PE Pe, Action<IPrettyPrintable> Printer, int recursion_depth = 0)\n        {\n            PEAssemblyReferences AssemblyReferences = new PEAssemblyReferences(Pe);\n            Printer(AssemblyReferences);\n        }\n\n        public static void DumpModuleReferences(PE Pe, Action<IPrettyPrintable> Printer, int recursion_depth = 0)\n        {\n            PEModuleReferences ModuleReferences = new PEModuleReferences(Pe);\n            Printer(ModuleReferences);\n        }\n\n        public static void DumpDependencyChain(PE Pe, Action<IPrettyPrintable> Printer, int recursion_depth = 0)\n        {\n            PeDependencies Deps = new PeDependencies(Pe, recursion_depth);\n            Printer(Deps);\n        }\n\n        public static void DumpModules(PE Pe, Action<IPrettyPrintable> Printer, int recursion_depth = 0)\n        {\n            if (Printer == JsonPrinter)\n            {\n                Console.Error.WriteLine(\"Json output is not currently supported when dumping the dependency chain.\");\n                return;\n            }\n\n            PeDependencies Deps = new PeDependencies(Pe, recursion_depth);\n            Printer(Deps.GetModules);\n        }\n\n        public static void DumpUsage()\n        {\n            string Usage = String.Join(Environment.NewLine,\n                \"Dependencies.exe : command line tool for dumping dependencies and various utilities.\",\n                \"\",\n                \"Usage : Dependencies.exe [OPTIONS] <FILE>\",\n                \"\",\n                \"Options :\",\n                \"  -h -help : display this help\",\n                \"  -json : activate json output.\",\n\t\t\t\t\"  -cache : load and use binary cache in order to prevent dll file locking.\",\n\t\t\t\t\"  -depth : limit recursion depth when analysing loaded modules or dependency chain. Default value is infinite.\",\n                \"  -apisets : dump the system's ApiSet schema (api set dll -> host dll)\",\n                \"  -apisetsdll : dump the ApiSet schema from apisetschema <FILE> (api set dll -> host dll)\",\n                \"  -knowndll : dump all the system's known dlls (x86 and x64)\",\n                \"  -manifest : dump <FILE> embedded manifest, if it exists.\",\n                \"  -sxsentries : dump all of <FILE>'s sxs dependencies.\",\n                \"  -imports : dump <FILE> imports\",\n                \"  -exports : dump <FILE> exports\",\n                \"  -modules : dump <FILE> resolved modules\",\n                \"  -chain : dump <FILE> whole dependency chain\"\n\n            );\n\n            Console.WriteLine(Usage);\n        }\n\n\t\tstatic Action<IPrettyPrintable> GetObjectPrinter(bool export_as_json)\n\t\t{\n\t\t\tif (export_as_json)\n\t\t\t\treturn JsonPrinter;\n\n\t\t\treturn PrettyPrinter;\n\t\t}\n\n\n\t\tpublic delegate void DumpCommand(PE Application, Action<IPrettyPrintable> Printer, int recursion_depth=0);\n\n\t\tstatic void Main(string[] args)\n\t\t{\n\t\t\t// always the first call to make\n\t\t\tPhlib.InitializePhLib();\n\n\t\t\tint recursion_depth = 0;\n\t\t\tbool early_exit = false;\n\t\t\tbool show_help = false;\n\t\t\tbool export_as_json = false;\n\t\t\tbool use_bin_cache = false;\n\t\t\tDumpCommand command = null;\n\n\t\t\tOptionSet opts = new OptionSet() {\n\t\t\t\t\t\t\t{ \"h|help\",  \"show this message and exit\", v => show_help = v != null },\n\t\t\t\t\t\t\t{ \"json\",  \"Export results in json format\", v => export_as_json = v != null },\n\t\t\t\t\t\t\t{ \"cache\",  \"load and use binary cache to prevent dll file locking\", v => use_bin_cache = v != null },\n\t\t\t\t\t\t\t{ \"d|depth=\",  \"limit recursion depth when analysing loaded modules or dependency chain. Default value is infinite\", (int v) =>  recursion_depth = v },\n\t\t\t\t\t\t\t{ \"knowndll\", \"List all known dlls\", v => { DumpKnownDlls(GetObjectPrinter(export_as_json));  early_exit = true; } },\n\t\t\t\t\t\t\t{ \"apisets\", \"List apisets redirections\", v => { DumpApiSets(GetObjectPrinter(export_as_json));  early_exit = true; } },\n                            { \"apisetsdll\", \"List apisets redirections from apisetschema <FILE>\", v => command = DumpApiSets },\n                            { \"manifest\", \"show manifest information embedded in <FILE>\", v => command = DumpManifest },\n                            { \"sxsentries\", \"dump all of <FILE>'s sxs dependencies\", v => command = DumpSxsEntries },\n                            { \"imports\", \"dump <FILE> imports\", v => command = DumpImports },\n                            { \"exports\", \"dump <FILE> exports\", v => command = DumpExports },\n                            { \"assemblyrefs\", \"dump <FILE> assemblyrefs\", v => command = DumpAssemblyReferences},\n                            { \"modulerefs\", \"dump <FILE> modulerefs\", v => command = DumpModuleReferences},\n                            { \"chain\", \"dump <FILE> whole dependency chain\", v => command = DumpDependencyChain },\n                            { \"modules\", \"dump <FILE> resolved modules\", v => command = DumpModules },\n\t\t\t\t\t\t};\n\n\t\t\tList<string> eps = opts.Parse(args);\n\n\t\t\tif (early_exit)\n\t\t\t\treturn;\n\n\t\t\tif ((show_help) || (args.Length == 0) || (command == null))\n\t\t\t{\n\t\t\t\tDumpUsage();\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tBinaryCache.InitializeBinaryCache(use_bin_cache);\n\n\t\t\tif (eps.Count == 0)\n            {\n                Console.Error.WriteLine(\"[x] Command {0:s} needs to have a PE <FILE> argument\", command.Method.Name);\n                Console.Error.WriteLine(\"\");\n\n                DumpUsage();\n                return;\n            }\n\n\t\t\tString FileName = eps[0];\n            if (!NativeFile.Exists(FileName))\n            {\n                Console.Error.WriteLine(\"[x] Could not find file {0:s} on disk\", FileName);\n                return;\n            }\n\n\t\t\tDebug.WriteLine(\"[-] Loading file {0:s} \", FileName);\n\t\t\tPE Pe = new PE(FileName);\n            if (!Pe.Load())\n            {\n                Console.Error.WriteLine(\"[x] Could not load file {0:s} as a PE\", FileName);\n                return;\n            }\n\n            command(Pe, GetObjectPrinter(export_as_json), recursion_depth);\n\n        }\n    }\n}\n"
  },
  {
    "path": "Dependencies/Properties/AssemblyInfo.cs",
    "content": "﻿using System.Reflection;\r\nusing System.Runtime.CompilerServices;\r\nusing System.Runtime.InteropServices;\r\n\r\n// Les informations générales relatives à un assembly dépendent de\r\n// l'ensemble d'attributs suivant. Changez les valeurs de ces attributs pour modifier les informations\r\n// associées à un assembly.\r\n[assembly: AssemblyTitle(\"Dependencies\")]\r\n[assembly: AssemblyDescription(\"\")]\r\n[assembly: AssemblyConfiguration(\"\")]\r\n[assembly: AssemblyCompany(\"\")]\r\n[assembly: AssemblyProduct(\"Dependencies\")]\r\n[assembly: AssemblyCopyright(\"Copyright ©  2017\")]\r\n[assembly: AssemblyTrademark(\"\")]\r\n[assembly: AssemblyCulture(\"\")]\r\n\r\n// L'affectation de la valeur false à ComVisible rend les types invisibles dans cet assembly\r\n// aux composants COM. Si vous devez accéder à un type dans cet assembly à partir de\r\n// COM, affectez la valeur true à l'attribut ComVisible sur ce type.\r\n[assembly: ComVisible(false)]\r\n\r\n// Le GUID suivant est pour l'ID de la typelib si ce projet est exposé à COM\r\n[assembly: Guid(\"5565a612-b250-4fe0-98dd-07c56916c194\")]\r\n\r\n// Les informations de version pour un assembly se composent des quatre valeurs suivantes :\r\n//\r\n//      Version principale\r\n//      Version secondaire\r\n//      Numéro de build\r\n//      Révision\r\n//\r\n// Vous pouvez spécifier toutes les valeurs ou indiquer les numéros de build et de révision par défaut\r\n// en utilisant '*', comme indiqué ci-dessous :\r\n// [assembly: AssemblyVersion(\"1.0.*\")]\r\n[assembly: AssemblyVersion(\"1.10.0.0\")]\r\n[assembly: AssemblyFileVersion(\"1.10.0.0\")]\r\n"
  },
  {
    "path": "Dependencies/packages.config",
    "content": "﻿<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<packages>\n  <package id=\"Mono.Cecil\" version=\"0.11.4\" targetFramework=\"net461\" />\n  <package id=\"NDesk.Options\" version=\"0.2.1\" targetFramework=\"net461\" />\n  <package id=\"Newtonsoft.Json\" version=\"13.0.1\" targetFramework=\"net461\" />\n</packages>"
  },
  {
    "path": "Dependencies.sln",
    "content": "﻿\r\nMicrosoft Visual Studio Solution File, Format Version 12.00\r\n# Visual Studio Version 16\r\nVisualStudioVersion = 16.0.30114.105\r\nMinimumVisualStudioVersion = 10.0.40219.1\r\nProject(\"{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}\") = \"DependenciesGui\", \"DependenciesGui\\DependenciesGui.csproj\", \"{9232B9B6-F2BA-44A3-B8A6-A352777F632C}\"\r\n\tProjectSection(ProjectDependencies) = postProject\r\n\t\t{4A459493-14FC-4C87-9254-60E0959535DA} = {4A459493-14FC-4C87-9254-60E0959535DA}\r\n\tEndProjectSection\r\nEndProject\r\nProject(\"{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}\") = \"ClrPhlib\", \"ClrPhlib\\ClrPhlib.vcxproj\", \"{FC5FFCAF-982F-4A95-8FA6-2A95B1F7CDC8}\"\r\n\tProjectSection(ProjectDependencies) = postProject\r\n\t\t{477D0215-F252-41A1-874B-F27E3EA1ED17} = {477D0215-F252-41A1-874B-F27E3EA1ED17}\r\n\t\t{BE4A9759-A412-44CB-887D-FEFBEF1ABBF1} = {BE4A9759-A412-44CB-887D-FEFBEF1ABBF1}\r\n\t\t{FC532FFF-EBB1-4601-B903-C09EFB79ECED} = {FC532FFF-EBB1-4601-B903-C09EFB79ECED}\r\n\tEndProjectSection\r\nEndProject\r\nProject(\"{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}\") = \"Dependencies\", \"Dependencies\\Dependencies.csproj\", \"{5565A612-B250-4FE0-98DD-07C56916C194}\"\r\n\tProjectSection(ProjectDependencies) = postProject\r\n\t\t{4A459493-14FC-4C87-9254-60E0959535DA} = {4A459493-14FC-4C87-9254-60E0959535DA}\r\n\tEndProjectSection\r\nEndProject\r\nProject(\"{2150E333-8FDC-42A3-9474-1A3956D46DE8}\") = \"third_party\", \"third_party\", \"{A2A2925A-0582-4436-9A12-8567E979A621}\"\r\nEndProject\r\nProject(\"{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}\") = \"phlib\", \"third_party\\phlib\\phlib.vcxproj\", \"{477D0215-F252-41A1-874B-F27E3EA1ED17}\"\r\nEndProject\r\nProject(\"{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}\") = \"Dragablz.net45\", \"third_party\\Dragablz\\Dragablz\\Dragablz.net45.csproj\", \"{7B11011C-7FD7-4AB0-A1AD-04E940B026DE}\"\r\nEndProject\r\nProject(\"{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}\") = \"demumble\", \"third_party\\demumble\\demumble.vcxproj\", \"{BE4A9759-A412-44CB-887D-FEFBEF1ABBF1}\"\r\nEndProject\r\nProject(\"{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}\") = \"DependenciesLib\", \"DependenciesLib\\DependenciesLib.csproj\", \"{4A459493-14FC-4C87-9254-60E0959535DA}\"\r\n\tProjectSection(ProjectDependencies) = postProject\r\n\t\t{FC5FFCAF-982F-4A95-8FA6-2A95B1F7CDC8} = {FC5FFCAF-982F-4A95-8FA6-2A95B1F7CDC8}\r\n\tEndProjectSection\r\nEndProject\r\nProject(\"{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}\") = \"llvm-demangle\", \"third_party\\llvm-demangle\\llvm-demangle.vcxproj\", \"{FC532FFF-EBB1-4601-B903-C09EFB79ECED}\"\r\nEndProject\r\nProject(\"{2150E333-8FDC-42A3-9474-1A3956D46DE8}\") = \"tests\", \"tests\", \"{D142CC15-3DBD-4295-BDD9-472FE53A00A7}\"\r\nEndProject\r\nProject(\"{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}\") = \"demangler-test\", \"test\\demangler-test\\demangler-test.csproj\", \"{24F9E0C0-CA6E-4565-A9E2-88602DD9F18A}\"\r\nEndProject\r\nProject(\"{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}\") = \"binarycache-test\", \"test\\binarycache-test\\binarycache-test.csproj\", \"{FF973409-2F2A-46F7-B01D-C6405EA40422}\"\r\nEndProject\r\nGlobal\r\n\tGlobalSection(SolutionConfigurationPlatforms) = preSolution\r\n\t\tDebug|Any CPU = Debug|Any CPU\r\n\t\tDebug|ARM = Debug|ARM\r\n\t\tDebug|x64 = Debug|x64\r\n\t\tDebug|x86 = Debug|x86\r\n\t\tRelease|Any CPU = Release|Any CPU\r\n\t\tRelease|ARM = Release|ARM\r\n\t\tRelease|x64 = Release|x64\r\n\t\tRelease|x86 = Release|x86\r\n\tEndGlobalSection\r\n\tGlobalSection(ProjectConfigurationPlatforms) = postSolution\r\n\t\t{9232B9B6-F2BA-44A3-B8A6-A352777F632C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\r\n\t\t{9232B9B6-F2BA-44A3-B8A6-A352777F632C}.Debug|ARM.ActiveCfg = Debug|x86\r\n\t\t{9232B9B6-F2BA-44A3-B8A6-A352777F632C}.Debug|x64.ActiveCfg = Debug|x64\r\n\t\t{9232B9B6-F2BA-44A3-B8A6-A352777F632C}.Debug|x64.Build.0 = Debug|x64\r\n\t\t{9232B9B6-F2BA-44A3-B8A6-A352777F632C}.Debug|x86.ActiveCfg = Debug|x86\r\n\t\t{9232B9B6-F2BA-44A3-B8A6-A352777F632C}.Debug|x86.Build.0 = Debug|x86\r\n\t\t{9232B9B6-F2BA-44A3-B8A6-A352777F632C}.Release|Any CPU.ActiveCfg = Release|Any CPU\r\n\t\t{9232B9B6-F2BA-44A3-B8A6-A352777F632C}.Release|ARM.ActiveCfg = Release|x86\r\n\t\t{9232B9B6-F2BA-44A3-B8A6-A352777F632C}.Release|x64.ActiveCfg = Release|x64\r\n\t\t{9232B9B6-F2BA-44A3-B8A6-A352777F632C}.Release|x64.Build.0 = Release|x64\r\n\t\t{9232B9B6-F2BA-44A3-B8A6-A352777F632C}.Release|x86.ActiveCfg = Release|x86\r\n\t\t{9232B9B6-F2BA-44A3-B8A6-A352777F632C}.Release|x86.Build.0 = Release|x86\r\n\t\t{FC5FFCAF-982F-4A95-8FA6-2A95B1F7CDC8}.Debug|Any CPU.ActiveCfg = Debug|Win32\r\n\t\t{FC5FFCAF-982F-4A95-8FA6-2A95B1F7CDC8}.Debug|ARM.ActiveCfg = Debug|Win32\r\n\t\t{FC5FFCAF-982F-4A95-8FA6-2A95B1F7CDC8}.Debug|x64.ActiveCfg = Debug|x64\r\n\t\t{FC5FFCAF-982F-4A95-8FA6-2A95B1F7CDC8}.Debug|x64.Build.0 = Debug|x64\r\n\t\t{FC5FFCAF-982F-4A95-8FA6-2A95B1F7CDC8}.Debug|x86.ActiveCfg = Debug|Win32\r\n\t\t{FC5FFCAF-982F-4A95-8FA6-2A95B1F7CDC8}.Debug|x86.Build.0 = Debug|Win32\r\n\t\t{FC5FFCAF-982F-4A95-8FA6-2A95B1F7CDC8}.Release|Any CPU.ActiveCfg = Release|Win32\r\n\t\t{FC5FFCAF-982F-4A95-8FA6-2A95B1F7CDC8}.Release|ARM.ActiveCfg = Release|Win32\r\n\t\t{FC5FFCAF-982F-4A95-8FA6-2A95B1F7CDC8}.Release|x64.ActiveCfg = Release|x64\r\n\t\t{FC5FFCAF-982F-4A95-8FA6-2A95B1F7CDC8}.Release|x64.Build.0 = Release|x64\r\n\t\t{FC5FFCAF-982F-4A95-8FA6-2A95B1F7CDC8}.Release|x86.ActiveCfg = Release|Win32\r\n\t\t{FC5FFCAF-982F-4A95-8FA6-2A95B1F7CDC8}.Release|x86.Build.0 = Release|Win32\r\n\t\t{5565A612-B250-4FE0-98DD-07C56916C194}.Debug|Any CPU.ActiveCfg = Debug|x86\r\n\t\t{5565A612-B250-4FE0-98DD-07C56916C194}.Debug|ARM.ActiveCfg = Debug|x86\r\n\t\t{5565A612-B250-4FE0-98DD-07C56916C194}.Debug|x64.ActiveCfg = Debug|x64\r\n\t\t{5565A612-B250-4FE0-98DD-07C56916C194}.Debug|x64.Build.0 = Debug|x64\r\n\t\t{5565A612-B250-4FE0-98DD-07C56916C194}.Debug|x86.ActiveCfg = Debug|x86\r\n\t\t{5565A612-B250-4FE0-98DD-07C56916C194}.Debug|x86.Build.0 = Debug|x86\r\n\t\t{5565A612-B250-4FE0-98DD-07C56916C194}.Release|Any CPU.ActiveCfg = Release|x86\r\n\t\t{5565A612-B250-4FE0-98DD-07C56916C194}.Release|ARM.ActiveCfg = Release|x86\r\n\t\t{5565A612-B250-4FE0-98DD-07C56916C194}.Release|x64.ActiveCfg = Release|x64\r\n\t\t{5565A612-B250-4FE0-98DD-07C56916C194}.Release|x64.Build.0 = Release|x64\r\n\t\t{5565A612-B250-4FE0-98DD-07C56916C194}.Release|x86.ActiveCfg = Release|x86\r\n\t\t{5565A612-B250-4FE0-98DD-07C56916C194}.Release|x86.Build.0 = Release|x86\r\n\t\t{477D0215-F252-41A1-874B-F27E3EA1ED17}.Debug|Any CPU.ActiveCfg = Debug|Win32\r\n\t\t{477D0215-F252-41A1-874B-F27E3EA1ED17}.Debug|ARM.ActiveCfg = Debug|Win32\r\n\t\t{477D0215-F252-41A1-874B-F27E3EA1ED17}.Debug|x64.ActiveCfg = Debug|x64\r\n\t\t{477D0215-F252-41A1-874B-F27E3EA1ED17}.Debug|x64.Build.0 = Debug|x64\r\n\t\t{477D0215-F252-41A1-874B-F27E3EA1ED17}.Debug|x86.ActiveCfg = Debug|Win32\r\n\t\t{477D0215-F252-41A1-874B-F27E3EA1ED17}.Debug|x86.Build.0 = Debug|Win32\r\n\t\t{477D0215-F252-41A1-874B-F27E3EA1ED17}.Release|Any CPU.ActiveCfg = Release|Win32\r\n\t\t{477D0215-F252-41A1-874B-F27E3EA1ED17}.Release|ARM.ActiveCfg = Release|Win32\r\n\t\t{477D0215-F252-41A1-874B-F27E3EA1ED17}.Release|x64.ActiveCfg = Release|x64\r\n\t\t{477D0215-F252-41A1-874B-F27E3EA1ED17}.Release|x64.Build.0 = Release|x64\r\n\t\t{477D0215-F252-41A1-874B-F27E3EA1ED17}.Release|x86.ActiveCfg = Release|Win32\r\n\t\t{477D0215-F252-41A1-874B-F27E3EA1ED17}.Release|x86.Build.0 = Release|Win32\r\n\t\t{7B11011C-7FD7-4AB0-A1AD-04E940B026DE}.Debug|Any CPU.ActiveCfg = Debug|x86\r\n\t\t{7B11011C-7FD7-4AB0-A1AD-04E940B026DE}.Debug|ARM.ActiveCfg = Debug|x86\r\n\t\t{7B11011C-7FD7-4AB0-A1AD-04E940B026DE}.Debug|x64.ActiveCfg = Debug|x64\r\n\t\t{7B11011C-7FD7-4AB0-A1AD-04E940B026DE}.Debug|x64.Build.0 = Debug|x64\r\n\t\t{7B11011C-7FD7-4AB0-A1AD-04E940B026DE}.Debug|x86.ActiveCfg = Debug|x86\r\n\t\t{7B11011C-7FD7-4AB0-A1AD-04E940B026DE}.Debug|x86.Build.0 = Debug|x86\r\n\t\t{7B11011C-7FD7-4AB0-A1AD-04E940B026DE}.Release|Any CPU.ActiveCfg = Release|x86\r\n\t\t{7B11011C-7FD7-4AB0-A1AD-04E940B026DE}.Release|ARM.ActiveCfg = Release|x86\r\n\t\t{7B11011C-7FD7-4AB0-A1AD-04E940B026DE}.Release|x64.ActiveCfg = Release|x64\r\n\t\t{7B11011C-7FD7-4AB0-A1AD-04E940B026DE}.Release|x64.Build.0 = Release|x64\r\n\t\t{7B11011C-7FD7-4AB0-A1AD-04E940B026DE}.Release|x86.ActiveCfg = Release|x86\r\n\t\t{7B11011C-7FD7-4AB0-A1AD-04E940B026DE}.Release|x86.Build.0 = Release|x86\r\n\t\t{BE4A9759-A412-44CB-887D-FEFBEF1ABBF1}.Debug|Any CPU.ActiveCfg = Debug|Win32\r\n\t\t{BE4A9759-A412-44CB-887D-FEFBEF1ABBF1}.Debug|ARM.ActiveCfg = Debug|Win32\r\n\t\t{BE4A9759-A412-44CB-887D-FEFBEF1ABBF1}.Debug|x64.ActiveCfg = Debug|x64\r\n\t\t{BE4A9759-A412-44CB-887D-FEFBEF1ABBF1}.Debug|x64.Build.0 = Debug|x64\r\n\t\t{BE4A9759-A412-44CB-887D-FEFBEF1ABBF1}.Debug|x86.ActiveCfg = Debug|Win32\r\n\t\t{BE4A9759-A412-44CB-887D-FEFBEF1ABBF1}.Debug|x86.Build.0 = Debug|Win32\r\n\t\t{BE4A9759-A412-44CB-887D-FEFBEF1ABBF1}.Release|Any CPU.ActiveCfg = Release|Win32\r\n\t\t{BE4A9759-A412-44CB-887D-FEFBEF1ABBF1}.Release|ARM.ActiveCfg = Release|Win32\r\n\t\t{BE4A9759-A412-44CB-887D-FEFBEF1ABBF1}.Release|x64.ActiveCfg = Release|x64\r\n\t\t{BE4A9759-A412-44CB-887D-FEFBEF1ABBF1}.Release|x64.Build.0 = Release|x64\r\n\t\t{BE4A9759-A412-44CB-887D-FEFBEF1ABBF1}.Release|x86.ActiveCfg = Release|Win32\r\n\t\t{BE4A9759-A412-44CB-887D-FEFBEF1ABBF1}.Release|x86.Build.0 = Release|Win32\r\n\t\t{4A459493-14FC-4C87-9254-60E0959535DA}.Debug|Any CPU.ActiveCfg = Debug|x86\r\n\t\t{4A459493-14FC-4C87-9254-60E0959535DA}.Debug|ARM.ActiveCfg = Debug|x86\r\n\t\t{4A459493-14FC-4C87-9254-60E0959535DA}.Debug|x64.ActiveCfg = Debug|x64\r\n\t\t{4A459493-14FC-4C87-9254-60E0959535DA}.Debug|x64.Build.0 = Debug|x64\r\n\t\t{4A459493-14FC-4C87-9254-60E0959535DA}.Debug|x86.ActiveCfg = Debug|x86\r\n\t\t{4A459493-14FC-4C87-9254-60E0959535DA}.Debug|x86.Build.0 = Debug|x86\r\n\t\t{4A459493-14FC-4C87-9254-60E0959535DA}.Release|Any CPU.ActiveCfg = Release|x86\r\n\t\t{4A459493-14FC-4C87-9254-60E0959535DA}.Release|ARM.ActiveCfg = Release|x86\r\n\t\t{4A459493-14FC-4C87-9254-60E0959535DA}.Release|x64.ActiveCfg = Release|x64\r\n\t\t{4A459493-14FC-4C87-9254-60E0959535DA}.Release|x64.Build.0 = Release|x64\r\n\t\t{4A459493-14FC-4C87-9254-60E0959535DA}.Release|x86.ActiveCfg = Release|x86\r\n\t\t{4A459493-14FC-4C87-9254-60E0959535DA}.Release|x86.Build.0 = Release|x86\r\n\t\t{FC532FFF-EBB1-4601-B903-C09EFB79ECED}.Debug|Any CPU.ActiveCfg = Debug|Win32\r\n\t\t{FC532FFF-EBB1-4601-B903-C09EFB79ECED}.Debug|ARM.ActiveCfg = Debug|Win32\r\n\t\t{FC532FFF-EBB1-4601-B903-C09EFB79ECED}.Debug|x64.ActiveCfg = Debug|x64\r\n\t\t{FC532FFF-EBB1-4601-B903-C09EFB79ECED}.Debug|x64.Build.0 = Debug|x64\r\n\t\t{FC532FFF-EBB1-4601-B903-C09EFB79ECED}.Debug|x86.ActiveCfg = Debug|Win32\r\n\t\t{FC532FFF-EBB1-4601-B903-C09EFB79ECED}.Debug|x86.Build.0 = Debug|Win32\r\n\t\t{FC532FFF-EBB1-4601-B903-C09EFB79ECED}.Release|Any CPU.ActiveCfg = Release|Win32\r\n\t\t{FC532FFF-EBB1-4601-B903-C09EFB79ECED}.Release|ARM.ActiveCfg = Release|Win32\r\n\t\t{FC532FFF-EBB1-4601-B903-C09EFB79ECED}.Release|x64.ActiveCfg = Release|x64\r\n\t\t{FC532FFF-EBB1-4601-B903-C09EFB79ECED}.Release|x64.Build.0 = Release|x64\r\n\t\t{FC532FFF-EBB1-4601-B903-C09EFB79ECED}.Release|x86.ActiveCfg = Release|Win32\r\n\t\t{FC532FFF-EBB1-4601-B903-C09EFB79ECED}.Release|x86.Build.0 = Release|Win32\r\n\t\t{24F9E0C0-CA6E-4565-A9E2-88602DD9F18A}.Debug|Any CPU.ActiveCfg = Debug|x86\r\n\t\t{24F9E0C0-CA6E-4565-A9E2-88602DD9F18A}.Debug|ARM.ActiveCfg = Debug|x86\r\n\t\t{24F9E0C0-CA6E-4565-A9E2-88602DD9F18A}.Debug|x64.ActiveCfg = Debug|x64\r\n\t\t{24F9E0C0-CA6E-4565-A9E2-88602DD9F18A}.Debug|x64.Build.0 = Debug|x64\r\n\t\t{24F9E0C0-CA6E-4565-A9E2-88602DD9F18A}.Debug|x86.ActiveCfg = Debug|x86\r\n\t\t{24F9E0C0-CA6E-4565-A9E2-88602DD9F18A}.Debug|x86.Build.0 = Debug|x86\r\n\t\t{24F9E0C0-CA6E-4565-A9E2-88602DD9F18A}.Release|Any CPU.ActiveCfg = Release|x86\r\n\t\t{24F9E0C0-CA6E-4565-A9E2-88602DD9F18A}.Release|ARM.ActiveCfg = Release|x86\r\n\t\t{24F9E0C0-CA6E-4565-A9E2-88602DD9F18A}.Release|x64.ActiveCfg = Release|x64\r\n\t\t{24F9E0C0-CA6E-4565-A9E2-88602DD9F18A}.Release|x64.Build.0 = Release|x64\r\n\t\t{24F9E0C0-CA6E-4565-A9E2-88602DD9F18A}.Release|x86.ActiveCfg = Release|x86\r\n\t\t{24F9E0C0-CA6E-4565-A9E2-88602DD9F18A}.Release|x86.Build.0 = Release|x86\r\n\t\t{FF973409-2F2A-46F7-B01D-C6405EA40422}.Debug|Any CPU.ActiveCfg = Debug|x86\r\n\t\t{FF973409-2F2A-46F7-B01D-C6405EA40422}.Debug|ARM.ActiveCfg = Debug|x86\r\n\t\t{FF973409-2F2A-46F7-B01D-C6405EA40422}.Debug|x64.ActiveCfg = Debug|x64\r\n\t\t{FF973409-2F2A-46F7-B01D-C6405EA40422}.Debug|x64.Build.0 = Debug|x64\r\n\t\t{FF973409-2F2A-46F7-B01D-C6405EA40422}.Debug|x86.ActiveCfg = Debug|x86\r\n\t\t{FF973409-2F2A-46F7-B01D-C6405EA40422}.Debug|x86.Build.0 = Debug|x86\r\n\t\t{FF973409-2F2A-46F7-B01D-C6405EA40422}.Release|Any CPU.ActiveCfg = Release|x86\r\n\t\t{FF973409-2F2A-46F7-B01D-C6405EA40422}.Release|ARM.ActiveCfg = Release|x86\r\n\t\t{FF973409-2F2A-46F7-B01D-C6405EA40422}.Release|x64.ActiveCfg = Release|x64\r\n\t\t{FF973409-2F2A-46F7-B01D-C6405EA40422}.Release|x64.Build.0 = Release|x64\r\n\t\t{FF973409-2F2A-46F7-B01D-C6405EA40422}.Release|x86.ActiveCfg = Release|x86\r\n\t\t{FF973409-2F2A-46F7-B01D-C6405EA40422}.Release|x86.Build.0 = Release|x86\r\n\tEndGlobalSection\r\n\tGlobalSection(SolutionProperties) = preSolution\r\n\t\tHideSolutionNode = FALSE\r\n\tEndGlobalSection\r\n\tGlobalSection(NestedProjects) = preSolution\r\n\t\t{477D0215-F252-41A1-874B-F27E3EA1ED17} = {A2A2925A-0582-4436-9A12-8567E979A621}\r\n\t\t{7B11011C-7FD7-4AB0-A1AD-04E940B026DE} = {A2A2925A-0582-4436-9A12-8567E979A621}\r\n\t\t{BE4A9759-A412-44CB-887D-FEFBEF1ABBF1} = {A2A2925A-0582-4436-9A12-8567E979A621}\r\n\t\t{FC532FFF-EBB1-4601-B903-C09EFB79ECED} = {A2A2925A-0582-4436-9A12-8567E979A621}\r\n\t\t{24F9E0C0-CA6E-4565-A9E2-88602DD9F18A} = {D142CC15-3DBD-4295-BDD9-472FE53A00A7}\r\n\t\t{FF973409-2F2A-46F7-B01D-C6405EA40422} = {D142CC15-3DBD-4295-BDD9-472FE53A00A7}\r\n\tEndGlobalSection\r\n\tGlobalSection(ExtensibilityGlobals) = postSolution\r\n\t\tSolutionGuid = {054EFA82-95F8-4719-9F9A-546E7BEC56BF}\r\n\tEndGlobalSection\r\nEndGlobal\r\n"
  },
  {
    "path": "DependenciesGui/About.xaml",
    "content": "﻿<Window x:Class=\"Dependencies.About\"\n        xmlns=\"http://schemas.microsoft.com/winfx/2006/xaml/presentation\"\n        xmlns:x=\"http://schemas.microsoft.com/winfx/2006/xaml\"\n        xmlns:d=\"http://schemas.microsoft.com/expression/blend/2008\"\n        xmlns:mc=\"http://schemas.openxmlformats.org/markup-compatibility/2006\"\n        xmlns:local=\"clr-namespace:Dependencies\"\n        mc:Ignorable=\"d\"\n        Title=\"About\" MinHeight=\"100\" MinWidth=\"600\" SizeToContent=\"WidthAndHeight\" ResizeMode=\"NoResize\" >\n    <Grid Margin=\"20 20 20 20\" MinHeight=\"100\"  MinWidth=\"600\">\n        <Grid.RowDefinitions>\n            <RowDefinition Height=\"33*\"/>\n        </Grid.RowDefinitions>\n\n        <Grid Grid.Row=\"0\">\n            <Grid.ColumnDefinitions>\n                <ColumnDefinition Width=\"20*\"/>\n                <ColumnDefinition Width=\"80*\"/>\n            </Grid.ColumnDefinitions>\n\n            <Image Source=\"Images/Dependencies_48px.png\" Height=\"48\" Width=\"48\" Grid.Column=\"0\"/>\n            <TextBlock Grid.Column=\"1\"\n                       TextWrapping=\"Wrap\"\n                       VerticalAlignment=\"Center\"\n                       Name=\"TextContent\">\n                Dependencies v<Run Text=\"{Binding VersionStr,Mode=OneWay}\" /> :<LineBreak />\n                <LineBreak />\n                Dependency tool made by lucasg.\n                <LineBreak />\n                Please go to \n                <Hyperlink\n                    NavigateUri=\"https://github.com/lucasg/Dependencies/issues\"\n                    RequestNavigate=\"Uri_RequestNavigate\">\n                    https://github.com/lucasg/Dependencies/issues\n                </Hyperlink> to report issues.\n                <LineBreak />\n                <LineBreak />\n                <TextBlock Name=\"UpdateCheck\"><Hyperlink NavigateUri=\"#\" RequestNavigate=\"Uri_CheckUpdates\">Check for updates</Hyperlink></TextBlock>\n            </TextBlock>\n        </Grid>\n    </Grid>\n</Window>\n"
  },
  {
    "path": "DependenciesGui/About.xaml.cs",
    "content": "﻿using System;\nusing System.Diagnostics;\nusing System.Net;\nusing System.Reflection;\nusing System.Threading.Tasks;\nusing System.Windows;\nusing System.Windows.Documents;\nusing System.Windows.Navigation;\n\nnamespace Dependencies\n{\n    /// <summary>\n    /// Logique d'interaction pour About.xaml\n    /// </summary>\n    public partial class About : Window\n    {\n        public About()\n        {\n            InitializeComponent();\n            DataContext = this;\n        }\n\n        private void Uri_RequestNavigate(object sender, RequestNavigateEventArgs e)\n        {\n            Process.Start(e.Uri.ToString());\n        }\n\n        public string VersionStr\n        {\n            get\n            {\n                return Assembly.GetEntryAssembly().GetName().Version.ToString();\n            }\n        }\n\n        private async void Uri_CheckUpdates(object sender, RequestNavigateEventArgs e)\n        {\n            string version = await GetLatestVersion(\"https://github.com/lucasg/Dependencies/releases/latest\");\n            UpdateCheck.Inlines.Clear();\n            UpdateCheck.Inlines.Add(\"Latest version: \");\n            var link = new Hyperlink()\n            {\n                NavigateUri = new Uri(version)\n            };\n            link.Inlines.Add(version);\n            link.RequestNavigate += Uri_RequestNavigate;\n            UpdateCheck.Inlines.Add(link);\n        }\n\n        // Based on https://stackoverflow.com/a/28424940/4928207\n        private async Task<string> GetLatestVersion(string url)\n        {\n            try\n            {\n                var req = (HttpWebRequest)HttpWebRequest.Create(url);\n                req.Method = \"HEAD\";\n                req.AllowAutoRedirect = false;\n                using (var resp = (HttpWebResponse)await req.GetResponseAsync())\n                {\n                    switch (resp.StatusCode)\n                    {\n                        case HttpStatusCode.OK:\n                            return url;\n                        case HttpStatusCode.Redirect:\n                        case HttpStatusCode.MovedPermanently:\n                        case HttpStatusCode.RedirectKeepVerb:\n                        case HttpStatusCode.RedirectMethod:\n                            if (resp.Headers[\"Location\"] == null)\n                                return url;\n                            return resp.Headers[\"Location\"];\n                        default:\n                            return url;\n                    }\n                }\n            }\n            catch\n            {\n            }\n            return url;\n        }\n    }\n}\n"
  },
  {
    "path": "DependenciesGui/App.config",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<configuration>\n    <configSections>\n        <sectionGroup name=\"userSettings\" type=\"System.Configuration.UserSettingsGroup, System, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089\">\n            <section name=\"Dependencies.Properties.Settings\" type=\"System.Configuration.ClientSettingsSection, System, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089\" allowExeDefinition=\"MachineToLocalUser\" requirePermission=\"false\"/>\n        </sectionGroup>\n    </configSections>\n    <startup> \n        <supportedRuntime version=\"v4.0\" sku=\".NETFramework,Version=v4.6.1\"/>\n    </startup>\n    <userSettings>\n        <Dependencies.Properties.Settings>\n            <setting name=\"Undecorate\" serializeAs=\"String\">\n                <value>True</value>\n            </setting>\n            <setting name=\"ShowStatusBar\" serializeAs=\"String\">\n                <value>True</value>\n            </setting>\n            <setting name=\"FullPath\" serializeAs=\"String\">\n                <value>True</value>\n            </setting>\n            <setting name=\"RecentFilesIndex\" serializeAs=\"String\">\n                <value>0</value>\n            </setting>\n            <setting name=\"PeViewerPath\" serializeAs=\"String\">\n                <value>peview.exe</value>\n            </setting>\n            <setting name=\"TreeBuildBehaviour\" serializeAs=\"String\">\n                <value>ChildOnly</value>\n            </setting>\n            <setting name=\"Font\" serializeAs=\"String\">\n                <value>Courier New</value>\n            </setting>\n            <setting name=\"RecentFiles\" serializeAs=\"Xml\">\n                <value>\n                    <ArrayOfString xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n                        xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\">\n                        <string />\n                        <string />\n                        <string />\n                        <string />\n                        <string />\n                        <string />\n                        <string />\n                        <string />\n                        <string />\n                        <string />\n                    </ArrayOfString>\n                </value>\n            </setting>\n            <setting name=\"TreeDepth\" serializeAs=\"String\">\n                <value>2</value>\n            </setting>\n            <setting name=\"BinaryCacheOptionValue\" serializeAs=\"String\">\n                <value>True</value>\n            </setting>\n        </Dependencies.Properties.Settings>\n    </userSettings>\n</configuration>\n"
  },
  {
    "path": "DependenciesGui/App.xaml",
    "content": "﻿<Application x:Class=\"Dependencies.App\"\n             xmlns=\"http://schemas.microsoft.com/winfx/2006/xaml/presentation\"\n             xmlns:x=\"http://schemas.microsoft.com/winfx/2006/xaml\"\n             Startup=\"App_Startup\"\n             Exit=\"App_Exit\">\n    <Application.Resources>\n        <ResourceDictionary >\n            <ResourceDictionary.MergedDictionaries>\n                <!-- Import themes for Dragablz forms -->\n                <ResourceDictionary Source=\"pack://application:,,,/Dragablz;component/Themes/Generic.xaml\" />\n                \n                <!-- Import themes for FilterControl forms -->\n                <ResourceDictionary Source=\"pack://application:,,,/DependenciesGui;component/FilterControl/FilterControl.generic.xaml\" />\n\n                <!-- Import themes for DependencyCustomListView forms -->\n                <ResourceDictionary Source=\"pack://application:,,,/DependenciesGui;component/DependencyCustomListView.xaml\" />\n            </ResourceDictionary.MergedDictionaries>\n        </ResourceDictionary>\n    </Application.Resources>\n    <JumpList.JumpList>\n        <JumpList ShowRecentCategory=\"True\">\n        </JumpList>\n    </JumpList.JumpList>\n</Application>\n"
  },
  {
    "path": "DependenciesGui/App.xaml.cs",
    "content": "﻿using System;\nusing System.Windows;\nusing System.Windows.Shell;\nusing System.ComponentModel;\nusing System.IO;\n\nusing Dependencies.ClrPh;\nusing System.Reflection;\n\nnamespace Dependencies\n{\n \n\n    /// <summary>\n    /// Application instance\n    /// </summary>\n    public partial class App : Application, INotifyPropertyChanged\n    {\n        private string statusBarMessage = \"\";\n        private MainWindow mainWindow;\n\n        public string StatusBarMessage\n        {\n            get { return statusBarMessage; }\n            set\n            {\n                if (statusBarMessage != value)\n                {\n                    statusBarMessage = value;\n                    OnPropertyChanged(\"StatusBarMessage\");\n                }\n            }\n        }\n\n        public event PropertyChangedEventHandler PropertyChanged;\n        protected void OnPropertyChanged(string propertyName)\n        {\n            PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));\n        }\n\n        private void App_PropertyChanged(object sender, PropertyChangedEventArgs e)\n        {\n            if (e.PropertyName == \"StatusBarMessage\")\n            {\n                mainWindow.AppStatusBarMessage.Content = (object)StatusBarMessage;\n            }\n        }\n\n        public PE LoadBinary(string path)\n        {\n            StatusBarMessage = String.Format(\"Loading module {0:s} ...\", path);\n\n\t\t\tif (!NativeFile.Exists(path))\n\t\t\t{\n\t\t\t\tStatusBarMessage = String.Format(\"Loading PE file \\\"{0:s}\\\" failed : file not present on disk.\", path);\n\t\t\t\treturn null;\n\t\t\t}\n\n\t\t\tPE pe = BinaryCache.LoadPe(path);\n            if (pe == null || !pe.LoadSuccessful)\n            {\n                StatusBarMessage = String.Format(\"Loading module {0:s} failed.\", path);\n            }\n            else\n            {\n                StatusBarMessage = String.Format(\"Loading PE file \\\"{0:s}\\\" successful.\", pe.Filepath);\n            }\n            \n            return pe;\n        }\n\n        void App_Startup(object sender, StartupEventArgs e)\n        {\n            (Application.Current as App).PropertyChanged += App_PropertyChanged;\n\n            Phlib.InitializePhLib();\n\n\t\t\t// Load singleton for binary caching\n\t\t\tBinaryCache.InitializeBinaryCache(Dependencies.BinaryCacheOption.GetGlobalBehaviour() == Dependencies.BinaryCacheOption.BinaryCacheOptionValue.Yes);\n\n\n\t\t\t// https://www.red-gate.com/simple-talk/blogs/wpf-menu-displays-to-the-left-of-the-window/\n\t\t\tSetDropDownMenuToBeRightAligned();\n\n            mainWindow = new MainWindow();\n            mainWindow.IsMaster = true;\n\n            switch(Phlib.GetClrPhArch())\n            {\n                case CLRPH_ARCH.x86:\n                    mainWindow.Title = \"Dependencies (x86)\";\n                    break;\n                case CLRPH_ARCH.x64:\n                    mainWindow.Title = \"Dependencies (x64)\";\n                    break;\n                case CLRPH_ARCH.WOW64:\n                    mainWindow.Title = \"Dependencies (WoW64)\";\n                    break;\n            }\n            \n            mainWindow.Show();\n\n\n\n            // Process command line args\n            if (e.Args.Length > 0)\n            {\n                mainWindow.OpenNewDependencyWindow(e.Args[0]);\n                \n            }\n        }\n\n        void App_Exit(object sender, ExitEventArgs e)\n        {\n            Dependencies.Properties.Settings.Default.Save();\n            BinaryCache.Instance.Unload();\n        }\n\n        private static void SetDropDownMenuToBeRightAligned()\n        {\n            var menuDropAlignmentField = typeof(SystemParameters).GetField(\"_menuDropAlignment\", BindingFlags.NonPublic | BindingFlags.Static);\n            Action setAlignmentValue = () =>\n            {\n                if (SystemParameters.MenuDropAlignment && menuDropAlignmentField != null) menuDropAlignmentField.SetValue(null, false);\n            };\n\n            setAlignmentValue();\n\n            SystemParameters.StaticPropertyChanged += (sender, e) =>\n            {\n                setAlignmentValue();\n            };\n        }\n\n        public static void AddToRecentDocuments(String Filename)\n        {\n            // Create custom task\n            JumpTask item = new JumpTask();\n            item.Title = System.IO.Path.GetFileName(Filename);\n            item.Description = Filename;\n            item.ApplicationPath = System.Reflection.Assembly.GetExecutingAssembly().CodeBase;\n            item.Arguments = Filename;\n            item.CustomCategory = \"Tasks\";\n            \n\n            // Add document to recent category\n            JumpList RecentsDocs = JumpList.GetJumpList(Application.Current);\n            RecentsDocs.JumpItems.Add(item);\n            JumpList.AddToRecentCategory(item);\n            RecentsDocs.Apply();\n\n            // Store a copy in application settings, LRU style\n            // First check if the item is not already present in the list\n            int index = Dependencies.Properties.Settings.Default.RecentFiles.IndexOf(Filename);\n            if (index != -1)\n            {\n                Dependencies.Properties.Settings.Default.RecentFiles.RemoveAt(index);\n            }\n\n            // Second check if the list is not full\n            if (Dependencies.Properties.Settings.Default.RecentFiles.Count == 10)\n            {\n                Dependencies.Properties.Settings.Default.RecentFiles.RemoveAt(9);\n            }\n\n            // Prepend the list with the new item\n            Dependencies.Properties.Settings.Default.RecentFiles.Insert(0, Filename);\n        }\n\n    }\n    \n}\n"
  },
  {
    "path": "DependenciesGui/CustomHeaderViewModel.cs",
    "content": "using System;\nusing System.Collections.Generic;\nusing System.ComponentModel;\nusing System.Linq;\nusing System.Runtime.CompilerServices;\nusing System.Text;\nusing System.Threading.Tasks;\n\nnamespace Dependencies\n{\n    public class CustomHeaderViewModel : INotifyPropertyChanged\n    {\n        private string _header;\n        private bool _isSelected;\n\n        public string Header\n        {\n            get { return _header; }\n            set\n            {\n                if (value == _header) return;\n                _header = value;\n                OnPropertyChanged(\"Header\");              \n            }\n        }\n\n        public bool IsSelected\n        {\n            get { return _isSelected; }\n            set\n            {\n                if (value.Equals(_isSelected)) return;\n                _isSelected = value;\n                OnPropertyChanged(\"IsSelected\");              \n            }\n        }\n\n        public event PropertyChangedEventHandler PropertyChanged;\n\n        protected void OnPropertyChanged(string propertyName)\n        {\n            PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));\n        }\n    }\n    \n}"
  },
  {
    "path": "DependenciesGui/Dependencies.manifest",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?>\n<assembly xmlns=\"urn:schemas-microsoft-com:asm.v1\" manifestVersion=\"1.0\">\n  <assemblyIdentity\n    name=\"Dependencies\"\n    processorArchitecture=\"*\"\n    version=\"1.0.0.0\"\n    type=\"win32\"\n    processorArchitecture=\"amd64\"\n  />\n  <description>Deependencies</description>\n  <dependency>\n    <dependentAssembly>\n      <assemblyIdentity\n        type=\"win32\"\n        type=\"win32\"\n        name=\"Microsoft.Windows.Common-Controls\"\n        version=\"6.0.0.0\"\n        processorArchitecture=\"*\"\n        publicKeyToken=\"6595b64144ccf1df\"\n        language=\"*\"\n      />\n    </dependentAssembly>\n  </dependency>\n  <trustInfo xmlns=\"urn:schemas-microsoft-com:asm.v3\">\n    <security>\n      <requestedPrivileges>\n        <requestedExecutionLevel level=\"asInvoker\" uiAccess=\"false\"/>\n      </requestedPrivileges>\n    </security>\n  </trustInfo>\n  <compatibility xmlns=\"urn:schemas-microsoft-com:compatibility.v1\">\n    <application>\n      <supportedOS Id=\"{e2011457-1546-43c5-a5fe-008deee3d3f0}\"/>\n      <supportedOS Id=\"{35138b9a-5d96-4fbd-8e2d-a2440225f93a}\"/>\n      <supportedOS Id=\"{4a2f28e3-53b9-4441-ba9c-d69d4a4a6e38}\"/>\n      <supportedOS Id=\"{1f676c76-80e1-4239-95bb-83d0f6d0da78}\"/>\n      <supportedOS Id=\"{8e0f7a12-bfb3-4fe8-b9a5-48fd50a15a9a}\"/>\n    </application>\n  </compatibility>\n  <asmv3:application xmlns:asmv3=\"urn:schemas-microsoft-com:asm.v3\">\n    <asmv3:windowsSettings xmlns=\"http://schemas.microsoft.com/SMI/2005/WindowsSettings\">\n      <dpiAware>true</dpiAware>\n    </asmv3:windowsSettings>\n    <asmv3:windowsSettings xmlns=\"http://schemas.microsoft.com/SMI/2016/WindowsSettings\">\n      <longPathAware>true</longPathAware>\n    </asmv3:windowsSettings>\n  </asmv3:application>\n</assembly>"
  },
  {
    "path": "DependenciesGui/DependenciesGui.csproj",
    "content": "﻿<?xml version=\"1.0\" encoding=\"utf-8\"?>\r\n<Project ToolsVersion=\"15.0\" xmlns=\"http://schemas.microsoft.com/developer/msbuild/2003\">\r\n  <Import Project=\"$(MSBuildExtensionsPath)\\$(MSBuildToolsVersion)\\Microsoft.Common.props\" Condition=\"Exists('$(MSBuildExtensionsPath)\\$(MSBuildToolsVersion)\\Microsoft.Common.props')\" />\r\n  <PropertyGroup>\r\n    <Configuration Condition=\" '$(Configuration)' == '' \">Debug</Configuration>\r\n    <Platform Condition=\" '$(Platform)' == '' \">AnyCPU</Platform>\r\n    <ProjectGuid>{9232B9B6-F2BA-44A3-B8A6-A352777F632C}</ProjectGuid>\r\n    <OutputType>WinExe</OutputType>\r\n    <RootNamespace>Dependencies</RootNamespace>\r\n    <AssemblyName>DependenciesGui</AssemblyName>\r\n    <TargetFrameworkVersion>v4.6.1</TargetFrameworkVersion>\r\n    <FileAlignment>512</FileAlignment>\r\n    <ProjectTypeGuids>{60dc8134-eba5-43b8-bcc9-bb4bc16c2548};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids>\r\n    <WarningLevel>4</WarningLevel>\r\n    <AutoGenerateBindingRedirects>true</AutoGenerateBindingRedirects>\r\n    <TargetFrameworkProfile />\r\n  </PropertyGroup>\r\n  <PropertyGroup>\r\n    <ApplicationIcon>Dependencies.ico</ApplicationIcon>\r\n  </PropertyGroup>\r\n  <PropertyGroup />\r\n  <PropertyGroup>\r\n    <StartupObject>Dependencies.App</StartupObject>\r\n  </PropertyGroup>\r\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)' == 'Debug|x86'\">\r\n    <DebugSymbols>true</DebugSymbols>\r\n    <OutputPath>$(SolutionDir)bin\\$(Configuration)$(Platform)</OutputPath>\r\n    <IntermediateOutputPath>$(SolutionDir)obj\\$(ProjectName)\\$(Configuration)$(Platform)</IntermediateOutputPath>\r\n    <DefineConstants>DEBUG;TRACE</DefineConstants>\r\n    <AllowUnsafeBlocks>true</AllowUnsafeBlocks>\r\n    <DebugType>full</DebugType>\r\n    <PlatformTarget>x86</PlatformTarget>\r\n    <ErrorReport>prompt</ErrorReport>\r\n    <CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>\r\n  </PropertyGroup>\r\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)' == 'Release|x86'\">\r\n    <OutputPath>$(SolutionDir)bin\\$(Configuration)$(Platform)</OutputPath>\r\n    <IntermediateOutputPath>$(SolutionDir)obj\\$(ProjectName)\\$(Configuration)$(Platform)</IntermediateOutputPath>\r\n    <DefineConstants>TRACE</DefineConstants>\r\n    <Optimize>true</Optimize>\r\n    <DebugType>pdbonly</DebugType>\r\n    <PlatformTarget>x86</PlatformTarget>\r\n    <ErrorReport>prompt</ErrorReport>\r\n    <CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>\r\n  </PropertyGroup>\r\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)' == 'Debug|x64'\">\r\n    <DebugSymbols>true</DebugSymbols>\r\n    <OutputPath>$(SolutionDir)bin\\$(Configuration)$(Platform)</OutputPath>\r\n    <IntermediateOutputPath>$(SolutionDir)obj\\$(ProjectName)\\$(Configuration)$(Platform)</IntermediateOutputPath>\r\n    <DefineConstants>DEBUG;TRACE</DefineConstants>\r\n    <AllowUnsafeBlocks>true</AllowUnsafeBlocks>\r\n    <DebugType>full</DebugType>\r\n    <PlatformTarget>x64</PlatformTarget>\r\n    <ErrorReport>prompt</ErrorReport>\r\n    <CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>\r\n  </PropertyGroup>\r\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)' == 'Release|x64'\">\r\n    <OutputPath>$(SolutionDir)bin\\$(Configuration)$(Platform)</OutputPath>\r\n    <IntermediateOutputPath>$(SolutionDir)obj\\$(ProjectName)\\$(Configuration)$(Platform)</IntermediateOutputPath>\r\n    <DefineConstants>TRACE</DefineConstants>\r\n    <Optimize>true</Optimize>\r\n    <DebugType>pdbonly</DebugType>\r\n    <PlatformTarget>x64</PlatformTarget>\r\n    <ErrorReport>prompt</ErrorReport>\r\n    <CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>\r\n  </PropertyGroup>\r\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)' == 'Appx|x86'\">\r\n    <OutputPath>$(SolutionDir)bin\\$(Configuration)$(Platform)</OutputPath>\r\n    <IntermediateOutputPath>$(SolutionDir)obj\\$(ProjectName)\\$(Configuration)$(Platform)</IntermediateOutputPath>\r\n    <DefineConstants>TRACE</DefineConstants>\r\n    <Optimize>true</Optimize>\r\n    <DebugType>pdbonly</DebugType>\r\n    <PlatformTarget>x86</PlatformTarget>\r\n    <ErrorReport>prompt</ErrorReport>\r\n    <CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>\r\n    <Prefer32Bit>true</Prefer32Bit>\r\n  </PropertyGroup>\r\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)' == 'Appx|x64'\">\r\n    <OutputPath>$(SolutionDir)bin\\$(Configuration)$(Platform)</OutputPath>\r\n    <IntermediateOutputPath>$(SolutionDir)obj\\$(ProjectName)\\$(Configuration)$(Platform)</IntermediateOutputPath>\r\n    <DefineConstants>TRACE</DefineConstants>\r\n    <Optimize>true</Optimize>\r\n    <DebugType>pdbonly</DebugType>\r\n    <PlatformTarget>x64</PlatformTarget>\r\n    <ErrorReport>prompt</ErrorReport>\r\n    <CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>\r\n    <Prefer32Bit>true</Prefer32Bit>\r\n  </PropertyGroup>\r\n  <ItemGroup>\r\n    <Reference Include=\"Mono.Cecil, Version=0.11.4.0, Culture=neutral, PublicKeyToken=50cebf1cceb9d05e, processorArchitecture=MSIL\">\r\n      <HintPath>..\\packages\\Mono.Cecil.0.11.4\\lib\\net40\\Mono.Cecil.dll</HintPath>\r\n    </Reference>\r\n    <Reference Include=\"Mono.Cecil.Mdb, Version=0.11.4.0, Culture=neutral, PublicKeyToken=50cebf1cceb9d05e, processorArchitecture=MSIL\">\r\n      <HintPath>..\\packages\\Mono.Cecil.0.11.4\\lib\\net40\\Mono.Cecil.Mdb.dll</HintPath>\r\n    </Reference>\r\n    <Reference Include=\"Mono.Cecil.Pdb, Version=0.11.4.0, Culture=neutral, PublicKeyToken=50cebf1cceb9d05e, processorArchitecture=MSIL\">\r\n      <HintPath>..\\packages\\Mono.Cecil.0.11.4\\lib\\net40\\Mono.Cecil.Pdb.dll</HintPath>\r\n    </Reference>\r\n    <Reference Include=\"Mono.Cecil.Rocks, Version=0.11.4.0, Culture=neutral, PublicKeyToken=50cebf1cceb9d05e, processorArchitecture=MSIL\">\r\n      <HintPath>..\\packages\\Mono.Cecil.0.11.4\\lib\\net40\\Mono.Cecil.Rocks.dll</HintPath>\r\n    </Reference>\r\n    <Reference Include=\"System\" />\r\n    <Reference Include=\"System.Data\" />\r\n    <Reference Include=\"System.Drawing\" />\r\n    <Reference Include=\"System.Windows.Forms\" />\r\n    <Reference Include=\"System.Xml\" />\r\n    <Reference Include=\"Microsoft.CSharp\" />\r\n    <Reference Include=\"System.Core\" />\r\n    <Reference Include=\"System.Xml.Linq\" />\r\n    <Reference Include=\"System.Data.DataSetExtensions\" />\r\n    <Reference Include=\"System.Net.Http\" />\r\n    <Reference Include=\"System.Xaml\">\r\n      <RequiredTargetFramework>4.0</RequiredTargetFramework>\r\n    </Reference>\r\n    <Reference Include=\"UIAutomationProvider\" />\r\n    <Reference Include=\"WindowsBase\" />\r\n    <Reference Include=\"PresentationCore\" />\r\n    <Reference Include=\"PresentationFramework\" />\r\n    <Reference Include=\"WindowsFormsIntegration\" />\r\n  </ItemGroup>\r\n  <ItemGroup>\r\n    <ApplicationDefinition Include=\"App.xaml\">\r\n      <Generator>MSBuild:Compile</Generator>\r\n      <SubType>Designer</SubType>\r\n    </ApplicationDefinition>\r\n    <Compile Include=\"About.xaml.cs\">\r\n      <DependentUpon>About.xaml</DependentUpon>\r\n    </Compile>\r\n    <Compile Include=\"CustomHeaderViewModel.cs\" />\r\n    <Compile Include=\"DependencyCustomListView.xaml.cs\">\r\n      <DependentUpon>DependencyCustomListView.xaml</DependentUpon>\r\n    </Compile>\r\n    <Compile Include=\"DependencyExportList.xaml.cs\">\r\n      <DependentUpon>DependencyExportList.xaml</DependentUpon>\r\n    </Compile>\r\n    <Compile Include=\"DependencyImportList.xaml.cs\">\r\n      <DependentUpon>DependencyImportList.xaml</DependentUpon>\r\n    </Compile>\r\n    <Compile Include=\"DependencyModuleList.xaml.cs\">\r\n      <DependentUpon>DependencyModuleList.xaml</DependentUpon>\r\n    </Compile>\r\n    <Compile Include=\"DragablzCustomHeader.cs\" />\r\n    <Compile Include=\"FilterControl\\FilterControl.cs\" />\r\n    <Compile Include=\"Helpers\\RelayCommand.cs\" />\r\n    <Compile Include=\"Helpers\\SettingBindingHandler.cs\" />\r\n    <Compile Include=\"Models\\ModuleInfo.cs\" />\r\n    <Compile Include=\"Models\\PeExport.cs\" />\r\n    <Compile Include=\"Models\\PeImport.cs\" />\r\n    <Compile Include=\"ModuleSearchOrder.xaml.cs\">\r\n      <DependentUpon>ModuleSearchOrder.xaml</DependentUpon>\r\n    </Compile>\r\n    <Compile Include=\"SearchFolder.xaml.cs\">\r\n      <DependentUpon>SearchFolder.xaml</DependentUpon>\r\n    </Compile>\r\n    <Compile Include=\"Settings.cs\" />\r\n    <Compile Include=\"Shell32IconExtractor.cs\" />\r\n    <Compile Include=\"UserSettings.xaml.cs\">\r\n      <DependentUpon>UserSettings.xaml</DependentUpon>\r\n    </Compile>\r\n    <Page Include=\"About.xaml\">\r\n      <SubType>Designer</SubType>\r\n      <Generator>MSBuild:Compile</Generator>\r\n    </Page>\r\n    <Page Include=\"DependencyCustomListView.xaml\">\r\n      <Generator>MSBuild:Compile</Generator>\r\n      <SubType>Designer</SubType>\r\n    </Page>\r\n    <Page Include=\"DependencyExportList.xaml\">\r\n      <SubType>Designer</SubType>\r\n      <Generator>MSBuild:Compile</Generator>\r\n    </Page>\r\n    <Page Include=\"DependencyImportList.xaml\">\r\n      <SubType>Designer</SubType>\r\n      <Generator>MSBuild:Compile</Generator>\r\n    </Page>\r\n    <Page Include=\"DependencyModuleList.xaml\">\r\n      <SubType>Designer</SubType>\r\n      <Generator>MSBuild:Compile</Generator>\r\n    </Page>\r\n    <Page Include=\"DependencyWindow.xaml\">\r\n      <SubType>Designer</SubType>\r\n      <Generator>MSBuild:Compile</Generator>\r\n    </Page>\r\n    <Page Include=\"DragablzCustomHeader.xaml\">\r\n      <Generator>MSBuild:Compile</Generator>\r\n      <SubType>Designer</SubType>\r\n    </Page>\r\n    <Page Include=\"FilterControl\\FilterControl.generic.xaml\">\r\n      <Generator>MSBuild:Compile</Generator>\r\n      <SubType>Designer</SubType>\r\n    </Page>\r\n    <Page Include=\"MainWindow.xaml\">\r\n      <Generator>MSBuild:Compile</Generator>\r\n      <SubType>Designer</SubType>\r\n    </Page>\r\n    <Compile Include=\"App.xaml.cs\">\r\n      <DependentUpon>App.xaml</DependentUpon>\r\n      <SubType>Code</SubType>\r\n    </Compile>\r\n    <Compile Include=\"DependencyWindow.xaml.cs\">\r\n      <DependentUpon>DependencyWindow.xaml</DependentUpon>\r\n    </Compile>\r\n    <Compile Include=\"GridViewSort.cs\" />\r\n    <Compile Include=\"MainWindow.xaml.cs\">\r\n      <DependentUpon>MainWindow.xaml</DependentUpon>\r\n      <SubType>Code</SubType>\r\n    </Compile>\r\n    <Page Include=\"ModuleSearchOrder.xaml\">\r\n      <SubType>Designer</SubType>\r\n      <Generator>MSBuild:Compile</Generator>\r\n    </Page>\r\n    <Page Include=\"SearchFolder.xaml\">\r\n      <SubType>Designer</SubType>\r\n      <Generator>MSBuild:Compile</Generator>\r\n    </Page>\r\n    <Page Include=\"UserSettings.xaml\">\r\n      <SubType>Designer</SubType>\r\n      <Generator>MSBuild:Compile</Generator>\r\n    </Page>\r\n  </ItemGroup>\r\n  <ItemGroup>\r\n    <Compile Include=\"Properties\\AssemblyInfo.cs\">\r\n      <SubType>Code</SubType>\r\n    </Compile>\r\n    <Compile Include=\"Properties\\Resources.Designer.cs\">\r\n      <AutoGen>True</AutoGen>\r\n      <DesignTime>True</DesignTime>\r\n      <DependentUpon>Resources.resx</DependentUpon>\r\n    </Compile>\r\n    <Compile Include=\"Properties\\Settings.Designer.cs\">\r\n      <AutoGen>True</AutoGen>\r\n      <DependentUpon>Settings.settings</DependentUpon>\r\n      <DesignTimeSharedInput>True</DesignTimeSharedInput>\r\n    </Compile>\r\n    <EmbeddedResource Include=\"Properties\\Resources.resx\">\r\n      <Generator>ResXFileCodeGenerator</Generator>\r\n      <LastGenOutput>Resources.Designer.cs</LastGenOutput>\r\n    </EmbeddedResource>\r\n    <None Include=\"Dependencies.manifest\" />\r\n    <None Include=\"packages.config\" />\r\n    <None Include=\"Properties\\Settings.settings\">\r\n      <Generator>SettingsSingleFileGenerator</Generator>\r\n      <LastGenOutput>Settings.Designer.cs</LastGenOutput>\r\n    </None>\r\n  </ItemGroup>\r\n  <ItemGroup>\r\n    <None Include=\"App.config\" />\r\n  </ItemGroup>\r\n  <ItemGroup>\r\n    <ProjectReference Include=\"..\\ClrPhlib\\ClrPhlib.vcxproj\">\r\n      <Project>{fc5ffcaf-982f-4a95-8fa6-2a95b1f7cdc8}</Project>\r\n      <Name>ClrPhlib</Name>\r\n    </ProjectReference>\r\n    <ProjectReference Include=\"..\\DependenciesLib\\DependenciesLib.csproj\">\r\n      <Project>{4a459493-14fc-4c87-9254-60e0959535da}</Project>\r\n      <Name>DependenciesLib</Name>\r\n    </ProjectReference>\r\n    <ProjectReference Include=\"..\\third_party\\Dragablz\\Dragablz\\Dragablz.net45.csproj\">\r\n      <Project>{7b11011c-7fd7-4ab0-a1ad-04e940b026de}</Project>\r\n      <Name>Dragablz.net45</Name>\r\n    </ProjectReference>\r\n  </ItemGroup>\r\n  <ItemGroup>\r\n    <Resource Include=\"Images\\Dependencies_48px.png\" />\r\n    <Resource Include=\"Images\\GlyphSortAscending.png\" />\r\n    <Resource Include=\"Images\\GlyphSortDescending.png\" />\r\n  </ItemGroup>\r\n  <ItemGroup>\r\n    <Resource Include=\"Images\\Hourglass.png\" />\r\n  </ItemGroup>\r\n  <ItemGroup>\r\n    <Resource Include=\"Images\\Question.png\" />\r\n  </ItemGroup>\r\n  <ItemGroup>\r\n    <Resource Include=\"Images\\Dependencies_32px.png\" />\r\n  </ItemGroup>\r\n  <ItemGroup>\r\n    <Resource Include=\"Images\\Dependencies_32px-no-blur.png\" />\r\n  </ItemGroup>\r\n  <ItemGroup>\r\n    <Resource Include=\"Images\\Dependencies_48px-no-blur.png\" />\r\n  </ItemGroup>\r\n  <ItemGroup>\r\n    <Resource Include=\"Images\\export_c.png\" />\r\n    <Resource Include=\"Images\\export_cpp.png\" />\r\n    <Resource Include=\"Images\\export_forward.png\" />\r\n    <Resource Include=\"Images\\export_ord.png\" />\r\n  </ItemGroup>\r\n  <ItemGroup>\r\n    <Resource Include=\"Images\\import_cpp_found.png\" />\r\n    <Resource Include=\"Images\\import_cpp_not_found.png\" />\r\n    <Resource Include=\"Images\\import_c_found.png\" />\r\n    <Resource Include=\"Images\\import_c_not_found.png\" />\r\n    <Resource Include=\"Images\\import_ord_not_found.png\" />\r\n  </ItemGroup>\r\n  <ItemGroup>\r\n    <Resource Include=\"Images\\import_ord_found.png\" />\r\n  </ItemGroup>\r\n  <ItemGroup>\r\n    <Resource Include=\"Dependencies.ico\" />\r\n  </ItemGroup>\r\n  <ItemGroup>\r\n    <Resource Include=\"Images\\Reference.png\" />\r\n  </ItemGroup>\r\n  <ItemGroup>\r\n    <Resource Include=\"Images\\InvalidOverlay.png\" />\r\n    <Resource Include=\"Images\\QuestionOverlay.png\" />\r\n    <Resource Include=\"Images\\ReferenceOverlay.png\" />\r\n  </ItemGroup>\r\n  <ItemGroup>\r\n    <Resource Include=\"Images\\HourglassOverlay.png\" />\r\n  </ItemGroup>\r\n  <Import Project=\"$(MSBuildToolsPath)\\Microsoft.CSharp.targets\" />\r\n</Project>"
  },
  {
    "path": "DependenciesGui/DependencyCustomListView.xaml",
    "content": "<ResourceDictionary \n                    \n    xmlns=\"http://schemas.microsoft.com/winfx/2006/xaml/presentation\"\n    xmlns:x=\"http://schemas.microsoft.com/winfx/2006/xaml\"\n    xmlns:mc=\"http://schemas.openxmlformats.org/markup-compatibility/2006\" \n    xmlns:d=\"http://schemas.microsoft.com/expression/blend/2008\" \n    xmlns:local=\"clr-namespace:Dependencies\"\n    xmlns:util=\"clr-namespace:Wpf.Util\"\n    xmlns:properties=\"clr-namespace:Dependencies.Properties\"\n    mc:Ignorable=\"d\" \n    x:Class=\"DependencyCustomListView\"\n>\n    <Style x:Key=\"LeftAlignHeader\" TargetType=\"{x:Type GridViewColumnHeader}\">\n        <Setter Property=\"HorizontalContentAlignment\" Value=\"Left\"></Setter>\n        <Setter Property=\"Padding\" Value=\"5,0,0,0\"></Setter>\n    </Style>\n\n    <Style x:Key=\"DependencyCustomListViewItem\" TargetType=\"{x:Type ListViewItem}\">\n         <Setter Property=\"HorizontalContentAlignment\" Value=\"Stretch\" />\n        <Setter Property=\"FontFamily\" Value=\"{Binding Source={x:Static properties:Settings.Default}, Path=Font, Mode=OneWay}\" />\n        <Setter Property=\"ContextMenu\" Value=\"{DynamicResource ResourceKey=ItemContextMenu}\" />\n        <Setter Property=\"ToolTip\" Value=\"{Binding Status }\" />\n    </Style>\n\n    <Style x:Key=\"DependencyCustomListViewStyle\" TargetType=\"{x:Type local:DependencyCustomListView}\">\n        <Setter Property=\"HorizontalContentAlignment\" Value=\"Stretch\"/>\n        <Setter Property=\"VerticalContentAlignment\" Value=\"Stretch\"/>\n        <Setter Property=\"util:GridViewSort.AutoSort\" Value=\"True\"/>\n        <Setter Property=\"ItemContainerStyle\" Value=\"{StaticResource DependencyCustomListViewItem}\"/>\n        \n        \n\n        <Setter Property=\"Template\">\n            <Setter.Value>\n                <ControlTemplate TargetType=\"{x:Type local:DependencyCustomListView}\">\n                    <Border x:Name=\"_Border\" Background=\"White\" BorderBrush=\"#FF828790\" BorderThickness=\"1,1,1,1\">\n                        <Grid  x:Name=\"_Grid\"   SnapsToDevicePixels=\"true\">\n\n                            <Grid.RowDefinitions>\n                                <RowDefinition Height=\"46*\"/>\n                                <RowDefinition  Height=\"auto\" MaxHeight=\"25\"/>\n                            </Grid.RowDefinitions>\n\n                            <ScrollViewer Style=\"{DynamicResource {x:Static GridView.GridViewScrollViewerStyleKey}}\" >\n                                <ItemsPresenter x:Name=\"ContentsItems\" Grid.Row=\"0\"/>\n                            </ScrollViewer>\n\n\n                            <!-- TargetControl is patched at runtime -->\n                            <local:FilterControl x:Name=\"PART_SearchBar\"\n                                Height=\"25\" Grid.Row=\"1\"\n                                FilterTextBindingPath=\"{TemplateBinding SearchListFilter}\"\n                                FilterFiringInterval=\"20\"\n                            />\n\n                        </Grid>\n                    </Border>\n                </ControlTemplate>\n            </Setter.Value>\n        </Setter>\n    </Style>\n</ResourceDictionary> "
  },
  {
    "path": "DependenciesGui/DependencyCustomListView.xaml.cs",
    "content": "using System;\nusing System.Collections.Generic;\nusing System.Windows.Controls;\nusing System.Windows.Input;\nusing System.Diagnostics;\nusing System.Windows;\n\nnamespace Dependencies\n{\n\n    /// <summary>\n    /// DependencyImportList  Filterable ListView for displaying exports.\n    /// @TODO(Make this a template user control in order to share it between Modeules, Imports and Exports)\n    /// </summary>\n    [TemplatePart(Name = PART_SearchBar, Type = typeof(FilterControl))]\n    public partial class DependencyCustomListView : ListView\n    {\n\n        private const string PART_SearchBar = \"PART_SearchBar\";\n        public FilterControl SearchBar = null;\n\n        public DependencyCustomListView()\n        {\n            this.KeyDown += new KeyEventHandler(OnListViewKeyDown);\n        }\n\n\n        public static readonly DependencyProperty SearchListFilterProperty = DependencyProperty.Register(\n            \"SearchListFilter\", typeof(string), typeof(DependencyCustomListView), new PropertyMetadata(null));\n\n        public string SearchListFilter\n        {\n            get { return (string)GetValue(SearchListFilterProperty); }\n            set { SetValue(SearchListFilterProperty, value); }\n        }\n\n\n        public static readonly DependencyProperty CopyHandlerProperty = DependencyProperty.Register(\n            \"CopyHandler\", typeof(Func<object, string>), typeof(DependencyCustomListView), new PropertyMetadata(null));\n\n        public Func<object, string> CopyHandler\n        {\n            get { return (Func<object, string>)GetValue(CopyHandlerProperty); }\n            set { SetValue(CopyHandlerProperty, value); }\n        }\n\n        \n        public override void OnApplyTemplate()\n        {\n            base.OnApplyTemplate();\n\n            AttachToVisualTree();\n        }\n\n        \n        private void AttachToVisualTree()\n        {\n            SearchBar = GetTemplateChild(PART_SearchBar) as FilterControl;\n            SearchBar.TargetControl = this;\n        }\n\n\n\n        #region events handlers\n        protected virtual void OnListViewKeyDown(object sender, System.Windows.Input.KeyEventArgs e)\n        {\n            System.Windows.Controls.ListView ListView = sender as System.Windows.Controls.ListView;\n            bool CtrlKeyDown = Keyboard.IsKeyDown(System.Windows.Input.Key.LeftCtrl) || Keyboard.IsKeyDown(System.Windows.Input.Key.RightCtrl);\n\t\t\tbool ShiftKeyDown = Keyboard.IsKeyDown(System.Windows.Input.Key.LeftShift) || Keyboard.IsKeyDown(System.Windows.Input.Key.RightShift);\n\n\t\t\tDebug.WriteLine(\"[DependencyCustomListView] Key Pressed : \" + e.Key + \". Ctrl Key down : \" + CtrlKeyDown);\n            if ((e.Key == System.Windows.Input.Key.C) && CtrlKeyDown && !ShiftKeyDown)\n\t\t\t{\n                List<string> StrToCopy = new List<string>();\n                foreach (object SelectItem in ListView.SelectedItems)\n                {\n                    StrToCopy.Add(CopyHandler(SelectItem));\n                }\n\n                System.Windows.Clipboard.Clear();\n\n\t\t\t\t// sometimes another process has \"opened\" the clipboard, so we need to wait for it\n\t\t\t\ttry\n\t\t\t\t{\n\t\t\t\t\tClipboard.SetText((string)String.Join(\"\\n\", StrToCopy), TextDataFormat.Text);\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\tcatch { }\n            }\n\n            else if ((e.Key == System.Windows.Input.Key.F) && CtrlKeyDown)\n            {\n                if (this.SearchBar != null)\n                {\n                    this.SearchBar.Visibility = System.Windows.Visibility.Visible;\n                    this.SearchBar.Focus();\n                }\n\n                return;\n            }\n\n            else if (e.Key == Key.Escape)\n            {\n                if (this.SearchBar != null)\n                {\n                    this.SearchBar.Clear();\n                }\n            }\n        }\n        #endregion events handlers\n        \n    }\n}\n"
  },
  {
    "path": "DependenciesGui/DependencyExportList.xaml",
    "content": "﻿<local:DependencyCustomListView x:Class=\"Dependencies.DependencyExportList\"\n        xmlns=\"http://schemas.microsoft.com/winfx/2006/xaml/presentation\"\n        xmlns:x=\"http://schemas.microsoft.com/winfx/2006/xaml\"\n        xmlns:mc=\"http://schemas.openxmlformats.org/markup-compatibility/2006\" \n        xmlns:d=\"http://schemas.microsoft.com/expression/blend/2008\" \n        xmlns:properties=\"clr-namespace:Dependencies.Properties\"\n        xmlns:local=\"clr-namespace:Dependencies\"\n        xmlns:util=\"clr-namespace:Wpf.Util\"\n        mc:Ignorable=\"d\" \n        d:DesignHeight=\"300\" d:DesignWidth=\"300\"\n                                \n        Style=\"{StaticResource DependencyCustomListViewStyle}\"\n        SearchListFilter=\"Name\"\n        CopyHandler=\"ExportCopyHandler\"\n    >\n    \n    <local:DependencyCustomListView.CommandBindings>\n        <CommandBinding Command=\"local:DependencyExportList.CopyValuesCommand\" Executed=\"ExportListCopySelectedValues\"></CommandBinding>\n    </local:DependencyCustomListView.CommandBindings>\n    \n    <local:DependencyCustomListView.Resources>\n        <ContextMenu x:Key=\"ItemContextMenu\">\n            <MenuItem Header = \"Copy\"\n                                Command=\"local:DependencyExportList.CopyValuesCommand\"\n                                InputGestureText=\"Ctrl+C\"  \n                                IsEnabled=\"True\"/>\n            <MenuItem HeaderStringFormat= \"Copy {0:s}\"\n                                Header = \"{Binding DataContext.Name, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=Grid}}\"\n                                Command=\"{Binding Path=DataContext.CopyValue, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type Grid},AncestorLevel=1 }}\"\n                                CommandParameter =\"{Binding DataContext.Name, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=Grid }}\"\n                                InputGestureText=\"Ctrl+Maj+C\"  \n                                IsEnabled=\"True\"/>\n            <MenuItem Header=\"Select All\" \n                                Command=\"ApplicationCommands.SelectAll\" \n                                IsEnabled=\"True\"/>\n            <Separator Height=\"3\" Margin=\"-1,0,0,0\"/>\n            <MenuItem Header=\"_Undecorate C++ Functions\" Height=\"26\" InputGestureText=\"F10\" IsCheckable=\"True\" IsChecked=\"{Binding Source={x:Static properties:Settings.Default}, Path=Undecorate, Mode=TwoWay }\"/>\n            <Separator Height=\"3\" Margin=\"-1,0,0,0\"/>\n            <MenuItem Header=\"Lookup Export function on MSDN\"  \n                            Command=\"{Binding Path=DataContext.QueryExportApi, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type Grid},AncestorLevel=1 }}\"\n                            CommandParameter =\"{Binding DataContext , RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=Grid}}\"\n                            InputGestureText=\"Alt+Enter\"  \n                            IsEnabled=\"True\" />\n        </ContextMenu>\n    </local:DependencyCustomListView.Resources>\n   \n\n    <local:DependencyCustomListView.View>\n        <GridView AllowsColumnReorder=\"true\">\n            <GridViewColumn Width=\"40\" Header=\"E\" util:GridViewSort.PropertyName=\"Type\">\n                <GridViewColumn.HeaderContainerStyle>\n                    <Style TargetType=\"{x:Type GridViewColumnHeader}\">\n                        <Setter Property=\"Control.ToolTip\" Value=\"Selected's module exports\"/>\n                        <Setter Property=\"HorizontalContentAlignment\" Value=\"Left\"></Setter>\n                        <Setter Property=\"Padding\" Value=\"5,0,0,0\"></Setter>\n                    </Style>\n                </GridViewColumn.HeaderContainerStyle>\n\n                <GridViewColumn.CellTemplate>\n                    <DataTemplate>\n                        <Image Width=\"30\" Height=\"14\" Source=\"{Binding IconUri}\"/>\n                    </DataTemplate>\n                </GridViewColumn.CellTemplate>\n            </GridViewColumn>\n            <GridViewColumn Header=\"Ordinal\" Width=\"140\" util:GridViewSort.PropertyName=\"Ordinal\" HeaderContainerStyle=\"{StaticResource LeftAlignHeader}\">\n                <GridViewColumn.CellTemplate>\n                    <DataTemplate>\n                        <TextBlock Text=\"{Binding Ordinal, StringFormat={}{0} (0x{0:x04}) }\" TextAlignment=\"Right\" HorizontalAlignment=\"Right\"/>\n                    </DataTemplate>\n                </GridViewColumn.CellTemplate>\n            </GridViewColumn>\n            <GridViewColumn Header=\"Hint\" Width=\"140\" util:GridViewSort.PropertyName=\"Hint\" HeaderContainerStyle=\"{StaticResource LeftAlignHeader}\">\n                <GridViewColumn.CellTemplate>\n                    <DataTemplate>\n                        <TextBlock Text=\"{Binding Hint, StringFormat={}{0} (0x{0:x04}), TargetNullValue='N/A' }\" TextAlignment=\"Right\" />\n                    </DataTemplate>\n                </GridViewColumn.CellTemplate>\n            </GridViewColumn>\n            <GridViewColumn Header=\"Function\" Width=\"250\" DisplayMemberBinding=\"{Binding Name}\" util:GridViewSort.PropertyName=\"Name\" HeaderContainerStyle=\"{StaticResource LeftAlignHeader}\"/>\n            <GridViewColumn Header=\"VirtualAddress\" Width=\"250\" DisplayMemberBinding=\"{Binding VirtualAddress}\" util:GridViewSort.PropertyName=\"VirtualAddress\" HeaderContainerStyle=\"{StaticResource LeftAlignHeader}\"/>\n            <GridViewColumn Header=\"Demangler\" Width=\"250\" DisplayMemberBinding=\"{Binding Demangler}\" util:GridViewSort.PropertyName=\"Name\" HeaderContainerStyle=\"{StaticResource LeftAlignHeader}\"/>\n        </GridView>\n    </local:DependencyCustomListView.View>\n</local:DependencyCustomListView>\n "
  },
  {
    "path": "DependenciesGui/DependencyExportList.xaml.cs",
    "content": "﻿using System;\nusing System.Linq;\nusing System.Windows;\nusing System.Collections.Generic;\nusing System.Windows.Input;\n\nusing Dependencies.ClrPh;\n\nnamespace Dependencies\n{\n    /// <summary>\n    /// DependencyImportList  Filterable ListView for displaying exports.\n    /// </summary>\n    public partial class DependencyExportList : DependencyCustomListView\n    {\n\t\tpublic static readonly RoutedUICommand CopyValuesCommand = new RoutedUICommand();\n\n\t\tpublic DependencyExportList()\n        {\n           InitializeComponent();\n        }\n\n        public void SetExports(List<PeExport> Exports, PhSymbolProvider SymPrv)\n        {\n            this.Items.Clear();\n\n            foreach (PeExport Export in Exports)\n            {\n                this.Items.Add(new DisplayPeExport(Export, SymPrv));\n            }\n        }\n\n        private string ExportCopyHandler(object SelectedItem)\n        {\n            if (SelectedItem == null)\n            {\n                return \"\";\n            }\n\n            return (SelectedItem as DisplayPeExport).ToString();\n        }\n\n\t\tprivate void ExportListCopySelectedValues(object sender, RoutedEventArgs e)\n\t\t{\n\t\t\tif (this.SelectedItems.Count == 0)\n\t\t\t\treturn;\n\n\t\t\tList<DisplayPeExport> selectedExports = new List<DisplayPeExport>();\n\t\t\tforeach (var import in this.SelectedItems)\n\t\t\t{\n\t\t\t\tselectedExports.Add((import as DisplayPeExport));\n\t\t\t}\n\n\t\t\tstring SelectedValues = String.Join(\"\\n\", selectedExports.Select(exp => exp.ToString()));\n\n\t\t\tClipboard.Clear();\n\n\t\t\t// sometimes another process has \"opened\" the clipboard, so we need to wait for it\n\t\t\ttry\n\t\t\t{\n\t\t\t\tClipboard.SetText((string)SelectedValues, TextDataFormat.Text);\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tcatch { }\n\t\t}\n\n\t\tpublic void ResetAutoSortProperty()\n\t\t{\n\t\t\tWpf.Util.GridViewSort.RemoveSort(this.Items, this);\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "DependenciesGui/DependencyImportList.xaml",
    "content": "﻿<local:DependencyCustomListView x:Class=\"Dependencies.DependencyImportList\"\n        xmlns=\"http://schemas.microsoft.com/winfx/2006/xaml/presentation\"\n        xmlns:x=\"http://schemas.microsoft.com/winfx/2006/xaml\"\n        xmlns:mc=\"http://schemas.openxmlformats.org/markup-compatibility/2006\" \n        xmlns:d=\"http://schemas.microsoft.com/expression/blend/2008\" \n        xmlns:local=\"clr-namespace:Dependencies\"\n        xmlns:util=\"clr-namespace:Wpf.Util\"\n        xmlns:properties=\"clr-namespace:Dependencies.Properties\"\n        mc:Ignorable=\"d\" \n        d:DesignHeight=\"300\" d:DesignWidth=\"300\"\n\n        Style=\"{StaticResource DependencyCustomListViewStyle}\"\n        SearchListFilter=\"FilterName\"\n        CopyHandler=\"ImportCopyHandler\"\n    >\n\n    <local:DependencyCustomListView.CommandBindings>\n        <CommandBinding Command=\"local:DependencyImportList.CopyValuesCommand\" Executed=\"ImportListCopySelectedValues\"></CommandBinding>\n    </local:DependencyCustomListView.CommandBindings>\n\n    <local:DependencyCustomListView.Resources>\n        <ContextMenu x:Key=\"ItemContextMenu\">\n            <MenuItem Header = \"Copy\"\n                                Command=\"local:DependencyImportList.CopyValuesCommand\"\n                                InputGestureText=\"Ctrl+C\"  \n                                IsEnabled=\"True\"/>\n            <MenuItem HeaderStringFormat= \"Copy {0:s}\"\n                                Header = \"{Binding DataContext.Name, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=Grid}}\"\n                                Command=\"{Binding Path=DataContext.CopyValue, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type Grid},AncestorLevel=1 }}\"\n                                CommandParameter =\"{Binding DataContext.Name, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=Grid }}\"\n                                InputGestureText=\"Ctrl+Maj+C\"  \n                                IsEnabled=\"True\"/>\n            <MenuItem Header=\"Select All\" \n                                Command=\"ApplicationCommands.SelectAll\" \n                                IsEnabled=\"True\"/>\n            <Separator Height=\"3\" Margin=\"-1,0,0,0\"/>\n            <MenuItem Header=\"_Undecorate C++ Functions\" \n                                Height=\"26\" InputGestureText=\"F10\" \n                                IsCheckable=\"True\" IsChecked=\"{Binding Source={x:Static properties:Settings.Default}, Path=Undecorate, Mode=TwoWay }\"/>\n            <Separator Height=\"3\" Margin=\"-1,0,0,0\"/>\n            <MenuItem Header=\"Lookup Import function on MSDN\"  \n                            Command=\"{Binding Path=DataContext.QueryImportApi, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type Grid},AncestorLevel=1 }}\"\n                            CommandParameter =\"{Binding DataContext , RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=Grid}}\"\n                            InputGestureText=\"Alt+Enter\"  \n                            IsEnabled=\"True\" />\n        </ContextMenu>\n    </local:DependencyCustomListView.Resources>\n\n\n    <local:DependencyCustomListView.View>\n        <GridView AllowsColumnReorder=\"true\">\n            <GridViewColumn Width=\"40\" Header=\"PI\" util:GridViewSort.PropertyName=\"Type\" >\n                <GridViewColumn.HeaderContainerStyle>\n                    <Style TargetType=\"{x:Type GridViewColumnHeader}\">\n                        <Setter Property=\"Control.ToolTip\" Value=\"Selected's module imports\"/>\n                        <Setter Property=\"HorizontalContentAlignment\" Value=\"Left\"></Setter>\n                        <Setter Property=\"Padding\" Value=\"5,0,0,0\"></Setter>\n                    </Style>\n                </GridViewColumn.HeaderContainerStyle>\n                \n                <GridViewColumn.CellTemplate>\n                    <DataTemplate>\n                        <Image Width=\"30\" Height=\"14\" Source=\"{Binding IconUri}\"/>\n                    </DataTemplate>\n                </GridViewColumn.CellTemplate>\n            </GridViewColumn>\n            <GridViewColumn Header=\"Ordinal\" Width=\"140\" util:GridViewSort.PropertyName=\"Ordinal\" HeaderContainerStyle=\"{StaticResource LeftAlignHeader}\">\n                <GridViewColumn.CellTemplate>\n                    <DataTemplate>\n                        <TextBlock Text=\"{Binding Ordinal, StringFormat={}{0} (0x{0:x04}), TargetNullValue='N/A' }\" TextAlignment=\"Right\" />\n                    </DataTemplate>\n                </GridViewColumn.CellTemplate>\n            </GridViewColumn>\n            <GridViewColumn Header=\"Hint\" Width=\"140\" util:GridViewSort.PropertyName=\"Hint\" HeaderContainerStyle=\"{StaticResource LeftAlignHeader}\">\n                <GridViewColumn.CellTemplate>\n                    <DataTemplate>\n                        <TextBlock Text=\"{Binding Hint, StringFormat={}{0} (0x{0:x04}), TargetNullValue='N/A' }\" TextAlignment=\"Right\" />\n                    </DataTemplate>\n                </GridViewColumn.CellTemplate>\n            </GridViewColumn>\n            <GridViewColumn Header=\"Function\" Width=\"250\" DisplayMemberBinding=\"{Binding Name}\" util:GridViewSort.PropertyName=\"Name\" HeaderContainerStyle=\"{StaticResource LeftAlignHeader}\"/>\n            <GridViewColumn Header=\"Module\" Width=\"300\" DisplayMemberBinding=\"{Binding ModuleName}\" util:GridViewSort.PropertyName=\"ModuleName\" HeaderContainerStyle=\"{StaticResource LeftAlignHeader}\"/>\n            <GridViewColumn Header=\"Delayed\" Width=\"100\" DisplayMemberBinding=\"{Binding DelayImport}\" util:GridViewSort.PropertyName=\"DelayImport\" HeaderContainerStyle=\"{StaticResource LeftAlignHeader}\"/>\n            <GridViewColumn Header=\"Demangler\" Width=\"250\" DisplayMemberBinding=\"{Binding Demangler}\" util:GridViewSort.PropertyName=\"Name\" HeaderContainerStyle=\"{StaticResource LeftAlignHeader}\"/>\n        </GridView>\n    </local:DependencyCustomListView.View>\n</local:DependencyCustomListView>\n"
  },
  {
    "path": "DependenciesGui/DependencyImportList.xaml.cs",
    "content": "﻿using System;\nusing System.Linq;\nusing System.Windows;\nusing System.Collections.Generic;\nusing System.Windows.Input;\n\nusing Dependencies.ClrPh;\n\nnamespace Dependencies\n{\n    /// <summary>\n    /// DependencyImportList  Filterable ListView for displaying imports.\n    /// </summary>\n    public partial class DependencyImportList : DependencyCustomListView\n    {\n\t\tpublic static readonly RoutedUICommand CopyValuesCommand = new RoutedUICommand();\n\n\t\tpublic DependencyImportList()\n        {\n            InitializeComponent();\n        }\n\n\t\tpublic void SetImports(string ModuleFilepath, List<PeExport> Exports, List<PeImportDll> ParentImports, PhSymbolProvider SymPrv, DependencyWindow Dependencies)\n\t\t{\n\t\t\tthis.Items.Clear();\n\n\t\t\tforeach (PeImportDll DllImport in ParentImports)\n\t\t\t{\n\t\t\t\tforeach (var Import in BinaryCache.LookupImports(DllImport, Exports))\n\t\t\t\t{\n\t\t\t\t\tthis.Items.Add(new DisplayPeImport(Import.Item1, SymPrv, ModuleFilepath, Import.Item2));\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n        public void SetRootImports(List<PeImportDll> Imports, PhSymbolProvider SymPrv, DependencyWindow Dependencies)\n        {\n            this.Items.Clear();\n\n            foreach (PeImportDll DllImport in Imports)\n            {\n\n                PE ModuleImport = Dependencies.LoadImport(DllImport.Name, null, DllImport.IsDelayLoad() );\n                string ModuleFilepath = (ModuleImport != null) ? ModuleImport.Filepath : null;\n\n                foreach( var Import in BinaryCache.LookupImports(DllImport, ModuleFilepath))\n                {\n                    this.Items.Add(new DisplayPeImport(Import.Item1, SymPrv, ModuleFilepath, Import.Item2));\n                }\n            }\n        }\n\n        private string ImportCopyHandler(object SelectedItem)\n        {\n            if (SelectedItem == null)\n            {\n                return \"\";\n            }\n\n            return (SelectedItem as DisplayPeImport).ToString();\n        }\n\n\t\tprivate void ImportListCopySelectedValues(object sender, RoutedEventArgs e)\n\t\t{\n\t\t\tif (this.SelectedItems.Count == 0)\n\t\t\t\treturn;\n\n\t\t\tList<DisplayPeImport> selectedImports = new List<DisplayPeImport>();\n\t\t\tforeach (var import in this.SelectedItems)\n\t\t\t{\n\t\t\t\tselectedImports.Add((import as DisplayPeImport));\n\t\t\t}\n\n\t\t\tstring SelectedValues = String.Join(\"\\n\", selectedImports.Select( imp => imp.ToString()));\n\n\t\t\tClipboard.Clear();\n\t\t\t// sometimes another process has \"opened\" the clipboard, so we need to wait for it\n\t\t\ttry\n\t\t\t{\n\t\t\t\tClipboard.SetText((string)SelectedValues, TextDataFormat.Text);\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tcatch { }\n\t\t\t\n\t\t}\n\n\t\tpublic void ResetAutoSortProperty()\n\t\t{\n\t\t\tWpf.Util.GridViewSort.RemoveSort(this.Items, this);\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "DependenciesGui/DependencyModuleList.xaml",
    "content": "﻿<local:DependencyCustomListView x:Class=\"Dependencies.DependencyModuleList\"\n        xmlns=\"http://schemas.microsoft.com/winfx/2006/xaml/presentation\"\n        xmlns:x=\"http://schemas.microsoft.com/winfx/2006/xaml\"\n        xmlns:mc=\"http://schemas.openxmlformats.org/markup-compatibility/2006\" \n        xmlns:d=\"http://schemas.microsoft.com/expression/blend/2008\" \n        xmlns:local=\"clr-namespace:Dependencies\"\n        xmlns:properties=\"clr-namespace:Dependencies.Properties\"\n        xmlns:util=\"clr-namespace:Wpf.Util\"\n        mc:Ignorable=\"d\" \n        d:DesignHeight=\"300\" d:DesignWidth=\"300\"\n                                \n        Style=\"{StaticResource DependencyCustomListViewStyle}\"\n        SearchListFilter=\"ModuleName\"\n        CopyHandler=\"ModuleCopyHandler\"\n                                \n        PreviewMouseLeftButtonUp=\"OnSelectedModuleChanged\"\n    >\n\n    <local:DependencyCustomListView.Resources>\n        <local:ImageToHeaderConverter x:Key=\"img\"/>\n        <local:OverlayImageToHeaderConverter x:Key=\"img_overlay\"/>\n\n        <ContextMenu x:Key=\"ItemContextMenu\">\n\n            <MenuItem Header=\"Highlight Matching Module In Tree\"\n                                Command=\"{Binding DataContext.DoFindModuleInTreeCommand, RelativeSource={RelativeSource AncestorType=ContextMenu}}\"\n                                CommandParameter =\"{Binding Path=PlacementTarget.DataContext, RelativeSource={RelativeSource AncestorType=ContextMenu} }\"\n                                InputGestureText=\"Ctrl+M\"\n                                IsEnabled=\"True\" />\n            <Separator Height=\"3\" Margin=\"-1,0,0,0\"/>\n            <MenuItem HeaderStringFormat= \"Copy {0:s}\"\n                                    Header = \"{Binding DataContext.ModuleName, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=Grid}}\"\n                                    Command=\"{Binding Path=DataContext.CopyValue, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type Grid},AncestorLevel=1 }}\"\n                                    CommandParameter =\"{Binding DataContext.ModuleName, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=Grid }}\"\n                                    InputGestureText=\"Ctrl+C\"  \n                                    IsEnabled=\"True\"/>\n            <MenuItem Header=\"Select All\" \n                                Command=\"ApplicationCommands.SelectAll\" \n                                IsEnabled=\"True\"\n                                />\n            <Separator Height=\"3\" Margin=\"-1,0,0,0\"/>\n            <MenuItem x:Name=\"FullPathItemModules\" Header=\"Full Paths\" Height=\"25\" InputGestureText=\"F9\" IsCheckable=\"True\" IsChecked=\"{Binding Source={x:Static properties:Settings.Default}, Path=FullPath, Mode=TwoWay}\" Margin=\"0,0,0.2,0\"/>\n            <Separator Height=\"3\" Margin=\"-1,0,0,0\"/>\n            <MenuItem Header=\"View Module in separate application\" \n                                Command=\"{Binding Path=PlacementTarget.DataContext.OpenNewAppCommand, RelativeSource={RelativeSource AncestorType=ContextMenu} }\"\n                                CommandParameter =\"{Binding Path=PlacementTarget.DataContext, RelativeSource={RelativeSource AncestorType=ContextMenu} }\"\n                                InputGestureText=\"Maj+Enter\"  \n                                IsEnabled=\"True\" />\n            <MenuItem Header=\"View Module in Peviewer\" \n                                Command=\"{Binding Path=PlacementTarget.DataContext.OpenPeviewerCommand, RelativeSource={RelativeSource AncestorType=ContextMenu} }\"\n                                CommandParameter =\"{Binding Path=PlacementTarget.DataContext, RelativeSource={RelativeSource AncestorType=ContextMenu} }\"\n                                InputGestureText=\"Alt+Enter\"  \n                                IsEnabled=\"True\" />\n            <Separator Height=\"3\" Margin=\"-1,0,0,0\"/>\n            <MenuItem x:Name=\"ModuleSearchOrderItem\" \n                      Header=\"View _Module search order\" \n                      Command=\"{Binding DataContext.ConfigureSearchOrderCommand, RelativeSource={RelativeSource AncestorType=ContextMenu}}\"\n                      CommandParameter =\"{Binding Path=PlacementTarget.DataContext, RelativeSource={RelativeSource AncestorType=ContextMenu} }\"\n                      InputGestureText=\"Maj+M\" \n                      IsEnabled=\"True\"/>\n\n        </ContextMenu>\n\n\n    </local:DependencyCustomListView.Resources>\n\n    <local:DependencyCustomListView.View>\n\n        <GridView AllowsColumnReorder=\"true\">\n            <GridViewColumn Header=\"\" Width=\"50\" util:GridViewSort.PropertyName=\"Type\">\n                <GridViewColumn.CellTemplate>\n                    <DataTemplate>\n                        <Grid Margin=\"0,2\">\n                            <Grid.ColumnDefinitions>\n                                <ColumnDefinition Width=\"24\" />\n                                <ColumnDefinition Width=\"3\" />\n                            </Grid.ColumnDefinitions>\n\n                            <Image Grid.Column=\"0\" Width=\"16\" Height=\"16\" Margin=\"0,0,0,0\" Source=\"{Binding  Filepath, Converter={StaticResource img}}\"></Image>\n                            <Image Grid.Column=\"0\" Width=\"16\" Height=\"16\" Margin=\"4,0,0,0\" Source=\"{Binding  Flags, Converter={StaticResource img_overlay}}\"></Image>\n                        </Grid>\n                    </DataTemplate>\n                </GridViewColumn.CellTemplate>\n            </GridViewColumn>\n            <GridViewColumn Header=\"Module\" Width=\"300\" DisplayMemberBinding=\"{Binding ModuleName, TargetNullValue='N/A'}\" util:GridViewSort.PropertyName=\"ModuleName\" HeaderContainerStyle=\"{StaticResource LeftAlignHeader}\"/>\n            <GridViewColumn Header=\"Machine\"  Width=\"60\" DisplayMemberBinding=\"{Binding Cpu, TargetNullValue='N/A'}\" util:GridViewSort.PropertyName=\"Cpu\" HeaderContainerStyle=\"{StaticResource LeftAlignHeader}\"/>\n            <GridViewColumn Header=\"Type\" Width=\"150\" DisplayMemberBinding=\"{Binding Type, TargetNullValue='N/A'}\" util:GridViewSort.PropertyName=\"Type\" HeaderContainerStyle=\"{StaticResource LeftAlignHeader}\"/>\n            <GridViewColumn Header=\"File Size\" Width=\"100\" DisplayMemberBinding=\"{Binding Filesize, TargetNullValue='N/A', StringFormat={}0x{0:x08}}\" util:GridViewSort.PropertyName=\"FileSize\" HeaderContainerStyle=\"{StaticResource LeftAlignHeader}\"/>\n            <GridViewColumn Header=\"Image Base\" Width=\"100\" DisplayMemberBinding=\"{Binding ImageBase, TargetNullValue='N/A', StringFormat={}0x{0:x08}}\" util:GridViewSort.PropertyName=\"ImageBase\" HeaderContainerStyle=\"{StaticResource LeftAlignHeader}\"/>\n            <GridViewColumn Header=\"Virtual Size\" Width=\"100\" DisplayMemberBinding=\"{Binding VirtualSize, TargetNullValue='N/A', StringFormat={}0x{0:x08}}\" util:GridViewSort.PropertyName=\"VirtualSize\" HeaderContainerStyle=\"{StaticResource LeftAlignHeader}\"/>\n            <GridViewColumn Header=\"Entry point\" Width=\"100\" DisplayMemberBinding=\"{Binding EntryPoint, TargetNullValue='N/A', StringFormat={}0x{0:x08}}\" util:GridViewSort.PropertyName=\"EntryPoint\" HeaderContainerStyle=\"{StaticResource LeftAlignHeader}\"/>\n            <GridViewColumn Header=\"Subsystem\" Width=\"100\" DisplayMemberBinding=\"{Binding Subsystem, TargetNullValue='N/A', StringFormat={}0x{0:x08}}\" util:GridViewSort.PropertyName=\"Subsystem\" HeaderContainerStyle=\"{StaticResource LeftAlignHeader}\"/>\n            <GridViewColumn Header=\"Subsystem Ver.\" Width=\"100\" DisplayMemberBinding=\"{Binding SubsystemVersion, TargetNullValue='N/A'}\" util:GridViewSort.PropertyName=\"SubsystemVersion\" HeaderContainerStyle=\"{StaticResource LeftAlignHeader}\"/>\n            <GridViewColumn Header=\"Checksum\" Width=\"200\" util:GridViewSort.PropertyName=\"Checksum\" HeaderContainerStyle=\"{StaticResource LeftAlignHeader}\">\n                <GridViewColumn.CellTemplate>\n                    <DataTemplate>\n                        <TextBlock  TextAlignment=\"Right\">\n                            <TextBlock.Style>\n                                <Style TargetType=\"{x:Type TextBlock}\">\n                                    \n                                    <Style.Triggers>\n                                        <DataTrigger Binding=\"{Binding CorrectChecksum , TargetNullValue='False'}\" Value=\"False\" >\n                                            <Setter Property=\"Text\" Value=\"{Binding Checksum, StringFormat={}0x{0:x08} (incorrect), TargetNullValue='N/A' }\"/>\n                                        </DataTrigger>\n\n                                        <DataTrigger Binding=\"{Binding CorrectChecksum}\" Value=\"True\" >\n                                            <Setter Property=\"Text\" Value=\"{Binding Checksum, StringFormat={}0x{0:x08} (correct), TargetNullValue='N/A' }\"/>\n                                        </DataTrigger>\n                                    </Style.Triggers>\n                                </Style>\n                            </TextBlock.Style>\n                        </TextBlock>\n                    </DataTemplate>\n                </GridViewColumn.CellTemplate>\n            </GridViewColumn>\n        </GridView>\n    </local:DependencyCustomListView.View>\n</local:DependencyCustomListView>\n"
  },
  {
    "path": "DependenciesGui/DependencyModuleList.xaml.cs",
    "content": "﻿using System;\nusing System.Windows;\nusing System.Collections.Generic;\nusing System.Windows.Controls;\nusing System.Windows.Input;\nusing System.Diagnostics;\nusing System.ComponentModel;\nusing System.Windows.Data;\n\n\nnamespace Dependencies\n{\n\n    public class ModuleCacheKey\n    {\n        public ModuleCacheKey(string _Name, string _Filepath, ModuleFlag _Flags = ModuleFlag.NoFlag)\n        {\n            Name = _Name;\n            Filepath = _Filepath;\n            Flags = _Flags;\n        }\n\n        public ModuleCacheKey(ImportContext import)\n        {\n            Name = import.ModuleName;\n            Filepath = import.PeFilePath;\n            Flags = import.Flags;\n        }\n\n        // mandatory since ModuleCacheKey is used as a dictionnary key\n        public override int GetHashCode()\n        {\n            int hashcode = Name.GetHashCode() ^ Flags.GetHashCode();\n\n            if (Filepath != null)\n            {\n                hashcode ^= Filepath.GetHashCode();\n            }\n\n            return hashcode;\n        }\n\n        public string Name;\n        public string Filepath;\n        public ModuleFlag Flags;\n    }\n\n\n\n    public class ModulesCache : Dictionary<ModuleCacheKey, DisplayModuleInfo>\n    {\n\n    }\n\n\n    /// <summary>\n    /// DependencyImportList  Filterable ListView for displaying modules.\n    /// </summary>\n    public partial class DependencyModuleList : DependencyCustomListView\n    {\n        //public ICollectionView ModulesItemsView { get; set; }\n\n        public RelayCommand DoFindModuleInTreeCommand\n        {\n            get { return (RelayCommand) GetValue(DoFindModuleInTreeCommandProperty); }\n            set { SetValue(DoFindModuleInTreeCommandProperty, value);}\n        }\n\n        public RelayCommand ConfigureSearchOrderCommand\n        {\n            get { return (RelayCommand)GetValue(ConfigureSearchOrderCommandProperty); }\n            set { SetValue(ConfigureSearchOrderCommandProperty, value); }\n        }\n\n        // Using a DependencyProperty as the backing store for DoFindModuleInTreeCommand.  This enables animation, styling, binding, etc...\n        public static readonly DependencyProperty DoFindModuleInTreeCommandProperty =\n            DependencyProperty.Register(\"DoFindModuleInTreeCommand\", typeof(RelayCommand), typeof(DependencyModuleList), new UIPropertyMetadata(null));\n\n        public static readonly DependencyProperty ConfigureSearchOrderCommandProperty =\n            DependencyProperty.Register(\"ConfigureSearchOrderCommand\", typeof(RelayCommand), typeof(DependencyModuleList), new UIPropertyMetadata(null));\n\n        public static readonly RoutedEvent SelectedModuleChangedEvent\n            = EventManager.RegisterRoutedEvent(\"SelectedModuleChanged\", RoutingStrategy.Direct, typeof(RoutedEventHandler), typeof(DependencyModuleList));\n\n\n        public DependencyModuleList()\n        {\n            InitializeComponent();\n\n        }\n\n        public void AddModule(DisplayModuleInfo NewModule)\n        {\n            // TODO : Find a way to properly bind commands instead of using this hack\n            NewModule.DoFindModuleInTreeCommand = DoFindModuleInTreeCommand;\n            NewModule.ConfigureSearchOrderCommand = ConfigureSearchOrderCommand;\n          \n\n            this.Items.Add(NewModule);\n        }\n\n        public event RoutedEventHandler SelectedModuleChanged\n        {\n            add { AddHandler(SelectedModuleChangedEvent, value); }\n            remove { RemoveHandler(SelectedModuleChangedEvent, value); }\n        }\n\n        private void OnSelectedModuleChanged(object sender, MouseButtonEventArgs e)\n        {\n            RaiseEvent(new RoutedEventArgs(SelectedModuleChangedEvent));\n        }\n\n        private string ModuleCopyHandler(object SelectedItem)\n        {\n            if (SelectedItem == null)\n            {\n                return \"\";\n            }\n\n            return (SelectedItem as DisplayModuleInfo).ModuleName;\n        }\n    }\n}\n"
  },
  {
    "path": "DependenciesGui/DependencyWindow.xaml",
    "content": "﻿<TabItem x:Class=\"Dependencies.DependencyWindow\"\n        xmlns=\"http://schemas.microsoft.com/winfx/2006/xaml/presentation\"\n        xmlns:x=\"http://schemas.microsoft.com/winfx/2006/xaml\"\n        xmlns:d=\"http://schemas.microsoft.com/expression/blend/2008\"\n        xmlns:mc=\"http://schemas.openxmlformats.org/markup-compatibility/2006\"\n        xmlns:local=\"clr-namespace:Dependencies\"\n        xmlns:properties=\"clr-namespace:Dependencies.Properties\"\n        mc:Ignorable=\"d\" d:DesignHeight=\"600\" d:DesignWidth=\"600\">\n\n    <TabItem.Resources>\n        <local:ImageToHeaderConverter x:Key=\"img\"/>\n        <local:OverlayImageToHeaderConverter x:Key=\"img_overlay\"/>\n        \n        <!-- Hide/Show the status bar based on a global switch -->\n        <local:BooleanToVisibilityConverter x:Key=\"BooleanToVisibility\"/>\n\n        <Style x:Key=\"LeftAlignHeaderText\" TargetType=\"{x:Type GridViewColumnHeader}\">\n            <Setter Property=\"HorizontalContentAlignment\" Value=\"Left\"></Setter>\n            <Setter Property=\"Padding\" Value=\"5,0,0,0\"></Setter>\n        </Style>\n\n    </TabItem.Resources>\n\n\n    <Grid x:Name=\"ResizeElemGrid\" Margin=\"0,0,0,0\">\n        <Grid.RowDefinitions>\n            <RowDefinition Height=\"146*\"/>\n            <RowDefinition Height=\"5\"/>\n            <RowDefinition Height=\"46*\"/>\n        </Grid.RowDefinitions>\n\n        <Grid x:Name=\"TreeImportExportGrid\" \n              Margin=\"0,0,0,0\"\n              Grid.Row=\"0\">\n\n            <Grid.ColumnDefinitions>\n                <ColumnDefinition Width=\"300*\"/>\n                <ColumnDefinition Width=\"5\"/>\n                <ColumnDefinition Width=\"600*\"/>\n            </Grid.ColumnDefinitions>\n\n            <TreeView x:Name=\"DllTreeView\"  \n                    HorizontalContentAlignment=\"Stretch\" \n                    VerticalContentAlignment=\"Stretch\" \n                    Padding=\"0\" \n                    SelectedItemChanged=\"OnTreeViewSelectedItemChanged\"\n                    >\n\n                <TreeView.Resources>\n                    <RoutedUICommand x:Key=\"DoExpandAllNodes\" Text=\"Expand All\" />\n                    <RoutedUICommand x:Key=\"DoCollapseAllNodes\" Text=\"Collapse All\" />\n                    <RoutedUICommand x:Key=\"DoFindModuleInList\" Text=\"Highlight Matching Module In List\" />\n\n                    <ContextMenu x:Key=\"TreeItemContextMenu\">\n                        <MenuItem Header=\"Highlight Matching Module In List\" \n                                Command=\"{StaticResource DoFindModuleInList}\"\n                                CommandParameter=\"{Binding RelativeSource={RelativeSource  AncestorLevel=1,AncestorType=TreeViewItem,Mode=FindAncestor}}\"\n                                InputGestureText=\"Ctrl+M\" \n                                IsEnabled=\"True\" />\n                        <Separator Height=\"3\" Margin=\"-1,0,0,0\"/>\n                        <MenuItem Header=\"Copy File Path\" \n                                Command=\"{Binding Path=DataContext.MoreInfo, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=ListView}}\" \n                                Background=\"WhiteSmoke\" \n                                InputGestureText=\"Ctrl+C\" \n                                IsEnabled=\"False\"  />\n                        <Separator Height=\"3\" Margin=\"-1,0,0,0\"/>\n                        <MenuItem Header=\"Expand All\" \n                                Command=\"{StaticResource DoExpandAllNodes}\"\n                                IsEnabled=\"True\"  />\n                        <MenuItem Header=\"Collapse All\" \n                                Command=\"{StaticResource DoCollapseAllNodes}\"\n                                IsEnabled=\"True\"  />\n                        <Separator Height=\"3\" Margin=\"-1,0,0,0\"/>\n                        <MenuItem Name=\"FullPathItemTree\" Header=\"Full Paths\" Height=\"25\" InputGestureText=\"F9\" IsCheckable=\"True\" IsChecked=\"{Binding Source={x:Static properties:Settings.Default}, Path=FullPath, Mode=TwoWay}\" Margin=\"0,0,0.2,0\"/>\n                        <Separator Height=\"3\" Margin=\"-1,0,0,0\"/>\n\n                        <MenuItem Header=\"View Module in separate application\" \n                                Command=\"{Binding  Path=OpenNewAppCommand, RelativeSource={RelativeSource AncestorLevel=1,AncestorType=TreeViewItem,Mode=FindAncestor}}\"\n                                CommandParameter =\"{Binding DataContext, RelativeSource={RelativeSource AncestorLevel=1,AncestorType=Grid,Mode=FindAncestor}}\"\n                                InputGestureText=\"Alt+Enter\"  \n                                IsEnabled=\"True\" />\n\n                        <MenuItem Header=\"View Module in Peviewer\" \n                                Command=\"{Binding  Path=OpenPeviewerCommand, RelativeSource={RelativeSource AncestorLevel=1,AncestorType=TreeViewItem,Mode=FindAncestor}}\"\n                                CommandParameter =\"{Binding DataContext, RelativeSource={RelativeSource AncestorLevel=1,AncestorType=Grid,Mode=FindAncestor}}\"\n                                InputGestureText=\"Alt+Enter\"  \n                                IsEnabled=\"True\" />\n\n                        <!--AncestorType=Grid To get the current context feel like magic to me -->\n                    </ContextMenu>\n\n                    <Style TargetType=\"local:ModuleTreeViewItem\">\n                        <Setter Property=\"HeaderTemplate\">\n                            <Setter.Value>\n                                <DataTemplate>\n                                    <Grid Margin=\"0,0,5,0\">\n                                        <Grid.ColumnDefinitions>\n                                            <ColumnDefinition Width=\"24\"/>\n                                            <ColumnDefinition Width=\"3\" />\n                                            <ColumnDefinition Width=\"*\" />\n                                        </Grid.ColumnDefinitions>\n\n                                        \n                                        <!--System icon for the current module-->\n                                        <Image Grid.Column=\"0\" Width=\"16\" Height=\"16\" Margin=\"0,0,0,0\" \n                                               Source=\"{Binding Path=(local:ModuleTreeViewItem.ModuleFilePath), RelativeSource={RelativeSource AncestorLevel=1,AncestorType=TreeViewItem,Mode=FindAncestor}, Converter={StaticResource img} }\"\n                                               ToolTip=\"{Binding Path=(local:ModuleTreeViewItem.Tooltip), RelativeSource={RelativeSource AncestorLevel=1,AncestorType=TreeViewItem,Mode=FindAncestor}}\"\n                                        ></Image>\n                                        \n                                        <!--Overlay for additional flags (delay import, apiset, etc.)-->\n                                        <Image Grid.Column=\"0\" Width=\"16\" Height=\"16\" Margin=\"4,0,0,0\" Source=\"{Binding Path=(local:ModuleTreeViewItem.Flags), RelativeSource={RelativeSource AncestorLevel=1,AncestorType=TreeViewItem,Mode=FindAncestor}, Converter={StaticResource img_overlay} }\"></Image>\n\n                                        <!--Another red rectangle overlay on modules issues-->\n                                        <Rectangle x:Name=\"ErrorModule\"  Grid.Column=\"0\" Width=\"14\" Height=\"14\" \n                                                   Visibility=\"{Binding Path=(local:ModuleTreeViewItem.HasErrors), RelativeSource={RelativeSource AncestorLevel=1,AncestorType=TreeViewItem,Mode=FindAncestor}, Converter={StaticResource BooleanToVisibility}}\"\n                                                   >\n                                            <Rectangle.Fill>\n                                                <SolidColorBrush Color=\"Red\" />\n                                            </Rectangle.Fill>\n                                            <Rectangle.OpacityMask>\n                                                <DrawingBrush AlignmentX=\"Left\" AlignmentY=\"Top\">\n                                                    <DrawingBrush.Drawing>\n                                                        <DrawingGroup>\n                                                            <GeometryDrawing Brush=\"#33000000\">\n                                                                <GeometryDrawing.Geometry>\n                                                                    <RectangleGeometry Rect=\"0,0,40,40\" />\n                                                                </GeometryDrawing.Geometry>\n                                                            </GeometryDrawing>\n                                                        </DrawingGroup>\n                                                    </DrawingBrush.Drawing>\n                                                </DrawingBrush>\n                                            </Rectangle.OpacityMask>\n                                        </Rectangle>\n\n                                        <!--Another red rectangle overlay on modules issues-->\n                                        <Rectangle x:Name=\"ChildErrorModule\"  Grid.Column=\"0\" Width=\"14\" Height=\"14\" \n                                                   Visibility=\"{Binding Path=(local:ModuleTreeViewItem.HasChildErrors), RelativeSource={RelativeSource AncestorLevel=1,AncestorType=TreeViewItem,Mode=FindAncestor}, Converter={StaticResource BooleanToVisibility}}\"\n                                                   >\n                                            <Rectangle.Fill>\n                                                <SolidColorBrush Color=\"DarkOrange\" />\n                                            </Rectangle.Fill>\n                                            <Rectangle.OpacityMask>\n                                                <DrawingBrush AlignmentX=\"Left\" AlignmentY=\"Top\">\n                                                    <DrawingBrush.Drawing>\n                                                        <DrawingGroup>\n                                                            <GeometryDrawing Brush=\"#88888888\">\n                                                                <GeometryDrawing.Geometry>\n                                                                    <RectangleGeometry Rect=\"0,0,40,40\" />\n                                                                </GeometryDrawing.Geometry>\n                                                            </GeometryDrawing>\n                                                        </DrawingGroup>\n                                                    </DrawingBrush.Drawing>\n                                                </DrawingBrush>\n                                            </Rectangle.OpacityMask>\n                                        </Rectangle>\n\n                                        <TextBlock Grid.Column=\"2\" Text=\"{Binding}\"></TextBlock>\n                                    </Grid>\n                                </DataTemplate>\n                            </Setter.Value>\n                        </Setter>\n                        \n                        <Setter Property=\"FontFamily\" Value=\"{Binding Source={x:Static properties:Settings.Default}, Path=Font, Mode=OneWay}\" />\n                        <Setter Property=\"ContextMenu\" Value=\"{StaticResource TreeItemContextMenu}\" />\n                        \n                    </Style>\n\n                </TreeView.Resources>\n\n                <TreeView.CommandBindings>\n                    <CommandBinding Command=\"{StaticResource DoExpandAllNodes}\" Executed=\"ExpandAllNodes_Executed\"/>\n                    <CommandBinding Command=\"{StaticResource DoCollapseAllNodes}\" Executed=\"CollapseAllNodes_Executed\"/>\n                    <CommandBinding Command=\"{StaticResource DoFindModuleInList}\" Executed=\"DoFindModuleInList_Executed\"/>\n                </TreeView.CommandBindings>\n            </TreeView>\n            \n            <GridSplitter Grid.Column=\"1\" \n                          HorizontalContentAlignment=\"Stretch\"\n                          VerticalContentAlignment=\"Stretch\"\n                          HorizontalAlignment=\"Stretch\"/>\n            \n            <Grid x:Name=\"ImportExportGrid\" Grid.Column=\"2\">\n\n                <Grid.RowDefinitions>\n                    <RowDefinition Height=\"145*\"/>\n                    <RowDefinition Height=\"5\"/>\n                    <RowDefinition Height=\"142*\"/>\n                </Grid.RowDefinitions>\n\n                <local:DependencyImportList x:Name=\"ImportList\" \n                                            Grid.Row=\"0\" />\n\n\n                <GridSplitter x:Name=\"ImportExportSplitter\" \n                              HorizontalAlignment=\"Stretch\" \n                              HorizontalContentAlignment=\"Stretch\" \n                              VerticalContentAlignment=\"Center\" \n                              MinHeight=\"8\" \n                              Grid.Row=\"1\"/>\n\n                <local:DependencyExportList x:Name=\"ExportList\" \n                                            Grid.Row=\"2\" />\n\n            </Grid>\n\n        </Grid>\n        \n\n        <GridSplitter x:Name=\"LogSplitter\" \n                      HorizontalAlignment=\"Stretch\" \n                      HorizontalContentAlignment=\"Stretch\" \n                      VerticalContentAlignment=\"Stretch\" \n                      Grid.Row=\"1\"/>\n\n\n\n        <local:DependencyModuleList x:Name=\"ModulesList\"\n                                    Grid.Row=\"2\"\n                                    SelectedModuleChanged=\"OnModuleViewSelectedItemChanged\"\n                                    />\n                                    \n\n\n    </Grid>\n</TabItem>\n"
  },
  {
    "path": "DependenciesGui/DependencyWindow.xaml.cs",
    "content": "using System;\nusing System.IO;\nusing System.Collections.Generic;\nusing System.Windows;\nusing System.Windows.Controls;\nusing System.ComponentModel;\nusing System.Windows.Input;\nusing System.Diagnostics;\nusing System.Windows.Data;\nusing Microsoft.Win32;\n\nusing Mono.Cecil;\nusing Dependencies.ClrPh;\n\nnamespace Dependencies\n{\n\n    /// <summary>\n    /// ImportContext : Describe an import module parsed from a PE.\n    /// Only used during the dependency tree building phase\n    /// </summary>\n    public struct ImportContext\n{\n        // Import \"identifier\" \n        public string ModuleName;\n\n        // Return how the module was found (NOT_FOUND otherwise)\n        public ModuleSearchStrategy ModuleLocation;\n\n        // If found, set the filepath and parsed PE, otherwise it's null\n        public string PeFilePath;\n        public PE PeProperties;\n\n        // Some imports are from api sets\n        public bool IsApiSet;\n        public string ApiSetModuleName;\n\n        // module flag attributes\n        public ModuleFlag Flags;\n    }\n\n\n    /// <summary>\n    /// Dependency tree building behaviour.\n    /// A full recursive dependency tree can be memory intensive, therefore the\n    /// choice is left to the user to override the default behaviour.\n    /// </summary>\n    public class TreeBuildingBehaviour : IValueConverter\n    { \n        public enum DependencyTreeBehaviour\n        {\n            ChildOnly,\n            RecursiveOnlyOnDirectImports,\n            Recursive,\n\n        }\n\n        public static DependencyTreeBehaviour GetGlobalBehaviour()\n        {\n            return (DependencyTreeBehaviour) (new TreeBuildingBehaviour()).Convert(\n                Dependencies.Properties.Settings.Default.TreeBuildBehaviour,\n                null,// targetType\n                null,// parameter\n                null // System.Globalization.CultureInfo\n            );\n        }\n\n        #region TreeBuildingBehaviour.IValueConverter_contract\n        public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)\n        {\n            string StrBehaviour = (string)value;\n\n            switch (StrBehaviour)\n            {\n                default:\n                case \"ChildOnly\":\n                    return DependencyTreeBehaviour.ChildOnly;\n                case \"RecursiveOnlyOnDirectImports\":\n                    return DependencyTreeBehaviour.RecursiveOnlyOnDirectImports;\n                case \"Recursive\":\n                    return DependencyTreeBehaviour.Recursive;\n            }\n        }\n\n        public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)\n        {\n            DependencyTreeBehaviour Behaviour = (DependencyTreeBehaviour) value;\n\n            switch (Behaviour)\n            {\n                default:\n                case DependencyTreeBehaviour.ChildOnly:\n                    return \"ChildOnly\";\n                case DependencyTreeBehaviour.RecursiveOnlyOnDirectImports:\n                    return \"RecursiveOnlyOnDirectImports\";\n                case DependencyTreeBehaviour.Recursive:\n                    return \"Recursive\";\n            }\n        }\n        #endregion TreeBuildingBehaviour.IValueConverter_contract\n    }\n\n    /// <summary>\n    /// Dependency tree building behaviour.\n    /// A full recursive dependency tree can be memory intensive, therefore the\n    /// choice is left to the user to override the default behaviour.\n    /// </summary>\n    public class BinaryCacheOption : IValueConverter\n    {\n        [TypeConverter(typeof(EnumToStringUsingDescription))]\n        public enum BinaryCacheOptionValue\n        {\n            [Description(\"No (faster, but locks dll until Dependencies is closed)\")]\n            No = 0,\n\n            [Description(\"Yes (prevents file locking issues)\")]\n            Yes = 1\n        }\n\n        public static BinaryCacheOptionValue GetGlobalBehaviour()\n        {\n            return (BinaryCacheOptionValue)(new BinaryCacheOption()).Convert(\n                Dependencies.Properties.Settings.Default.BinaryCacheOptionValue,\n                null,// targetType\n                null,// parameter\n                null // System.Globalization.CultureInfo\n            );\n        }\n\n        #region BinaryCacheOption.IValueConverter_contract\n        public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)\n        {\n            bool StrOption = (bool)value;\n\n            switch (StrOption)\n            {\n                default:\n                case true:\n                    return BinaryCacheOptionValue.Yes;\n                case false:\n                    return BinaryCacheOptionValue.No;\n            }\n\n        }\n\n        public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)\n        {\n            BinaryCacheOptionValue Behaviour = (BinaryCacheOptionValue)(int)value;\n\n            switch (Behaviour)\n            {\n                default:\n                case BinaryCacheOptionValue.Yes:\n                    return true;\n                case BinaryCacheOptionValue.No:\n                    return false;\n            }\n        }\n        #endregion BinaryCacheOption.IValueConverter_contract\n    }\n\n    public class EnumToStringUsingDescription : TypeConverter\n    {\n        public override bool CanConvertFrom(ITypeDescriptorContext context, Type sourceType)\n        {\n            return (sourceType.Equals(typeof(Enum)));\n        }\n\n        public override bool CanConvertTo(ITypeDescriptorContext context, Type destinationType)\n        {\n            return (destinationType.Equals(typeof(String)));\n        }\n\n        public override object ConvertFrom(ITypeDescriptorContext context, System.Globalization.CultureInfo culture, object value)\n        {\n            return base.ConvertFrom(context, culture, value);\n        }\n\n        public override object ConvertTo(ITypeDescriptorContext context, System.Globalization.CultureInfo culture, object value, Type destinationType)\n        {\n            if (!destinationType.Equals(typeof(String)))\n            {\n                throw new ArgumentException(\"Can only convert to string.\", \"destinationType\");\n            }\n\n            if (!value.GetType().BaseType.Equals(typeof(Enum)))\n            {\n                throw new ArgumentException(\"Can only convert an instance of enum.\", \"value\");\n            }\n\n            string name = value.ToString();\n            object[] attrs =\n                value.GetType().GetField(name).GetCustomAttributes(typeof(DescriptionAttribute), false);\n            return (attrs.Length > 0) ? ((DescriptionAttribute)attrs[0]).Description : name;\n        }\n    }\n\n    /// <summary>\n    /// User context of every dependency tree node.\n    /// </summary>\n    public struct DependencyNodeContext\n    {\n        public DependencyNodeContext(DependencyNodeContext other)\n        {\n            ModuleInfo = other.ModuleInfo;\n            IsDummy = other.IsDummy;\n        }\n\n        /// <summary>\n        /// We use a WeakReference to point towars a DisplayInfoModule\n        /// in order to reduce memory allocations.\n        /// </summary>\n        public WeakReference ModuleInfo;\n\n        /// <summary>\n        /// Depending on the dependency tree behaviour, we may have to\n        /// set up \"dummy\" nodes in order for the parent to display the \">\" button.\n        /// Those dummy are usually destroyed when their parents is expandend and imports resolved.\n        /// </summary>\n        public bool IsDummy;\n    }\n\n    /// <summary>\n    /// Deprendency Tree custom node. It's DataContext is a DependencyNodeContext struct\n    /// </summary>\n    public class ModuleTreeViewItem : TreeViewItem, INotifyPropertyChanged\n    {\n        public event PropertyChangedEventHandler PropertyChanged;\n\n\t\tpublic ModuleTreeViewItem()\n\t\t{\n\t\t\t_importsVerified = false;\n\t\t\t_Parent = null;\n\t\t\tDependencies.Properties.Settings.Default.PropertyChanged += this.ModuleTreeViewItem_PropertyChanged;\n\t\t}\n\n\t\tpublic ModuleTreeViewItem(ModuleTreeViewItem Parent)\n        {\n\t\t\t_importsVerified = false;\n\t\t\t_Parent = Parent;\n\t\t\tDependencies.Properties.Settings.Default.PropertyChanged += this.ModuleTreeViewItem_PropertyChanged;\n        }\n\n        public ModuleTreeViewItem(ModuleTreeViewItem Other, ModuleTreeViewItem Parent)\n        {\n\t\t\t_importsVerified = false;\n\t\t\t_Parent = Parent;\n\t\t\tthis.DataContext = new DependencyNodeContext( (DependencyNodeContext) Other.DataContext );\n\t\t\tDependencies.Properties.Settings.Default.PropertyChanged += this.ModuleTreeViewItem_PropertyChanged;\n\t\t}\n\n        #region PropertyEventHandlers \n        public virtual void OnPropertyChanged(string propertyName)\n        {\n            PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));\n        }\n\n        private void ModuleTreeViewItem_PropertyChanged(object sender, PropertyChangedEventArgs e)\n        {\n            if (e.PropertyName == \"FullPath\")\n            {\n                this.Header = (object)GetTreeNodeHeaderName(Dependencies.Properties.Settings.Default.FullPath);\n            }\n        }\n        #endregion PropertyEventHandlers\n\n        #region Getters\n\n        public string GetTreeNodeHeaderName(bool FullPath)\n        {\n            return (((DependencyNodeContext)this.DataContext).ModuleInfo.Target as DisplayModuleInfo).ModuleName;\n        }\n\n        public string ModuleFilePath\n        {\n            get\n            {\n                return (((DependencyNodeContext)this.DataContext).ModuleInfo.Target as DisplayModuleInfo).Filepath;\n            }\n        }\n\n        public ModuleTreeViewItem ParentModule\n\t\t{\n\t\t\tget\n\t\t\t{\n\t\t\t\treturn _Parent;\n\t\t\t}\n\t\t}\n\n\n\t\tpublic ModuleFlag Flags\n        {\n            get\n            {\n                return ModuleInfo.Flags;\n            }\n        }\n\n        private bool _has_error;\n\n\t\tpublic bool HasErrors\n\t\t{\n            get\n            {\n                if (!_importsVerified)\n                {\n                    _has_error = VerifyModuleImports();\n                    _importsVerified = true;\n\n                    // Update tooltip only once some basic checks are done\n                    this.ToolTip = ModuleInfo.Status;\n                }\n\n                // propagate error for parent\n                if (_has_error)\n                {\n                    ModuleTreeViewItem ParentModule = this.ParentModule;\n                    if (ParentModule != null)\n                    {\n                        ParentModule.HasChildErrors = true;\n                    }\n                }\n\n                return _has_error;\n            }\n\n            set\n            {\n                if (value == _has_error) return;\n                _has_error = value;\n                OnPropertyChanged(\"HasErrors\");\n            }\n\t\t}\n\n\n        public string Tooltip\n        {\n            get\n            {\n                return ModuleInfo.Status;\n            }\n        }\n\n        public bool HasChildErrors\n        {\n            get\n            {\n                return _has_child_errors;\n            }\n            set\n            {\n                if (value)\n                {\n                    ModuleInfo.Flags |= ModuleFlag.ChildrenError;\n                }\n                else\n                {\n                    ModuleInfo.Flags &= ~ModuleFlag.ChildrenError;\n                }\n\n                ToolTip = ModuleInfo.Status;\n                _has_child_errors = true;\n                OnPropertyChanged(\"HasChildErrors\");\n\n                // propagate error for parent\n                ModuleTreeViewItem ParentModule = this.ParentModule;\n                if (ParentModule != null)\n                {\n                    ParentModule.HasChildErrors = true;\n                }\n            }\n        }\n\n        public DisplayModuleInfo ModuleInfo\n\t\t{\n\t\t\tget\n\t\t\t{\n\t\t\t\treturn (((DependencyNodeContext)this.DataContext).ModuleInfo.Target as DisplayModuleInfo);\n\t\t\t}\n\t\t}\n\n\n\t\tprivate bool VerifyModuleImports()\n\t\t{\n\n            // current module has issues\n            if ((Flags & (ModuleFlag.NotFound | ModuleFlag.MissingImports | ModuleFlag.ChildrenError)) != 0)\n            {\n                return true;\n            }\n\n            // no parent : it's probably the root item\n            ModuleTreeViewItem ParentModule = this.ParentModule;\n            if (ParentModule == null)\n\t\t\t{\n\t\t\t\treturn false;\n\t\t\t}\n\n            // Check we have any imports issues\n            foreach (PeImportDll DllImport in ParentModule.ModuleInfo.Imports)\n\t\t\t{\n\t\t\t\tif (DllImport.Name != ModuleInfo._Name)\n\t\t\t\t\tcontinue;\n\n\n\n\t\t\t\tList<Tuple<PeImport, bool>> resolvedImports = BinaryCache.LookupImports(DllImport, ModuleInfo.Filepath);\n\t\t\t\tif (resolvedImports.Count == 0)\n\t\t\t\t{\n                    return true;\n                }\n\n\t\t\t\tforeach (var Import in resolvedImports)\n\t\t\t\t{\n\t\t\t\t\tif (!Import.Item2)\n\t\t\t\t\t{\n                        return true;\n                    }\n\t\t\t\t}\n\t\t\t}\n\n\n\n            return false;\n        }\n\n        \n\n\t\t#endregion Getters\n\n\n\t\t#region Commands \n\t\tpublic RelayCommand OpenPeviewerCommand\n        {\n            get\n            {\n                if (_OpenPeviewerCommand == null)\n                {\n                    _OpenPeviewerCommand = new RelayCommand((param) => this.OpenPeviewer((object)param));\n                }\n\n                return _OpenPeviewerCommand;\n            }\n        }\n\n        public bool OpenPeviewer(object Context)\n        {\n            string programPath = Dependencies.Properties.Settings.Default.PeViewerPath;\n            Process PeviewerProcess = new Process();\n\n            if (Context == null)\n            {\n                return false;\n            }\n\n            if (!File.Exists(programPath))\n            {\n                System.Windows.MessageBox.Show(String.Format(\"{0:s} file could not be found !\", programPath));\n                return false;\n            }\n\n            string Filepath = ModuleFilePath;\n            if (Filepath == null)\n            {\n                return false;\n            }\n\n            PeviewerProcess.StartInfo.FileName = String.Format(\"\\\"{0:s}\\\"\", programPath);\n            PeviewerProcess.StartInfo.Arguments = String.Format(\"\\\"{0:s}\\\"\", Filepath); \n            return PeviewerProcess.Start();\n        }\n\n        public RelayCommand OpenNewAppCommand\n        {\n            get\n            {\n                if (_OpenNewAppCommand == null)\n                {\n                    _OpenNewAppCommand = new RelayCommand((param) =>\n                    {\n                        string Filepath = ModuleFilePath;\n                        if (Filepath == null)\n                        {\n                            return;\n                        }\n\n                        Process OtherDependenciesProcess = new Process();\n                        OtherDependenciesProcess.StartInfo.FileName = System.Windows.Forms.Application.ExecutablePath;\n                        OtherDependenciesProcess.StartInfo.Arguments = String.Format(\"\\\"{0:s}\\\"\", Filepath);\n                        OtherDependenciesProcess.Start();\n                    });\n                }\n\n                return _OpenNewAppCommand;\n            }\n        }\n\n        #endregion // Commands \n\n        private RelayCommand _OpenPeviewerCommand;\n        private RelayCommand _OpenNewAppCommand;\n\t\tprivate ModuleTreeViewItem _Parent;\n\t\tprivate bool _importsVerified;\n        private bool _has_child_errors;\n\n\n    }\n\n\n    /// <summary>\n    /// Dependemcy tree analysis window for a given PE.\n    /// </summary>\n    public partial class DependencyWindow :  TabItem \n    { \n\n        PE Pe;\n\t\tpublic string RootFolder;\n\t\tpublic string WorkingDirectory;\n\t\tstring Filename;\n        PhSymbolProvider SymPrv;\n        SxsEntries SxsEntriesCache;\n        ApiSetSchema ApiSetmapCache;\n        ModulesCache ProcessedModulesCache;\n        DisplayModuleInfo _SelectedModule;\n        bool _DisplayWarning;\n\n\t\tpublic List<string> CustomSearchFolders;\n\n        #region PublicAPI\n        public DependencyWindow(String Filename, List<string> CustomSearchFolders = null)\n        {\n            InitializeComponent();\n\n\t\t\tif (CustomSearchFolders != null)\n\t\t\t{\n\t\t\t\tthis.CustomSearchFolders = CustomSearchFolders;\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\tthis.CustomSearchFolders = new List<string>();\n\t\t\t}\n\t\t\t\n\t\t\tthis.Filename = Filename;\n\t\t\tthis.WorkingDirectory = Path.GetDirectoryName(this.Filename);\n\t\t\tInitializeView();\n        }\n\n        public void InitializeView()\n        {\n            if (!NativeFile.Exists(this.Filename))\n            {\n                MessageBox.Show(\n                    String.Format(\"{0:s} is not present on the disk\", this.Filename),\n                    \"Invalid PE\",\n                    MessageBoxButton.OK\n                );\n\n                return;\n            }\n\n            this.Pe = (Application.Current as App).LoadBinary(this.Filename);\n\t\t\tif (this.Pe == null || !this.Pe.LoadSuccessful)\n\t\t\t{\n                MessageBox.Show(\n                    String.Format(\"{0:s} is not a valid PE-COFF file\", this.Filename),\n                    \"Invalid PE\",\n                    MessageBoxButton.OK\n                );\n\n                return;\n            }\n\n            this.SymPrv = new PhSymbolProvider();\n            this.RootFolder = Path.GetDirectoryName(this.Filename);\n            this.SxsEntriesCache = SxsManifest.GetSxsEntries(this.Pe);\n            this.ProcessedModulesCache = new ModulesCache();\n            this.ApiSetmapCache = Phlib.GetApiSetSchema();\n            this._SelectedModule = null;\n            this._DisplayWarning = false;\n\n            // TODO : Find a way to properly bind commands instead of using this hack\n            this.ModulesList.Items.Clear();\n            this.ModulesList.DoFindModuleInTreeCommand = DoFindModuleInTree;\n            this.ModulesList.ConfigureSearchOrderCommand = ConfigureSearchOrderCommand;\n\n            var RootFilename = Path.GetFileName(this.Filename);\n            var RootModule = new DisplayModuleInfo(RootFilename, this.Pe, ModuleSearchStrategy.ROOT);\n            this.ProcessedModulesCache.Add(new ModuleCacheKey(RootFilename, this.Filename), RootModule);\n\n            ModuleTreeViewItem treeNode = new ModuleTreeViewItem();\n            DependencyNodeContext childTreeInfoContext = new DependencyNodeContext()\n            {\n                ModuleInfo = new WeakReference(RootModule),\n                IsDummy = false\n            };\n\n            treeNode.DataContext = childTreeInfoContext;\n            treeNode.Header = treeNode.GetTreeNodeHeaderName(Dependencies.Properties.Settings.Default.FullPath);\n            treeNode.IsExpanded = true;\n\n            this.DllTreeView.Items.Clear();\n            this.DllTreeView.Items.Add(treeNode);\n\n            // Recursively construct tree of dll imports\n            ConstructDependencyTree(treeNode, this.Pe);\n        }\n        #endregion PublicAPI\n\n\t\t\n\n        #region TreeConstruction\n\n        private ImportContext ResolveImport(PeImportDll DllImport)\n        {\n            ImportContext ImportModule = new ImportContext();\n\n            ImportModule.PeFilePath = null;\n            ImportModule.PeProperties = null;\n            ImportModule.ModuleName = DllImport.Name;\n            ImportModule.ApiSetModuleName = null;\n            ImportModule.Flags = 0;\n            if (DllImport.IsDelayLoad())\n            {\n                ImportModule.Flags |= ModuleFlag.DelayLoad;\n            }\n\n            Tuple<ModuleSearchStrategy, PE> ResolvedModule = BinaryCache.ResolveModule(\n                    this.Pe,\n                    DllImport.Name,\n                    this.SxsEntriesCache,\n                    this.CustomSearchFolders,\n                    this.WorkingDirectory\n                );\n\n            ImportModule.ModuleLocation = ResolvedModule.Item1;\n            if (ImportModule.ModuleLocation != ModuleSearchStrategy.NOT_FOUND)\n            {\n                ImportModule.PeProperties = ResolvedModule.Item2;\n\n                if (ResolvedModule.Item2 != null)\n                {\n                    ImportModule.PeFilePath = ResolvedModule.Item2.Filepath;\n                    foreach (var Import in BinaryCache.LookupImports(DllImport, ImportModule.PeFilePath))\n                    {\n                        if (!Import.Item2)\n                        {\n                            ImportModule.Flags |= ModuleFlag.MissingImports;\n                            break;\n                        }\n\n                    }\n                }\n            }\n            else\n            {\n                ImportModule.Flags |= ModuleFlag.NotFound;\n            }\n\n            // special case for apiset schema\n            ImportModule.IsApiSet = (ImportModule.ModuleLocation == ModuleSearchStrategy.ApiSetSchema);\n            if (ImportModule.IsApiSet)\n            {\n                ImportModule.Flags |= ModuleFlag.ApiSet;\n                ImportModule.ApiSetModuleName = BinaryCache.LookupApiSetLibrary(DllImport.Name);\n\n                if (DllImport.Name.StartsWith(\"ext-\"))\n                {\n                    ImportModule.Flags |= ModuleFlag.ApiSetExt;\n                }\n            }\n\n            return ImportModule;\n        }\n\n        private void TriggerWarningOnAppvIsvImports(string DllImportName)\n        {\n            if (String.Compare(DllImportName, \"AppvIsvSubsystems32.dll\", StringComparison.OrdinalIgnoreCase) == 0 ||\n                    String.Compare(DllImportName, \"AppvIsvSubsystems64.dll\", StringComparison.OrdinalIgnoreCase) == 0)\n                {\n                    if (!this._DisplayWarning)\n                    {\n                        MessageBoxResult result = MessageBox.Show(\n                        \"This binary use the App-V containerization technology which fiddle with search directories and PATH env in ways Dependencies can't handle.\\n\\nFollowing results are probably not quite exact.\",\n                        \"App-V ISV disclaimer\"\n                        );\n\n                        this._DisplayWarning = true; // prevent the same warning window to popup several times\n                    }\n\n            }\n        }\n\n        private void ProcessAppInitDlls(Dictionary<string, ImportContext> NewTreeContexts, PE AnalyzedPe, ImportContext ImportModule)\n        {\n            List<PeImportDll> PeImports = AnalyzedPe.GetImports();\n\n            // only user32 triggers appinit dlls\n            string User32Filepath = Path.Combine(FindPe.GetSystemPath(this.Pe), \"user32.dll\");\n            if (ImportModule.PeFilePath != User32Filepath)\n            {\n                return;\n            }\n\n            string AppInitRegistryKey =\n                (this.Pe.IsArm32Dll()) ?\n                \"SOFTWARE\\\\WowAA32Node\\\\Microsoft\\\\Windows NT\\\\CurrentVersion\\\\Windows\" :\n                (this.Pe.IsWow64Dll()) ?\n                \"SOFTWARE\\\\Wow6432Node\\\\Microsoft\\\\Windows NT\\\\CurrentVersion\\\\Windows\" :\n                \"SOFTWARE\\\\Microsoft\\\\Windows NT\\\\CurrentVersion\\\\Windows\";\n\n            // Opening registry values\n            RegistryKey localKey = RegistryKey.OpenBaseKey(Microsoft.Win32.RegistryHive.LocalMachine, RegistryView.Registry64);\n            localKey = localKey.OpenSubKey(AppInitRegistryKey);\n            int LoadAppInitDlls = (int)localKey.GetValue(\"LoadAppInit_DLLs\", 0);\n            string AppInitDlls = (string)localKey.GetValue(\"AppInit_DLLs\", \"\");\n            if (LoadAppInitDlls == 0 || String.IsNullOrEmpty(AppInitDlls))\n            {\n                return;\n            }\n                \n            // Extremely crude parser. TODO : Add support for quotes wrapped paths with spaces\n            foreach (var AppInitDll in AppInitDlls.Split(' '))\n            {\n                Debug.WriteLine(\"AppInit loading \" + AppInitDll);\n\n                // Do not process twice the same imported module\n                if (null != PeImports.Find(module => module.Name == AppInitDll))\n                {\n                    continue;\n                }\n\n                if (NewTreeContexts.ContainsKey(AppInitDll))\n                {\n                    continue;\n                }\n\n                ImportContext AppInitImportModule = new ImportContext();\n                AppInitImportModule.PeFilePath = null;\n                AppInitImportModule.PeProperties = null;\n                AppInitImportModule.ModuleName = AppInitDll;\n                AppInitImportModule.ApiSetModuleName = null;\n                AppInitImportModule.Flags = 0;\n                AppInitImportModule.ModuleLocation = ModuleSearchStrategy.AppInitDLL;\n\n\n\n                Tuple<ModuleSearchStrategy, PE> ResolvedAppInitModule = BinaryCache.ResolveModule(\n                    this.Pe,\n                    AppInitDll,\n                    this.SxsEntriesCache,\n                    this.CustomSearchFolders,\n                    this.WorkingDirectory\n                );\n                if (ResolvedAppInitModule.Item1 != ModuleSearchStrategy.NOT_FOUND)\n                {\n                    AppInitImportModule.PeProperties = ResolvedAppInitModule.Item2;\n                    AppInitImportModule.PeFilePath = ResolvedAppInitModule.Item2.Filepath;\n                }\n                else\n                {\n                    AppInitImportModule.Flags |= ModuleFlag.NotFound;\n                }\n\n                NewTreeContexts.Add(AppInitDll, AppInitImportModule);\n            }\n        }\n\n        private void ProcessClrImports(Dictionary<string, ImportContext> NewTreeContexts, PE AnalyzedPe, ImportContext ImportModule)\n        {\n            List<PeImportDll> PeImports = AnalyzedPe.GetImports();\n\n            // only mscorre triggers clr parsing\n            string User32Filepath = Path.Combine(FindPe.GetSystemPath(this.Pe), \"mscoree.dll\");\n            if (ImportModule.PeFilePath != User32Filepath)\n            {\n                return;\n            }\n\n            var resolver = new DefaultAssemblyResolver();\n            resolver.AddSearchDirectory(RootFolder);\n\n            // Parse it via cecil\n            AssemblyDefinition PeAssembly = null;\n            try\n            {\n                PeAssembly = AssemblyDefinition.ReadAssembly(AnalyzedPe.Filepath);\n            }\n            catch (BadImageFormatException)\n            {\n                MessageBoxResult result = MessageBox.Show(\n                        String.Format(\"Cecil could not correctly parse {0:s}, which can happens on .NET Core executables. CLR imports will be not shown\", AnalyzedPe.Filepath),\n                        \"CLR parsing fail\"\n                ); \n\n                return;\n            }\n\n            foreach (var module in PeAssembly.Modules)\n            {\n                // Process CLR referenced assemblies\n                foreach (var assembly in module.AssemblyReferences)\n                {\n                    AssemblyDefinition definition;\n                    try\n                    {\n                        definition = resolver.Resolve(assembly);\n                    }\n                    catch (AssemblyResolutionException)\n                    {\n                        ImportContext AppInitImportModule = new ImportContext();\n                        AppInitImportModule.PeFilePath = null;\n                        AppInitImportModule.PeProperties = null;\n                        AppInitImportModule.ModuleName = Path.GetFileName(assembly.Name);\n                        AppInitImportModule.ApiSetModuleName = null;\n                        AppInitImportModule.Flags = ModuleFlag.ClrReference;\n                        AppInitImportModule.ModuleLocation = ModuleSearchStrategy.ClrAssembly;\n                        AppInitImportModule.Flags |= ModuleFlag.NotFound;\n\n                        if (!NewTreeContexts.ContainsKey(AppInitImportModule.ModuleName))\n                        {\n                            NewTreeContexts.Add(AppInitImportModule.ModuleName, AppInitImportModule);\n                        }\n\n                        continue;\n                    }\n\n                    foreach (var AssemblyModule in definition.Modules)\n                    {\n                        Debug.WriteLine(\"Referenced Assembling loading \" + AssemblyModule.Name + \" : \" + AssemblyModule.FileName);\n\n                        // Do not process twice the same imported module\n                        if (null != PeImports.Find(mod => mod.Name == Path.GetFileName(AssemblyModule.FileName)))\n                        {\n                            continue;\n                        }\n\n                        ImportContext AppInitImportModule = new ImportContext();\n                        AppInitImportModule.PeFilePath = null;\n                        AppInitImportModule.PeProperties = null;\n                        AppInitImportModule.ModuleName = Path.GetFileName(AssemblyModule.FileName);\n                        AppInitImportModule.ApiSetModuleName = null;\n                        AppInitImportModule.Flags = ModuleFlag.ClrReference;\n                        AppInitImportModule.ModuleLocation = ModuleSearchStrategy.ClrAssembly;\n\n                        Tuple<ModuleSearchStrategy, PE> ResolvedAppInitModule = BinaryCache.ResolveModule(\n                            this.Pe,\n                            AssemblyModule.FileName,\n                            this.SxsEntriesCache,\n                            this.CustomSearchFolders,\n                            this.WorkingDirectory\n                        );\n                        if (ResolvedAppInitModule.Item1 != ModuleSearchStrategy.NOT_FOUND)\n                        {\n                            AppInitImportModule.PeProperties = ResolvedAppInitModule.Item2;\n                            AppInitImportModule.PeFilePath = ResolvedAppInitModule.Item2.Filepath;\n                        }\n                        else\n                        {\n                            AppInitImportModule.Flags |= ModuleFlag.NotFound;\n                        }\n\n                        if (!NewTreeContexts.ContainsKey(AppInitImportModule.ModuleName))\n                        {\n                            NewTreeContexts.Add(AppInitImportModule.ModuleName, AppInitImportModule);\n                        }\n                    }\n\n                }\n\n                // Process unmanaged dlls for native calls\n                foreach (var UnmanagedModule in module.ModuleReferences)\n                {\n                    // some clr dll have a reference to an \"empty\" dll\n                    if (UnmanagedModule.Name.Length == 0)\n                    {\n                        continue;\n                    }\n\n                    Debug.WriteLine(\"Referenced module loading \" + UnmanagedModule.Name);\n\n                    // Do not process twice the same imported module\n                    if (null != PeImports.Find(m => m.Name == UnmanagedModule.Name))\n                    {\n                        continue;\n                    }\n\n\n\n                    ImportContext AppInitImportModule = new ImportContext();\n                    AppInitImportModule.PeFilePath = null;\n                    AppInitImportModule.PeProperties = null;\n                    AppInitImportModule.ModuleName = UnmanagedModule.Name;\n                    AppInitImportModule.ApiSetModuleName = null;\n                    AppInitImportModule.Flags = ModuleFlag.ClrReference;\n                    AppInitImportModule.ModuleLocation = ModuleSearchStrategy.ClrAssembly;\n\n                    Tuple<ModuleSearchStrategy, PE> ResolvedAppInitModule = BinaryCache.ResolveModule(\n                        this.Pe,\n                        UnmanagedModule.Name,\n                        this.SxsEntriesCache,\n                        this.CustomSearchFolders,\n                        this.WorkingDirectory\n                    );\n                    if (ResolvedAppInitModule.Item1 != ModuleSearchStrategy.NOT_FOUND)\n                    {\n                        AppInitImportModule.PeProperties = ResolvedAppInitModule.Item2;\n                        AppInitImportModule.PeFilePath = ResolvedAppInitModule.Item2.Filepath;\n                    }\n\n                    if (!NewTreeContexts.ContainsKey(AppInitImportModule.ModuleName))\n                    {\n                        NewTreeContexts.Add(AppInitImportModule.ModuleName, AppInitImportModule);\n                    }\n                }\n            }\n        }\n\n        /// <summary>\n        /// Background processing of a single PE file.\n        /// It can be lengthy since there are disk access (and misses).\n        /// </summary>\n        /// <param name=\"NewTreeContexts\"> This variable is passed as reference to be updated since this function is run in a separate thread. </param>\n        /// <param name=\"newPe\"> Current PE file analyzed </param>\n        private void ProcessPe(Dictionary<string, ImportContext> NewTreeContexts, PE newPe)\n        {\n            List<PeImportDll> PeImports = newPe.GetImports();\n\n            foreach (PeImportDll DllImport in PeImports)\n            {\n                // Ignore already processed imports\n                if (NewTreeContexts.ContainsKey(DllImport.Name))\n                {\n                    continue;\n                }\n\n                // Find Dll in \"paths\"\n                ImportContext ImportModule = ResolveImport(DllImport);\n\n                // add warning for appv isv applications \n                TriggerWarningOnAppvIsvImports(DllImport.Name);\n\t\t\t\t\n\n                NewTreeContexts.Add(DllImport.Name, ImportModule);\n\n\n                // AppInitDlls are triggered by user32.dll, so if the binary does not import user32.dll they are not loaded.\n                ProcessAppInitDlls(NewTreeContexts, newPe, ImportModule);\n\n\n                // if mscoree.dll is imported, it means the module is a C# assembly, and we can use Mono.Cecil to enumerate its references\n                ProcessClrImports(NewTreeContexts, newPe, ImportModule);\n            }\n        }\n\n        private class BacklogImport : Tuple<ModuleTreeViewItem, string>\n        {\n            public BacklogImport(ModuleTreeViewItem Node, string Filepath)\n            : base(Node, Filepath)\n            {\n            }\n        }\n\n        private void ConstructDependencyTree(ModuleTreeViewItem RootNode, string FilePath, int RecursionLevel = 0)\n        {\n            PE CurrentPE = (Application.Current as App).LoadBinary(FilePath);\n\n            if (null == CurrentPE)\n            {\n                return;\n            }\n\n            ConstructDependencyTree(RootNode, CurrentPE, RecursionLevel);\n        }\n\n        private void ConstructDependencyTree(ModuleTreeViewItem RootNode, PE CurrentPE, int RecursionLevel = 0)\n        {\n            // \"Closured\" variables (it 's a scope hack really).\n            Dictionary<string, ImportContext> NewTreeContexts = new Dictionary<string, ImportContext>();\n\n            BackgroundWorker bw = new BackgroundWorker();\n            bw.WorkerReportsProgress = true; // useless here for now\n\n\n            bw.DoWork += (sender, e) => {\n\n                ProcessPe(NewTreeContexts, CurrentPE);\n            };\n\n\n            bw.RunWorkerCompleted += (sender, e) =>\n            {\n                TreeBuildingBehaviour.DependencyTreeBehaviour SettingTreeBehaviour = Dependencies.TreeBuildingBehaviour.GetGlobalBehaviour();\n                List<ModuleTreeViewItem> PeWithDummyEntries = new List<ModuleTreeViewItem>();\n                List<BacklogImport> PEProcessingBacklog = new List<BacklogImport>();\n\n                // Important !\n                // \n                // This handler is executed in the STA (Single Thread Application)\n                // which is authorized to manipulate UI elements. The BackgroundWorker is not.\n                //\n\n                foreach (ImportContext NewTreeContext in NewTreeContexts.Values)\n                {\n                    ModuleTreeViewItem childTreeNode = new ModuleTreeViewItem(RootNode);\n                    DependencyNodeContext childTreeNodeContext = new DependencyNodeContext();\n                    childTreeNodeContext.IsDummy = false;\n\n                    string ModuleName = NewTreeContext.ModuleName;\n                    string ModuleFilePath = NewTreeContext.PeFilePath;\n                    ModuleCacheKey ModuleKey = new ModuleCacheKey(NewTreeContext);\n\n                    // Newly seen modules\n                    if (!this.ProcessedModulesCache.ContainsKey(ModuleKey))\n                    {\n                        // Missing module \"found\"\n                        if ((NewTreeContext.PeFilePath == null) || !NativeFile.Exists(NewTreeContext.PeFilePath)) \n                        {\n\t\t\t\t\t\t\tif (NewTreeContext.IsApiSet)\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tthis.ProcessedModulesCache[ModuleKey] = new ApiSetNotFoundModuleInfo(ModuleName, NewTreeContext.ApiSetModuleName);\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\telse\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tthis.ProcessedModulesCache[ModuleKey] = new NotFoundModuleInfo(ModuleName);\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\n                        }\n                        else\n                        {\n\n\n                            if (NewTreeContext.IsApiSet)\n                            {\n                                var ApiSetContractModule = new DisplayModuleInfo(NewTreeContext.ApiSetModuleName, NewTreeContext.PeProperties, NewTreeContext.ModuleLocation, NewTreeContext.Flags);\n                                var NewModule = new ApiSetModuleInfo(NewTreeContext.ModuleName, ref ApiSetContractModule);\n\n                                this.ProcessedModulesCache[ModuleKey] = NewModule;\n\n                                if (SettingTreeBehaviour == TreeBuildingBehaviour.DependencyTreeBehaviour.Recursive)\n                                {\n                                    PEProcessingBacklog.Add(new BacklogImport(childTreeNode, ApiSetContractModule.ModuleName));\n                                }\n                            }\n                            else\n                            {\n                                var NewModule = new DisplayModuleInfo(NewTreeContext.ModuleName, NewTreeContext.PeProperties, NewTreeContext.ModuleLocation, NewTreeContext.Flags);\n                                this.ProcessedModulesCache[ModuleKey] = NewModule;\n\n                                switch(SettingTreeBehaviour)\n                                {\n                                    case TreeBuildingBehaviour.DependencyTreeBehaviour.RecursiveOnlyOnDirectImports:\n                                        if ((NewTreeContext.Flags & ModuleFlag.DelayLoad) == 0)\n                                        {\n                                            PEProcessingBacklog.Add(new BacklogImport(childTreeNode, NewModule.ModuleName));\n                                        }\n                                        break;\n\n                                    case TreeBuildingBehaviour.DependencyTreeBehaviour.Recursive:\n                                        PEProcessingBacklog.Add(new BacklogImport(childTreeNode, NewModule.ModuleName));\n                                        break;\n                                }\n                            }\n                        }\n\n                        // add it to the module list\n                        this.ModulesList.AddModule(this.ProcessedModulesCache[ModuleKey]);\n                    }\n                    \n                    // Since we uniquely process PE, for thoses who have already been \"seen\",\n                    // we set a dummy entry in order to set the \"[+]\" icon next to the node.\n                    // The dll dependencies are actually resolved on user double-click action\n                    // We can't do the resolution in the same time as the tree construction since\n                    // it's asynchronous (we would have to wait for all the background to finish and\n                    // use another Async worker to resolve).\n\n                    if ((NewTreeContext.PeProperties != null) && (NewTreeContext.PeProperties.GetImports().Count > 0))\n                    {\n                        ModuleTreeViewItem DummyEntry = new ModuleTreeViewItem();\n                        DependencyNodeContext DummyContext = new DependencyNodeContext()\n                        {\n                            ModuleInfo = new WeakReference(new NotFoundModuleInfo(\"Dummy\")),\n                            IsDummy = true\n                        };\n\n                        DummyEntry.DataContext = DummyContext;\n                        DummyEntry.Header = \"@Dummy : if you see this header, it's a bug.\";\n                        DummyEntry.IsExpanded = false;\n\n                        childTreeNode.Items.Add(DummyEntry);\n                        childTreeNode.Expanded += ResolveDummyEntries;\n                    }\n\n                    // Add to tree view\n                    childTreeNodeContext.ModuleInfo = new WeakReference(this.ProcessedModulesCache[ModuleKey]);\n                    childTreeNode.DataContext = childTreeNodeContext;\n                    childTreeNode.Header = childTreeNode.GetTreeNodeHeaderName(Dependencies.Properties.Settings.Default.FullPath);\n                    RootNode.Items.Add(childTreeNode);\n                }\n\n\n\t\t\t\t// Process next batch of dll imports only if :\n\t\t\t\t//\t1. Recursive tree building has been activated\n\t\t\t\t//  2. Recursion is not hitting the max depth level\n\t\t\t\tbool doProcessNextLevel = (SettingTreeBehaviour != TreeBuildingBehaviour.DependencyTreeBehaviour.ChildOnly) &&\n\t\t\t\t\t\t\t\t\t\t  (RecursionLevel < Dependencies.Properties.Settings.Default.TreeDepth);\n\n\t\t\t\tif (doProcessNextLevel)\n                { \n                    foreach (var ImportNode in PEProcessingBacklog)\n                    {\n                        ConstructDependencyTree(ImportNode.Item1, ImportNode.Item2, RecursionLevel + 1); // warning : recursive call\n                    }\n                }\n\n\n            };\n\n            bw.RunWorkerAsync();\n        }\n\n        /// <summary>\n        /// Resolve imports when the user expand the node.\n        /// </summary>\n        private void ResolveDummyEntries(object sender, RoutedEventArgs e)\n        {\n            ModuleTreeViewItem NeedDummyPeNode = e.OriginalSource as ModuleTreeViewItem;\n\n            if (NeedDummyPeNode.Items.Count == 0)\n            {\n                return;\n            }\n            ModuleTreeViewItem MaybeDummyNode = (ModuleTreeViewItem) NeedDummyPeNode.Items[0];\n            DependencyNodeContext Context = (DependencyNodeContext)MaybeDummyNode.DataContext;\n\n            //TODO: Improve resolution predicate\n            if (!Context.IsDummy)\n            {\n                return;\n            }\n\n            NeedDummyPeNode.Items.Clear();\n            string Filepath = NeedDummyPeNode.ModuleFilePath;\n\n            ConstructDependencyTree(NeedDummyPeNode, Filepath);     \n        }\n\n#endregion TreeConstruction\n\n#region Commands\n     \n        private void OnModuleViewSelectedItemChanged(object sender, RoutedEventArgs e)\n        {\n            DisplayModuleInfo SelectedModule = (sender as DependencyModuleList).SelectedItem as DisplayModuleInfo;\n\n            // Selected Pe has not been found on disk\n            if (SelectedModule == null)\n                return;\n\t\t\t\n\t\t\t// Display module as root (since we can't know which parent it's attached to)\n\t\t\tUpdateImportExportLists(SelectedModule, null);\n        }\n\n        private void OnTreeViewSelectedItemChanged(object sender, RoutedPropertyChangedEventArgs<object> e)\n        {\n            if (this.DllTreeView.SelectedItem == null)\n            {\n                UpdateImportExportLists(null, null);\n                return;\n            }\n\t\t\t\n\t\t\tDependencyNodeContext childTreeContext = ((DependencyNodeContext)(this.DllTreeView.SelectedItem as ModuleTreeViewItem).DataContext);\n            DisplayModuleInfo SelectedModule = childTreeContext.ModuleInfo.Target as DisplayModuleInfo;\n            if (SelectedModule == null)\n            {\n                return;\n            }\n\n            // Selected Pe has not been found on disk : unvalidate current module\n            SelectedModule.HasErrors = !NativeFile.Exists(SelectedModule.Filepath);\n            if (SelectedModule.HasErrors)\n            {\n                // TODO : do a proper refresh instead of asking the user to do it\n                System.Windows.MessageBox.Show(String.Format(\"We could not find {0:s} file on the disk anymore, please fix this problem and refresh the window via F5\", SelectedModule.Filepath));\n            }\n\n            // Root Item : no parent\n            ModuleTreeViewItem TreeRootItem = this.DllTreeView.Items[0] as ModuleTreeViewItem;\n\t\t\tModuleTreeViewItem SelectedItem = this.DllTreeView.SelectedItem as ModuleTreeViewItem;\n\t\t\tif (SelectedItem == TreeRootItem)\n\t\t\t{\n                // Selected Pe has not been found on disk : unvalidate current module\n                if (SelectedModule.HasErrors)\n                {\n                    UpdateImportExportLists(null, null);\n                }\n                else\n                {\n                    SelectedModule.HasErrors = false;\n                    UpdateImportExportLists(SelectedModule, null);\n                }\n    \n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\t// Tree Item\n\t\t\tDisplayModuleInfo parentModule = SelectedItem.ParentModule.ModuleInfo;\n            UpdateImportExportLists(SelectedModule, parentModule);\n            \n        }\n\n        private void UpdateImportExportLists(DisplayModuleInfo SelectedModule, DisplayModuleInfo Parent)\n        {\n            if (SelectedModule == null)\n            {\n                this.ImportList.Items.Clear();\n                this.ExportList.Items.Clear();\n            }\n            else\n            {\n\t\t\t\tif (Parent == null) // root module\n\t\t\t\t{\n\t\t\t\t\tthis.ImportList.SetRootImports(SelectedModule.Imports, SymPrv, this);\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\t// Imports from the same dll are not necessarly sequential (see: HDDGuru\\RawCopy.exe)\n\t\t\t\t\tvar machingImports = Parent.Imports.FindAll(imp => imp.Name == SelectedModule._Name);\n\t\t\t\t\tthis.ImportList.SetImports(SelectedModule.Filepath, SelectedModule.Exports, machingImports, SymPrv, this);\n\t\t\t\t}\n\t\t\t\tthis.ImportList.ResetAutoSortProperty();\n\n\t\t\t\tthis.ExportList.SetExports(SelectedModule.Exports, SymPrv);\n\t\t\t\tthis.ExportList.ResetAutoSortProperty();\n            }\n        }\n\n        public PE LoadImport(string ModuleName, DisplayModuleInfo CurrentModule = null, bool DelayLoad = false)\n        {\n            if (CurrentModule == null)\n            {\n                CurrentModule = this._SelectedModule;\n            }\n\n            Tuple<ModuleSearchStrategy, PE> ResolvedModule = BinaryCache.ResolveModule(\n\t\t\t\tthis.Pe, \n\t\t\t\tModuleName, \n\t\t\t\tthis.SxsEntriesCache,\n\t\t\t\tthis.CustomSearchFolders,\n\t\t\t\tthis.WorkingDirectory\n\t\t\t);\n\n            string ModuleFilepath = (ResolvedModule.Item2 != null) ? ResolvedModule.Item2.Filepath : null;\n\n            // Not found module, returning PE without update module list\n            if (ModuleFilepath == null)\n            {\n                return ResolvedModule.Item2;\n            }\n\n            ModuleFlag ModuleFlags = ModuleFlag.NoFlag;\n            if (DelayLoad)\n                ModuleFlags |= ModuleFlag.DelayLoad;\n            if (ResolvedModule.Item1 == ModuleSearchStrategy.ApiSetSchema)\n                ModuleFlags |= ModuleFlag.ApiSet;\n\n            ModuleCacheKey ModuleKey = new ModuleCacheKey(ModuleName, ModuleFilepath, ModuleFlags);\n            if (!this.ProcessedModulesCache.ContainsKey(ModuleKey))\n            {\n                DisplayModuleInfo NewModule;\n\n                // apiset resolution are a bit trickier\n                if (ResolvedModule.Item1 == ModuleSearchStrategy.ApiSetSchema)\n                {\n                    var ApiSetContractModule = new DisplayModuleInfo(\n                        BinaryCache.LookupApiSetLibrary(ModuleName),\n                        ResolvedModule.Item2,\n                        ResolvedModule.Item1,\n                        ModuleFlags\n                    );\n                    NewModule = new ApiSetModuleInfo(ModuleName, ref ApiSetContractModule);\n                }\n                else\n                {\n                    NewModule = new DisplayModuleInfo(\n                        ModuleName,\n                        ResolvedModule.Item2,\n                        ResolvedModule.Item1,\n                        ModuleFlags\n                    );\n                    \n                }\n\n                this.ProcessedModulesCache[ModuleKey] = NewModule;\n\n                // add it to the module list\n                this.ModulesList.AddModule(this.ProcessedModulesCache[ModuleKey]);\n            }\n\n            return ResolvedModule.Item2;\n        }\n\n\n        /// <summary>\n        /// Reentrant version of Collapse/Expand Node\n        /// </summary>\n        /// <param name=\"Item\"></param>\n        /// <param name=\"ExpandNode\"></param>\n        private void CollapseOrExpandAllNodes(ModuleTreeViewItem Item, bool ExpandNode)\n        {\n            Item.IsExpanded = ExpandNode;\n            foreach(ModuleTreeViewItem ChildItem in Item.Items)\n            {\n                CollapseOrExpandAllNodes(ChildItem, ExpandNode);\n            }\n        }\n\n        private void ExpandAllNodes_Executed(object sender, ExecutedRoutedEventArgs e)\n        {\n            // Expanding all nodes tends to slow down the application (massive allocations for node DataContext)\n            // TODO : Reduce memory pressure by storing tree nodes data context in a HashSet and find an async trick\n            // to improve the command responsiveness.\n            System.Windows.Controls.TreeView TreeNode = sender as System.Windows.Controls.TreeView;\n            CollapseOrExpandAllNodes((TreeNode.Items[0] as ModuleTreeViewItem), true);\n        }\n\n        private void CollapseAllNodes_Executed(object sender, ExecutedRoutedEventArgs e)\n        {\n            System.Windows.Controls.TreeView TreeNode = sender as System.Windows.Controls.TreeView;\n            CollapseOrExpandAllNodes((TreeNode.Items[0] as ModuleTreeViewItem), false);\n        }\n\n        private void DoFindModuleInList_Executed(object sender, ExecutedRoutedEventArgs e)\n        {\n            ModuleTreeViewItem Source = e.Source as ModuleTreeViewItem;\n            String SelectedModuleName = Source.GetTreeNodeHeaderName(Dependencies.Properties.Settings.Default.FullPath);\n\n            foreach (DisplayModuleInfo item in this.ModulesList.Items)\n            {\n                if (item.ModuleName == SelectedModuleName)\n                {\n\n                    this.ModulesList.SelectedItem = item;\n                    this.ModulesList.ScrollIntoView(item);\n                    return;\n                }\n            }\n        }\n\n        private void ExpandAllParentNode(ModuleTreeViewItem Item)\n        {\n            if (Item != null)\n            {\n                ExpandAllParentNode(Item.Parent as ModuleTreeViewItem);\n                Item.IsExpanded = true;\n            }\n        }\n\n        /// <summary>\n        /// Reentrant version of Collapse/Expand Node\n        /// </summary>\n        /// <param name=\"Item\"></param>\n        /// <param name=\"ExpandNode\"></param>\n        private ModuleTreeViewItem FindModuleInTree(ModuleTreeViewItem Item, DisplayModuleInfo Module, bool Highlight=false)\n        {\n            \n            if (Item.GetTreeNodeHeaderName(Dependencies.Properties.Settings.Default.FullPath) == Module.ModuleName)\n            {\n\t\t\t\tif (Highlight)\n\t\t\t\t{ \n\t\t\t\t\tExpandAllParentNode(Item.Parent as ModuleTreeViewItem);\n\t\t\t\t\tItem.IsSelected = true;\n\t\t\t\t\tItem.BringIntoView();\n\t\t\t\t\tItem.Focus();\n\t\t\t\t}\n\n\t\t\t\treturn Item;\n            }\n\n            // BFS style search -> return the first matching node with the lowest \"depth\"\n            foreach (ModuleTreeViewItem ChildItem in Item.Items)\n            {\n                if(ChildItem.GetTreeNodeHeaderName(Dependencies.Properties.Settings.Default.FullPath) == Module.ModuleName)\n                {\n\t\t\t\t\tif (Highlight)\n\t\t\t\t\t{\n\t\t\t\t\t\tExpandAllParentNode(Item);\n\t\t\t\t\t\tChildItem.IsSelected = true;\n\t\t\t\t\t\tChildItem.BringIntoView();\n\t\t\t\t\t\tChildItem.Focus();\n\t\t\t\t\t}\n\n                    return Item;\n                }\n            }\n\n            foreach (ModuleTreeViewItem ChildItem in Item.Items)\n            {\n\t\t\t\tModuleTreeViewItem matchingItem = FindModuleInTree(ChildItem, Module, Highlight);\n\t\t\t\t\n\t\t\t\t// early exit as soon as we find a matching node\n\t\t\t\tif (matchingItem != null)\n                    return matchingItem;\n            }\n\n            return null;\n        }\n\n        \n        public  RelayCommand DoFindModuleInTree\n        {\n            get\n            {\n                return new RelayCommand((param) =>\n                {\n                    DisplayModuleInfo SelectedModule = (param as DisplayModuleInfo);\n                    ModuleTreeViewItem TreeRootItem = this.DllTreeView.Items[0] as ModuleTreeViewItem;\n\n                    FindModuleInTree(TreeRootItem, SelectedModule, true);\n                });\n            }\n        }\n\n        public RelayCommand ConfigureSearchOrderCommand\n        {\n            get\n            {\n                return new RelayCommand((param) =>\n                {\n                    ModuleSearchOrder modalWindow = new ModuleSearchOrder(ProcessedModulesCache);\n                    modalWindow.ShowDialog();\n                });\n            }\n        }\n#endregion // Commands \n\n    }\n}\n"
  },
  {
    "path": "DependenciesGui/DragablzCustomHeader.cs",
    "content": "﻿using System;\nusing System.Collections.Generic;\nusing System.Linq;\nusing System.Text;\nusing System.Threading.Tasks;\nusing System.Windows;\nusing System.Windows.Controls;\nusing System.Windows.Data;\nusing System.Windows.Documents;\nusing System.Windows.Input;\nusing System.Windows.Media;\nusing System.Windows.Media.Imaging;\nusing System.Windows.Navigation;\nusing System.Windows.Shapes;\n\nnamespace Dependencies\n{\n    public partial class DragablzCustomHeader : UserControl\n    {\n        public DragablzCustomHeader()\n        {\n            InitializeComponent();\n        }\n    }\n}\n"
  },
  {
    "path": "DependenciesGui/DragablzCustomHeader.xaml",
    "content": "﻿<UserControl x:Class=\"Dependencies.DragablzCustomHeader\"\n             xmlns=\"http://schemas.microsoft.com/winfx/2006/xaml/presentation\"\n             xmlns:x=\"http://schemas.microsoft.com/winfx/2006/xaml\"\n             xmlns:mc=\"http://schemas.openxmlformats.org/markup-compatibility/2006\" \n             xmlns:d=\"http://schemas.microsoft.com/expression/blend/2008\"\n             xmlns:dragablz=\"clr-namespace:Dragablz;assembly=Dragablz\"\n             xmlns:local=\"clr-namespace:Dependencies\"\n             mc:Ignorable=\"d\" \n             d:DesignHeight=\"300\" d:DesignWidth=\"300\"\n             d:DataContext=\"{d:DesignInstance local:CustomHeaderViewModel, IsDesignTimeCreatable=False}\">\n    \n    <!--     \n        Illustrates how to add a custom header, without completely rewriting the DragablzItem header template.\n    \n        Note that rewriting the DragablzItem header template is a perfectly valid thing to do, but this allows\n        customisation of existing templates.    \n    -->\n\n\n    <UserControl.InputBindings>\n        <MouseBinding Command=\"dragablz:TabablzControl.CloseItemCommand\" MouseAction=\"MiddleClick\" />\n    </UserControl.InputBindings>\n    \n    <StackPanel Orientation=\"Horizontal\">\n        <Grid>\n            <TextBlock Text=\"{Binding Header}\" />\n            <!-- you should provide your own Thumb, which will be used to monitor dragging -->\n            <Thumb Style=\"{DynamicResource InvisibleThumbStyle}\"\n                   dragablz:DragablzItem.IsCustomThumb=\"True\" />\n        </Grid>\n    </StackPanel>\n\n</UserControl>"
  },
  {
    "path": "DependenciesGui/FilterControl/FilterControl.cs",
    "content": "﻿using System;\nusing System.Windows.Controls;\nusing System.Windows;\nusing System.Windows.Threading;\nusing System.Windows.Data;\nusing System.Windows.Input;\nusing System.Collections;\nusing System.Reflection;\nusing System.ComponentModel;\nusing System.Linq;\n\nnamespace Dependencies\n{\n    public delegate void FilterRoutedEventHandler(object sender, FilterEventArgs e);\n\n    public delegate void DirectionRoutedEventHandler(object sender, DirectionEventArgs e);\n\n    public enum DirectionEnum\n    {\n        Default,\n        Up,\n        Down,\n        Left,\n        Right,\n    }\n\n    [TemplatePart(Name = PART_FilterBox, Type = typeof(TextBox))]\n    [TemplatePart(Name = PART_ClearButton, Type = typeof(Button))]\n    [TemplatePart(Name = PART_Header, Type = typeof(TextBlock))]\n    public class FilterControl : Control\n    {\n\n        #region Declarations\n\n        private const string PART_FilterBox = \"PART_FilterBox\";\n        private const string PART_ClearButton = \"PART_ClearButton\";\n        private const string PART_Header = \"PART_Header\";\n\n        public static readonly RoutedEvent FilterEvent;\n\n        public static readonly RoutedEvent DirectionEvent;\n\n        public static readonly RoutedEvent ClearFilterEvent;\n\n        private Button clearButton = null;\n        private TextBox filterBox = null;\n        private TextBlock textBlock = null;\n        private int tickCount;\n\n        private bool byPassEvent = false;\n\n        private DispatcherTimer timer;\n\n        #endregion\n\n        #region Constructors\n\n        static FilterControl()\n        {\n            //This OverrideMetadata call tells the system that this element wants to provide a style that is different than its base class.\n            //This style is defined in themes\\generic.xaml\n            DefaultStyleKeyProperty.OverrideMetadata(typeof(FilterControl),\n                                                     new FrameworkPropertyMetadata(typeof(FilterControl)));\n\n            FilterEvent = EventManager.RegisterRoutedEvent(\"Filter\", RoutingStrategy.Bubble, typeof(FilterRoutedEventHandler), typeof(FilterControl));\n\n            DirectionEvent = EventManager.RegisterRoutedEvent(\"Direction\", RoutingStrategy.Bubble, typeof(DirectionRoutedEventHandler), typeof(FilterControl));\n\n            ClearFilterEvent = EventManager.RegisterRoutedEvent(\"ClearFilter\", RoutingStrategy.Bubble, typeof(RoutedEventArgs), typeof(FilterControl));\n\n        }\n\n        public FilterControl()\n        {\n            timer = new DispatcherTimer(DispatcherPriority.Normal);\n            timer.Interval = new TimeSpan(0, 0, 0, 0, FilterFiringInterval);\n            timer.Tick += new EventHandler(OnDispatcherTimerTick);\n\n            Visibility = System.Windows.Visibility.Collapsed;\n        }\n\n        #endregion\n\n        #region FilterText property\n\n        public string FilterText\n        {\n            get\n            {\n                return (string)GetValue(FilterTextProperty);\n            }\n            set\n            {\n                SetValue(FilterTextProperty, value);\n            }\n        }\n\n        public static readonly DependencyProperty FilterTextProperty =\n            DependencyProperty.Register(\"FilterText\", typeof(string),\n            typeof(FilterControl), new PropertyMetadata(string.Empty));\n\n        #endregion\n\n        #region Header property\n\n        public string Header\n        {\n            get { return (string)GetValue(HeaderProperty); }\n            set { SetValue(HeaderProperty, value); }\n        }\n\n        public static readonly DependencyProperty HeaderProperty =\n            DependencyProperty.Register(\"Header\", typeof(string), typeof(FilterControl), new UIPropertyMetadata(string.Empty));\n\n        #endregion\n\n        #region TargetControl property\n\n        public ItemsControl TargetControl\n        {\n            get { return (ItemsControl)GetValue(TargetControlProperty); }\n            set { SetValue(TargetControlProperty, value); }\n        }\n\n        public static readonly DependencyProperty TargetControlProperty =\n            DependencyProperty.Register(\"TargetControl\", typeof(ItemsControl), typeof(FilterControl), new UIPropertyMetadata(null));\n\n        #endregion\n\n        #region FilterTextBindingPath property\n\n        public string FilterTextBindingPath\n        {\n            get\n            {\n                return (string)GetValue(FilterTextBindingPathProperty);\n            }\n            set\n            {\n                SetValue(FilterTextBindingPathProperty, value);\n            }\n        }\n\n        public static readonly DependencyProperty FilterTextBindingPathProperty =\n            DependencyProperty.Register(\"FilterTextBindingPath\", typeof(string),\n            typeof(FilterControl), new PropertyMetadata(string.Empty));\n\n        #endregion\n\n        #region FilterOnEnter property\n\n        public bool FilterOnEnter\n        {\n            get { return (bool)GetValue(FilterOnEnterProperty); }\n            set { SetValue(FilterOnEnterProperty, value); }\n        }\n\n        public static readonly DependencyProperty FilterOnEnterProperty =\n            DependencyProperty.Register(\"FilterOnEnter\", typeof(bool), typeof(FilterControl), new UIPropertyMetadata(false));\n\n        #endregion\n\n        #region FilterFiringInterval property\n\n        public int FilterFiringInterval\n        {\n            get { return (int)GetValue(FilterFiringIntervalProperty); }\n            set { SetValue(FilterFiringIntervalProperty, value); }\n        }\n\n        public static readonly DependencyProperty FilterFiringIntervalProperty =\n            DependencyProperty.Register(\"FilterFiringInterval\", typeof(int), typeof(FilterControl), new UIPropertyMetadata(300, new PropertyChangedCallback(OnFilterFiringIntervalChanged)));\n\n        private static void OnFilterFiringIntervalChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)\n        {\n            FilterControl filterBox = d as FilterControl;\n            filterBox.timer.Interval = new TimeSpan(0, 0, 0, 0, filterBox.FilterFiringInterval);\n        }\n\n        #endregion\n\n        #region Filter event\n\n        public event FilterRoutedEventHandler Filter\n        {\n            add\n            {\n                base.AddHandler(FilterEvent, value);\n            }\n            remove\n            {\n                base.RemoveHandler(FilterEvent, value);\n            }\n        }\n\n        #endregion\n\n        #region Direction event\n\n        public event DirectionRoutedEventHandler Direction\n        {\n            add\n            {\n                base.AddHandler(DirectionEvent, value);\n            }\n            remove\n            {\n                base.RemoveHandler(DirectionEvent, value);\n            }\n        }\n\n        #endregion\n\n        #region ClearFilter event\n\n        public event RoutedEventHandler ClearFilter\n        {\n            add\n            {\n                base.AddHandler(ClearFilterEvent, value);\n            }\n            remove\n            {\n                base.RemoveHandler(ClearFilterEvent, value);\n            }\n        }\n\n        #endregion\n\n        #region Overridden Functions/Methods\n\n        public override void OnApplyTemplate()\n        {\n            base.OnApplyTemplate();\n\n            AttachToVisualTree();\n        }\n\n        #endregion\n\n        #region Private Functions/Methods\n\n        private void ApplyFilterOnTarget()\n        {\n            if (TargetControl == null || TargetControl.Items.SourceCollection == null)\n                return;\n\n            ICollectionView collectionView = CollectionViewSource.GetDefaultView(TargetControl.Items.SourceCollection);\n\n            if (collectionView == null)\n            {\n                throw new InvalidOperationException(\"The TargetConrol should use ICollectionView as ItemSource.\");\n            }\n\n\n            if (string.IsNullOrEmpty(this.FilterTextBindingPath))\n            {\n                throw new InvalidOperationException(\"FilterTextBindingPath is not set.\");\n            }\n\n            collectionView.Filter = (m => (GetDataValue<string>(m, this.FilterTextBindingPath).IndexOf(this.FilterText, StringComparison.InvariantCultureIgnoreCase) > -1));\n\n        }\n\n        private void ClearFilterOnTarget()\n        {\n            if (TargetControl == null || TargetControl.Items.SourceCollection == null)\n                return;\n\n            ICollectionView collectionView = CollectionViewSource.GetDefaultView(TargetControl.Items.SourceCollection);\n\n            if (collectionView == null)\n            {\n                throw new InvalidOperationException(\"The TargetControl should use ICollectionView as ItemSource.\");\n            }            \n\n            collectionView.Filter = null;\n            this.Visibility = System.Windows.Visibility.Collapsed;\n        }\n\n        public void RaiseFilterEvent()\n        {\n            FilterEventArgs args = new FilterEventArgs(FilterEvent, this, this.FilterText);\n            RaiseEvent(args);\n\n            if (!args.IsFilterApplied)\n            {\n                ApplyFilterOnTarget();\n            }\n        }\n\n        private T GetDataValue<T>(object data, string propertyName)\n        {\n\n            PropertyInfo[] propinfo = data.GetType().GetProperties();\n            PropertyDescriptorCollection descriptors = TypeDescriptor.GetProperties(data.GetType());\n            PropertyDescriptor descriptor = descriptors[propertyName];\n\n            if (descriptor == null)\n            {\n                throw new InvalidOperationException();\n            }\n\n            T value = (T)descriptor.GetValue(data);\n\n            return value;\n        }\n\n        private void AttachToVisualTree()\n        {\n            textBlock = GetTemplateChild(PART_Header) as TextBlock;\n\n            filterBox = GetTemplateChild(PART_FilterBox) as TextBox;\n\n            if (filterBox != null)\n            {\n                filterBox.Focus();\n                filterBox.LostKeyboardFocus += new System.Windows.Input.KeyboardFocusChangedEventHandler(OnLostKeyboardFocus);\n                filterBox.GotKeyboardFocus += new System.Windows.Input.KeyboardFocusChangedEventHandler(OnGotKeyboardFocus);\n                filterBox.TextChanged += new TextChangedEventHandler(OnFilterBoxTextChanged);\n            }\n\n            clearButton = GetTemplateChild(PART_ClearButton) as Button;\n\n            if (clearButton != null)\n            {\n                clearButton.Click += new RoutedEventHandler(OnClearButtonClick);\n            }\n\n            this.KeyDown += new KeyEventHandler(OnControlKeyDown);\n            this.GotKeyboardFocus += new KeyboardFocusChangedEventHandler(OnKeyboardGotFocus);\n        }\n\n        private void OnKeyboardGotFocus(object sender, KeyboardFocusChangedEventArgs e)\n        {\n            Keyboard.Focus(filterBox);\n        }\n\n        private void OnControlKeyDown(object sender, KeyEventArgs e)\n        {\n            if (e.Key == Key.Escape) /* && !string.IsNullOrEmpty(FilterText)) */\n            {\n                Clear();\n            }\n            else if (e.Key == Key.Enter && FilterOnEnter)\n            {\n                RaiseFilterEvent();\n            }\n            else if (e.Key == Key.Up)\n            {\n                DirectionEventArgs args = new DirectionEventArgs(DirectionEvent, this, DirectionEnum.Up);\n                RaiseEvent(args);\n            }\n            else if (e.Key == Key.Down)\n            {\n                DirectionEventArgs args = new DirectionEventArgs(DirectionEvent, this, DirectionEnum.Down);\n                RaiseEvent(args);\n            }\n            else if (e.Key == Key.Right)\n            {\n                DirectionEventArgs args = new DirectionEventArgs(DirectionEvent, this, DirectionEnum.Right);\n                RaiseEvent(args);\n            }\n            else if (e.Key == Key.Left)\n            {\n                DirectionEventArgs args = new DirectionEventArgs(DirectionEvent, this, DirectionEnum.Left);\n                RaiseEvent(args);\n            }\n        }\n\n        private void OnClearButtonClick(object sender, RoutedEventArgs e)\n        {\n            Clear();\n        }\n\n        public void Clear()\n        {\n            byPassEvent = true;\n            filterBox.Text = string.Empty;\n            Keyboard.Focus(filterBox);\n\n\n            RoutedEventArgs args = new RoutedEventArgs(ClearFilterEvent, this);\n            RaiseEvent(args);\n\n            if (!args.Handled)\n            {\n                ClearFilterOnTarget();\n            }\n\n        }\n\n        private void OnFilterBoxTextChanged(object sender, TextChangedEventArgs e)\n        {\n            if (!FilterOnEnter)\n            {\n                tickCount = 0;\n                timer.Start();\n            }\n            if (string.IsNullOrEmpty(filterBox.Text))\n            {\n                // clearButton.Visibility = Visibility.Collapsed;\n\n                if (!filterBox.IsFocused)\n                    textBlock.Visibility = Visibility.Visible;\n                else\n                    textBlock.Visibility = Visibility.Collapsed;\n            }\n            else\n            {\n                //clearButton.Visibility = Visibility.Visible;\n                textBlock.Visibility = Visibility.Collapsed;\n            }\n        }\n\n        private void OnGotKeyboardFocus(object sender, System.Windows.Input.KeyboardFocusChangedEventArgs e)\n        {\n            textBlock.Visibility = Visibility.Collapsed;\n            \n        }\n\n        private void OnLostKeyboardFocus(object sender, System.Windows.Input.KeyboardFocusChangedEventArgs e)\n        {\n            if (string.IsNullOrEmpty(filterBox.Text))\n            {\n                textBlock.Visibility = Visibility.Visible;\n            }\n        }\n\n        private void OnDispatcherTimerTick(object sender, EventArgs e)\n        {\n            if (tickCount == 2)\n            {\n                tickCount = 0;\n                timer.Stop();\n\n                if (!byPassEvent)\n                {\n                    RaiseFilterEvent();\n                }\n                byPassEvent = false;\n            }\n\n            tickCount++;\n        }\n\n        #endregion\n\n    }\n\n    public class FilterEventArgs : RoutedEventArgs\n    {\n        public string FilterText\n        {\n            get;\n            private set;\n        }\n\n        public bool IsFilterApplied\n        {\n            get;\n            set;\n        }\n\n        public FilterEventArgs()\n            : base()\n        {\n            FilterText = null;\n            IsFilterApplied = false;\n        }\n\n        public FilterEventArgs(RoutedEvent routedEvent, object source) :\n            this(routedEvent, source, string.Empty)\n        {\n        }\n\n        public FilterEventArgs(RoutedEvent routedEvent, object source, string filterText)\n            : base(routedEvent, source)\n        {\n            FilterText = filterText;\n        }\n    }\n\n    public class DirectionEventArgs : RoutedEventArgs\n    {\n        public DirectionEnum Direction\n        {\n            get;\n            private set;\n        }\n\n        public DirectionEventArgs()\n            : base()\n        {\n            Direction = DirectionEnum.Default;\n        }\n\n        public DirectionEventArgs(RoutedEvent routedEvent, object source) :\n            this(routedEvent, source, DirectionEnum.Default)\n        {\n        }\n\n        public DirectionEventArgs(RoutedEvent routedEvent, object source, DirectionEnum direction)\n            : base(routedEvent, source)\n        {\n            Direction = direction;\n        }\n    }\n\n}\n"
  },
  {
    "path": "DependenciesGui/FilterControl/FilterControl.generic.xaml",
    "content": "﻿<ResourceDictionary \n    xmlns=\"http://schemas.microsoft.com/winfx/2006/xaml/presentation\"\n    xmlns:x=\"http://schemas.microsoft.com/winfx/2006/xaml\"\n    xmlns:d=\"http://schemas.microsoft.com/expression/blend/2008\" \n    xmlns:mc=\"http://schemas.openxmlformats.org/markup-compatibility/2006\" \n    xmlns:local=\"clr-namespace:Dependencies\"\n    mc:Ignorable=\"d\">\n\n    <!-- Style for the Clear Button -->\n    <Style x:Key=\"ClearButtonStyle\" TargetType=\"{x:Type Button}\">\n        <Setter Property=\"BorderBrush\" Value=\"Transparent\"/>\n        <Setter Property=\"Background\" Value=\"Transparent\"/>\n        <Setter Property=\"Template\">\n            <Setter.Value>\n                <ControlTemplate TargetType=\"{x:Type Button}\">\n                    <Border x:Name=\"border\" \n\t\t\t\t\t\tCornerRadius=\"2\" \n\t\t\t\t\t\tBackground=\"{TemplateBinding Background}\" \n\t\t\t\t\t\tBorderThickness=\"1\" \n\t\t\t\t\t\tBorderBrush=\"{TemplateBinding BorderBrush}\" \n\t\t\t\t\t\tWidth=\"16\" Height=\"16\" \n\t\t\t\t\t\tSnapsToDevicePixels=\"True\">\n                        <Grid Width=\"8\" Height=\"8\" HorizontalAlignment=\"Center\" VerticalAlignment=\"Center\">\n                            <Path x:Name=\"path1\" Stroke=\"#ADADAD\" Data=\"M0,0 L8,8\" StrokeThickness=\"2\" />\n                            <Path x:Name=\"path2\" Stroke=\"#ADADAD\" Data=\"M8,0 L0,8\" StrokeThickness=\"2\" />\n                        </Grid>\n                    </Border>\n                    <ControlTemplate.Triggers>\n                        <Trigger Property=\"IsMouseOver\" Value=\"True\">\n                            <Setter Property=\"BorderBrush\" Value=\"#ADADAD\"/>\n                            <Setter Property=\"Background\" Value=\"WhiteSmoke\"/>\n                            <Setter Property=\"Stroke\" TargetName=\"path1\" Value=\"DarkRed\"/>\n                            <Setter Property=\"Stroke\" TargetName=\"path2\" Value=\"DarkRed\"/>\n                        </Trigger>\n                        <Trigger Property=\"IsPressed\" Value=\"True\">\n                            <Setter Property=\"Background\">\n                                <Setter.Value>\n                                    <LinearGradientBrush EndPoint=\"0,1\" StartPoint=\"0,0\">\n                                        <GradientStop Color=\"#FFADADAD\" Offset=\"0\"/>\n                                        <GradientStop Color=\"White\" Offset=\"0.5\"/>\n                                        <GradientStop Color=\"White\" Offset=\"1\"/>\n                                    </LinearGradientBrush>\n                                </Setter.Value>\n                            </Setter>\n                        </Trigger>\n                    </ControlTemplate.Triggers>\n                </ControlTemplate>\n            </Setter.Value>\n        </Setter>\n    </Style>\n\n    <SolidColorBrush x:Key=\"ListBorder\" Color=\"#FF7F9DB9\"/>\n\n    <LinearGradientBrush x:Key=\"FocusBackground\" EndPoint=\"0.5,0\" StartPoint=\"0.5,1.667\">\n        <GradientStop Color=\"#FF073553\" Offset=\"0\"/>\n        <GradientStop Color=\"#FFA7D5F4\" Offset=\"0.796\"/>\n        <GradientStop Color=\"#FF5A88A8\" Offset=\"1\"/>\n    </LinearGradientBrush>\n\n    <Style x:Key=\"FilterTextBoxStyle\" TargetType=\"{x:Type TextBox}\">\n        <Setter Property=\"Background\" Value=\"{DynamicResource {x:Static SystemColors.WindowBrushKey}}\"/>\n        <Setter Property=\"BorderBrush\" Value=\"{StaticResource ListBorder}\"/>\n        <Setter Property=\"Foreground\" Value=\"{DynamicResource {x:Static SystemColors.ControlTextBrushKey}}\"/>        \n        <Setter Property=\"Padding\" Value=\"2\"/>\n        <Setter Property=\"FocusVisualStyle\" Value=\"{x:Null}\"/>\n        <Setter Property=\"AllowDrop\" Value=\"true\"/>\n        <Setter Property=\"Template\">\n            <Setter.Value>\n                <ControlTemplate TargetType=\"{x:Type TextBox}\">\n                    <Border x:Name=\"Bd\" SnapsToDevicePixels=\"true\" Background=\"{TemplateBinding Background}\" BorderBrush=\"{TemplateBinding BorderBrush}\" BorderThickness=\"{TemplateBinding BorderThickness}\">\n                        <ScrollViewer x:Name=\"PART_ContentHost\" SnapsToDevicePixels=\"{TemplateBinding SnapsToDevicePixels}\"/>\n                    </Border>\n                    <ControlTemplate.Triggers>\n                        <Trigger Property=\"IsEnabled\" Value=\"false\">\n                            <Setter Property=\"Background\" TargetName=\"Bd\" Value=\"{DynamicResource {x:Static SystemColors.ControlBrushKey}}\"/>\n                            <Setter Property=\"Foreground\" Value=\"{DynamicResource {x:Static SystemColors.GrayTextBrushKey}}\"/>\n                        </Trigger>\n                    </ControlTemplate.Triggers>\n                </ControlTemplate>\n            </Setter.Value>\n        </Setter>\n        <Setter Property=\"BorderThickness\" Value=\"0,0,0,0\"/>\n    </Style>\n\n    <Style TargetType=\"{x:Type local:FilterControl}\">\n        <Setter Property=\"Background\" Value=\"{DynamicResource {x:Static SystemColors.WindowBrushKey}}\"/>        \n        <Setter Property=\"FilterOnEnter\" Value=\"False\"/>\n        <Setter Property=\"Template\">\n            <Setter.Value>\n                <ControlTemplate TargetType=\"{x:Type local:FilterControl}\">\n                    <Border x:Name=\"border\" Background=\"#ADADAD\">\n                \t\t<Grid Margin=\"1\">\n                            <Grid.ColumnDefinitions>\n                                <ColumnDefinition Width=\"Auto\"/>\n                                <ColumnDefinition Width=\"*\"/>\n                                <ColumnDefinition Width=\"Auto\"/>\n                            </Grid.ColumnDefinitions>                \t\t\t\n                            <Border Background=\"{TemplateBinding Background}\" Grid.ColumnSpan=\"3\" VerticalAlignment=\"Stretch\" HorizontalAlignment=\"Stretch\" />\n                            <Label Height=\"25\" \n                                   VerticalAlignment=\"Center\"\n                                   Grid.Column=\"0\">\n                                        Search :\n                            </Label>\n                            <TextBox Style=\"{StaticResource FilterTextBoxStyle}\"\n                                     x:Name=\"PART_FilterBox\"  AutoWordSelection=\"True\"\n                                     Grid.Column=\"1\"\n                                     Margin=\"0,1,0,1\" VerticalAlignment=\"Center\"\n                                     Text=\"{Binding RelativeSource={RelativeSource AncestorType={x:Type local:FilterControl}}, Path=FilterText, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}\"/>\n                            <TextBlock x:Name=\"PART_Header\" Text=\"{TemplateBinding Header}\"  VerticalAlignment=\"Center\" HorizontalAlignment=\"Left\" Margin=\"2,0,0,0\"\n                                       Grid.Column=\"1\"\n                                       IsHitTestVisible=\"False\" Foreground=\"#ADADAD\"/>\n                \t\t\t<Button x:Name=\"PART_ClearButton\" Grid.Column=\"2\" Margin=\"0,0,4,0\" Style=\"{StaticResource ClearButtonStyle}\" \n                                    Visibility=\"Visible\"/>\n                \t\t</Grid>\n                \t</Border>\n                    <ControlTemplate.Triggers>\n                        <Trigger Property=\"IsFocused\" Value=\"True\" SourceName=\"PART_FilterBox\" >\n                            <Setter Property=\"Background\" Value=\"{StaticResource FocusBackground}\" TargetName=\"border\" />\n                        </Trigger>\n                        <Trigger Property=\"IsFocused\" Value=\"True\" SourceName=\"PART_ClearButton\" >\n                            <Setter Property=\"Background\" Value=\"{StaticResource FocusBackground}\" TargetName=\"border\" />\n                        </Trigger>\n                        <Trigger Property=\"IsFocused\" Value=\"True\" >\n                            <Setter Property=\"Background\" Value=\"{StaticResource FocusBackground}\" TargetName=\"border\" />\n                        </Trigger>                        \n                    </ControlTemplate.Triggers>\n                </ControlTemplate>\n            </Setter.Value>\n        </Setter>                \n    </Style>    \n    \n</ResourceDictionary>"
  },
  {
    "path": "DependenciesGui/GridViewSort.cs",
    "content": "﻿using System.ComponentModel;\nusing System.Windows;\nusing System.Windows.Controls;\nusing System.Windows.Input;\nusing System.Windows.Media;\nusing System.Windows.Documents;\n\nnamespace Wpf.Util\n{\n    public class GridViewSort\n    {\n        #region Public attached properties\n\n        public static ICommand GetCommand(DependencyObject obj)\n        {\n            return (ICommand)obj.GetValue(CommandProperty);\n        }\n\n        public static void SetCommand(DependencyObject obj, ICommand value)\n        {\n            obj.SetValue(CommandProperty, value);\n        }\n\n        // Using a DependencyProperty as the backing store for Command.  This enables animation, styling, binding, etc...\n        public static readonly DependencyProperty CommandProperty =\n            DependencyProperty.RegisterAttached(\n                \"Command\",\n                typeof(ICommand),\n                typeof(GridViewSort),\n                new UIPropertyMetadata(\n                    null,\n                    (o, e) =>\n                    {\n                        ItemsControl listView = o as ItemsControl;\n                        if (listView != null)\n                        {\n                            if (!GetAutoSort(listView)) // Don't change click handler if AutoSort enabled\n                            {\n                                if (e.OldValue != null && e.NewValue == null)\n                                {\n                                    listView.RemoveHandler(GridViewColumnHeader.ClickEvent, new RoutedEventHandler(ColumnHeader_Click));\n                                }\n                                if (e.OldValue == null && e.NewValue != null)\n                                {\n                                    listView.AddHandler(GridViewColumnHeader.ClickEvent, new RoutedEventHandler(ColumnHeader_Click));\n                                }\n                            }\n                        }\n                    }\n                )\n            );\n\n        public static bool GetAutoSort(DependencyObject obj)\n        {\n            return (bool)obj.GetValue(AutoSortProperty);\n        }\n\n        public static void SetAutoSort(DependencyObject obj, bool value)\n        {\n            obj.SetValue(AutoSortProperty, value);\n        }\n\n        // Using a DependencyProperty as the backing store for AutoSort.  This enables animation, styling, binding, etc...\n        public static readonly DependencyProperty AutoSortProperty =\n            DependencyProperty.RegisterAttached(\n                \"AutoSort\",\n                typeof(bool),\n                typeof(GridViewSort),\n                new UIPropertyMetadata(\n                    false,\n                    (o, e) =>\n                    {\n                        ListView listView = o as ListView;\n                        if (listView != null)\n                        {\n                            if (GetCommand(listView) == null) // Don't change click handler if a command is set\n                            {\n                                bool oldValue = (bool)e.OldValue;\n                                bool newValue = (bool)e.NewValue;\n                                if (oldValue && !newValue)\n                                {\n                                    listView.RemoveHandler(GridViewColumnHeader.ClickEvent, new RoutedEventHandler(ColumnHeader_Click));\n                                }\n                                if (!oldValue && newValue)\n                                {\n                                    listView.AddHandler(GridViewColumnHeader.ClickEvent, new RoutedEventHandler(ColumnHeader_Click));\n                                }\n                            }\n                        }\n                    }\n                )\n            );\n\n        public static string GetPropertyName(DependencyObject obj)\n        {\n            return (string)obj.GetValue(PropertyNameProperty);\n        }\n\n        public static void SetPropertyName(DependencyObject obj, string value)\n        {\n            obj.SetValue(PropertyNameProperty, value);\n        }\n\n        // Using a DependencyProperty as the backing store for PropertyName.  This enables animation, styling, binding, etc...\n        public static readonly DependencyProperty PropertyNameProperty =\n            DependencyProperty.RegisterAttached(\n                \"PropertyName\",\n                typeof(string),\n                typeof(GridViewSort),\n                new UIPropertyMetadata(null)\n            );\n\n        public static bool GetShowSortGlyph(DependencyObject obj)\n        {\n            return (bool)obj.GetValue(ShowSortGlyphProperty);\n        }\n\n        public static void SetShowSortGlyph(DependencyObject obj, bool value)\n        {\n            obj.SetValue(ShowSortGlyphProperty, value);\n        }\n\n        // Using a DependencyProperty as the backing store for ShowSortGlyph.  This enables animation, styling, binding, etc...\n        public static readonly DependencyProperty ShowSortGlyphProperty =\n            DependencyProperty.RegisterAttached(\"ShowSortGlyph\", typeof(bool), typeof(GridViewSort), new UIPropertyMetadata(true));\n\n        public static ImageSource GetSortGlyphAscending(DependencyObject obj)\n        {\n            return (ImageSource)obj.GetValue(SortGlyphAscendingProperty);\n        }\n\n        public static void SetSortGlyphAscending(DependencyObject obj, ImageSource value)\n        {\n            obj.SetValue(SortGlyphAscendingProperty, value);\n        }\n\n        // Using a DependencyProperty as the backing store for SortGlyphAscending.  This enables animation, styling, binding, etc...\n        public static readonly DependencyProperty SortGlyphAscendingProperty =\n            DependencyProperty.RegisterAttached(\"SortGlyphAscending\", typeof(ImageSource), typeof(GridViewSort), new UIPropertyMetadata(null));\n\n        public static ImageSource GetSortGlyphDescending(DependencyObject obj)\n        {\n            return (ImageSource)obj.GetValue(SortGlyphDescendingProperty);\n        }\n\n        public static void SetSortGlyphDescending(DependencyObject obj, ImageSource value)\n        {\n            obj.SetValue(SortGlyphDescendingProperty, value);\n        }\n\n        // Using a DependencyProperty as the backing store for SortGlyphDescending.  This enables animation, styling, binding, etc...\n        public static readonly DependencyProperty SortGlyphDescendingProperty =\n            DependencyProperty.RegisterAttached(\"SortGlyphDescending\", typeof(ImageSource), typeof(GridViewSort), new UIPropertyMetadata(null));\n\n        #endregion\n\n        #region Private attached properties\n\n        private static GridViewColumnHeader GetSortedColumnHeader(DependencyObject obj)\n        {\n            return (GridViewColumnHeader)obj.GetValue(SortedColumnHeaderProperty);\n        }\n\n        private static void SetSortedColumnHeader(DependencyObject obj, GridViewColumnHeader value)\n        {\n            obj.SetValue(SortedColumnHeaderProperty, value);\n        }\n\n        // Using a DependencyProperty as the backing store for SortedColumn.  This enables animation, styling, binding, etc...\n        private static readonly DependencyProperty SortedColumnHeaderProperty =\n            DependencyProperty.RegisterAttached(\"SortedColumnHeader\", typeof(GridViewColumnHeader), typeof(GridViewSort), new UIPropertyMetadata(null));\n\n        #endregion\n\n        #region Column header click event handler\n\n        private static void ColumnHeader_Click(object sender, RoutedEventArgs e)\n        {\n            GridViewColumnHeader headerClicked = e.OriginalSource as GridViewColumnHeader;\n            if (headerClicked != null && headerClicked.Column != null)\n            {\n                string propertyName = GetPropertyName(headerClicked.Column);\n                if (!string.IsNullOrEmpty(propertyName))\n                {\n                    ListView listView = GetAncestor<ListView>(headerClicked);\n                    if (listView != null)\n                    {\n                        ICommand command = GetCommand(listView);\n                        if (command != null)\n                        {\n                            if (command.CanExecute(propertyName))\n                            {\n                                command.Execute(propertyName);\n                            }\n                        }\n                        else if (GetAutoSort(listView))\n                        {\n                            ApplySort(listView.Items, propertyName, listView, headerClicked);\n                        }\n                    }\n                }\n            }\n        }\n\n        #endregion\n\n        #region Helper methods\n\n        public static T GetAncestor<T>(DependencyObject reference) where T : DependencyObject\n        {\n            DependencyObject parent = VisualTreeHelper.GetParent(reference);\n            while (!(parent is T))\n            {\n                parent = VisualTreeHelper.GetParent(parent);\n            }\n            if (parent != null)\n                return (T)parent;\n            else\n                return null;\n        }\n\n        public static void ApplySort(ICollectionView view, string propertyName, ListView listView, GridViewColumnHeader sortedColumnHeader)\n        {\n            ListSortDirection direction = ListSortDirection.Ascending;\n            if (view.SortDescriptions.Count > 0)\n            {\n                SortDescription currentSort = view.SortDescriptions[0];\n                if (currentSort.PropertyName == propertyName)\n                {\n                    if (currentSort.Direction == ListSortDirection.Ascending)\n                        direction = ListSortDirection.Descending;\n                    else\n                        direction = ListSortDirection.Ascending;\n                }\n                view.SortDescriptions.Clear();\n\n                GridViewColumnHeader currentSortedColumnHeader = GetSortedColumnHeader(listView);\n                if (currentSortedColumnHeader != null)\n                {\n                    RemoveSortGlyph(currentSortedColumnHeader);\n                }\n            }\n            if (!string.IsNullOrEmpty(propertyName))\n            {\n                view.SortDescriptions.Add(new SortDescription(propertyName, direction));\n                if (GetShowSortGlyph(listView))\n                    AddSortGlyph(\n                        sortedColumnHeader,\n                        direction,\n                        direction == ListSortDirection.Ascending ? GetSortGlyphAscending(listView) : GetSortGlyphDescending(listView));\n                SetSortedColumnHeader(listView, sortedColumnHeader);\n               \n            }\n        }\n\n        public static void RemoveSort(ICollectionView view, ListView listView)\n        {\n            view.SortDescriptions.Clear();\n            GridViewColumnHeader currentSortedColumnHeader = GetSortedColumnHeader(listView);\n            if (currentSortedColumnHeader != null)\n            {\n                RemoveSortGlyph(currentSortedColumnHeader);\n            }\n        }\n\n        private static void AddSortGlyph(GridViewColumnHeader columnHeader, ListSortDirection direction, ImageSource sortGlyph)\n        {\n            AdornerLayer adornerLayer = AdornerLayer.GetAdornerLayer(columnHeader);\n            adornerLayer.Add(\n                new SortGlyphAdorner(\n                    columnHeader,\n                    direction,\n                    sortGlyph\n                    ));\n        }\n\n        private static void RemoveSortGlyph(GridViewColumnHeader columnHeader)\n        {\n            AdornerLayer adornerLayer = AdornerLayer.GetAdornerLayer(columnHeader);\n            Adorner[] adorners = adornerLayer.GetAdorners(columnHeader);\n            if (adorners != null)\n            {\n                foreach (Adorner adorner in adorners)\n                {\n                    if (adorner is SortGlyphAdorner)\n                        adornerLayer.Remove(adorner);\n                }\n            }\n        }\n\n        #endregion\n\n        #region SortGlyphAdorner nested class\n\n        private class SortGlyphAdorner : Adorner\n        {\n            private GridViewColumnHeader _columnHeader;\n            private ListSortDirection _direction;\n            private ImageSource _sortGlyph;\n\n            public SortGlyphAdorner(GridViewColumnHeader columnHeader, ListSortDirection direction, ImageSource sortGlyph)\n                : base(columnHeader)\n            {\n                _columnHeader = columnHeader;\n                _direction = direction;\n                _sortGlyph = sortGlyph;\n            }\n\n            private Geometry GetDefaultGlyph()\n            {\n                double x1 = _columnHeader.ActualWidth - 13;\n                double x2 = x1 + 10;\n                double x3 = x1 + 5;\n                double y1 = _columnHeader.ActualHeight / 2 - 3;\n                double y2 = y1 + 5;\n\n                if (_direction == ListSortDirection.Ascending)\n                {\n                    double tmp = y1;\n                    y1 = y2;\n                    y2 = tmp;\n                }\n\n                PathSegmentCollection pathSegmentCollection = new PathSegmentCollection();\n                pathSegmentCollection.Add(new LineSegment(new Point(x2, y1), true));\n                pathSegmentCollection.Add(new LineSegment(new Point(x3, y2), true));\n\n                PathFigure pathFigure = new PathFigure(\n                    new Point(x1, y1),\n                    pathSegmentCollection,\n                    true);\n\n                PathFigureCollection pathFigureCollection = new PathFigureCollection();\n                pathFigureCollection.Add(pathFigure);\n\n                PathGeometry pathGeometry = new PathGeometry(pathFigureCollection);\n                return pathGeometry;\n            }\n\n            protected override void OnRender(DrawingContext drawingContext)\n            {\n                base.OnRender(drawingContext);\n\n                if (_sortGlyph != null)\n                {\n                    double x = _columnHeader.ActualWidth - 13;\n                    double y = _columnHeader.ActualHeight / 2 - 5;\n                    Rect rect = new Rect(x, y, 10, 10);\n                    drawingContext.DrawImage(_sortGlyph, rect);\n                }\n                else\n                {\n                    drawingContext.DrawGeometry(Brushes.LightGray, new Pen(Brushes.Gray, 1.0), GetDefaultGlyph());\n                }\n            }\n        }\n\n        #endregion\n    }\n}\n"
  },
  {
    "path": "DependenciesGui/Helpers/RelayCommand.cs",
    "content": "﻿using System;\nusing System.Windows.Input;\nusing System.Diagnostics;\n\nnamespace Dependencies\n{\n    public class RelayCommand : ICommand\n    {\n        #region Fields \n        readonly Action<object> _execute;\n        readonly Predicate<object> _canExecute;\n        #endregion // Fields \n\n        #region Constructors \n        public RelayCommand(Action<object> execute) : this(execute, null) { }\n        public RelayCommand(Action<object> execute, Predicate<object> canExecute)\n        {\n            if (execute == null)\n                throw new ArgumentNullException(\"execute\");\n            _execute = execute; _canExecute = canExecute;\n        }\n        #endregion // Constructors \n\n        #region ICommand Members \n        [DebuggerStepThrough]\n        public bool CanExecute(object parameter)\n        {\n            return _canExecute == null ? true : _canExecute(parameter);\n        }\n        public event EventHandler CanExecuteChanged\n        {\n            add { CommandManager.RequerySuggested += value; }\n            remove { CommandManager.RequerySuggested -= value; }\n        }\n        public void Execute(object parameter) { _execute(parameter); }\n        #endregion // ICommand Members \n    }\n}\n"
  },
  {
    "path": "DependenciesGui/Helpers/SettingBindingHandler.cs",
    "content": "﻿using System.ComponentModel;\nusing System.Collections.Generic;\n\nnamespace Dependencies\n{\n    public class SettingBindingHandler : INotifyPropertyChanged\n    {\n        public delegate string CallbackEventHandler(bool settingValue);\n        public struct EventHandlerInfo\n        {\n            public string Property;\n            public string Settings;\n            public string MemberBindingName;\n            public CallbackEventHandler Handler;\n        }\n\n        public event PropertyChangedEventHandler PropertyChanged;\n        private List<EventHandlerInfo> Handlers;\n\n        public SettingBindingHandler()\n        {\n            Dependencies.Properties.Settings.Default.PropertyChanged += this.Handler_PropertyChanged;\n            Handlers = new List<EventHandlerInfo>();\n        }\n\n        public void AddNewEventHandler(string PropertyName, string SettingsName, string MemberBindingName, CallbackEventHandler Handler)\n        {\n            EventHandlerInfo info = new EventHandlerInfo();\n            info.Property = PropertyName;\n            info.Settings = SettingsName;\n            info.MemberBindingName = MemberBindingName;\n            info.Handler = Handler;\n\n            Handlers.Add(info);\n        }\n\n        public virtual void OnPropertyChanged(string propertyName)\n        {\n            PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));\n        }\n\n        private void Handler_PropertyChanged(object sender, PropertyChangedEventArgs e)\n        {\n            foreach (EventHandlerInfo Handler in Handlers.FindAll(x => x.Property == e.PropertyName))\n            {\n                Handler.Handler(((bool)Dependencies.Properties.Settings.Default[Handler.Settings]));\n                OnPropertyChanged(Handler.MemberBindingName);\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "DependenciesGui/MainWindow.xaml",
    "content": "﻿<Window x:Name=\"Dependencies\" x:Class=\"Dependencies.MainWindow\"\n        xmlns=\"http://schemas.microsoft.com/winfx/2006/xaml/presentation\"\n        xmlns:x=\"http://schemas.microsoft.com/winfx/2006/xaml\"\n        xmlns:d=\"http://schemas.microsoft.com/expression/blend/2008\"\n        xmlns:mc=\"http://schemas.openxmlformats.org/markup-compatibility/2006\"\n        xmlns:local=\"clr-namespace:Dependencies\"\n        xmlns:dragablz=\"clr-namespace:Dragablz;assembly=Dragablz\"\n        xmlns:dockablz=\"clr-namespace:Dragablz.Dockablz;assembly=Dragablz\"\n        xmlns:properties=\"clr-namespace:Dependencies.Properties\"\n        mc:Ignorable=\"d\"\n        \n        Title=\"Dependencies\" \n        Icon=\"Images/Dependencies_32px-no-blur.png\"\n        HorizontalContentAlignment=\"Stretch\" \n        VerticalContentAlignment=\"Bottom\"\n        VerticalAlignment=\"Bottom\"\n        Height=\"521\" Width=\"791\" \n        AllowDrop=\"True\"\n        Drop=\"MainWindow_Drop\"\n        >\n\n    <Window.CommandBindings>\n        <!--<CommandBinding Command=\"Exit\" Executed=\"ExitCommandBinding_Executed\"></CommandBinding>-->\n        <CommandBinding Command=\"Open\" Executed=\"OpenCommandBinding_Executed\"></CommandBinding>\n        <CommandBinding Command=\"Close\" Executed=\"ExitCommandBinding_Executed\"></CommandBinding>\n        <CommandBinding Command=\"local:MainWindow.OpenAboutCommand\" Executed=\"OpenAboutCommandBinding_Executed\" />\n        <CommandBinding Command=\"local:MainWindow.OpenUserSettingsCommand\" Executed=\"OpenUserSettingsCommandBinding_Executed\" />\n        <CommandBinding Command=\"local:MainWindow.OpenCustomizeSearchFolderCommand\" Executed=\"OpenCustomizeSearchFolderCommand_Executed\" />\n        <CommandBinding Command=\"Refresh\" Executed=\"RefreshCommandBinding_Executed\" />\n    </Window.CommandBindings>\n\n    <Window.InputBindings>\n        <KeyBinding Key=\"O\" Modifiers=\"Control\" Command=\"Open\"></KeyBinding>\n        <KeyBinding Key=\"Q\" Modifiers=\"Control\" Command=\"Close\"></KeyBinding>\n    </Window.InputBindings>\n\n    <Window.Resources>\n\n        <ResourceDictionary>\n\n            <!-- Hide/Show the status bar based on a global switch -->\n            <local:BooleanToVisibilityConverter x:Key=\"BooleanToVisibility\"/>\n\n            <!-- CustomHeader with middle click to close tab -->\n            <DataTemplate DataType=\"{x:Type local:CustomHeaderViewModel }\">\n                <local:DragablzCustomHeader />\n            </DataTemplate>\n\n            <dragablz:InterTabController  x:Key=\"DependenciesInterTabController\" x:Shared=\"False\"  Partition=\"2AE89D18-F236-4D20-9605-6C03319038E6\"/>\n\n            <Style TargetType=\"{x:Type dragablz:TabablzControl}\" x:Key=\"DependenciesTabControlStyle\">\n                <Setter Property=\"ShowDefaultCloseButton\" Value=\"True\" />\n                <Setter Property=\"ItemContainerStyle\" Value=\"{StaticResource TrapezoidDragableTabItemStyle}\" />\n                <Setter Property=\"HeaderMemberPath\" Value=\"Header\" />\n                <Setter Property=\"HeaderMemberPath\" Value=\"Header\" />\n                <Setter Property=\"InterTabController\" Value=\"{StaticResource InterTabController}\" />\n                <Setter Property=\"Margin\" Value=\"0 0 0 0\" />\n                <Setter Property=\"AdjacentHeaderItemOffset\" Value=\"-10\" />\n                <Setter Property=\"FixedHeaderCount\" Value=\"0\" />\n                <Setter Property=\"Background\" Value=\"#FF5C8F88\"/>\n            </Style>\n        </ResourceDictionary>\n\n    </Window.Resources>\n\n    <Grid x:Name=\"MainGrid\" Margin=\"0,0,0,0\" Background=\"#FF5C8F88\">\n        <Grid.RowDefinitions>\n            <RowDefinition Height=\"26\"/>\n            <RowDefinition Height=\"785*\"/>\n            <RowDefinition Height=\"Auto\"/>\n        </Grid.RowDefinitions>\n\n        <Menu x:Name=\"MainMenu\"  HorizontalContentAlignment=\"Stretch\" MinHeight=\"26\" Panel.ZIndex=\"1\" Grid.Row=\"0\" VerticalContentAlignment=\"Top\" VerticalAlignment=\"Top\">\n            \n            \n            <MenuItem x:Name=\"FileItem\" Header=\"_File\" Height=\"25\" Width=\"39\" VerticalAlignment=\"Top\" >\n                <MenuItem x:Name=\"OpenItem\" Header=\"_Open\" Height=\"25\" Command=\"Open\" InputGestureText=\"Ctrl+O\" />\n                <Separator Height=\"3\"/>\n                <MenuItem x:Name=\"RecentItems\" Header=\"Recent Items\" HorizontalAlignment=\"Left\" ItemsSource=\"{Binding  Path=RecentsItems}\">\n                    <MenuItem.ItemTemplate>\n                        <HierarchicalDataTemplate DataType=\"{x:Type local:RecentMenuItem}\" ItemsSource=\"{Binding  Path=RecentsItems}\">\n                            <TextBlock Text=\"{Binding Path=HeaderTitle}\"/>\n                        </HierarchicalDataTemplate>\n                    </MenuItem.ItemTemplate>\n                    <MenuItem.ItemContainerStyle>\n                        <Style TargetType=\"MenuItem\">\n                            <EventSetter Event=\"Click\" Handler=\"RecentFileCommandBinding_Clicked\"/>\n                        </Style>\n                    </MenuItem.ItemContainerStyle>\n                </MenuItem>\n\n                <Separator Height=\"3\" Margin=\"-1,0,0,0\" />\n                <MenuItem x:Name=\"ExitItem\" Header=\"E_xit\" Height=\"25\"  InputGestureText=\"Ctrl+Q\" Command=\"Close\" />\n            </MenuItem>\n            <MenuItem x:Name=\"ViewItem\" Header=\"_View\"  Height=\"25\" Width=\"42\">\n                <MenuItem x:Name=\"_SystemInformation\" Header=\"System Information ...\" Height=\"25\"  IsEnabled=\"False\" Margin=\"0\" HorizontalAlignment=\"Left\" HorizontalContentAlignment=\"Stretch\" />\n                <Separator Height=\"3\" Margin=\"0\"/>\n                <MenuItem x:Name=\"_FullPathItem\" Header=\"Full Paths\" Height=\"25\" InputGestureText=\"F9\" IsCheckable=\"True\" IsChecked=\"{Binding Source={x:Static properties:Settings.Default}, Path=FullPath, Mode=TwoWay}\" Margin=\"0,0,0.2,0\"/>\n                <MenuItem Header=\"_Undecorate C++ Functions\" Height=\"26\" InputGestureText=\"F10\" IsCheckable=\"True\" IsChecked=\"{Binding Source={x:Static properties:Settings.Default}, Path=Undecorate, Mode=TwoWay }\"/>\n                <Separator Height=\"3\" Margin=\"0\"/>\n                <MenuItem x:Name=\"_RefreshItem\" Header=\"_Refresh\" Height=\"25\" InputGestureText=\"F5\" IsEnabled=\"False\"/>\n                <Separator Height=\"3\" Margin=\"0\"/>\n                <MenuItem x:Name=\"_StatusBarItem\" Header=\"Status Bar\" Height=\"25\" IsCheckable=\"True\" Margin=\"0\" IsChecked=\"{Binding Source={x:Static properties:Settings.Default}, Path=ShowStatusBar, Mode=TwoWay}\"/>\n            </MenuItem>\n            <MenuItem x:Name=\"OptionsItem\" Header=\"_Options\" Height=\"25\" Width=\"54\">\n                <MenuItem x:Name=\"CustomizeSearchFoldersItem\" Header=\"_Customize search folders\" Height=\"25\" Margin=\"0\" Command=\"local:MainWindow.OpenCustomizeSearchFolderCommand\" IsEnabled=\"{Binding Path=DataContext.EnableSearchFolderCustomization, Source=OneWay}\"/>\n                <Separator Height=\"3\" Margin=\"0\"/>\n                <MenuItem x:Name=\"UserSettingsItem\" Header=\"_Properties\" Height=\"25\" Margin=\"0\" Command=\"local:MainWindow.OpenUserSettingsCommand\"/>\n            </MenuItem>\n            <MenuItem x:Name=\"HelpIem\" Header=\"_Help\" Height=\"25\" Width=\"49\">\n                <MenuItem x:Name=\"HelpAboutItem\" Header=\"About Dependencies\" Height=\"25\" Command=\"local:MainWindow.OpenAboutCommand\"/>\n            </MenuItem>\n        </Menu>\n\n        <Grid   Name=\"DefaultMessage\"\n                Grid.Row=\"1\" \n                Panel.ZIndex=\"1\"\n                HorizontalAlignment=\"Center\"\n                VerticalAlignment=\"Center\"\n              >\n            <Grid.ColumnDefinitions>\n                <ColumnDefinition Width=\"48\"/>\n                <ColumnDefinition Width=\"auto\"/>\n            </Grid.ColumnDefinitions>\n\n            <Image Source=\"Images/Dependencies_48px-no-blur.png\" Height=\"48\" Width=\"48\" Grid.Column=\"0\"/>\n            \n            \n            \n            <TextBlock Grid.Column=\"2\" \n                       TextWrapping=\"Wrap\"\n                       VerticalAlignment=\"Center\"\n                       Name=\"TextContent\"\n                       FontFamily=\"Courrier New\"\n                       FontSize=\"18\"\n                       Margin=\"20 0 0 00\"\n                       >\n                Analyze a new binary via \"File -> Open\" (Ctrl+O) <LineBreak/>\n                or simply by dragging it into the application.\n            </TextBlock>\n        </Grid>\n               \n        \n        <!-- dockablz:Layout is part of the main grid =>  Grid.Row=\"1\" -->\n        <!-- DependencyWindow does not support being a floating window => IsFloatDropZoneEnabled=\"False\" -->\n        <!-- all dragablz controls need to reference  Partition=\"2AE89D18-F236-4D20-9605-6C03319038E6\" in order to dock correctly -->\n        <dockablz:Layout Partition=\"2AE89D18-F236-4D20-9605-6C03319038E6\" Name=\"DependencyRootLayout\"\n                    IsFloatDropZoneEnabled=\"False\"\n                    FloatingItemHeaderMemberPath=\"Header\"\n                    Grid.Row=\"1\" d:IsHidden=\"True\">\n\n            <!-- branch template lets dragablz create a new tab control after a window is split via docking -->\n            <dockablz:Layout.BranchTemplate>\n                <DataTemplate>\n                    <dragablz:TabablzControl Style=\"{StaticResource DependenciesTabControlStyle}\" InterTabController=\"{StaticResource DependenciesInterTabController}\">\n                    </dragablz:TabablzControl>\n                </DataTemplate>\n            </dockablz:Layout.BranchTemplate>\n            \n            <!-- a root, named tab control is needed, so when a tab is torn and a new window is created, the new target tab control can be identified -->\n            <dragablz:TabablzControl x:Name=\"TabControl\"\n                                 Style=\"{StaticResource DependenciesTabControlStyle}\"\n                                 InterTabController=\"{StaticResource DependenciesInterTabController}\">\n        \n                \n                <!--<dragablz:TabablzControl.HeaderSuffixContent>\n                    <Grid x:Name=\"CustomHeaderContainerGrid\" \n                          Margin=\"0,2,2,0\">\n                        <Grid.Resources>\n                            <Style TargetType=\"{x:Type Button}\" BasedOn=\"{StaticResource StandardEmbeddedButtonStyle}\"></Style>\n                        </Grid.Resources>\n                        <Grid.ColumnDefinitions>\n                            <ColumnDefinition Width=\"Auto\" />\n                            <ColumnDefinition Width=\"*\" />\n                        </Grid.ColumnDefinitions>\n\n                        --><!-- a root, named tab control is needed, so when a tab is torn and a new window is created, the new target tab control can be identified --><!--\n                        <Button Style=\"{StaticResource AddItemCommandButtonStyle}\"\n                                    x:Name=\"AddButton\"\n                                    Grid.Column=\"0\"\n                                    Command=\"Open\"\n                                    />\n                    </Grid>\n                </dragablz:TabablzControl.HeaderSuffixContent>-->            \n           </dragablz:TabablzControl>\n\n\n        </dockablz:Layout>\n\n        <StatusBar x:Name=\"AppStatusBar\" \n                   HorizontalContentAlignment=\"Stretch\" \n                   VerticalContentAlignment=\"Bottom\" \n                   Grid.Row=\"2\" \n                   MinHeight=\"20\" \n                   Panel.ZIndex=\"1\" \n                   Margin=\"0\" \n                   VerticalAlignment=\"Bottom\" \n                   Visibility=\"{Binding Source={x:Static properties:Settings.Default}, Path=ShowStatusBar, Mode=OneWay, Converter={StaticResource BooleanToVisibility}}\"\n                   >\n            <StatusBarItem \n                x:Name=\"AppStatusBarMessage\">\n                \"Welcome to Dependencies !\"\n            </StatusBarItem>\n        </StatusBar>\n\n\n    </Grid>\n</Window>\n"
  },
  {
    "path": "DependenciesGui/MainWindow.xaml.cs",
    "content": "using System;\nusing System.IO;\nusing System.Windows;\nusing System.Windows.Input;\nusing System.Windows.Forms;\nusing System.Windows.Data;\n\nusing Dragablz;\nusing System.Windows.Shell;\nusing System.Globalization;\nusing System.Collections.ObjectModel;\nusing System.ComponentModel;\n\nnamespace Dependencies\n{\n    /// <summary>\n    /// We override the default Dragablz.IInterTabClient  in order to change\n    /// it's behaviour on closing all tabs.\n    /// </summary>\n    public class DependenciesInterTabClient : DefaultInterTabClient\n    {\n        /// <summary>\n        /// When closing all tabs on a particular MainWindow instances, we want\n        /// to know if it's okay to close the application also. the MainWindow created\n        /// by the \"App\" entry point is marked as \"master\" and is not closed,\n        /// whereas all the others are.\n        /// </summary>\n        public override TabEmptiedResponse TabEmptiedHandler(TabablzControl tabControl, Window window)\n        {\n            MainWindow main = window as MainWindow;\n            if (main.IsMaster)\n            {\n                //main.DefaultMessage.Visibility = Visibility.Visible;\n                return TabEmptiedResponse.DoNothing;\n            }\n                \n\n            return TabEmptiedResponse.CloseWindowOrLayoutBranch;\n        }\n    }\n\n    public class RecentMenuItem : INotifyPropertyChanged\n    {\n        public event PropertyChangedEventHandler PropertyChanged;\n\n        public RecentMenuItem(string _Filepath)\n        {\n            Filepath = _Filepath;\n\n            if (Properties.Settings.Default.FullPath)\n                HeaderTitle = Filepath;\n            else\n                HeaderTitle = System.IO.Path.GetFileName(Filepath);\n\n            Properties.Settings.Default.PropertyChanged += this.RecentMenuItem_PropertyChanged;\n        }\n\n        private void RecentMenuItem_PropertyChanged(object sender, PropertyChangedEventArgs e)\n        {\n            if (e.PropertyName == \"FullPath\")\n            {\n                if (Properties.Settings.Default.FullPath)\n                    HeaderTitle = Filepath;\n                else\n                    HeaderTitle = System.IO.Path.GetFileName(Filepath);\n\n                if (PropertyChanged != null)\n                {\n                    PropertyChanged(this, new PropertyChangedEventArgs(\"HeaderTitle\"));\n                }\n            }\n        }\n\n        public string Filepath {get; set;}\n\n        public string HeaderTitle { get; set; }\n\n    }\n\n    /// <summary>\n    /// MainWindow : container for displaying one or sereral DependencyWindow tree elements.\n    /// </summary>\n    public partial class MainWindow : Window\n    {\n        public static readonly RoutedUICommand OpenAboutCommand = new RoutedUICommand();\n        public static readonly RoutedUICommand OpenUserSettingsCommand = new RoutedUICommand();\n\t\tpublic static readonly RoutedUICommand OpenCustomizeSearchFolderCommand = new RoutedUICommand();\n\n        public ObservableCollection<RecentMenuItem> _recentsItems;\n\n        private readonly IInterTabClient _interTabClient = new DependenciesInterTabClient();\n\n        private About AboutPage;\n        private UserSettings UserSettings;\n\t\tprivate SearchFolder SearchFolder;\n\n        private bool _Master;\n\t\tprivate bool _EnableSearchFolderCustomization;\n\n\n        #region PublicAPI\n        public MainWindow()\n        {\n\n            InitializeComponent();\n\n            _recentsItems = new ObservableCollection<RecentMenuItem>();\n            PopulateRecentFilesMenuItems();\n\n            this.AboutPage = new About();\n            this.UserSettings = new UserSettings();\n\t\t\tthis.SearchFolder = null;\n\n\t\t\t// TODO : understand how to reliably bind in xaml\n\t\t\tthis.TabControl.InterTabController.InterTabClient = DoNothingInterTabClient;\n            this.TabControl.IsEmptyChanged += MainWindow_TabControlIsEmptyHandler;\n\n            this._Master = false;\n\t\t\tthis.DataContext = this;\n        }\n\n        public ObservableCollection<RecentMenuItem> RecentsItems\n        {\n            get\n            {\n                return _recentsItems;\n            }\n        }\n\n        /// <summary>\n        /// Open a new depedency tree window on a given PE.\n        /// </summary>\n        /// <param name=\"Filename\">File path to a PE to process.</param>\n        public void OpenNewDependencyWindow(String Filename)\n        {\n            var newDependencyWindow = new DependencyWindow(Filename);\n            newDependencyWindow.Header = new CustomHeaderViewModel { Header = Path.GetFileNameWithoutExtension(Filename) };\n\n            this.TabControl.AddToSource(newDependencyWindow);\n            this.TabControl.SelectedItem = newDependencyWindow;\n\n            // Update recent files entries\n            App.AddToRecentDocuments(Filename);\n            PopulateRecentFilesMenuItems();\n        }\n\n        /// <summary>\n        /// We override the default Dragablz.IInterTabClient  in order to change\n        /// it's behaviour on closing all tabs.\n        /// </summary>\n        public IInterTabClient DoNothingInterTabClient\n        {\n            get { return _interTabClient; }\n        }\n\n\t\t\n\t\tpublic bool EnableSearchFolderCustomization\n\t\t{\n\t\t\t// find a way to update the toggle based on the number of window opened without relying on\n\t\t\t// creating a custom IsEnabledChanged event\n\t\t\tget { return true;/*this.TabControl.SelectedItem != null;*/ }\n\t\t}\n\n\t\t/// <summary>\n\t\t/// When closing all tabs on a particular MainWindow instances, we want\n\t\t/// to know if it's okay to close the application also. the MainWindow created\n\t\t/// by the \"App\" entry point is marked as \"master\" and is not closed,\n\t\t/// whereas all the others are.\n\t\t/// </summary>\n\t\tpublic bool IsMaster\n        {\n            get { return _Master; }\n            set { _Master = value; }\n        }\n\n\n        #endregion PublicAPI\n\n        /// <summary>\n        /// Populate \"recent entries\" menu items\n        /// </summary>\n        public void PopulateRecentFilesMenuItems()\n        {\n\n            //System.Windows.Controls.MenuItem FileMenuItem = (System.Windows.Controls.MenuItem)this.MainMenu.Items[0];\n            \n\n            if (Properties.Settings.Default.RecentFiles.Count == 0) {\n                return;\n            }\n\n\n            foreach (var RecentFilePath in Properties.Settings.Default.RecentFiles)\n            {\n                // Ignore empty dummy entries\n                if (String.IsNullOrEmpty(RecentFilePath))\n                {\n                    continue;\n                }\n\n                AddRecentFilesMenuItem(RecentFilePath, Properties.Settings.Default.RecentFiles.IndexOf(RecentFilePath));\n            }\n        }\n\n\n        private void AddRecentFilesMenuItem(string Filepath, int index)\n        {\n\n            //System.Windows.Controls.MenuItem FileMenuItem = (System.Windows.Controls.MenuItem)this.MainMenu.Items[0];\n\n            // Create new menu item\n            //System.Windows.Controls.MenuItem newRecentFileItem = new System.Windows.Controls.MenuItem();\n            //newRecentFileItem.DataContext = Filepath;\n            //newRecentFileItem.Click += new RoutedEventHandler(RecentFileCommandBinding_Clicked);\n            //newRecentFileItem.Style = \"FullpathStyle\";\n\n            //RecentsItems.Add(new RecentMenuItem {\n            //    MenuItemName = \"Edit\"\n            //});\n            //RecentsItems.Add(\n            //    new RecentMenuItem{\n            //        MenuItemName = \"Search\"\n            //    }\n            //);\n\n            RecentsItems.Add(new RecentMenuItem(Filepath));\n            \n\n\n\n            //// check if the item already is in the list, diregarding others menu items\n            //if (index + 5 < FileMenuItem.Items.Count)\n            //{\n            //    FileMenuItem.Items[3 + index] = newRecentFileItem;\n            //}\n            //else\n            //{\n            //    // Add it to the list at the top\n            //    FileMenuItem.Items.Insert(3, newRecentFileItem);\n            //}\n\n        }\n\n        #region Commands\n        private void RecentFileCommandBinding_Clicked(object sender, RoutedEventArgs e)\n        {\n            System.Windows.Controls.MenuItem RecentFile = sender as System.Windows.Controls.MenuItem;\n            String RecentFilePath = (RecentFile.DataContext as RecentMenuItem).Filepath;\n\n            if (RecentFilePath.Length != 0 )\n            {\n                OpenNewDependencyWindow(RecentFilePath);\n            }\n\n        }\n\n        private void OpenCommandBinding_Executed(object sender, RoutedEventArgs e)\n        {\n            OpenFileDialog InputFileNameDlg = new OpenFileDialog\n            {\n                Filter = \"exe files (*.exe, *.dll)| *.exe;*.dll; | All files (*.*)|*.*\",\n                FilterIndex = 0,\n                RestoreDirectory = true,\n                \n            };\n            \n\n            if (InputFileNameDlg.ShowDialog() != System.Windows.Forms.DialogResult.OK)\n                return;\n\n            OpenNewDependencyWindow(InputFileNameDlg.FileName);\n\n        }\n\n        private void ExitCommandBinding_Executed(object sender, RoutedEventArgs e)\n        {\n            System.Windows.Application.Current.Shutdown();\n        }\n\n        private void OpenAboutCommandBinding_Executed(object sender, RoutedEventArgs e)\n        {\n            this.AboutPage.Close();\n            this.AboutPage = new About();\n            this.AboutPage.Show();\n        }\n\n        private void OpenUserSettingsCommandBinding_Executed(object sender, RoutedEventArgs e)\n        {\n            this.UserSettings.Close();\n            this.UserSettings = new UserSettings();\n            this.UserSettings.Owner = this;\n            this.UserSettings.Show();\n        }\n\n\t\tprivate void OpenCustomizeSearchFolderCommand_Executed(object sender, RoutedEventArgs e)\n\t\t{\n\t\t\tDependencyWindow SelectedItem = this.TabControl.SelectedItem as DependencyWindow;\n\t\t\tif (SelectedItem == null)\n\t\t\t\treturn;\n\n\t\t\tif (this.SearchFolder != null)\n\t\t\t{\n\t\t\t\tthis.SearchFolder.Close();\n\t\t\t}\n\t\t\t\n\t\t\tthis.SearchFolder = new SearchFolder(SelectedItem);\n\t\t\tthis.SearchFolder.Show();\n\t\t}\n\n\n\t\tprivate void RefreshCommandBinding_Executed(object sender, RoutedEventArgs e)\n        {\n\t\t\tDependencyWindow SelectedItem = this.TabControl.SelectedItem as DependencyWindow;\n\t\t\tif (SelectedItem == null)\n\t\t\t\treturn;\n\n\t\t\tSelectedItem.InitializeView();\n        }\n        #endregion Commands\n\n        #region EventsHandler\n\n        /// <summary>\n        /// Application.Close event handler. Save user settings and close every child windows.\n        /// </summary>\n        protected override void OnClosing(System.ComponentModel.CancelEventArgs e)\n        {\n            this.UserSettings.Close();\n            this.AboutPage.Close();\n\n\t\t\tif (this.SearchFolder!= null)\n\t\t\t{\n\t\t\t\tthis.SearchFolder.Close();\n\t\t\t}\n\t\t\t\n\n\n\t\t\tbase.OnClosing(e);\n        }\n\n        /// <summary>\n        /// file drag-and-drop event handler.\n        /// </summary>\n        private void MainWindow_Drop(object sender, System.Windows.DragEventArgs e)\n        {\n            if (e.Data.GetDataPresent(System.Windows.Forms.DataFormats.FileDrop))\n            {\n                string[] files = (string[])e.Data.GetData(System.Windows.Forms.DataFormats.FileDrop);\n                \n                foreach (var file in files)\n                {\n                    OpenNewDependencyWindow(file);\n                }\n            }\n        }\n\n        private void MainWindow_TabControlIsEmptyHandler(object sender, RoutedPropertyChangedEventArgs<bool> e)\n        {\n            this.DefaultMessage.Visibility = (e.NewValue) ? Visibility.Visible : Visibility.Hidden;\n            this._RefreshItem.IsEnabled = !e.NewValue;\n        }\n        #endregion EventsHandler\n    }\n\n    /// <summary>\n    /// Converter to transform a boolean into a Visibility settings. \n    /// Why is this not part of the WPF standard lib ? Everybody ends up coding one in every project.\n    /// </summary>\n    public class BooleanToVisibilityConverter : IValueConverter\n    {\n        public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)\n        {\n            Boolean SettingValue = (Boolean) value;\n\n            if (SettingValue)\n                return Visibility.Visible;\n\n            return Visibility.Collapsed;\n\n        }\n\n        public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)\n        {\n            throw new NotImplementedException();\n        }\n    }\n}"
  },
  {
    "path": "DependenciesGui/Models/ModuleInfo.cs",
    "content": "using System;\nusing System.Collections.Generic;\nusing System.Windows.Forms;\nusing System.Diagnostics;\nusing System.IO;\nusing System.ComponentModel;\n\nusing Dependencies.ClrPh;\n\n[Flags]\npublic enum PeTypes\n{\n    None = 0,\n    IMAGE_FILE_EXECUTABLE_IMAGE = 0x02,\n    IMAGE_FILE_DLL = 0x2000,\n}\n\n[Flags]\npublic enum ModuleFlag\n{\n    NoFlag = 0x00,\n\n    DelayLoad = 0x01,\n    ClrReference = 0x02,\n    ApiSet = 0x04,\n\tApiSetExt = 0x08,\n\tNotFound = 0x10,\n    MissingImports = 0x20,\n    ChildrenError = 0x40,\n}\n\nnamespace Dependencies\n{\n\n    public struct ModuleInfo\n    {\n        // @TODO(Hack: refactor correctly for image generation)\n        // public TreeViewItemContext context;\n\n        public Int16 Machine;\n        public Int16 Magic;\n\n        public UInt64 ImageBase;\n        public Int32 SizeOfImage;\n        public UInt64 EntryPoint;\n\n\n        public Int32 Checksum;\n        public Boolean CorrectChecksum;\n\n        public Int16 Subsystem;\n        public Tuple<Int16, Int16> SubsystemVersion;\n\n        public Int16 Characteristics;\n        public Int16 DllCharacteristics;\n\n        public UInt64 Filesize;\n    }\n\n\tpublic class ApiSetNotFoundModuleInfo : NotFoundModuleInfo\n\t{\n\t\tpublic ApiSetNotFoundModuleInfo(string ApiSetModuleName, string NotFoundHostModule)\n\t\t:base(ApiSetModuleName)\n\t\t{\n\t\t\t_HostName = NotFoundHostModule;\n\n\t\t\t_Flags |= ModuleFlag.ApiSet;\n\t\t\t_Flags |= ModuleFlag.NotFound;\n\t\t\tif (ApiSetModuleName.StartsWith(\"ext-\"))\n\t\t\t{\n\t\t\t\t_Flags |= ModuleFlag.ApiSetExt;\n\t\t\t}\n\t\t}\n\n\t\tpublic override string ModuleName { get { return String.Format(\"{0:s} -> {1:s}\", this._Name, _HostName); } }\n\n\t\tprivate string _HostName;\n\t}\n\n\tpublic class NotFoundModuleInfo : DisplayModuleInfo\n    {\n        public NotFoundModuleInfo(string NotFoundModuleName)\n        : base(NotFoundModuleName)\n        {\n\t\t\t_Flags |= ModuleFlag.NotFound;\n        }\n\n        public override string Filepath { get { return _Name; } }\n        public override List<PeImportDll> Imports { get { return new List<PeImportDll>(); } }\n        public override List<PeExport> Exports { get { return new List<PeExport>(); } }\n\n        public override string Cpu { get { return null; } }\n        public override string Type { get { return null; } }\n        public override UInt64? Filesize { get { return null; } }\n        public override UInt64? ImageBase { get { return null; } }\n        public override int? VirtualSize { get { return null; } }\n        public override UInt64? EntryPoint { get { return null; } }\n        public override int? Subsystem { get { return null; } }\n        public override string SubsystemVersion { get { return null; } }\n        public override int? Checksum { get { return null; } }\n        public override bool? CorrectChecksum { get { return null; } }\n        public override ModuleSearchStrategy Location { get { return ModuleSearchStrategy.NOT_FOUND; } }\n\n    }\n\n\n    public class ApiSetModuleInfo : DisplayModuleInfo\n    {\n        public ApiSetModuleInfo(string ApiSetModuleName, ref DisplayModuleInfo _UnderlyingModule)\n        : base(ApiSetModuleName)\n        {\n            UnderlyingModule = _UnderlyingModule;\n\n            _Flags = _UnderlyingModule.Flags;\n            _Flags |= ModuleFlag.ApiSet;\n            if (ApiSetModuleName.StartsWith(\"ext-\"))\n            {\n                _Flags |= ModuleFlag.ApiSetExt;\n            }\n        }\n\n        public override string ModuleName { get { return String.Format(\"{0:s} -> {1:s}\", this._Name, UnderlyingModule.ModuleName);}}\n        public override string Filepath { get { return UnderlyingModule.Filepath; } }\n\n        public override List<PeImportDll> Imports { get { return UnderlyingModule.Imports; } }\n        public override List<PeExport> Exports { get { return UnderlyingModule.Exports; } }\n\n\n        public override string Cpu { get { return UnderlyingModule.Cpu; } }\n        public override string Type { get { return UnderlyingModule.Type; } }\n        public override UInt64? Filesize { get { return UnderlyingModule.Filesize; } }\n        public override UInt64? ImageBase { get { return UnderlyingModule.ImageBase; } }\n        public override int? VirtualSize { get { return UnderlyingModule.VirtualSize; } }\n        public override UInt64? EntryPoint { get { return UnderlyingModule.EntryPoint; } }\n        public override int? Subsystem { get { return UnderlyingModule.Subsystem; } }\n        public override string SubsystemVersion { get { return UnderlyingModule.SubsystemVersion; } }\n        public override int? Checksum { get { return UnderlyingModule.Checksum; } }\n        public override bool? CorrectChecksum { get { return UnderlyingModule.CorrectChecksum; } }\n        public override ModuleSearchStrategy Location { get { return ModuleSearchStrategy.ApiSetSchema; } }\n\n        /// <summary>\n        /// The pointed module which actually does implement the api set contract\n        /// TODO : there might be more than one contract modules ?\n        /// </summary>\n        private DisplayModuleInfo UnderlyingModule;\n    }\n\n    public class DisplayModuleInfo : SettingBindingHandler, INotifyPropertyChanged\n    {\n        #region Constructors \n        public DisplayModuleInfo(string ModuleName)\n        {\n\n\t\t\t_Name = ModuleName;\n            _Filepath = null;\n            _Flags = 0;\n\n            AddNewEventHandler(\"FullPath\", \"FullPath\", \"ModuleName\", this.GetPathDisplayName);\n        }\n\n        public DisplayModuleInfo(string ModuleName, PE Pe, ModuleSearchStrategy Location, ModuleFlag Flags = 0)\n        {\n\n\n\t\t\t_Name = ModuleName;\n            _Filepath = Pe.Filepath;\n            _Flags = Flags;\n            \n            \n            // Do not set this variables in order to \n            // lessen memory allocations\n            _Imports = null;\n            _Exports = null;\n            _Location = Location;\n\n            _Info = new ModuleInfo()\n            {\n\n                Machine = Pe.Properties.Machine,\n                Magic = Pe.Properties.Magic,\n                Filesize = Pe.Properties.FileSize,\n\n                ImageBase = (UInt64)Pe.Properties.ImageBase,\n                SizeOfImage = Pe.Properties.SizeOfImage,\n                EntryPoint = (UInt64)Pe.Properties.EntryPoint,\n\n                Checksum = Pe.Properties.Checksum,\n                CorrectChecksum = Pe.Properties.CorrectChecksum,\n\n                Subsystem = Pe.Properties.Subsystem,\n                SubsystemVersion = Pe.Properties.SubsystemVersion,\n\n                Characteristics = Pe.Properties.Characteristics,\n                DllCharacteristics = Pe.Properties.DllCharacteristics,\n            };\n\n            AddNewEventHandler(\"FullPath\", \"FullPath\", \"ModuleName\", this.GetPathDisplayName);\n        }\n        #endregion // Constructors \n\n\n\n        #region PublicAPI\n        public virtual string ModuleName\n        {\n            get { return GetPathDisplayName(Dependencies.Properties.Settings.Default.FullPath); }\n        }\n\n        public virtual string Filepath {\n            get { return _Filepath; }\n        }\n\n        public virtual bool DelayLoad\n        {\n            get { return (_Flags & ModuleFlag.DelayLoad) != 0;  }\n        }\n\n        public virtual ModuleFlag Flags\n        {\n            get { return _Flags; }\n            set { _Flags = value; }\n        }\n\n        public virtual List<PeImportDll> Imports\n        {\n            get { \n            \n                if (_Imports == null) {\n                    _Imports = (System.Windows.Application.Current as App).LoadBinary(Filepath).GetImports();\n                }\n            \n                return _Imports;  \n            }\n        }\n\n        public virtual List<PeExport> Exports\n        {\n            get { \n            \n                if (_Exports == null) {\n                    _Exports = (System.Windows.Application.Current as App).LoadBinary(Filepath).GetExports();\n                }\n\n                return _Exports;\n            }\n        }\n\n\n        protected string GetPathDisplayName(bool FullPath)\n        {\n            if ((FullPath) && (_Filepath != null))\n                return _Filepath;\n\n            return _Name;\n        }\n\n    \n        public virtual string Cpu\n        {\n            get\n            {\n                int machine_id = _Info.Machine & 0xffff;\n                switch (machine_id)\n                {\n                    case 0x014c: /*IMAGE_FILE_MACHINE_I386*/\n                        return \"i386\";\n\n                    case 0x8664: /*IMAGE_FILE_MACHINE_AMD64*/\n                        return \"AMD64\";\n\n                    case 0x0200:/*IMAGE_FILE_MACHINE_IA64*/\n                        return \"IA64\";\n\n                    case 0x01c4:/*IMAGE_FILE_MACHINE_ARMNT*/\n                        return \"ARM Thumb-2\";\n\n                    case 0xAA64:/*IMAGE_FILE_MACHINE_ARM64*/\n                        return \"ARM64\";\n\n                    default:\n                        return \"Unknown\";\n                }\n            }\n        }\n\n        public virtual string Type\n        {\n            get\n            {\n                List<String> TypeList = new List<String>();\n                PeTypes Type = (PeTypes)_Info.Characteristics;\n\n                if ((Type & PeTypes.IMAGE_FILE_DLL) != PeTypes.None)/* IMAGE_FILE_DLL */\n                    TypeList.Add(\"Dll\");\n\n                if ((Type & PeTypes.IMAGE_FILE_EXECUTABLE_IMAGE) != PeTypes.None) /* IMAGE_FILE_EXECUTABLE_IMAGE */\n                    TypeList.Add(\"Executable\");\n\n\n\n                return String.Join(\"; \", TypeList.ToArray());\n            }\n        }\n\n\t\tpublic bool HasErrors\n\t\t{\n\t\t\tget\n\t\t\t{\n\t\t\t\treturn _ErrorImport;\n\t\t\t}\n\t\t\tset\n\t\t\t{\n\t\t\t\t_ErrorImport = value;\n                OnPropertyChanged(\"HasErrors\");\n\n            }\n\t\t}\n\n\n        public virtual UInt64? Filesize { get { return _Info.Filesize; } }\n        public virtual UInt64? ImageBase { get { return _Info.ImageBase; } }\n        public virtual int? VirtualSize { get { return _Info.SizeOfImage; } }\n        public virtual UInt64? EntryPoint { get { return _Info.EntryPoint; } }\n        public virtual int? Subsystem { get { return _Info.Subsystem; } }\n        public virtual string SubsystemVersion { get { return String.Format(\"{0:d}.{1:d}\" , _Info.SubsystemVersion.Item1, _Info.SubsystemVersion.Item2); } }\n        public virtual int? Checksum { get { return _Info.Checksum; } }\n        public virtual bool? CorrectChecksum { get { return _Info.CorrectChecksum; } }\n        public virtual ModuleSearchStrategy Location { get { return _Location; } }\n\n        public string Status\n        {\n            get\n            {\n                if ((this.Flags & ModuleFlag.NotFound) != 0)\n                {\n                    return String.Format(\"{0:s} module could not be found on disk\", this.Filepath);\n                }\n\n                if ((this.Flags & ModuleFlag.MissingImports) != 0)\n                {\n                    return String.Format(\"{0:s} module has missing imports\", this.Filepath);\n                }\n\n                if ((this.Flags & ModuleFlag.DelayLoad) != 0)\n                {\n                    return String.Format(\"{0:s} module is delay-load\", this.Filepath);\n                }\n\n                if ((this.Flags & ModuleFlag.ChildrenError) != 0)\n                {\n                    return String.Format(\"{0:s} module has an erroneous child module\", this.Filepath);\n                }\n\n                return String.Format(\"{0:s} module loaded correctly\", this.Filepath); ;\n            }\n        }\n\n\n        #endregion PublicAPI\n\n\n\n        #region Commands \n        private RelayCommand _DoFindModuleInTreeCommand;\n        private RelayCommand _ConfigureSearchOrderCommand;\n\n        public RelayCommand DoFindModuleInTreeCommand\n        {\n            get { return _DoFindModuleInTreeCommand; }\n            set { _DoFindModuleInTreeCommand = value; }\n        }\n\n        public RelayCommand ConfigureSearchOrderCommand\n        {\n            get { return _ConfigureSearchOrderCommand; }\n            set { _ConfigureSearchOrderCommand = value; }\n        }\n\n\n        public RelayCommand OpenPeviewerCommand\n        {\n            get\n            {\n                if (_OpenPeviewerCommand == null)\n                {\n                    _OpenPeviewerCommand = new RelayCommand((param) => this.OpenPeviewer((object)param));\n                }\n\n                return _OpenPeviewerCommand;\n            }\n        }\n\n        public bool OpenPeviewer(object Module)\n        {\n            string programPath = Dependencies.Properties.Settings.Default.PeViewerPath;\n            Process PeviewerProcess = new Process();\n        \n            if ((Module == null))\n            {\n                return false;\n            }\n\n            if (!File.Exists(programPath))\n            {\n                MessageBox.Show(\"peview.exe file could not be found !\");\n                return false;\n            }\n\n            string Filepath = (Module as DisplayModuleInfo).GetPathDisplayName(true);\n            if (Filepath == null)\n            {\n                return false;\n            }\n\n            PeviewerProcess.StartInfo.FileName = programPath;\n            PeviewerProcess.StartInfo.Arguments = Filepath;\n            return PeviewerProcess.Start();\n        }\n\n        public RelayCommand OpenNewAppCommand\n        {\n            get\n            {\n                if (_OpenPeviewerCommand == null)\n                {\n                    _OpenNewAppCommand = new RelayCommand((param) =>\n                    {\n                        string Filepath = (param as DisplayModuleInfo).GetPathDisplayName(true);\n                        if (Filepath == null)\n                        {\n                            return;\n                        }\n\n                        Process OtherDependenciesProcess = new Process();\n                        OtherDependenciesProcess.StartInfo.FileName = Application.ExecutablePath;\n                        OtherDependenciesProcess.StartInfo.Arguments = Filepath;\n                        OtherDependenciesProcess.Start();\n                    });\n                }\n\n                return _OpenNewAppCommand;\n            }\n        }\n\n        public RelayCommand CopyValue\n        {\n            get\n            {\n                if (_CopyValue == null)\n                {\n                    _CopyValue = new RelayCommand((param) =>\n                    {\n\n                        if ((param == null))\n                        {\n                            return;\n                        }\n\n                        Clipboard.Clear();\n\n                        try\n                        {\n\n                            Clipboard.SetText((string)param, TextDataFormat.Text);\n                        }\n                        catch { }\n                    });\n                }\n\n                return _CopyValue;\n            }\n        }\n        #endregion // Commands \n\n\n        /// <summary>\n        /// Name : string to identify the module.\n        /// This is the only \"mandatory\" data, the rest can be private.\n        /// </summary>\n        public string _Name;\n        protected string _Filepath;\n        protected ModuleFlag _Flags;\n\n        private ModuleInfo _Info;\n        private ModuleSearchStrategy _Location;\n        private List<PeImportDll> _Imports;\n        private List<PeExport> _Exports;\n\t\tprivate bool _ErrorImport;\n\n\n        private RelayCommand _OpenPeviewerCommand;\n        private RelayCommand _OpenNewAppCommand;\n        private RelayCommand _CopyValue;\n    }\n}"
  },
  {
    "path": "DependenciesGui/Models/PeExport.cs",
    "content": "using System;\r\nusing System.Diagnostics;\r\nusing System.Windows;\r\nusing System.Collections.Generic;\r\n\r\nusing Dependencies;\r\nusing Dependencies.ClrPh;\r\n\r\npublic class DisplayPeExport : SettingBindingHandler\r\n{\r\n    # region Constructors\r\n    public DisplayPeExport(\r\n        PeExport PeExport,\r\n        PhSymbolProvider SymPrv\r\n    )\r\n    {\r\n        PeInfo.ordinal = (ushort) PeExport.Ordinal;\r\n        //PeInfo.hint = (ushort) (/*PeExport.Hint*/ PeExport.Ordinal - 1); // @TODO(add hints to exports)\r\n        PeInfo.name = PeExport.Name;\r\n        PeInfo.ForwardName = PeExport.ForwardedName;\r\n        PeInfo.exportByOrdinal = PeExport.ExportByOrdinal;\r\n        PeInfo.forwardedExport = PeExport.ForwardedName.Length > 0;\r\n        PeInfo.exportAsCppName = (PeExport.Name.Length > 0 && PeExport.Name[0] == '?');\r\n        PeInfo.virtualAddress = PeExport.VirtualAddress;\r\n        \r\n\r\n        Tuple<CLRPH_DEMANGLER, string> DemanglingInfos = SymPrv.UndecorateName(PeExport.Name);\r\n        PeInfo.Demangler = Enum.GetName(typeof(CLRPH_DEMANGLER), DemanglingInfos.Item1);\r\n        PeInfo.UndecoratedName = DemanglingInfos.Item2;\r\n\r\n        AddNewEventHandler(\"Undecorate\", \"Undecorate\", \"Name\", this.GetDisplayName);\r\n    }\r\n\t#endregion Constructors\r\n\r\n\t#region PublicAPI\r\n\tpublic override string ToString()\r\n\t{\r\n\t\tList<string> members = new List<string>() {\r\n\t\t\tString.Format(\"{0} (0x{0:x04})\", Ordinal),\r\n\t\t\tHint != 0 ? String.Format(\"{0} (0x{0:x08})\", Hint) : \"N/A\",\r\n\t\t\tName,\r\n\t\t\tVirtualAddress,\r\n\t\t\tDemangler\r\n\t\t};\r\n\r\n\t\treturn String.Join(\", \", members.ToArray());\r\n\t}\r\n\r\n\tpublic string IconUri\r\n    {\r\n        get\r\n        {\r\n            if (PeInfo.forwardedExport)\r\n                return \"Images/export_forward.png\";\r\n            if (PeInfo.exportByOrdinal)\r\n                return \"Images/export_ord.png\";\r\n            if (PeInfo.exportAsCppName)\r\n                return \"Images/export_cpp.png\";\r\n            \r\n            return \"Images/export_C.png\";\r\n        }\r\n    }\r\n\r\n    public int Type\r\n    {\r\n        get\r\n        {\r\n            if (PeInfo.forwardedExport)\r\n                return 1;\r\n            if (PeInfo.exportByOrdinal)\r\n                return 2;\r\n            if (PeInfo.exportAsCppName)\r\n                return 3;\r\n\r\n            return 0;\r\n        }\r\n    }\r\n    public ushort ? Hint\r\n    {\r\n        get\r\n        {\r\n            return null;\r\n        }\r\n    }\r\n\r\n    public ushort Ordinal { get { return PeInfo.ordinal; } }\r\n\r\n    public string Name\r\n    {\r\n        get { return GetDisplayName(Dependencies.Properties.Settings.Default.Undecorate); }\r\n    }\r\n\r\n    public string VirtualAddress\r\n    {\r\n        get\r\n        {\r\n            if (PeInfo.forwardedExport)\r\n                return PeInfo.ForwardName;\r\n            return String.Format(\"0x{0:x8}\", PeInfo.virtualAddress);\r\n        }\r\n    }\r\n\r\n    public string Demangler { get { return PeInfo.Demangler; } }\r\n\r\n    protected string GetDisplayName(bool Undecorate)\r\n    { \r\n        if (PeInfo.exportByOrdinal)\r\n            return String.Format(\"Ordinal_{0:d}\", PeInfo.ordinal);\r\n\r\n\r\n        if ((Undecorate) && (PeInfo.UndecoratedName.Length > 0))\r\n            return PeInfo.UndecoratedName;\r\n\r\n        return PeInfo.name;\r\n        \r\n    }\r\n    # endregion PublicAPI\r\n\r\n    #region Commands \r\n    public RelayCommand QueryExportApi\r\n    {\r\n        get\r\n        {\r\n            if (_QueryExportApi == null)\r\n            {\r\n                _QueryExportApi = new RelayCommand((param) =>\r\n                {\r\n                    if ((param == null))\r\n                    {\r\n                        return;\r\n                    }\r\n\r\n                    string ExportName = (param as DisplayPeExport).Name;\r\n                    if (ExportName == null)\r\n                    {\r\n                        return;\r\n                    }\r\n\r\n                    Process.Start(@\"https://docs.microsoft.com/search/?search=\" + ExportName);\r\n                });\r\n            }\r\n\r\n            return _QueryExportApi;\r\n        }\r\n    }\r\n    public RelayCommand CopyValue\r\n    {\r\n        get\r\n        {\r\n            if (_CopyValue == null)\r\n            {\r\n                _CopyValue = new RelayCommand((param) =>\r\n                {\r\n\r\n                    if ((param == null))\r\n                    {\r\n                        return;\r\n                    }\r\n\r\n                    Clipboard.Clear();\r\n\r\n                    try\r\n                    {\r\n                        \r\n                        Clipboard.SetText((string)param, TextDataFormat.Text);\r\n                    } catch { }\r\n\r\n                });\r\n            }\r\n\r\n            return _CopyValue;\r\n        }\r\n    }\r\n\r\n    #endregion // Commands \r\n\r\n\r\n    private PeExportInfo PeInfo;\r\n    private RelayCommand _QueryExportApi;\r\n    private RelayCommand _CopyValue;\r\n}\r\n\r\npublic struct PeExportInfo\r\n{\r\n    public Boolean exportByOrdinal;\r\n    public Boolean exportAsCppName;\r\n    public Boolean forwardedExport;\r\n    public ushort ordinal;\r\n    //public ushort hint;\r\n    public long virtualAddress;\r\n    public string name;\r\n    public string ForwardName;\r\n    public string UndecoratedName;\r\n    public string Demangler;\r\n}"
  },
  {
    "path": "DependenciesGui/Models/PeImport.cs",
    "content": "using System;\nusing System.Diagnostics;\nusing System.Windows;\nusing System.Collections.Generic;\n\nusing Dependencies;\nusing Dependencies.ClrPh;\n\npublic class DisplayPeImport : SettingBindingHandler\n{\n    #region Constructors\n    public DisplayPeImport(\n        PeImport PeImport,\n        PhSymbolProvider SymPrv,\n        string ModuleFilePath,\n        bool ImportFound\n    )\n    {\n       Info.ordinal = PeImport.Ordinal;\n       Info.hint = PeImport.Hint;\n       Info.name = PeImport.Name;\n       Info.moduleName = PeImport.ModuleName;\n       Info.modulePath = ModuleFilePath;\n       Info.importNotFound = !ImportFound;\n\n       Tuple<CLRPH_DEMANGLER, string> DemanglingInfos = SymPrv.UndecorateName(PeImport.Name);\n       Info.Demangler = Enum.GetName(typeof(CLRPH_DEMANGLER), DemanglingInfos.Item1); \n       Info.UndecoratedName = DemanglingInfos.Item2;\n        \n       if (ImportFound)\n       { \n           Info.delayedImport = PeImport.DelayImport;\n           Info.importAsCppName = (PeImport.Name.Length > 0 && PeImport.Name[0] == '?');\n           Info.importByOrdinal = PeImport.ImportByOrdinal;\n       }\n\n        AddNewEventHandler(\"Undecorate\", \"Undecorate\", \"Name\", this.GetDisplayName);\n        AddNewEventHandler(\"FullPath\", \"FullPath\", \"ModuleName\", this.GetPathDisplayName);\n    }\n\t#endregion Constructors\n\n\t#region PublicAPI\n\tpublic override string ToString()\n\t{\n\t\tList<string> members = new List<string>() {\n\t\t\tOrdinal != null ? String.Format(\"{0} (0x{0:x08})\", Ordinal) : \"N/A\",\n\t\t\tHint != null ? String.Format(\"{0} (0x{0:x08})\", Hint) : \"N/A\",\n\t\t\tName,\n\t\t\tModuleName,\n\t\t\tDelayImport.ToString(),\n\t\t\tDemangler\n\t\t};\n\n\t\treturn String.Join(\", \", members.ToArray());\n\t}\n\n\n\tpublic string IconUri\n    {\n        // @TODO(implement API lookup in order to test for API Export presence)\n        get\n        {\n            string PathStrFormat = \"Images/import_{0:s}_found.png\";\n            if (Info.importNotFound)\n                PathStrFormat = \"Images/import_{0:s}_not_found.png\";\n\n\n            if (Info.importByOrdinal)\n                return String.Format(PathStrFormat, \"ord\");\n\n            if (Info.importAsCppName)\n                return String.Format(PathStrFormat, \"cpp\");\n\n            return String.Format(PathStrFormat, \"c\");\n        }\n    }\n\n    public int Type\n    {\n        get\n        {\n            if (Info.importNotFound)\n                return 1;\n            if (Info.importByOrdinal)\n                return 2;\n            if (Info.importAsCppName)\n                return 3;\n\n            return 0;\n        }\n    }\n\n    public ushort? Hint\n    {\n        get\n        {\n            if (Info.importByOrdinal)\n                return null;\n\n            return Info.hint;\n        }\n    }\n\n    public ushort? Ordinal { get { if (Info.importByOrdinal) { return Info.ordinal; } return null; } }\n\n    public string Name\n    {\n        get { return GetDisplayName(Dependencies.Properties.Settings.Default.Undecorate); }\n    }\n\n    public string ModuleName\n    {\n        get { return GetPathDisplayName(Dependencies.Properties.Settings.Default.FullPath); }\n    }\n\n    public string FilterName\n    {\n        get { return  String.Format(\"{0:s}:{1:s}\", this.ModuleName, this.Name); }\n    }\n\n    public Boolean DelayImport { get { return Info.delayedImport; } }\n\n    public string Demangler { get { return this.Info.Demangler; } }\n\n    protected string GetDisplayName(bool UndecorateName)\n    {\n        if (Info.importByOrdinal)\n            return String.Format(\"Ordinal_{0:d}\", Info.ordinal);\n\n        if ((UndecorateName) && (Info.UndecoratedName.Length > 0))\n            return Info.UndecoratedName;\n        \n       \n       return Info.name;\n    }\n\n    protected string GetPathDisplayName(bool FullPath)\n    {\n        if ((FullPath) && (Info.modulePath != null))\n            return Info.modulePath;\n\n        return Info.moduleName;\n    }\n    #endregion PublicAPI\n\n    #region Commands \n    public RelayCommand QueryImportApi\n    {\n        get\n        {\n            if (_QueryImportApi == null)\n            {\n                _QueryImportApi = new RelayCommand((param) =>\n                {\n                    if ((param == null))\n                    {\n                        return;\n                    }\n\n                    string ExportName = (param as DisplayPeImport).Name;\n                    if (ExportName == null)\n                    {\n                        return;\n                    }\n\n                    Process.Start(@\"https://docs.microsoft.com/search/?search=\" + ExportName);\n                });\n            }\n\n            return _QueryImportApi;\n        }\n    }\n\n    public RelayCommand CopyValue\n    {\n        get\n        {\n            if (_CopyValue == null)\n            {\n                _CopyValue = new RelayCommand((param) =>\n                {\n\n                    if ((param == null))\n                    {\n                        return;\n                    }\n\n                    Clipboard.Clear();\n\n                    try\n                    {\n\n                        Clipboard.SetText((string)param, TextDataFormat.Text);\n                    }\n                    catch { }\n                });\n            }\n\n            return _CopyValue;\n        }\n    }\n    #endregion // Commands \n\n\n    private PeImportInfo Info;\n    private RelayCommand _QueryImportApi;\n    private RelayCommand _CopyValue;\n}\n\npublic struct PeImportInfo\n{\n   public ushort ordinal;\n   public ushort hint;\n\n   public string name;\n   public string moduleName;\n   public string modulePath;\n\n   public string UndecoratedName;\n   public string Demangler;\n\n   public Boolean delayedImport;\n   public Boolean importByOrdinal;\n   public Boolean importAsCppName;\n   public Boolean importNotFound;\n\n}\n\n"
  },
  {
    "path": "DependenciesGui/ModuleSearchOrder.xaml",
    "content": "﻿<Window x:Class=\"Dependencies.ModuleSearchOrder\"\n        xmlns=\"http://schemas.microsoft.com/winfx/2006/xaml/presentation\"\n        xmlns:x=\"http://schemas.microsoft.com/winfx/2006/xaml\"\n        xmlns:d=\"http://schemas.microsoft.com/expression/blend/2008\"\n        xmlns:mc=\"http://schemas.openxmlformats.org/markup-compatibility/2006\"\n        xmlns:local=\"clr-namespace:Dependencies\"\n        mc:Ignorable=\"d\"\n        Title=\"Configure module search order\" \n        MinHeight=\"200\" \n        MinWidth=\"600\" \n        SizeToContent=\"Width\" \n        Width=\"500\" Height=\"400\" >\n        <!--ResizeMode=\"NoResize\"-->\n    <Grid Margin=\"20 20 20 20\"  MinWidth=\"500\">\n        <Grid.RowDefinitions>\n            <RowDefinition Height=\"33*\"/>\n        </Grid.RowDefinitions>\n\n        <Grid Grid.Row=\"0\">\n            <Grid.ColumnDefinitions>\n                <ColumnDefinition Width=\"80*\"/>\n            </Grid.ColumnDefinitions>\n\n            <ListView Name=\"OrderedModules\"\n                      HorizontalAlignment=\"Stretch\"\n                      HorizontalContentAlignment=\"Stretch\"\n                      Grid.Column=\"0\">\n                <ListView.View>\n                    <GridView>\n                        <GridViewColumn Header=\"Module\" DisplayMemberBinding=\"{Binding ModuleFilePath}\" />\n                    </GridView>\n                </ListView.View>\n\n                <ListView.ItemContainerStyle>\n                    <Style TargetType=\"ListViewItem\">\n                        <Setter Property=\"HorizontalAlignment\" Value=\"Stretch\" />\n                        <Setter Property=\"HorizontalContentAlignment\" Value=\"Stretch\" />\n                        <Setter Property=\"VerticalContentAlignment\" Value=\"Stretch\" />\n                        <Setter Property=\"FontFamily\" Value=\"Courier New\" />\n                        <Setter Property=\"FontSize\" Value=\"12\" />\n                    </Style>\n                </ListView.ItemContainerStyle>\n\n                <ListView.GroupStyle>\n                    <GroupStyle>\n                        <GroupStyle.HeaderTemplate>\n                            <DataTemplate>\n                                <Border BorderThickness=\"1\" Padding=\"0\" BorderBrush=\"lightgray\" Background=\"gainsboro\" SnapsToDevicePixels=\"True\">\n                                    <TextBlock FontWeight=\"Bold\" FontSize=\"14\" Text=\"{Binding Name}\"/>\n                                </Border>\n                            </DataTemplate>\n                        </GroupStyle.HeaderTemplate>\n                    </GroupStyle>\n                </ListView.GroupStyle>\n            </ListView>\n        </Grid>\n    </Grid>\n</Window>\n"
  },
  {
    "path": "DependenciesGui/ModuleSearchOrder.xaml.cs",
    "content": "﻿using System;\nusing System.Collections.Generic;\nusing System.Linq;\nusing System.Windows;\nusing System.ComponentModel;\nusing System.Windows.Data;\n\n\nnamespace Dependencies\n{\n\n\n    public class ModuleSearchResult\n    {\n        public string ModuleFilePath { get; set; }\n\n        public ModuleSearchStrategy SearchStrategy { get; set; }\n    }\n\n\n    /// <summary>\n    /// Interaction logic for ModuleSearchOrder.xaml\n    /// </summary>\n    public partial class ModuleSearchOrder : Window\n    {\n        public ModuleSearchOrder(ModulesCache LoadedModules)\n        {\n            InitializeComponent();\n            List<ModuleSearchResult> items = new List<ModuleSearchResult>();\n\n            foreach (var LoadedModule in LoadedModules.Values)\n            {\n                items.Add(new ModuleSearchResult() { ModuleFilePath = LoadedModule.ModuleName, SearchStrategy = LoadedModule.Location });\n            }\n            OrderedModules.ItemsSource = items;\n\n            CollectionView view = (CollectionView)CollectionViewSource.GetDefaultView(OrderedModules.ItemsSource);\n\n            PropertyGroupDescription groupDescription = new PropertyGroupDescription(\"SearchStrategy\");\n            view.GroupDescriptions.Add(groupDescription);\n\n            SortDescription sortDescription = new SortDescription(\"SearchStrategy\", ListSortDirection.Ascending);\n            view.SortDescriptions.Add(sortDescription);\n        }\n    }\n}\n"
  },
  {
    "path": "DependenciesGui/Properties/AssemblyInfo.cs",
    "content": "﻿using System.Reflection;\nusing System.Resources;\nusing System.Runtime.CompilerServices;\nusing System.Runtime.InteropServices;\nusing System.Windows;\n\n// Les informations générales relatives à un assembly dépendent de\n// l'ensemble d'attributs suivant. Changez les valeurs de ces attributs pour modifier les informations\n// associées à un assembly.\n[assembly: AssemblyTitle(\"DependenciesGui\")]\n[assembly: AssemblyDescription(\"Modern rewrite of the depends.exe tool.\")]\n[assembly: AssemblyConfiguration(\"\")]\n[assembly: AssemblyCompany(\"\")]\n[assembly: AssemblyProduct(\"Dependencies\")]\n[assembly: AssemblyCopyright(\"Copyright ©  2017\")]\n[assembly: AssemblyTrademark(\"\")]\n[assembly: AssemblyCulture(\"\")]\n\n// L'affectation de la valeur false à ComVisible rend les types invisibles dans cet assembly\n// aux composants COM. Si vous devez accéder à un type dans cet assembly à partir de\n// COM, affectez la valeur true à l'attribut ComVisible sur ce type.\n[assembly: ComVisible(false)]\n\n//Pour commencer à générer des applications localisables, définissez\n//<UICulture>CultureUtiliséePourCoder</UICulture> dans votre fichier .csproj\n//dans <PropertyGroup>.  Par exemple, si vous utilisez le français\n//dans vos fichiers sources, définissez <UICulture> à fr-FR. Puis, supprimez les marques de commentaire de\n//l'attribut NeutralResourceLanguage ci-dessous. Mettez à jour \"fr-FR\" dans\n//la ligne ci-après pour qu'elle corresponde au paramètre UICulture du fichier projet.\n\n//[assembly: NeutralResourcesLanguage(\"en-US\", UltimateResourceFallbackLocation.Satellite)]\n\n\n[assembly: ThemeInfo(\n    ResourceDictionaryLocation.None, //où se trouvent les dictionnaires de ressources spécifiques à un thème\n                                     //(utilisé si une ressource est introuvable dans la page,\n                                     // ou dictionnaires de ressources de l'application)\n    ResourceDictionaryLocation.SourceAssembly //où se trouve le dictionnaire de ressources générique\n                                              //(utilisé si une ressource est introuvable dans la page,\n                                              // dans l'application ou dans l'un des dictionnaires de ressources spécifiques à un thème)\n)]\n\n\n// Les informations de version pour un assembly se composent des quatre valeurs suivantes :\n//\n//      Version principale\n//      Version secondaire\n//      Numéro de build\n//      Révision\n//\n// Vous pouvez spécifier toutes les valeurs ou indiquer les numéros de build et de révision par défaut\n// en utilisant '*', comme indiqué ci-dessous :\n// [assembly: AssemblyVersion(\"1.0.*\")]\n[assembly: AssemblyVersion(\"1.11.1.0\")]\n[assembly: AssemblyFileVersion(\"1.11.1.0\")]\n"
  },
  {
    "path": "DependenciesGui/Properties/Resources.Designer.cs",
    "content": "﻿//------------------------------------------------------------------------------\n// <auto-generated>\n//     Ce code a été généré par un outil.\n//     Version du runtime :4.0.30319.42000\n//\n//     Les modifications apportées à ce fichier peuvent provoquer un comportement incorrect et seront perdues si\n//     le code est régénéré.\n// </auto-generated>\n//------------------------------------------------------------------------------\n\nnamespace Dependencies.Properties {\n    using System;\n    \n    \n    /// <summary>\n    ///   Une classe de ressource fortement typée destinée, entre autres, à la consultation des chaînes localisées.\n    /// </summary>\n    // Cette classe a été générée automatiquement par la classe StronglyTypedResourceBuilder\n    // à l'aide d'un outil, tel que ResGen ou Visual Studio.\n    // Pour ajouter ou supprimer un membre, modifiez votre fichier .ResX, puis réexécutez ResGen\n    // avec l'option /str ou régénérez votre projet VS.\n    [global::System.CodeDom.Compiler.GeneratedCodeAttribute(\"System.Resources.Tools.StronglyTypedResourceBuilder\", \"15.0.0.0\")]\n    [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]\n    [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]\n    internal class Resources {\n        \n        private static global::System.Resources.ResourceManager resourceMan;\n        \n        private static global::System.Globalization.CultureInfo resourceCulture;\n        \n        [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute(\"Microsoft.Performance\", \"CA1811:AvoidUncalledPrivateCode\")]\n        internal Resources() {\n        }\n        \n        /// <summary>\n        ///   Retourne l'instance ResourceManager mise en cache utilisée par cette classe.\n        /// </summary>\n        [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]\n        internal static global::System.Resources.ResourceManager ResourceManager {\n            get {\n                if (object.ReferenceEquals(resourceMan, null)) {\n                    global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager(\"Dependencies.Properties.Resources\", typeof(Resources).Assembly);\n                    resourceMan = temp;\n                }\n                return resourceMan;\n            }\n        }\n        \n        /// <summary>\n        ///   Remplace la propriété CurrentUICulture du thread actuel pour toutes\n        ///   les recherches de ressources à l'aide de cette classe de ressource fortement typée.\n        /// </summary>\n        [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]\n        internal static global::System.Globalization.CultureInfo Culture {\n            get {\n                return resourceCulture;\n            }\n            set {\n                resourceCulture = value;\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "DependenciesGui/Properties/Resources.resx",
    "content": "﻿<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<root>\n  <!-- \n    Microsoft ResX Schema \n    \n    Version 2.0\n    \n    The primary goals of this format is to allow a simple XML format \n    that is mostly human readable. The generation and parsing of the \n    various data types are done through the TypeConverter classes \n    associated with the data types.\n    \n    Example:\n    \n    ... ado.net/XML headers & schema ...\n    <resheader name=\"resmimetype\">text/microsoft-resx</resheader>\n    <resheader name=\"version\">2.0</resheader>\n    <resheader name=\"reader\">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>\n    <resheader name=\"writer\">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>\n    <data name=\"Name1\"><value>this is my long string</value><comment>this is a comment</comment></data>\n    <data name=\"Color1\" type=\"System.Drawing.Color, System.Drawing\">Blue</data>\n    <data name=\"Bitmap1\" mimetype=\"application/x-microsoft.net.object.binary.base64\">\n        <value>[base64 mime encoded serialized .NET Framework object]</value>\n    </data>\n    <data name=\"Icon1\" type=\"System.Drawing.Icon, System.Drawing\" mimetype=\"application/x-microsoft.net.object.bytearray.base64\">\n        <value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>\n        <comment>This is a comment</comment>\n    </data>\n                \n    There are any number of \"resheader\" rows that contain simple \n    name/value pairs.\n    \n    Each data row contains a name, and value. The row also contains a \n    type or mimetype. Type corresponds to a .NET class that support \n    text/value conversion through the TypeConverter architecture. \n    Classes that don't support this are serialized and stored with the \n    mimetype set.\n    \n    The mimetype is used for serialized objects, and tells the \n    ResXResourceReader how to depersist the object. This is currently not \n    extensible. For a given mimetype the value must be set accordingly:\n    \n    Note - application/x-microsoft.net.object.binary.base64 is the format \n    that the ResXResourceWriter will generate, however the reader can \n    read any of the formats listed below.\n    \n    mimetype: application/x-microsoft.net.object.binary.base64\n    value   : The object must be serialized with \n            : System.Serialization.Formatters.Binary.BinaryFormatter\n            : and then encoded with base64 encoding.\n    \n    mimetype: application/x-microsoft.net.object.soap.base64\n    value   : The object must be serialized with \n            : System.Runtime.Serialization.Formatters.Soap.SoapFormatter\n            : and then encoded with base64 encoding.\n\n    mimetype: application/x-microsoft.net.object.bytearray.base64\n    value   : The object must be serialized into a byte array \n            : using a System.ComponentModel.TypeConverter\n            : and then encoded with base64 encoding.\n    -->\n  <xsd:schema id=\"root\" xmlns=\"\" xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\" xmlns:msdata=\"urn:schemas-microsoft-com:xml-msdata\">\n    <xsd:element name=\"root\" msdata:IsDataSet=\"true\">\n      <xsd:complexType>\n        <xsd:choice maxOccurs=\"unbounded\">\n          <xsd:element name=\"metadata\">\n            <xsd:complexType>\n              <xsd:sequence>\n                <xsd:element name=\"value\" type=\"xsd:string\" minOccurs=\"0\" />\n              </xsd:sequence>\n              <xsd:attribute name=\"name\" type=\"xsd:string\" />\n              <xsd:attribute name=\"type\" type=\"xsd:string\" />\n              <xsd:attribute name=\"mimetype\" type=\"xsd:string\" />\n            </xsd:complexType>\n          </xsd:element>\n          <xsd:element name=\"assembly\">\n            <xsd:complexType>\n              <xsd:attribute name=\"alias\" type=\"xsd:string\" />\n              <xsd:attribute name=\"name\" type=\"xsd:string\" />\n            </xsd:complexType>\n          </xsd:element>\n          <xsd:element name=\"data\">\n            <xsd:complexType>\n              <xsd:sequence>\n                <xsd:element name=\"value\" type=\"xsd:string\" minOccurs=\"0\" msdata:Ordinal=\"1\" />\n                <xsd:element name=\"comment\" type=\"xsd:string\" minOccurs=\"0\" msdata:Ordinal=\"2\" />\n              </xsd:sequence>\n              <xsd:attribute name=\"name\" type=\"xsd:string\" msdata:Ordinal=\"1\" />\n              <xsd:attribute name=\"type\" type=\"xsd:string\" msdata:Ordinal=\"3\" />\n              <xsd:attribute name=\"mimetype\" type=\"xsd:string\" msdata:Ordinal=\"4\" />\n            </xsd:complexType>\n          </xsd:element>\n          <xsd:element name=\"resheader\">\n            <xsd:complexType>\n              <xsd:sequence>\n                <xsd:element name=\"value\" type=\"xsd:string\" minOccurs=\"0\" msdata:Ordinal=\"1\" />\n              </xsd:sequence>\n              <xsd:attribute name=\"name\" type=\"xsd:string\" use=\"required\" />\n            </xsd:complexType>\n          </xsd:element>\n        </xsd:choice>\n      </xsd:complexType>\n    </xsd:element>\n  </xsd:schema>\n  <resheader name=\"resmimetype\">\n    <value>text/microsoft-resx</value>\n  </resheader>\n  <resheader name=\"version\">\n    <value>2.0</value>\n  </resheader>\n  <resheader name=\"reader\">\n    <value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>\n  </resheader>\n  <resheader name=\"writer\">\n    <value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>\n  </resheader>\n</root>"
  },
  {
    "path": "DependenciesGui/Properties/Settings.Designer.cs",
    "content": "﻿//------------------------------------------------------------------------------\n// <auto-generated>\n//     Ce code a été généré par un outil.\n//     Version du runtime :4.0.30319.42000\n//\n//     Les modifications apportées à ce fichier peuvent provoquer un comportement incorrect et seront perdues si\n//     le code est régénéré.\n// </auto-generated>\n//------------------------------------------------------------------------------\n\nnamespace Dependencies.Properties {\n    \n    \n    [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]\n    [global::System.CodeDom.Compiler.GeneratedCodeAttribute(\"Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator\", \"15.7.0.0\")]\n    internal sealed partial class Settings : global::System.Configuration.ApplicationSettingsBase {\n        \n        private static Settings defaultInstance = ((Settings)(global::System.Configuration.ApplicationSettingsBase.Synchronized(new Settings())));\n        \n        public static Settings Default {\n            get {\n                return defaultInstance;\n            }\n        }\n        \n        [global::System.Configuration.UserScopedSettingAttribute()]\n        [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]\n        [global::System.Configuration.DefaultSettingValueAttribute(\"True\")]\n        public bool Undecorate {\n            get {\n                return ((bool)(this[\"Undecorate\"]));\n            }\n            set {\n                this[\"Undecorate\"] = value;\n            }\n        }\n        \n        [global::System.Configuration.UserScopedSettingAttribute()]\n        [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]\n        [global::System.Configuration.DefaultSettingValueAttribute(\"True\")]\n        public bool ShowStatusBar {\n            get {\n                return ((bool)(this[\"ShowStatusBar\"]));\n            }\n            set {\n                this[\"ShowStatusBar\"] = value;\n            }\n        }\n        \n        [global::System.Configuration.UserScopedSettingAttribute()]\n        [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]\n        [global::System.Configuration.DefaultSettingValueAttribute(\"True\")]\n        public bool FullPath {\n            get {\n                return ((bool)(this[\"FullPath\"]));\n            }\n            set {\n                this[\"FullPath\"] = value;\n            }\n        }\n        \n        [global::System.Configuration.UserScopedSettingAttribute()]\n        [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]\n        [global::System.Configuration.DefaultSettingValueAttribute(\"0\")]\n        public byte RecentFilesIndex {\n            get {\n                return ((byte)(this[\"RecentFilesIndex\"]));\n            }\n            set {\n                this[\"RecentFilesIndex\"] = value;\n            }\n        }\n        \n        [global::System.Configuration.UserScopedSettingAttribute()]\n        [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]\n        [global::System.Configuration.DefaultSettingValueAttribute(\"peview.exe\")]\n        public string PeViewerPath {\n            get {\n                return ((string)(this[\"PeViewerPath\"]));\n            }\n            set {\n                this[\"PeViewerPath\"] = value;\n            }\n        }\n        \n        [global::System.Configuration.UserScopedSettingAttribute()]\n        [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]\n        [global::System.Configuration.DefaultSettingValueAttribute(\"ChildOnly\")]\n        public string TreeBuildBehaviour {\n            get {\n                return ((string)(this[\"TreeBuildBehaviour\"]));\n            }\n            set {\n                this[\"TreeBuildBehaviour\"] = value;\n            }\n        }\n        \n        [global::System.Configuration.UserScopedSettingAttribute()]\n        [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]\n        [global::System.Configuration.DefaultSettingValueAttribute(\"Courier New\")]\n        public string Font {\n            get {\n                return ((string)(this[\"Font\"]));\n            }\n            set {\n                this[\"Font\"] = value;\n            }\n        }\n        \n        [global::System.Configuration.UserScopedSettingAttribute()]\n        [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]\n        [global::System.Configuration.DefaultSettingValueAttribute(@\"<?xml version=\"\"1.0\"\" encoding=\"\"utf-16\"\"?>\n<ArrayOfString xmlns:xsi=\"\"http://www.w3.org/2001/XMLSchema-instance\"\" xmlns:xsd=\"\"http://www.w3.org/2001/XMLSchema\"\">\n  <string />\n  <string />\n  <string />\n  <string />\n  <string />\n  <string />\n  <string />\n  <string />\n  <string />\n  <string />\n</ArrayOfString>\")]\n        public global::System.Collections.Specialized.StringCollection RecentFiles {\n            get {\n                return ((global::System.Collections.Specialized.StringCollection)(this[\"RecentFiles\"]));\n            }\n            set {\n                this[\"RecentFiles\"] = value;\n            }\n        }\n        \n        [global::System.Configuration.UserScopedSettingAttribute()]\n        [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]\n        [global::System.Configuration.DefaultSettingValueAttribute(\"2\")]\n        public int TreeDepth {\n            get {\n                return ((int)(this[\"TreeDepth\"]));\n            }\n            set {\n                this[\"TreeDepth\"] = value;\n            }\n        }\n        \n        [global::System.Configuration.UserScopedSettingAttribute()]\n        [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]\n        [global::System.Configuration.DefaultSettingValueAttribute(\"True\")]\n        public bool BinaryCacheOptionValue {\n            get {\n                return ((bool)(this[\"BinaryCacheOptionValue\"]));\n            }\n            set {\n                this[\"BinaryCacheOptionValue\"] = value;\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "DependenciesGui/Properties/Settings.settings",
    "content": "﻿<?xml version='1.0' encoding='utf-8'?>\n<SettingsFile xmlns=\"http://schemas.microsoft.com/VisualStudio/2004/01/settings\" CurrentProfile=\"(Default)\" GeneratedClassNamespace=\"Dependencies.Properties\" GeneratedClassName=\"Settings\">\n  <Profiles />\n  <Settings>\n    <Setting Name=\"Undecorate\" Type=\"System.Boolean\" Scope=\"User\">\n      <Value Profile=\"(Default)\">True</Value>\n    </Setting>\n    <Setting Name=\"ShowStatusBar\" Type=\"System.Boolean\" Scope=\"User\">\n      <Value Profile=\"(Default)\">True</Value>\n    </Setting>\n    <Setting Name=\"FullPath\" Type=\"System.Boolean\" Scope=\"User\">\n      <Value Profile=\"(Default)\">True</Value>\n    </Setting>\n    <Setting Name=\"RecentFilesIndex\" Type=\"System.Byte\" Scope=\"User\">\n      <Value Profile=\"(Default)\">0</Value>\n    </Setting>\n    <Setting Name=\"PeViewerPath\" Type=\"System.String\" Scope=\"User\">\n      <Value Profile=\"(Default)\">peview.exe</Value>\n    </Setting>\n    <Setting Name=\"TreeBuildBehaviour\" Type=\"System.String\" Scope=\"User\">\n      <Value Profile=\"(Default)\">ChildOnly</Value>\n    </Setting>\n    <Setting Name=\"Font\" Type=\"System.String\" Scope=\"User\">\n      <Value Profile=\"(Default)\">Courier New</Value>\n    </Setting>\n    <Setting Name=\"RecentFiles\" Type=\"System.Collections.Specialized.StringCollection\" Scope=\"User\">\n      <Value Profile=\"(Default)\">&lt;?xml version=\"1.0\" encoding=\"utf-16\"?&gt;\n&lt;ArrayOfString xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\"&gt;\n  &lt;string /&gt;\n  &lt;string /&gt;\n  &lt;string /&gt;\n  &lt;string /&gt;\n  &lt;string /&gt;\n  &lt;string /&gt;\n  &lt;string /&gt;\n  &lt;string /&gt;\n  &lt;string /&gt;\n  &lt;string /&gt;\n&lt;/ArrayOfString&gt;</Value>\n    </Setting>\n    <Setting Name=\"TreeDepth\" Type=\"System.Int32\" Scope=\"User\">\n      <Value Profile=\"(Default)\">2</Value>\n    </Setting>\n    <Setting Name=\"BinaryCacheOptionValue\" Type=\"System.Boolean\" Scope=\"User\">\n      <Value Profile=\"(Default)\">True</Value>\n    </Setting>\n  </Settings>\n</SettingsFile>"
  },
  {
    "path": "DependenciesGui/SearchFolder.xaml",
    "content": "﻿<Window x:Class=\"Dependencies.SearchFolder\"\n        xmlns=\"http://schemas.microsoft.com/winfx/2006/xaml/presentation\"\n        xmlns:x=\"http://schemas.microsoft.com/winfx/2006/xaml\"\n        xmlns:d=\"http://schemas.microsoft.com/expression/blend/2008\"\n        xmlns:mc=\"http://schemas.openxmlformats.org/markup-compatibility/2006\"\n        xmlns:local=\"clr-namespace:Dependencies\"\n        mc:Ignorable=\"d\"\n        Title=\"Search folders customization\" Height=\"400\" Width=\"600\">\n    <Grid Margin=\"10 10 10 10\" MinHeight=\"100\"  MinWidth=\"560\">\n\n        <Grid.RowDefinitions>\n            <RowDefinition Height=\"0*\"/>\n            <RowDefinition Height=\"30*\"/>\n            <RowDefinition Height=\"276*\"/>\n            <RowDefinition Height=\"36*\"/>\n            <RowDefinition Height=\"7*\"/>\n        </Grid.RowDefinitions>\n\n        <Grid Grid.Row=\"1\">\n            <Grid.ColumnDefinitions>\n                <ColumnDefinition Width=\"139\"/>\n                <ColumnDefinition/>\n                <ColumnDefinition Width=\"30\"/>\n            </Grid.ColumnDefinitions>\n\n            <Label Content=\"Binary current directory:\" \n                   VerticalAlignment=\"Center\"\n                   Grid.Column=\"0\"\n                   Height=\"26\" Margin=\"0,2\"\n                   />\n\n            <TextBox Text=\"{Binding Path=WorkingDirectory, Mode=OneWay}\"\n                    Name=\"WorkingDirectoryTextBox\"\n                    TextWrapping=\"Wrap\" \n                    HorizontalContentAlignment=\"Stretch\"\n                    HorizontalAlignment=\"Stretch\"\n                    Width=\"auto\" \n                    Grid.Column=\"1\" Margin=\"0,5\"\n                    />\n\n            <Button Content=\"...\"\n                    Margin=\"2,5,0,5\"\n                    Click=\"OnBinaryWorkindDirectoryChange\"\n                    Grid.Column=\"2\"/>\n        </Grid>\n\n        <Grid Grid.Row=\"2\">\n            <Grid.RowDefinitions>\n                <RowDefinition Height=\"29*\"/>\n                <RowDefinition Height=\"247*\"/>\n            </Grid.RowDefinitions>\n\n            <Label Content=\"Additional search folders:\" \n                   HorizontalAlignment=\"Left\" \n                   HorizontalContentAlignment=\"Left\"\n                   VerticalAlignment=\"Top\"\n                   Grid.Row=\"0\"\n                   Height=\"25\"\n                   Margin=\"0 0 0 0\" Width=\"144\"\n                   />\n\n            <Grid Grid.Row=\"1\">\n                <Grid.ColumnDefinitions>\n                    <ColumnDefinition Width=\"70*\"/>\n                    <ColumnDefinition Width=\"10\"/>\n                    <ColumnDefinition Width=\"80\"/>\n                </Grid.ColumnDefinitions>\n\n                <ListBox ItemsSource=\"{Binding Path=SearchFolders}\" \n                     Name=\"SearchFoldersList\"\n                     Height=\"auto\" \n                     Margin=\"2,0,0,0\" \n                     VerticalAlignment=\"Stretch\"\n                     VerticalContentAlignment=\"Stretch\"\n                     HorizontalContentAlignment=\"Stretch\"\n                     HorizontalAlignment=\"Stretch\"\n                     Width=\"auto\" \n                     AllowDrop=\"True\" \n                     Drop=\"SearchFolder_Drop\" \n                     DragOver=\"SearchFolder_DragOver\" \n                     DragLeave=\"SearchFolder_DragLeave\" \n                     MouseDoubleClick =\"SearchFoldersList_MouseDoubleClick\"\n                     SelectionChanged=\"OnSearchFolderViewSelectedItemChanged\"\n                     Background=\"#FFE2E2E2\" \n                     FontSize=\"10\"\n                     Grid.Column=\"0\">\n                    <ListBox.ItemTemplate>\n                        <DataTemplate>\n                            <Grid>\n                                <TextBlock Text=\"{Binding Path=Folder}\"/>\n                                <TextBox  Text=\"{Binding Path=Folder}\" Visibility=\"{Binding IsEditable, Converter={StaticResource BooleanToVisibilityConverter}}\"/>\n                            </Grid>\n                        </DataTemplate>\n                    </ListBox.ItemTemplate>\n                </ListBox>\n\n                <Grid Grid.Column=\"2\">\n                    <Grid.RowDefinitions>\n                        <RowDefinition Height=\"30\"/>\n                        <RowDefinition Height=\"30\"/>\n                        <RowDefinition Height=\"30\"/>\n                        <RowDefinition Height=\"30\"/>\n                        <RowDefinition Height=\"10\"/>\n                        <RowDefinition Height=\"30\"/>\n                        <RowDefinition Height=\"30\"/>\n                        <RowDefinition Height=\"150*\"/>\n                    </Grid.RowDefinitions>\n\n                    <Button Content=\"New\" \n                        Height=\"20\"\n                        Margin=\"2,0,2,10\"\n                        \n                        Click=\"OnNewEntry\"\n                        Grid.Row=\"0\"/>\n\n                    <Button Content=\"Edit\" \n                        Height=\"20\"\n                        Margin=\"2,0,2,10\"\n                        Click=\"OnEditEntry\"\n                        Grid.Row=\"1\"/>\n\n                    <Button Content=\"Browse ...\" \n                        Height=\"20\"\n                        Margin=\"2,0,2,10\"\n                        Click=\"OnBrowseEntry\"\n                        Grid.Row=\"2\"/>\n\n                    <Button Content=\"Delete\" \n                        Height=\"20\"\n                        Margin=\"2,0,2,10\"\n                        Click=\"OnDeleteEntry\"\n                        Grid.Row=\"3\"/>\n\n                    <Button Content=\"Move Up\" \n                        Height=\"20\"\n                        Margin=\"2,0,2,10\"\n                        Click=\"OnMoveUpEntry\"\n                        Grid.Row=\"5\"/>\n\n                    <Button Content=\"Move Down\" \n                        Height=\"20\"\n                        Margin=\"2,0,2,10\"\n                        Click=\"OnMoveDownEntry\"\n                        Grid.Row=\"6\"/>\n                </Grid>\n            </Grid>\n        </Grid>\n\n        <Grid Grid.Row=\"3\">\n            <Grid.ColumnDefinitions>\n                <ColumnDefinition Width=\"150*\"/>\n                <ColumnDefinition Width=\"70\"/>\n                <ColumnDefinition Width=\"70\"/>\n            </Grid.ColumnDefinitions>\n\n            <Button Content=\"Cancel\" \n                    Height=\"20\"\n                    Margin=\"2 0 2 0\"\n                    Click=\"OnCancel\"\n                    Grid.Column=\"1\"/>\n\n            <Button Content=\"OK\" \n                    Height=\"20\"\n                    Margin=\"2 0 2 0\"\n                    Click=\"OnValidate\"\n                    Grid.Column=\"2\"/>\n        </Grid>\n    </Grid>\n</Window>\n"
  },
  {
    "path": "DependenciesGui/SearchFolder.xaml.cs",
    "content": "﻿using System;\nusing System.Collections.Generic;\nusing System.Collections.ObjectModel;\nusing System.Linq;\nusing System.IO;\nusing System.Threading.Tasks;\nusing System.Windows;\nusing System.Windows.Controls;\nusing System.Windows.Data;\nusing System.Windows.Documents;\nusing System.Windows.Input;\nusing System.Windows.Media;\nusing System.Windows.Media.Imaging;\nusing System.ComponentModel;\nusing System.Windows.Forms;\n\nnamespace Dependencies\n{\n\tpublic class SearchFolderItem : INotifyPropertyChanged\n\t{\n\t\tpublic event PropertyChangedEventHandler PropertyChanged;\n\n\t\tprotected void OnPropertyChanged(string info)\n\t\t{\n            PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(info));\n        }\n\n\t\tpublic string Folder {\n\t\t\tget { return folder; }\n\t\t\tset { folder = value;  OnPropertyChanged(\"Folder\"); }\n\t\t}\n\n        public Boolean IsEditable\n        {\n            get { return is_editable; }\n            set { is_editable = value; OnPropertyChanged(\"IsEditable\"); }\n        }\n\n        public bool Dummy { get; set; }\n\n\t\tprivate string folder;\n        private Boolean is_editable;\n    }\n\n\t/// <summary>\n\t/// Logique d'interaction pour SearchFolder.xaml\n\t/// </summary>\n\tpublic partial class SearchFolder : Window\n\t{\n\t\tprivate DependencyWindow _SelectedItem;\n\t\tprivate ObservableCollection<SearchFolderItem> _CustomSearchFolders;\n\t\tprivate string _working_directory;\n\n\t\tpublic SearchFolder(DependencyWindow SelectedItem)\n\t\t{\n\t\t\t_SelectedItem = SelectedItem;\n\t\t\t_working_directory = SelectedItem.RootFolder;\n\t\t\t_CustomSearchFolders = new ObservableCollection<SearchFolderItem>();\n\t\t\tforeach (var item in SelectedItem.CustomSearchFolders)\n\t\t\t{\n\t\t\t\t_CustomSearchFolders.Add(\n\t\t\t\t\tnew SearchFolderItem()\n\t\t\t\t\t{\n\t\t\t\t\t\tFolder = item,\n\t\t\t\t\t\tDummy = false,\n                        IsEditable = false,\n                    }\n\t\t\t\t);\n\t\t\t}\n\n\t\t\tEnsureSearchFolderHasDummyEntry();\n\n\t\t\t// bind window to observable collections\n\t\t\tthis.DataContext = this; \n\t\t\tInitializeComponent();\n\t\t}\n\n\t\tpublic ObservableCollection<SearchFolderItem> SearchFolders\n\t\t{\n\t\t\tget\n\t\t\t{\n                return _CustomSearchFolders;\n                //return (ObservableCollection < SearchFolderItem >) _CustomSearchFolders.Where(sf => !sf.Dummy);\n\t\t\t}\n\t\t}\n\n\t\tpublic string WorkingDirectory\n\t\t{\n\t\t\tget { return _working_directory; }\n\t\t\tset { _working_directory = value; this.WorkingDirectoryTextBox.Text = value;}\n\t\t}\n\n\t\tprivate void OnChangeSearchFolder(object sender, RoutedEventArgs e)\n\t\t{\n\t\t\tSystem.Windows.Controls.Button selectedButton = sender as System.Windows.Controls.Button;\n\t\t\tSearchFolderItem selectedItem = (SearchFolderItem) (selectedButton.DataContext as System.Windows.Controls.ListBoxItem).Content;\n\n\t\t\tFolderBrowserDialog InputFileNameDlg = new FolderBrowserDialog();\n\t\t\tif (InputFileNameDlg.ShowDialog() != System.Windows.Forms.DialogResult.OK)\n\t\t\t\treturn;\n\n\t\t\tvar selectedPath = InputFileNameDlg.SelectedPath;\n\n\n\t\t\tselectedItem.Folder = selectedPath;\n\t\t\tselectedItem.Dummy = false;\n\t\t\t\n\n\t\t\tEnsureSearchFolderHasDummyEntry();\n\t\t}\n\n\t\tprivate void OnRemoveSearchFolder(object sender, RoutedEventArgs e)\n\t\t{\n\t\t\tSystem.Windows.Controls.Button selectedButton = sender as System.Windows.Controls.Button;\n\t\t\tSearchFolderItem selectedItem = (SearchFolderItem)(selectedButton.DataContext as System.Windows.Controls.ListBoxItem).Content;\n\n\t\t\t_CustomSearchFolders.Remove(selectedItem);\n\n\t\t\tEnsureSearchFolderHasDummyEntry();\n\t\t}\n\n\t\tprivate void EnsureSearchFolderHasDummyEntry()\n\t\t{\n\t\t\t// add a dummy entry if necessary\n\t\t\tif (_CustomSearchFolders.Count == 0 || !_CustomSearchFolders.Last().Dummy)\n\t\t\t{\n\t\t\t\t_CustomSearchFolders.Add(\n\t\t\t\t\tnew SearchFolderItem()\n\t\t\t\t\t{\n\t\t\t\t\t\tFolder = null,\n\t\t\t\t\t\tDummy = true,\n                        IsEditable= false,\n                    }\n\t\t\t\t);\n\t\t\t}\n        }\n\n\t\tprivate void OnBinaryWorkindDirectoryChange(object sender, RoutedEventArgs e)\n\t\t{\n\t\t\tFolderBrowserDialog InputFileNameDlg = new FolderBrowserDialog()\n\t\t\t{\n\t\t\t\tSelectedPath = WorkingDirectory\n\t\t\t};\n\n\n\t\t\tif (InputFileNameDlg.ShowDialog() != System.Windows.Forms.DialogResult.OK)\n\t\t\t\treturn;\n\n\t\t\tWorkingDirectory = InputFileNameDlg.SelectedPath;\n\t\t}\n\n\t\tprivate void OnCancel(object sender, RoutedEventArgs e)\n\t\t{\n\t\t\tthis.Close();\n\t\t}\n\n\t\tprivate void OnValidate(object sender, RoutedEventArgs e)\n\t\t{\n\t\t\tvar nonDummySearchFolders = _CustomSearchFolders.ToList()\n\t\t\t\t\t\t\t\t\t\t\t\t.FindAll(item => !item.Dummy)\n\t\t\t\t\t\t\t\t\t\t\t\t.Select(i => i.Folder)\n\t\t\t\t\t\t\t\t\t\t\t\t.ToList();\n\n\t\t\t// do not launch analysis again if there is no modifications\n\t\t\tbool searchFoldersChanged = (_SelectedItem.CustomSearchFolders != nonDummySearchFolders) || (WorkingDirectory != _SelectedItem.WorkingDirectory);\n\t\t\t\n\t\t\tthis.Close();\n\n\t\t\tif (searchFoldersChanged)\n\t\t\t{\n\t\t\t\t_SelectedItem.CustomSearchFolders = nonDummySearchFolders;\n\t\t\t\t_SelectedItem.WorkingDirectory = WorkingDirectory;\n\n\t\t\t\t// Force refresh\n\t\t\t\t_SelectedItem.InitializeView();\n\t\t\t}\n\t\t}\n\n        private void OnNewEntry(object sender, RoutedEventArgs e)\n        {\n            EnsureSearchFolderHasDummyEntry();\n\n            // The last entry is always a dummy one, so we can use it\n            SearchFolderItem newItem = _CustomSearchFolders.Last();\n\n            newItem.Dummy = false;\n            newItem.IsEditable = true;\n            newItem.PropertyChanged += SearchFolder_PropertyChanged;\n\n           \n\n            EnsureSearchFolderHasDummyEntry();\n        }\n\n        private void OnEditEntry(object sender, RoutedEventArgs e)\n        {\n            SearchFolderItem selectedItem = (SearchFolderItem)SearchFoldersList.SelectedItem;\n            if (selectedItem == null)\n            {\n                return;\n            }\n\n            selectedItem.IsEditable = true;\n            selectedItem.PropertyChanged += SearchFolder_PropertyChanged;\n\n            foreach (var sfi in _CustomSearchFolders)\n            {\n                if (sfi != selectedItem)\n                {\n                    sfi.IsEditable = false;\n                }\n            }\n\n            EnsureSearchFolderHasDummyEntry();\n        }\n\n        private void OnBrowseEntry(object sender, RoutedEventArgs e)\n        {\n            // Ask the user for a path\n            FolderBrowserDialog InputFileNameDlg = new FolderBrowserDialog();\n            if (InputFileNameDlg.ShowDialog() != System.Windows.Forms.DialogResult.OK)\n                return;\n\n            var selectedPath = InputFileNameDlg.SelectedPath;\n\n            // Either edit the selected item or add a new one \n            SearchFolderItem selectedItem = (SearchFolderItem) SearchFoldersList.SelectedItem;\n            if (selectedItem == null || !selectedItem.IsEditable)\n            {\n                // The last entry is always a dummy one, so we can use it\n                selectedItem = _CustomSearchFolders.Last();\n            }\n\n\n            selectedItem.Folder = selectedPath;\n            selectedItem.Dummy = false;\n            selectedItem.IsEditable = true;\n\n            foreach (var sfi in _CustomSearchFolders)\n            {\n                if (sfi != selectedItem)\n                {\n                    sfi.IsEditable = false;\n                }\n            }\n\n            EnsureSearchFolderHasDummyEntry();\n        }\n\n        private void OnDeleteEntry(object sender, RoutedEventArgs e)\n        {\n            SearchFolderItem selectedItem = (SearchFolderItem) SearchFoldersList.SelectedItem;\n            if (selectedItem == null)\n            {\n                return;\n            }\n\n            _CustomSearchFolders.Remove(selectedItem);\n\n            EnsureSearchFolderHasDummyEntry();\n        }\n\n        private void OnMoveUpEntry(object sender, RoutedEventArgs e)\n        {\n            SearchFolderItem selectedItem = (SearchFolderItem)SearchFoldersList.SelectedItem;\n            if (selectedItem == null)\n            {\n                return;\n            }\n\n            // Dummy entry stays last\n            if (selectedItem.Dummy)\n            {\n                return;\n            }\n\n            // No need to move up the first entry\n            int index = _CustomSearchFolders.IndexOf(selectedItem);\n            if (index == 0)\n            {\n                return;\n            }\n            _CustomSearchFolders.Remove(selectedItem);\n            _CustomSearchFolders.Insert(index - 1, selectedItem);\n\n            EnsureSearchFolderHasDummyEntry();\n        }\n\n        private void OnMoveDownEntry(object sender, RoutedEventArgs e)\n        {\n            SearchFolderItem selectedItem = (SearchFolderItem)SearchFoldersList.SelectedItem;\n            if (selectedItem == null)\n            {\n                return;\n            }\n\n            // Dummy entry stays last\n            if (selectedItem.Dummy)\n            {\n                return;\n            }\n\n            // No need to move down the last non-dummy entry\n            int index = _CustomSearchFolders.IndexOf(selectedItem);\n            if (index == _CustomSearchFolders.Count() - 2 )\n            {\n                return;\n            }\n            _CustomSearchFolders.Remove(selectedItem);\n            _CustomSearchFolders.Insert(index + 1, selectedItem);\n\n            EnsureSearchFolderHasDummyEntry();\n        }\n\n        private void SearchFolder_PropertyChanged(object sender, PropertyChangedEventArgs e)\n        {\n            if (sender.GetType() == typeof(SearchFolderItem) && e.PropertyName == \"Folder\")\n            {\n                SearchFolderItem ChangedSearchFolder = (SearchFolderItem)sender;\n\n                ChangedSearchFolder.IsEditable = false;\n                ChangedSearchFolder.PropertyChanged -= SearchFolder_PropertyChanged;\n                ChangeSearchFolder(ChangedSearchFolder);\n            }\n        }\n\n        private void OnSearchFolderViewSelectedItemChanged(object sender, RoutedEventArgs e)\n        {\n            SearchFolderItem selectedItem = (SearchFolderItem)SearchFoldersList.SelectedItem;\n\n            foreach(var sfi in _CustomSearchFolders)\n            {\n                if(sfi != selectedItem)\n                {\n                    sfi.IsEditable = false;\n                }\n            }\n        }\n\n        private void ChangeSearchFolder(SearchFolderItem Item)\n        {\n\n        }\n\n        private void SearchFolder_DragOver(object sender, System.Windows.DragEventArgs e)\n\t\t{\n\t\t\tif (e.Data.GetDataPresent(System.Windows.DataFormats.FileDrop))\n\t\t\t{\n\t\t\t\te.Effects = System.Windows.DragDropEffects.Copy;\n\t\t\t\tvar listbox = sender as System.Windows.Controls.ListBox;\n\t\t\t\tlistbox.Background = new SolidColorBrush(Color.FromRgb(155, 155, 155));\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\te.Effects = System.Windows.DragDropEffects.None;\n\t\t\t}\n\t\t}\n\n        private void SearchFoldersList_MouseDoubleClick(object sender, MouseButtonEventArgs e)\n        {\n            var listbox = sender as System.Windows.Controls.ListBox;\n\n            SearchFolderItem selectedItem = (SearchFolderItem)listbox.SelectedItem;\n            if (selectedItem == null)\n            {\n                return;\n            }\n\n            selectedItem.IsEditable = true;\n            selectedItem.PropertyChanged += SearchFolder_PropertyChanged;\n\n            EnsureSearchFolderHasDummyEntry();\n        }\n\n\n        private void SearchFolder_DragLeave(object sender, System.Windows.DragEventArgs e)\n\t\t{\n\t\t\tvar listbox = sender as System.Windows.Controls.ListBox;\n\t\t\tlistbox.Background = new SolidColorBrush(Color.FromRgb(226, 226, 226));\n\t\t}\n\n\t\tprivate void SearchFolder_Drop(object sender, System.Windows.DragEventArgs e)\n\t\t{\n\t\t\tif (e.Data.GetDataPresent(System.Windows.DataFormats.FileDrop))\n\t\t\t{\n\t\t\t\tstring[] folders = (string[]) e.Data.GetData(System.Windows.DataFormats.FileDrop);\n\n\t\t\t\tforeach (string FolderPath in folders)\n\t\t\t\t{\n\t\t\t\t\tif (Directory.Exists(FolderPath))\n\t\t\t\t\t{\n\t\t\t\t\t\tif (_CustomSearchFolders.Last().Dummy)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t_CustomSearchFolders.Last().Folder = FolderPath;\n\t\t\t\t\t\t\t_CustomSearchFolders.Last().Dummy = false;\n\t\t\t\t\t\t}\n\t\t\t\t\t\telse\n\t\t\t\t\t\t{ \n\t\t\t\t\t\t\t_CustomSearchFolders.Add(new SearchFolderItem()\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tFolder = FolderPath,\n\t\t\t\t\t\t\t\tDummy = false\n\t\t\t\t\t\t\t});\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tEnsureSearchFolderHasDummyEntry();\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tvar listbox = sender as System.Windows.Controls.ListBox;\n\t\t\tlistbox.Background = new SolidColorBrush(Color.FromRgb(226, 226, 226));\n\t\t}\n\n    }\n}\n"
  },
  {
    "path": "DependenciesGui/Settings.cs",
    "content": "﻿namespace Dependencies.Properties {\n    \n    \n    // Cette classe vous permet de gérer des événements spécifiques dans la classe de paramètres :\n    //  L'événement SettingChanging est déclenché avant la modification d'une valeur de paramètre.\n    //  L'événement PropertyChanged est déclenché après la modification d'une valeur de paramètre.\n    //  L'événement SettingsLoaded est déclenché après le chargement des valeurs de paramètre.\n    //  L'événement SettingsSaving est déclenché avant l'enregistrement des valeurs de paramètre.\n    internal sealed partial class Settings {\n        \n        public Settings() {\n            // // Pour ajouter des gestionnaires d'événements afin d'enregistrer et de modifier les paramètres, supprimez les marques de commentaire des lignes ci-dessous :\n            //\n            // this.SettingChanging += this.SettingChangingEventHandler;\n            //\n            // this.SettingsSaving += this.SettingsSavingEventHandler;\n            //\n        }\n        \n        private void SettingChangingEventHandler(object sender, System.Configuration.SettingChangingEventArgs e) {\n            // Ajouter du code pour gérer l'événement SettingChangingEvent ici.\n        }\n        \n        private void SettingsSavingEventHandler(object sender, System.ComponentModel.CancelEventArgs e) {\n            // Ajouter du code pour gérer l'événement SettingsSaving ici.\n        }\n    }\n}\n"
  },
  {
    "path": "DependenciesGui/Shell32IconExtractor.cs",
    "content": "using System;\nusing System.Windows;\nusing System.Windows.Data;\nusing System.Drawing;\nusing System.Windows.Media.Imaging;\nusing System.Runtime.InteropServices;\nusing Microsoft.Win32.SafeHandles;\n\nusing Dependencies.ClrPh;\n\nnamespace Dependencies\n{\n\t/// <summary>\n    /// Summary description for ShellIcon.  Get a small or large Icon with an easy C# function call\n    /// that returns a 32x32 or 16x16 System.Drawing.Icon depending on which function you call\n    /// either GetSmallIcon(string fileName) or GetLargeIcon(string fileName)\n    /// </summary>\n    public static class ShellIcon\n    {\n        [StructLayout(LayoutKind.Sequential)]\n        public struct SHFILEINFO\n        {\n            public IntPtr hIcon;\n            public IntPtr iIcon;\n            public uint dwAttributes;\n            [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 260)]\n            public string szDisplayName;\n            [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 80)]\n            public string szTypeName;\n        };\n\n        class Win32\n        {\n            public const uint SHGFI_ICON = 0x100;\n            public const uint SHGFI_LARGEICON = 0x0; // 'Large icon\n            public const uint SHGFI_SMALLICON = 0x1; // 'Small icon\n\n            [DllImport(\"shell32.dll\")]\n            public static extern IntPtr SHGetFileInfo(string pszPath, uint dwFileAttributes, ref SHFILEINFO psfi, uint cbSizeFileInfo, uint uFlags);\n\n            [DllImport(\"User32.dll\")]\n            public static extern int DestroyIcon(IntPtr hIcon);\n\n            [DllImport(\"kernel32.dll\", SetLastError = true)]\n            public static extern bool Wow64DisableWow64FsRedirection(ref IntPtr ptr);\n\n            [DllImport(\"kernel32.dll\", SetLastError = true)]\n            public static extern bool Wow64RevertWow64FsRedirection(IntPtr ptr);\n\n            [DllImport(\"kernel32.dll\", SetLastError = true, CallingConvention = CallingConvention.Winapi)]\n            [return: MarshalAs(UnmanagedType.Bool)]\n            public static extern bool IsWow64Process(\n                [In] IntPtr processHandle,\n                [Out, MarshalAs(UnmanagedType.Bool)] out bool wow64Process\n            );\n        }\n\n        static ShellIcon()\n        {\n\n        }\n\n        public static Icon GetSmallIcon(string fileName)\n        {\n            return GetIcon(fileName, Win32.SHGFI_SMALLICON);\n        }\n\n        public static Icon GetLargeIcon(string fileName)\n        {\n            return GetIcon(fileName, Win32.SHGFI_LARGEICON);\n        }\n\n        private static Icon GetIcon(string fileName, uint flags)\n        {\n            bool bIsWow64;\n            SHFILEINFO shinfo = new SHFILEINFO();\n\n            // Check if calling process is 32-bit\n            SafeProcessHandle processHandle = System.Diagnostics.Process.GetCurrentProcess().SafeHandle;\n            if (!Win32.IsWow64Process(processHandle.DangerousGetHandle(), out bIsWow64))\n            {\n                return null;\n            }\n            \n            // Force ignoring folder redirection\n            IntPtr OldRedirectionValue = new IntPtr();\n            if (bIsWow64)\n            {\n                Win32.Wow64DisableWow64FsRedirection(ref OldRedirectionValue);\n            }\n        \n            IntPtr hImgSmall = Win32.SHGetFileInfo(fileName, 0, ref shinfo, (uint)Marshal.SizeOf(shinfo), Win32.SHGFI_ICON | flags);\n\n            if (bIsWow64)\n            {\n                Win32.Wow64RevertWow64FsRedirection(OldRedirectionValue);\n            }\n\n            if (hImgSmall == (IntPtr) 0x00)\n            {\n                return null;\n            }\n                   \n            Icon icon = (Icon)System.Drawing.Icon.FromHandle(shinfo.hIcon).Clone();\n            Win32.DestroyIcon(shinfo.hIcon);\n            return icon;\n        }\n    }\n\n    public class ImageToHeaderConverter : IValueConverter\n    {\n        public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)\n        {\n            string Filepath = (string) value;\n            Icon icon = ShellIcon.GetSmallIcon(Filepath);\n\n            if (NativeFile.Exists(Filepath) && (icon != null))\n            {\n                return System.Windows.Interop.Imaging.CreateBitmapSourceFromHIcon(\n                            icon.Handle,\n                            new Int32Rect(0, 0, icon.Width, icon.Height),\n                            BitmapSizeOptions.FromEmptyOptions()); \n            }\n\n            return \"Images/Question.png\";\n        }\n\n        public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)\n        {\n            throw new NotImplementedException();\n        }\n    }\n\n    public class OverlayImageToHeaderConverter : IValueConverter\n    {\n        public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)\n        {\n            ModuleFlag Flags = (ModuleFlag)value;\n\n\t\t\t// ext-ms api are considered optional\n\t\t\tif (((Flags & ModuleFlag.NotFound) != 0) && ((Flags & ModuleFlag.ApiSetExt) == 0))\n\t\t\t{\n\t\t\t\treturn \"Images/InvalidOverlay.png\";\n\t\t\t}\n\n\t\t\tbool DelayLoadModule = (Flags & ModuleFlag.DelayLoad) != 0;\n            if (DelayLoadModule)\n            {\n                return \"Images/HourglassOverlay.png\";\n            }\n\n            // How to handle delay-load + missing import?\n            if ((Flags & ModuleFlag.MissingImports) != 0)\n            {\n                return \"Images/InvalidOverlay.png\";\n            }\n\n            bool ClrAssembly = (Flags & ModuleFlag.ClrReference) != 0;\n            if (ClrAssembly)\n            {\n                return \"Images/ReferenceOverlay.png\";\n            }\n\n\t\t\treturn null;\n\t\t}\n\n        public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)\n        {\n            throw new NotImplementedException();\n        }\n    }\n\n}"
  },
  {
    "path": "DependenciesGui/UserSettings.xaml",
    "content": "﻿<Window x:Class=\"Dependencies.UserSettings\"\n        xmlns=\"http://schemas.microsoft.com/winfx/2006/xaml/presentation\"\n        xmlns:x=\"http://schemas.microsoft.com/winfx/2006/xaml\"\n        xmlns:d=\"http://schemas.microsoft.com/expression/blend/2008\"\n        xmlns:mc=\"http://schemas.openxmlformats.org/markup-compatibility/2006\"\n        xmlns:local=\"clr-namespace:Dependencies\"\n        xmlns:properties=\"clr-namespace:Dependencies.Properties\"\n        xmlns:System=\"clr-namespace:System;assembly=mscorlib\"\n        mc:Ignorable=\"d\"\n        Title=\"UserSettings\"\n        Height=\"400\" Width=\"700\"\n        WindowStartupLocation=\"CenterOwner\">\n    <Window.Resources>\n        <local:TreeBuildingBehaviour x:Key=\"TreeBuildingBehaviourConverter\"/>\n        <local:BinaryCacheOption x:Key=\"BinaryCacheOptionConverter\"/>\n    </Window.Resources>\n    <Grid Margin=\"10 20 20 20\" >\n\n        <Grid.ColumnDefinitions>\n            <ColumnDefinition Width=\"Auto\" />\n            <ColumnDefinition Width=\"*\" />\n        </Grid.ColumnDefinitions>\n\n        <Grid.RowDefinitions>\n            <RowDefinition Height=\"Auto\"/>\n            <RowDefinition Height=\"Auto\"/>\n            <RowDefinition Height=\"Auto\"/>\n            <RowDefinition Height=\"Auto\"/>\n            <RowDefinition Height=\"*\"/>\n            <RowDefinition Height=\"Auto\"/>\n        </Grid.RowDefinitions>\n\n        <Label Margin=\"5\" \n               Grid.Row=\"0\"\n               Grid.Column=\"0\"\n               Content=\"Use BinaryCache:\" \n               HorizontalAlignment=\"Left\" \n               VerticalAlignment=\"Center\" />\n\n        <ComboBox x:Name=\"BinaryCacheCombo\"\n                  Margin=\"5\"\n                  Grid.Row=\"0\"\n                  Grid.Column=\"1\" \n                  SelectedItem=\"{Binding Source={x:Static properties:Settings.Default}, Path=BinaryCacheOptionValue, Mode=OneWay, Converter={StaticResource BinaryCacheOptionConverter}}\"\n                  />\n\n        <!-- Previewer Path selection -->\n        <Label Content=\"Peviewer path:\"\n               Margin=\"5\"\n               Grid.Column=\"0\"\n               Grid.Row=\"1\"\n               HorizontalAlignment=\"Left\" \n               VerticalAlignment=\"Center\" />\n\n        <Grid Margin=\"5\" Grid.Row=\"1\" Grid.Column=\"1\">\n\n            <Grid.ColumnDefinitions>\n                <ColumnDefinition Width=\"*\" />\n                <ColumnDefinition Width=\"Auto\" />\n            </Grid.ColumnDefinitions>\n\n            <TextBox Grid.Column=\"0\"\n                     Text=\"{Binding Source={x:Static properties:Settings.Default}, Path=PeViewerPath, Mode=OneWay}\"\n                     TextWrapping=\"Wrap\" \n                     VerticalContentAlignment=\"Center\" />\n\n            <Button Margin=\"2 0 0 0\"\n                    Grid.Column=\"1\"\n                    Width=\"30\"\n                    Content=\"...\"\n                    Click=\"OnPeviewerPathSettingChange\" />\n        </Grid>\n\n        \n        <!-- Tree build behaviour selection -->\n        <Label Margin=\"5\" \n               Grid.Row=\"2\"\n               Grid.Column=\"0\"\n               Content=\"Tree build behaviour:\" \n               HorizontalAlignment=\"Left\" \n               VerticalAlignment=\"Center\" />\n\n        <ComboBox x:Name=\"TreeBuildCombo\"\n                  Margin=\"5\"\n                  Grid.Row=\"2\"\n                  Grid.Column=\"1\" \n                  SelectedItem=\"{Binding Source={x:Static properties:Settings.Default}, Path=TreeBuildBehaviour, Mode=OneWay, Converter={StaticResource TreeBuildingBehaviourConverter}}\"\n                  />\n\n        <!-- Tree depth -->\n        <Label Margin=\"5\" \n               Grid.Row=\"3\"\n               Grid.Column=\"0\"\n               Content=\"Tree depth:\" \n               HorizontalAlignment=\"Left\" \n               VerticalAlignment=\"Center\" />\n\n        <TextBox  Name=\"TreeDepthValue\"\n                  PreviewTextInput=\"NumericOnly\"\n                  Grid.Row=\"3\"\n                  Grid.Column=\"1\" \n                  Margin=\"5\"\n                  Text=\"{Binding Source={x:Static properties:Settings.Default}, Path=TreeDepth, Mode=OneWay}\"\n                  TextWrapping=\"Wrap\" \n                  VerticalContentAlignment=\"Center\" />\n\n\n        <!-- Font family selection -->\n        <Label Margin=\"5\"\n               Grid.Row=\"4\"\n               Grid.Column=\"0\"\n               Content=\"Font family:\" \n               HorizontalAlignment=\"Left\" \n               VerticalAlignment=\"Top\" />\n\n        <ListBox Name=\"FontFamilyList\"\n                 Margin=\"5\"\n                 Grid.Row=\"4\"\n                 Grid.Column=\"1\" />\n        \n        \n        <!-- Buttons -->\n        <StackPanel Grid.Row=\"5\" Grid.Column=\"1\" \n                    Orientation=\"Horizontal\" HorizontalAlignment=\"Right\">\n            <Button Content=\"Cancel\" \n                    Height=\"20\"\n                    Width=\"60\"\n                    Margin=\"2\"\n                    Padding=\"2\"\n                    Click=\"OnCancel\" />\n\n            <Button Content=\"OK\" \n                    Height=\"20\"\n                    Width=\"60\"\n                    Margin=\"2\"\n                    Padding=\"2\"\n                    Click=\"OnValidate\" />\n        </StackPanel>\n\n    </Grid>\n</Window>\n"
  },
  {
    "path": "DependenciesGui/UserSettings.xaml.cs",
    "content": "﻿using System;\nusing System.Windows;\nusing System.Windows.Forms;\nusing System.Collections.Generic;\nusing System.Windows.Media;\nusing System.Windows.Controls;\nusing System.Windows.Documents;\nusing System.Globalization;\nusing System.Windows.Markup;\n\nnamespace Dependencies\n{\n    internal static class NameDictionaryHelper\n    {\n        public static string GetDisplayName(LanguageSpecificStringDictionary nameDictionary)\n        {\n            // Look up the display name based on the UI culture, which is the same culture\n            // used for resource loading.\n            XmlLanguage userLanguage = XmlLanguage.GetLanguage(CultureInfo.CurrentUICulture.IetfLanguageTag);\n\n            // Look for an exact match.\n            string name;\n            if (nameDictionary.TryGetValue(userLanguage, out name))\n            {\n                return name;\n            }\n\n            // No exact match; return the name for the most closely related language.\n            int bestRelatedness = -1;\n            string bestName = string.Empty;\n\n            foreach (KeyValuePair<XmlLanguage, string> pair in nameDictionary)\n            {\n                int relatedness = GetRelatedness(pair.Key, userLanguage);\n                if (relatedness > bestRelatedness)\n                {\n                    bestRelatedness = relatedness;\n                    bestName = pair.Value;\n                }\n            }\n\n            return bestName;\n        }\n\n        public static string GetDisplayName(IDictionary<CultureInfo, string> nameDictionary)\n        {\n            // Look for an exact match.\n            string name;\n            if (nameDictionary.TryGetValue(CultureInfo.CurrentUICulture, out name))\n            {\n                return name;\n            }\n\n            // No exact match; return the name for the most closely related language.\n            int bestRelatedness = -1;\n            string bestName = string.Empty;\n\n            XmlLanguage userLanguage = XmlLanguage.GetLanguage(CultureInfo.CurrentUICulture.IetfLanguageTag);\n\n            foreach (KeyValuePair<CultureInfo, string> pair in nameDictionary)\n            {\n                int relatedness = GetRelatedness(XmlLanguage.GetLanguage(pair.Key.IetfLanguageTag), userLanguage);\n                if (relatedness > bestRelatedness)\n                {\n                    bestRelatedness = relatedness;\n                    bestName = pair.Value;\n                }\n            }\n\n            return bestName;\n        }\n\n        private static int GetRelatedness(XmlLanguage keyLang, XmlLanguage userLang)\n        {\n            try\n            {\n                // Get equivalent cultures.\n                CultureInfo keyCulture = CultureInfo.GetCultureInfoByIetfLanguageTag(keyLang.IetfLanguageTag);\n                CultureInfo userCulture = CultureInfo.GetCultureInfoByIetfLanguageTag(userLang.IetfLanguageTag);\n                if (!userCulture.IsNeutralCulture)\n                {\n                    userCulture = userCulture.Parent;\n                }\n\n                // If the key is a prefix or parent of the user language it's a good match.\n                if (IsPrefixOf(keyLang.IetfLanguageTag, userLang.IetfLanguageTag) || userCulture.Equals(keyCulture))\n                {\n                    return 2;\n                }\n\n                // If the key and user language share a common prefix or parent neutral culture, it's a reasonable match.\n                if (IsPrefixOf(TrimSuffix(userLang.IetfLanguageTag), keyLang.IetfLanguageTag) || userCulture.Equals(keyCulture.Parent))\n                {\n                    return 1;\n                }\n            }\n            catch (ArgumentException)\n            {\n                // Language tag with no corresponding CultureInfo.\n            }\n\n            // They're unrelated languages.\n            return 0;\n        }\n\n        private static string TrimSuffix(string tag)\n        {\n            int i = tag.LastIndexOf('-');\n            if (i > 0)\n            {\n                return tag.Substring(0, i);\n            }\n            else\n            {\n                return tag;\n            }\n        }\n\n        private static bool IsPrefixOf(string prefix, string tag)\n        {\n            return prefix.Length < tag.Length &&\n                tag[prefix.Length] == '-' &&\n                string.CompareOrdinal(prefix, 0, tag, 0, prefix.Length) == 0;\n        }\n    }\n\n    internal class FontFamilyListItem : TextBlock, IComparable\n    {\n        private string _displayName;\n\n        public FontFamilyListItem(FontFamily fontFamily)\n        {\n            _displayName = GetDisplayName(fontFamily);\n\n            this.FontFamily = fontFamily;\n            this.Text = _displayName;\n            this.ToolTip = _displayName;\n\n            // In the case of symbol font, apply the default message font to the text so it can be read.\n            if (IsSymbolFont(fontFamily))\n            {\n                TextRange range = new TextRange(this.ContentStart, this.ContentEnd);\n                range.ApplyPropertyValue(TextBlock.FontFamilyProperty, SystemFonts.MessageFontFamily);\n            }\n        }\n\n        public override string ToString()\n        {\n            return _displayName;\n        }\n\n        int IComparable.CompareTo(object obj)\n        {\n            return string.Compare(_displayName, obj.ToString(), true, CultureInfo.CurrentCulture);\n        }\n\n        internal static bool IsSymbolFont(FontFamily fontFamily)\n        {\n            foreach (Typeface typeface in fontFamily.GetTypefaces())\n            {\n                GlyphTypeface face;\n                if (typeface.TryGetGlyphTypeface(out face))\n                {\n                    return face.Symbol;\n                }\n            }\n            return false;\n        }\n\n        internal static string GetDisplayName(FontFamily family)\n        {\n            return NameDictionaryHelper.GetDisplayName(family.FamilyNames);\n        }\n    }\n\n    public partial class UserSettings : Window\n    {\n        private string PeviewerPath;\n        private ICollection<FontFamily> _familyCollection;          // see FamilyCollection property\n        private FontFamily SelectedFontFamily;\n\n        public UserSettings()\n        {\n            InitializeComponent();\n\n            TreeBuildCombo.ItemsSource = Enum.GetValues(typeof(TreeBuildingBehaviour.DependencyTreeBehaviour));\n            BinaryCacheCombo.ItemsSource = Enum.GetValues(typeof(BinaryCacheOption.BinaryCacheOptionValue));\n            PeviewerPath = Dependencies.Properties.Settings.Default.PeViewerPath;\n\n        }\n\n        protected override void OnInitialized(EventArgs e)\n        {\n            base.OnInitialized(e);\n            InitializeFontFamilyList();\n\n            SelectedFontFamily = new FontFamily(Dependencies.Properties.Settings.Default.Font);\n            SelectListItem(FontFamilyList, FontFamilyListItem.GetDisplayName(SelectedFontFamily));\n            FontFamilyList.SelectionChanged += new SelectionChangedEventHandler(fontFamilyList_SelectionChanged);\n            \n        }\n\n        private void OnCancel(object sender, RoutedEventArgs e)\n        {\n            this.Close();\n        }\n\n        private void OnValidate(object sender, RoutedEventArgs e)\n        {\n            // Update defaults\n            Dependencies.Properties.Settings.Default.PeViewerPath = PeviewerPath;\n\n\t\t\tint TreeDepth = Dependencies.Properties.Settings.Default.TreeDepth;\n\t\t\tif (Int32.TryParse(TreeDepthValue.Text, out TreeDepth))\n\t\t\t{\n\t\t\t\tDependencies.Properties.Settings.Default.TreeDepth = TreeDepth;\n\t\t\t}\n\t\t\t\n\n\t\t\tif (TreeBuildCombo.SelectedItem != null)\n            {\n                Dependencies.Properties.Settings.Default.TreeBuildBehaviour = TreeBuildCombo.SelectedItem.ToString();\n            }\n\n            if (BinaryCacheCombo.SelectedItem != null)\n            {\n                bool newValue = (bool) (new BinaryCacheOption()).ConvertBack(BinaryCacheCombo.SelectedItem, null, null, null);\n\n                if (Dependencies.Properties.Settings.Default.BinaryCacheOptionValue != newValue)\n                {\n                    System.Windows.MessageBox.Show(\"The binary caching preference has been modified, you need to restart Dependencies for the modifications to be actually reloaded.\");\n                }\n\n                Dependencies.Properties.Settings.Default.BinaryCacheOptionValue = newValue;\n            }\n\n\n            Dependencies.Properties.Settings.Default.Font = FontFamilyListItem.GetDisplayName(SelectedFontFamily);\n            this.Close();\n        }\n\n        private bool SelectListItem(System.Windows.Controls.ListBox list, object value)\n        {\n            ItemCollection itemList = list.Items;\n\n            // Perform a binary search for the item.\n            int first = 0;\n            int limit = itemList.Count;\n\n            while (first < limit)\n            {\n                int i = first + (limit - first) / 2;\n                IComparable item = (IComparable)(itemList[i]);\n                int comparison = item.CompareTo(value);\n                if (comparison < 0)\n                {\n                    // Value must be after i\n                    first = i + 1;\n                }\n                else if (comparison > 0)\n                {\n                    // Value must be before i\n                    limit = i;\n                }\n                else\n                {\n                    // Exact match; select the item.\n                    list.SelectedIndex = i;\n                    itemList.MoveCurrentToPosition(i);\n                    list.ScrollIntoView(itemList[i]);\n                    return true;\n                }\n            }\n\n            // Not an exact match; move current position to the nearest item but don't select it.\n            if (itemList.Count > 0)\n            {\n                int i = Math.Min(first, itemList.Count - 1);\n                itemList.MoveCurrentToPosition(i);\n                list.ScrollIntoView(itemList[i]);\n            }\n\n            return false;\n        }\n\n        public ICollection<FontFamily> FontFamilyCollection\n        {\n            get\n            {\n                return (_familyCollection == null) ? Fonts.SystemFontFamilies : _familyCollection;\n            }\n\n            set\n            {\n                if (value != _familyCollection)\n                {\n                    _familyCollection = value;\n                }\n            }\n        }\n\n        private void fontFamilyList_SelectionChanged(object sender, SelectionChangedEventArgs e)\n        {\n            FontFamilyListItem item = FontFamilyList.SelectedItem as FontFamilyListItem;\n            if (item != null)\n            {\n                SelectedFontFamily = item.FontFamily;\n            }\n        }\n\n        private void InitializeFontFamilyList()\n        {\n            ICollection<FontFamily> familyCollection = FontFamilyCollection;\n            if (familyCollection != null)\n            {\n                FontFamilyListItem[] items = new FontFamilyListItem[familyCollection.Count];\n\n                int i = 0;\n\n                foreach (FontFamily family in familyCollection)\n                {\n                    items[i++] = new FontFamilyListItem(family);\n                }\n\n                Array.Sort<FontFamilyListItem>(items);\n\n                foreach (FontFamilyListItem item in items)\n                {\n                    FontFamilyList.Items.Add(item);\n                }\n            }\n        }\n\n        private void OnPeviewerPathSettingChange(object sender, RoutedEventArgs e)\n        {\n            string programPath = Dependencies.Properties.Settings.Default.PeViewerPath;\n\n            OpenFileDialog InputFileNameDlg = new OpenFileDialog()\n            {\n                Filter = \"exe files (*.exe, *.dll)| *.exe;*.dll; | All files (*.*)|*.*\",\n                FilterIndex = 0,\n                RestoreDirectory = true,\n                InitialDirectory = System.IO.Path.GetDirectoryName(programPath)\n            };\n\n\n            if (InputFileNameDlg.ShowDialog() != System.Windows.Forms.DialogResult.OK)\n                return;\n\n            PeviewerPath = InputFileNameDlg.FileName;\n        }\n\n\t\tprivate void NumericOnly(System.Object sender, System.Windows.Input.TextCompositionEventArgs e)\n\t\t{\n\t\t\te.Handled = IsTextNumeric(e.Text);\n\n\t\t}\n\n\t\tprivate static bool IsTextNumeric(string str)\n\t\t{\n\t\t\tSystem.Text.RegularExpressions.Regex reg = new System.Text.RegularExpressions.Regex(\"[^0-9]+\");\n\t\t\treturn reg.IsMatch(str);\n\n\t\t}\n\t}\n\n}\n"
  },
  {
    "path": "DependenciesGui/packages.config",
    "content": "﻿<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<packages>\n  <package id=\"Mono.Cecil\" version=\"0.11.4\" targetFramework=\"net461\" />\n</packages>"
  },
  {
    "path": "DependenciesLib/BinaryCache.cs",
    "content": "﻿using System;\nusing System.Collections.Generic;\nusing System.IO;\nusing System.Diagnostics;\nusing Dependencies.ClrPh;\nusing System.ComponentModel;\n\nnamespace Dependencies\n{\n   \n    /// <summary>\n    /// Application wide PE cache on disk. This is used to solve the issue of phlib mapping\n    /// analyzed binaries in memory and thus locking those in the filesystem (https://github.com/lucasg/Dependencies/issues/9).\n    /// The BinaryCache copy every PE the application wants to open in a special folder in LocalAppData\n    /// and open this one instead, prevent the original file from being locked.\n    /// </summary>\n    public abstract class BinaryCache\n    {\n        #region Singleton implementation\n        private static BinaryCache SingletonInstance;\n        \n        /// <summary>\n        /// Singleton implemenation for the BinaryCache. This class must be \n        /// visible and unique throughout the whole application in order to be efficient.\n        /// </summary>\n        public static BinaryCache Instance\n        {\n            get\n            {\n                return SingletonInstance;\n            }\n            set\n            {\n                SingletonInstance = value;\n            }\n        }\n\n\t\tpublic static void InitializeBinaryCache(bool UseCache)\n\t\t{\n\t\t\tif (UseCache)\n\t\t\t{\n\t\t\t\tstring ApplicationLocalAppDataPath = Path.Combine(\n\t\t\t\t   Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData),\n\t\t\t\t   \"Dependencies\"\n\t\t\t   );\n\t\t\t\tInstance = new BinaryCacheImpl(ApplicationLocalAppDataPath, 200);\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\tInstance = new BinaryNoCacheImpl();\n\t\t\t}\n\n\t\t\tInstance.Load();\n\t\t}\n        #endregion Singleton implementation\n\n        #region PublicAPI\n        \n        /// <summary>\n        /// Ask the BinaryCache to load a PE from the filesystem. The\n        /// whole cache magic is hidden underneath\n        /// \n        /// </summary>\n        /// <param name=\"PePath\"> Path to desired PE file.</param>\n        /// <returns>\n        ///     return null if the file is not found\n        ///     return PE.LoadSuccessful == false if the file exists but it's not a valid PE file\n        /// </returns>\n        public static PE LoadPe(string PePath)\n        {\n            return Instance.GetBinary(PePath);\n        }\n\n\t\tpublic static Tuple<ModuleSearchStrategy, PE> ResolveModule(string ModuleName)\n\t\t{\n\t\t\tPE RootPe = LoadPe(Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.Windows), \"ntdll.dll\"));\n\t\t\tstring WorkingDirectory = Path.GetDirectoryName(RootPe.Filepath);\n\t\t\tList<string> CustomSearchFolders = new List<string>();\n\t\t\tSxsEntries SxsCache = SxsManifest.GetSxsEntries(RootPe);\n\n\t\t\treturn ResolveModule(RootPe, ModuleName, SxsCache, CustomSearchFolders, WorkingDirectory);\n\t\t}\n\n\t\tpublic static Tuple<ModuleSearchStrategy, PE> ResolveModule(PE RootPe, string ModuleName)\n\t\t{\n\t\t\tstring WorkingDirectory = Path.GetDirectoryName(RootPe.Filepath);\n\t\t\tList<string> CustomSearchFolders = new List<string>();\n\t\t\tSxsEntries SxsCache = SxsManifest.GetSxsEntries(RootPe);\n\n\t\t\treturn ResolveModule(RootPe, ModuleName, SxsCache, CustomSearchFolders, WorkingDirectory);\n\t\t}\n\n\n\t\tpublic static Tuple<ModuleSearchStrategy, PE> ResolveModule(PE RootPe, string ModuleName, SxsEntries SxsCache, List<string> CustomSearchFolders, string WorkingDirectory)\n        {\n            Tuple<ModuleSearchStrategy, string> ResolvedFilepath;\n\n            // if no extension is used, assume a .dll\n            if (Path.GetExtension(ModuleName) == String.Empty)\n            {\n                ModuleName = String.Format(\"{0:s}.dll\", ModuleName);\n            }\n\n            string ApiSetName = LookupApiSetLibrary(ModuleName);\n            if (!string.IsNullOrEmpty(ApiSetName))\n            {\n                ModuleName = ApiSetName;\n            }\n\n            ResolvedFilepath = FindPe.FindPeFromDefault(RootPe, ModuleName, SxsCache, CustomSearchFolders, WorkingDirectory);\n\n            // ApiSet override the underneath search location if found or not\n            ModuleSearchStrategy ModuleLocation = ResolvedFilepath.Item1;\n            if (!string.IsNullOrEmpty(ApiSetName) /*&& (ResolvedFilepath.Item2 != null)*/)\n                ModuleLocation = ModuleSearchStrategy.ApiSetSchema;\n\n            // \n            PE ResolvedModule = null;\n            if (ResolvedFilepath.Item2 != null)\n                ResolvedModule = LoadPe(ResolvedFilepath.Item2);\n\n\n            return new Tuple<ModuleSearchStrategy, PE>(ModuleLocation, ResolvedModule);\n        }\n\n\n        private static ApiSetSchema ApiSetmapCache = Phlib.GetApiSetSchema();\n\n        /// <summary>\n        /// Attempt to query the HostDll pointed by the Apiset contract.\n        /// </summary>\n        /// <param name=\"ImportDllName\"> DLL name as in the parent import entry. May or may not be an apiset contract </param>\n        /// <returns> Return the first host dll pointed by the apiset contract if found, otherwise it return an empty string.</returns>\n        public static string LookupApiSetLibrary(string ImportDllName)\n        {\n            // Look for api set target \n            if (!ImportDllName.StartsWith(\"api-\", StringComparison.CurrentCultureIgnoreCase) && !ImportDllName.StartsWith(\"ext-\", StringComparison.CurrentCultureIgnoreCase))\n                return \"\";\n\n           \n            // Strip the .dll extension and search for matching targets\n            var ImportDllWIthoutExtension = Path.GetFileNameWithoutExtension(ImportDllName);\n            var Targets = ApiSetmapCache.Lookup(ImportDllWIthoutExtension);\n            if ((Targets != null) && (Targets.Count > 0))\n                return Targets[0];\n\n            return \"\";\n        }\n\n        public static bool LookupImport(string ModuleFilePath, string ImportName, int ImportOrdinal, bool ImportByOrdinal)\n        {\n            if (ModuleFilePath == null)\n                return false;\n\n            string ApiSetName = LookupApiSetLibrary(ModuleFilePath);\n            if (!string.IsNullOrEmpty(ApiSetName))\n            {\n                ModuleFilePath = ApiSetName;\n            }\n\n            PE Module = LoadPe(ModuleFilePath);\n            if (Module == null)\n                return false;\n\n            foreach (var export in Module.GetExports())\n            {\n                if (ImportByOrdinal)\n                {\n                    if ((export.Ordinal == ImportOrdinal) && export.ExportByOrdinal)\n                        return true;\n                }\n                else\n                {\n                    if (export.ForwardedName == ImportName)\n                        return true;\n\n                    if (export.Name == ImportName)\n                        return true;\n\n                }\n                \n            }\n\n            return false;\n        }\n\n\t\tpublic static List<Tuple<PeImport, bool>> LookupImports(PeImportDll ParentImports, List<PeExport> ModuleExports)\n\t\t{\n\t\t\tList<Tuple<PeImport, bool>> Result = new List<Tuple<PeImport, bool>>();\n\n\t\t\tforeach (PeImport Import in ParentImports.ImportList)\n\t\t\t{\n\t\t\t\tbool bFoundImport = false;\n\n\t\t\t\tforeach (var export in ModuleExports)\n\t\t\t\t{\n\t\t\t\t\tif (Import.ImportByOrdinal)\n\t\t\t\t\t{\n                        // Even if the export has a Name (therefore not a pure export by ordinal) \n                        // we can still possibly import it by its ordinal, although it's not recommended.\n\t\t\t\t\t\tif ((export.Ordinal == Import.Ordinal) /*&& export.ExportByOrdinal*/)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tbFoundImport = true;\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t}\n\n\t\t\t\t\t}\n\t\t\t\t\telse\n\t\t\t\t\t{\n\t\t\t\t\t\tif (export.ForwardedName == Import.Name)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tbFoundImport = true;\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t}\n\n\n\t\t\t\t\t\tif (export.Name == Import.Name)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tbFoundImport = true;\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t}\n\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tResult.Add(new Tuple<PeImport, bool>(Import, bFoundImport));\n\t\t\t}\n\n\t\t\treturn Result;\n\t\t}\n\n\t\tpublic static List<Tuple<PeImport, bool>> LookupImports(PeImportDll ModuleImport, string ModuleFilePath)\n        {\n\t\t\tPE Module = null;\n\t\t\tList<Tuple<PeImport, bool>> Result = new List<Tuple<PeImport, bool>>();\n\n            // if there is a module name, try to resolve apiset for attempting to load it\n\t\t\tif (ModuleFilePath != null)\n            { \n                string ApiSetName = LookupApiSetLibrary(ModuleFilePath);\n\t\t\t    if (!string.IsNullOrEmpty(ApiSetName))\n\t\t\t    {\n\t\t\t\t    Module = ResolveModule(ApiSetName).Item2;\n                }\n\t\t\t    else\n\t\t\t    {\n\t\t\t\t    Module = LoadPe(ModuleFilePath);\n\t\t\t    }\n            }\n\n            // If the module has not been found, mark all imports as not found\n            if (Module == null)\n            {\n                foreach (PeImport Import in ModuleImport.ImportList)\n                {\n                    Result.Add(new Tuple<PeImport, bool>(Import, false));\n                }\n\n                return Result;\n            }\n\n\t\t\treturn LookupImports(ModuleImport, Module.GetExports());\n\n\t\t}\n\n        #endregion PublicAPI\n\n\n\n        #region constructors\n        #endregion constructors\n\n        #region Contract\n\n        // Attempt to load a file as a PE\n        public abstract PE GetBinary(string PePath);\n\n        // static initialization => warmup\n        public abstract void Load();\n\n        // Graceful cleanup\n        public abstract void Unload();\n\n        #endregion Contract\n\n\n        #region Members\n        #endregion Members\n    }\n\n    public class BinaryCacheImpl :  BinaryCache\n    {\n        public BinaryCacheImpl(string ApplicationAppDataPath, int _MaxBinaryCount)\n        {\n\n            BinaryDatabase = new Dictionary<string, PE>();\n            FilepathDatabase = new Dictionary<string, PE>();\n            BinaryDatabaseLock = new Object();\n            LruCache = new List<string>();\n\n            MaxBinaryCount = _MaxBinaryCount;\n            string platform = (IntPtr.Size == 8) ? \"x64\" : \"x86\";\n\n            BinaryCacheFolderPath = Path.Combine(ApplicationAppDataPath, \"BinaryCache\", platform);\n            Directory.CreateDirectory(BinaryCacheFolderPath);\n        }\n\n        public override void Load()\n        {\n            // \"warm up\" the cache\n            foreach (var CachedBinary in Directory.EnumerateFiles(BinaryCacheFolderPath))\n            {\n                GetBinaryAsync(CachedBinary);\n            }\n\n            string System32Folder = Environment.GetFolderPath(Environment.SpecialFolder.System);\n            string SysWow64Folder = Environment.GetFolderPath(Environment.SpecialFolder.SystemX86);\n\n            // wow64.dll, wow64cpu.dll and wow64win.dll are listed as wow64 known dlls,\n            // but they are actually x64 binaries.\n            List<String> Wow64Dlls = new List<string>(new string[] {\n                    \"wow64.dll\",\n                    \"wow64cpu.dll\",\n                    \"wow64win.dll\"\n                });\n\n            // preload all well known dlls\n            foreach (String KnownDll in Phlib.GetKnownDlls(false))\n            {\n                GetBinaryAsync(Path.Combine(System32Folder, KnownDll));\n            }\n\n            foreach (String KnownDll in Phlib.GetKnownDlls(true))\n            {\n                if (Wow64Dlls.Contains(KnownDll))\n                {\n                    GetBinaryAsync(Path.Combine(System32Folder, KnownDll));\n                }\n                else\n                {\n                    GetBinaryAsync(Path.Combine(SysWow64Folder, KnownDll));\n                }\n\n            }\n\n        }\n\n        public override void Unload()\n        {\n            // cut off the LRU cache\n            LruCache = LruCache.GetRange(0, Math.Min(LruCache.Count, MaxBinaryCount));\n\n            foreach (var CachedBinary in Directory.EnumerateFiles(BinaryCacheFolderPath))\n            {\n                string PeHash = GetBinaryHash(CachedBinary);\n\n                if (LruCache.Find(Hash => (Hash == PeHash)) == null)\n                {\n                    // Force map unloading before deleting file\n                    if (BinaryDatabase.ContainsKey(PeHash))\n                    {\n                        BinaryDatabase[PeHash].Unload();\n                    }\n\n                    try\n                    {\n                        File.Delete(CachedBinary);\n                    }\n                    catch (System.UnauthorizedAccessException uae)\n                    {\n                        // The BinaryCache is shared among serveral Dependencies.exe instance\n                        // so only the last one alive can clear the cache.\n                        Debug.WriteLine(\"[BinaryCache] Could not unload file {0:s} : {1:s} \", CachedBinary, uae);\n                    }\n\n                }\n            }\n\n\n            // flush the cache\n            BinaryDatabase.Clear();\n            FilepathDatabase.Clear();\n        }\n\n        public void GetBinaryAsync(string PePath, RunWorkerCompletedEventHandler Callback = null)\n        {\n            BackgroundWorker bw = new BackgroundWorker();\n            bw.DoWork += (sender, e) => {\n\n                GetBinary(PePath);\n            };\n\n            if (Callback != null)\n            {\n                bw.RunWorkerCompleted += Callback;\n            }\n\n\n            bw.RunWorkerAsync();\n        }\n\n        public override PE GetBinary(string PePath)\n        {\n            //Debug.WriteLine(String.Format(\"Attempt to load : {0:s}\", PePath), \"BinaryCache\");\n\n            if (!NativeFile.Exists(PePath))\n            {\n                Debug.WriteLine(String.Format(\"File not present on the filesystem : {0:s} \", PePath), \"BinaryCache\");\n                return null;\n            }\n\n            string Fullpath = Path.GetFullPath(PePath);\n            if (FilepathDatabase.ContainsKey(Fullpath))\n            {\n                // TODO : update LRU cache\n                PE sShadowBinary = FilepathDatabase[Fullpath];\n                sShadowBinary.Filepath = Fullpath;\n                return sShadowBinary;\n            }\n\n            string PeHash = GetBinaryHash(PePath);\n            //Debug.WriteLine(String.Format(\"File {0:s} hash : {1:s} \", PePath, PeHash), \"BinaryCache\");\n\n            // A sync lock is mandatory here in order not to load twice the\n            // same binary from two differents workers\n            lock (BinaryDatabaseLock)\n            {\n                bool hit = BinaryDatabase.ContainsKey(PeHash);\n\n                // Cache \"miss\"\n                if (!hit)\n                {\n\n                    string DestFilePath = Path.Combine(BinaryCacheFolderPath, PeHash);\n                    if (!File.Exists(DestFilePath) && (DestFilePath != PePath))\n                    {\n                        // Debug.WriteLine(String.Format(\"FileCopy from {0:s} to {1:s}\", PePath, DestFilePath), \"BinaryCache\");\n                        NativeFile.Copy(PePath, DestFilePath);\n                    }\n\n                    PE NewShadowBinary = new PE(DestFilePath);\n                    NewShadowBinary.Load();\n\n                    LruCache.Add(PeHash);\n                    BinaryDatabase.Add(PeHash, NewShadowBinary);\n                    FilepathDatabase.Add(Fullpath, NewShadowBinary);\n                }\n            }\n\n            // Cache \"Hit\"\n            UpdateLru(PeHash);\n            PE ShadowBinary = BinaryDatabase[PeHash];\n            ShadowBinary.Filepath = Path.GetFullPath(PePath); // convert any paths to an absolute one.\n\n            Debug.WriteLine(String.Format(\"File {0:s} loaded from {1:s}\", PePath, Path.Combine(BinaryCacheFolderPath, PeHash)), \"BinaryCache\");\n            return ShadowBinary;\n        }\n\n        protected string GetBinaryHash(string PePath)\n        {\n            return NativeFile.GetPartialHashFile(PePath, 1024);\n        }\n\n        protected void UpdateLru(string PeHash)\n        {\n            string MatchingHash = LruCache.Find(Hash => (Hash == PeHash));\n            if (null == MatchingHash)\n                return;\n\n            lock (BinaryDatabaseLock)\n            {\n                // prepend the matching item at the beginning of the list\n                LruCache.Remove(MatchingHash);\n                LruCache.Insert(0, MatchingHash);\n            }\n        }\n\n        #region Members\n        private List<string> LruCache;\n        private Dictionary<string, PE> BinaryDatabase;\n        private Dictionary<string, PE> FilepathDatabase;\n        private Object BinaryDatabaseLock;\n\n        private string BinaryCacheFolderPath;\n        private int MaxBinaryCount;\n\n        #endregion Members\n    }\n\n\n    public class BinaryNoCacheImpl : BinaryCache\n    {\n        public override PE GetBinary(string PePath)\n        {\n            PE pefile = new PE(PePath);\n            pefile.Load();\n\n            return pefile;\n        }\n\n        // static initialization => warmup\n        public override void Load()\n        {\n\n        }\n\n        // Graceful cleanup\n        public override void Unload()\n        {\n\n        }\n    }\n}\n\n"
  },
  {
    "path": "DependenciesLib/DependenciesLib.csproj",
    "content": "﻿<?xml version=\"1.0\" encoding=\"utf-8\"?>\r\n<Project ToolsVersion=\"15.0\" xmlns=\"http://schemas.microsoft.com/developer/msbuild/2003\">\r\n  <Import Project=\"$(MSBuildExtensionsPath)\\$(MSBuildToolsVersion)\\Microsoft.Common.props\" Condition=\"Exists('$(MSBuildExtensionsPath)\\$(MSBuildToolsVersion)\\Microsoft.Common.props')\" />\r\n  <PropertyGroup>\r\n    <Configuration Condition=\" '$(Configuration)' == '' \">Debug</Configuration>\r\n    <Platform Condition=\" '$(Platform)' == '' \">AnyCPU</Platform>\r\n    <ProjectGuid>{4A459493-14FC-4C87-9254-60E0959535DA}</ProjectGuid>\r\n    <OutputType>Library</OutputType>\r\n    <AppDesignerFolder>Properties</AppDesignerFolder>\r\n    <RootNamespace>Dependencies</RootNamespace>\r\n    <AssemblyName>DependenciesLib</AssemblyName>\r\n    <TargetFrameworkVersion>v4.6.1</TargetFrameworkVersion>\r\n    <FileAlignment>512</FileAlignment>\r\n  </PropertyGroup>\r\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)' == 'Debug|x86'\">\r\n    <DebugSymbols>true</DebugSymbols>\r\n    <OutputPath>$(SolutionDir)bin\\$(Configuration)$(Platform)</OutputPath>\r\n    <IntermediateOutputPath>$(SolutionDir)obj\\$(ProjectName)\\$(Configuration)$(Platform)</IntermediateOutputPath>\r\n    <DefineConstants>DEBUG;TRACE</DefineConstants>\r\n    <DebugType>full</DebugType>\r\n    <PlatformTarget>x86</PlatformTarget>\r\n    <ErrorReport>prompt</ErrorReport>\r\n    <CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>\r\n  </PropertyGroup>\r\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)' == 'Release|x86'\">\r\n    <OutputPath>$(SolutionDir)bin\\$(Configuration)$(Platform)</OutputPath>\r\n    <IntermediateOutputPath>$(SolutionDir)obj\\$(ProjectName)\\$(Configuration)$(Platform)</IntermediateOutputPath>\r\n    <DefineConstants>TRACE</DefineConstants>\r\n    <Optimize>true</Optimize>\r\n    <DebugType>pdbonly</DebugType>\r\n    <PlatformTarget>x86</PlatformTarget>\r\n    <ErrorReport>prompt</ErrorReport>\r\n    <CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>\r\n  </PropertyGroup>\r\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)' == 'Debug|x64'\">\r\n    <DebugSymbols>true</DebugSymbols>\r\n    <OutputPath>$(SolutionDir)bin\\$(Configuration)$(Platform)</OutputPath>\r\n    <IntermediateOutputPath>$(SolutionDir)obj\\$(ProjectName)\\$(Configuration)$(Platform)</IntermediateOutputPath>\r\n    <DefineConstants>DEBUG;TRACE</DefineConstants>\r\n    <DebugType>full</DebugType>\r\n    <PlatformTarget>x64</PlatformTarget>\r\n    <ErrorReport>prompt</ErrorReport>\r\n    <CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>\r\n  </PropertyGroup>\r\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)' == 'Release|x64'\">\r\n    <OutputPath>$(SolutionDir)bin\\$(Configuration)$(Platform)</OutputPath>\r\n    <IntermediateOutputPath>$(SolutionDir)obj\\$(ProjectName)\\$(Configuration)$(Platform)</IntermediateOutputPath>\r\n    <DefineConstants>TRACE</DefineConstants>\r\n    <Optimize>true</Optimize>\r\n    <DebugType>pdbonly</DebugType>\r\n    <PlatformTarget>x64</PlatformTarget>\r\n    <ErrorReport>prompt</ErrorReport>\r\n    <CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>\r\n  </PropertyGroup>\r\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)' == 'Appx|x86'\">\r\n    <OutputPath>$(SolutionDir)bin\\$(Configuration)$(Platform)</OutputPath>\r\n    <IntermediateOutputPath>$(SolutionDir)obj\\$(ProjectName)\\$(Configuration)$(Platform)</IntermediateOutputPath>\r\n    <DefineConstants>TRACE</DefineConstants>\r\n    <Optimize>true</Optimize>\r\n    <DebugType>pdbonly</DebugType>\r\n    <PlatformTarget>x86</PlatformTarget>\r\n    <ErrorReport>prompt</ErrorReport>\r\n    <CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>\r\n  </PropertyGroup>\r\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)' == 'Appx|x64'\">\r\n    <OutputPath>$(SolutionDir)bin\\$(Configuration)$(Platform)</OutputPath>\r\n    <IntermediateOutputPath>$(SolutionDir)obj\\$(ProjectName)\\$(Configuration)$(Platform)</IntermediateOutputPath>\r\n    <DefineConstants>TRACE</DefineConstants>\r\n    <Optimize>true</Optimize>\r\n    <DebugType>pdbonly</DebugType>\r\n    <PlatformTarget>x64</PlatformTarget>\r\n    <ErrorReport>prompt</ErrorReport>\r\n    <CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>\r\n  </PropertyGroup>\r\n  <ItemGroup>\r\n    <Reference Include=\"System\" />\r\n    <Reference Include=\"System.Core\" />\r\n    <Reference Include=\"System.Xml.Linq\" />\r\n    <Reference Include=\"System.Data.DataSetExtensions\" />\r\n    <Reference Include=\"Microsoft.CSharp\" />\r\n    <Reference Include=\"System.Data\" />\r\n    <Reference Include=\"System.Net.Http\" />\r\n    <Reference Include=\"System.Xml\" />\r\n  </ItemGroup>\r\n  <ItemGroup>\r\n    <Compile Include=\"BinaryCache.cs\" />\r\n    <Compile Include=\"FindPeModule.cs\" />\r\n    <Compile Include=\"SxsManifest.cs\" />\r\n    <Compile Include=\"Properties\\AssemblyInfo.cs\" />\r\n  </ItemGroup>\r\n  <ItemGroup>\r\n    <ProjectReference Include=\"..\\ClrPhlib\\ClrPhlib.vcxproj\">\r\n      <Project>{fc5ffcaf-982f-4a95-8fa6-2a95b1f7cdc8}</Project>\r\n      <Name>ClrPhlib</Name>\r\n    </ProjectReference>\r\n  </ItemGroup>\r\n  <Import Project=\"$(MSBuildToolsPath)\\Microsoft.CSharp.targets\" />\r\n</Project>"
  },
  {
    "path": "DependenciesLib/FindPeModule.cs",
    "content": "using System;\nusing System.IO;\nusing System.Collections.Generic;\nusing System.Linq;\nusing System.Diagnostics;\n\nusing Dependencies.ClrPh;\n\nnamespace Dependencies\n{\n    public enum ModuleSearchStrategy\n    {\n        ROOT = -1,\n\n        SxS = 0,\n        ApiSetSchema = 1,\n        WellKnownDlls = 2,\n        ApplicationDirectory = 3,\n        System32Folder = 4,\n        WindowsFolder = 5,\n        WorkingDirectory = 6,\n        Environment = 7,\n        AppInitDLL = 8,\n        Fullpath = 9,\n        ClrAssembly = 10,\n\n\t\tUserDefined = 0xfe,\n\t\tNOT_FOUND = 0xff\n    };\n\n    #region FindPe\n\n    /// <summary>\n    /// Dll path resolver emulator for the NT Loader.\n    /// </summary>\n    public class FindPe\n    {\n        public static string GetSystemPath(PE RootPe)\n        {\n            if (RootPe.IsArm32Dll())\n            {\n                return Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.Windows), \"SysArm32\");\n            }\n            else if (RootPe.IsWow64Dll())\n            {\n                return Environment.GetFolderPath(Environment.SpecialFolder.SystemX86);\n            }\n\n            return Environment.GetFolderPath(Environment.SpecialFolder.System);\n        }\n\t\tstatic bool IsFilepathInvalid(string Filepath)\n\t\t{\n\t\t\tforeach (char InvalidChar in System.IO.Path.GetInvalidFileNameChars())\n\t\t\t{\n\t\t\t\t// do not treat these characters as invalid since the are necessary\n\t\t\t\t// for absolute imports\n                // also allow '/' because path env var manages it\n\t\t\t\tif (InvalidChar == ':' || InvalidChar == '\\\\' || InvalidChar == '/')\n\t\t\t\t\tcontinue;\n\n\t\t\t\tif (Filepath.IndexOf(InvalidChar) != -1)\n\t\t\t\t\treturn true;\n\t\t\t}\n\n\t\t\treturn false;\n\t\t}\n\n        static string FindPeFromPath(string ModuleName, List<string> CandidateFolders, string ProcessorArch)\n        {\n            string PeFilePath = null;\n\n\t\t\t// Filter out \"problematic\" search paths before it triggers an exception from Path.Combine\n\t\t\t// see https://github.com/lucasg/Dependencies/issues/49\n\t\t\tvar CuratedCandidateFolders = CandidateFolders.Where(\n\t\t\t\tpath => !IsFilepathInvalid(path)\n\t\t\t);\n\n\n\t\t\tforeach (String CandidatePath in CuratedCandidateFolders)\n\t\t\t{\n\t\n\t\t\t\tPeFilePath = Path.Combine(CandidatePath, ModuleName);\n                PE TestPe = BinaryCache.LoadPe(PeFilePath);\n\n                if (TestPe != null && TestPe.LoadSuccessful)\n                { \n                    Debug.WriteLine(\"Attempt to load {0:s} {1:s} {2:s}\", PeFilePath, TestPe.GetProcessor(), ProcessorArch);\n                    if (TestPe.GetProcessor() == ProcessorArch)\n                        return PeFilePath;\n                }\n            }\n\n            return null;\n        }\n\n\t\tpublic static Tuple<ModuleSearchStrategy, string> FindPeFromDefault(PE RootPe, string ModuleName)\n\t\t{\n\t\t\tstring WorkingDirectory = Path.GetDirectoryName(RootPe.Filepath);\n\t\t\tList<string> CustomSearchFolders = new List<string>();\n\t\t\tSxsEntries SxsCache = SxsManifest.GetSxsEntries(RootPe);\n\n\t\t\treturn FindPeFromDefault(\n\t\t\t\tRootPe,\n\t\t\t\tModuleName,\n\t\t\t\tSxsCache,\n\t\t\t\tCustomSearchFolders,\n\t\t\t\tWorkingDirectory\n\t\t\t);\n\t\t}\n\n\t\t// default search order : \n\t\t// https://msdn.microsoft.com/en-us/library/windows/desktop/ms682586(v=vs.85).aspx\n\t\t// \n\t\t// if (SafeDllSearchMode) {\n\t\t//      -1. Sxs manifests\n\t\t//      0. KnownDlls list\n\t\t//      1. Loaded PE folder\n\t\t//      2. C:\\Windows\\(System32 | SysWow64 )\n\t\t//      3. 16-bit system directory   <-- ignored\n\t\t//      4. C:\\Windows\n\t\t//      5. %pwd%\n\t\t//      6. AppDatas\n\t\t//      }\n\t\tpublic static Tuple<ModuleSearchStrategy, string> FindPeFromDefault(PE RootPe, string ModuleName, SxsEntries SxsCache, List<string> CustomSearchFolders, string WorkingDirectory)\n        {\n            bool Wow64Dll = RootPe.IsWow64Dll();\n            string ProcessorArch = RootPe.GetProcessor();\n            string RootPeFolder = Path.GetDirectoryName(RootPe.Filepath);\n            string FoundPePath = null;\n            \n            Environment.SpecialFolder WindowsSystemFolder = (Wow64Dll) ?\n                Environment.SpecialFolder.SystemX86 :\n                Environment.SpecialFolder.System;\n            String WindowsSystemFolderPath = (RootPe.IsArm32Dll()) ? Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.Windows), \"SysArm32\") \n            : Environment.GetFolderPath(WindowsSystemFolder);\n\n\n            // -1. Look in Sxs manifest (copious reversing needed)\n            // TODO : find dll search order\n            if (SxsCache.Count != 0)\n            {\n                SxsEntry Entry = SxsCache.Find( SxsItem =>\n                    string.Equals(SxsItem.Name, ModuleName, StringComparison.OrdinalIgnoreCase)\n                );\n\n                if (Entry != null)\n                {\n                    return new Tuple<ModuleSearchStrategy, string>(ModuleSearchStrategy.SxS, Entry.Path);\n                }\n            }\n\n\n            // 0. Look in well-known dlls list\n            // HKEY_LOCAL_MACHINE\\System\\CurrentControlSet\\Control\\Session Manager\\KnownDLLs\n            // https://blogs.msdn.microsoft.com/larryosterman/2004/07/19/what-are-known-dlls-anyway/\n            String KnownDll = Phlib.GetKnownDlls(Wow64Dll).Find(x => string.Equals(x, ModuleName, StringComparison.OrdinalIgnoreCase));\n            if (KnownDll != null)\n            {\n                return new Tuple<ModuleSearchStrategy, string>(\n                    ModuleSearchStrategy.WellKnownDlls, \n                    Path.Combine(WindowsSystemFolderPath, KnownDll)\n                );\n            }\n\n\n            // 1. Look in application folder\n            FoundPePath = FindPeFromPath(ModuleName, new List<string>(new string[] { RootPeFolder }), ProcessorArch);\n            if (FoundPePath != null)\n            {\n                return new Tuple<ModuleSearchStrategy, string>(\n                    ModuleSearchStrategy.ApplicationDirectory,\n                   FoundPePath\n                );\n            }\n\n            // {2-3-4}. Look in system folders\n            List<String> SystemFolders = new List<string>(new string[] {\n                WindowsSystemFolderPath,\n                Environment.GetFolderPath(Environment.SpecialFolder.Windows)\n                }\n            );\n\n            FoundPePath = FindPeFromPath(ModuleName, SystemFolders, ProcessorArch);\n            if (FoundPePath != null)\n            {\n                return new Tuple<ModuleSearchStrategy, string>(\n                    ModuleSearchStrategy.WindowsFolder,\n                   FoundPePath\n                );\n            }\n\n\t\t\t// 5. Look in current directory\n\t\t\t// Ignored for the time being since we can't know from\n\t\t\t// where the exe is run\n\t\t\t// TODO : Add a user supplied path emulating %cwd%\n\t\t\tFoundPePath = FindPeFromPath(ModuleName, new List<string>(new string[] { WorkingDirectory }), ProcessorArch);\n\t\t\tif (FoundPePath != null)\n\t\t\t{\n\t\t\t\treturn new Tuple<ModuleSearchStrategy, string>(\n\t\t\t\t\tModuleSearchStrategy.WorkingDirectory,\n\t\t\t\t   FoundPePath\n\t\t\t\t);\n\t\t\t}\n\n\t\t\t// 6. Look in local app data (check for python for exemple)\n\n\n\n\t\t\t// 7. Find in PATH\n\t\t\tstring PATH = Environment.GetEnvironmentVariable(\"PATH\");\n            List<String> PATHFolders = new List<string>(PATH.Split(';'));\n\n\t\t\t// Filter out empty paths, since it resolve to the current working directory\n\t\t\t// fix https://github.com/lucasg/Dependencies/issues/51\n\t\t\tPATHFolders = PATHFolders.Where(path => path.Length != 0).ToList();\n\n\n\t\t\tFoundPePath = FindPeFromPath(ModuleName, PATHFolders, ProcessorArch);\n            if (FoundPePath != null)\n            {\n                return new Tuple<ModuleSearchStrategy, string>(\n                    ModuleSearchStrategy.Environment,\n                   FoundPePath\n                );\n            }\n\n\n            // 8. Check if it's an absolute import\n            if (ModuleName != \"\" && (Path.GetFullPath(ModuleName) == ModuleName) && File.Exists(ModuleName))\n            {\n                return new Tuple<ModuleSearchStrategy, string>(\n                   ModuleSearchStrategy.Fullpath,\n                   ModuleName\n               );\n            }\n\n\n\t\t\t// 0xff. Allow the user to supply custom search folders, to take into account\n\t\t\t// specific cases.\n\t\t\tFoundPePath = FindPeFromPath(ModuleName, CustomSearchFolders, ProcessorArch);\n\t\t\tif (FoundPePath != null)\n\t\t\t{\n\t\t\t\treturn new Tuple<ModuleSearchStrategy, string>(\n\t\t\t\t\tModuleSearchStrategy.UserDefined,\n\t\t\t\t   FoundPePath\n\t\t\t\t);\n\t\t\t}\n\n\t\t\treturn new Tuple<ModuleSearchStrategy, string>(\n                ModuleSearchStrategy.NOT_FOUND,\n                null\n            );\n        }\n    }\n    #endregion FindPe\n}\n"
  },
  {
    "path": "DependenciesLib/Properties/AssemblyInfo.cs",
    "content": "﻿using System.Reflection;\nusing System.Runtime.CompilerServices;\nusing System.Runtime.InteropServices;\n\n// General Information about an assembly is controlled through the following\n// set of attributes. Change these attribute values to modify the information\n// associated with an assembly.\n[assembly: AssemblyTitle(\"DependenciesLib\")]\n[assembly: AssemblyDescription(\"\")]\n[assembly: AssemblyConfiguration(\"\")]\n[assembly: AssemblyCompany(\"\")]\n[assembly: AssemblyProduct(\"DependenciesLib\")]\n[assembly: AssemblyCopyright(\"Copyright ©  2018\")]\n[assembly: AssemblyTrademark(\"\")]\n[assembly: AssemblyCulture(\"\")]\n\n// Setting ComVisible to false makes the types in this assembly not visible\n// to COM components.  If you need to access a type in this assembly from\n// COM, set the ComVisible attribute to true on that type.\n[assembly: ComVisible(false)]\n\n// The following GUID is for the ID of the typelib if this project is exposed to COM\n[assembly: Guid(\"4a459493-14fc-4c87-9254-60e0959535da\")]\n\n// Version information for an assembly consists of the following four values:\n//\n//      Major Version\n//      Minor Version\n//      Build Number\n//      Revision\n//\n// You can specify all the values or you can default the Build and Revision Numbers\n// by using the '*' as shown below:\n// [assembly: AssemblyVersion(\"1.0.*\")]\n[assembly: AssemblyVersion(\"1.10.0.0\")]\n[assembly: AssemblyFileVersion(\"1.10.0.0\")]\n"
  },
  {
    "path": "DependenciesLib/SxsManifest.cs",
    "content": "using System;\nusing System.Collections.Generic;\nusing System.Xml;\nusing System.Xml.Linq;\nusing System.IO;\nusing System.Text.RegularExpressions;\n\nusing Dependencies.ClrPh;\n\nnamespace Dependencies\n{\n    // C# typedefs\n    #region Sxs Classes\n    public class SxsEntry \n    {\n        public SxsEntry(string _Name, string _Path, string _Version=\"\", string _Type=\"\", string _PublicKeyToken = \"\")\n        { \n\n            Name = _Name;\n            Path = _Path;\n            Version = _Version;\n            Type = _Type;\n            PublicKeyToken = _PublicKeyToken;\n        }\n\n        public SxsEntry(SxsEntry OtherSxsEntry)\n        {\n            Name = OtherSxsEntry.Name;\n            Path = OtherSxsEntry.Path;\n            Version = OtherSxsEntry.Version;\n            Type = OtherSxsEntry.Type;\n            PublicKeyToken = OtherSxsEntry.PublicKeyToken;\n        }\n\n        public SxsEntry(XElement SxsAssemblyIdentity, XElement SxsFile, string Folder)\n        {\n            var RelPath = SxsFile.Attribute(\"name\").Value.ToString();\n\n            Name = System.IO.Path.GetFileName(RelPath);\n            Path = System.IO.Path.Combine(Folder, RelPath);\n            Version = \"\";\n            Type = \"\";\n            PublicKeyToken = \"\";\n\n            if (SxsAssemblyIdentity != null)\n            {\n                if (SxsAssemblyIdentity.Attribute(\"version\") != null)\n                    Version = SxsAssemblyIdentity.Attribute(\"version\").Value.ToString();\n\n                if (SxsAssemblyIdentity.Attribute(\"type\") != null)\n                    Type = SxsAssemblyIdentity.Attribute(\"type\").Value.ToString();\n\n                if (SxsAssemblyIdentity.Attribute(\"publicKeyToken\") != null)\n                    PublicKeyToken = SxsAssemblyIdentity.Attribute(\"publicKeyToken\").Value.ToString();\n            }\n\n\n            // TODO : DLL search order ?\n            //if (!File.Exists(Path))\n            //{\n            //    Path = \"???\";\n            //}\n\n        }\n\n        public string Name;\n        public string Path;\n        public string Version;\n        public string Type;\n        public string PublicKeyToken;\n    }\n\n    public class SxsEntries : List<SxsEntry> \n    {\n        public static SxsEntries FromSxsAssembly(XElement SxsAssembly, XNamespace Namespace, string Folder)\n        {\n            SxsEntries Entries =  new SxsEntries();\n\n            XElement SxsAssemblyIdentity = SxsAssembly.Element(Namespace + \"assemblyIdentity\");\n            foreach (XElement SxsFile in SxsAssembly.Elements(Namespace + \"file\"))\n            {\n                Entries.Add(new SxsEntry(SxsAssemblyIdentity, SxsFile, Folder));\n            }\n\n            return Entries;\n        }\n    }\n    #endregion Sxs Classes\n\n    #region SxsManifest\n    public class SxsManifest\n    {\n        // find dll with same name as sxs assembly in target directory\n        public static SxsEntries SxsFindTargetDll(string AssemblyName, string Folder)\n        {\n            SxsEntries EntriesFromElement = new SxsEntries();\n\n            string TargetFilePath = Path.Combine(Folder, AssemblyName);\n            if (File.Exists(TargetFilePath))\n            {\n                var Name = System.IO.Path.GetFileName(TargetFilePath);\n                var Path = TargetFilePath;\n\n                EntriesFromElement.Add(new SxsEntry(Name, Path));\n                return EntriesFromElement;\n            }\n\n            string TargetDllPath = Path.Combine(Folder, String.Format(\"{0:s}.dll\", AssemblyName));\n            if (File.Exists(TargetDllPath))\n            {\n                var Name = System.IO.Path.GetFileName(TargetDllPath);\n                var Path = TargetDllPath;\n\n                EntriesFromElement.Add(new SxsEntry(Name, Path));\n                return EntriesFromElement;\n            }\n\n            return EntriesFromElement;\n        }\n\n        public static SxsEntries ExtractDependenciesFromSxsElement(XElement SxsAssembly, string Folder, string ExecutableName = \"\", string ProcessorArch = \"\")\n        {\n            // Private assembly search sequence : https://msdn.microsoft.com/en-us/library/windows/desktop/aa374224(v=vs.85).aspx\n            // \n            // * In the application's folder. Typically, this is the folder containing the application's executable file.\n            // * In a subfolder in the application's folder. The subfolder must have the same name as the assembly.\n            // * In a language-specific subfolder in the application's folder. \n            //      -> The name of the subfolder is a string of DHTML language codes indicating a language-culture or language.\n            // * In a subfolder of a language-specific subfolder in the application's folder.\n            //      -> The name of the higher subfolder is a string of DHTML language codes indicating a language-culture or language. The deeper subfolder has the same name as the assembly.\n            //\n            // \n            // 0.   Side-by-side searches the WinSxS folder.\n            // 1.   \\\\<appdir>\\<assemblyname>.DLL\n            // 2.   \\\\<appdir>\\<assemblyname>.manifest\n            // 3.   \\\\<appdir>\\<assemblyname>\\<assemblyname>.DLL\n            // 4.   \\\\<appdir>\\<assemblyname>\\<assemblyname>.manifest\n\n            string TargetSxsManifestPath;\n            string SxsManifestName = SxsAssembly.Attribute(\"name\").Value.ToString();\n            string SxsManifestDir = Path.Combine(Folder, SxsManifestName);\n\n\n            // 0. find publisher manifest in %WINDIR%/WinSxs/Manifest\n            if (SxsAssembly.Attribute(\"publicKeyToken\") != null)\n            {\n\n                string WinSxsDir = Path.Combine(\n                    Environment.GetFolderPath(Environment.SpecialFolder.Windows),\n                    \"WinSxs\"\n                );\n\n                string WinSxsManifestDir = Path.Combine(WinSxsDir, \"Manifests\");\n                var RegisteredManifests = Directory.EnumerateFiles(\n                    WinSxsManifestDir,\n                    \"*.manifest\"\n                );\n\n                string PublicKeyToken = SxsAssembly.Attribute(\"publicKeyToken\").Value;\n                string Name = SxsAssembly.Attribute(\"name\").Value.ToLower();\n                string ProcessArch = SxsAssembly.Attribute(\"processorArchitecture\") != null ? SxsAssembly.Attribute(\"processorArchitecture\").Value : \"*\";\n                string Version = SxsAssembly.Attribute(\"version\").Value;\n                string Langage = SxsAssembly.Attribute(\"langage\") != null ? SxsAssembly.Attribute(\"langage\").Value : \"none\"; // TODO : support localized sxs redirection\n                \n\n                switch (ProcessArch.ToLower())\n                {\n                    case \"$(build.arch)\":\n                    case \"*\":\n                        ProcessArch = ProcessorArch;\n                        break;\n                    case \"amd64\":\n                    case \"x86\":\n                    case \"wow64\":\n                    case \"msil\":\n                    case \"arm\":\n                    case \"arm64\":\n                        break; // nothing to do\n                    default:\n                        ProcessArch = \".*\";\n                        break;\n                }\n\n                Regex VersionRegex = new Regex(@\"([0-9]+)\\.([0-9]+)\\.([0-9]+)\\.([0-9]+)\", RegexOptions.IgnoreCase);\n                Match VersionMatch = VersionRegex.Match(Version);\n\n                if (VersionMatch.Success)\n                {\n                    string Major = VersionMatch.Groups[1].Value;\n                    string Minor = VersionMatch.Groups[2].Value;\n                    string Build = (VersionMatch.Groups[3].Value == \"0\") ? \".*\" : VersionMatch.Groups[3].Value;\n                    string Patch = (VersionMatch.Groups[4].Value == \"0\") ? \".*\" : VersionMatch.Groups[4].Value;\n\n                    // Manifest filename : {ProcArch}_{Name}_{PublicKeyToken}_{FuzzyVersion}_{Langage}_{some_hash}.manifest\n                    Regex ManifestFileNameRegex = new Regex(\n                        String.Format(@\"({0:s}_{1:s}_{2:s}_{3:s}\\.{4:s}\\.({5:s})\\.({6:s})_none_([a-fA-F0-9]+))\\.manifest\",\n                            ProcessArch, \n                            Name,\n                            PublicKeyToken,\n                            Major,\n                            Minor,\n                            Build,\n                            Patch\n                            //Langage,\n                            // some hash\n                        ), \n                        RegexOptions.IgnoreCase\n                    );\n\n                    bool FoundMatch = false;\n                    int HighestBuild = 0;\n                    int HighestPatch = 0;\n                    string MatchSxsManifestDir = \"\";\n                    string MatchSxsManifestPath = \"\";\n\n                    foreach (var FileName in RegisteredManifests)\n                    {\n                        Match MatchingSxsFile = ManifestFileNameRegex.Match(FileName);\n                        if (MatchingSxsFile.Success)\n                        {\n                            \n                            int MatchingBuild = Int32.Parse(MatchingSxsFile.Groups[2].Value);\n                            int MatchingPatch = Int32.Parse(MatchingSxsFile.Groups[3].Value);\n\n                            if ((MatchingBuild > HighestBuild) || ((MatchingBuild == HighestBuild) && (MatchingPatch > HighestPatch)))\n                            {\n                                \n                                \n                                string TestMatchSxsManifestDir = MatchingSxsFile.Groups[1].Value;\n\n                                // Check the directory exists before confirming there is a match\n                                string FullPathMatchSxsManifestDir = Path.Combine(WinSxsDir, TestMatchSxsManifestDir);\n                                //Debug.WriteLine(\"FullPathMatchSxsManifestDir : Checking {0:s}\", FullPathMatchSxsManifestDir);\n                                if (NativeFile.Exists(FullPathMatchSxsManifestDir, true))\n                                {\n\n                                    //Debug.WriteLine(\"FullPathMatchSxsManifestDir : Checking {0:s} TRUE\", FullPathMatchSxsManifestDir);\n                                    FoundMatch = true;\n\n                                    HighestBuild = MatchingBuild;\n                                    HighestPatch = MatchingPatch;\n\n                                    MatchSxsManifestDir = TestMatchSxsManifestDir;\n                                    MatchSxsManifestPath = Path.Combine(WinSxsManifestDir, FileName);\n                                }\n                            }\n                        }\n                    }\n\n                    if (FoundMatch)\n                    {\n                        \n                        string FullPathMatchSxsManifestDir = Path.Combine(WinSxsDir, MatchSxsManifestDir);\n\n                        // \"{name}.local\" local sxs directory hijack ( really used for UAC bypasses )\n                        if (ExecutableName != \"\")\n                        {\n                            string LocalSxsDir = Path.Combine(Folder, String.Format(\"{0:s}.local\", ExecutableName));\n                            string MatchingLocalSxsDir = Path.Combine(LocalSxsDir, MatchSxsManifestDir);\n\n                            if (Directory.Exists(LocalSxsDir) && Directory.Exists(MatchingLocalSxsDir))\n                            {\n                                FullPathMatchSxsManifestDir = MatchingLocalSxsDir;\n                            }\n                        }\n\n\n                        return ExtractDependenciesFromSxsManifestFile(MatchSxsManifestPath, FullPathMatchSxsManifestDir, ExecutableName, ProcessorArch);\n                    }\n                }\n            }\n\n            // 1. \\\\<appdir>\\<assemblyname>.DLL\n            // find dll with same assembly name in same directory\n            SxsEntries EntriesFromMatchingDll = SxsFindTargetDll(SxsManifestName, Folder);\n            if (EntriesFromMatchingDll.Count > 0) \n            {\n                return EntriesFromMatchingDll;\n            }\n\n\n            // 2. \\\\<appdir>\\<assemblyname>.manifest\n            // find manifest with same assembly name in same directory\n            TargetSxsManifestPath = Path.Combine(Folder, String.Format(\"{0:s}.manifest\", SxsManifestName));\n            if (File.Exists(TargetSxsManifestPath))\n            {\n                return ExtractDependenciesFromSxsManifestFile(TargetSxsManifestPath, Folder, ExecutableName, ProcessorArch);\n            }\n\n\n            // 3. \\\\<appdir>\\<assemblyname>\\<assemblyname>.DLL\n            // find matching dll in sub directory\n            SxsEntries EntriesFromMatchingDllSub = SxsFindTargetDll(SxsManifestName, SxsManifestDir);\n            if (EntriesFromMatchingDllSub.Count > 0) \n            {\n                return EntriesFromMatchingDllSub;\n            }\n\n            // 4. \\<appdir>\\<assemblyname>\\<assemblyname>.manifest\n            // find manifest in sub directory\n            TargetSxsManifestPath = Path.Combine(SxsManifestDir, String.Format(\"{0:s}.manifest\", SxsManifestName));\n            if (Directory.Exists(SxsManifestDir) && File.Exists(TargetSxsManifestPath))\n            {\n                return ExtractDependenciesFromSxsManifestFile(TargetSxsManifestPath, SxsManifestDir, ExecutableName, ProcessorArch);\n            }\n\n            // TODO : do the same thing for localization\n            // \n            // 0. Side-by-side searches the WinSxS folder.\n            // 1. \\\\<appdir>\\<language-culture>\\<assemblyname>.DLL\n            // 2. \\\\<appdir>\\<language-culture>\\<assemblyname>.manifest\n            // 3. \\\\<appdir>\\<language-culture>\\<assemblyname>\\<assemblyname>.DLL\n            // 4. \\\\<appdir>\\<language-culture>\\<assemblyname>\\<assemblyname>.manifest\n\n            // TODO : also take into account Multilanguage User Interface (MUI) when\n            // scanning manifests and WinSxs dll. God this is horrendously complicated.\n\n            // Could not find the dependency\n            {\n                SxsEntries EntriesFromElement = new SxsEntries();\n                EntriesFromElement.Add(new SxsEntry(SxsManifestName, \"file ???\"));\n                return EntriesFromElement;\n            }\n        }\n\n        public static SxsEntries ExtractDependenciesFromSxsManifestFile(string ManifestFile, string Folder, string ExecutableName = \"\", string ProcessorArch = \"\")\n        {\n            // Console.WriteLine(\"Extracting deps from file {0:s}\", ManifestFile);\n\n            using (FileStream fs = new FileStream(ManifestFile, FileMode.Open, FileAccess.Read))\n            {\n                return ExtractDependenciesFromSxsManifest(fs, Folder, ExecutableName, ProcessorArch);\n            }\n        }\n\n\n        public static SxsEntries ExtractDependenciesFromSxsManifest(System.IO.Stream ManifestStream, string Folder, string ExecutableName = \"\", string ProcessorArch = \"\")\n        {\n            SxsEntries AdditionnalDependencies = new SxsEntries();\n            \n            XDocument XmlManifest = ParseSxsManifest(ManifestStream);\n            XNamespace Namespace = XmlManifest.Root.GetDefaultNamespace();\n\n            // Find any declared dll\n            //< assembly xmlns = 'urn:schemas-microsoft-com:asm.v1' manifestVersion = '1.0' >\n            //    < assemblyIdentity name = 'additional_dll' version = 'XXX.YY.ZZ' type = 'win32' />\n            //    < file name = 'additional_dll.dll' />\n            //</ assembly >\n            foreach (XElement SxsAssembly in XmlManifest.Descendants(Namespace + \"assembly\"))\n            {\n                AdditionnalDependencies.AddRange(SxsEntries.FromSxsAssembly(SxsAssembly, Namespace, Folder));\n            }\n\n           \n\n            // Find any dependencies :\n            // <dependency>\n            //     <dependentAssembly>\n            //         <assemblyIdentity\n            //             type=\"win32\"\n            //             name=\"Microsoft.Windows.Common-Controls\"\n            //             version=\"6.0.0.0\"\n            //             processorArchitecture=\"amd64\" \n            //             publicKeyToken=\"6595b64144ccf1df\"\n            //             language=\"*\"\n            //         />\n            //     </dependentAssembly>\n            // </dependency>\n            foreach (XElement SxsAssembly in XmlManifest.Descendants(Namespace + \"dependency\")\n                                                        .Elements(Namespace + \"dependentAssembly\")\n                                                        .Elements(Namespace + \"assemblyIdentity\")\n            )\n            {\n                // find target PE\n                AdditionnalDependencies.AddRange(ExtractDependenciesFromSxsElement(SxsAssembly, Folder, ExecutableName, ProcessorArch));\n            }\n\n            return AdditionnalDependencies;\n        }\n\n        public static XDocument ParseSxsManifest(System.IO.Stream ManifestStream)\n        {\n            XDocument XmlManifest = null;\n            // Hardcode namespaces for manifests since they are no always specified in the embedded manifests.\n            XmlNamespaceManager nsmgr = new XmlNamespaceManager(new NameTable());\n            nsmgr.AddNamespace(String.Empty, \"urn:schemas-microsoft-com:asm.v1\"); //default namespace : manifest V1\n            nsmgr.AddNamespace(\"asmv3\", \"urn:schemas-microsoft-com:asm.v3\");      // sometimes missing from manifests : V3\n            nsmgr.AddNamespace(\"asmv3\", \"http://schemas.microsoft.com/SMI/2005/WindowsSettings\");      // sometimes missing from manifests : V3\n            XmlParserContext context = new XmlParserContext(null, nsmgr, null, XmlSpace.Preserve);\n\n\n            \n            \n            using (StreamReader xStream = new StreamReader(ManifestStream))\n            {\n                // Trim double quotes in manifest attributes\n                // Example :\n                //      * Before : <assemblyIdentity name=\"\"Microsoft.Windows.Shell.DevicePairingFolder\"\" processorArchitecture=\"\"amd64\"\" version=\"\"5.1.0.0\"\" type=\"win32\" />\n                //      * After  : <assemblyIdentity name=\"Microsoft.Windows.Shell.DevicePairingFolder\" processorArchitecture=\"amd64\" version=\"5.1.0.0\" type=\"win32\" />\n\n                string PeManifest = xStream.ReadToEnd();\n                PeManifest = new Regex(\"\\\\\\\"\\\\\\\"([\\\\w\\\\d\\\\.]*)\\\\\\\"\\\\\\\"\").Replace(PeManifest, \"\\\"$1\\\"\"); // Regex magic here\n\n                // some manifests have \"macros\" that break xml parsing\n                PeManifest = new Regex(\"SXS_PROCESSOR_ARCHITECTURE\").Replace(PeManifest, \"\\\"amd64\\\"\"); \n                PeManifest = new Regex(\"SXS_ASSEMBLY_VERSION\").Replace(PeManifest, \"\\\"\\\"\");\n                PeManifest = new Regex(\"SXS_ASSEMBLY_NAME\").Replace(PeManifest, \"\\\"\\\"\");\n\n                // Remove blank lines\n                PeManifest = Regex.Replace(PeManifest, @\"^\\s+$[\\r\\n]*\", string.Empty, RegexOptions.Multiline);\n\n                using (XmlTextReader xReader = new XmlTextReader(PeManifest, XmlNodeType.Document, context))\n                {\n                    XmlManifest = XDocument.Load(xReader);\n                }\n            }\n\n            return XmlManifest;\n        }\n\n\n        public static SxsEntries GetSxsEntries(PE Pe)\n        {\n            SxsEntries Entries = new SxsEntries();\n\n            string RootPeFolder = Path.GetDirectoryName(Pe.Filepath);\n            string RootPeFilename = Path.GetFileName(Pe.Filepath);\n\n            // Look for overriding manifest file (named \"{$name}.manifest)\n            string OverridingManifest = String.Format(\"{0:s}.manifest\", Pe.Filepath);\n            if (File.Exists(OverridingManifest))\n            {\n                return ExtractDependenciesFromSxsManifestFile(\n                    OverridingManifest,\n                    RootPeFolder,\n                    RootPeFilename,\n                    Pe.GetProcessor()\n                );\n            }\n\n            // Retrieve embedded manifest\n            string PeManifest = Pe.GetManifest();\n            if (PeManifest.Length == 0)\n                return Entries;\n\n\n            byte[] RawManifest = System.Text.Encoding.UTF8.GetBytes(PeManifest);\n            System.IO.Stream ManifestStream = new System.IO.MemoryStream(RawManifest);\n\n            Entries = ExtractDependenciesFromSxsManifest(\n                ManifestStream, \n                RootPeFolder,\n                RootPeFilename,\n                Pe.GetProcessor()\n                );\n            return Entries;\n        }\n    }\n    #endregion SxsManifest\n}"
  },
  {
    "path": "Deploy-Dependencies.ps1",
    "content": "function Get-PeviewBinary {\n  param(\n    [String] $BuildVersion,\n    [String] $Hash\n  )\n\n  Push-Location;\n  $PeviewBinaryFile = \"\";\n\n  # use temporary folder for download\n  New-Item -ItemType Directory -Force -Path \"$($env:TEMP)/tmp\";\n  Set-Location \"$($env:TEMP)/tmp\"\n\n  $apiUrl = 'https://ci.appveyor.com/api';\n  $headers = @{\n    \"Content-type\" = \"application/json\"\n  };\n  $accountName = 'processhacker';\n  $projectName = 'processhacker';\n  $artifactFileName = \"processhacker-build-bin.zip\";\n\n  # get project with last build details\n  $build = Invoke-RestMethod -Method Get -Uri \"$apiUrl/projects/$accountName/$projectName/build/$BuildVersion\" -Headers $headers\n\n  # processhacker builds have a single job\n  # get the job id\n  $jobId = $build.build.jobs[0].jobId;\n\n  # get the zip file job artifacts\n  Invoke-WebRequest -Uri \"$apiUrl/buildjobs/$jobId/artifacts/$artifactFileName\" -OutFile \"./$artifactFileName\"\n\n  # get the platform subfolder within the artifact zip file\n  $pePlatform = \"32bit\"\n  if ($env:platform -eq \"x64\") {\n    $pePlatform = \"64bit\"\n  }\n\n  # check the expected hash before extracing binaries\n  $PhArchiveHash = (Get-FileHash -Algorithm SHA256 -Path \"./$artifactFileName\").Hash;\n  if ($PhArchiveHash -eq $Hash) {\n    &7z.exe x \"./$artifactFileName\" \"$($pePlatform)/peview.exe\";\n    $PeviewBinaryFile = (Resolve-Path \"./$($pePlatform)/peview.exe\").Path;\n  }\n\n  # Because of wacky Powershell \"return\" behavior, it's better to store the result in a env variable.\n  $env:PEVIEW_PATH = $PeviewBinaryFile;\n  Pop-Location;\n}\n\nfunction Copy-SystemDll {\n  param(\n    [String] $DllName,\n    [String] $OutputFolder\n  )\n\n  $SystemFolder = [System.Environment]::GetFolderPath('SystemX86');\n  if ($env:platform -eq \"x64\")\n  {\n    # Check if it's a 32-bit powershell application, in order to force accessing System32\n    if (Test-path \"$([System.Environment]::GetFolderPath('Windows'))\\sysnative\")\n    {\n      $SystemFolder = \"$([System.Environment]::GetFolderPath('Windows'))\\sysnative\";\n    }\n    else\n    {\n      $SystemFolder = [System.Environment]::GetFolderPath('System');\n    }\n  }\n\n  $DllPath=\"$($SystemFolder)\\$($DllName)\";\n  if (Test-Path $DllPath) {\n    Write-Host \"Copy system dll $((Resolve-Path $DllPath).Path)\";\n    Copy-Item (Resolve-Path $DllPath).Path -Destination $OutputFolder;\n  }\n}\n\n\nfunction Copy-UniversalCrt {\n  param(\n    [String] $OutputFolder\n  )\n\n  # reference : https://github.com/mozilla/gecko-dev/blob/50b3fb522bdb080a7c9c00b1fdc758d171586cb6/media/webrtc/trunk/webrtc/build/vs_toolchain.py#L203\n  $UcrtFolder = \"C:\\Program Files (x86)\\Windows Kits\\10\\Redist\\ucrt\\DLLs\\$($env:platform)\";\n  \n  foreach ($ucrtdll in gci $UcrtFolder -File) {\n    Write-Host \"Copy ucrt dll $($ucrtdll.FullName)\";\n    Copy-Item $ucrtdll.FullName -Destination $OutputFolder;\n  }\n}\n\nfunction Get-DependenciesDeps {\n  param(\n    [String] $Binpath,\n    [String] $OutputFolder\n  )\n\n  # Download external dependencies like peview\n  $PeBuildVersion = \"3.0.2995\";\n  $PeviewBuildHash = \"2d6e76f6ff752cfbd595544ae0f967843e0fa2402700418d933d4d5d3ce2b99b\";\n  Get-PeviewBinary -BuildVersion $PeBuildVersion -Hash $PeviewBuildHash;\n  if (-not $env:PEVIEW_PATH)\n  {\n    Write-Error \"[x] Peview binary has not correctly been downloaded.\"\n  }\n\n\n  # Bundling dbghelp.dll along for undecorating names\n  Copy-SystemDll -DllName \"dbghelp.dll\" -OutputFolder $OutputFolder;\n\n  # Bundling every msvc redistribuables\n  $ClrPhLibPath = \"$($Binpath)/ClrPhLib.dll\";\n  $ClrPhLibImports = &\"$($Binpath)/Dependencies.exe\" -json -imports $ClrPhLibPath | ConvertFrom-Json;\n  foreach($DllImport in $ClrPhLibImports.Imports) {\n    \n    # vcruntime\n    if ($DllImport.Name.ToLower().StartsWith(\"vcruntime\"))\n    {\n      Copy-SystemDll -DllName $DllImport.Name -OutputFolder $OutputFolder;\n    }\n\n    # msvc\n    if ($DllImport.Name.ToLower().StartsWith(\"msvc\"))\n    {\n      Copy-SystemDll -DllName $DllImport.Name -OutputFolder $OutputFolder;\n    }\n\n    # ucrtbase\n    if ($DllImport.Name.ToLower().StartsWith(\"ucrtbase\"))\n    {\n      Copy-SystemDll -DllName $DllImport.Name -OutputFolder $OutputFolder;\n    }\n\n     # concrt\n    if ($DllImport.Name.ToLower().StartsWith(\"concrt\"))\n    {\n      Copy-SystemDll -DllName $DllImport.Name -OutputFolder $OutputFolder;\n    }\n\n  }\n\n  # Packaging universal CRT on Release builds\n  if ($($env:CONFIGURATION) -eq \"Release\") {\n    Copy-UniversalCrt -OutputFolder $OutputFolder;\n  }\n\n  return [string]$PeviewBinaryFile;\n}\n\nfunction Run-RegressTests {\n  param(\n    [String] $Binpath\n  )\n\n  Write-Host \"Test if the binary (and the underlying lib) actually works\"\n  \n  Write-Host \"Test basic functionnality\"\n  &\"$($Binpath)/Dependencies.exe\" -knowndll\n  &\"$($Binpath)/Dependencies.exe\" -apisets\n  &\"$($Binpath)/Dependencies.exe\" -sxsentries \"$($env:windir)/System32/ctfmon.exe\" \n\n\n  Write-Host \"Test manifest parsing\"\n  ./test/manifest-regress/Test-ManifestRegress.ps1 $($Binpath)\n\n  # deactivated since it's too long\n  # &\"$BINPATH/demangler-test.exe\"\n\n  Write-Host \"Tests done.\"\n}\n\n$BINPATH=\"C:/projects/dependencies/bin/$($env:CONFIGURATION)$($env:platform)\";\n$DepsFolder=\"C:/projects/dependencies/deps/$($env:CONFIGURATION)$($env:platform)\";\n$OutputFolder=\"C:/projects/dependencies/output\";\n\n# Creating output directory\nNew-Item -ItemType Directory -Force -Path $DepsFolder;\nNew-Item -ItemType Directory -Force -Path $OutputFolder;\n\n\n# Retrieve all dependencies that need to be packaged\nGet-DependenciesDeps -Binpath $BINPATH -OutputFolder $DepsFolder;\n\n# Running regress tests\nRun-RegressTests -Binpath $BINPATH;\n\n\nWrite-Host \"Zipping everything\"\nif ($($env:CONFIGURATION) -eq \"Debug\") {\n\t&7z.exe a \"$($OutputFolder)/Dependencies_$($env:platform)_$($env:CONFIGURATION).zip\" $BINPATH/tests $BINPATH/*.dll $BINPATH/*.exe $BINPATH/*.config $BINPATH/*.pdb $DepsFolder/* $env:PEVIEW_PATH;\n}\nelse {\n\t&7z.exe a \"$($OutputFolder)/Dependencies_$($env:platform)_$($env:CONFIGURATION).zip\" $BINPATH/*.dll $BINPATH/*.exe $BINPATH/*.config $BINPATH/*.pdb $DepsFolder/* $env:PEVIEW_PATH;\n\t&7z.exe a \"$($OutputFolder)/Dependencies_$($env:platform)_$($env:CONFIGURATION)_(without peview.exe).zip\" $BINPATH/*.dll $BINPATH/*.exe $BINPATH/*.config $BINPATH/*.pdb $DepsFolder/*;\n}\n\n# APPX packaging\n<#if (( $($env:CONFIGURATION) -eq \"Release\") -and ($env:APPVEYOR_REPO_TAG)) {\n  $makeappx = \"${env:ProgramFiles(x86)}\\Windows Kits\\10\\App Certification Kit\\makeappx.exe\";\n  $signtool = \"${env:ProgramFiles(x86)}\\Windows Kits\\10\\App Certification Kit\\signtool.exe\";\n\n  # Copy assets to build folder\n  Copy-Item \"C:/projects/dependencies/DependenciesAppx/Assets\" -Destination \"C:/projects/dependencies/bin/Appx_$($env:CONFIGURATION)$($env:platform)\" -Force -Recurse\n\n  # Create appx package\n  & $makeappx pack /d \"C:/projects/dependencies/bin/Appx_$($env:CONFIGURATION)$($env:platform)\" /l /p \"C:/projects/dependencies/bin/Appx_$($env:CONFIGURATION)$($env:platform).appx\"\n\n  # Sign appx package\n  & $signtool sign /fd SHA256 /a /f \"C:/projects/dependencies/DependenciesAppx/DependenciesAppx_TemporaryKey.pfx\" \"C:/projects/dependencies/bin/Appx_$($env:CONFIGURATION)$($env:platform).appx\"\n}#>"
  },
  {
    "path": "LICENSE",
    "content": "MIT License\n\nCopyright (c) 2017 lucasg\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n"
  },
  {
    "path": "README.md",
    "content": "# Dependencies - An open-source modern Dependency Walker\r\n[![Build status](https://ci.appveyor.com/api/projects/status/wtr5v8ksndbkkqxg?svg=true)](https://ci.appveyor.com/project/lucasg/dependencies)\r\n\r\n### [Download here](https://github.com/lucasg/Dependencies/releases/download/v1.11.1/Dependencies_x64_Release.zip)\r\n\r\n#### [(If you're running an AV, use this download instead)](https://github.com/lucasg/Dependencies/releases/download/v1.11.1/Dependencies_x64_Release_.without.peview.exe.zip)\r\n\r\nNB : due to [limitations on /clr compilation](https://msdn.microsoft.com/en-us/library/ffkc918h.aspx), `Dependencies` needs [Visual C++  Redistributable](https://support.microsoft.com/en-us/help/2977003/the-latest-supported-visual-c-downloads) installed to run properly.\r\n\r\n<p align=\"center\">\r\n<img alt=\"Usage Exemple\" src=\"screenshots/UsageExemple.gif\"/>\r\n</p>\r\n\r\n\r\n## Overview\r\n`Dependencies` is a rewrite of the legacy software [Dependency Walker](http://www.dependencywalker.com/) which was shipped along Windows SDKs, but whose development stopped around 2006.\r\n`Dependencies` can help Windows developers troubleshooting their dll load dependencies issues.\r\n\r\n## Releases\r\n* [v1.11](https://github.com/lucasg/Dependencies/releases/download/v1.11.1/Dependencies_x64_Release.zip) :\r\n\t* lots of bugfixes and incremental improvements\r\n\t* covid pandemic\r\n* [v1.10](https://github.com/lucasg/Dependencies/releases/download/v1.10/Dependencies_x64_Release.zip) :\r\n\t* lots of bugfixes and incremental improvements\r\n\t* support of Windows 8.1 apisets parsing\r\n* [v1.9](https://github.com/lucasg/Dependencies/releases/download/v1.9/Dependencies_x64_Release.zip) :\r\n\t* Display imports and exports the way Depends.exe does.\r\n\t* Added user customization for search folders and working directory\r\n\t* Added LLVM demangler to availables symbol demangling\r\n\t* Fixed Wow64 FsRedirection bugs\r\n\t* F5 can now refresh the analysis\r\n\t* Added CLR assembly dependencies enumeration\r\n\t* Added a packaging option without Peview.exe (which triggers some AV).\r\n* [v1.8](https://github.com/lucasg/Dependencies/releases/download/v1.8/Dependencies_x64_Release.zip) :\r\n\t* Add x86/x64 variants for Dependencies\r\n* [v1.7](https://github.com/lucasg/Dependencies/releases/download/v1.7/Dependencies.zip) :\r\n\t* Add CLI tool \"dependencies.exe\"\r\n* [v1.6](https://github.com/lucasg/Dependencies/releases/download/v1.6/Dependencies.zip) :\r\n\t* Add appx packaging\r\n* [v1.5](https://github.com/lucasg/Dependencies/releases/download/v1.5/Dependencies.zip) :\r\n\t* Support of Sxs parsing\r\n\t* Support of api set schema parsing\r\n\t* API and Modules list can be filtered\r\n* [v1.0](https://github.com/lucasg/Dependencies/releases/download/v1.0/Dependencies.zip) -- Initial release\r\n\r\n\r\n## Installation and Usage\r\n\r\n`Dependencies` is currently shipped as two binaries (no installer present) : `Dependencies.exe` as a CLI tool and `DependenciesGui.exe` for its GUI counterpart (see screenshot). Just click on one of the release numbers above (preferably the latest), download and uncompress the archive and run `DependenciesGui.exe`.\r\nSince the binary is not signed, `SmartScreen` might scream at runtime. `Dependencies` also bundle `ClrPhTester.exe`, a dumpbin-like executable used to test for non-regressions.\r\n\r\n`Dependencies` currently does not recursively resolve child imports when parsing a new PE since it can be really memory-hungry to do so ( it can over a GB even for \"simple\" PEs ). This behavior can be overridden (app-wide) via a property located in \"Options->Properties->Tree build behaviour\".\r\n\r\n<p align=\"center\">\r\n<img alt=\"User options\" src=\"screenshots/UserOptions.png\"/>\r\n</p>\r\n\r\nTree build behaviours available :\r\n\r\n* `ChildOnly` (default) : only process PE child imports and nothing beyond.\r\n* `RecursiveOnlyOnDirectImports`  : do not process delayload dlls.\r\n* `Recursive` : Full recursive analysis. You better have time and RAM on your hands if you activate this setting :\r\n\r\n<p align=\"center\">\r\n<img alt=\"Yes that's 7 GB of RAM being consumed. I'm impressed the application didn't even crash\" src=\"screenshots/RamEater.PNG\"/>\r\n</p>\r\n\r\n\r\n## Limitations\r\n\r\nAt the moment, `Dependencies` recreates features and \"features\" of `depends.exe`, which means :\r\n\r\n* Only direct, forwarded and delay load dependencies are supported. Dynamic loading via `LoadLibrary` are not supported (and probably won't ever be).\r\n* Support of api set schema redirection since 1.5\r\n* Checks between Api Imports and Exports. \r\n* Minimal support of sxs private manifests search only.\r\n\r\n\r\n## Building\r\n\r\nBuilding is pretty straightforward.\r\nThe only caveat is you need to select the \"Debug\" or \"Release\" configuration and \"x64\" or \"x86\" platform which may not be the default.\r\n\r\n\r\n## Credits and licensing\r\n\r\nSpecial thanks to :\r\n\r\n* [ProcessHacker2](https://github.com/processhacker2/processhacker) for :\r\n  * `phlib`, which does the heavy lifting for processing PE informations.\r\n  * `peview`, a powerful and lightweight PE informations viewer.\r\n* [Dragablz](https://github.com/ButchersBoy/Dragablz) a C#/XAML library which implement dockable and dragable UI elements, and can recreate the [MDI programming model](https://en.wikipedia.org/wiki/Multiple_document_interface) in `WPF`.\r\n* @aionescu, @zodiacon and Quarkslab for their public infos on ApiSets schema.\r\n* [Thomas levesque's blog](https://www.thomaslevesque.com) which pretty much solved all my `WPF` programming issues. His [`AutoGridSort`](http://www.thomaslevesque.com/2009/08/04/wpf-automatically-sort-a-gridview-continued/) is used in this project \r\n* Venkatesh Mookkan [for it's `FilterControl` for ListView used in this project](https://www.codeproject.com/Articles/170095/WPF-Custom-Control-FilterControl-for-ListBox-ListV)\r\n* [demumble](https://github.com/nico/demumble) for demangling GCC symbols on Windows\r\n"
  },
  {
    "path": "appveyor.yml",
    "content": "\r\nconfiguration:\r\n    - Release\r\n    - Debug\r\n\r\n# common configuration\r\nfor:\r\n\r\n# override for tag push\r\n-\r\n  branches:\r\n    only:\r\n      - master\r\n  \r\n  configuration:\r\n    - Release\r\n    - Debug\r\n    # - Appx\r\n\r\n# Do not package appx on pull requests\r\n- \r\n  branches:\r\n    only:\r\n      - /pr*/\r\n\r\n  configuration:\r\n    - Release\r\n    - Debug\r\n\r\n\r\n\r\n# Operating system (build VM template)\r\nos:\r\n  - Visual Studio 2019\r\n  #- Visual Studio 2017\r\n  #- Visual Studio 2015\r\n  #- Visual Studio 2013\r\n\r\n\r\nplatform:\r\n  - x86\r\n  - x64\r\n\r\nartifacts:\r\n\r\n  # old style packaging\r\n  - path: output/Dependencies_*.zip\r\n    name: Dependencies\r\n\r\n  # \"centennial\" style packaging\r\n  - path: \"bin/**/*.appx\"\r\n  - path: \"DependenciesAppx/DependenciesAppx_TemporaryKey.cer\"\r\n\r\ndeploy:\r\n  # Deploy to GitHub Releases\r\n  - provider: GitHub\r\n    description: \"Dependencies v$(APPVEYOR_REPO_TAG_NAME)\"\r\n    artifact: Dependencies\r\n    auth_token:\r\n      secure: 2QjekNwJsIupEgFBXAcsfMXsJIpb0kU8ijjsEEjsGNJkW3SVf31ho4aSBnoku1y6\r\n    draft: false\r\n    prerelease: false\r\n    on:\r\n      appveyor_repo_tag: true       # deploy on tag push only\r\n\r\ncache:\r\n  - packages -> **\\packages.config\r\n\r\nbuild:\r\n  project: C:/projects/dependencies/Dependencies.sln\r\n\r\nenvironment:\r\n  git_tag: \"git tag -l --points-at HEAD\" # return the tag associated with the current commit\r\n  certsecret:\r\n    secure: 1id6kDyNieDfYWTAnoJ/hA==\r\n\r\nbefore_build:\r\n  - ps: |\r\n      # extracting signing cert\r\n      # &nuget install secure-file -ExcludeVersion;\r\n      # &secure-file/tools/secure-file -decrypt \"C:/projects/dependencies/DependenciesAppx/DependenciesAppx_TemporaryKey.pfx.enc\" -secret \"$($env:certsecret)\" -out \"C:/projects/dependencies/DependenciesAppx/DependenciesAppx_TemporaryKey.pfx\";\r\n  \r\n      # download all the necessary packages\r\n      nuget restore \r\n\r\nafter_test:\r\n - ps: |\r\n      # remove decoded cert as soon as it is not useful anymore\r\n      # Remove-Item -Force \"C:/projects/dependencies/DependenciesAppx/DependenciesAppx_TemporaryKey.pfx\"\r\n      \r\n\r\ntest_script: # should be on_finish, but it need to be executed before artifacts is\r\n  - ps: .\\Deploy-Dependencies.ps1 \r\n  - ps: Write-Host \"Building artifact done\""
  },
  {
    "path": "nuget.config",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\r\n<configuration>\r\n  <packageSources>\r\n    <clear />\r\n    <add key=\"nuget-org\" value=\"https://api.nuget.org/v3/index.json\" />\r\n  </packageSources>\r\n</configuration>\r\n"
  },
  {
    "path": "test/binarycache-test/App.config",
    "content": "﻿<?xml version=\"1.0\" encoding=\"utf-8\" ?>\n<configuration>\n    <startup> \n        <supportedRuntime version=\"v4.0\" sku=\".NETFramework,Version=v4.6.1\" />\n    </startup>\n</configuration>"
  },
  {
    "path": "test/binarycache-test/Program.cs",
    "content": "﻿using System;\nusing System.Diagnostics;\nusing System.Collections.Generic;\n\nusing Dependencies.ClrPh;\nusing NDesk.Options;\n\nnamespace Dependencies\n{\n    namespace Test\n    {\n        class Program\n        {\n            static void ShowHelp(OptionSet p)\n            {\n                Console.WriteLine(\"Usage: binarycache [options] <FILES_TO_LOAD>\");\n                Console.WriteLine();\n                Console.WriteLine(\"Options:\");\n                p.WriteOptionDescriptions(Console.Out);\n            }\n\n            static void Main(string[] args)\n            {\n                bool is_verbose = false;\n                bool show_help = false;\n\n                OptionSet opts = new OptionSet() {\n                            { \"v|verbose\", \"redirect debug traces to console\", v => is_verbose = v != null },\n                            { \"h|help\",  \"show this message and exit\", v => show_help = v != null },\n                        };\n\n                List<string> eps = opts.Parse(args);\n\n                if (show_help)\n                {\n                    ShowHelp(opts);\n                    return;\n                }\n\n                if (is_verbose)\n                {\n                    // Redirect debug log to the console\n                    Debug.Listeners.Add(new TextWriterTraceListener(Console.Out));\n                    Debug.AutoFlush = true;\n                }\n\n                // always the first call to make\n                Phlib.InitializePhLib();\n\n                BinaryCache.Instance.Load();\n\n                foreach ( var peFilePath in eps)\n                {\n                    PE Pe = BinaryCache.LoadPe(peFilePath);\n                    Console.WriteLine(\"Loaded PE file : {0:s}\", Pe.Filepath);\n                }\n\n\n                BinaryCache.Instance.Unload();\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "test/binarycache-test/Properties/AssemblyInfo.cs",
    "content": "﻿using System.Reflection;\nusing System.Runtime.CompilerServices;\nusing System.Runtime.InteropServices;\n\n// Les informations générales relatives à un assembly dépendent de\n// l'ensemble d'attributs suivant. Changez les valeurs de ces attributs pour modifier les informations\n// associées à un assembly.\n[assembly: AssemblyTitle(\"binarycache-test\")]\n[assembly: AssemblyDescription(\"\")]\n[assembly: AssemblyConfiguration(\"\")]\n[assembly: AssemblyCompany(\"\")]\n[assembly: AssemblyProduct(\"binarycache-test\")]\n[assembly: AssemblyCopyright(\"Copyright ©  2018\")]\n[assembly: AssemblyTrademark(\"\")]\n[assembly: AssemblyCulture(\"\")]\n\n// L'affectation de la valeur false à ComVisible rend les types invisibles dans cet assembly\n// aux composants COM. Si vous devez accéder à un type dans cet assembly à partir de\n// COM, affectez la valeur true à l'attribut ComVisible sur ce type.\n[assembly: ComVisible(false)]\n\n// Le GUID suivant est pour l'ID de la typelib si ce projet est exposé à COM\n[assembly: Guid(\"ff973409-2f2a-46f7-b01d-c6405ea40422\")]\n\n// Les informations de version pour un assembly se composent des quatre valeurs suivantes :\n//\n//      Version principale\n//      Version secondaire\n//      Numéro de build\n//      Révision\n//\n// Vous pouvez spécifier toutes les valeurs ou indiquer les numéros de build et de révision par défaut\n// en utilisant '*', comme indiqué ci-dessous :\n// [assembly: AssemblyVersion(\"1.0.*\")]\n[assembly: AssemblyVersion(\"1.0.0.0\")]\n[assembly: AssemblyFileVersion(\"1.0.0.0\")]\n"
  },
  {
    "path": "test/binarycache-test/binarycache-test.csproj",
    "content": "﻿<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<Project ToolsVersion=\"15.0\" xmlns=\"http://schemas.microsoft.com/developer/msbuild/2003\">\n  <Import Project=\"$(MSBuildExtensionsPath)\\$(MSBuildToolsVersion)\\Microsoft.Common.props\" Condition=\"Exists('$(MSBuildExtensionsPath)\\$(MSBuildToolsVersion)\\Microsoft.Common.props')\" />\n  <PropertyGroup>\n    <Configuration Condition=\" '$(Configuration)' == '' \">Debug</Configuration>\n    <Platform Condition=\" '$(Platform)' == '' \">AnyCPU</Platform>\n    <ProjectGuid>{FF973409-2F2A-46F7-B01D-C6405EA40422}</ProjectGuid>\n    <OutputType>Exe</OutputType>\n    <RootNamespace>binarycache_test</RootNamespace>\n    <AssemblyName>binarycache-test</AssemblyName>\n    <TargetFrameworkVersion>v4.6.1</TargetFrameworkVersion>\n    <FileAlignment>512</FileAlignment>\n    <AutoGenerateBindingRedirects>true</AutoGenerateBindingRedirects>\n  </PropertyGroup>\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)' == 'Debug|x86'\">\n    <DebugSymbols>true</DebugSymbols>\n    <OutputPath>$(SolutionDir)bin\\$(Configuration)$(Platform)\\tests</OutputPath>\n    <IntermediateOutputPath>$(SolutionDir)obj\\$(ProjectName)\\$(Configuration)$(Platform)</IntermediateOutputPath>\n    <DefineConstants>DEBUG;TRACE</DefineConstants>\n    <DebugType>full</DebugType>\n    <PlatformTarget>x86</PlatformTarget>\n    <ErrorReport>prompt</ErrorReport>\n    <CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>\n  </PropertyGroup>\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)' == 'Release|x86'\">\n    <OutputPath>$(SolutionDir)bin\\$(Configuration)$(Platform)\\tests</OutputPath>\n    <IntermediateOutputPath>$(SolutionDir)obj\\$(ProjectName)\\$(Configuration)$(Platform)</IntermediateOutputPath>\n    <DefineConstants>TRACE</DefineConstants>\n    <Optimize>true</Optimize>\n    <DebugType>pdbonly</DebugType>\n    <PlatformTarget>x86</PlatformTarget>\n    <ErrorReport>prompt</ErrorReport>\n    <CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>\n    <Prefer32Bit>true</Prefer32Bit>\n  </PropertyGroup>\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)' == 'Debug|x64'\">\n    <DebugSymbols>true</DebugSymbols>\n    <OutputPath>$(SolutionDir)bin\\$(Configuration)$(Platform)\\tests</OutputPath>\n    <IntermediateOutputPath>$(SolutionDir)obj\\$(ProjectName)\\$(Configuration)$(Platform)</IntermediateOutputPath>\n    <DefineConstants>DEBUG;TRACE</DefineConstants>\n    <DebugType>full</DebugType>\n    <PlatformTarget>x64</PlatformTarget>\n    <ErrorReport>prompt</ErrorReport>\n    <CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>\n  </PropertyGroup>\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)' == 'Release|x64'\">\n    <OutputPath>$(SolutionDir)bin\\$(Configuration)$(Platform)\\tests</OutputPath>\n    <IntermediateOutputPath>$(SolutionDir)obj\\$(ProjectName)\\$(Configuration)$(Platform)</IntermediateOutputPath>\n    <DefineConstants>TRACE</DefineConstants>\n    <Optimize>true</Optimize>\n    <DebugType>pdbonly</DebugType>\n    <PlatformTarget>x64</PlatformTarget>\n    <ErrorReport>prompt</ErrorReport>\n    <CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>\n    <Prefer32Bit>true</Prefer32Bit>\n  </PropertyGroup>\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)' == 'Appx|x86'\">\n    <OutputPath>$(SolutionDir)bin\\$(Configuration)$(Platform)\\tests</OutputPath>\n    <IntermediateOutputPath>$(SolutionDir)obj\\$(ProjectName)\\$(Configuration)$(Platform)</IntermediateOutputPath>\n    <DefineConstants>TRACE</DefineConstants>\n    <Optimize>true</Optimize>\n    <DebugType>pdbonly</DebugType>\n    <PlatformTarget>x86</PlatformTarget>\n    <ErrorReport>prompt</ErrorReport>\n    <CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>\n    <Prefer32Bit>true</Prefer32Bit>\n  </PropertyGroup>\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)' == 'Appx|x64'\">\n    <OutputPath>$(SolutionDir)bin\\$(Configuration)$(Platform)\\tests</OutputPath>\n    <IntermediateOutputPath>$(SolutionDir)obj\\$(ProjectName)\\$(Configuration)$(Platform)</IntermediateOutputPath>\n    <DefineConstants>TRACE</DefineConstants>\n    <Optimize>true</Optimize>\n    <DebugType>pdbonly</DebugType>\n    <PlatformTarget>x64</PlatformTarget>\n    <ErrorReport>prompt</ErrorReport>\n    <CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>\n    <Prefer32Bit>true</Prefer32Bit>\n  </PropertyGroup>\n  <ItemGroup>\n    <Reference Include=\"NDesk.Options, Version=0.2.1.0, Culture=neutral, processorArchitecture=MSIL\">\n      <HintPath>..\\..\\packages\\NDesk.Options.0.2.1\\lib\\NDesk.Options.dll</HintPath>\n    </Reference>\n    <Reference Include=\"System\" />\n    <Reference Include=\"System.Core\" />\n    <Reference Include=\"System.Xml.Linq\" />\n    <Reference Include=\"System.Data.DataSetExtensions\" />\n    <Reference Include=\"Microsoft.CSharp\" />\n    <Reference Include=\"System.Data\" />\n    <Reference Include=\"System.Net.Http\" />\n    <Reference Include=\"System.Xml\" />\n  </ItemGroup>\n  <ItemGroup>\n    <Compile Include=\"Program.cs\" />\n    <Compile Include=\"Properties\\AssemblyInfo.cs\" />\n  </ItemGroup>\n  <ItemGroup>\n    <None Include=\"App.config\" />\n    <None Include=\"packages.config\" />\n  </ItemGroup>\n  <ItemGroup>\n    <ProjectReference Include=\"..\\..\\ClrPhlib\\ClrPhlib.vcxproj\">\n      <Project>{fc5ffcaf-982f-4a95-8fa6-2a95b1f7cdc8}</Project>\n      <Name>ClrPhlib</Name>\n    </ProjectReference>\n    <ProjectReference Include=\"..\\..\\DependenciesLib\\DependenciesLib.csproj\">\n      <Project>{4a459493-14fc-4c87-9254-60e0959535da}</Project>\n      <Name>DependenciesLib</Name>\n    </ProjectReference>\n  </ItemGroup>\n  <Import Project=\"$(MSBuildToolsPath)\\Microsoft.CSharp.targets\" />\n</Project>"
  },
  {
    "path": "test/binarycache-test/packages.config",
    "content": "﻿<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<packages>\n  <package id=\"NDesk.Options\" version=\"0.2.1\" targetFramework=\"net461\" />\n</packages>"
  },
  {
    "path": "test/demangler-test/App.config",
    "content": "﻿<?xml version=\"1.0\" encoding=\"utf-8\" ?>\n<configuration>\n    <startup> \n        <supportedRuntime version=\"v4.0\" sku=\".NETFramework,Version=v4.6.1\" />\n    </startup>\n</configuration>"
  },
  {
    "path": "test/demangler-test/Program.cs",
    "content": "﻿using System;\nusing System.Collections.Generic;\nusing System.Linq;\nusing System.Text;\nusing System.Threading;\nusing System.Diagnostics;\n\nusing NDesk.Options;\nusing Dependencies.ClrPh;\n\nnamespace Dependencies\n{\n    namespace Test\n    {\n        public class Demangler :  PhSymbolProvider\n        {\n            public Demangler(CLRPH_DEMANGLER demangler = CLRPH_DEMANGLER.Default)\n            {\n                _demangler = demangler;\n            }\n\n            public override Tuple<CLRPH_DEMANGLER, string> UndecorateName(string DecoratedName)\n            {\n\n                switch (_demangler)\n                {\n                    case CLRPH_DEMANGLER.Demumble:\n                        return new Tuple<CLRPH_DEMANGLER, string>(CLRPH_DEMANGLER.Demumble, base.UndecorateNameDemumble(DecoratedName));\n                    case CLRPH_DEMANGLER.LLVMItanium:\n                        return new Tuple<CLRPH_DEMANGLER, string>(CLRPH_DEMANGLER.LLVMItanium, base.UndecorateNameLLVMItanium(DecoratedName));\n                    case CLRPH_DEMANGLER.LLVMMicrosoft:\n                        return new Tuple<CLRPH_DEMANGLER, string>(CLRPH_DEMANGLER.LLVMMicrosoft, base.UndecorateNameLLVMMicrosoft(DecoratedName));\n                    case CLRPH_DEMANGLER.Microsoft:\n                        return new Tuple<CLRPH_DEMANGLER, string>(CLRPH_DEMANGLER.Microsoft, base.UndecorateNamePh(DecoratedName));\n\n                    default:\n                    case CLRPH_DEMANGLER.Default:\n                        return base.UndecorateName(DecoratedName);\n                }\n\n            }\n\n            private CLRPH_DEMANGLER _demangler;\n        }\n\n        class Program\n        {\n            static void ShowHelp(OptionSet p)\n            {\n                Console.WriteLine(\"Usage: demangler [options] FILE_OR_SYMBOL\");\n                Console.WriteLine();\n                Console.WriteLine(\"Options:\");\n                p.WriteOptionDescriptions(Console.Out);\n            }\n\n            static CLRPH_DEMANGLER ParseDemanglerName(string v)\n            {\n                switch (v)\n                {\n                    case \"Default\":\n                        return CLRPH_DEMANGLER.Default;\n                    case \"Demumble\":\n                        return CLRPH_DEMANGLER.Demumble;\n                    case \"LLVMItanium\":\n                        return CLRPH_DEMANGLER.LLVMItanium;\n                    case \"LLVMMicrosoft\":\n                        return CLRPH_DEMANGLER.LLVMMicrosoft;\n                    case \"Microsoft\":\n                        return CLRPH_DEMANGLER.Microsoft;\n\n                    default:\n                        string msg = String.Format(\"Unknown demangler '{0}'. Only 'Default', 'Demumble', 'LLVMItanium', 'LLVMMicrosoft' and 'Microsoft' are supported.\", v);\n                        throw new OptionException(msg, \"severity\");\n                }\n            }\n\n            static bool TestKnownInputs(Demangler SymPrv)\n            {\n                Debug.Assert(SymPrv.UndecorateName(\"??1type_info@@UEAA@XZ\").Item2 == \"public: virtual __cdecl type_info::~type_info(void) __ptr64\");\n                Debug.Assert(SymPrv.UndecorateName(\"?setbuf@strstreambuf@@UEAAPEAVstreambuf@@PEADH@Z\").Item2 == \"public: virtual class streambuf * __ptr64 __cdecl strstreambuf::setbuf(char * __ptr64,int) __ptr64\");\n                Debug.Assert(SymPrv.UndecorateName(\"?CreateXBaby@XProvider@DirectUI@@UEAAJPEAVIXElementCP@2@PEAUHWND__@@PEAVElement@2@PEAKPEAPEAUIXBaby@2@@Z\").Item2 == \"public: virtual long __cdecl DirectUI::XProvider::CreateXBaby(class DirectUI::IXElementCP * __ptr64,struct HWND__ * __ptr64,class DirectUI::Element * __ptr64,unsigned long * __ptr64,struct DirectUI::IXBaby * __ptr64 * __ptr64) __ptr64\");\n                Debug.Assert(SymPrv.UndecorateName(\"??0exception@@QEAA@AEBQEBDH@Z\").Item2 == \"public: __cdecl exception::exception(char const * __ptr64 const & __ptr64,int) __ptr64\");\n                Debug.Assert(SymPrv.UndecorateName(\"?what@exception@@UEBAPEBDXZ\").Item2 == \"public: virtual char const * __ptr64 __cdecl exception::what(void)const __ptr64\");\n                Debug.Assert(SymPrv.UndecorateName(\"?_Execute_once@std@@YAHAEAUonce_flag@1@P6AHPEAX1PEAPEAX@Z1@Z\").Item2 == \"int __cdecl std::_Execute_once(struct std::once_flag & __ptr64,int (__cdecl*)(void * __ptr64,void * __ptr64,void * __ptr64 * __ptr64),void * __ptr64)\");\n                Debug.Assert(SymPrv.UndecorateName(\"?swap@?$basic_streambuf@_WU?$char_traits@_W@std@@@std@@IEAAXAEAV12@@Z\").Item2 == \"protected: void __cdecl std::basic_streambuf<wchar_t,struct std::char_traits<wchar_t> >::swap(class std::basic_streambuf<wchar_t,struct std::char_traits<wchar_t> > & __ptr64) __ptr64\");\n\n                Console.WriteLine(\"demangler-test : all known inputs OK\");\n                return true;\n            }\n\n            static bool TestFilepath(string Filepath, Demangler SymPrv)\n            {\n\n                PE Pe = new PE(Filepath);\n                if (!Pe.Load())\n                {\n                    Console.Error.WriteLine(\"[x] Could not load file {0:s} as a PE\", Filepath);\n                    return false;\n                }\n\n                foreach (PeExport Export in Pe.GetExports())\n                {\n                    if (Export.Name.Length > 0)\n                    {\n                        Console.Write(\"\\t Export : {0:s} -> \", Export.Name);\n                        Console.Out.Flush();\n                        Console.WriteLine(\"{0:s}\", SymPrv.UndecorateName(Export.Name));\n                    }\n                        \n                }\n\n                foreach (PeImportDll DllImport in Pe.GetImports())\n                {\n                    foreach (PeImport Import in DllImport.ImportList)\n                    {\n                        if (!Import.ImportByOrdinal)\n                        {\n                            Console.Write(\"\\t Import from {0:s} : {1:s} -> \", DllImport.Name, Import.Name);\n                            Console.Out.Flush();\n                            Console.WriteLine(\"{0:s}\", SymPrv.UndecorateName(Import.Name));\n                        }\n\n                    }\n                }\n\n                return true;\n            }\n\n            static void Main(string[] args)\n            {\n                bool is_verbose = false;\n                bool show_help = false;\n                CLRPH_DEMANGLER demangler_name = CLRPH_DEMANGLER.Default;\n\n                OptionSet opts = new OptionSet() {\n                            { \"v|verbose\", \"redirect debug traces to console\", v => is_verbose = v != null },\n                            { \"h|help\",  \"show this message and exit\", v => show_help = v != null },\n                            { \"d=|demangler=\",  \"Choose demangler name\", v => demangler_name = ParseDemanglerName(v) },\n                        };\n\n                List<string> eps = opts.Parse(args);\n\n                if (show_help)\n                {\n                    ShowHelp(opts);\n                    return;\n                }\n\n                if (is_verbose)\n                {\n                    // Redirect debug log to the console\n                    Debug.Listeners.Add(new TextWriterTraceListener(Console.Out));\n                    Debug.AutoFlush = true;\n                }\n\n                // always the first call to make\n                Phlib.InitializePhLib();\n                Demangler demangler;\n\n                switch(args.Length)\n                {\n                    case 0:\n                        demangler = new Demangler(CLRPH_DEMANGLER.Microsoft);\n                        TestKnownInputs(demangler);\n                        break;\n\n                    default:\n                    case 1:\n                        demangler = new Demangler(demangler_name);\n                        string Filepath = args[1];\n\n                        if (NativeFile.Exists(Filepath))\n                        {\n                            TestFilepath(Filepath, demangler);\n                        }\n                        else\n                        {\n                            string undecoratedName = demangler.UndecorateName(args[1]).Item2;\n                            Console.WriteLine(undecoratedName);\n                        }\n\n                        break;\n                }\n\n                // Force flushing out buffer\n                Console.Out.Flush();\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "test/demangler-test/Properties/AssemblyInfo.cs",
    "content": "﻿using System.Reflection;\nusing System.Runtime.CompilerServices;\nusing System.Runtime.InteropServices;\n\n// Les informations générales relatives à un assembly dépendent de\n// l'ensemble d'attributs suivant. Changez les valeurs de ces attributs pour modifier les informations\n// associées à un assembly.\n[assembly: AssemblyTitle(\"demangler-test\")]\n[assembly: AssemblyDescription(\"\")]\n[assembly: AssemblyConfiguration(\"\")]\n[assembly: AssemblyCompany(\"\")]\n[assembly: AssemblyProduct(\"demangler-test\")]\n[assembly: AssemblyCopyright(\"Copyright ©  2018\")]\n[assembly: AssemblyTrademark(\"\")]\n[assembly: AssemblyCulture(\"\")]\n\n// L'affectation de la valeur false à ComVisible rend les types invisibles dans cet assembly\n// aux composants COM. Si vous devez accéder à un type dans cet assembly à partir de\n// COM, affectez la valeur true à l'attribut ComVisible sur ce type.\n[assembly: ComVisible(false)]\n\n// Le GUID suivant est pour l'ID de la typelib si ce projet est exposé à COM\n[assembly: Guid(\"24f9e0c0-ca6e-4565-a9e2-88602dd9f18a\")]\n\n// Les informations de version pour un assembly se composent des quatre valeurs suivantes :\n//\n//      Version principale\n//      Version secondaire\n//      Numéro de build\n//      Révision\n//\n// Vous pouvez spécifier toutes les valeurs ou indiquer les numéros de build et de révision par défaut\n// en utilisant '*', comme indiqué ci-dessous :\n// [assembly: AssemblyVersion(\"1.0.*\")]\n[assembly: AssemblyVersion(\"1.0.0.0\")]\n[assembly: AssemblyFileVersion(\"1.0.0.0\")]\n"
  },
  {
    "path": "test/demangler-test/demangler-test.csproj",
    "content": "﻿<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<Project ToolsVersion=\"15.0\" xmlns=\"http://schemas.microsoft.com/developer/msbuild/2003\">\n  <Import Project=\"$(MSBuildExtensionsPath)\\$(MSBuildToolsVersion)\\Microsoft.Common.props\" Condition=\"Exists('$(MSBuildExtensionsPath)\\$(MSBuildToolsVersion)\\Microsoft.Common.props')\" />\n  <PropertyGroup>\n    <Configuration Condition=\" '$(Configuration)' == '' \">Debug</Configuration>\n    <Platform Condition=\" '$(Platform)' == '' \">AnyCPU</Platform>\n    <ProjectGuid>{24F9E0C0-CA6E-4565-A9E2-88602DD9F18A}</ProjectGuid>\n    <OutputType>Exe</OutputType>\n    <RootNamespace>demangler_test</RootNamespace>\n    <AssemblyName>demangler-test</AssemblyName>\n    <TargetFrameworkVersion>v4.6.1</TargetFrameworkVersion>\n    <FileAlignment>512</FileAlignment>\n    <AutoGenerateBindingRedirects>true</AutoGenerateBindingRedirects>\n  </PropertyGroup>\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)' == 'Debug|x86'\">\n    <DebugSymbols>true</DebugSymbols>\n    <OutputPath>$(SolutionDir)bin\\$(Configuration)$(Platform)\\tests</OutputPath>\n    <IntermediateOutputPath>$(SolutionDir)obj\\$(ProjectName)\\$(Configuration)$(Platform)</IntermediateOutputPath>\n    <DefineConstants>DEBUG;TRACE</DefineConstants>\n    <DebugType>full</DebugType>\n    <PlatformTarget>x86</PlatformTarget>\n    <ErrorReport>prompt</ErrorReport>\n    <CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>\n  </PropertyGroup>\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)' == 'Release|x86'\">\n    <OutputPath>$(SolutionDir)bin\\$(Configuration)$(Platform)\\tests</OutputPath>\n    <IntermediateOutputPath>$(SolutionDir)obj\\$(ProjectName)\\$(Configuration)$(Platform)</IntermediateOutputPath>\n    <DefineConstants>TRACE</DefineConstants>\n    <Optimize>true</Optimize>\n    <DebugType>pdbonly</DebugType>\n    <PlatformTarget>x86</PlatformTarget>\n    <ErrorReport>prompt</ErrorReport>\n    <CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>\n    <Prefer32Bit>true</Prefer32Bit>\n  </PropertyGroup>\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)' == 'Debug|x64'\">\n    <DebugSymbols>true</DebugSymbols>\n    <OutputPath>$(SolutionDir)bin\\$(Configuration)$(Platform)\\tests</OutputPath>\n    <IntermediateOutputPath>$(SolutionDir)obj\\$(ProjectName)\\$(Configuration)$(Platform)</IntermediateOutputPath>\n    <DefineConstants>DEBUG;TRACE</DefineConstants>\n    <DebugType>full</DebugType>\n    <PlatformTarget>x64</PlatformTarget>\n    <ErrorReport>prompt</ErrorReport>\n    <CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>\n  </PropertyGroup>\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)' == 'Release|x64'\">\n    <OutputPath>$(SolutionDir)bin\\$(Configuration)$(Platform)\\tests</OutputPath>\n    <IntermediateOutputPath>$(SolutionDir)obj\\$(ProjectName)\\$(Configuration)$(Platform)</IntermediateOutputPath>\n    <DefineConstants>TRACE</DefineConstants>\n    <Optimize>true</Optimize>\n    <DebugType>pdbonly</DebugType>\n    <PlatformTarget>x64</PlatformTarget>\n    <ErrorReport>prompt</ErrorReport>\n    <CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>\n    <Prefer32Bit>true</Prefer32Bit>\n  </PropertyGroup>\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)' == 'Appx|x86'\">\n    <OutputPath>$(SolutionDir)bin\\$(Configuration)$(Platform)\\tests</OutputPath>\n    <IntermediateOutputPath>$(SolutionDir)obj\\$(ProjectName)\\$(Configuration)$(Platform)</IntermediateOutputPath>\n    <DefineConstants>TRACE</DefineConstants>\n    <Optimize>true</Optimize>\n    <DebugType>pdbonly</DebugType>\n    <PlatformTarget>x86</PlatformTarget>\n    <ErrorReport>prompt</ErrorReport>\n    <CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>\n    <Prefer32Bit>true</Prefer32Bit>\n  </PropertyGroup>\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)' == 'Appx|x64'\">\n    <OutputPath>$(SolutionDir)bin\\$(Configuration)$(Platform)\\tests</OutputPath>\n    <IntermediateOutputPath>$(SolutionDir)obj\\$(ProjectName)\\$(Configuration)$(Platform)</IntermediateOutputPath>\n    <DefineConstants>TRACE</DefineConstants>\n    <Optimize>true</Optimize>\n    <DebugType>pdbonly</DebugType>\n    <PlatformTarget>x64</PlatformTarget>\n    <ErrorReport>prompt</ErrorReport>\n    <CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>\n    <Prefer32Bit>true</Prefer32Bit>\n  </PropertyGroup>\n  <PropertyGroup>\n    <StartupObject>Dependencies.Test.Program</StartupObject>\n  </PropertyGroup>\n  <ItemGroup>\n    <Reference Include=\"NDesk.Options, Version=0.2.1.0, Culture=neutral, processorArchitecture=MSIL\">\n      <HintPath>..\\..\\packages\\NDesk.Options.0.2.1\\lib\\NDesk.Options.dll</HintPath>\n    </Reference>\n    <Reference Include=\"System\" />\n    <Reference Include=\"System.Core\" />\n    <Reference Include=\"System.Xml.Linq\" />\n    <Reference Include=\"System.Data.DataSetExtensions\" />\n    <Reference Include=\"Microsoft.CSharp\" />\n    <Reference Include=\"System.Data\" />\n    <Reference Include=\"System.Net.Http\" />\n    <Reference Include=\"System.Xml\" />\n  </ItemGroup>\n  <ItemGroup>\n    <Compile Include=\"Program.cs\" />\n    <Compile Include=\"Properties\\AssemblyInfo.cs\" />\n  </ItemGroup>\n  <ItemGroup>\n    <None Include=\"App.config\" />\n    <None Include=\"packages.config\" />\n  </ItemGroup>\n  <ItemGroup>\n    <ProjectReference Include=\"..\\..\\ClrPhlib\\ClrPhlib.vcxproj\">\n      <Project>{fc5ffcaf-982f-4a95-8fa6-2a95b1f7cdc8}</Project>\n      <Name>ClrPhlib</Name>\n    </ProjectReference>\n  </ItemGroup>\n  <Import Project=\"$(MSBuildToolsPath)\\Microsoft.CSharp.targets\" />\n</Project>"
  },
  {
    "path": "test/demangler-test/packages.config",
    "content": "﻿<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<packages>\n  <package id=\"NDesk.Options\" version=\"0.2.1\" targetFramework=\"net461\" />\n</packages>"
  },
  {
    "path": "test/manifest-regress/Test-ManifestRegress.ps1",
    "content": "\nfunction Test-Executable {\n    param (\n        [String] $TestName,\n        [String] $TestExecutable,\n        [String] $BinFolder,\n        [Parameter(Mandatory=$False)][String] $StringToFound = $null,\n        [Parameter(Mandatory=$False)][String] $StringNotToFound = $null,\n        [String] $Command\n    )\n\n\n    Write-Host -ForegroundColor Magenta \"[-] Regress test : $TestName -> $StringToFound\"\n    $SxsDepsResult  = &\"$($BinFolder)/Dependencies.exe\" $Command $TestExecutable 2>&1 | Out-String \n    Write-Debug \"[-] result : \"\n    Write-Debug  $($SxsDepsResult -join \"`r`n\" )\n\n    $DllFound = $False;\n    if (-not($StringToFound))\n    {\n        $DllFound = $True;\n    }\n\n    foreach ($line in $SxsDepsResult)\n    {\n    \n        if ($StringToFound)\n        {\n            Write-Debug \"$line contains $StringToFound : $($line.ToLower().Contains($StringToFound.ToLower()))\"\n            if ($line.ToLower().Contains($StringToFound.ToLower()))\n            {\n                $DllFound = $True;\n                break;\n            }\n        }\n        \n\n        if ($StringNotToFound)\n        {\n            Write-Debug \"$line not contains $StringNotToFound : $($line.ToLower().Contains($StringNotToFound.ToLower()))\"\n            if ($line.ToLower().Contains($StringNotToFound.ToLower()))\n            {\n                Write-Error \"[x] $TestName test failed\";\n                Write-Output \"\"\n                return\n            }\n        }\n    }\n\n    if (-not $DllFound)\n    {\n        Write-Error \"[x] $TestName test failed\";\n    }\n    else \n    {\n        Write-Host -ForegroundColor Green \"[+] $TestName test passed\";    \n    }\n\n    Write-Output \"\"\n}\n\n$DependenciesDir = $args[0]\n$RegressDir = [System.IO.Path]::GetDirectoryName($myInvocation.MyCommand.Definition)\n\n# Malformed manifest due to asmv3 url redefining\n$ChangePkPath = Join-Path $RegressDir \"changepk.exe\";\nTest-Executable -TestName \"Changepk\" -TestExecutable $ChangePkPath -Command \"-manifest\" -StringNotToFound \"System.Xml.XmlException\" -StringToFound '<requestedExecutionLevel level=\"requireAdministrator\" />' -BinFolder $DependenciesDir\n\n# Embededd Manifest resource index > 1\n$SystemSettingsPath = Join-Path $RegressDir \"SystemSettings.exe\";\nTest-Executable -TestName \"SystemSettings\" -TestExecutable $SystemSettingsPath -Command \"-manifest\" -StringToFound \"<assembly xmlns=\"urn:schemas-microsoft-com:asm.v1\" xmlns:asmv3=\"urn:schemas-microsoft-com:asm.v3\" manifestVersion=\"1.0\">\" -BinFolder $DependenciesDir\n\n# Double quotes in assemblyIdentity name attribute !\n$DevicePairingFolderPath = Join-Path $RegressDir \"DevicePairingFolder.dll\";\nTest-Executable -TestName \"DevicePairingFolder\" -TestExecutable $DevicePairingFolderPath -Command \"-manifest\" -StringToFound '<assemblyIdentity name=\"Microsoft.Windows.Shell.DevicePairingFolder\" processorArchitecture=\"amd64\"' -BinFolder $DependenciesDir"
  },
  {
    "path": "third_party/Dragablz/Dragablz/CanvasOrganiser.cs",
    "content": "﻿using System;\nusing System.Collections.Generic;\nusing System.Linq;\nusing System.Windows;\nusing System.Windows.Controls;\n\nnamespace Dragablz\n{\n    public class CanvasOrganiser : IItemsOrganiser\n    {\n        public virtual void Organise(DragablzItemsControl requestor, Size measureBounds, IEnumerable<DragablzItem> items)\n        {\n            \n        }\n\n        public virtual void Organise(DragablzItemsControl requestor, Size measureBounds, IOrderedEnumerable<DragablzItem> items)\n        {\n\n        }\n\n        public virtual void OrganiseOnMouseDownWithin(DragablzItemsControl requestor, Size measureBounds, List<DragablzItem> siblingItems, DragablzItem dragablzItem)\n        {\n            var zIndex = int.MaxValue;\n            foreach (var source in siblingItems.OrderByDescending(Panel.GetZIndex))\n            {\n                Panel.SetZIndex(source, --zIndex);\n\n            }\n            Panel.SetZIndex(dragablzItem, int.MaxValue);\n        }\n\n        public virtual void OrganiseOnDragStarted(DragablzItemsControl requestor, Size measureBounds, IEnumerable<DragablzItem> siblingItems, DragablzItem dragItem)\n        {\n            \n        }\n\n        public virtual void OrganiseOnDrag(DragablzItemsControl requestor, Size measureBounds, IEnumerable<DragablzItem> siblingItems, DragablzItem dragItem)\n        {\n            \n        }\n\n        public virtual void OrganiseOnDragCompleted(DragablzItemsControl requestor, Size measureBounds, IEnumerable<DragablzItem> siblingItems, DragablzItem dragItem)\n        {\n            \n        }\n\n        public virtual Point ConstrainLocation(DragablzItemsControl requestor, Size measureBounds, Point itemCurrentLocation, Size itemCurrentSize, Point itemDesiredLocation, Size itemDesiredSize)\n        {\n            //we will stop it pushing beyond the bounds...unless it's already beyond...\n            var reduceBoundsWidth = itemCurrentLocation.X + itemCurrentSize.Width > measureBounds.Width\n                ? 0\n                : itemDesiredSize.Width;\n            var reduceBoundsHeight = itemCurrentLocation.Y + itemCurrentSize.Height > measureBounds.Height\n                ? 0\n                : itemDesiredSize.Height;\n\n            return new Point(\n                Math.Min(Math.Max(itemDesiredLocation.X, 0), measureBounds.Width - reduceBoundsWidth),\n                Math.Min(Math.Max(itemDesiredLocation.Y, 0), measureBounds.Height - reduceBoundsHeight));\n        }\n\n        public virtual Size Measure(DragablzItemsControl requestor, Size availableSize, IEnumerable<DragablzItem> items)\n        {\n            return availableSize;\n        }\n\n        public virtual IEnumerable<DragablzItem> Sort(IEnumerable<DragablzItem> items)\n        {\n            return items;\n        }\n    }\n}"
  },
  {
    "path": "third_party/Dragablz/Dragablz/ContainerCustomisations.cs",
    "content": "using System;\nusing System.Windows;\n\nnamespace Dragablz\n{\n    internal class ContainerCustomisations\n    {\n        private readonly Func<DragablzItem> _getContainerForItemOverride;\n        private readonly Action<DependencyObject, object> _prepareContainerForItemOverride;\n        private readonly Action<DependencyObject, object> _clearingContainerForItemOverride;\n\n        public ContainerCustomisations(Func<DragablzItem> getContainerForItemOverride = null, Action<DependencyObject, object> prepareContainerForItemOverride = null, Action<DependencyObject, object> clearingContainerForItemOverride = null)\n        {\n            _getContainerForItemOverride = getContainerForItemOverride;\n            _prepareContainerForItemOverride = prepareContainerForItemOverride;\n            _clearingContainerForItemOverride = clearingContainerForItemOverride;\n        }\n\n        public Func<DragablzItem> GetContainerForItemOverride\n        {\n            get { return _getContainerForItemOverride; }\n        }\n\n        public Action<DependencyObject, object> PrepareContainerForItemOverride\n        {\n            get { return _prepareContainerForItemOverride; }\n        }\n\n        public Action<DependencyObject, object> ClearingContainerForItemOverride\n        {\n            get { return _clearingContainerForItemOverride; }\n        }\n    }\n}"
  },
  {
    "path": "third_party/Dragablz/Dragablz/Converters/BooleanAndToVisibilityConverter.cs",
    "content": "﻿using System;\nusing System.Globalization;\nusing System.Linq;\nusing System.Windows;\nusing System.Windows.Data;\n\nnamespace Dragablz.Converters\n{\n    public class BooleanAndToVisibilityConverter : IMultiValueConverter\n    {\n        public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)\n        {\n            if (values == null)\n                return Visibility.Collapsed;\n            \n            return values.Select(GetBool).All(b => b) \n                ? Visibility.Visible\n                : Visibility.Collapsed;\n        }\n\n        public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture)\n        {\n            return null;\n        }\n\n        private static bool GetBool(object value)\n        {\n            if (value is bool)\n            {\n                return (bool)value;\n            }\n            \n            return false;\n        }\n    }\n}"
  },
  {
    "path": "third_party/Dragablz/Dragablz/Converters/EqualityToBooleanConverter.cs",
    "content": "﻿using System;\nusing System.Globalization;\nusing System.Windows.Data;\n\nnamespace Dragablz.Converters\n{\n    public class EqualityToBooleanConverter : IValueConverter\n    {\n        public object Convert(object value, Type targetType, object parameter, CultureInfo culture)\n        {\n            return Equals(value, parameter);\n        }\n\n        public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)\n        {\n            return Binding.DoNothing;\n        }\n    }\n}"
  },
  {
    "path": "third_party/Dragablz/Dragablz/Converters/EqualityToVisibilityConverter.cs",
    "content": "﻿using System;\nusing System.Collections.Generic;\nusing System.Globalization;\nusing System.Text;\nusing System.Threading.Tasks;\nusing System.Windows;\nusing System.Windows.Controls;\nusing System.Windows.Data;\n\nnamespace Dragablz.Converters\n{\n    public class EqualityToVisibilityConverter : IValueConverter\n    {\n        public object Convert(object value, Type targetType, object parameter, CultureInfo culture)\n        {\n            return Equals(value, parameter)\n                ? Visibility.Visible\n                : Visibility.Collapsed;\n        }\n\n        public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)\n        {\n            return Binding.DoNothing;\n        }\n    }\n}\n"
  },
  {
    "path": "third_party/Dragablz/Dragablz/Converters/ShowDefaultCloseButtonConverter.cs",
    "content": "﻿using System;\nusing System.Globalization;\nusing System.Windows;\nusing System.Windows.Data;\n\nnamespace Dragablz.Converters\n{\n    public class ShowDefaultCloseButtonConverter : IMultiValueConverter\n    {\n        /// <summary>\n        /// [0] is owning tabcontrol ShowDefaultCloseButton value.\n        /// [1] is owning tabcontrol FixedHeaderCount value.\n        /// [2] is item LogicalIndex\n        /// </summary>\n        /// <param name=\"values\"></param>\n        /// <param name=\"targetType\"></param>\n        /// <param name=\"parameter\"></param>\n        /// <param name=\"culture\"></param>\n        /// <returns></returns>\n        public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)\n        {\n            return ((values[0] == DependencyProperty.UnsetValue ? false : (bool)values[0]) && \n                    (values[2] == DependencyProperty.UnsetValue ? 0 : (int)values[2]) >= \n                    (values[1] == DependencyProperty.UnsetValue ? 0 : (int)values[1])) ? Visibility.Visible : Visibility.Collapsed;\n        }\n\n        public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture)\n        {\n            return null;            \n        }\n    }\n}\n"
  },
  {
    "path": "third_party/Dragablz/Dragablz/Core/CollectionTeaser.cs",
    "content": "﻿using System;\nusing System.Collections;\nusing System.Collections.Generic;\nusing System.Linq;\n\nnamespace Dragablz.Core\n{\n    internal class CollectionTeaser\n    {\n        private readonly Action<object> _addMethod;\n        private readonly Action<object> _removeMethod;\n\n        private CollectionTeaser(Action<object> addMethod, Action<object> removeMethod)\n        {            \n            _addMethod = addMethod;\n            _removeMethod = removeMethod;\n        }\n\n        public static bool TryCreate(object items, out CollectionTeaser collectionTeaser)\n        {\n            collectionTeaser = null;\n\n            var list = items as IList;\n            if (list != null)\n            {\n                collectionTeaser = new CollectionTeaser(i => list.Add(i), list.Remove);                \n            }\n            else if (items != null)\n            {\n                var itemsType = items.GetType();\n                var genericCollectionType = typeof (ICollection<>);\n\n                //TODO, *IF* we really wanted to we could get the consumer to inform us of the correct type\n                //if there are multiple impls.  havent got time for this edge case right now though\n                var collectionImplType = itemsType.GetInterfaces().SingleOrDefault(x =>\n                    x.IsGenericType &&\n                    x.GetGenericTypeDefinition() == genericCollectionType);\n\n                if (collectionImplType != null)\n                {\n                    var genericArgType = collectionImplType.GetGenericArguments().First();\n\n                    var addMethodInfo = collectionImplType.GetMethod(\"Add\", new[] {genericArgType});\n                    var removeMethodInfo = collectionImplType.GetMethod(\"Remove\", new[] { genericArgType });\n\n                    collectionTeaser = new CollectionTeaser(\n                        i => addMethodInfo.Invoke(items, new[] {i}),\n                        i => removeMethodInfo.Invoke(items, new[] {i}));\n                }\n            }\n            \n            return collectionTeaser != null;\n        }\n\n        public void Add(object item)\n        {\n            _addMethod(item);\n        }\n\n        public void Remove(object item)\n        {\n            _removeMethod(item);\n        }\n    }\n}\n"
  },
  {
    "path": "third_party/Dragablz/Dragablz/Core/Extensions.cs",
    "content": "#if NET40\nusing System.Collections;\n#endif\nusing System;\nusing System.Collections.Generic;\nusing System.Linq;\nusing System.Reflection;\nusing System.Windows;\nusing System.Windows.Controls;\nusing System.Windows.Media;\n\nnamespace Dragablz.Core\n{\n    internal static class Extensions\n    {\n        public static IEnumerable<TContainer> Containers<TContainer>(this ItemsControl itemsControl) where TContainer : class\n        {\n#if NET45\n            for (var i = 0; i < itemsControl.ItemContainerGenerator.Items.Count; i++)\n#endif\n#if NET40\n            var fieldInfo = typeof(ItemContainerGenerator).GetField(\"_items\", BindingFlags.NonPublic | BindingFlags.Instance);\n            var list = (IList)fieldInfo.GetValue(itemsControl.ItemContainerGenerator);            \n            for (var i = 0; i < list.Count; i++)\n#endif\n            {\n                var container = itemsControl.ItemContainerGenerator.ContainerFromIndex(i) as TContainer;\n                if (container != null)\n                    yield return container;\n            }            \n        }\n\n        public static IEnumerable<TObject> Except<TObject>(this IEnumerable<TObject> first, params TObject[] second)\n        {\n            return first.Except((IEnumerable<TObject>)second);\n        }\n\n        public static IEnumerable<object> LogicalTreeDepthFirstTraversal(this DependencyObject node)\n        {\n            if (node == null) yield break;\n            yield return node;\n\n            foreach (var child in LogicalTreeHelper.GetChildren(node).OfType<DependencyObject>()\n                .SelectMany(depObj => depObj.LogicalTreeDepthFirstTraversal()))            \n                yield return child;\n        }\n\n        public static IEnumerable<object> VisualTreeDepthFirstTraversal(this DependencyObject node)\n        {\n            if (node == null) yield break;\n            yield return node;\n\n            for (var i = 0; i < VisualTreeHelper.GetChildrenCount(node); i++)\n            {\n                var child = VisualTreeHelper.GetChild(node, i);\n                foreach (var d in child.VisualTreeDepthFirstTraversal())\n                {\n                    yield return d;\n                }\n            }\n        }\n\n        /// <summary>\n        /// Yields the visual ancestory (including the starting point).\n        /// </summary>\n        /// <param name=\"dependencyObject\"></param>\n        /// <returns></returns>\n        public static IEnumerable<DependencyObject> VisualTreeAncestory(this DependencyObject dependencyObject)\n        {\n            if (dependencyObject == null) throw new ArgumentNullException(\"dependencyObject\");\n\n            while (dependencyObject != null)\n            {\n                yield return dependencyObject;\n                dependencyObject = VisualTreeHelper.GetParent(dependencyObject);\n            }            \n        }\n\n        /// <summary>\n        /// Yields the logical ancestory (including the starting point).\n        /// </summary>\n        /// <param name=\"dependencyObject\"></param>\n        /// <returns></returns>\n        public static IEnumerable<DependencyObject> LogicalTreeAncestory(this DependencyObject dependencyObject)\n        {\n            if (dependencyObject == null) throw new ArgumentNullException(\"dependencyObject\");\n\n            while (dependencyObject != null)\n            {\n                yield return dependencyObject;\n                dependencyObject = LogicalTreeHelper.GetParent(dependencyObject);\n            }\n        }\n        \n        /// <summary>\n        /// Returns the actual Left of the Window independently from the WindowState\n        /// </summary>\n        /// <param name=\"window\"></param>\n        /// <returns></returns>\n        public static double GetActualLeft(this Window window)\n        {\n            if (window.WindowState == WindowState.Maximized)\n            {\n                var leftField = typeof(Window).GetField(\"_actualLeft\", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance);\n                return leftField?.GetValue(window) as double? ?? 0;\n            }\n\n            return window.Left;\n        }\n\n        /// <summary>\n        /// Returns the actual Top of the Window independently from the WindowState\n        /// </summary>\n        /// <param name=\"window\"></param>\n        /// <returns></returns>\n        public static double GetActualTop(this Window window)\n        {\n            if (window.WindowState == WindowState.Maximized)\n            {\n                var topField = typeof(Window).GetField(\"_actualTop\", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance);\n                return topField?.GetValue(window) as double? ?? 0;\n            }\n\n            return window.Top;\n        }\n\n    }\n}\n"
  },
  {
    "path": "third_party/Dragablz/Dragablz/Core/FuncComparer.cs",
    "content": "using System;\nusing System.Collections.Generic;\n\nnamespace Dragablz.Core\n{\n    internal class FuncComparer<TObject> : IComparer<TObject>\n    {\n        private readonly Func<TObject, TObject, int> _comparer;\n\n        public FuncComparer(Func<TObject, TObject, int> comparer)\n        {\n            if (comparer == null) throw new ArgumentNullException(\"comparer\");\n            \n            _comparer = comparer;\n        }\n\n        public int Compare(TObject x, TObject y)\n        {\n            return _comparer(x, y);\n        }\n    }\n}"
  },
  {
    "path": "third_party/Dragablz/Dragablz/Core/HitTest.cs",
    "content": "﻿namespace Dragablz.Core\n{\n    /// <summary>\n    /// Non-client hit test values, HT*\n    /// </summary>\n    internal enum HitTest\n    {\n        HT_ERROR = -2,\n        HT_TRANSPARENT = -1,\n        HT_NOWHERE = 0,\n        HT_CLIENT = 1,\n        HT_CAPTION = 2,\n        HT_SYSMENU = 3,\n        HT_GROWBOX = 4,\n        HT_MENU = 5,\n        HT_HSCROLL = 6,\n        HT_VSCROLL = 7,\n        HT_MINBUTTON = 8,\n        HT_MAXBUTTON = 9,\n        HT_LEFT = 10,\n        HT_RIGHT = 11,\n        HT_TOP = 12,\n        HT_TOPLEFT = 13,\n        HT_TOPRIGHT = 14,\n        HT_BOTTOM = 15,\n        HT_BOTTOMLEFT = 16,\n        HT_BOTTOMRIGHT = 17,\n        HT_BORDER = 18,\n        HT_OBJECT = 19,\n        HT_CLOSE = 20,\n        HT_HELP = 21\n    }\n}"
  },
  {
    "path": "third_party/Dragablz/Dragablz/Core/InterTabTransfer.cs",
    "content": "﻿using System;\nusing System.Collections.Generic;\nusing System.Windows;\nusing System.Windows.Controls;\nusing Dragablz.Dockablz;\n\nnamespace Dragablz.Core\n{\n    internal enum InterTabTransferReason\n    {\n        Breach,\n        Reentry\n    }\n\n    internal class InterTabTransfer\n    {\n        private readonly object _item;\n        private readonly DragablzItem _originatorContainer;\n        private readonly Orientation _breachOrientation;\n        private readonly Point _dragStartWindowOffset;\n        private readonly Point _dragStartItemOffset;\n        private readonly Point _itemPositionWithinHeader;\n        private readonly Size _itemSize;\n        private readonly IList<FloatingItemSnapShot> _floatingItemSnapShots;\n        private readonly bool _isTransposing;\n        private readonly InterTabTransferReason _transferReason; \n\n        public InterTabTransfer(object item, DragablzItem originatorContainer, Orientation breachOrientation, Point dragStartWindowOffset, Point dragStartItemOffset, Point itemPositionWithinHeader, Size itemSize, IList<FloatingItemSnapShot> floatingItemSnapShots, bool isTransposing)\n        {\n            if (item == null) throw new ArgumentNullException(\"item\");\n            if (originatorContainer == null) throw new ArgumentNullException(\"originatorContainer\");\n            if (floatingItemSnapShots == null) throw new ArgumentNullException(\"floatingItemSnapShots\");\n\n            _transferReason = InterTabTransferReason.Breach;\n\n            _item = item;\n            _originatorContainer = originatorContainer;\n            _breachOrientation = breachOrientation;\n            _dragStartWindowOffset = dragStartWindowOffset;\n            _dragStartItemOffset = dragStartItemOffset;\n            _itemPositionWithinHeader = itemPositionWithinHeader;\n            _itemSize = itemSize;\n            _floatingItemSnapShots = floatingItemSnapShots;\n            _isTransposing = isTransposing;\n        }\n\n        public InterTabTransfer(object item, DragablzItem originatorContainer, Point dragStartItemOffset,\n            IList<FloatingItemSnapShot> floatingItemSnapShots)\n        {\n            if (item == null) throw new ArgumentNullException(\"item\");\n            if (originatorContainer == null) throw new ArgumentNullException(\"originatorContainer\");\n            if (floatingItemSnapShots == null) throw new ArgumentNullException(\"floatingItemSnapShots\");\n\n            _transferReason = InterTabTransferReason.Reentry;\n\n            _item = item;\n            _originatorContainer = originatorContainer;\n            _dragStartItemOffset = dragStartItemOffset;\n            _floatingItemSnapShots = floatingItemSnapShots;\n        }\n\n        public Orientation BreachOrientation\n        {\n            get { return _breachOrientation; }\n        }\n\n        public Point DragStartWindowOffset\n        {\n            get { return _dragStartWindowOffset; }\n        }\n\n        public object Item\n        {\n            get { return _item; }\n        }\n\n        public DragablzItem OriginatorContainer\n        {\n            get { return _originatorContainer; }\n        }\n\n        public InterTabTransferReason TransferReason\n        {\n            get { return _transferReason; }\n        }\n\n        public Point DragStartItemOffset\n        {\n            get { return _dragStartItemOffset; }\n        }\n\n        public Point ItemPositionWithinHeader\n        {\n            get { return _itemPositionWithinHeader; }\n        }\n\n        public Size ItemSize\n        {\n            get { return _itemSize; }\n        }\n\n        public IList<FloatingItemSnapShot> FloatingItemSnapShots\n        {\n            get { return _floatingItemSnapShots; }\n        }\n\n        public bool IsTransposing\n        {\n            get { return _isTransposing; }\n        }\n    }\n}"
  },
  {
    "path": "third_party/Dragablz/Dragablz/Core/MultiComparer.cs",
    "content": "﻿using System;\nusing System.Collections.Generic;\nusing System.Linq;\n\nnamespace Dragablz.Core\n{\n    internal class MultiComparer<TObject> : IComparer<TObject>\n    {\n        private readonly IList<FuncComparer<TObject>> _attributeComparers;\n\n        private MultiComparer(FuncComparer<TObject> firstComparer)        \n        {\n            _attributeComparers = new List<FuncComparer<TObject>>\n            {\n                firstComparer\n            };\n        }\n\n        public static MultiComparer<TObject> Ascending<TAttribute>(Func<TObject, TAttribute> accessor) \n            where TAttribute : IComparable\n        {\n            if (accessor == null) throw new ArgumentNullException(\"accessor\");            \n\n            return new MultiComparer<TObject>(BuildAscendingComparer(accessor));\n        }\n\n        public static MultiComparer<TObject> Descending<TAttribute>(Func<TObject, TAttribute> accessor) \n            where TAttribute : IComparable\n        {\n            if (accessor == null) throw new ArgumentNullException(\"accessor\");\n\n            return new MultiComparer<TObject>(BuildDescendingComparer(accessor));\n        }\n\n        public MultiComparer<TObject> ThenAscending<TAttribute>(Func<TObject, TAttribute> accessor)\n            where TAttribute : IComparable\n        {\n            if (accessor == null) throw new ArgumentNullException(\"accessor\");\n\n            _attributeComparers.Add(BuildAscendingComparer(accessor));\n\n            return this;\n        }\n\n        public MultiComparer<TObject> ThenDescending<TAttribute>(Func<TObject, TAttribute> accessor)\n            where TAttribute : IComparable\n        {\n            if (accessor == null) throw new ArgumentNullException(\"accessor\");\n\n            _attributeComparers.Add(BuildDescendingComparer(accessor));\n\n            return this;\n        }\n\n        public int Compare(TObject x, TObject y)\n        {\n            var nonEqual = _attributeComparers.Select(c => new {result = c.Compare(x, y)}).FirstOrDefault(a => a.result != 0);\n\n            return nonEqual == null ? 0 : nonEqual.result;\n        }\n\n        private static FuncComparer<TObject> BuildAscendingComparer<TAttribute>(Func<TObject, TAttribute> accessor)\n             where TAttribute : IComparable\n        {\n            //TODO handle ref types better\n            return new FuncComparer<TObject>((x, y) => accessor(x).CompareTo(accessor(y)));\n            \n        }\n\n        private static FuncComparer<TObject> BuildDescendingComparer<TAttribute>(Func<TObject, TAttribute> accessor)\n            where TAttribute : IComparable\n        {\n            //TODO handle ref types better\n            return new FuncComparer<TObject>((x, y) => accessor(y).CompareTo(accessor(x)));\n        }\n    }\n}\n"
  },
  {
    "path": "third_party/Dragablz/Dragablz/Core/Native.cs",
    "content": "﻿using System;\nusing System.Collections.Generic;\nusing System.Linq;\nusing System.Runtime.InteropServices;\nusing System.Windows;\nusing System.Windows.Interop;\n\nnamespace Dragablz.Core\n{\n    internal static class Native\n    {\n        [StructLayout(LayoutKind.Sequential)]\n        public struct POINT\n        {\n            public int X;\n            public int Y;\n\n            public static implicit operator Point(POINT point)\n            {\n                return new Point(point.X, point.Y);\n            }\n        }\n\n        [StructLayout(LayoutKind.Sequential)]\n        public struct RECT\n        {\n            public int left;\n            public int top;\n            public int right;\n            public int bottom;\n        }   \n\n        [DllImport(\"user32.dll\")]\n        private static extern bool GetCursorPos(out POINT lpPoint);\n\n        public static POINT GetRawCursorPos()\n        {\n            POINT lpPoint;\n            GetCursorPos(out lpPoint);\n            return lpPoint;\n        }\n\n        public static Point GetCursorPos()\n        {\n            POINT lpPoint;\n            GetCursorPos(out lpPoint);\n            return lpPoint;\n        }\n\n        [DllImport(\"User32.dll\")]\n        private static extern IntPtr GetDC(IntPtr hwnd);\n\n        [DllImport(\"gdi32.dll\")]\n        private static extern int GetDeviceCaps(IntPtr hdc, int nIndex);\n\n        [DllImport(\"user32.dll\")]\n        private static extern bool ReleaseDC(IntPtr hWnd, IntPtr hDC);\n\n        public static Point ToWpf(this Point pixelPoint)\n        {\n            var desktop = GetDC(IntPtr.Zero); \n            var dpi = GetDeviceCaps(desktop, 88);\n            ReleaseDC(IntPtr.Zero, desktop);\n\n            var physicalUnitSize = 96d / dpi ;\n            var wpfPoint = new Point(physicalUnitSize * pixelPoint.X, physicalUnitSize * pixelPoint.Y);\n\n            return wpfPoint;\n        }\n\n        public static IEnumerable<Window> SortWindowsTopToBottom(IEnumerable<Window> windows)\n        {\n            var windowsByHandle = windows.Select(window =>\n            {\n                var hwndSource = PresentationSource.FromVisual(window) as HwndSource;\n                var handle = hwndSource != null ? hwndSource.Handle : IntPtr.Zero;\n                return new {window, handle};\n            }).Where(x => x.handle != IntPtr.Zero)\n                .ToDictionary(x => x.handle, x => x.window);\n\n            for (var hWnd = GetTopWindow(IntPtr.Zero); hWnd != IntPtr.Zero; hWnd = GetWindow(hWnd, GW_HWNDNEXT))\n                if (windowsByHandle.ContainsKey((hWnd)))\n                    yield return windowsByHandle[hWnd];\n        }\n\n        public const int SW_SHOWNORMAL = 1;\n        [DllImport(\"user32.dll\")]\n        public static extern bool SetWindowPlacement(IntPtr hWnd, [In] ref WINDOWPLACEMENT lpwndpl);\n\n        private const uint GW_HWNDNEXT = 2;\n        [DllImport(\"User32\")]\n        public static extern IntPtr GetTopWindow(IntPtr hWnd);\n\n        [DllImport(\"User32\")]\n        public static extern IntPtr GetWindow(IntPtr hWnd, uint wCmd);\n\n        [Serializable]\n        [StructLayout(LayoutKind.Sequential)]\n        public struct WINDOWPLACEMENT\n        {\n            public int length;\n            public int flags;\n            public int showCmd;\n            public POINT minPosition;\n            public POINT maxPosition;\n            public RECT normalPosition;\n        }        \n\n        [DllImport(\"user32.dll\", CharSet = CharSet.Auto)]\n        internal static extern IntPtr SendMessage(IntPtr hWnd, WindowMessage msg, IntPtr wParam, IntPtr lParam);\n        [DllImport(\"user32.dll\", CharSet = CharSet.Auto)]\n        internal static extern IntPtr PostMessage(IntPtr hWnd, WindowMessage msg, IntPtr wParam, IntPtr lParam);\n\n\n        [DllImport(\"dwmapi.dll\", EntryPoint = \"#127\")]\n        internal static extern void DwmGetColorizationParameters(ref DWMCOLORIZATIONPARAMS dp);\n\n        [StructLayout(LayoutKind.Sequential)]\n        internal struct DWMCOLORIZATIONPARAMS\n        {\n            public UInt32 ColorizationColor;\n            public UInt32 ColorizationAfterglow;\n            public UInt32 ColorizationColorBalance;\n            public UInt32 ColorizationAfterglowBalance;\n            public UInt32 ColorizationBlurBalance;\n            public UInt32 ColorizationGlassReflectionIntensity;\n            public UInt32 ColorizationOpaqueBlend;\n        }\n\n    }\n}\n"
  },
  {
    "path": "third_party/Dragablz/Dragablz/Core/SystemCommand.cs",
    "content": "﻿namespace Dragablz.Core\n{\n    internal enum SystemCommand\n    {\n        SC_CLOSE = 0xF060,\n        SC_CONTEXTHELP = 0xF180,\n        SC_DEFAULT = 0xF160,\n        SC_HOTKEY = 0xF150,\n        SC_HSCROLL = 0xF080,\n        SCF_ISSECURE = 0x00000001,\n        SC_KEYMENU = 0xF100,\n        SC_MAXIMIZE = 0xF030,\n        SC_MINIMIZE = 0xF020,\n        SC_MONITORPOWER = 0xF170,\n        SC_MOUSEMENU = 0xF090,\n        SC_MOVE = 0xF010,\n        SC_MOUSEMOVE = 0xF012,\n        SC_NEXTWINDOW = 0xF040,\n        SC_PREVWINDOW = 0xF050,\n        SC_RESTORE = 0xF120,\n        SC_SCREENSAVE = 0xF140,\n        SC_SIZE = 0xF000,\n        SC_TASKLIST = 0xF130,\n        SC_VSCROLL = 0xF070\n    }\n}"
  },
  {
    "path": "third_party/Dragablz/Dragablz/Core/TabHeaderDragStartInformation.cs",
    "content": "﻿using System;\n\nnamespace Dragablz.Core\n{\n    internal class TabHeaderDragStartInformation\n    {\n        private readonly DragablzItem _dragItem;\n        private readonly double _dragablzItemsControlHorizontalOffset;\n        private readonly double _dragablzItemControlVerticalOffset; \n        private readonly double _dragablzItemHorizontalOffset;\n        private readonly double _dragablzItemVerticalOffset;\n\n        public TabHeaderDragStartInformation(\n            DragablzItem dragItem,\n            double dragablzItemsControlHorizontalOffset, double dragablzItemControlVerticalOffset, double dragablzItemHorizontalOffset, double dragablzItemVerticalOffset)\n        {\n            if (dragItem == null) throw new ArgumentNullException(\"dragItem\");\n\n            _dragItem = dragItem;\n            _dragablzItemsControlHorizontalOffset = dragablzItemsControlHorizontalOffset;\n            _dragablzItemControlVerticalOffset = dragablzItemControlVerticalOffset;\n            _dragablzItemHorizontalOffset = dragablzItemHorizontalOffset;\n            _dragablzItemVerticalOffset = dragablzItemVerticalOffset;\n        }\n\n        public double DragablzItemsControlHorizontalOffset\n        {\n            get { return _dragablzItemsControlHorizontalOffset; }\n        }\n\n        public double DragablzItemControlVerticalOffset\n        {\n            get { return _dragablzItemControlVerticalOffset; }\n        }\n\n        public double DragablzItemHorizontalOffset\n        {\n            get { return _dragablzItemHorizontalOffset; }\n        }\n\n        public double DragablzItemVerticalOffset\n        {\n            get { return _dragablzItemVerticalOffset; }\n        }\n\n        public DragablzItem DragItem\n        {\n            get { return _dragItem; }\n        }\n    }\n}"
  },
  {
    "path": "third_party/Dragablz/Dragablz/Core/WindowMessage.cs",
    "content": "﻿namespace Dragablz.Core\n{\n    internal enum WindowMessage\n    {\n        WM_NULL = 0,\n        WM_CREATE = 1,\n        WM_DESTROY = 2,\n        WM_MOVE = 3,\n        WM_SIZE = 5,\n        WM_ACTIVATE = 6,\n        WM_SETFOCUS = 7,\n        WM_KILLFOCUS = 8,\n        WM_ENABLE = 10,\n        WM_SETREDRAW = 11,\n        WM_SETTEXT = 12,\n        WM_GETTEXT = 13,\n        WM_GETTEXTLENGTH = 14,\n        WM_PAINT = 15,\n        WM_CLOSE = 16,\n        WM_QUERYENDSESSION = 17,\n        WM_QUIT = 18,\n        WM_QUERYOPEN = 19,\n        WM_ERASEBKGND = 20,\n        WM_SYSCOLORCHANGE = 21,\n        WM_ENDSESSION = 22,\n        WM_SHOWWINDOW = 24,\n        WM_CTLCOLOR = 25,\n        WM_SETTINGCHANGE = 26,\n        WM_WININICHANGE = 26,\n        WM_DEVMODECHANGE = 27,\n        WM_ACTIVATEAPP = 28,\n        WM_FONTCHANGE = 29,\n        WM_TIMECHANGE = 30,\n        WM_CANCELMODE = 31,\n        WM_SETCURSOR = 32,\n        WM_TABLET_MAXOFFSET = 32,\n        WM_MOUSEACTIVATE = 33,\n        WM_CHILDACTIVATE = 34,\n        WM_QUEUESYNC = 35,\n        WM_GETMINMAXINFO = 36,\n        WM_PAINTICON = 38,\n        WM_ICONERASEBKGND = 39,\n        WM_NEXTDLGCTL = 40,\n        WM_SPOOLERSTATUS = 42,\n        WM_DRAWITEM = 43,\n        WM_MEASUREITEM = 44,\n        WM_DELETEITEM = 45,\n        WM_VKEYTOITEM = 46,\n        WM_CHARTOITEM = 47,\n        WM_SETFONT = 48,\n        WM_GETFONT = 49,\n        WM_SETHOTKEY = 50,\n        WM_GETHOTKEY = 51,\n        WM_QUERYDRAGICON = 55,\n        WM_COMPAREITEM = 57,\n        WM_GETOBJECT = 61,\n        WM_COMPACTING = 65,\n        WM_COMMNOTIFY = 68,\n        WM_WINDOWPOSCHANGING = 70,\n        WM_WINDOWPOSCHANGED = 71,\n        WM_POWER = 72,\n        WM_COPYDATA = 74,\n        WM_CANCELJOURNAL = 75,\n        WM_NOTIFY = 78,\n        WM_INPUTLANGCHANGEREQUEST = 80,\n        WM_INPUTLANGCHANGE = 81,\n        WM_TCARD = 82,\n        WM_HELP = 83,\n        WM_USERCHANGED = 84,\n        WM_NOTIFYFORMAT = 85,\n        WM_CONTEXTMENU = 123,\n        WM_STYLECHANGING = 124,\n        WM_STYLECHANGED = 125,\n        WM_DISPLAYCHANGE = 126,\n        WM_GETICON = 127,\n        WM_SETICON = 128,\n        WM_NCCREATE = 129,\n        WM_NCDESTROY = 130,\n        WM_NCCALCSIZE = 131,\n        WM_NCHITTEST = 132,\n        WM_NCPAINT = 133,\n        WM_NCACTIVATE = 134,\n        WM_GETDLGCODE = 135,\n        WM_SYNCPAINT = 136,\n        WM_MOUSEQUERY = 155,\n        WM_NCMOUSEMOVE = 160,\n        WM_NCLBUTTONDOWN = 161,\n        WM_NCLBUTTONUP = 162,\n        WM_NCLBUTTONDBLCLK = 163,\n        WM_NCRBUTTONDOWN = 164,\n        WM_NCRBUTTONUP = 165,\n        WM_NCRBUTTONDBLCLK = 166,\n        WM_NCMBUTTONDOWN = 167,\n        WM_NCMBUTTONUP = 168,\n        WM_NCMBUTTONDBLCLK = 169,\n        WM_NCXBUTTONDOWN = 171,\n        WM_NCXBUTTONUP = 172,\n        WM_NCXBUTTONDBLCLK = 173,\n        WM_INPUT = 255,\n        WM_KEYDOWN = 256,\n        WM_KEYFIRST = 256,\n        WM_KEYUP = 257,\n        WM_CHAR = 258,\n        WM_DEADCHAR = 259,\n        WM_SYSKEYDOWN = 260,\n        WM_SYSKEYUP = 261,\n        WM_SYSCHAR = 262,\n        WM_SYSDEADCHAR = 263,\n        WM_KEYLAST = 264,\n        WM_IME_STARTCOMPOSITION = 269,\n        WM_IME_ENDCOMPOSITION = 270,\n        WM_IME_COMPOSITION = 271,\n        WM_IME_KEYLAST = 271,\n        WM_INITDIALOG = 272,\n        WM_COMMAND = 273,\n        WM_SYSCOMMAND = 274,\n        WM_TIMER = 275,\n        WM_HSCROLL = 276,\n        WM_VSCROLL = 277,\n        WM_INITMENU = 278,\n        WM_INITMENUPOPUP = 279,\n        WM_MENUSELECT = 287,\n        WM_MENUCHAR = 288,\n        WM_ENTERIDLE = 289,\n        WM_UNINITMENUPOPUP = 293,\n        WM_CHANGEUISTATE = 295,\n        WM_UPDATEUISTATE = 296,\n        WM_QUERYUISTATE = 297,\n        WM_CTLCOLORMSGBOX = 306,\n        WM_CTLCOLOREDIT = 307,\n        WM_CTLCOLORLISTBOX = 308,\n        WM_CTLCOLORBTN = 309,\n        WM_CTLCOLORDLG = 310,\n        WM_CTLCOLORSCROLLBAR = 311,\n        WM_CTLCOLORSTATIC = 312,\n        WM_MOUSEFIRST = 512,\n        WM_MOUSEMOVE = 512,\n        WM_LBUTTONDOWN = 513,\n        WM_LBUTTONUP = 514,\n        WM_LBUTTONDBLCLK = 515,\n        WM_RBUTTONDOWN = 516,\n        WM_RBUTTONUP = 517,\n        WM_RBUTTONDBLCLK = 518,\n        WM_MBUTTONDOWN = 519,\n        WM_MBUTTONUP = 520,\n        WM_MBUTTONDBLCLK = 521,\n        WM_MOUSEWHEEL = 522,\n        WM_XBUTTONDOWN = 523,\n        WM_XBUTTONUP = 524,\n        WM_XBUTTONDBLCLK = 525,\n        WM_MOUSEHWHEEL = 526,\n        WM_MOUSELAST = 526,\n        WM_PARENTNOTIFY = 528,\n        WM_ENTERMENULOOP = 529,\n        WM_EXITMENULOOP = 530,\n        WM_NEXTMENU = 531,\n        WM_SIZING = 532,\n        WM_CAPTURECHANGED = 533,\n        WM_MOVING = 534,\n        WM_POWERBROADCAST = 536,\n        WM_DEVICECHANGE = 537,\n        WM_MDICREATE = 544,\n        WM_MDIDESTROY = 545,\n        WM_MDIACTIVATE = 546,\n        WM_MDIRESTORE = 547,\n        WM_MDINEXT = 548,\n        WM_MDIMAXIMIZE = 549,\n        WM_MDITILE = 550,\n        WM_MDICASCADE = 551,\n        WM_MDIICONARRANGE = 552,\n        WM_MDIGETACTIVE = 553,\n        WM_MDISETMENU = 560,\n        WM_ENTERSIZEMOVE = 561,\n        WM_EXITSIZEMOVE = 562,\n        WM_DROPFILES = 563,\n        WM_MDIREFRESHMENU = 564,\n        WM_IME_SETCONTEXT = 641,\n        WM_IME_NOTIFY = 642,\n        WM_IME_CONTROL = 643,\n        WM_IME_COMPOSITIONFULL = 644,\n        WM_IME_SELECT = 645,\n        WM_IME_CHAR = 646,\n        WM_IME_REQUEST = 648,\n        WM_IME_KEYDOWN = 656,\n        WM_IME_KEYUP = 657,\n        WM_MOUSEHOVER = 673,\n        WM_NCMOUSELEAVE = 674,\n        WM_MOUSELEAVE = 675,\n        WM_WTSSESSION_CHANGE = 689,\n        WM_TABLET_DEFBASE = 704,\n        WM_TABLET_ADDED = 712,\n        WM_TABLET_DELETED = 713,\n        WM_TABLET_FLICK = 715,\n        WM_TABLET_QUERYSYSTEMGESTURESTATUS = 716,\n        WM_CUT = 768,\n        WM_COPY = 769,\n        WM_PASTE = 770,\n        WM_CLEAR = 771,\n        WM_UNDO = 772,\n        WM_RENDERFORMAT = 773,\n        WM_RENDERALLFORMATS = 774,\n        WM_DESTROYCLIPBOARD = 775,\n        WM_DRAWCLIPBOARD = 776,\n        WM_PAINTCLIPBOARD = 777,\n        WM_VSCROLLCLIPBOARD = 778,\n        WM_SIZECLIPBOARD = 779,\n        WM_ASKCBFORMATNAME = 780,\n        WM_CHANGECBCHAIN = 781,\n        WM_HSCROLLCLIPBOARD = 782,\n        WM_QUERYNEWPALETTE = 783,\n        WM_PALETTEISCHANGING = 784,\n        WM_PALETTECHANGED = 785,\n        WM_HOTKEY = 786,\n        WM_PRINT = 791,\n        WM_PRINTCLIENT = 792,\n        WM_APPCOMMAND = 793,\n        WM_THEMECHANGED = 794,\n        WM_DWMCOMPOSITIONCHANGED = 798,\n        WM_DWMNCRENDERINGCHANGED = 799,\n        WM_DWMCOLORIZATIONCOLORCHANGED = 800,\n        WM_DWMWINDOWMAXIMIZEDCHANGE = 801,\n        WM_DWMSENDICONICTHUMBNAIL = 803,\n        WM_DWMSENDICONICLIVEPREVIEWBITMAP = 806,\n        WM_HANDHELDFIRST = 856,\n        WM_HANDHELDLAST = 863,\n        WM_AFXFIRST = 864,\n        WM_AFXLAST = 895,\n        WM_PENWINFIRST = 896,\n        WM_PENWINLAST = 911,\n        WM_USER = 1024,\n        WM_APP = 32768,\n    }\n\n    public enum WindowSizingMessage\n    {\n        WMSZ_BOTTOM = 6,\n        WMSZ_BOTTOMLEFT = 7,\n        WMSZ_BOTTOMRIGHT = 8,\n        WMSZ_LEFT = 1,\n        WMSZ_RIGHT = 2,\n        WMSZ_TOP = 3,\n        WMSZ_TOPLEFT = 4,\n        WMSZ_TOPRIGHT = 5,\n    }\n}"
  },
  {
    "path": "third_party/Dragablz/Dragablz/DefaultInterLayoutClient.cs",
    "content": "using System;\nusing System.Runtime.ConstrainedExecution;\nusing System.Windows;\nusing System.Windows.Controls;\nusing System.Windows.Data;\n\nnamespace Dragablz\n{\n    /// <summary>\n    /// Provides a simple implementation of <see cref=\"IInterLayoutClient\"/>, but only really useful if \n    /// <see cref=\"TabItem\"/> instances are specified in XAML.  If you are binding via ItemsSource then\n    /// you most likely want to create your own implementation of <see cref=\"IInterLayoutClient\"/>.\n    /// </summary>\n    public class DefaultInterLayoutClient : IInterLayoutClient\n    {\n        public INewTabHost<UIElement> GetNewHost(object partition, TabablzControl source)\n        {\n            var tabablzControl = new TabablzControl {DataContext = source.DataContext};\n\n            Clone(source, tabablzControl);\n\n            if (source.InterTabController == null)\n                throw new InvalidOperationException(\"Source tab does not have an InterTabCOntroller set.  Ensure this is set on initial, and subsequently generated tab controls.\");\n\n            var newInterTabController = new InterTabController\n            {\n                Partition = source.InterTabController.Partition\n            };\n            Clone(source.InterTabController, newInterTabController);\n            tabablzControl.SetCurrentValue(TabablzControl.InterTabControllerProperty, newInterTabController);            \n\n            return new NewTabHost<UIElement>(tabablzControl, tabablzControl);\n        }\n\n        private static void Clone(DependencyObject from, DependencyObject to)\n        {\n            var localValueEnumerator = from.GetLocalValueEnumerator();\n            while (localValueEnumerator.MoveNext())\n            {\n                if (localValueEnumerator.Current.Property.ReadOnly ||\n                    localValueEnumerator.Current.Value is FrameworkElement) continue;\n                \n                if (!(localValueEnumerator.Current.Value is BindingExpressionBase))\n                    to.SetCurrentValue(localValueEnumerator.Current.Property, localValueEnumerator.Current.Value);                \n            }            \n        }\n    }\n}"
  },
  {
    "path": "third_party/Dragablz/Dragablz/DefaultInterTabClient.cs",
    "content": "using System;\nusing System.Linq;\nusing System.Windows;\nusing System.Windows.Threading;\nusing Dragablz.Core;\n\nnamespace Dragablz\n{\n    public class DefaultInterTabClient : IInterTabClient\n    {        \n        public virtual INewTabHost<Window> GetNewHost(IInterTabClient interTabClient, object partition, TabablzControl source)\n        {\n            if (source == null) throw new ArgumentNullException(\"source\");\n            var sourceWindow = Window.GetWindow(source);\n            if (sourceWindow == null) throw new ApplicationException(\"Unable to ascertain source window.\");\n            var newWindow = (Window)Activator.CreateInstance(sourceWindow.GetType());\n\n            newWindow.Dispatcher.Invoke(new Action(() => { }), DispatcherPriority.DataBind);\n\n            var newTabablzControl = newWindow.LogicalTreeDepthFirstTraversal().OfType<TabablzControl>().FirstOrDefault();\n            if (newTabablzControl == null) throw new ApplicationException(\"Unable to ascertain tab control.\");\n\n            if (newTabablzControl.ItemsSource == null)\n                newTabablzControl.Items.Clear();\n\n            return new NewTabHost<Window>(newWindow, newTabablzControl);            \n        }\n\n        public virtual TabEmptiedResponse TabEmptiedHandler(TabablzControl tabControl, Window window)\n        {\n            return TabEmptiedResponse.CloseWindowOrLayoutBranch;\n        }\n    }\n}"
  },
  {
    "path": "third_party/Dragablz/Dragablz/Dockablz/Branch.cs",
    "content": "﻿using System;\nusing System.Collections.Generic;\nusing System.ComponentModel;\nusing System.Globalization;\nusing System.Linq;\nusing System.Text;\nusing System.Threading.Tasks;\nusing System.Windows;\nusing System.Windows.Controls;\nusing System.Windows.Data;\nusing System.Windows.Documents;\nusing System.Windows.Input;\nusing System.Windows.Markup;\nusing System.Windows.Media;\nusing System.Windows.Media.Imaging;\nusing System.Windows.Navigation;\nusing System.Windows.Shapes;\n\nnamespace Dragablz.Dockablz\n{\n    [TemplatePart(Name = FirstContentPresenterPartName, Type=typeof(ContentPresenter))]\n    [TemplatePart(Name = SecondContentPresenterPartName, Type = typeof(ContentPresenter))]\n    public class Branch : Control\n    {\n        private const string FirstContentPresenterPartName = \"PART_FirstContentPresenter\";\n        private const string SecondContentPresenterPartName = \"PART_SecondContentPresenter\";\n\n        static Branch()\n        {\n            DefaultStyleKeyProperty.OverrideMetadata(typeof(Branch), new FrameworkPropertyMetadata(typeof(Branch)));\n        }\n\n        public static readonly DependencyProperty OrientationProperty = DependencyProperty.Register(\n            \"Orientation\", typeof (Orientation), typeof (Branch), new PropertyMetadata(default(Orientation)));\n\n        public Orientation Orientation\n        {\n            get { return (Orientation) GetValue(OrientationProperty); }\n            set { SetValue(OrientationProperty, value); }\n        }\n\n        public static readonly DependencyProperty FirstItemProperty = DependencyProperty.Register(\n            \"FirstItem\", typeof(object), typeof(Branch), new PropertyMetadata(default(object)));\n\n        public object FirstItem\n        {\n            get { return GetValue(FirstItemProperty); }\n            set { SetValue(FirstItemProperty, value); }\n        }\n\n        public static readonly DependencyProperty FirstItemLengthProperty = DependencyProperty.Register(\n            \"FirstItemLength\", typeof (GridLength), typeof (Branch), new FrameworkPropertyMetadata(new GridLength(0.49999, GridUnitType.Star), FrameworkPropertyMetadataOptions.BindsTwoWayByDefault));\n\n        public GridLength FirstItemLength\n        {\n            get { return (GridLength) GetValue(FirstItemLengthProperty); }\n            set { SetValue(FirstItemLengthProperty, value); }\n        }\n\n        public static readonly DependencyProperty SecondItemProperty = DependencyProperty.Register(\n            \"SecondItem\", typeof(object), typeof(Branch), new PropertyMetadata(default(object)));\n\n        public object SecondItem\n        {\n            get { return GetValue(SecondItemProperty); }\n            set { SetValue(SecondItemProperty, value); }\n        }\n\n        public static readonly DependencyProperty SecondItemLengthProperty = DependencyProperty.Register(\n            \"SecondItemLength\", typeof(GridLength), typeof(Branch), new FrameworkPropertyMetadata(new GridLength(0.50001, GridUnitType.Star), FrameworkPropertyMetadataOptions.BindsTwoWayByDefault));\n\n        public GridLength SecondItemLength\n        {\n            get { return (GridLength) GetValue(SecondItemLengthProperty); }\n            set { SetValue(SecondItemLengthProperty, value); }\n        }        \n\n        /// <summary>\n        /// Gets the proportional size of the first item, between 0 and 1, where 1 would represent the entire size of the branch.\n        /// </summary>\n        /// <returns></returns>\n        public double GetFirstProportion()\n        {\n            return (1/(FirstItemLength.Value + SecondItemLength.Value))*FirstItemLength.Value;\n        }\n\n        public override void OnApplyTemplate()\n        {\n            base.OnApplyTemplate();\n\n            FirstContentPresenter = GetTemplateChild(FirstContentPresenterPartName) as ContentPresenter;\n            SecondContentPresenter = GetTemplateChild(SecondContentPresenterPartName) as ContentPresenter;\n        }\n\n        internal ContentPresenter FirstContentPresenter { get; private set; }\n        internal ContentPresenter SecondContentPresenter { get; private set; }\n    }\n}\n"
  },
  {
    "path": "third_party/Dragablz/Dragablz/Dockablz/BranchAccessor.cs",
    "content": "﻿using System;\nusing System.Linq;\nusing System.Text;\nusing System.Threading.Tasks;\nusing System.Windows;\nusing System.Windows.Controls;\nusing Dragablz.Core;\n\nnamespace Dragablz.Dockablz\n{ \n    public class BranchAccessor\n    {\n        private readonly Branch _branch;\n        private readonly BranchAccessor _firstItemBranchAccessor;\n        private readonly BranchAccessor _secondItemBranchAccessor;\n        private readonly TabablzControl _firstItemTabablzControl;\n        private readonly TabablzControl _secondItemTabablzControl;\n\n        public BranchAccessor(Branch branch)\n        {\n            if (branch == null) throw new ArgumentNullException(\"branch\");\n\n            _branch = branch;\n\n            var firstChildBranch = branch.FirstItem as Branch;\n            if (firstChildBranch != null)\n                _firstItemBranchAccessor = new BranchAccessor(firstChildBranch);\n            else\n                _firstItemTabablzControl = FindTabablzControl(branch.FirstItem, branch.FirstContentPresenter);\n\n            var secondChildBranch = branch.SecondItem as Branch;            \n            if (secondChildBranch != null)\n                _secondItemBranchAccessor = new BranchAccessor(secondChildBranch);\n            else\n                _secondItemTabablzControl = FindTabablzControl(branch.SecondItem, branch.SecondContentPresenter);\n        }\n\n        private static TabablzControl FindTabablzControl(object item, DependencyObject contentPresenter)\n        {\n            var result = item as TabablzControl;\n            return result ?? contentPresenter.VisualTreeDepthFirstTraversal().OfType<TabablzControl>().FirstOrDefault();\n        }\n\n        public Branch Branch\n        {\n            get { return _branch; }\n        }\n\n        public BranchAccessor FirstItemBranchAccessor\n        {\n            get { return _firstItemBranchAccessor; }\n        }\n\n        public BranchAccessor SecondItemBranchAccessor\n        {\n            get { return _secondItemBranchAccessor; }\n        }\n\n        public TabablzControl FirstItemTabablzControl\n        {\n            get { return _firstItemTabablzControl; }\n        }\n\n        public TabablzControl SecondItemTabablzControl\n        {\n            get { return _secondItemTabablzControl; }\n        }\n\n        /// <summary>\n        /// Visits the content of the first or second side of a branch, according to its content type.  No more than one of the provided <see cref=\"Action\"/>\n        /// callbacks will be called.  \n        /// </summary>\n        /// <param name=\"childItem\"></param>\n        /// <param name=\"childBranchVisitor\"></param>\n        /// <param name=\"childTabablzControlVisitor\"></param>\n        /// <param name=\"childContentVisitor\"></param>\n        /// <returns></returns>\n        public BranchAccessor Visit(BranchItem childItem,\n            Action<BranchAccessor> childBranchVisitor = null,\n            Action<TabablzControl> childTabablzControlVisitor = null,\n            Action<object> childContentVisitor = null)\n        {\n            Func<BranchAccessor> branchGetter;\n            Func<TabablzControl> tabGetter;\n            Func<object> contentGetter;\n\n            switch (childItem)\n            {\n                case BranchItem.First:\n                    branchGetter = () => _firstItemBranchAccessor;\n                    tabGetter = () => _firstItemTabablzControl;\n                    contentGetter = () => _branch.FirstItem;\n                    break;\n                case BranchItem.Second:\n                    branchGetter = () => _secondItemBranchAccessor;\n                    tabGetter = () => _secondItemTabablzControl;\n                    contentGetter = () => _branch.SecondItem;\n                    break;\n                default:\n                    throw new ArgumentOutOfRangeException(\"childItem\");\n            }\n\n            var branchDescription = branchGetter();\n            if (branchDescription != null)\n            {\n                if (childBranchVisitor != null)\n                    childBranchVisitor(branchDescription);\n                return this;\n            }\n            \n            var tabablzControl = tabGetter();\n            if (tabablzControl != null)\n            {\n                if (childTabablzControlVisitor != null)\n                    childTabablzControlVisitor(tabablzControl);\n\n                return this;\n            }\n\n            if (childContentVisitor == null) return this;\n\n            var content = contentGetter();\n            if (content != null)\n                childContentVisitor(content);\n\n            return this;\n        }\n    }    \n}\n"
  },
  {
    "path": "third_party/Dragablz/Dragablz/Dockablz/BranchItem.cs",
    "content": "﻿namespace Dragablz.Dockablz\n{\n    public enum BranchItem\n    {\n        First,\n        Second\n    }\n}"
  },
  {
    "path": "third_party/Dragablz/Dragablz/Dockablz/BranchResult.cs",
    "content": "using System;\n\nnamespace Dragablz.Dockablz\n{\n    public class BranchResult\n    {\n        private readonly Branch _branch;\n        private readonly TabablzControl _tabablzControl;\n\n        public BranchResult(Branch branch, TabablzControl tabablzControl)\n        {\n            if (branch == null) throw new ArgumentNullException(\"branch\");\n            if (tabablzControl == null) throw new ArgumentNullException(\"tabablzControl\");\n            \n            _branch = branch;\n            _tabablzControl = tabablzControl;\n        }\n\n        /// <summary>\n        /// The new branch.\n        /// </summary>\n        public Branch Branch\n        {\n            get { return _branch; }\n        }\n\n        /// <summary>\n        /// The new tab control.\n        /// </summary>\n        public TabablzControl TabablzControl\n        {\n            get { return _tabablzControl; }\n        }\n    }\n}"
  },
  {
    "path": "third_party/Dragablz/Dragablz/Dockablz/CouldBeHeaderedStyleSelector.cs",
    "content": "using System.Windows;\nusing System.Windows.Controls;\n\nnamespace Dragablz.Dockablz\n{\n    public class CouldBeHeaderedStyleSelector : StyleSelector\n    {\n        public Style NonHeaderedStyle { get; set; }\n\n        public Style HeaderedStyle { get; set; }\n\n        public override Style SelectStyle(object item, DependencyObject container)\n        {\n            return container is HeaderedDragablzItem || container is HeaderedContentControl\n                ? HeaderedStyle\n                : NonHeaderedStyle;\n        }\n    }\n}"
  },
  {
    "path": "third_party/Dragablz/Dragablz/Dockablz/DropZone.cs",
    "content": "using System.Windows;\nusing System.Windows.Controls;\n\nnamespace Dragablz.Dockablz\n{\n    public class DropZone : Control\n    {\n        static DropZone()\n        {\n            DefaultStyleKeyProperty.OverrideMetadata(typeof(DropZone), new FrameworkPropertyMetadata(typeof(DropZone)));            \n        }\n\n        public static readonly DependencyProperty LocationProperty = DependencyProperty.Register(\n            \"Location\", typeof (DropZoneLocation), typeof (DropZone), new PropertyMetadata(default(DropZoneLocation)));\n\n        public DropZoneLocation Location\n        {\n            get { return (DropZoneLocation) GetValue(LocationProperty); }\n            set { SetValue(LocationProperty, value); }\n        }\n\n        private static readonly DependencyPropertyKey IsOfferedPropertyKey =\n            DependencyProperty.RegisterReadOnly(\n                \"IsOffered\", typeof (bool), typeof (DropZone),\n                new PropertyMetadata(default(bool)));\n\n        public static readonly DependencyProperty IsOfferedProperty =\n            IsOfferedPropertyKey.DependencyProperty;\n\n        public bool IsOffered\n        {\n            get { return (bool) GetValue(IsOfferedProperty); }\n            internal set { SetValue(IsOfferedPropertyKey, value); }\n        }\n\n    }\n}"
  },
  {
    "path": "third_party/Dragablz/Dragablz/Dockablz/DropZoneLocation.cs",
    "content": "namespace Dragablz.Dockablz\n{\n    public enum DropZoneLocation\n    {        \n        Top,\n        Right,\n        Bottom,\n        Left,     \n        Floating\n    }\n}"
  },
  {
    "path": "third_party/Dragablz/Dragablz/Dockablz/Extensions.cs",
    "content": "using System;\nusing System.Runtime.Serialization;\n\nnamespace Dragablz.Dockablz\n{\n    public static class Extensions\n    {\n        /// <summary>\n        /// Begin a query of layout content, returning an accessor for examining the children.\n        /// </summary>\n        /// <param name=\"layout\"></param>\n        /// <returns></returns>\n        public static LayoutAccessor Query(this Layout layout)\n        {\n            if (layout == null) throw new ArgumentNullException(\"layout\");\n\n            return new LayoutAccessor(layout);\n        }\n\n        /// <summary>\n        /// Helper method for <see cref=\"LayoutAccessor.Visit\"/> which allows a context to be passed through.\n        /// </summary>\n        /// <typeparam name=\"TContext\"></typeparam>\n        /// <param name=\"layoutAccessor\"></param>\n        /// <param name=\"context\"></param>\n        /// <param name=\"branchVisitor\"></param>\n        /// <param name=\"tabablzControlVisitor\"></param>\n        /// <param name=\"contentVisitor\"></param>\n        /// <returns></returns>\n        public static LayoutAccessor Visit<TContext>(\n            this LayoutAccessor layoutAccessor,\n            TContext context,\n            Action<TContext, BranchAccessor> branchVisitor = null,\n            Action<TContext, TabablzControl> tabablzControlVisitor = null,\n            Action<TContext, object> contentVisitor = null)\n        {\n            if (layoutAccessor == null) throw new ArgumentNullException(\"layoutAccessor\");\n\n            layoutAccessor.Visit(\n                WrapVisitor(context, branchVisitor),\n                WrapVisitor(context, tabablzControlVisitor),\n                WrapVisitor(context, contentVisitor)\n                );\n\n            return layoutAccessor;\n        }\n\n        /// <summary>\n        /// Helper method for <see cref=\"BranchAccessor.Visit\"/> which allows a context to be passed through.\n        /// </summary>\n        /// <typeparam name=\"TContext\"></typeparam>\n        /// <param name=\"branchAccessor\"></param>\n        /// <param name=\"context\"></param>\n        /// <param name=\"childItem\"></param>\n        /// <param name=\"branchVisitor\"></param>\n        /// <param name=\"tabablzControlVisitor\"></param>\n        /// <param name=\"contentVisitor\"></param>\n        /// <returns></returns>\n        public static BranchAccessor Visit<TContext>(\n            this BranchAccessor branchAccessor,\n            TContext context,\n            BranchItem childItem,\n            Action<TContext, BranchAccessor> branchVisitor = null,\n            Action<TContext, TabablzControl> tabablzControlVisitor = null,\n            Action<TContext, object> contentVisitor = null)\n        {\n            if (branchAccessor == null) throw new ArgumentNullException(\"branchAccessor\");\n\n            branchAccessor.Visit(\n                childItem,\n                WrapVisitor(context, branchVisitor),\n                WrapVisitor(context, tabablzControlVisitor),\n                WrapVisitor(context, contentVisitor)\n                );\n\n            return branchAccessor;\n        }\n\n        private static Action<TVisitArg> WrapVisitor<TContext, TVisitArg>(TContext context, Action<TContext, TVisitArg> visitor)\n        {\n            if (visitor == null) return null;\n\n            return a => visitor(context, a);\n        }\n    }\n}"
  },
  {
    "path": "third_party/Dragablz/Dragablz/Dockablz/Finder.cs",
    "content": "using System;\n\nnamespace Dragablz.Dockablz\n{\n    internal static class Finder\n    {\n        internal static LocationReport Find(TabablzControl tabablzControl)\n        {\n            if (tabablzControl == null) throw new ArgumentNullException(\"tabablzControl\");\n\n            var locationReportBuilder = new LocationReportBuilder(tabablzControl);            \n\n            foreach (var loadedInstance in Layout.GetLoadedInstances())\n            {\n                locationReportBuilder.CurrentLayout = loadedInstance;\n\n                loadedInstance.Query().Visit(\n                    locationReportBuilder,\n                    BranchVisitor,\n                    TabablzControlVisitor\n                    );\n\n                if (locationReportBuilder.IsFound)\n                    break;\n            }\n\n            if (!locationReportBuilder.IsFound)\n                throw new LocationReportException(\"Instance not within any layout.\");\n\n            return locationReportBuilder.ToLocationReport();\n        }\n\n        private static void BranchVisitor(LocationReportBuilder locationReportBuilder, BranchAccessor branchAccessor)\n        {\n            if (Equals(branchAccessor.FirstItemTabablzControl, locationReportBuilder.TargetTabablzControl))\n                locationReportBuilder.MarkFound(branchAccessor.Branch, false);\n            else if (Equals(branchAccessor.SecondItemTabablzControl, locationReportBuilder.TargetTabablzControl))\n                locationReportBuilder.MarkFound(branchAccessor.Branch, true);\n            else\n            {\n                branchAccessor.Visit(BranchItem.First, ba => BranchVisitor(locationReportBuilder, ba));\n                if (locationReportBuilder.IsFound) return;\n                branchAccessor.Visit(BranchItem.Second, ba => BranchVisitor(locationReportBuilder, ba));\n            }            \n        }\n\n        private static void TabablzControlVisitor(LocationReportBuilder locationReportBuilder, TabablzControl tabablzControl)\n        {\n            if (Equals(tabablzControl, locationReportBuilder.TargetTabablzControl))\n                locationReportBuilder.MarkFound();\n        }\n    }\n}"
  },
  {
    "path": "third_party/Dragablz/Dragablz/Dockablz/FloatRequestedEvent.cs",
    "content": "﻿using System;\nusing System.Collections.Generic;\nusing System.Linq;\nusing System.Text;\nusing System.Threading.Tasks;\nusing System.Windows;\n\nnamespace Dragablz.Dockablz\n{\n    public delegate void FloatRequestedEventHandler(object sender, FloatRequestedEventArgs e);\n\n    public class FloatRequestedEventArgs : DragablzItemEventArgs\n    {\n        public FloatRequestedEventArgs(RoutedEvent routedEvent, object source, DragablzItem dragablzItem) \n            : base(routedEvent, source, dragablzItem)\n        { }\n\n        public FloatRequestedEventArgs(RoutedEvent routedEvent, DragablzItem dragablzItem) \n            : base(routedEvent, dragablzItem)\n        { }\n    }\n}\n"
  },
  {
    "path": "third_party/Dragablz/Dragablz/Dockablz/FloatTransfer.cs",
    "content": "using System;\n\nnamespace Dragablz.Dockablz\n{\n    internal class FloatTransfer\n    {\n        private readonly double _width;\n        private readonly double _height;\n        private readonly object _content;\n\n        public FloatTransfer(double width, double height, object content)\n        {\n            if (content == null) throw new ArgumentNullException(\"content\");\n            \n            _width = width;\n            _height = height;\n            _content = content;\n        }\n\n        public static FloatTransfer TakeSnapshot(DragablzItem dragablzItem, TabablzControl sourceTabControl)\n        {\n            if (dragablzItem == null) throw new ArgumentNullException(\"dragablzItem\");\n\n            return new FloatTransfer(sourceTabControl.ActualWidth, sourceTabControl.ActualHeight, dragablzItem.UnderlyingContent ?? dragablzItem.Content ?? dragablzItem);\n        }\n\n        [Obsolete]\n        //TODO width and height transfer obsolete\n        public double Width\n        {\n            get { return _width; }\n        }\n\n        [Obsolete]\n        //TODO width and height transfer obsolete\n        public double Height\n        {\n            get { return _height; }\n        }\n\n        public object Content\n        {\n            get { return _content; }\n        }\n    }\n}"
  },
  {
    "path": "third_party/Dragablz/Dragablz/Dockablz/FloatingItemSnapShot.cs",
    "content": "﻿using System;\nusing System.Collections.Generic;\nusing System.Linq;\nusing System.Text;\nusing System.Threading.Tasks;\nusing System.Windows;\nusing System.Windows.Controls;\n\nnamespace Dragablz.Dockablz\n{\n    /// <summary>\n    /// experimentational.  might have to puish this back to mvvm only\n    /// </summary>    \n    internal class FloatingItemSnapShot\n    {\n        private readonly object _content;\n        private readonly Rect _location;\n        private readonly int _zIndex;\n        private readonly WindowState _state;\n\n        public FloatingItemSnapShot(object content, Rect location, int zIndex, WindowState state)\n        {\n            if (content == null) throw new ArgumentNullException(\"content\");\n\n            _content = content;\n            _location = location;\n            _zIndex = zIndex;\n            _state = state;\n        }\n\n        public static FloatingItemSnapShot Take(DragablzItem dragablzItem)\n        {\n            if (dragablzItem == null) throw new ArgumentNullException(\"dragablzItem\");\n\n            return new FloatingItemSnapShot(\n                dragablzItem.Content, \n                new Rect(dragablzItem.X, dragablzItem.Y, dragablzItem.ActualWidth, dragablzItem.ActualHeight), \n                Panel.GetZIndex(dragablzItem),\n                Layout.GetFloatingItemState(dragablzItem));\n        }\n\n        public void Apply(DragablzItem dragablzItem)\n        {\n            if (dragablzItem == null) throw new ArgumentNullException(\"dragablzItem\");\n\n            dragablzItem.SetCurrentValue(DragablzItem.XProperty, Location.Left);\n            dragablzItem.SetCurrentValue(DragablzItem.YProperty, Location.Top);\n            dragablzItem.SetCurrentValue(FrameworkElement.WidthProperty, Location.Width);\n            dragablzItem.SetCurrentValue(FrameworkElement.HeightProperty, Location.Height);\n            Layout.SetFloatingItemState(dragablzItem, State);\n            Panel.SetZIndex(dragablzItem, ZIndex);\n        }\n\n        public object Content\n        {\n            get { return _content; }\n        }\n\n        public Rect Location\n        {\n            get { return _location; }\n        }\n\n        public int ZIndex\n        {\n            get { return _zIndex; }\n        }\n\n        public WindowState State\n        {\n            get { return _state; }\n        }\n    }\n}\n"
  },
  {
    "path": "third_party/Dragablz/Dragablz/Dockablz/Layout.cs",
    "content": "﻿using System;\nusing System.CodeDom;\nusing System.Collections;\nusing System.Collections.Generic;\nusing System.Linq;\nusing System.Windows;\nusing System.Windows.Controls;\nusing System.Windows.Controls.Primitives;\nusing System.Windows.Data;\nusing System.Windows.Input;\nusing System.Windows.Media;\nusing System.Windows.Threading;\nusing Dragablz.Core;\n\nnamespace Dragablz.Dockablz\n{\n    public delegate void ClosingFloatingItemCallback(ItemActionCallbackArgs<Layout> args);\n\n    [TemplatePart(Name = TopDropZonePartName, Type = typeof(DropZone))]\n    [TemplatePart(Name = RightDropZonePartName, Type = typeof(DropZone))]\n    [TemplatePart(Name = BottomDropZonePartName, Type = typeof(DropZone))]\n    [TemplatePart(Name = LeftDropZonePartName, Type = typeof(DropZone))]\n    [TemplatePart(Name = FloatingDropZonePartName, Type = typeof(DropZone))]\n    [TemplatePart(Name = FloatingContentPresenterPartName, Type = typeof(ContentPresenter))]\n    public class Layout : ContentControl\n    {\n        private static readonly HashSet<Layout> LoadedLayouts = new HashSet<Layout>();\n        private const string TopDropZonePartName = \"PART_TopDropZone\";\n        private const string RightDropZonePartName = \"PART_RightDropZone\";\n        private const string BottomDropZonePartName = \"PART_BottomDropZone\";\n        private const string LeftDropZonePartName = \"PART_LeftDropZone\";\n        private const string FloatingDropZonePartName = \"PART_FloatDropZone\";\n        private const string FloatingContentPresenterPartName = \"PART_FloatContentPresenter\";\n    \n        private readonly IDictionary<DropZoneLocation, DropZone> _dropZones = new Dictionary<DropZoneLocation, DropZone>();\n        private static Tuple<Layout, DropZone> _currentlyOfferedDropZone;\n\n        public static RoutedCommand UnfloatItemCommand = new RoutedCommand();\n        public static RoutedCommand MaximiseFloatingItem = new RoutedCommand();\n        public static RoutedCommand RestoreFloatingItem = new RoutedCommand();\n        public static RoutedCommand CloseFloatingItem = new RoutedCommand();\n        public static RoutedCommand TileFloatingItemsCommand = new RoutedCommand();\n        public static RoutedCommand TileFloatingItemsVerticallyCommand = new RoutedCommand();\n        public static RoutedCommand TileFloatingItemsHorizontallyCommand = new RoutedCommand();\n        \n        private readonly DragablzItemsControl _floatingItems;\n        private static bool _isDragOpWireUpPending;\n        private FloatTransfer _floatTransfer;\n\n        static Layout()\n        {\n            DefaultStyleKeyProperty.OverrideMetadata(typeof(Layout), new FrameworkPropertyMetadata(typeof(Layout)));\n            \n            EventManager.RegisterClassHandler(typeof(DragablzItem), DragablzItem.DragStarted, new DragablzDragStartedEventHandler(ItemDragStarted));\n            EventManager.RegisterClassHandler(typeof(DragablzItem), DragablzItem.PreviewDragDelta, new DragablzDragDeltaEventHandler(PreviewItemDragDelta), true);            \n            EventManager.RegisterClassHandler(typeof(DragablzItem), DragablzItem.DragCompleted, new DragablzDragCompletedEventHandler(ItemDragCompleted));            \n        }        \n\n        public Layout()\n        {\n            Loaded += (sender, args) =>\n            {\n                LoadedLayouts.Add(this);\n                MarkTopLeftItem(this);\n            };\n            Unloaded += (sender, args) => LoadedLayouts.Remove(this);            \n\n            CommandBindings.Add(new CommandBinding(UnfloatItemCommand, UnfloatExecuted, CanExecuteUnfloat));\n            CommandBindings.Add(new CommandBinding(MaximiseFloatingItem, MaximiseFloatingItemExecuted, CanExecuteMaximiseFloatingItem));\n            CommandBindings.Add(new CommandBinding(CloseFloatingItem, CloseFloatingItemExecuted, CanExecuteCloseFloatingItem));\n            CommandBindings.Add(new CommandBinding(RestoreFloatingItem, RestoreFloatingItemExecuted, CanExecuteRestoreFloatingItem));\n            CommandBindings.Add(new CommandBinding(TileFloatingItemsCommand, TileFloatingItemsExecuted));\n            CommandBindings.Add(new CommandBinding(TileFloatingItemsCommand, TileFloatingItemsExecuted));\n            CommandBindings.Add(new CommandBinding(TileFloatingItemsVerticallyCommand, TileFloatingItemsVerticallyExecuted));\n            CommandBindings.Add(new CommandBinding(TileFloatingItemsHorizontallyCommand, TileFloatingItemsHorizontallyExecuted));                        \n\n            //TODO bad bad behaviour.  Pick up this from the template.\n            _floatingItems = new DragablzItemsControl\n            {\n                ContainerCustomisations = new ContainerCustomisations(\n                    GetFloatingContainerForItemOverride,\n                    PrepareFloatingContainerForItemOverride,\n                    ClearingFloatingContainerForItemOverride)\n            };\n\n            var floatingItemsSourceBinding = new Binding(\"FloatingItemsSource\") { Source = this };\n            _floatingItems.SetBinding(ItemsControl.ItemsSourceProperty, floatingItemsSourceBinding);\n            var floatingItemsControlStyleBinding = new Binding(\"FloatingItemsControlStyle\") { Source = this };\n            _floatingItems.SetBinding(StyleProperty, floatingItemsControlStyleBinding);\n            var floatingItemTemplateBinding = new Binding(\"FloatingItemTemplate\") { Source = this };\n            _floatingItems.SetBinding(ItemsControl.ItemTemplateProperty, floatingItemTemplateBinding);\n            var floatingItemTemplateSelectorBinding = new Binding(\"FloatingItemTemplateSelector\") { Source = this };\n            _floatingItems.SetBinding(ItemsControl.ItemTemplateSelectorProperty, floatingItemTemplateSelectorBinding);            \n            var floatingItemContainerStyeBinding = new Binding(\"FloatingItemContainerStyle\") { Source = this };\n            _floatingItems.SetBinding(ItemsControl.ItemContainerStyleProperty, floatingItemContainerStyeBinding);\n            var floatingItemContainerStyleSelectorBinding = new Binding(\"FloatingItemContainerStyleSelector\") { Source = this };\n            _floatingItems.SetBinding(ItemsControl.ItemContainerStyleSelectorProperty, floatingItemContainerStyleSelectorBinding);\n        }\n\n        /// <summary>\n        /// Helper method to get all the currently loaded layouts.\n        /// </summary>\n        /// <returns></returns>\n        public static IEnumerable<Layout> GetLoadedInstances()\n        {\n            return LoadedLayouts.ToList();\n        }        \n\n        /// <summary>\n        /// Finds the location of a tab control withing a layout.\n        /// </summary>\n        /// <param name=\"tabablzControl\"></param>\n        /// <returns></returns>\n        public static LocationReport Find(TabablzControl tabablzControl)\n        {\n            if (tabablzControl == null) throw new ArgumentNullException(\"tabablzControl\");\n\n            return Finder.Find(tabablzControl);            \n        }\n\n        /// <summary>\n        /// Creates a split in a layout, at the location of a specified <see cref=\"TabablzControl\"/>.\n        /// </summary>\n        /// <para></para>\n        /// <param name=\"tabablzControl\">Tab control to be split.</param>\n        /// <param name=\"orientation\">Direction of split.</param>\n        /// <param name=\"makeSecond\">Set to <c>true</c> to make the current tab control push into the right hand or bottom of the split.</param>\n        /// <remarks>The tab control to be split must be hosted in a layout control.</remarks>\n        public static BranchResult Branch(TabablzControl tabablzControl, Orientation orientation, bool makeSecond)\n        {\n            return Branch(tabablzControl, orientation, makeSecond, .5);\n        }\n\n        /// <summary>\n        /// Creates a split in a layout, at the location of a specified <see cref=\"TabablzControl\"/>.\n        /// </summary>\n        /// <para></para>\n        /// <param name=\"tabablzControl\">Tab control to be split.</param>\n        /// <param name=\"orientation\">Direction of split.</param>\n        /// <param name=\"makeSecond\">Set to <c>true</c> to make the current tab control push into the right hand or bottom of the split.</param>\n        /// <param name=\"firstItemProportion\">Sets the proportion of the first tab control, with 0.5 being 50% of available space.</param>\n        /// <remarks>The tab control to be split must be hosted in a layout control.  <see cref=\"Layout.BranchTemplate\" /> should be set (typically via XAML).</remarks>\n        public static BranchResult Branch(TabablzControl tabablzControl, Orientation orientation, bool makeSecond, double firstItemProportion)\n        {\n            return Branch(tabablzControl, null, orientation, makeSecond, firstItemProportion);\n        }\n\n        /// <summary>\n        /// Creates a split in a layout, at the location of a specified <see cref=\"TabablzControl\"/>.\n        /// </summary>\n        /// <para></para>\n        /// <param name=\"tabablzControl\">Tab control to be split.</param>\n        /// <param name=\"newSiblingTabablzControl\">New sibling tab control (otherwise <see cref=\"Layout.BranchTemplate\"/> will be used).</param>\n        /// <param name=\"orientation\">Direction of split.</param>\n        /// <param name=\"makeCurrentSecond\">Set to <c>true</c> to make the current tab control push into the right hand or bottom of the split.</param>\n        /// <param name=\"firstItemProportion\">Sets the proportion of the first tab control, with 0.5 being 50% of available space.</param>\n        /// <remarks>The tab control to be split must be hosted in a layout control. </remarks>\n        public static BranchResult Branch(TabablzControl tabablzControl, TabablzControl newSiblingTabablzControl, Orientation orientation, bool makeCurrentSecond,\n            double firstItemProportion)\n        {\n            if (firstItemProportion < 0.0 || firstItemProportion > 1.0) throw new ArgumentOutOfRangeException(\"firstItemProportion\", \"Must be >= 0.0 and <= 1.0\");\n\n            var locationReport = Find(tabablzControl);\n\n            Action<Branch> applier;\n            object existingContent;\n            if (!locationReport.IsLeaf)\n            {\n                existingContent = locationReport.RootLayout.Content;\n                applier = branch => locationReport.RootLayout.Content = branch;\n            }\n            else if (!locationReport.IsSecondLeaf)\n            {\n                existingContent = locationReport.ParentBranch.FirstItem;\n                applier = branch => locationReport.ParentBranch.FirstItem = branch;\n            }\n            else\n            {\n                existingContent = locationReport.ParentBranch.SecondItem;\n                applier = branch => locationReport.ParentBranch.SecondItem = branch;\n            }\n\n            var selectedItem = tabablzControl.SelectedItem;\n            var branchResult = Branch(orientation, firstItemProportion, makeCurrentSecond, locationReport.RootLayout.BranchTemplate, newSiblingTabablzControl, existingContent, applier);\n            tabablzControl.SelectedItem = selectedItem;\n            tabablzControl.Dispatcher.BeginInvoke(new Action(() =>\n            {\n                tabablzControl.SetCurrentValue(Selector.SelectedItemProperty, selectedItem);\n                MarkTopLeftItem(locationReport.RootLayout);\n            }),\n                DispatcherPriority.Loaded);\n\n            return branchResult;\n        }        \n\n        /// <summary>\n        /// Use in conjuction with the <see cref=\"InterTabController.Partition\"/> on a <see cref=\"TabablzControl\"/>\n        /// to isolate drag and drop spaces/control instances.\n        /// </summary>\n        public string Partition { get; set; }\n\n        public static readonly DependencyProperty InterLayoutClientProperty = DependencyProperty.Register(\n            \"InterLayoutClient\", typeof (IInterLayoutClient), typeof (Layout), new PropertyMetadata(new DefaultInterLayoutClient()));\n\n        public IInterLayoutClient InterLayoutClient\n        {\n            get { return (IInterLayoutClient) GetValue(InterLayoutClientProperty); }\n            set { SetValue(InterLayoutClientProperty, value); }\n        }\n\n        internal static bool IsContainedWithinBranch(DependencyObject dependencyObject)\n        {\n            do \n            {                \n                dependencyObject = VisualTreeHelper.GetParent(dependencyObject);\n                if (dependencyObject is Branch)\n                    return true;\n            } while (dependencyObject != null);\n            return false;\n        }\n\n        private static readonly DependencyPropertyKey IsParticipatingInDragPropertyKey =\n            DependencyProperty.RegisterReadOnly(\n                \"IsParticipatingInDrag\", typeof (bool), typeof (Layout),\n                new PropertyMetadata(default(bool)));\n\n        public static readonly DependencyProperty IsParticipatingInDragProperty =\n            IsParticipatingInDragPropertyKey.DependencyProperty;\n\n        public bool IsParticipatingInDrag\n        {\n            get { return (bool) GetValue(IsParticipatingInDragProperty); }\n            private set { SetValue(IsParticipatingInDragPropertyKey, value); }\n        }\n\n        public static readonly DependencyProperty BranchTemplateProperty = DependencyProperty.Register(\n            \"BranchTemplate\", typeof (DataTemplate), typeof (Layout), new PropertyMetadata(default(DataTemplate)));\n\n        public DataTemplate BranchTemplate\n        {\n            get { return (DataTemplate) GetValue(BranchTemplateProperty); }\n            set { SetValue(BranchTemplateProperty, value); }\n        }\n\n        public static readonly DependencyProperty IsFloatDropZoneEnabledProperty = DependencyProperty.Register(\n            \"IsFloatDropZoneEnabled\", typeof (bool), typeof (Layout), new PropertyMetadata(default(bool)));\n\n        public bool IsFloatDropZoneEnabled\n        {\n            get { return (bool) GetValue(IsFloatDropZoneEnabledProperty); }\n            set { SetValue(IsFloatDropZoneEnabledProperty, value); }\n        }\n\n        /// <summary>\n        /// Defines a margin for the container which hosts all floating items.\n        /// </summary>\n        public static readonly DependencyProperty FloatingItemsContainerMarginProperty = DependencyProperty.Register(\n            \"FloatingItemsContainerMargin\", typeof (Thickness), typeof (Layout), new PropertyMetadata(default(Thickness)));\n\n        /// <summary>\n        /// Defines a margin for the container which hosts all floating items.\n        /// </summary>\n        public Thickness FloatingItemsContainerMargin\n        {\n            get { return (Thickness) GetValue(FloatingItemsContainerMarginProperty); }\n            set { SetValue(FloatingItemsContainerMarginProperty, value); }\n        }\n\n        /// <summary>\n        /// Floating items, such as tool/MDI windows, which will sit above the <see cref=\"Content\"/>.\n        /// </summary>\n        public ItemCollection FloatingItems\n        {\n            get { return _floatingItems.Items; }\n        }\n\n        public static readonly DependencyProperty FloatingItemsSourceProperty = DependencyProperty.Register(\n            \"FloatingItemsSource\", typeof (IEnumerable), typeof (Layout), new PropertyMetadata(default(IEnumerable)));\n\n        /// <summary>\n        /// Floating items, such as tool/MDI windows, which will sit above the <see cref=\"Content\"/>.\n        /// </summary>\n        public IEnumerable FloatingItemsSource\n        {\n            get { return (IEnumerable) GetValue(FloatingItemsSourceProperty); }\n            set { SetValue(FloatingItemsSourceProperty, value); }\n        }\n\n        public static readonly DependencyProperty FloatingItemsControlStyleProperty = DependencyProperty.Register(\n            \"FloatingItemsControlStyle\", typeof (Style), typeof (Layout), new PropertyMetadata((Style)null));\n\n        /// <summary>\n        /// The style to be applied to the <see cref=\"DragablzItemsControl\"/> which is used to display floating items.\n        /// In most scenarios it should be OK to leave this to that applied by the default style.\n        /// </summary>\n        public Style FloatingItemsControlStyle\n        {\n            get { return (Style) GetValue(FloatingItemsControlStyleProperty); }\n            set { SetValue(FloatingItemsControlStyleProperty, value); }\n        }\n\n        public static readonly DependencyProperty FloatingItemContainerStyleProperty = DependencyProperty.Register(\n            \"FloatingItemContainerStyle\", typeof (Style), typeof (Layout), new PropertyMetadata(default(Style)));\n\n        public Style FloatingItemContainerStyle\n        {\n            get { return (Style) GetValue(FloatingItemContainerStyleProperty); }\n            set { SetValue(FloatingItemContainerStyleProperty, value); }\n        }\n\n        public static readonly DependencyProperty FloatingItemContainerStyleSelectorProperty = DependencyProperty.Register(\n            \"FloatingItemContainerStyleSelector\", typeof (StyleSelector), typeof (Layout), new PropertyMetadata(new CouldBeHeaderedStyleSelector()));\n\n        public StyleSelector FloatingItemContainerStyleSelector\n        {\n            get { return (StyleSelector) GetValue(FloatingItemContainerStyleSelectorProperty); }\n            set { SetValue(FloatingItemContainerStyleSelectorProperty, value); }\n        }\n\n        public static readonly DependencyProperty FloatingItemTemplateProperty = DependencyProperty.Register(\n            \"FloatingItemTemplate\", typeof (DataTemplate), typeof (Layout), new PropertyMetadata(default(DataTemplate)));\n\n        public DataTemplate FloatingItemTemplate\n        {\n            get { return (DataTemplate) GetValue(FloatingItemTemplateProperty); }\n            set { SetValue(FloatingItemTemplateProperty, value); }\n        }\n\n        public static readonly DependencyProperty FloatingItemTemplateSelectorProperty = DependencyProperty.Register(\n            \"FloatingItemTemplateSelector\", typeof (DataTemplateSelector), typeof (Layout), new PropertyMetadata(default(DataTemplateSelector)));\n\n        public DataTemplateSelector FloatingItemTemplateSelector\n        {\n            get { return (DataTemplateSelector) GetValue(FloatingItemTemplateSelectorProperty); }\n            set { SetValue(FloatingItemTemplateSelectorProperty, value); }\n        }\n\n        public static readonly DependencyProperty FloatingItemHeaderMemberPathProperty = DependencyProperty.Register(\n            \"FloatingItemHeaderMemberPath\", typeof (string), typeof (Layout), new PropertyMetadata(default(string)));\n\n        public string FloatingItemHeaderMemberPath\n        {\n            get { return (string) GetValue(FloatingItemHeaderMemberPathProperty); }\n            set { SetValue(FloatingItemHeaderMemberPathProperty, value); }\n        }\n\n        public static readonly DependencyProperty FloatingItemDisplayMemberPathProperty = DependencyProperty.Register(\n            \"FloatingItemDisplayMemberPath\", typeof (string), typeof (Layout), new PropertyMetadata(default(string)));\n\n        public string FloatingItemDisplayMemberPath\n        {\n            get { return (string) GetValue(FloatingItemDisplayMemberPathProperty); }\n            set { SetValue(FloatingItemDisplayMemberPathProperty, value); }\n        }\n\n        public static readonly DependencyProperty ClosingFloatingItemCallbackProperty = DependencyProperty.Register(\n            \"ClosingFloatingItemCallback\", typeof (ClosingFloatingItemCallback), typeof (Layout), new PropertyMetadata(default(ClosingFloatingItemCallback)));\n\n        public ClosingFloatingItemCallback ClosingFloatingItemCallback\n        {\n            get { return (ClosingFloatingItemCallback) GetValue(ClosingFloatingItemCallbackProperty); }\n            set { SetValue(ClosingFloatingItemCallbackProperty, value); }\n        }\n\n        public static readonly DependencyPropertyKey KeyIsFloatingInLayoutPropertyKey = DependencyProperty.RegisterAttachedReadOnly(\n            \"IsFloatingInLayout\", typeof (bool), typeof (Layout), new PropertyMetadata(default(bool)));\n\n        private static void SetIsFloatingInLayout(DependencyObject element, bool value)\n        {\n            element.SetValue(KeyIsFloatingInLayoutPropertyKey, value);\n        }\n\n        public static bool GetIsFloatingInLayout(DependencyObject element)\n        {\n            return (bool)element.GetValue(KeyIsFloatingInLayoutPropertyKey.DependencyProperty);\n        }\n\n        private static readonly DependencyPropertyKey IsTopLeftItemPropertyKey =\n            DependencyProperty.RegisterReadOnly(\n                \"IsTopLeftItem\", typeof(bool), typeof(Layout),\n                new PropertyMetadata(default(bool)));\n\n        /// <summary>\n        /// Indicates if an item/tab control within a layout is contained at the top most and left most branch item.\n        /// </summary>\n        public static readonly DependencyProperty IsTopLeftItemProperty = IsTopLeftItemPropertyKey.DependencyProperty;\n\n        /// <summary>\n        /// Indicates if an item/tab control within a layout is contained at the top most and left most branch item.\n        /// </summary>\n        private static void SetIsTopLeftItem(DependencyObject element, bool value)\n        {\n            element.SetValue(IsTopLeftItemPropertyKey, value);\n        }\n\n        /// <summary>\n        /// Indicates if an item/tab control within a layout is contained at the top most and left most branch item.\n        /// </summary>\n        public static bool GetIsTopLeftItem(DependencyObject element)\n        {\n            return (bool)element.GetValue(IsTopLeftItemProperty);\n        }\n\n        /// <summary>When overridden in a derived class, is invoked whenever application code or internal processes call <see cref=\"M:System.Windows.FrameworkElement.ApplyTemplate\" />.</summary>\n        public override void OnApplyTemplate()\n        {            \n            base.OnApplyTemplate();\n\n            var floatingItemsContentPresenter = GetTemplateChild(FloatingContentPresenterPartName) as ContentPresenter;\n            if (floatingItemsContentPresenter != null)\n                floatingItemsContentPresenter.Content = _floatingItems;\n\n            _dropZones[DropZoneLocation.Top] = GetTemplateChild(TopDropZonePartName) as DropZone;\n            _dropZones[DropZoneLocation.Right] = GetTemplateChild(RightDropZonePartName) as DropZone;\n            _dropZones[DropZoneLocation.Bottom] = GetTemplateChild(BottomDropZonePartName) as DropZone;\n            _dropZones[DropZoneLocation.Left] = GetTemplateChild(LeftDropZonePartName) as DropZone;\n            _dropZones[DropZoneLocation.Floating] = GetTemplateChild(FloatingDropZonePartName) as DropZone;\n        }\n\n        internal IEnumerable<DragablzItem> FloatingDragablzItems()\n        {\n            return _floatingItems.DragablzItems();\n        }\n\n        internal static void RestoreFloatingItemSnapShots(DependencyObject ancestor, IEnumerable<FloatingItemSnapShot> floatingItemSnapShots)\n        {\n            var layouts = ancestor.VisualTreeDepthFirstTraversal().OfType<Layout>().ToList();\n            foreach (var floatingDragablzItem in layouts.SelectMany(l => l.FloatingDragablzItems()))\n            {\n                var itemSnapShots = floatingItemSnapShots as FloatingItemSnapShot[] ?? floatingItemSnapShots.ToArray();\n                var floatingItemSnapShot = itemSnapShots.FirstOrDefault(\n                    ss => ss.Content == floatingDragablzItem.Content);\n                if (floatingItemSnapShot != null)\n                    floatingItemSnapShot.Apply(floatingDragablzItem);\n            }\n        }\n\n        private static void ItemDragStarted(object sender, DragablzDragStartedEventArgs e)\n        {\n            //we wait until drag is in full flow so we know the partition has been setup by the owning tab control\n            _isDragOpWireUpPending = true;            \n        }\n\n        private static void SetupParticipatingLayouts(DragablzItem dragablzItem)\n        {\n            var sourceOfDragItemsControl = ItemsControl.ItemsControlFromItemContainer(dragablzItem) as DragablzItemsControl;\n            if (sourceOfDragItemsControl == null || sourceOfDragItemsControl.Items.Count != 1) return;\n\n            var draggingWindow = Window.GetWindow(dragablzItem);\n            if (draggingWindow == null) return;\n\n            foreach (var loadedLayout in LoadedLayouts.Where(l =>\n                l.Partition == dragablzItem.PartitionAtDragStart &&\n                !Equals(Window.GetWindow(l), draggingWindow)))\n\n            {\n                loadedLayout.IsParticipatingInDrag = true;\n            }\n        }\n\n        private void MonitorDropZones(Point cursorPos)\n        {\n            var myWindow = Window.GetWindow(this);\n            if (myWindow == null) return;\n\n            foreach (var dropZone in _dropZones.Values.Where(dz => dz != null))\n            {                \n                var pointFromScreen = myWindow.PointFromScreen(cursorPos);\n                var pointRelativeToDropZone = myWindow.TranslatePoint(pointFromScreen, dropZone);\n                var inputHitTest = dropZone.InputHitTest(pointRelativeToDropZone);\n                //TODO better halding when windows are layered over each other\n                if (inputHitTest != null)\n                {\n                    if (_currentlyOfferedDropZone != null)\n                        _currentlyOfferedDropZone.Item2.IsOffered = false;\n                    dropZone.IsOffered = true;\n                    _currentlyOfferedDropZone = new Tuple<Layout, DropZone>(this, dropZone);\n                }\n                else\n                {\n                    dropZone.IsOffered = false;\n                    if (_currentlyOfferedDropZone != null && _currentlyOfferedDropZone.Item2 == dropZone)\n                        _currentlyOfferedDropZone = null;\n                }\n            }\n        }\n\n        private static bool TryGetSourceTabControl(DragablzItem dragablzItem, out TabablzControl tabablzControl)\n        {\n            var sourceOfDragItemsControl = ItemsControl.ItemsControlFromItemContainer(dragablzItem) as DragablzItemsControl;\n            if (sourceOfDragItemsControl == null) throw new ApplicationException(\"Unable to determine source items control.\");\n\n            tabablzControl = TabablzControl.GetOwnerOfHeaderItems(sourceOfDragItemsControl);\n            \n            return tabablzControl != null;\n        }\n\n        private void Branch(DropZoneLocation location, DragablzItem sourceDragablzItem)\n        {\n            if (InterLayoutClient == null)\n                throw new InvalidOperationException(\"InterLayoutClient is not set.\");            \n\n            var sourceOfDragItemsControl = ItemsControl.ItemsControlFromItemContainer(sourceDragablzItem) as DragablzItemsControl;\n            if (sourceOfDragItemsControl == null) throw new ApplicationException(\"Unable to determin source items control.\");\n            \n            var sourceTabControl = TabablzControl.GetOwnerOfHeaderItems(sourceOfDragItemsControl);\n            if (sourceTabControl == null) throw new ApplicationException(\"Unable to determin source tab control.\");\n\n            var floatingItemSnapShots = sourceTabControl.VisualTreeDepthFirstTraversal()\n                    .OfType<Layout>()\n                    .SelectMany(l => l.FloatingDragablzItems().Select(FloatingItemSnapShot.Take))\n                    .ToList();\n\n            var sourceItem = sourceOfDragItemsControl.ItemContainerGenerator.ItemFromContainer(sourceDragablzItem);\n            sourceTabControl.RemoveItem(sourceDragablzItem);\n\n            var branchItem = new Branch\n            {\n                Orientation = (location == DropZoneLocation.Right || location == DropZoneLocation.Left) ? Orientation.Horizontal : Orientation.Vertical\n            };\n\n            object newContent;\n            if (BranchTemplate == null)\n            {\n                var newTabHost = InterLayoutClient.GetNewHost(Partition, sourceTabControl);\n                if (newTabHost == null)\n                    throw new ApplicationException(\"InterLayoutClient did not provide a new tab host.\");\n                newTabHost.TabablzControl.AddToSource(sourceItem);\n                newTabHost.TabablzControl.SelectedItem = sourceItem;\n                newContent = newTabHost.Container;\n\n                Dispatcher.BeginInvoke(new Action(() => RestoreFloatingItemSnapShots(newTabHost.TabablzControl, floatingItemSnapShots)), DispatcherPriority.Loaded);\n            }\n            else\n            {\n                newContent = new ContentControl\n                {\n                    Content = new object(),\n                    ContentTemplate = BranchTemplate,                  \n                };\n                ((ContentControl) newContent).Dispatcher.BeginInvoke(new Action(() =>\n                {\n                    //TODO might need to improve this a bit, make it a bit more declarative for complex trees\n                    var newTabControl = ((ContentControl)newContent).VisualTreeDepthFirstTraversal().OfType<TabablzControl>().FirstOrDefault();\n                    if (newTabControl == null) return;\n\n                    newTabControl.DataContext = sourceTabControl.DataContext;\n                    newTabControl.AddToSource(sourceItem);\n                    newTabControl.SelectedItem = sourceItem;\n                    Dispatcher.BeginInvoke(new Action(() => RestoreFloatingItemSnapShots(newTabControl, floatingItemSnapShots)), DispatcherPriority.Loaded);\n                }), DispatcherPriority.Loaded);                \n            }\n            \n            if (location == DropZoneLocation.Right || location == DropZoneLocation.Bottom)\n            {\n                branchItem.FirstItem = Content;\n                branchItem.SecondItem = newContent;\n            }\n            else\n            {\n                branchItem.FirstItem = newContent;\n                branchItem.SecondItem = Content;\n            }\n\n            SetCurrentValue(ContentProperty, branchItem);\n\n            Dispatcher.BeginInvoke(new Action(() => MarkTopLeftItem(this)), DispatcherPriority.Loaded);            \n        }\n\n        internal static bool ConsolidateBranch(DependencyObject redundantNode)\n        {\n            bool isSecondLineageWhenOwnerIsBranch;\n            var ownerBranch = FindLayoutOrBranchOwner(redundantNode, out isSecondLineageWhenOwnerIsBranch) as Branch;\n            if (ownerBranch == null) return false;\n\n            var survivingItem = isSecondLineageWhenOwnerIsBranch ? ownerBranch.FirstItem : ownerBranch.SecondItem;\n\n            var grandParent = FindLayoutOrBranchOwner(ownerBranch, out isSecondLineageWhenOwnerIsBranch);\n            if (grandParent == null) throw new ApplicationException(\"Unexpected structure, grandparent Layout or Branch not found\");\n\n            var layout = grandParent as Layout;\n            if (layout != null)\n            {\n                layout.Content = survivingItem;\n                MarkTopLeftItem(layout);\n                return true;\n            }\n\n            var branch = (Branch) grandParent;            \n            if (isSecondLineageWhenOwnerIsBranch)\n                branch.SecondItem = survivingItem;\n            else\n                branch.FirstItem = survivingItem;\n            var rootLayout = branch.VisualTreeAncestory().OfType<Layout>().FirstOrDefault();\n            if (rootLayout != null)\n                MarkTopLeftItem(rootLayout);\n\n            return true;\n        }\n\n        private static object FindLayoutOrBranchOwner(DependencyObject node, out bool isSecondLineageWhenOwnerIsBranch)\n        {\n            isSecondLineageWhenOwnerIsBranch = false;\n            \n            var ancestoryStack = new Stack<DependencyObject>();\n            do\n            {\n                ancestoryStack.Push(node);\n                node = VisualTreeHelper.GetParent(node);\n                if (node is Layout) \n                    return node;\n                \n                var branch = node as Branch;\n                if (branch == null) continue;\n\n                isSecondLineageWhenOwnerIsBranch = ancestoryStack.Contains(branch.SecondContentPresenter);\n                return branch;\n\n            } while (node != null);            \n\n            return null;\n        }\n\n        private static BranchResult Branch(Orientation orientation, double proportion, bool makeSecond, DataTemplate branchTemplate, TabablzControl newSibling, object existingContent, Action<Branch> applier)\n        {\n            var branchItem = new Branch\n            {\n                Orientation = orientation\n            };         \n            \n            var newContent = new ContentControl\n            {\n                Content = newSibling ?? new object(),\n                ContentTemplate = branchTemplate,\n            };            \n\n            if (!makeSecond)\n            {\n                branchItem.FirstItem = existingContent;\n                branchItem.SecondItem = newContent;\n            }\n            else\n            {\n                branchItem.FirstItem = newContent;\n                branchItem.SecondItem = existingContent;\n            }\n\n            branchItem.SetCurrentValue(Dockablz.Branch.FirstItemLengthProperty, new GridLength(proportion, GridUnitType.Star));\n            branchItem.SetCurrentValue(Dockablz.Branch.SecondItemLengthProperty, new GridLength(1-proportion, GridUnitType.Star));\n\n            applier(branchItem);\n\n            newContent.Dispatcher.Invoke(new Action(() => { }), DispatcherPriority.Loaded);\n            var newTabablzControl = newContent.VisualTreeDepthFirstTraversal().OfType<TabablzControl>().FirstOrDefault();\n            if (newTabablzControl != null) return new BranchResult(branchItem, newTabablzControl);\n\n            //let#s be kinf and give WPF an extra change to gen the controls\n            newContent.Dispatcher.Invoke(new Action(() => { }), DispatcherPriority.Background);\n            newTabablzControl = newContent.VisualTreeDepthFirstTraversal().OfType<TabablzControl>().FirstOrDefault();\n\n            if (newTabablzControl == null)\n                throw new ApplicationException(\"New TabablzControl was not generated inside branch.\");\n\n            return new BranchResult(branchItem, newTabablzControl);\n        }\n\n        private static void ItemDragCompleted(object sender, DragablzDragCompletedEventArgs e)\n        {\n            _isDragOpWireUpPending = false;\n\n            foreach (var loadedLayout in LoadedLayouts)\n                loadedLayout.IsParticipatingInDrag = false;\n\n            if (_currentlyOfferedDropZone == null || e.DragablzItem.IsDropTargetFound) return;\n\n            TabablzControl tabablzControl;\n            if (TryGetSourceTabControl(e.DragablzItem, out tabablzControl))\n            {\n                if (tabablzControl.Items.Count > 1) return;\n\n                if (_currentlyOfferedDropZone.Item2.Location == DropZoneLocation.Floating)\n                    Float(_currentlyOfferedDropZone.Item1, e.DragablzItem);\n                else\n                    _currentlyOfferedDropZone.Item1.Branch(_currentlyOfferedDropZone.Item2.Location, e.DragablzItem);\n            }\n\n            _currentlyOfferedDropZone = null;\n        }\n\n        private static void Float(Layout layout, DragablzItem dragablzItem)\n        {\n            //TODO we need eq of IManualInterTabClient here, so consumer can control this op'.            \n\n            //remove from source\n            var sourceOfDragItemsControl = ItemsControl.ItemsControlFromItemContainer(dragablzItem) as DragablzItemsControl;\n            if (sourceOfDragItemsControl == null) throw new ApplicationException(\"Unable to determin source items control.\");            \n            var sourceTabControl = TabablzControl.GetOwnerOfHeaderItems(sourceOfDragItemsControl);\n            layout._floatTransfer = FloatTransfer.TakeSnapshot(dragablzItem, sourceTabControl);\n            var floatingItemSnapShots = sourceTabControl.VisualTreeDepthFirstTraversal()\n                    .OfType<Layout>()\n                    .SelectMany(l => l.FloatingDragablzItems().Select(FloatingItemSnapShot.Take))\n                    .ToList();\n            if (sourceTabControl == null) throw new ApplicationException(\"Unable to determin source tab control.\");            \n            sourceTabControl.RemoveItem(dragablzItem);\n            \n            //add to float layer            \n            CollectionTeaser collectionTeaser;\n            if (CollectionTeaser.TryCreate(layout.FloatingItemsSource, out collectionTeaser))\n                collectionTeaser.Add(layout._floatTransfer.Content);\n            else\n                layout.FloatingItems.Add(layout._floatTransfer.Content);\n\n            layout.Dispatcher.BeginInvoke(new Action(() => RestoreFloatingItemSnapShots(layout, floatingItemSnapShots)), DispatcherPriority.Loaded);\n        }\n\n        private static void PreviewItemDragDelta(object sender, DragablzDragDeltaEventArgs e)\n        {\n            if (e.Cancel) return;\n\n            if (_isDragOpWireUpPending)\n            {\n                SetupParticipatingLayouts(e.DragablzItem);\n                _isDragOpWireUpPending = false;\n            }\n\n            foreach (var layout in LoadedLayouts.Where(l => l.IsParticipatingInDrag))\n            {                \n                var cursorPos = Native.GetCursorPos();\n                layout.MonitorDropZones(cursorPos);\n            }         \n        }\n\n        private void PrepareFloatingContainerForItemOverride(DependencyObject dependencyObject, object o)\n        {\n            var headeredDragablzItem = dependencyObject as HeaderedDragablzItem;\n            if (headeredDragablzItem == null) return;\n\n            SetIsFloatingInLayout(dependencyObject, true);\n\n            var headerBinding = new Binding(FloatingItemHeaderMemberPath) {Source = o};\n            headeredDragablzItem.SetBinding(HeaderedDragablzItem.HeaderContentProperty, headerBinding);\n\n            if (!string.IsNullOrWhiteSpace(FloatingItemDisplayMemberPath))\n            {\n                var contentBinding = new Binding(FloatingItemDisplayMemberPath) {Source = o};\n                headeredDragablzItem.SetBinding(ContentProperty, contentBinding);\n            }\n\n            if (_floatTransfer == null || (o != _floatTransfer.Content && dependencyObject != _floatTransfer.Content))\n                return;\n\n            var dragablzItem = (DragablzItem) dependencyObject;\n\n            Dispatcher.BeginInvoke(new Action(() =>\n            {\n                //TODO might be nice to allow user a bit of control over sizing...especially the .75 thing i have handily hard coded.  shoot me.\n                dragablzItem.Measure(new Size(_floatingItems.ActualWidth, _floatingItems.ActualHeight));\n                var newWidth = Math.Min(_floatingItems.ActualWidth*.75, dragablzItem.DesiredSize.Width);\n                var newHeight = Math.Min(_floatingItems.ActualHeight * .75, dragablzItem.DesiredSize.Height);\n                dragablzItem.SetCurrentValue(DragablzItem.XProperty, _floatingItems.ActualWidth/2 - newWidth/2);\n                dragablzItem.SetCurrentValue(DragablzItem.YProperty, _floatingItems.ActualHeight/2 - newHeight/2);\n                dragablzItem.SetCurrentValue(WidthProperty, newWidth);\n                dragablzItem.SetCurrentValue(HeightProperty, newHeight);\n            }), DispatcherPriority.Loaded);                \n                \n            _floatTransfer = null;\n        }\n\n        private DragablzItem GetFloatingContainerForItemOverride()\n        {\n            if (string.IsNullOrWhiteSpace(FloatingItemHeaderMemberPath))\n                return new DragablzItem();\n\n            return new HeaderedDragablzItem();\n        }\n\n        private static void ClearingFloatingContainerForItemOverride(DependencyObject dependencyObject, object o)\n        {\n            SetIsFloatingInLayout(dependencyObject, false);\n        }\n\n        private void TileFloatingItemsExecuted(object sender, ExecutedRoutedEventArgs executedRoutedEventArgs)\n        {\n            var dragablzItems = _floatingItems.DragablzItems();\n            Tiler.Tile(dragablzItems, new Size(_floatingItems.ActualWidth, _floatingItems.ActualHeight));\n        }\n\n        private void TileFloatingItemsHorizontallyExecuted(object sender, ExecutedRoutedEventArgs e)\n        {\n            var dragablzItems = _floatingItems.DragablzItems();\n            Tiler.TileHorizontally(dragablzItems, new Size(_floatingItems.ActualWidth, _floatingItems.ActualHeight));\n        }\n\n        private void TileFloatingItemsVerticallyExecuted(object sender, ExecutedRoutedEventArgs e)\n        {\n            var dragablzItems = _floatingItems.DragablzItems();\n            Tiler.TileVertically(dragablzItems, new Size(_floatingItems.ActualWidth, _floatingItems.ActualHeight));\n        }\n\n        public static readonly DependencyProperty FloatingItemStateProperty = DependencyProperty.RegisterAttached(\n            \"FloatingItemState\", typeof (WindowState), typeof (Layout), new PropertyMetadata(default(WindowState)));\n\n        public static void SetFloatingItemState(DependencyObject element, WindowState value)\n        {\n            element.SetValue(FloatingItemStateProperty, value);\n        }\n\n        public static WindowState GetFloatingItemState(DependencyObject element)\n        {\n            return (WindowState) element.GetValue(FloatingItemStateProperty);\n        }\n\n        internal static readonly DependencyProperty LocationSnapShotProperty = DependencyProperty.RegisterAttached(\n            \"LocationSnapShot\", typeof (LocationSnapShot), typeof (Layout), new PropertyMetadata(default(LocationSnapShot)));\n\n        internal static void SetLocationSnapShot(FrameworkElement element, LocationSnapShot value)\n        {\n            element.SetValue(LocationSnapShotProperty, value);\n        }\n\n        internal static LocationSnapShot GetLocationSnapShot(FrameworkElement element)\n        {\n            return (LocationSnapShot) element.GetValue(LocationSnapShotProperty);\n        }\n\n        private static void CanExecuteMaximiseFloatingItem(object sender, CanExecuteRoutedEventArgs canExecuteRoutedEventArgs)\n        {\n            canExecuteRoutedEventArgs.CanExecute = false;\n            canExecuteRoutedEventArgs.Handled = true;\n\n            var dragablzItem = canExecuteRoutedEventArgs.Parameter as DragablzItem;\n            if (dragablzItem != null)\n            {\n                canExecuteRoutedEventArgs.CanExecute = new[] {WindowState.Normal, WindowState.Minimized}.Contains(GetFloatingItemState(dragablzItem));\n            }\n        }\n\n        private static void CanExecuteRestoreFloatingItem(object sender, CanExecuteRoutedEventArgs canExecuteRoutedEventArgs)\n        {\n            canExecuteRoutedEventArgs.CanExecute = false;\n            canExecuteRoutedEventArgs.Handled = true;\n\n            var dragablzItem = canExecuteRoutedEventArgs.Parameter as DragablzItem;\n            if (dragablzItem != null)\n            {\n                canExecuteRoutedEventArgs.CanExecute = new[] { WindowState.Maximized, WindowState.Minimized }.Contains(GetFloatingItemState(dragablzItem));\n            }\n        }\n\n        private static void CanExecuteCloseFloatingItem(object sender, CanExecuteRoutedEventArgs canExecuteRoutedEventArgs)\n        {\n            canExecuteRoutedEventArgs.CanExecute = true;\n            canExecuteRoutedEventArgs.Handled = true;\n        }\n\n        private void CloseFloatingItemExecuted(object sender, ExecutedRoutedEventArgs executedRoutedEventArgs)\n        {\n            var dragablzItem = executedRoutedEventArgs.Parameter as DragablzItem;\n            if (dragablzItem == null) throw new ApplicationException(\"Parameter must be a DragablzItem\");\n\n            var cancel = false;\n            if (ClosingFloatingItemCallback != null)\n            {\n                var callbackArgs = new ItemActionCallbackArgs<Layout>(Window.GetWindow(this), this, dragablzItem);\n                ClosingFloatingItemCallback(callbackArgs);\n                cancel = callbackArgs.IsCancelled;\n            }\n\n            if (cancel) return;\n\n            //TODO ...need a similar tp manual inter tab controlller here for the extra hook\n\n            var item = _floatingItems.ItemContainerGenerator.ItemFromContainer(dragablzItem);\n\n            CollectionTeaser collectionTeaser;\n            if (CollectionTeaser.TryCreate(_floatingItems.ItemsSource, out collectionTeaser))\n                collectionTeaser.Remove(item);\n            else\n                _floatingItems.Items.Remove(item);\n        }\n\n        private static void MaximiseFloatingItemExecuted(object sender, ExecutedRoutedEventArgs e)\n        {\n            var dragablzItem = e.Parameter as DragablzItem;\n            if (dragablzItem == null) return;\n            \n            SetLocationSnapShot(dragablzItem, LocationSnapShot.Take(dragablzItem));\n            SetFloatingItemState(dragablzItem, WindowState.Maximized);\n        }\n\n        private static void RestoreFloatingItemExecuted(object sender, ExecutedRoutedEventArgs e)\n        {\n            var dragablzItem = e.Parameter as DragablzItem;\n            if (dragablzItem == null) return;\n            \n            SetFloatingItemState(dragablzItem, WindowState.Normal);\n            var locationSnapShot = GetLocationSnapShot(dragablzItem);\n            if (locationSnapShot != null)\n                locationSnapShot.Apply(dragablzItem);            \n        }\n\n        private bool IsHostingTab()\n        {\n            return this.VisualTreeDepthFirstTraversal().OfType<TabablzControl>()\n                .FirstOrDefault(t => t.InterTabController != null && t.InterTabController.Partition == Partition)\n                != null;\n        }\n\n        private static void MarkTopLeftItem(Layout layout)\n        {\n            var layoutAccessor = layout.Query();\n            if (layoutAccessor.TabablzControl != null)\n            {\n                SetIsTopLeftItem(layoutAccessor.TabablzControl, true);\n                return;\n            }\n            var branchAccessor = layoutAccessor.BranchAccessor;\n            while (branchAccessor != null && branchAccessor.FirstItemTabablzControl == null)\n            {\n                branchAccessor = branchAccessor.FirstItemBranchAccessor;\n            }\n\n            foreach (var tabablzControl in layoutAccessor.TabablzControls())\n            {\n                SetIsTopLeftItem(tabablzControl, branchAccessor != null && Equals(tabablzControl, branchAccessor.FirstItemTabablzControl));\n            }\n        }\n\n        private void CanExecuteUnfloat(object sender, CanExecuteRoutedEventArgs canExecuteRoutedEventArgs)\n        {\n            canExecuteRoutedEventArgs.CanExecute = IsHostingTab();\n            canExecuteRoutedEventArgs.ContinueRouting = false;\n            canExecuteRoutedEventArgs.Handled = true;\n        }        \n\n        private void UnfloatExecuted(object sender, ExecutedRoutedEventArgs executedRoutedEventArgs)\n        {\n            var dragablzItem = executedRoutedEventArgs.Parameter as DragablzItem;\n            if (dragablzItem == null) return;\n            \n            var exemplarTabControl = this.VisualTreeDepthFirstTraversal().OfType<TabablzControl>()\n                .FirstOrDefault(t => t.InterTabController != null && t.InterTabController.Partition == Partition);                \n\n            if (exemplarTabControl == null) return;\n\n            //TODO passing the exemplar tab in here isnt ideal, as strictly speaking there isnt one.\n            var newTabHost = exemplarTabControl.InterTabController.InterTabClient.GetNewHost(exemplarTabControl.InterTabController.InterTabClient,\n                exemplarTabControl.InterTabController.Partition, exemplarTabControl);\n            if (newTabHost == null || newTabHost.TabablzControl == null || newTabHost.Container == null)\n                throw new ApplicationException(\"New tab host was not correctly provided\");\n\n            var floatingItemSnapShots = dragablzItem.VisualTreeDepthFirstTraversal()\n                    .OfType<Layout>()\n                    .SelectMany(l => l.FloatingDragablzItems().Select(FloatingItemSnapShot.Take))\n                    .ToList();\n\n            var content = dragablzItem.Content ?? dragablzItem;\n\n            //remove from source\n            CollectionTeaser collectionTeaser;\n            if (CollectionTeaser.TryCreate(FloatingItemsSource, out collectionTeaser))\n                collectionTeaser.Remove(content);\n            else\n                FloatingItems.Remove(content);\n\n            var myWindow = Window.GetWindow(this);\n            if (myWindow == null) throw new ApplicationException(\"Unable to find owning window.\");\n            newTabHost.Container.Width = myWindow.RestoreBounds.Width;\n            newTabHost.Container.Height = myWindow.RestoreBounds.Height;\n\n            newTabHost.Container.Left = myWindow.Left + 20;\n            newTabHost.Container.Top = myWindow.Top + 20;                     \n\n            Dispatcher.BeginInvoke(new Action(() =>            \n            {\n                newTabHost.TabablzControl.AddToSource(content);\n                newTabHost.TabablzControl.SelectedItem = content;\n                newTabHost.Container.Show();\n                newTabHost.Container.Activate();\n\n                Dispatcher.BeginInvoke(\n                    new Action(() => RestoreFloatingItemSnapShots(newTabHost.TabablzControl, floatingItemSnapShots)));\n            }), DispatcherPriority.DataBind);            \n        }\n    }\n}"
  },
  {
    "path": "third_party/Dragablz/Dragablz/Dockablz/LayoutAccessor.cs",
    "content": "using System;\nusing System.Collections.Generic;\n\nnamespace Dragablz.Dockablz\n{\n    /// <summary>\n    /// Provides information about the <see cref=\"Layout\"/> instance.\n    /// </summary>\n    public class LayoutAccessor\n    {\n        private readonly Layout _layout;\n        private readonly BranchAccessor _branchAccessor;\n        private readonly TabablzControl _tabablzControl;\n\n        public LayoutAccessor(Layout layout)\n        {\n            if (layout == null) throw new ArgumentNullException(\"layout\");\n            \n            _layout = layout;\n\n            var branch = Layout.Content as Branch;\n            if (branch != null)\n                _branchAccessor = new BranchAccessor(branch);\n            else            \n                _tabablzControl = Layout.Content as TabablzControl;            \n        }\n\n        public Layout Layout\n        {\n            get { return _layout; }\n        }\n\n        public IEnumerable<DragablzItem> FloatingItems\n        {\n            get { return _layout.FloatingDragablzItems(); }\n        }\n\n        /// <summary>\n        /// <see cref=\"BranchAccessor\"/> and <see cref=\"TabablzControl\"/> are mutually exclusive, according to whether the layout has been split, or just contains a tab control.\n        /// </summary>\n        public BranchAccessor BranchAccessor\n        {\n            get { return _branchAccessor; }\n        }\n\n        /// <summary>\n        /// <see cref=\"BranchAccessor\"/> and <see cref=\"TabablzControl\"/> are mutually exclusive, according to whether the layout has been split, or just contains a tab control.\n        /// </summary>\n        public TabablzControl TabablzControl\n        {\n            get { return _tabablzControl; }\n        }\n\n        /// <summary>\n        /// Visits the content of the layout, according to its content type.  No more than one of the provided <see cref=\"Action\"/>\n        /// callbacks will be called.  \n        /// </summary>        \n        public LayoutAccessor Visit(\n            Action<BranchAccessor> branchVisitor = null,\n            Action<TabablzControl> tabablzControlVisitor = null,\n            Action<object> contentVisitor = null)\n        {\n            if (_branchAccessor != null)\n            {\n                if (branchVisitor != null)\n                {\n                    branchVisitor(_branchAccessor);\n                }\n                    \n                return this;\n            }\n\n            if (_tabablzControl != null)\n            {\n                if (tabablzControlVisitor != null)\n                    tabablzControlVisitor(_tabablzControl);\n\n                return this;\n            }\n\n            if (_layout.Content != null && contentVisitor != null)\n                contentVisitor(_layout.Content);\n\n            return this;\n        }\n\n        /// <summary>\n        /// Gets all the Tabablz controls in a Layout, regardless of location.\n        /// </summary>\n        /// <returns></returns>\n        public IEnumerable<TabablzControl> TabablzControls()\n        {\n            var tabablzControls = new List<TabablzControl>();\n            this.Visit(tabablzControls, BranchAccessorVisitor, TabablzControlVisitor);\n            return tabablzControls;\n        }\n\n        private static void TabablzControlVisitor(IList<TabablzControl> resultSet, TabablzControl tabablzControl)\n        {\n            resultSet.Add(tabablzControl);\n        }\n\n        private static void BranchAccessorVisitor(IList<TabablzControl> resultSet, BranchAccessor branchAccessor)\n        {\n            branchAccessor\n                .Visit(resultSet, BranchItem.First, BranchAccessorVisitor, TabablzControlVisitor)\n                .Visit(resultSet, BranchItem.Second, BranchAccessorVisitor, TabablzControlVisitor);\n        }\n    }\n}"
  },
  {
    "path": "third_party/Dragablz/Dragablz/Dockablz/LocationReport.cs",
    "content": "using System;\n\nnamespace Dragablz.Dockablz\n{\n    /// <summary>\n    /// Provides information about where a tab control is withing a layout structure.\n    /// </summary>\n    public class LocationReport\n    {\n        private readonly TabablzControl _tabablzControl;\n        private readonly Layout _rootLayout;\n        private readonly Branch _parentBranch;\n        private readonly bool _isLeaf;\n        private readonly bool _isSecondLeaf;\n\n        //TODO I've internalised constructor for now, so I can come back and add Window without breaking.\n\n        internal LocationReport(TabablzControl tabablzControl, Layout rootLayout)\n            : this(tabablzControl, rootLayout, null, false)\n        { }\n\n        internal LocationReport(TabablzControl tabablzControl, Layout rootLayout, Branch parentBranch, bool isSecondLeaf)\n        {\n            if (tabablzControl == null) throw new ArgumentNullException(\"tabablzControl\");\n            if (rootLayout == null) throw new ArgumentNullException(\"rootLayout\");\n\n            _tabablzControl = tabablzControl;\n            _rootLayout = rootLayout;\n            _parentBranch = parentBranch;\n            _isLeaf = _parentBranch != null;\n            _isSecondLeaf = isSecondLeaf;\n        }\n\n        public TabablzControl TabablzControl\n        {\n            get { return _tabablzControl; }\n        }\n\n        public Layout RootLayout\n        {\n            get { return _rootLayout; }\n        }\n\n        /// <summary>\n        /// Gets the parent branch if this is a leaf. If the <see cref=\"TabablzControl\"/> is directly under the <see cref=\"RootLayout\"/> will be <c>null</c>.\n        /// </summary>\n        public Branch ParentBranch\n        {\n            get { return _parentBranch; }\n        }\n\n        /// <summary>\n        /// Idicates if this is a leaf in a branch. <c>True</c> if <see cref=\"ParentBranch\"/> is not null.\n        /// </summary>\n        public bool IsLeaf\n        {\n            get { return _isLeaf; }\n        }\n\n        public bool IsSecondLeaf\n        {\n            get { return _isSecondLeaf; }\n        }\n    }\n}"
  },
  {
    "path": "third_party/Dragablz/Dragablz/Dockablz/LocationReportBuilder.cs",
    "content": "using System;\n\nnamespace Dragablz.Dockablz\n{\n    internal class LocationReportBuilder\n    {\n        private readonly TabablzControl _targetTabablzControl;\n        private Branch _branch;\n        private bool _isSecondLeaf;\n        private Layout _layout;\n\n        public LocationReportBuilder(TabablzControl targetTabablzControl)\n        {\n            _targetTabablzControl = targetTabablzControl;\n        }\n\n        public TabablzControl TargetTabablzControl\n        {\n            get { return _targetTabablzControl; }\n        }\n\n        public bool IsFound { get; private set; }\n\n        public void MarkFound()\n        {\n            if (IsFound)\n                throw new InvalidOperationException(\"Already found.\");\n\n            IsFound = true;\n\n            _layout = CurrentLayout;\n        }\n\n        public void MarkFound(Branch branch, bool isSecondLeaf)\n        {\n            if (branch == null) throw new ArgumentNullException(\"branch\");\n            if (IsFound)\n                throw new InvalidOperationException(\"Already found.\");\n\n            IsFound = true;\n\n            _layout = CurrentLayout;\n            _branch = branch;\n            _isSecondLeaf = isSecondLeaf;\n        }\n\n        public Layout CurrentLayout { get; set; }\n\n        public LocationReport ToLocationReport()\n        {\n            return new LocationReport(_targetTabablzControl, _layout, _branch, _isSecondLeaf);\n        }\n    }\n}"
  },
  {
    "path": "third_party/Dragablz/Dragablz/Dockablz/LocationReportException.cs",
    "content": "using System;\n\nnamespace Dragablz.Dockablz\n{\n    /// <summary>\n    /// \n    /// </summary>\n    public class LocationReportException : Exception\n    {\n        public LocationReportException()\n        {\n        }\n\n        public LocationReportException(string message) : base(message)\n        {\n        }\n\n        public LocationReportException(string message, Exception innerException) : base(message, innerException)\n        {\n        }\n    }\n}"
  },
  {
    "path": "third_party/Dragablz/Dragablz/Dockablz/LocationSnapShot.cs",
    "content": "﻿using System;\nusing System.Windows;\nusing System.Windows.Navigation;\n\nnamespace Dragablz.Dockablz\n{\n    /// <summary>\n    /// Initially needed to restore MDI dragablz items styles after a max then restore,\n    /// as the trigger which binds the item width to the canvas width sets the  Width back to the default\n    /// (e.g double.NaN) when the trigger is unset.  so we need to re-apply sizes manually\n    /// </summary>\n    internal class LocationSnapShot\n    {\n        private readonly double _width;\n        private readonly double _height;\n\n        public static LocationSnapShot Take(FrameworkElement frameworkElement)\n        {\n            if (frameworkElement == null) throw new ArgumentNullException(\"frameworkElement\");\n            \n            return new LocationSnapShot(frameworkElement.Width, frameworkElement.Height);\n        }\n\n        private LocationSnapShot(double width, double height)\n        {\n            _width = width;\n            _height = height;\n        }\n\n        public void Apply(FrameworkElement frameworkElement)\n        {\n            if (frameworkElement == null) throw new ArgumentNullException(\"frameworkElement\");\n            \n            frameworkElement.SetCurrentValue(FrameworkElement.WidthProperty, _width);\n            frameworkElement.SetCurrentValue(FrameworkElement.HeightProperty, _height);\n        }\n    }\n}"
  },
  {
    "path": "third_party/Dragablz/Dragablz/Dockablz/Tiler.cs",
    "content": "﻿using System;\nusing System.CodeDom;\nusing System.Collections.Generic;\nusing System.Linq;\nusing System.Runtime.CompilerServices;\nusing System.Text;\nusing System.Threading.Tasks;\nusing System.Windows;\nusing System.Windows.Controls;\n\nnamespace Dragablz.Dockablz\n{\n    internal class Tiler\n    {\n        public static void Tile(IEnumerable<DragablzItem> dragablzItems, Size bounds)\n        {\n            if (dragablzItems == null) throw new ArgumentNullException(\"dragablzItems\");            \n\n            var items = new Queue<DragablzItem>(dragablzItems.OrderBy(Panel.GetZIndex));\n\n            var cellCountPerColumn = TilerCalculator.GetCellCountPerColumn(items.Count());\n            var x = 0d;\n            var cellWidth = bounds.Width / cellCountPerColumn.Length;\n            foreach (var cellCount in cellCountPerColumn)\n            {\n                var y = 0d;\n                var cellHeight = bounds.Height / cellCount;\n                for (var cell = 0; cell < cellCount; cell++)\n                {\n                    var item = items.Dequeue();\n                    Layout.SetFloatingItemState(item, WindowState.Normal);\n                    item.SetCurrentValue(DragablzItem.XProperty, x);\n                    item.SetCurrentValue(DragablzItem.YProperty, y);\n                    item.SetCurrentValue(FrameworkElement.WidthProperty, cellWidth);\n                    item.SetCurrentValue(FrameworkElement.HeightProperty, cellHeight);\n\n                    y += cellHeight;\n                }\n\n                x += cellWidth;\n            }\n        }\n\n        public static void TileHorizontally(IEnumerable<DragablzItem> dragablzItems, Size bounds)\n        {\n            if (dragablzItems == null) throw new ArgumentNullException(\"dragablzItems\");\n\n            var items = dragablzItems.ToList();\n\n            var x = 0.0;\n            var width = bounds.Width/items.Count;\n            foreach (var dragablzItem in items)\n            {\n                Layout.SetFloatingItemState(dragablzItem, WindowState.Normal);\n                dragablzItem.SetCurrentValue(DragablzItem.XProperty, x);\n                dragablzItem.SetCurrentValue(DragablzItem.YProperty, 0d);\n                x += width;\n                dragablzItem.SetCurrentValue(FrameworkElement.WidthProperty, width);\n                dragablzItem.SetCurrentValue(FrameworkElement.HeightProperty, bounds.Height);\n            }\n        }\n\n        public static void TileVertically(IEnumerable<DragablzItem> dragablzItems, Size bounds)\n        {\n            if (dragablzItems == null) throw new ArgumentNullException(\"dragablzItems\");\n\n            var items = dragablzItems.ToList();\n\n            var y = 0.0;\n            var height = bounds.Height / items.Count;\n            foreach (var dragablzItem in items)\n            {\n                Layout.SetFloatingItemState(dragablzItem, WindowState.Normal);\n                dragablzItem.SetCurrentValue(DragablzItem.YProperty, y);\n                dragablzItem.SetCurrentValue(DragablzItem.XProperty, 0d);\n                y += height;\n                dragablzItem.SetCurrentValue(FrameworkElement.HeightProperty, height);\n                dragablzItem.SetCurrentValue(FrameworkElement.WidthProperty, bounds.Width);\n            }\n        }\n\n    }\n}"
  },
  {
    "path": "third_party/Dragablz/Dragablz/Dockablz/TilerCalculator.cs",
    "content": "﻿using System;\nusing System.Collections.Generic;\nusing System.Linq;\n\nnamespace Dragablz.Dockablz\n{\n    internal static class TilerCalculator\n    {\n        public static int[] GetCellCountPerColumn(int totalCells)\n        {\n            if (totalCells == 2)\n                return new[] {1, 1};\n\n            var sqrt = Math.Sqrt(totalCells);            \n\n            if (unchecked(sqrt == (int) sqrt))\n                return Enumerable.Repeat((int) sqrt, (int) sqrt).ToArray();\n\n            var columns = (int)Math.Round(sqrt, MidpointRounding.AwayFromZero);\n            var minimumCellsPerColumns = (int)Math.Floor(sqrt);\n            var result = Enumerable.Repeat(minimumCellsPerColumns, columns).ToArray();\n\n            for (var i = columns - 1; result.Aggregate((current, next) => current + next) < totalCells; i--)\n                result[i]+=1;\n\n            return result;\n        }\n    }\n}"
  },
  {
    "path": "third_party/Dragablz/Dragablz/Dragablz.net40.csproj",
    "content": "﻿<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<Project ToolsVersion=\"12.0\" DefaultTargets=\"Build\" xmlns=\"http://schemas.microsoft.com/developer/msbuild/2003\">\n  <Import Project=\"$(MSBuildExtensionsPath)\\$(MSBuildToolsVersion)\\Microsoft.Common.props\" Condition=\"Exists('$(MSBuildExtensionsPath)\\$(MSBuildToolsVersion)\\Microsoft.Common.props')\" />\n  <PropertyGroup>\n    <Configuration Condition=\" '$(Configuration)' == '' \">Debug</Configuration>\n    <Platform Condition=\" '$(Platform)' == '' \">AnyCPU</Platform>\n    <ProjectGuid>{886AD9DE-BCED-4A99-8376-5177B376C0AC}</ProjectGuid>\n    <OutputType>Library</OutputType>\n    <AppDesignerFolder>Properties</AppDesignerFolder>\n    <RootNamespace>Dragablz</RootNamespace>\n    <AssemblyName>Dragablz</AssemblyName>\n    <TargetFrameworkVersion>v4.0</TargetFrameworkVersion>\n    <FileAlignment>512</FileAlignment>\n    <TargetFrameworkProfile>\n    </TargetFrameworkProfile>\n  </PropertyGroup>\n  <PropertyGroup Condition=\" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' \">\n    <DebugSymbols>true</DebugSymbols>\n    <DebugType>full</DebugType>\n    <Optimize>false</Optimize>\n    <OutputPath>..\\bin\\Debug_net40\\</OutputPath>\n    <DefineConstants>TRACE;DEBUG;NET40</DefineConstants>\n    <ErrorReport>prompt</ErrorReport>\n    <WarningLevel>4</WarningLevel>\n    <DocumentationFile>..\\bin\\Debug_net40\\Dragablz.XML</DocumentationFile>\n  </PropertyGroup>\n  <PropertyGroup Condition=\" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' \">\n    <DebugType>pdbonly</DebugType>\n    <Optimize>true</Optimize>\n    <OutputPath>..\\bin\\Release_net40\\</OutputPath>\n    <DefineConstants>TRACE;NET40</DefineConstants>\n    <ErrorReport>prompt</ErrorReport>\n    <WarningLevel>4</WarningLevel>\n    <DocumentationFile>..\\bin\\Release_net40\\Dragablz.XML</DocumentationFile>\n  </PropertyGroup>\n  <ItemGroup>\n    <Reference Include=\"PresentationCore\" />\n    <Reference Include=\"PresentationFramework\" />\n    <Reference Include=\"System\" />\n    <Reference Include=\"System.Core\" />\n    <Reference Include=\"System.Xaml\" />\n    <Reference Include=\"System.Xml.Linq\" />\n    <Reference Include=\"System.Data.DataSetExtensions\" />\n    <Reference Include=\"Microsoft.CSharp\" />\n    <Reference Include=\"System.Data\" />\n    <Reference Include=\"System.Xml\" />\n    <Reference Include=\"WindowsBase\" />\n  </ItemGroup>\n  <ItemGroup>\n    <Compile Include=\"Core\\HitTest.cs\" />\n    <Compile Include=\"Dockablz\\BranchResult.cs\" />\n    <Compile Include=\"Dockablz\\Finder.cs\" />\n    <Compile Include=\"Dockablz\\LocationReport.cs\" />\n    <Compile Include=\"Dockablz\\LocationReportBuilder.cs\" />\n    <Compile Include=\"Dockablz\\LocationReportException.cs\" />\n    <Compile Include=\"EmptyHeaderSizingHint.cs\" />\n    <Compile Include=\"LocationHint.cs\" />\n    <Compile Include=\"CanvasOrganiser.cs\" />\n    <Compile Include=\"ContainerCustomisations.cs\" />\n    <Compile Include=\"Converters\\BooleanAndToVisibilityConverter.cs\" />\n    <Compile Include=\"Converters\\EqualityToBooleanConverter.cs\" />\n    <Compile Include=\"Converters\\EqualityToVisibilityConverter.cs\" />\n    <Compile Include=\"Converters\\ShowDefaultCloseButtonConverter.cs\" />\n    <Compile Include=\"Core\\CollectionTeaser.cs\" />\n    <Compile Include=\"Core\\Extensions.cs\" />\n    <Compile Include=\"Core\\FuncComparer.cs\" />\n    <Compile Include=\"Core\\InterTabTransfer.cs\" />\n    <Compile Include=\"Core\\MultiComparer.cs\" />\n    <Compile Include=\"Core\\Native.cs\" />\n    <Compile Include=\"Core\\SystemCommand.cs\" />\n    <Compile Include=\"Core\\TabHeaderDragStartInformation.cs\" />\n    <Compile Include=\"Core\\WindowMessage.cs\" />\n    <Compile Include=\"DefaultInterLayoutClient.cs\" />\n    <Compile Include=\"DefaultInterTabClient.cs\" />\n    <Compile Include=\"Dockablz\\Branch.cs\" />\n    <Compile Include=\"Dockablz\\BranchAccessor.cs\" />\n    <Compile Include=\"Dockablz\\BranchItem.cs\" />\n    <Compile Include=\"Dockablz\\CouldBeHeaderedStyleSelector.cs\" />\n    <Compile Include=\"Dockablz\\DropZone.cs\" />\n    <Compile Include=\"Dockablz\\DropZoneLocation.cs\" />\n    <Compile Include=\"Dockablz\\Extensions.cs\" />\n    <Compile Include=\"Dockablz\\FloatingItemSnapShot.cs\" />\n    <Compile Include=\"Dockablz\\FloatRequestedEvent.cs\" />\n    <Compile Include=\"Dockablz\\FloatTransfer.cs\" />\n    <Compile Include=\"Dockablz\\Layout.cs\" />\n    <Compile Include=\"Dockablz\\LayoutAccessor.cs\" />\n    <Compile Include=\"Dockablz\\LocationSnapShot.cs\" />\n    <Compile Include=\"Dockablz\\Tiler.cs\" />\n    <Compile Include=\"Dockablz\\TilerCalculator.cs\" />\n    <Compile Include=\"DragablzColors.cs\" />\n    <Compile Include=\"DragablzDragCompletedEventArgs.cs\" />\n    <Compile Include=\"DragablzDragDeltaEventArgs.cs\" />\n    <Compile Include=\"DragablzDragStartedEventArgs.cs\" />\n    <Compile Include=\"DragablzIcon.cs\" />\n    <Compile Include=\"DragablzItem.cs\" />\n    <Compile Include=\"DragablzItemEventArgs.cs\" />\n    <Compile Include=\"DragablzItemsControl.cs\" />\n    <Compile Include=\"DragablzWindow.cs\" />\n    <Compile Include=\"HeaderedDragablzItem.cs\" />\n    <Compile Include=\"HeaderedItemViewModel.cs\" />\n    <Compile Include=\"HorizontalOrganiser.cs\" />\n    <Compile Include=\"HorizontalPositionMonitor.cs\" />\n    <Compile Include=\"IInterLayoutClient.cs\" />\n    <Compile Include=\"IInterTabClient.cs\" />\n    <Compile Include=\"IItemsOrganiser.cs\" />\n    <Compile Include=\"IManualInterTabClient.cs\" />\n    <Compile Include=\"INewTabHost.cs\" />\n    <Compile Include=\"InterTabController.cs\" />\n    <Compile Include=\"ItemActionCallbackArgs.cs\" />\n    <Compile Include=\"MoveItemRequest.cs\" />\n    <Compile Include=\"StackOrganiser.cs\" />\n    <Compile Include=\"StackPositionMonitor.cs\" />\n    <Compile Include=\"LocationChangedEventArgs.cs\" />\n    <Compile Include=\"NewTabHost.cs\" />\n    <Compile Include=\"OrderChangedEventArgs.cs\" />\n    <Compile Include=\"PositionMonitor.cs\" />\n    <Compile Include=\"Properties\\AssemblyInfo.cs\" />\n    <Compile Include=\"Referenceless\\AnonymousDisposable.cs\" />\n    <Compile Include=\"Referenceless\\DefaultDisposable.cs\" />\n    <Compile Include=\"Referenceless\\Disposable.cs\" />\n    <Compile Include=\"Referenceless\\ICancelable.cs\" />\n    <Compile Include=\"Referenceless\\SerialDisposable.cs\" />\n    <Compile Include=\"StoryboardCompletionListener.cs\" />\n    <Compile Include=\"TabablzControl.cs\" />\n    <Compile Include=\"TabablzHeaderSizeConverter.cs\" />\n    <Compile Include=\"TabablzItemStyleSelector.cs\" />\n    <Compile Include=\"TabEmptiedResponse.cs\" />\n    <Compile Include=\"Themes\\BrushToRadialGradientBrushConverter.cs\" />\n    <Compile Include=\"Themes\\MaterialDesignAssist.cs\" />\n    <Compile Include=\"Themes\\Ripple.cs\" />\n    <Compile Include=\"Themes\\RippleAssist.cs\" />\n    <Compile Include=\"Themes\\SystemCommandIcon.cs\" />\n    <Compile Include=\"Trapezoid.cs\" />\n    <Compile Include=\"VerticalOrganiser.cs\" />\n    <Compile Include=\"VerticalPositionMonitor.cs\" />\n  </ItemGroup>\n  <ItemGroup>\n    <Page Include=\"Themes\\Dockablz.xaml\">\n      <Generator>MSBuild:Compile</Generator>\n      <SubType>Designer</SubType>\n    </Page>\n    <Page Include=\"Themes\\Generic.xaml\">\n      <Generator>MSBuild:Compile</Generator>\n      <SubType>Designer</SubType>\n    </Page>\n    <Page Include=\"Themes\\MahApps.xaml\">\n      <Generator>MSBuild:Compile</Generator>\n      <SubType>Designer</SubType>\n    </Page>\n    <Page Include=\"Themes\\MaterialDesign.xaml\">\n      <Generator>MSBuild:Compile</Generator>\n      <SubType>Designer</SubType>\n    </Page>\n  </ItemGroup>\n  <Import Project=\"$(MSBuildToolsPath)\\Microsoft.CSharp.targets\" />\n  <!-- To modify your build process, add your task inside one of the targets below and uncomment it. \n       Other similar extension points exist, see Microsoft.Common.targets.\n  <Target Name=\"BeforeBuild\">\n  </Target>\n  <Target Name=\"AfterBuild\">\n  </Target>\n  -->\n</Project>"
  },
  {
    "path": "third_party/Dragablz/Dragablz/Dragablz.net45.csproj",
    "content": "﻿<?xml version=\"1.0\" encoding=\"utf-8\"?>\r\n<Project ToolsVersion=\"12.0\" DefaultTargets=\"Build\" xmlns=\"http://schemas.microsoft.com/developer/msbuild/2003\">\r\n  <PropertyGroup>\r\n    <Configuration Condition=\" '$(Configuration)' == '' \">Debug</Configuration>\r\n    <Platform Condition=\" '$(Platform)' == '' \">AnyCPU</Platform>\r\n    <ProductVersion>8.0.30703</ProductVersion>\r\n    <SchemaVersion>2.0</SchemaVersion>\r\n    <ProjectGuid>{7B11011C-7FD7-4AB0-A1AD-04E940B026DE}</ProjectGuid>\r\n    <OutputType>library</OutputType>\r\n    <AppDesignerFolder>Properties</AppDesignerFolder>\r\n    <RootNamespace>Dragablz</RootNamespace>\r\n    <AssemblyName>Dragablz</AssemblyName>\r\n    <TargetFrameworkVersion>v4.5</TargetFrameworkVersion>\r\n    <TargetFrameworkProfile>\r\n    </TargetFrameworkProfile>\r\n    <FileAlignment>512</FileAlignment>\r\n    <ProjectTypeGuids>{60dc8134-eba5-43b8-bcc9-bb4bc16c2548};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids>\r\n    <WarningLevel>4</WarningLevel>\r\n  </PropertyGroup>\r\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)' == 'Debug|x86'\">\r\n    <DebugSymbols>true</DebugSymbols>\r\n    <OutputPath>bin\\x86\\Debug\\</OutputPath>\r\n    <DefineConstants>TRACE;DEBUG;NET45</DefineConstants>\r\n    <DocumentationFile>bin\\x86\\Debug\\Dragablz.xml</DocumentationFile>\r\n    <NoWarn>CS1591, CS0169, CS1574, CS1587</NoWarn>\r\n    <DebugType>full</DebugType>\r\n    <PlatformTarget>x86</PlatformTarget>\r\n    <ErrorReport>prompt</ErrorReport>\r\n    <CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>\r\n  </PropertyGroup>\r\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)' == 'Release|x86'\">\r\n    <OutputPath>bin\\x86\\Release\\</OutputPath>\r\n    <DefineConstants>TRACE;NET45</DefineConstants>\r\n    <DocumentationFile>..\\bin\\Release_net45\\Dragablz.XML</DocumentationFile>\r\n    <Optimize>true</Optimize>\r\n    <NoWarn>CS1591, CS0169, CS1574, CS1587</NoWarn>\r\n    <DebugType>pdbonly</DebugType>\r\n    <PlatformTarget>x86</PlatformTarget>\r\n    <ErrorReport>prompt</ErrorReport>\r\n    <CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>\r\n  </PropertyGroup>\r\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)' == 'Debug|x64'\">\r\n    <DebugSymbols>true</DebugSymbols>\r\n    <OutputPath>bin\\x64\\Debug\\</OutputPath>\r\n    <DefineConstants>TRACE;DEBUG;NET45</DefineConstants>\r\n    <DocumentationFile>..\\bin\\Debug_net45\\Dragablz.XML</DocumentationFile>\r\n    <NoWarn>CS1591, CS0169, CS1574, CS1587</NoWarn>\r\n    <DebugType>full</DebugType>\r\n    <PlatformTarget>x64</PlatformTarget>\r\n    <ErrorReport>prompt</ErrorReport>\r\n    <CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>\r\n  </PropertyGroup>\r\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)' == 'Release|x64'\">\r\n    <OutputPath>bin\\x64\\Release\\</OutputPath>\r\n    <DefineConstants>TRACE;NET45</DefineConstants>\r\n    <DocumentationFile>..\\bin\\Release_net45\\Dragablz.XML</DocumentationFile>\r\n    <Optimize>true</Optimize>\r\n    <NoWarn>CS1591, CS0169, CS1574, CS1587</NoWarn>\r\n    <DebugType>pdbonly</DebugType>\r\n    <PlatformTarget>x64</PlatformTarget>\r\n    <ErrorReport>prompt</ErrorReport>\r\n    <CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>\r\n  </PropertyGroup>\r\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)' == 'Appx|x86'\">\r\n    <OutputPath>bin\\x86\\Appx\\</OutputPath>\r\n    <DefineConstants>TRACE;NET45</DefineConstants>\r\n    <DocumentationFile>..\\bin\\Release_net45\\Dragablz.XML</DocumentationFile>\r\n    <Optimize>true</Optimize>\r\n    <NoWarn>CS1591, CS0169, CS1574, CS1587</NoWarn>\r\n    <DebugType>pdbonly</DebugType>\r\n    <PlatformTarget>x86</PlatformTarget>\r\n    <ErrorReport>prompt</ErrorReport>\r\n    <CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>\r\n  </PropertyGroup>\r\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)' == 'Appx|x64'\">\r\n    <OutputPath>bin\\x64\\Appx\\</OutputPath>\r\n    <DefineConstants>TRACE;NET45</DefineConstants>\r\n    <DocumentationFile>..\\bin\\Release_net45\\Dragablz.XML</DocumentationFile>\r\n    <Optimize>true</Optimize>\r\n    <NoWarn>CS1591, CS0169, CS1574, CS1587</NoWarn>\r\n    <DebugType>pdbonly</DebugType>\r\n    <PlatformTarget>x64</PlatformTarget>\r\n    <ErrorReport>prompt</ErrorReport>\r\n    <CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>\r\n  </PropertyGroup>\r\n  <ItemGroup>\r\n    <Reference Include=\"System\" />\r\n    <Reference Include=\"System.Data\" />\r\n    <Reference Include=\"System.Xml\" />\r\n    <Reference Include=\"Microsoft.CSharp\" />\r\n    <Reference Include=\"System.Core\" />\r\n    <Reference Include=\"System.Xml.Linq\" />\r\n    <Reference Include=\"System.Data.DataSetExtensions\" />\r\n    <Reference Include=\"System.Xaml\">\r\n      <RequiredTargetFramework>4.0</RequiredTargetFramework>\r\n    </Reference>\r\n    <Reference Include=\"WindowsBase\" />\r\n    <Reference Include=\"PresentationCore\" />\r\n    <Reference Include=\"PresentationFramework\" />\r\n  </ItemGroup>\r\n  <ItemGroup>\r\n    <Compile Include=\"Converters\\ShowDefaultCloseButtonConverter.cs\" />\r\n    <Compile Include=\"Core\\HitTest.cs\" />\r\n    <Compile Include=\"Dockablz\\BranchResult.cs\" />\r\n    <Compile Include=\"Dockablz\\Finder.cs\" />\r\n    <Compile Include=\"Dockablz\\LocationReport.cs\" />\r\n    <Compile Include=\"Dockablz\\LocationReportBuilder.cs\" />\r\n    <Compile Include=\"Dockablz\\LocationReportException.cs\" />\r\n    <Compile Include=\"EmptyHeaderSizingHint.cs\" />\r\n    <Compile Include=\"ItemActionCallbackArgs.cs\" />\r\n    <Compile Include=\"ContainerCustomisations.cs\" />\r\n    <Compile Include=\"Converters\\BooleanAndToVisibilityConverter.cs\" />\r\n    <Compile Include=\"Converters\\EqualityToBooleanConverter.cs\" />\r\n    <Compile Include=\"Converters\\EqualityToVisibilityConverter.cs\" />\r\n    <Compile Include=\"Core\\SystemCommand.cs\" />\r\n    <Compile Include=\"Core\\WindowMessage.cs\" />\r\n    <Compile Include=\"DefaultInterLayoutClient.cs\" />\r\n    <Compile Include=\"Dockablz\\Branch.cs\" />\r\n    <Compile Include=\"Dockablz\\BranchItem.cs\" />\r\n    <Compile Include=\"Dockablz\\CouldBeHeaderedStyleSelector.cs\" />\r\n    <Compile Include=\"Dockablz\\DropZone.cs\" />\r\n    <Compile Include=\"Dockablz\\DropZoneLocation.cs\" />\r\n    <Compile Include=\"Dockablz\\Extensions.cs\" />\r\n    <Compile Include=\"Dockablz\\FloatingItemSnapShot.cs\" />\r\n    <Compile Include=\"Dockablz\\FloatRequestedEvent.cs\" />\r\n    <Compile Include=\"Dockablz\\FloatTransfer.cs\" />\r\n    <Compile Include=\"Dockablz\\Layout.cs\" />\r\n    <Compile Include=\"Core\\FuncComparer.cs\" />\r\n    <Compile Include=\"Core\\MultiComparer.cs\" />\r\n    <Compile Include=\"Core\\CollectionTeaser.cs\" />\r\n    <Compile Include=\"Dockablz\\LayoutAccessor.cs\" />\r\n    <Compile Include=\"Dockablz\\LocationSnapShot.cs\" />\r\n    <Compile Include=\"Dockablz\\BranchAccessor.cs\" />\r\n    <Compile Include=\"Dockablz\\Tiler.cs\" />\r\n    <Compile Include=\"Dockablz\\TilerCalculator.cs\" />\r\n    <Compile Include=\"DragablzColors.cs\" />\r\n    <Compile Include=\"DragablzDragCompletedEventArgs.cs\" />\r\n    <Compile Include=\"DragablzDragDeltaEventArgs.cs\" />\r\n    <Compile Include=\"DragablzDragStartedEventArgs.cs\" />\r\n    <Compile Include=\"DragablzIcon.cs\" />\r\n    <Compile Include=\"DragablzItem.cs\" />\r\n    <Compile Include=\"DragablzItemEventArgs.cs\" />\r\n    <Compile Include=\"DragablzWindow.cs\" />\r\n    <Compile Include=\"HeaderedDragablzItem.cs\" />\r\n    <Compile Include=\"HeaderedItemViewModel.cs\" />\r\n    <Compile Include=\"HorizontalOrganiser.cs\" />\r\n    <Compile Include=\"HorizontalPositionMonitor.cs\" />\r\n    <Compile Include=\"IInterLayoutClient.cs\" />\r\n    <Compile Include=\"IInterTabClient.cs\" />\r\n    <Compile Include=\"IItemsOrganiser.cs\" />\r\n    <Compile Include=\"Core\\Extensions.cs\" />\r\n    <Compile Include=\"IManualInterTabClient.cs\" />\r\n    <Compile Include=\"INewTabHost.cs\" />\r\n    <Compile Include=\"InterTabController.cs\" />\r\n    <Compile Include=\"Core\\InterTabTransfer.cs\" />\r\n    <Compile Include=\"LocationHint.cs\" />\r\n    <Compile Include=\"MoveItemRequest.cs\" />\r\n    <Compile Include=\"StackOrganiser.cs\" />\r\n    <Compile Include=\"LocationChangedEventArgs.cs\" />\r\n    <Compile Include=\"Core\\Native.cs\" />\r\n    <Compile Include=\"NewTabHost.cs\" />\r\n    <Compile Include=\"OrderChangedEventArgs.cs\" />\r\n    <Compile Include=\"PositionMonitor.cs\" />\r\n    <Compile Include=\"DefaultInterTabClient.cs\" />\r\n    <Compile Include=\"Referenceless\\AnonymousDisposable.cs\" />\r\n    <Compile Include=\"Referenceless\\DefaultDisposable.cs\" />\r\n    <Compile Include=\"Referenceless\\Disposable.cs\" />\r\n    <Compile Include=\"Referenceless\\ICancelable.cs\" />\r\n    <Compile Include=\"Referenceless\\SerialDisposable.cs\" />\r\n    <Compile Include=\"StackPositionMonitor.cs\" />\r\n    <Compile Include=\"StoryboardCompletionListener.cs\" />\r\n    <Compile Include=\"TabablzControl.cs\" />\r\n    <Compile Include=\"TabablzHeaderSizeConverter.cs\" />\r\n    <Compile Include=\"TabablzItemStyleSelector.cs\" />\r\n    <Compile Include=\"TabEmptiedResponse.cs\" />\r\n    <Compile Include=\"Core\\TabHeaderDragStartInformation.cs\" />\r\n    <Compile Include=\"Themes\\BrushToRadialGradientBrushConverter.cs\" />\r\n    <Compile Include=\"Themes\\MaterialDesignAssist.cs\" />\r\n    <Compile Include=\"Themes\\Ripple.cs\" />\r\n    <Compile Include=\"Themes\\RippleAssist.cs\" />\r\n    <Compile Include=\"Themes\\SystemCommandIcon.cs\" />\r\n    <Compile Include=\"Trapezoid.cs\" />\r\n    <Compile Include=\"VerticalOrganiser.cs\" />\r\n    <Compile Include=\"VerticalPositionMonitor.cs\" />\r\n    <Compile Include=\"CanvasOrganiser.cs\" />\r\n    <Page Include=\"Themes\\Dockablz.xaml\">\r\n      <SubType>Designer</SubType>\r\n      <Generator>MSBuild:Compile</Generator>\r\n    </Page>\r\n    <Page Include=\"Themes\\Generic.xaml\">\r\n      <Generator>MSBuild:Compile</Generator>\r\n      <SubType>Designer</SubType>\r\n    </Page>\r\n    <Page Include=\"Themes\\MahApps.xaml\">\r\n      <SubType>Designer</SubType>\r\n      <Generator>MSBuild:Compile</Generator>\r\n    </Page>\r\n    <Page Include=\"Themes\\MaterialDesign.xaml\">\r\n      <SubType>Designer</SubType>\r\n      <Generator>MSBuild:Compile</Generator>\r\n    </Page>\r\n  </ItemGroup>\r\n  <ItemGroup>\r\n    <Compile Include=\"DragablzItemsControl.cs\" />\r\n    <Compile Include=\"Properties\\AssemblyInfo.cs\">\r\n      <SubType>Code</SubType>\r\n    </Compile>\r\n    <Compile Include=\"Properties\\Resources.Designer.cs\">\r\n      <AutoGen>True</AutoGen>\r\n      <DesignTime>True</DesignTime>\r\n      <DependentUpon>Resources.resx</DependentUpon>\r\n    </Compile>\r\n    <Compile Include=\"Properties\\Settings.Designer.cs\">\r\n      <AutoGen>True</AutoGen>\r\n      <DependentUpon>Settings.settings</DependentUpon>\r\n      <DesignTimeSharedInput>True</DesignTimeSharedInput>\r\n    </Compile>\r\n    <EmbeddedResource Include=\"Properties\\Resources.resx\">\r\n      <Generator>ResXFileCodeGenerator</Generator>\r\n      <LastGenOutput>Resources.Designer.cs</LastGenOutput>\r\n    </EmbeddedResource>\r\n    <None Include=\"Properties\\Settings.settings\">\r\n      <Generator>SettingsSingleFileGenerator</Generator>\r\n      <LastGenOutput>Settings.Designer.cs</LastGenOutput>\r\n    </None>\r\n    <AppDesigner Include=\"Properties\\\" />\r\n  </ItemGroup>\r\n  <ItemGroup />\r\n  <Import Project=\"$(MSBuildToolsPath)\\Microsoft.CSharp.targets\" />\r\n  <!-- To modify your build process, add your task inside one of the targets below and uncomment it. \n       Other similar extension points exist, see Microsoft.Common.targets.\n  <Target Name=\"BeforeBuild\">\n  </Target>\n  <Target Name=\"AfterBuild\">\n  </Target>\n  -->\r\n</Project>"
  },
  {
    "path": "third_party/Dragablz/Dragablz/Dragablz.nuspec",
    "content": "<?xml version=\"1.0\"?>\n<package >\n  <metadata>\n    <id>Dragablz</id>\n    <version>0.0.0.0</version>\n    <title>Dragablz - Dragable and tearable tab control for WPF</title>\n    <authors>James Willock</authors>\n    <owners>James Willock</owners>\n    <iconUrl>https://raw.githubusercontent.com/ButchersBoy/Dragablz/master/Resources/D32.png</iconUrl>\n    <licenseUrl>http://opensource.org/licenses/MS-PL</licenseUrl>\n    <projectUrl>http://dragablz.net</projectUrl>    \n    <requireLicenseAcceptance>false</requireLicenseAcceptance>\n    <description>Dragable and tearable tab control for WPF</description>\n    <releaseNotes>We are in alpha right now!.</releaseNotes>\n    <copyright>Copyright 2014-16 James Willock/Mulholland Software Ltd</copyright>\n    <tags>WPF TabControl Tab Tearable</tags>\n  </metadata>\n  <files>\n    <file src=\"..\\bin\\Release_net45\\Dragablz.dll\" target=\"lib\\net45\" />\n    <file src=\"..\\bin\\Release_net45\\Dragablz.pdb\" target=\"lib\\net45\" />\n    <file src=\"..\\bin\\Release_net45\\Dragablz.xml\" target=\"lib\\net45\" />\n    <file src=\"..\\bin\\Release_net40\\Dragablz.dll\" target=\"lib\\net40\" />\n    <file src=\"..\\bin\\Release_net40\\Dragablz.pdb\" target=\"lib\\net40\" />\n    <file src=\"..\\bin\\Release_net40\\Dragablz.xml\" target=\"lib\\net40\" />\t\n    <file src=\"..\\Dragablz\\**\\*.cs\" target=\"src\\net45\" />\n    <file src=\"..\\Dragablz\\**\\*.cs\" target=\"src\\net40\" />\n  </files>  \n</package>\n"
  },
  {
    "path": "third_party/Dragablz/Dragablz/DragablzColors.cs",
    "content": "using System;\nusing System.Windows;\nusing System.Windows.Media;\nusing Dragablz.Core;\n\nnamespace Dragablz\n{\n    /// <summary>\n    /// \n    /// </summary>\n    /// <remarks>\n    /// In supporting .Net 4.0 we don't have access to SystemParameters.WindowGlassBrush, and even then\n    /// the opacity is not provided, so this class wraps up a few issues around here.\n    /// </remarks>\n    public static class DragablzColors\n    {\n        //TODO listen to changes from the OS to provide updates\n        public static Color WindowBaseColor = Color.FromRgb(217, 217, 217);\n        public static Brush WindowGlassBrush = GetWindowGlassBrush();\n        public static Brush WindowGlassBalancedBrush = GetBalancedWindowGlassBrush();\n        public static Brush WindowInactiveBrush = GetWindowInactiveBrush();\n\n        private static Brush GetWindowGlassBrush()\n        {\n            var colorizationParams = new Native.DWMCOLORIZATIONPARAMS();\n            Native.DwmGetColorizationParameters(ref colorizationParams);\n            var frameColor = ToColor(colorizationParams.ColorizationColor);\n\n            return new SolidColorBrush(frameColor);\n        }\n\n\n        private static Brush GetBalancedWindowGlassBrush()\n        {\n            var colorizationParams = new Native.DWMCOLORIZATIONPARAMS();\n            Native.DwmGetColorizationParameters(ref colorizationParams);\n            var frameColor = ToColor(colorizationParams.ColorizationColor);\n            var blendedColor = BlendColor(frameColor, WindowBaseColor, 100f - colorizationParams.ColorizationColorBalance);\n\n            return new SolidColorBrush(blendedColor);\n        }\n\n        private static Brush GetWindowInactiveBrush()\n        {\n            return new SolidColorBrush(SystemColors.MenuBarColor);\n        }\n\n        private static Color ToColor(UInt32 value)\n        {\n            return Color.FromArgb(255,\n                (byte)(value >> 16),\n                (byte)(value >> 8),\n                (byte)value\n                );\n        }\n\n        private static Color BlendColor(Color color1, Color color2, double percentage)\n        {\n            percentage = Math.Min(100, Math.Max(0, percentage));\n\n            return Color.FromRgb(\n                BlendColorChannel(color1.R, color2.R, percentage),\n                BlendColorChannel(color1.G, color2.G, percentage),\n                BlendColorChannel(color1.B, color2.B, percentage));\n        }\n\n        private static byte BlendColorChannel(double channel1, double channel2, double channel2Percentage)\n        {\n            var buff = channel1 + (channel2 - channel1) * channel2Percentage / 100D;\n            return Math.Min((byte)Math.Round(buff), (byte)255);\n        }   \n        \n    }\n}"
  },
  {
    "path": "third_party/Dragablz/Dragablz/DragablzDragCompletedEventArgs.cs",
    "content": "﻿using System;\nusing System.Windows;\nusing System.Windows.Controls.Primitives;\n\nnamespace Dragablz\n{\n    public delegate void DragablzDragCompletedEventHandler(object sender, DragablzDragCompletedEventArgs e);\n\n    public class DragablzDragCompletedEventArgs : RoutedEventArgs\n    {\n        private readonly DragablzItem _dragablzItem;\n        private readonly bool _isDropTargetFound;\n        private readonly DragCompletedEventArgs _dragCompletedEventArgs;\n\n        public DragablzDragCompletedEventArgs(DragablzItem dragablzItem, DragCompletedEventArgs dragCompletedEventArgs)\n        {\n            if (dragablzItem == null) throw new ArgumentNullException(\"dragablzItem\");\n            if (dragCompletedEventArgs == null) throw new ArgumentNullException(\"dragCompletedEventArgs\");\n            \n            _dragablzItem = dragablzItem;\n            _dragCompletedEventArgs = dragCompletedEventArgs;\n        }\n\n        public DragablzDragCompletedEventArgs(RoutedEvent routedEvent, DragablzItem dragablzItem, DragCompletedEventArgs dragCompletedEventArgs)\n            : base(routedEvent)\n        {\n            if (dragablzItem == null) throw new ArgumentNullException(\"dragablzItem\");\n            if (dragCompletedEventArgs == null) throw new ArgumentNullException(\"dragCompletedEventArgs\");\n\n            _dragablzItem = dragablzItem;            \n            _dragCompletedEventArgs = dragCompletedEventArgs;\n        }\n\n        public DragablzDragCompletedEventArgs(RoutedEvent routedEvent, object source, DragablzItem dragablzItem, DragCompletedEventArgs dragCompletedEventArgs)\n            : base(routedEvent, source)\n        {\n            if (dragablzItem == null) throw new ArgumentNullException(\"dragablzItem\");\n            if (dragCompletedEventArgs == null) throw new ArgumentNullException(\"dragCompletedEventArgs\");\n\n            _dragablzItem = dragablzItem;\n            _dragCompletedEventArgs = dragCompletedEventArgs;\n        }\n\n        public DragablzItem DragablzItem\n        {\n            get { return _dragablzItem; }\n        }\n\n        public DragCompletedEventArgs DragCompletedEventArgs\n        {\n            get { return _dragCompletedEventArgs; }\n        }        \n    }\n}"
  },
  {
    "path": "third_party/Dragablz/Dragablz/DragablzDragDeltaEventArgs.cs",
    "content": "using System;\nusing System.Windows;\nusing System.Windows.Controls.Primitives;\n\nnamespace Dragablz\n{\n    public delegate void DragablzDragDeltaEventHandler(object sender, DragablzDragDeltaEventArgs e);\n\n    public class DragablzDragDeltaEventArgs : DragablzItemEventArgs\n    {\n        private readonly DragDeltaEventArgs _dragDeltaEventArgs;\n\n        public DragablzDragDeltaEventArgs(DragablzItem dragablzItem, DragDeltaEventArgs dragDeltaEventArgs)\n            : base(dragablzItem)\n        {\n            if (dragDeltaEventArgs == null) throw new ArgumentNullException(\"dragDeltaEventArgs\");\n\n            _dragDeltaEventArgs = dragDeltaEventArgs;\n        }\n\n        public DragablzDragDeltaEventArgs(RoutedEvent routedEvent, DragablzItem dragablzItem, DragDeltaEventArgs dragDeltaEventArgs) \n            : base(routedEvent, dragablzItem)\n        {\n            if (dragDeltaEventArgs == null) throw new ArgumentNullException(\"dragDeltaEventArgs\");\n\n            _dragDeltaEventArgs = dragDeltaEventArgs;\n        }\n\n        public DragablzDragDeltaEventArgs(RoutedEvent routedEvent, object source, DragablzItem dragablzItem, DragDeltaEventArgs dragDeltaEventArgs) \n            : base(routedEvent, source, dragablzItem)\n        {\n            if (dragDeltaEventArgs == null) throw new ArgumentNullException(\"dragDeltaEventArgs\");\n\n            _dragDeltaEventArgs = dragDeltaEventArgs;\n        }\n\n        public DragDeltaEventArgs DragDeltaEventArgs\n        {\n            get { return _dragDeltaEventArgs; }\n        }\n\n        public bool Cancel { get; set; }        \n    }\n}"
  },
  {
    "path": "third_party/Dragablz/Dragablz/DragablzDragStartedEventArgs.cs",
    "content": "using System;\nusing System.Windows;\nusing System.Windows.Controls.Primitives;\n\nnamespace Dragablz\n{\n    public delegate void DragablzDragStartedEventHandler(object sender, DragablzDragStartedEventArgs e);\n\n    public class DragablzDragStartedEventArgs : DragablzItemEventArgs\n    {\n        private readonly DragStartedEventArgs _dragStartedEventArgs;\n\n        public DragablzDragStartedEventArgs(DragablzItem dragablzItem, DragStartedEventArgs dragStartedEventArgs)\n            : base(dragablzItem)\n        {\n            if (dragStartedEventArgs == null) throw new ArgumentNullException(\"dragStartedEventArgs\");\n\n            _dragStartedEventArgs = dragStartedEventArgs;\n        }\n\n        public DragablzDragStartedEventArgs(RoutedEvent routedEvent, DragablzItem dragablzItem, DragStartedEventArgs dragStartedEventArgs)\n            : base(routedEvent, dragablzItem)\n        {\n            _dragStartedEventArgs = dragStartedEventArgs;\n        }\n\n        public DragablzDragStartedEventArgs(RoutedEvent routedEvent, object source, DragablzItem dragablzItem, DragStartedEventArgs dragStartedEventArgs)\n            : base(routedEvent, source, dragablzItem)\n        {\n            _dragStartedEventArgs = dragStartedEventArgs;\n        }\n\n        public DragStartedEventArgs DragStartedEventArgs\n        {\n            get { return _dragStartedEventArgs; }\n        }        \n    }\n}"
  },
  {
    "path": "third_party/Dragablz/Dragablz/DragablzIcon.cs",
    "content": "﻿using System;\nusing System.Collections.Generic;\nusing System.Linq;\nusing System.Text;\nusing System.Threading.Tasks;\nusing System.Windows;\nusing System.Windows.Controls;\nusing System.Windows.Data;\nusing System.Windows.Documents;\nusing System.Windows.Input;\nusing System.Windows.Media;\nusing System.Windows.Media.Imaging;\nusing System.Windows.Navigation;\nusing System.Windows.Shapes;\n\nnamespace Dragablz\n{    \n    public class DragablzIcon : Control\n    {\n        static DragablzIcon()\n        {\n            DefaultStyleKeyProperty.OverrideMetadata(typeof(DragablzIcon), new FrameworkPropertyMetadata(typeof(DragablzIcon)));\n        }\n    }\n}\n"
  },
  {
    "path": "third_party/Dragablz/Dragablz/DragablzItem.cs",
    "content": "﻿using System;\nusing System.Dynamic;\nusing System.Linq;\nusing System.Windows;\nusing System.Windows.Controls;\nusing System.Windows.Controls.Primitives;\nusing System.Windows.Input;\nusing System.Windows.Threading;\nusing Dragablz.Core;\nusing Dragablz.Referenceless;\n\nnamespace Dragablz\n{\n    public enum SizeGrip\n    {\n        NotApplicable,\n        Left,\n        TopLeft,\n        Top,\n        TopRight,\n        Right,\n        BottomRight,\n        Bottom,\n        BottomLeft\n    }\n\n    [TemplatePart(Name = ThumbPartName, Type = typeof(Thumb))]\n    public class DragablzItem : ContentControl\n    {\n        public const string ThumbPartName = \"PART_Thumb\";\n\n        private readonly SerialDisposable _templateSubscriptions = new SerialDisposable();\n        private readonly SerialDisposable _rightMouseUpCleanUpDisposable = new SerialDisposable();\n\n        private Thumb _customThumb;\n        private Thumb _thumb;\n        private bool _seizeDragWithTemplate;\n        private Action<DragablzItem> _dragSeizedContinuation;\n\n        static DragablzItem()\n        {\n            DefaultStyleKeyProperty.OverrideMetadata(typeof(DragablzItem), new FrameworkPropertyMetadata(typeof(DragablzItem)));            \n        }\n\n        public DragablzItem()\n        {\n            AddHandler(MouseDownEvent, new RoutedEventHandler(MouseDownHandler), true);            \n        }\n\n        public static readonly DependencyProperty XProperty = DependencyProperty.Register(\n            \"X\", typeof (double), typeof (DragablzItem), new PropertyMetadata(default(double), OnXChanged));\n\n        public double X\n        {\n            get { return (double) GetValue(XProperty); }\n            set { SetValue(XProperty, value); }\n        }\n\n        public static readonly RoutedEvent XChangedEvent =\n            EventManager.RegisterRoutedEvent(\n                \"XChanged\",\n                RoutingStrategy.Bubble,\n                typeof(RoutedPropertyChangedEventHandler<double>),\n                typeof(DragablzItem));\n\n        public event RoutedPropertyChangedEventHandler<double> XChanged\n        {\n            add { AddHandler(XChangedEvent, value); }\n            remove { RemoveHandler(IsDraggingChangedEvent, value); }\n        }\n\n        private static void OnXChanged(\n            DependencyObject d, DependencyPropertyChangedEventArgs e)\n        {   \n            var instance = (DragablzItem)d;\n            var args = new RoutedPropertyChangedEventArgs<double>(\n                (double)e.OldValue,\n                (double)e.NewValue)\n            {\n                RoutedEvent = XChangedEvent\n            };\n            instance.RaiseEvent(args);            \n        } \n\n        public static readonly DependencyProperty YProperty = DependencyProperty.Register(\n            \"Y\", typeof (double), typeof (DragablzItem), new PropertyMetadata(default(double), OnYChanged));\n\n        public double Y\n        {\n            get { return (double) GetValue(YProperty); }\n            set { SetValue(YProperty, value); }\n        }\n\n        public static readonly RoutedEvent YChangedEvent =\n            EventManager.RegisterRoutedEvent(\n                \"YChanged\",\n                RoutingStrategy.Bubble,\n                typeof(RoutedPropertyChangedEventHandler<double>),\n                typeof(DragablzItem));\n\n        public event RoutedPropertyChangedEventHandler<double> YChanged\n        {\n            add { AddHandler(YChangedEvent, value); }\n            remove { RemoveHandler(IsDraggingChangedEvent, value); }\n        }\n\n        private static void OnYChanged(\n            DependencyObject d, DependencyPropertyChangedEventArgs e)\n        {\n            var instance = (DragablzItem)d;\n            var args = new RoutedPropertyChangedEventArgs<double>(\n                (double)e.OldValue,\n                (double)e.NewValue)\n            {\n                RoutedEvent = YChangedEvent\n            };\n            instance.RaiseEvent(args);\n        }\n\n        private static readonly DependencyPropertyKey LogicalIndexPropertyKey =\n            DependencyProperty.RegisterReadOnly(\n                \"LogicalIndex\", typeof (int), typeof (DragablzItem),\n                new PropertyMetadata(default(int), OnLogicalIndexChanged));\n\n        public static readonly DependencyProperty LogicalIndexProperty =\n            LogicalIndexPropertyKey.DependencyProperty;\n\n        public int LogicalIndex\n        {\n            get { return (int) GetValue(LogicalIndexProperty); }\n            internal set { SetValue(LogicalIndexPropertyKey, value); }\n        }\n\n        public static readonly RoutedEvent LogicalIndexChangedEvent =\n            EventManager.RegisterRoutedEvent(\n                \"LogicalIndexChanged\",\n                RoutingStrategy.Bubble,\n                typeof (RoutedPropertyChangedEventHandler<int>),\n                typeof (DragablzItem));\n\n        public event RoutedPropertyChangedEventHandler<int> LogicalIndexChanged\n        {\n            add { AddHandler(LogicalIndexChangedEvent, value); }\n            remove { RemoveHandler(LogicalIndexChangedEvent, value); }\n        }\n\n        private static void OnLogicalIndexChanged(\n            DependencyObject d, DependencyPropertyChangedEventArgs e)\n        {\n            var instance = (DragablzItem) d;\n            var args = new RoutedPropertyChangedEventArgs<int>(\n                (int) e.OldValue,\n                (int) e.NewValue)\n            {\n                RoutedEvent = DragablzItem.LogicalIndexChangedEvent\n            };\n            instance.RaiseEvent(args);\n        } \n\n        public static readonly DependencyProperty SizeGripProperty = DependencyProperty.RegisterAttached(\n            \"SizeGrip\", typeof (SizeGrip), typeof (DragablzItem), new PropertyMetadata(default(SizeGrip), SizeGripPropertyChangedCallback));\n\n        private static void SizeGripPropertyChangedCallback(DependencyObject dependencyObject, DependencyPropertyChangedEventArgs dependencyPropertyChangedEventArgs)\n        {\n            var thumb = (dependencyObject as Thumb);\n            if (thumb == null) return;\n            thumb.DragDelta += SizeThumbOnDragDelta;\n        }\n\n        private static void SizeThumbOnDragDelta(object sender, DragDeltaEventArgs dragDeltaEventArgs)\n        {\n            var thumb = ((Thumb) sender);\n            var dragablzItem = thumb.VisualTreeAncestory().OfType<DragablzItem>().FirstOrDefault();\n            if (dragablzItem == null) return;\n\n            var sizeGrip = (SizeGrip) thumb.GetValue(SizeGripProperty);\n            var width = dragablzItem.ActualWidth;\n            var height = dragablzItem.ActualHeight;\n            var x = dragablzItem.X;\n            var y = dragablzItem.Y;\n            switch (sizeGrip)\n            {                                   \n                case SizeGrip.NotApplicable:\n                    break;\n                case SizeGrip.Left:\n                    width += -dragDeltaEventArgs.HorizontalChange;\n                    x += dragDeltaEventArgs.HorizontalChange;\n                    break;\n                case SizeGrip.TopLeft:\n                    width += -dragDeltaEventArgs.HorizontalChange;\n                    height += -dragDeltaEventArgs.VerticalChange;\n                    x += dragDeltaEventArgs.HorizontalChange;\n                    y += dragDeltaEventArgs.VerticalChange;\n                    break;\n                case SizeGrip.Top:\n                    height += -dragDeltaEventArgs.VerticalChange;                    \n                    y += dragDeltaEventArgs.VerticalChange;\n                    break;\n                case SizeGrip.TopRight:\n                    height += -dragDeltaEventArgs.VerticalChange;\n                    width += dragDeltaEventArgs.HorizontalChange;\n                    y += dragDeltaEventArgs.VerticalChange;\n                    break;\n                case SizeGrip.Right:\n                    width += dragDeltaEventArgs.HorizontalChange;\n                    break;\n                case SizeGrip.BottomRight:\n                    width += dragDeltaEventArgs.HorizontalChange;\n                    height += dragDeltaEventArgs.VerticalChange;\n                    break;\n                case SizeGrip.Bottom:\n                    height += dragDeltaEventArgs.VerticalChange;\n                    break;\n                case SizeGrip.BottomLeft:\n                    height += dragDeltaEventArgs.VerticalChange;\n                    width += -dragDeltaEventArgs.HorizontalChange;\n                    x += dragDeltaEventArgs.HorizontalChange;\n                    break;\n                default:\n                    throw new ArgumentOutOfRangeException();\n            }\n            dragablzItem.SetCurrentValue(XProperty, x);\n            dragablzItem.SetCurrentValue(YProperty, y);\n            dragablzItem.SetCurrentValue(WidthProperty, Math.Max(width, thumb.DesiredSize.Width));\n            dragablzItem.SetCurrentValue(HeightProperty, Math.Max(height, thumb.DesiredSize.Height));\n        }\n\n        public static void SetSizeGrip(DependencyObject element, SizeGrip value)\n        {\n            element.SetValue(SizeGripProperty, value);\n        }\n\n        public static SizeGrip GetSizeGrip(DependencyObject element)\n        {\n            return (SizeGrip) element.GetValue(SizeGripProperty);\n        }\n\n        /// <summary>\n        /// Allows item content to be rotated (in suppported templates), typically for use in a vertical/side tab.\n        /// </summary>\n        public static readonly DependencyProperty ContentRotateTransformAngleProperty = DependencyProperty.RegisterAttached(\n            \"ContentRotateTransformAngle\", typeof (double), typeof (DragablzItem), new FrameworkPropertyMetadata(default(double), FrameworkPropertyMetadataOptions.Inherits));\n\n        /// <summary>\n        /// Allows item content to be rotated (in suppported templates), typically for use in a vertical/side tab.\n        /// </summary>\n        /// <param name=\"element\"></param>\n        /// <param name=\"value\"></param>\n        public static void SetContentRotateTransformAngle(DependencyObject element, double value)\n        {\n            element.SetValue(ContentRotateTransformAngleProperty, value);\n        }\n\n        /// <summary>\n        /// Allows item content to be rotated (in suppported templates), typically for use in a vertical/side tab.\n        /// </summary>\n        /// <param name=\"element\"></param>\n        /// <returns></returns>\n        public static double GetContentRotateTransformAngle(DependencyObject element)\n        {\n            return (double) element.GetValue(ContentRotateTransformAngleProperty);\n        }\n\n        public static readonly DependencyProperty IsSelectedProperty = DependencyProperty.Register(\n            \"IsSelected\", typeof(bool), typeof(DragablzItem), new FrameworkPropertyMetadata(false, FrameworkPropertyMetadataOptions.BindsTwoWayByDefault | FrameworkPropertyMetadataOptions.AffectsParentMeasure));\n\n        public bool IsSelected\n        {\n            get { return (bool) GetValue(IsSelectedProperty); }\n            set { SetValue(IsSelectedProperty, value); }\n        }\n\n        private static readonly DependencyPropertyKey IsDraggingPropertyKey =\n            DependencyProperty.RegisterReadOnly(\n                \"IsDragging\", typeof (bool), typeof (DragablzItem),\n                new PropertyMetadata(default(bool), OnIsDraggingChanged));\n\n        public static readonly DependencyProperty IsDraggingProperty =\n            IsDraggingPropertyKey.DependencyProperty;\n\n        public bool IsDragging\n        {\n            get { return (bool) GetValue(IsDraggingProperty); }\n            internal set { SetValue(IsDraggingPropertyKey, value); }\n        }\n\n        public static readonly RoutedEvent IsDraggingChangedEvent =\n            EventManager.RegisterRoutedEvent(\n                \"IsDraggingChanged\",\n                RoutingStrategy.Bubble,\n                typeof (RoutedPropertyChangedEventHandler<bool>),\n                typeof (DragablzItem));\n\n        public event RoutedPropertyChangedEventHandler<bool> IsDraggingChanged\n        {\n            add { AddHandler(IsDraggingChangedEvent, value); }\n            remove { RemoveHandler(IsDraggingChangedEvent, value); }\n        }\n\n        internal object UnderlyingContent { get; set; }\n\n        private static void OnIsDraggingChanged(\n            DependencyObject d, DependencyPropertyChangedEventArgs e)\n        {\n            var instance = (DragablzItem)d;\n            var args = new RoutedPropertyChangedEventArgs<bool>(\n                (bool)e.OldValue,\n                (bool)e.NewValue) { RoutedEvent = IsDraggingChangedEvent };\n            instance.RaiseEvent(args);\n        }\n\n        public static readonly RoutedEvent MouseDownWithinEvent =\n            EventManager.RegisterRoutedEvent(\n                \"MouseDownWithin\",\n                RoutingStrategy.Bubble,\n                typeof(DragablzItemEventHandler),\n                typeof (DragablzItem));\n\n        private static void OnMouseDownWithin(DependencyObject d)\n        {\n            var instance = (DragablzItem)d;\n            instance.RaiseEvent(new DragablzItemEventArgs(MouseDownWithinEvent, instance));\n        }\n\n        private static readonly DependencyPropertyKey IsSiblingDraggingPropertyKey =\n            DependencyProperty.RegisterReadOnly(\n                \"IsSiblingDragging\", typeof (bool), typeof (DragablzItem),\n                new PropertyMetadata(default(bool), OnIsSiblingDraggingChanged));\n\n        public static readonly DependencyProperty IsSiblingDraggingProperty =\n            IsSiblingDraggingPropertyKey.DependencyProperty;\n\n        public bool IsSiblingDragging\n        {\n            get { return (bool) GetValue(IsSiblingDraggingProperty); }\n            internal set { SetValue(IsSiblingDraggingPropertyKey, value); }\n        }\n\n        public static readonly RoutedEvent IsSiblingDraggingChangedEvent =\n            EventManager.RegisterRoutedEvent(\n                \"IsSiblingDraggingChanged\",\n                RoutingStrategy.Bubble,\n                typeof (RoutedPropertyChangedEventHandler<bool>),\n                typeof (DragablzItem));\n\n        public event RoutedPropertyChangedEventHandler<bool> IsSiblingDraggingChanged\n        {\n            add { AddHandler(IsSiblingDraggingChangedEvent, value); }\n            remove { RemoveHandler(IsSiblingDraggingChangedEvent, value); }\n        }\n\n        private static void OnIsSiblingDraggingChanged(\n            DependencyObject d, DependencyPropertyChangedEventArgs e)\n        {\n            var instance = (DragablzItem) d;\n            var args = new RoutedPropertyChangedEventArgs<bool>(\n                (bool) e.OldValue,\n                (bool) e.NewValue)\n            {\n                RoutedEvent = IsSiblingDraggingChangedEvent\n            };\n            instance.RaiseEvent(args);\n        }         \n\n        public static readonly RoutedEvent DragStarted =\n            EventManager.RegisterRoutedEvent(\n                \"DragStarted\",\n                RoutingStrategy.Bubble,\n                typeof(DragablzDragStartedEventHandler),\n                typeof(DragablzItem));\n\n        protected void OnDragStarted(DragablzDragStartedEventArgs e)\n        {            \n            RaiseEvent(e);\n        }\n\n        public static readonly RoutedEvent DragDelta =\n            EventManager.RegisterRoutedEvent(\n                \"DragDelta\",\n                RoutingStrategy.Bubble,\n                typeof (DragablzDragDeltaEventHandler),\n                typeof (DragablzItem));\n\n        protected void OnDragDelta(DragablzDragDeltaEventArgs e)\n        {            \n            RaiseEvent(e);            \n        }\n\n        public static readonly RoutedEvent PreviewDragDelta =\n            EventManager.RegisterRoutedEvent(\n                \"PreviewDragDelta\",\n                RoutingStrategy.Tunnel,\n                typeof(DragablzDragDeltaEventHandler),\n                typeof(DragablzItem));\n\n        protected void OnPreviewDragDelta(DragablzDragDeltaEventArgs e)\n        {            \n            RaiseEvent(e);\n        }\n\n        public static readonly RoutedEvent DragCompleted =\n            EventManager.RegisterRoutedEvent(\n                \"DragCompleted\",\n                RoutingStrategy.Bubble,\n                typeof(DragablzDragCompletedEventHandler),\n                typeof(DragablzItem));\n\n        protected void OnDragCompleted(DragCompletedEventArgs e)\n        {\n            var args = new DragablzDragCompletedEventArgs(DragCompleted, this, e);\n            RaiseEvent(args);\n\n            //OK, this is a cheeky bit.  A completed drag may have occured after a tab as been pushed\n            //intom a new window, which means we may have reverted to the template thumb.  So, let's\n            //refresh the thumb in case the user has a custom one\n            _customThumb = FindCustomThumb();\n            _templateSubscriptions.Disposable = SelectAndSubscribeToThumb().Item2;\n        }\n\n        /// <summary>\n        /// <see cref=\"DragablzItem\" /> templates contain a thumb, which is used to drag the item around.\n        /// For most scenarios this is fine, but by setting this flag to <value>true</value> you can define\n        /// a custom thumb in your content, without having to override the template.  This can be useful if you\n        /// have extra content; such as a custom button that you want the user to be able to interact with (as usually\n        /// the default thumb will handle mouse interaction).\n        /// </summary>\n        public static readonly DependencyProperty IsCustomThumbProperty = DependencyProperty.RegisterAttached(\n            \"IsCustomThumb\", typeof (bool), typeof (DragablzItem), new PropertyMetadata(default(bool), IsCustomThumbPropertyChangedCallback));\n\n        private static void IsCustomThumbPropertyChangedCallback(DependencyObject dependencyObject, DependencyPropertyChangedEventArgs dependencyPropertyChangedEventArgs)\n        {\n            var thumb = dependencyObject as Thumb;\n            if (thumb == null) throw new ApplicationException(\"IsCustomThumb can only be applied to a thumb\");\n\n            if (thumb.IsLoaded)\n                ApplyCustomThumbSetting(thumb);\n            else\n                thumb.Loaded += CustomThumbOnLoaded;\n        }        \n\n        /// <summary>\n        /// <see cref=\"DragablzItem\" /> templates contain a thumb, which is used to drag the item around.\n        /// For most scenarios this is fine, but by setting this flag to <value>true</value> you can define\n        /// a custom thumb in your content, without having to override the template.  This can be useful if you\n        /// have extra content; such as a custom button that you want the user to be able to interact with (as usually\n        /// the default thumb will handle mouse interaction).\n        /// </summary>\n        public static void SetIsCustomThumb(Thumb element, bool value)\n        {\n            element.SetValue(IsCustomThumbProperty, value);\n        }\n\n        public static bool GetIsCustomThumb(Thumb element)\n        {\n            return (bool) element.GetValue(IsCustomThumbProperty);\n        }\n\n        private bool _isTemplateThumbWithMouseAfterSeize = false;\n        public override void OnApplyTemplate()\n        {\n            base.OnApplyTemplate();                        \n            \n            var thumbAndSubscription = SelectAndSubscribeToThumb();\n            _templateSubscriptions.Disposable = thumbAndSubscription.Item2;\n            \n            if (_seizeDragWithTemplate && thumbAndSubscription.Item1 != null)\n            {\n                _isTemplateThumbWithMouseAfterSeize = true;\n                Mouse.AddLostMouseCaptureHandler(this, LostMouseAfterSeizeHandler);\n                if (_dragSeizedContinuation != null)\n                    _dragSeizedContinuation(this);\n                _dragSeizedContinuation = null;\n\n                Dispatcher.BeginInvoke(new Action(() => thumbAndSubscription.Item1.RaiseEvent(new MouseButtonEventArgs(InputManager.Current.PrimaryMouseDevice,\n                    0,\n                    MouseButton.Left) {RoutedEvent = MouseLeftButtonDownEvent})));\n            }\n            _seizeDragWithTemplate = false;\n        }\n\n        protected override void OnPreviewMouseRightButtonDown(MouseButtonEventArgs e)\n        {            \n            if (_thumb != null)\n            {\n                var currentThumbIsHitTestVisible = _thumb.IsHitTestVisible;\n                _thumb.SetCurrentValue(IsHitTestVisibleProperty, false);\n                _rightMouseUpCleanUpDisposable.Disposable = Disposable.Create(() =>\n                {\n                    _thumb.SetCurrentValue(IsHitTestVisibleProperty, currentThumbIsHitTestVisible);\n                });\n            }\n            else\n            {\n                _rightMouseUpCleanUpDisposable.Disposable = Disposable.Empty;\n            }            \n            \n            base.OnPreviewMouseRightButtonDown(e);\n        }\n\n        protected override void OnPreviewMouseRightButtonUp(MouseButtonEventArgs e)\n        {\n            _rightMouseUpCleanUpDisposable.Disposable = Disposable.Empty;\n            base.OnPreviewMouseRightButtonUp(e);\n        }\n\n        private void LostMouseAfterSeizeHandler(object sender, MouseEventArgs mouseEventArgs)\n        {\n            _isTemplateThumbWithMouseAfterSeize = false;\n            Mouse.RemoveLostMouseCaptureHandler(this, LostMouseAfterSeizeHandler);\n        }\n\n        internal void InstigateDrag(Action<DragablzItem> continuation)\n        {\n            _dragSeizedContinuation = continuation;\n            var thumb = GetTemplateChild(ThumbPartName) as Thumb;\n            if (thumb != null)\n            {\n                thumb.CaptureMouse();             \n            }\n            else\n                _seizeDragWithTemplate = true;\n        }\n\n        internal Point MouseAtDragStart { get; set; }\n\n        internal string PartitionAtDragStart { get; set; }\n\n        internal bool IsDropTargetFound { get; set; }\n\n        private void ThumbOnDragCompleted(object sender, DragCompletedEventArgs dragCompletedEventArgs)\n        {            \n            OnDragCompleted(dragCompletedEventArgs);\n            MouseAtDragStart = new Point();\n        }        \n\n        private void ThumbOnDragDelta(object sender, DragDeltaEventArgs dragDeltaEventArgs)\n        {\n            var thumb = (Thumb) sender;\n\n            var previewEventArgs = new DragablzDragDeltaEventArgs(PreviewDragDelta, this, dragDeltaEventArgs);\n            OnPreviewDragDelta(previewEventArgs);            \n            if (previewEventArgs.Cancel)\n                thumb.CancelDrag();\n            if (!previewEventArgs.Handled)\n            {\n                var eventArgs = new DragablzDragDeltaEventArgs(DragDelta, this, dragDeltaEventArgs);\n                OnDragDelta(eventArgs);\n                if (eventArgs.Cancel)\n                    thumb.CancelDrag();\n            }\n        }\n        \n        private void ThumbOnDragStarted(object sender, DragStartedEventArgs dragStartedEventArgs)\n        {\n            MouseAtDragStart = Mouse.GetPosition(this);\n            OnDragStarted(new DragablzDragStartedEventArgs(DragStarted, this, dragStartedEventArgs));            \n        }\n\n        private void MouseDownHandler(object sender, RoutedEventArgs routedEventArgs)\n        {\n            OnMouseDownWithin(this);\n        }\n\n        private static void CustomThumbOnLoaded(object sender, RoutedEventArgs routedEventArgs)\n        {\n            var thumb = (Thumb)sender;\n            thumb.Loaded -= CustomThumbOnLoaded;\n            ApplyCustomThumbSetting(thumb);\n        }\n\n        private Thumb FindCustomThumb()\n        {\n            return this.VisualTreeDepthFirstTraversal().OfType<Thumb>().FirstOrDefault(GetIsCustomThumb);\n        }        \n\n        private static void ApplyCustomThumbSetting(Thumb thumb)\n        {            \n            var dragablzItem = thumb.VisualTreeAncestory().OfType<DragablzItem>().FirstOrDefault();\n            if (dragablzItem == null) throw new ApplicationException(\"Cannot find parent DragablzItem for custom thumb\");\n\n            var enableCustomThumb = (bool)thumb.GetValue(IsCustomThumbProperty);\n            dragablzItem._customThumb = enableCustomThumb ? thumb : null;\n            dragablzItem._templateSubscriptions.Disposable = dragablzItem.SelectAndSubscribeToThumb().Item2;\n\n            if (dragablzItem._customThumb != null && dragablzItem._isTemplateThumbWithMouseAfterSeize)\n                dragablzItem.Dispatcher.BeginInvoke(new Action(() => dragablzItem._customThumb.RaiseEvent(new MouseButtonEventArgs(InputManager.Current.PrimaryMouseDevice,\n                        0,\n                        MouseButton.Left) { RoutedEvent = MouseLeftButtonDownEvent })));\n        }\n\n        private Tuple<Thumb, IDisposable> SelectAndSubscribeToThumb()\n        {\n            var templateThumb = GetTemplateChild(ThumbPartName) as Thumb;\n            templateThumb?.SetCurrentValue(IsHitTestVisibleProperty, _customThumb == null);\n            \n            _thumb = _customThumb ?? templateThumb;\n            if (_thumb != null)\n            {\n                _thumb.DragStarted += ThumbOnDragStarted;\n                _thumb.DragDelta += ThumbOnDragDelta;\n                _thumb.DragCompleted += ThumbOnDragCompleted;\n            }\n\n            var tidyUpThumb = _thumb;\n            var disposable = Disposable.Create(() =>\n            {\n                if (tidyUpThumb == null) return;\n                tidyUpThumb.DragStarted -= ThumbOnDragStarted;\n                tidyUpThumb.DragDelta -= ThumbOnDragDelta;\n                tidyUpThumb.DragCompleted -= ThumbOnDragCompleted;\n            });\n\n            return new Tuple<Thumb, IDisposable>(_thumb, disposable);\n        }\n    }\n}"
  },
  {
    "path": "third_party/Dragablz/Dragablz/DragablzItemEventArgs.cs",
    "content": "using System;\nusing System.Windows;\nusing System.Windows.Controls.Primitives;\n\nnamespace Dragablz\n{\n    public delegate void DragablzItemEventHandler(object sender, DragablzItemEventArgs e);\n\n    public class DragablzItemEventArgs : RoutedEventArgs\n    {\n        private readonly DragablzItem _dragablzItem;\n\n        public DragablzItemEventArgs(DragablzItem dragablzItem)\n        {\n            if (dragablzItem == null) throw new ArgumentNullException(\"dragablzItem\");            \n\n            _dragablzItem = dragablzItem;\n        }\n\n        public DragablzItemEventArgs(RoutedEvent routedEvent, DragablzItem dragablzItem)\n            : base(routedEvent)\n        {\n            _dragablzItem = dragablzItem;\n        }\n\n        public DragablzItemEventArgs(RoutedEvent routedEvent, object source, DragablzItem dragablzItem)\n            : base(routedEvent, source)\n        {\n            _dragablzItem = dragablzItem;\n        }\n\n        public DragablzItem DragablzItem\n        {\n            get { return _dragablzItem; }\n        }\n    }\n}"
  },
  {
    "path": "third_party/Dragablz/Dragablz/DragablzItemsControl.cs",
    "content": "﻿using System;\nusing System.Collections;\nusing System.Collections.Generic;\nusing System.Linq;\nusing System.Windows;\nusing System.Windows.Controls;\nusing System.Windows.Controls.Primitives;\nusing System.Windows.Data;\nusing System.Windows.Threading;\nusing Dragablz.Core;\n\nnamespace Dragablz\n{\n    /// <summary>\n    /// Items control which typically uses a canvas and \n    /// </summary>\n    public class DragablzItemsControl : ItemsControl\n    {        \n        private object[] _previousSortQueryResult;\n\n        static DragablzItemsControl()\n        {\n            DefaultStyleKeyProperty.OverrideMetadata(typeof(DragablzItemsControl), new FrameworkPropertyMetadata(typeof(DragablzItemsControl)));            \n        }        \n\n        public DragablzItemsControl()\n        {            \n            ItemContainerGenerator.StatusChanged += ItemContainerGeneratorOnStatusChanged;\n            ItemContainerGenerator.ItemsChanged += ItemContainerGeneratorOnItemsChanged;\n            AddHandler(DragablzItem.XChangedEvent, new RoutedPropertyChangedEventHandler<double>(ItemXChanged));\n            AddHandler(DragablzItem.YChangedEvent, new RoutedPropertyChangedEventHandler<double>(ItemYChanged));\n            AddHandler(DragablzItem.DragDelta, new DragablzDragDeltaEventHandler(ItemDragDelta));\n            AddHandler(DragablzItem.DragCompleted, new DragablzDragCompletedEventHandler(ItemDragCompleted));\n            AddHandler(DragablzItem.DragStarted, new DragablzDragStartedEventHandler(ItemDragStarted));\n            AddHandler(DragablzItem.MouseDownWithinEvent, new DragablzItemEventHandler(ItemMouseDownWithinHandlerTarget));                        \n        }\n\n        public static readonly DependencyProperty FixedItemCountProperty = DependencyProperty.Register(\n            \"FixedItemCount\", typeof (int), typeof (DragablzItemsControl), new PropertyMetadata(default(int)));\n\n        public int FixedItemCount\n        {\n            get { return (int) GetValue(FixedItemCountProperty); }\n            set { SetValue(FixedItemCountProperty, value); }\n        }\n\n        private void ItemContainerGeneratorOnItemsChanged(object sender, ItemsChangedEventArgs itemsChangedEventArgs)\n        {\n            //throw new NotImplementedException();\n        }\n\n        protected override void ClearContainerForItemOverride(DependencyObject element, object item)\n        {\n            if (ContainerCustomisations != null && ContainerCustomisations.ClearingContainerForItemOverride != null)\n                ContainerCustomisations.ClearingContainerForItemOverride(element, item);            \n\n            base.ClearContainerForItemOverride(element, item);\n\n            ((DragablzItem)element).SizeChanged -= ItemSizeChangedEventHandler;\n\n            Dispatcher.BeginInvoke(new Action(() =>\n            {\n                var dragablzItems = DragablzItems().ToList();\n                if (ItemsOrganiser == null) return;\n                ItemsOrganiser.Organise(this, new Size(ItemsPresenterWidth, ItemsPresenterHeight), dragablzItems);\n                var measure = ItemsOrganiser.Measure(this, new Size(ActualWidth, ActualHeight), dragablzItems);\n                ItemsPresenterWidth = measure.Width;\n                ItemsPresenterHeight = measure.Height;\n            }), DispatcherPriority.Input);            \n        }        \n\n        public static readonly DependencyProperty ItemsOrganiserProperty = DependencyProperty.Register(\n            \"ItemsOrganiser\", typeof (IItemsOrganiser), typeof (DragablzItemsControl), new PropertyMetadata(default(IItemsOrganiser)));\n\n        public IItemsOrganiser ItemsOrganiser\n        {\n            get { return (IItemsOrganiser) GetValue(ItemsOrganiserProperty); }\n            set { SetValue(ItemsOrganiserProperty, value); }\n        }\n\n        public static readonly DependencyProperty PositionMonitorProperty = DependencyProperty.Register(\n            \"PositionMonitor\", typeof (PositionMonitor), typeof (DragablzItemsControl), new PropertyMetadata(default(PositionMonitor)));\n\n        public PositionMonitor PositionMonitor\n        {\n            get { return (PositionMonitor) GetValue(PositionMonitorProperty); }\n            set { SetValue(PositionMonitorProperty, value); }\n        }\n\n        private static readonly DependencyPropertyKey ItemsPresenterWidthPropertyKey =\n            DependencyProperty.RegisterReadOnly(\n                \"ItemsPresenterWidth\", typeof(double), typeof (DragablzItemsControl),\n                new PropertyMetadata(default(double)));\n\n        public static readonly DependencyProperty ItemsPresenterWidthProperty =\n            ItemsPresenterWidthPropertyKey.DependencyProperty;\n\n        public double ItemsPresenterWidth\n        {\n            get { return (double) GetValue(ItemsPresenterWidthProperty); }\n            private set { SetValue(ItemsPresenterWidthPropertyKey, value); }\n        }\n\n        private static readonly DependencyPropertyKey ItemsPresenterHeightPropertyKey =\n            DependencyProperty.RegisterReadOnly(\n                \"ItemsPresenterHeight\", typeof (double), typeof (DragablzItemsControl),\n                new PropertyMetadata(default(double)));\n\n        public static readonly DependencyProperty ItemsPresenterHeightProperty =\n            ItemsPresenterHeightPropertyKey.DependencyProperty;\n\n        public double ItemsPresenterHeight\n        {\n            get { return (double) GetValue(ItemsPresenterHeightProperty); }\n            private set { SetValue(ItemsPresenterHeightPropertyKey, value); }\n        }\n\n        /// <summary>\n        /// Adds an item to the underlying source, displaying in a specific position in rendered control.\n        /// </summary>\n        /// <param name=\"item\"></param>\n        /// <param name=\"addLocationHint\"></param>\n        public void AddToSource(object item, AddLocationHint addLocationHint)\n        {\n            AddToSource(item, null, addLocationHint);\n        }\n\n        /// <summary>\n        /// Adds an item to the underlying source, displaying in a specific position in rendered control.\n        /// </summary>\n        /// <param name=\"item\"></param>\n        /// <param name=\"nearItem\"></param>\n        /// <param name=\"addLocationHint\"></param>\n        public void AddToSource(object item, object nearItem, AddLocationHint addLocationHint)\n        {\n            CollectionTeaser collectionTeaser;\n            if (CollectionTeaser.TryCreate(ItemsSource, out collectionTeaser))\n                collectionTeaser.Add(item);\n            else\n                Items.Add(item);\n            MoveItem(new MoveItemRequest(item, nearItem, addLocationHint));\n        }\n\n        internal ContainerCustomisations ContainerCustomisations { get; set; }\n\n        private void ItemContainerGeneratorOnStatusChanged(object sender, EventArgs eventArgs)\n        {            \n            if (ItemContainerGenerator.Status != GeneratorStatus.ContainersGenerated) return;\n\n            InvalidateMeasure();\n            //extra kick\n            Dispatcher.BeginInvoke(new Action(InvalidateMeasure), DispatcherPriority.Loaded);\n        }\n\n        protected override bool IsItemItsOwnContainerOverride(object item)\n        {            \n            var dragablzItem = item as DragablzItem;\n            if (dragablzItem == null) return false;\n            \n            return true;\n        }\n\n        protected override DependencyObject GetContainerForItemOverride()\n        {\n            var result = ContainerCustomisations != null && ContainerCustomisations.GetContainerForItemOverride != null\n                ? ContainerCustomisations.GetContainerForItemOverride()\n                : new DragablzItem();\n\n            result.SizeChanged += ItemSizeChangedEventHandler;\n\n            return result;\n        }\n\n        protected override void PrepareContainerForItemOverride(DependencyObject element, object item)\n        {\n            if (ContainerCustomisations != null && ContainerCustomisations.PrepareContainerForItemOverride != null)\n                ContainerCustomisations.PrepareContainerForItemOverride(element, item);\n\n            base.PrepareContainerForItemOverride(element, item);\n        }\n\n        protected override Size MeasureOverride(Size constraint)        \n        {\n            if (ItemsOrganiser == null) return base.MeasureOverride(constraint);\n\n            if (LockedMeasure.HasValue)\n            {\n                ItemsPresenterWidth = LockedMeasure.Value.Width;\n                ItemsPresenterHeight = LockedMeasure.Value.Height;\n                return LockedMeasure.Value;\n            }\n\n            var dragablzItems = DragablzItems().ToList();            \n            var maxConstraint = new Size(double.PositiveInfinity, double.PositiveInfinity);\n\n            ItemsOrganiser.Organise(this, maxConstraint, dragablzItems);\n            var measure = ItemsOrganiser.Measure(this, new Size(ActualWidth, ActualHeight), dragablzItems);\n\n            ItemsPresenterWidth = measure.Width;\n            ItemsPresenterHeight = measure.Height;                          \n\n            var width = double.IsInfinity(constraint.Width) ? measure.Width : constraint.Width;\n            var height = double.IsInfinity(constraint.Height) ? measure.Height : constraint.Height;\n\n            return new Size(width, height);\n        }\n\n        internal void InstigateDrag(object item, Action<DragablzItem> continuation)\n        {   \n            var dragablzItem = (DragablzItem)ItemContainerGenerator.ContainerFromItem(item);            \n            dragablzItem.InstigateDrag(continuation);            \n        }\n\n        /// <summary>\n        /// Move an item in the rendered layout.\n        /// </summary>\n        /// <param name=\"moveItemRequest\"></param>\n        public void MoveItem(MoveItemRequest moveItemRequest)\n        {\n            if (moveItemRequest == null) throw new ArgumentNullException(\"moveItemRequest\");\n\n            if (ItemsOrganiser == null) return;\n\n            var dragablzItem = moveItemRequest.Item as DragablzItem ??\n                               ItemContainerGenerator.ContainerFromItem(\n                                   moveItemRequest.Item) as DragablzItem;\n            var contextDragablzItem = moveItemRequest.Context as DragablzItem ??\n                               ItemContainerGenerator.ContainerFromItem(\n                                   moveItemRequest.Context) as DragablzItem;\n\n            if (dragablzItem == null) return;\n\n            var sortedItems = DragablzItems().OrderBy(di => di.LogicalIndex).ToList();\n            sortedItems.Remove(dragablzItem);\n                \n            switch (moveItemRequest.AddLocationHint)\n            {\n                case AddLocationHint.First:\n                    sortedItems.Insert(0, dragablzItem);                        \n                    break;\n                case AddLocationHint.Last:\n                    sortedItems.Add(dragablzItem);\n                    break;\n                case AddLocationHint.Prior:\n                case AddLocationHint.After:\n                    if (contextDragablzItem == null)\n                        return;\n\n                    var contextIndex = sortedItems.IndexOf(contextDragablzItem);\n                    sortedItems.Insert(moveItemRequest.AddLocationHint == AddLocationHint.Prior ? contextIndex : contextIndex + 1, dragablzItem);\n\n                    break;\n                default:\n                    throw new ArgumentOutOfRangeException();\n            }            \n\n            //TODO might not be too great for perf on larger lists\n            var orderedEnumerable = sortedItems.OrderBy(di => sortedItems.IndexOf(di));\n\n            ItemsOrganiser.Organise(this, new Size(ItemsPresenterWidth, ItemsPresenterHeight), orderedEnumerable);\n        }        \n\n        internal IEnumerable<DragablzItem> DragablzItems()\n        {\n            return this.Containers<DragablzItem>().ToList();            \n        }\n\n        internal Size? LockedMeasure { get; set; }\n\n        private void ItemDragStarted(object sender, DragablzDragStartedEventArgs eventArgs)\n        {            \n            if (ItemsOrganiser != null)\n            {\n                var bounds = new Size(ActualWidth, ActualHeight);\n                ItemsOrganiser.OrganiseOnDragStarted(this, bounds,\n                    DragablzItems().Except(new[] { eventArgs.DragablzItem }).ToList(),\n                    eventArgs.DragablzItem);\n            }\n\n            eventArgs.Handled = true;\n\n            Dispatcher.BeginInvoke(new Action(InvalidateMeasure), DispatcherPriority.Loaded);\n        }\n\n        private void ItemDragCompleted(object sender, DragablzDragCompletedEventArgs eventArgs)\n        {\n            var dragablzItems = DragablzItems()\n                .Select(i =>\n                {\n                    i.IsDragging = false;\n                    i.IsSiblingDragging = false;\n                    return i;\n                })\n                .ToList();\n\n            if (ItemsOrganiser != null)\n            {\n                var bounds = new Size(ActualWidth, ActualHeight);\n                ItemsOrganiser.OrganiseOnDragCompleted(this, bounds,\n                    dragablzItems.Except(eventArgs.DragablzItem),\n                    eventArgs.DragablzItem);\n            }            \n\n            eventArgs.Handled = true;\n\n            //wowsers\n            Dispatcher.BeginInvoke(new Action(InvalidateMeasure));\n            Dispatcher.BeginInvoke(new Action(InvalidateMeasure), DispatcherPriority.Loaded);\n        }\n\n        private void ItemDragDelta(object sender, DragablzDragDeltaEventArgs eventArgs)\n        {\n            var bounds = new Size(ItemsPresenterWidth, ItemsPresenterHeight);\n            var desiredLocation = new Point(\n                eventArgs.DragablzItem.X + eventArgs.DragDeltaEventArgs.HorizontalChange,\n                eventArgs.DragablzItem.Y + eventArgs.DragDeltaEventArgs.VerticalChange\n                );\n            if (ItemsOrganiser != null)\n            {                \n                if (FixedItemCount > 0 &&\n                    ItemsOrganiser.Sort(DragablzItems()).Take(FixedItemCount).Contains(eventArgs.DragablzItem))\n                {\n                    eventArgs.Handled = true;\n                    return;\n                }                \n            \n                desiredLocation = ItemsOrganiser.ConstrainLocation(this, bounds,\n                    new Point(eventArgs.DragablzItem.X, eventArgs.DragablzItem.Y),\n                    new Size(eventArgs.DragablzItem.ActualWidth, eventArgs.DragablzItem.ActualHeight),\n                    desiredLocation, eventArgs.DragablzItem.DesiredSize);\n            }\n\n            foreach (var dragableItem in DragablzItems()\n                .Except(new[] { eventArgs.DragablzItem })) // how about Linq.Where() ?\n            {\n                dragableItem.IsSiblingDragging = true;\n            }\n            eventArgs.DragablzItem.IsDragging = true;\n\n            eventArgs.DragablzItem.X = desiredLocation.X;\n            eventArgs.DragablzItem.Y = desiredLocation.Y;\n\n            if (ItemsOrganiser != null)\n                ItemsOrganiser.OrganiseOnDrag(\n                    this,\n                    bounds,\n                    DragablzItems().Except(new[] {eventArgs.DragablzItem}), eventArgs.DragablzItem);\n            \n            eventArgs.DragablzItem.BringIntoView();\n\n            eventArgs.Handled = true;\n        }\n\n        private void ItemXChanged(object sender, RoutedPropertyChangedEventArgs<double> routedPropertyChangedEventArgs)\n        {\n            UpdateMonitor(routedPropertyChangedEventArgs);\n        }\n\n        private void ItemYChanged(object sender, RoutedPropertyChangedEventArgs<double> routedPropertyChangedEventArgs)\n        {\n            UpdateMonitor(routedPropertyChangedEventArgs);\n        }        \n\n        private void UpdateMonitor(RoutedEventArgs routedPropertyChangedEventArgs)\n        {\n            if (PositionMonitor == null) return;\n\n            var dragablzItem = (DragablzItem) routedPropertyChangedEventArgs.OriginalSource;\n\n            if (!Equals(ItemsControlFromItemContainer(dragablzItem), this)) return;\n\n            PositionMonitor.OnLocationChanged(new LocationChangedEventArgs(dragablzItem.Content, new Point(dragablzItem.X, dragablzItem.Y)));\n\n            var linearPositionMonitor = PositionMonitor as StackPositionMonitor;\n            if (linearPositionMonitor == null) return;\n\n            var sortedItems = linearPositionMonitor.Sort(this.Containers<DragablzItem>()).Select(di => di.Content).ToArray();\n            if (_previousSortQueryResult == null || !_previousSortQueryResult.SequenceEqual(sortedItems))\n                linearPositionMonitor.OnOrderChanged(new OrderChangedEventArgs(_previousSortQueryResult, sortedItems));\n\n            _previousSortQueryResult = sortedItems;\n        }\n\n        private void ItemMouseDownWithinHandlerTarget(object sender, DragablzItemEventArgs e)\n        {            \n            if (ItemsOrganiser == null) return;\n\n            var bounds = new Size(ActualWidth, ActualHeight);\n            ItemsOrganiser.OrganiseOnMouseDownWithin(this, bounds,\n                DragablzItems().Except(e.DragablzItem).ToList(),\n                e.DragablzItem);\n        }\n\n        private void ItemSizeChangedEventHandler(object sender, SizeChangedEventArgs e)\n        {\n            InvalidateMeasure();\n            //extra kick\n            Dispatcher.BeginInvoke(new Action(InvalidateMeasure), DispatcherPriority.Loaded);\n        }\n    }\n}\n"
  },
  {
    "path": "third_party/Dragablz/Dragablz/DragablzWindow.cs",
    "content": "﻿using System;\nusing System.Linq;\nusing System.Reflection;\nusing System.Windows;\nusing System.Windows.Controls;\nusing System.Windows.Controls.Primitives;\nusing System.Windows.Input;\nusing System.Windows.Interop;\nusing System.Windows.Media;\nusing System.Windows.Threading;\nusing Dragablz.Core;\nusing Dragablz.Dockablz;\nusing Dragablz.Referenceless;\n\nnamespace Dragablz\n{\n    /// <summary>\n    /// It is not necessary to use a <see cref=\"DragablzWindow\"/> to gain tab dragging features.\n    /// What this Window does is allow a quick way to remove the Window border, and support transparency whilst\n    /// dragging.  \n    /// </summary>\n    [TemplatePart(Name = WindowSurfaceGridPartName, Type = typeof(Grid))]\n    [TemplatePart(Name = WindowRestoreThumbPartName, Type = typeof(Thumb))]\n    [TemplatePart(Name = WindowResizeThumbPartName, Type = typeof(Thumb))]\n    public class DragablzWindow : Window\n    {\n        public const string WindowSurfaceGridPartName = \"PART_WindowSurface\";\n        public const string WindowRestoreThumbPartName = \"PART_WindowRestoreThumb\";\n        public const string WindowResizeThumbPartName = \"PART_WindowResizeThumb\";\n        private readonly SerialDisposable _templateSubscription = new SerialDisposable();\n\n        public static RoutedCommand CloseWindowCommand = new RoutedCommand();\n        public static RoutedCommand RestoreWindowCommand = new RoutedCommand();\n        public static RoutedCommand MaximizeWindowCommand = new RoutedCommand();\n        public static RoutedCommand MinimizeWindowCommand = new RoutedCommand();        \n\n        private const int ResizeMargin = 4;\n        private Size _sizeWhenResizeBegan;\n        private Point _screenMousePointWhenResizeBegan;\n        private Point _windowLocationPointWhenResizeBegan;\n        private SizeGrip _resizeType;\n\n        private static SizeGrip[] _leftMode = new[] { SizeGrip.TopLeft, SizeGrip.Left, SizeGrip.BottomLeft };\n        private static SizeGrip[] _rightMode = new[] { SizeGrip.TopRight, SizeGrip.Right, SizeGrip.BottomRight };\n        private static SizeGrip[] _topMode = new[] { SizeGrip.TopLeft, SizeGrip.Top, SizeGrip.TopRight };\n        private static SizeGrip[] _bottomMode = new[] { SizeGrip.BottomLeft, SizeGrip.Bottom, SizeGrip.BottomRight };\n\n        private static double _xScale = 1;\n        private static double _yScale = 1;\n        private static bool _dpiInitialized = false;\n\n        static DragablzWindow()\n        {\n            DefaultStyleKeyProperty.OverrideMetadata(typeof(DragablzWindow), new FrameworkPropertyMetadata(typeof(DragablzWindow)));            \n        }\n\n        public DragablzWindow()\n        {\n            AddHandler(DragablzItem.DragStarted, new DragablzDragStartedEventHandler(ItemDragStarted), true);\n            AddHandler(DragablzItem.DragCompleted, new DragablzDragCompletedEventHandler(ItemDragCompleted), true);\n            CommandBindings.Add(new CommandBinding(CloseWindowCommand, CloseWindowExecuted));\n            CommandBindings.Add(new CommandBinding(MaximizeWindowCommand, MaximizeWindowExecuted));\n            CommandBindings.Add(new CommandBinding(MinimizeWindowCommand, MinimizeWindowExecuted));\n            CommandBindings.Add(new CommandBinding(RestoreWindowCommand, RestoreWindowExecuted));                        \n        }\n\n        private static readonly DependencyPropertyKey IsWindowBeingDraggedByTabPropertyKey =\n            DependencyProperty.RegisterReadOnly(\n                \"IsBeingDraggedByTab\", typeof (bool), typeof (DragablzWindow),\n                new PropertyMetadata(default(bool)));\n\n        public static readonly DependencyProperty IsBeingDraggedByTabProperty =\n            IsWindowBeingDraggedByTabPropertyKey.DependencyProperty;\n\n        public bool IsBeingDraggedByTab\n        {\n            get { return (bool) GetValue(IsBeingDraggedByTabProperty); }\n            private set { SetValue(IsWindowBeingDraggedByTabPropertyKey, value); }\n        }        \n\n        private void ItemDragCompleted(object sender, DragablzDragCompletedEventArgs e)\n        {            \n            IsBeingDraggedByTab = false;\n        }\n\n        private void ItemDragStarted(object sender, DragablzDragStartedEventArgs e)\n        {\n            var sourceOfDragItemsControl = ItemsControl.ItemsControlFromItemContainer(e.DragablzItem) as DragablzItemsControl;\n            if (sourceOfDragItemsControl == null) return;\n\n            var sourceTab = TabablzControl.GetOwnerOfHeaderItems(sourceOfDragItemsControl);\n            if (sourceTab == null) return;\n\n            if (sourceOfDragItemsControl.Items.Count != 1\n                || (sourceTab.InterTabController != null && !sourceTab.InterTabController.MoveWindowWithSolitaryTabs)\n                || Layout.IsContainedWithinBranch(sourceOfDragItemsControl))\n                return;\n\n            IsBeingDraggedByTab = true;\n        }\n\n        public override void OnApplyTemplate()\n        {\n            var windowSurfaceGrid = GetTemplateChild(WindowSurfaceGridPartName) as Grid;\n            var windowRestoreThumb = GetTemplateChild(WindowRestoreThumbPartName) as Thumb;\n            var windowResizeThumb = GetTemplateChild(WindowResizeThumbPartName) as Thumb;\n\n            _templateSubscription.Disposable = Disposable.Create(() =>\n            {\n                if (windowSurfaceGrid != null)\n                {\n                    windowSurfaceGrid.MouseLeftButtonDown -= WindowSurfaceGridOnMouseLeftButtonDown;\n                }\n\n                if (windowRestoreThumb != null)\n                {\n                    windowRestoreThumb.DragDelta -= WindowMoveThumbOnDragDelta;\n                    windowRestoreThumb.MouseDoubleClick -= WindowRestoreThumbOnMouseDoubleClick;\n                }\n\n                if (windowResizeThumb == null) return;\n\n                windowResizeThumb.MouseMove -= WindowResizeThumbOnMouseMove;\n                windowResizeThumb.DragStarted -= WindowResizeThumbOnDragStarted;\n                windowResizeThumb.DragDelta -= WindowResizeThumbOnDragDelta;\n                windowResizeThumb.DragCompleted -= WindowResizeThumbOnDragCompleted;\n            });\n\n            base.OnApplyTemplate();\n\n            if (windowSurfaceGrid != null)\n            {\n                windowSurfaceGrid.MouseLeftButtonDown += WindowSurfaceGridOnMouseLeftButtonDown;\n            }\n\n            if (windowRestoreThumb != null)\n            {\n                windowRestoreThumb.DragDelta += WindowMoveThumbOnDragDelta;\n                windowRestoreThumb.MouseDoubleClick += WindowRestoreThumbOnMouseDoubleClick;\n            }\n\n            if (windowResizeThumb == null) return;\n\n            windowResizeThumb.MouseMove += WindowResizeThumbOnMouseMove;                \n            windowResizeThumb.DragStarted += WindowResizeThumbOnDragStarted;\n            windowResizeThumb.DragDelta += WindowResizeThumbOnDragDelta;\n            windowResizeThumb.DragCompleted += WindowResizeThumbOnDragCompleted;\n        }\n\n        protected override void OnRenderSizeChanged(SizeChangedInfo sizeInfo)\n        {\n            var resizeThumb = GetTemplateChild(WindowResizeThumbPartName) as Thumb;\n            if (resizeThumb != null)\n            {\n                var outerRectangleGeometry = new RectangleGeometry(new Rect(sizeInfo.NewSize));\n                var innerRectangleGeometry =\n                    new RectangleGeometry(new Rect(ResizeMargin, ResizeMargin, sizeInfo.NewSize.Width - ResizeMargin * 2, sizeInfo.NewSize.Height - ResizeMargin*2));\n                resizeThumb.Clip = new CombinedGeometry(GeometryCombineMode.Exclude, outerRectangleGeometry,\n                    innerRectangleGeometry);\n            }\n\n            base.OnRenderSizeChanged(sizeInfo);\n        }\n\n        protected IntPtr CriticalHandle\n        {\n            get\n            {\n                var value = typeof (Window).GetProperty(\"CriticalHandle\", BindingFlags.NonPublic | BindingFlags.Instance)\n                    .GetValue(this, new object[0]);\n                return (IntPtr) value;\n            }\n        }\n\n        private void WindowSurfaceGridOnMouseLeftButtonDown(object sender, MouseButtonEventArgs mouseButtonEventArgs)\n        {\n            if (mouseButtonEventArgs.ChangedButton != MouseButton.Left) return;\n            if (mouseButtonEventArgs.ClickCount == 1)\n                DragMove();\n            if (mouseButtonEventArgs.ClickCount == 2)\n                WindowState = WindowState.Maximized;\n        }\n\n        private static void WindowResizeThumbOnMouseMove(object sender, MouseEventArgs mouseEventArgs)\n        {\n            var thumb = (Thumb)sender;\n            var mousePositionInThumb = Mouse.GetPosition(thumb);\n            thumb.Cursor = SelectCursor(SelectSizingMode(mousePositionInThumb, thumb.RenderSize));\n        }\n\n        private void WindowRestoreThumbOnMouseDoubleClick(object sender, MouseButtonEventArgs mouseButtonEventArgs)\n        {            \n            WindowState = WindowState.Normal;            \n        }\n\n        private void WindowResizeThumbOnDragCompleted(object sender, DragCompletedEventArgs dragCompletedEventArgs)\n        {\n            Cursor = Cursors.Arrow;\n        }\n\n        private void WindowResizeThumbOnDragDelta(object sender, DragDeltaEventArgs dragDeltaEventArgs)\n        {\n            var mousePositionInWindow = Mouse.GetPosition(this);\n            var currentScreenMousePoint = PointToScreen(mousePositionInWindow);\n\n            var width = _sizeWhenResizeBegan.Width;\n            var height = _sizeWhenResizeBegan.Height;\n            var left = _windowLocationPointWhenResizeBegan.X;\n            var top = _windowLocationPointWhenResizeBegan.Y;\n\n            if (_leftMode.Contains(_resizeType))\n            {\n                var diff = currentScreenMousePoint.X - _screenMousePointWhenResizeBegan.X;\n                diff /= _xScale;\n                var suggestedWidth = width + -diff;\n                left += diff;\n                width = suggestedWidth;\n            }\n            if (_rightMode.Contains(_resizeType))\n            {\n                var diff = currentScreenMousePoint.X - _screenMousePointWhenResizeBegan.X;\n                diff /= _xScale;\n                width += diff;\n            }\n            if (_topMode.Contains(_resizeType))\n            {\n                var diff = currentScreenMousePoint.Y - _screenMousePointWhenResizeBegan.Y;\n                diff /= _yScale;\n                height += -diff;\n                top += diff;\n            }\n            if (_bottomMode.Contains(_resizeType))\n            {\n                var diff = currentScreenMousePoint.Y - _screenMousePointWhenResizeBegan.Y;\n                diff /= _yScale; \n                height += diff;\n            }\n\n            width = Math.Max(MinWidth, width);\n            height = Math.Max(MinHeight, height);   \n            //TODO must try harder.\n            left = Math.Min(left, _windowLocationPointWhenResizeBegan.X + _sizeWhenResizeBegan.Width - ResizeMargin*4);\n            //TODO must try harder.\n            top = Math.Min(top, _windowLocationPointWhenResizeBegan.Y + _sizeWhenResizeBegan.Height - ResizeMargin * 4);\n            SetCurrentValue(WidthProperty, width);\n            SetCurrentValue(HeightProperty, height);\n            SetCurrentValue(LeftProperty, left);\n            SetCurrentValue(TopProperty, top);\n        }\n\n        private void GetDPI()\n        {\n            if (_dpiInitialized)\n            {\n                return;\n            }\n\n            Matrix m = PresentationSource.FromVisual(this).CompositionTarget.TransformToDevice;\n            _xScale = m.M11;\n            _yScale = m.M22;\n            _dpiInitialized = true;\n        }\n\n        private void WindowResizeThumbOnDragStarted(object sender, DragStartedEventArgs dragStartedEventArgs)\n        {\n            _sizeWhenResizeBegan = new Size(ActualWidth, ActualHeight);\n            _windowLocationPointWhenResizeBegan = new Point(Left, Top);\n            var mousePositionInWindow = Mouse.GetPosition(this);\n            _screenMousePointWhenResizeBegan = PointToScreen(mousePositionInWindow);\n\n            var thumb = (Thumb)sender;\n            var mousePositionInThumb = Mouse.GetPosition(thumb);\n            _resizeType = SelectSizingMode(mousePositionInThumb, thumb.RenderSize);\n\n            GetDPI();\n        }\n\n        private static SizeGrip SelectSizingMode(Point mousePositionInThumb, Size thumbSize)\n        {\n            if (mousePositionInThumb.X <= ResizeMargin)\n            {\n                if (mousePositionInThumb.Y <= ResizeMargin)\n                    return SizeGrip.TopLeft;\n                if (mousePositionInThumb.Y >= thumbSize.Height - ResizeMargin)\n                    return SizeGrip.BottomLeft;\n                return SizeGrip.Left;\n            }\n\n            if (mousePositionInThumb.X >= thumbSize.Width - ResizeMargin)\n            {\n                if (mousePositionInThumb.Y <= ResizeMargin)\n                    return SizeGrip.TopRight;\n                if (mousePositionInThumb.Y >= thumbSize.Height - ResizeMargin)\n                    return SizeGrip.BottomRight;\n                return SizeGrip.Right;\n            }\n\n            if (mousePositionInThumb.Y <= ResizeMargin)\n                return SizeGrip.Top;\n\n            return SizeGrip.Bottom;\n        }\n\n        private static Cursor SelectCursor(SizeGrip sizeGrip)\n        {\n            switch (sizeGrip)\n            {                \n                case SizeGrip.Left:\n                    return Cursors.SizeWE;\n                case SizeGrip.TopLeft:\n                    return Cursors.SizeNWSE;\n                case SizeGrip.Top:\n                    return Cursors.SizeNS;\n                case SizeGrip.TopRight:\n                    return Cursors.SizeNESW;\n                case SizeGrip.Right:\n                    return Cursors.SizeWE;\n                case SizeGrip.BottomRight:\n                    return Cursors.SizeNWSE;\n                case SizeGrip.Bottom:\n                    return Cursors.SizeNS;\n                case SizeGrip.BottomLeft:\n                    return Cursors.SizeNESW;\n                default:\n                    return Cursors.Arrow;\n            }\n        }\n\n        private void WindowMoveThumbOnDragDelta(object sender, DragDeltaEventArgs dragDeltaEventArgs)\n        {\n            if (WindowState != WindowState.Maximized ||\n                (!(Math.Abs(dragDeltaEventArgs.HorizontalChange) > 2) &&\n                 !(Math.Abs(dragDeltaEventArgs.VerticalChange) > 2))) return;\n\n            var cursorPos = Native.GetRawCursorPos();\n            WindowState = WindowState.Normal;\n\n            Top = cursorPos.Y - 2;\n            Left = cursorPos.X - RestoreBounds.Width / 2;\n            \n            var lParam = (int)(uint)cursorPos.X | (cursorPos.Y << 16);\n            Native.SendMessage(CriticalHandle, WindowMessage.WM_LBUTTONUP, (IntPtr)HitTest.HT_CAPTION,\n                (IntPtr)lParam);\n            Native.SendMessage(CriticalHandle, WindowMessage.WM_SYSCOMMAND, (IntPtr)SystemCommand.SC_MOUSEMOVE,\n                IntPtr.Zero);            \n        }\n\n        private void RestoreWindowExecuted(object sender, ExecutedRoutedEventArgs e)\n        {\n            Native.PostMessage(new WindowInteropHelper(this).Handle, WindowMessage.WM_SYSCOMMAND, (IntPtr)SystemCommand.SC_RESTORE, IntPtr.Zero);\n        }\n\n        private void MinimizeWindowExecuted(object sender, ExecutedRoutedEventArgs e)\n        {\n            Native.PostMessage(new WindowInteropHelper(this).Handle, WindowMessage.WM_SYSCOMMAND, (IntPtr)SystemCommand.SC_MINIMIZE, IntPtr.Zero);\n        }\n\n        private void MaximizeWindowExecuted(object sender, ExecutedRoutedEventArgs e)\n        {\n            Native.PostMessage(new WindowInteropHelper(this).Handle, WindowMessage.WM_SYSCOMMAND, (IntPtr)SystemCommand.SC_MAXIMIZE, IntPtr.Zero);\n        }\n\n        private void CloseWindowExecuted(object sender, ExecutedRoutedEventArgs executedRoutedEventArgs)\n        {\n            Native.PostMessage(new WindowInteropHelper(this).Handle, WindowMessage.WM_CLOSE, IntPtr.Zero, IntPtr.Zero);\n        }             \n    }\n}\n"
  },
  {
    "path": "third_party/Dragablz/Dragablz/EmptyHeaderSizingHint.cs",
    "content": "namespace Dragablz\n{\n    /// <summary>\n    /// Provide a hint for how the header should size itself if there are no tabs left (and a Window is still open).\n    /// </summary>\n    public enum EmptyHeaderSizingHint\n    {\n        /// <summary>\n        /// The header size collapses to zero along the correct axis.\n        /// </summary>\n        Collapse,\n        /// <summary>\n        /// The header size remains that of the last tab prior to the tab header becoming empty.\n        /// </summary>\n        PreviousTab,\n        //TODO implement EmptyHeaderSizingHint.Stretch        \n        /// <summary>\n        /// The header stretches along the according axis.\n        /// </summary>\n        //Stretch\n    }\n}"
  },
  {
    "path": "third_party/Dragablz/Dragablz/HeaderedDragablzItem.cs",
    "content": "using System.Windows;\nusing System.Windows.Controls;\n\nnamespace Dragablz\n{\n    public class HeaderedDragablzItem : DragablzItem\n    {\n        static HeaderedDragablzItem()\n        {\n            DefaultStyleKeyProperty.OverrideMetadata(typeof(HeaderedDragablzItem), new FrameworkPropertyMetadata(typeof(HeaderedDragablzItem)));            \n        }\n        \n        public static readonly DependencyProperty HeaderContentProperty = DependencyProperty.Register(\n            \"HeaderContent\", typeof (object), typeof (HeaderedDragablzItem), new PropertyMetadata(default(object)));\n\n        public object HeaderContent\n        {\n            get { return (object) GetValue(HeaderContentProperty); }\n            set { SetValue(HeaderContentProperty, value); }\n        }\n\n        public static readonly DependencyProperty HeaderContentStringFormatProperty = DependencyProperty.Register(\n            \"HeaderContentStringFormat\", typeof (string), typeof (HeaderedDragablzItem), new PropertyMetadata(default(string)));\n\n        public string HeaderContentStringFormat\n        {\n            get { return (string) GetValue(HeaderContentStringFormatProperty); }\n            set { SetValue(HeaderContentStringFormatProperty, value); }\n        }\n\n        public static readonly DependencyProperty HeaderContentTemplateProperty = DependencyProperty.Register(\n            \"HeaderContentTemplate\", typeof (DataTemplate), typeof (HeaderedDragablzItem), new PropertyMetadata(default(DataTemplate)));\n\n        public DataTemplate HeaderContentTemplate\n        {\n            get { return (DataTemplate) GetValue(HeaderContentTemplateProperty); }\n            set { SetValue(HeaderContentTemplateProperty, value); }\n        }\n\n        public static readonly DependencyProperty HeaderContentTemplateSelectorProperty = DependencyProperty.Register(\n            \"HeaderContentTemplateSelector\", typeof (DataTemplateSelector), typeof (HeaderedDragablzItem), new PropertyMetadata(default(DataTemplateSelector)));\n\n        public DataTemplateSelector HeaderContentTemplateSelector\n        {\n            get { return (DataTemplateSelector) GetValue(HeaderContentTemplateSelectorProperty); }\n            set { SetValue(HeaderContentTemplateSelectorProperty, value); }\n        }         \n    }\n}"
  },
  {
    "path": "third_party/Dragablz/Dragablz/HeaderedItemViewModel.cs",
    "content": "﻿using System;\nusing System.Collections.Generic;\nusing System.ComponentModel;\nusing System.Linq;\nusing System.Runtime.CompilerServices;\nusing System.Text;\nusing System.Threading.Tasks;\n\nnamespace Dragablz\n{\n    /// <summary>\n    /// Helper class to create view models, particularly for tool/MDI windows.\n    /// </summary>\n    public class HeaderedItemViewModel : INotifyPropertyChanged\n    {\n        private bool _isSelected;\n        private object _header;\n        private object _content;\n\n        public HeaderedItemViewModel()\n        {\n        }\n\n        public HeaderedItemViewModel(object header, object content, bool isSelected = false)\n        {\n            _header = header;\n            _content = content;\n            _isSelected = isSelected;\n        }\n\n        public object Header\n        {\n            get { return _header; }\n            set\n            {\n                if (_header == value) return;\n                _header = value;\n#if NET40\n                OnPropertyChanged(\"Header\");\n#endif\n#if NET45\n                OnPropertyChanged();\n#endif\n            }\n        }\n\n        public object Content\n        {\n            get { return _content; }\n            set\n            {\n                if (_content == value) return;\n                _content = value;\n#if NET40\n                OnPropertyChanged(\"Content\");\n#endif\n#if NET45\n                OnPropertyChanged();\n#endif\n            }\n        }\n\n        public bool IsSelected\n        {\n            get { return _isSelected; }\n            set\n            {\n                if (_isSelected == value) return;\n                _isSelected = value;\n#if NET40\n                OnPropertyChanged(\"IsSelected\");\n#endif\n#if NET45\n                OnPropertyChanged();\n#endif\n            }\n        }\n\n        public event PropertyChangedEventHandler PropertyChanged;\n\n#if NET40\n        protected virtual void OnPropertyChanged(string propertyName)\n#endif\n#if NET45\n        protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)\n#endif\n        {\n            var handler = PropertyChanged;\n            if (handler != null) handler(this, new PropertyChangedEventArgs(propertyName));\n        }\n    }\n}\n"
  },
  {
    "path": "third_party/Dragablz/Dragablz/HorizontalOrganiser.cs",
    "content": "using System;\nusing System.Windows;\nusing System.Windows.Controls;\nusing System.Windows.Media.Animation;\n\nnamespace Dragablz\n{\n    public class HorizontalOrganiser : StackOrganiser\n    {\n        public HorizontalOrganiser() : base(Orientation.Horizontal)\n        { }\n\n        public HorizontalOrganiser(double itemOffset) : base(Orientation.Horizontal, itemOffset)\n        { }\n    }    \n}"
  },
  {
    "path": "third_party/Dragablz/Dragablz/HorizontalPositionMonitor.cs",
    "content": "﻿using System.Windows.Controls;\n\nnamespace Dragablz\n{\n    public class HorizontalPositionMonitor : StackPositionMonitor\n    {\n        public HorizontalPositionMonitor() : base(Orientation.Horizontal)\n        {\n        }\n    }\n}"
  },
  {
    "path": "third_party/Dragablz/Dragablz/IInterLayoutClient.cs",
    "content": "using System.Windows;\n\nnamespace Dragablz\n{\n    /// <summary>\n    /// Implementors should provide a mechanism to provide a new host control which contains a new <see cref=\"TabablzControl\"/>.\n    /// </summary>\n    public interface IInterLayoutClient\n    {\n        /// <summary>\n        /// Provide a new host control and tab into which will be placed into a newly created layout branch.\n        /// </summary>\n        /// <param name=\"partition\">Provides the partition where the drag operation was initiated.</param>\n        /// <param name=\"source\">The source control where a dragging operation was initiated.</param>\n        /// <returns></returns>\n        INewTabHost<UIElement> GetNewHost(object partition, TabablzControl source);\n        \n    }\n}"
  },
  {
    "path": "third_party/Dragablz/Dragablz/IInterTabClient.cs",
    "content": "using System.Threading;\nusing System.Windows;\n\nnamespace Dragablz\n{\n    /// <summary>\n    /// Implementors should provide mechanisms for providing new windows and closing old windows.\n    /// </summary>\n    public interface IInterTabClient\n    {\n        /// <summary>\n        /// Provide a new host window so a tab can be teared from an existing window into a new window.\n        /// </summary>\n        /// <param name=\"interTabClient\"></param>\n        /// <param name=\"partition\">Provides the partition where the drag operation was initiated.</param>\n        /// <param name=\"source\">The source control where a dragging operation was initiated.</param>\n        /// <returns></returns>\n        INewTabHost<Window> GetNewHost(IInterTabClient interTabClient, object partition, TabablzControl source);\n        /// <summary>\n        /// Called when a tab has been emptied, and thus typically a window needs closing.\n        /// </summary>\n        /// <param name=\"tabControl\"></param>\n        /// <param name=\"window\"></param>\n        /// <returns></returns>\n        TabEmptiedResponse TabEmptiedHandler(TabablzControl tabControl, Window window);\n    }\n}"
  },
  {
    "path": "third_party/Dragablz/Dragablz/IItemsOrganiser.cs",
    "content": "﻿using System;\nusing System.Collections.Generic;\nusing System.Linq;\nusing System.Text;\nusing System.Windows;\n\nnamespace Dragablz\n{\n    public interface IItemsOrganiser\n    {\n        void Organise(DragablzItemsControl requestor, Size measureBounds, IEnumerable<DragablzItem> items);\n        void Organise(DragablzItemsControl requestor, Size measureBounds, IOrderedEnumerable<DragablzItem> items);\n        void OrganiseOnMouseDownWithin(DragablzItemsControl requestor, Size measureBounds, List<DragablzItem> siblingItems, DragablzItem dragablzItem);\n        void OrganiseOnDragStarted(DragablzItemsControl requestor, Size measureBounds, IEnumerable<DragablzItem> siblingItems, DragablzItem dragItem);\n        void OrganiseOnDrag(DragablzItemsControl requestor, Size measureBounds, IEnumerable<DragablzItem> siblingItems, DragablzItem dragItem);\n        void OrganiseOnDragCompleted(DragablzItemsControl requestor, Size measureBounds, IEnumerable<DragablzItem> siblingItems, DragablzItem dragItem);        \n        Point ConstrainLocation(DragablzItemsControl requestor, Size measureBounds, Point itemCurrentLocation, Size itemCurrentSize, Point itemDesiredLocation, Size itemDesiredSize);\n        Size Measure(DragablzItemsControl requestor, Size availableSize, IEnumerable<DragablzItem> items);\n        IEnumerable<DragablzItem> Sort(IEnumerable<DragablzItem> items);\n    }\n}\n"
  },
  {
    "path": "third_party/Dragablz/Dragablz/IManualInterTabClient.cs",
    "content": "﻿namespace Dragablz\n{\n    public interface IManualInterTabClient : IInterTabClient\n    {\n        void Add(object item);\n        void Remove(object item);\n    }\n}"
  },
  {
    "path": "third_party/Dragablz/Dragablz/INewTabHost.cs",
    "content": "﻿using System.Windows;\n\nnamespace Dragablz\n{\n    public interface INewTabHost<out TElement> where TElement : UIElement\n    {\n        TElement Container { get; }\n        TabablzControl TabablzControl { get; }\n    }\n}"
  },
  {
    "path": "third_party/Dragablz/Dragablz/InterTabController.cs",
    "content": "﻿using System.Dynamic;\nusing System.Windows;\n\nnamespace Dragablz\n{\n    public class InterTabController : FrameworkElement\n    {\n        public InterTabController()\n        {\n            HorizontalPopoutGrace = 8;\n            VerticalPopoutGrace = 8;\n            MoveWindowWithSolitaryTabs = true;            \n        }\n\n        public static readonly DependencyProperty HorizontalPopoutGraceProperty = DependencyProperty.Register(\n            \"HorizontalPopoutGrace\", typeof (double), typeof (InterTabController), new PropertyMetadata(8.0));\n\n        public double HorizontalPopoutGrace\n        {\n            get { return (double) GetValue(HorizontalPopoutGraceProperty); }\n            set { SetValue(HorizontalPopoutGraceProperty, value); }\n        }\n\n        public static readonly DependencyProperty VerticalPopoutGraceProperty = DependencyProperty.Register(\n            \"VerticalPopoutGrace\", typeof (double), typeof (InterTabController), new PropertyMetadata(8.0));\n\n        public double VerticalPopoutGrace\n        {\n            get { return (double) GetValue(VerticalPopoutGraceProperty); }\n            set { SetValue(VerticalPopoutGraceProperty, value); }\n        }\n\n        public static readonly DependencyProperty MoveWindowWithSolitaryTabsProperty = DependencyProperty.Register(\n            \"MoveWindowWithSolitaryTabs\", typeof (bool), typeof (InterTabController), new PropertyMetadata(true));\n\n        public bool MoveWindowWithSolitaryTabs\n        {\n            get { return (bool) GetValue(MoveWindowWithSolitaryTabsProperty); }\n            set { SetValue(MoveWindowWithSolitaryTabsProperty, value); }\n        }\n\n        public static readonly DependencyProperty InterTabClientProperty = DependencyProperty.Register(\n            \"InterTabClient\", typeof (IInterTabClient), typeof (InterTabController),\n            new PropertyMetadata(new DefaultInterTabClient()));\n\n        public IInterTabClient InterTabClient\n        {\n            get { return (IInterTabClient) GetValue(InterTabClientProperty); }\n            set { SetValue(InterTabClientProperty, value); }\n        }\n\n        /*\n        public static readonly DependencyProperty PartitionProperty = DependencyProperty.Register(\n            \"Partition\", typeof (object), typeof (InterTabController), new PropertyMetadata(default(object)));\n\n        /// <summary>\n        /// The partition allows on or more tab environments in a single application.  Only tabs which have a tab controller\n        /// with a common partition will be allowed to have tabs dragged between them.  <c>null</c> is a valid partition (i.e global).\n        /// </summary>\n        public object Partition\n        {\n            get { return (object) GetValue(PartitionProperty); }\n            set { SetValue(PartitionProperty, value); }\n        }\n         */\n\n        /// <summary>\n        /// The partition allows on or more tab environments in a single application.  Only tabs which have a tab controller\n        /// with a common partition will be allowed to have tabs dragged between them.  <c>null</c> is a valid partition (i.e global).\n        /// </summary>\n        public string Partition { get; set; }\n    }\n}"
  },
  {
    "path": "third_party/Dragablz/Dragablz/ItemActionCallbackArgs.cs",
    "content": "﻿using System;\nusing System.Windows;\n\nnamespace Dragablz\n{\n    public delegate void ItemActionCallback(ItemActionCallbackArgs<TabablzControl> args);\n\n    public class ItemActionCallbackArgs<TOwner> where TOwner : FrameworkElement\n    {\n        private readonly Window _window;\n        private readonly TOwner _owner;\n        private readonly DragablzItem _dragablzItem;\n\n        public ItemActionCallbackArgs(Window window, TOwner owner, DragablzItem dragablzItem)\n        {\n            if (window == null) throw new ArgumentNullException(\"window\");\n            if (owner == null) throw new ArgumentNullException(\"owner\");\n            if (dragablzItem == null) throw new ArgumentNullException(\"dragablzItem\");\n\n            _window = window;\n            _owner = owner;\n            _dragablzItem = dragablzItem;\n        }\n\n        public Window Window\n        {\n            get { return _window; }\n        }\n\n        public TOwner Owner\n        {\n            get { return _owner; }\n        }\n\n        public DragablzItem DragablzItem\n        {\n            get { return _dragablzItem; }\n        }\n\n        public bool IsCancelled { get; private set; }\n\n        public void Cancel()\n        {\n            IsCancelled = true;\n        }\n    }\n}\n"
  },
  {
    "path": "third_party/Dragablz/Dragablz/LocationChangedEventArgs.cs",
    "content": "using System;\nusing System.Windows;\n\nnamespace Dragablz\n{\n    public class LocationChangedEventArgs : EventArgs\n    {\n        private readonly object _item;\n        private readonly Point _location;\n\n        public LocationChangedEventArgs(object item, Point location)\n        {\n            if (item == null) throw new ArgumentNullException(\"item\");\n            \n            _item = item;\n            _location = location;\n        }\n\n        public object Item\n        {\n            get { return _item; }\n        }\n\n        public Point Location\n        {\n            get { return _location; }\n        }\n    }\n}"
  },
  {
    "path": "third_party/Dragablz/Dragablz/LocationHint.cs",
    "content": "namespace Dragablz\n{\n    /// <summary>\n    /// Specifies where an item should appear when added to tab control, as the headers order do not\n    /// specifically correlate to the order of the the source items.\n    /// </summary>\n    public enum AddLocationHint\n    {        \n        /// <summary>\n        /// Display item in the first position.\n        /// </summary>\n        First,\n        /// <summary>\n        /// Display item in the first position.\n        /// </summary>\n        Last,\n        /// <summary>\n        /// Display an item prior to the selected, or specified item.\n        /// </summary>\n        Prior,\n        /// <summary>\n        /// Display an item after the selected, or specified item.\n        /// </summary>\n        After\n    }\n}"
  },
  {
    "path": "third_party/Dragablz/Dragablz/MoveItemRequest.cs",
    "content": "namespace Dragablz\n{\n    public class MoveItemRequest\n    {\n        private readonly object _item;\n        private readonly object _context;\n        private readonly AddLocationHint _addLocationHint;\n\n        public MoveItemRequest(object item, object context, AddLocationHint addLocationHint)\n        {\n            _item = item;\n            _context = context;\n            _addLocationHint = addLocationHint;\n        }\n\n        public object Item\n        {\n            get { return _item; }\n        }\n\n        public object Context\n        {\n            get { return _context; }\n        }\n\n        public AddLocationHint AddLocationHint\n        {\n            get { return _addLocationHint; }\n        }\n    }\n}"
  },
  {
    "path": "third_party/Dragablz/Dragablz/NewTabHost.cs",
    "content": "﻿using System;\nusing System.Windows;\n\nnamespace Dragablz\n{\n    public class NewTabHost<TElement> : INewTabHost<TElement> where TElement : UIElement\n    {\n        private readonly TElement _container;\n        private readonly TabablzControl _tabablzControl;\n\n        public NewTabHost(TElement container, TabablzControl tabablzControl)\n        {\n            if (container == null) throw new ArgumentNullException(\"container\");\n            if (tabablzControl == null) throw new ArgumentNullException(\"tabablzControl\");\n\n            _container = container;\n            _tabablzControl = tabablzControl;\n        }\n\n        public TElement Container\n        {\n            get { return _container; }\n        }\n\n        public TabablzControl TabablzControl\n        {\n            get { return _tabablzControl; }\n        }\n    }\n}"
  },
  {
    "path": "third_party/Dragablz/Dragablz/OrderChangedEventArgs.cs",
    "content": "﻿using System;\n\nnamespace Dragablz\n{\n    public class OrderChangedEventArgs : EventArgs\n    {\n        private readonly object[] _previousOrder;\n        private readonly object[] _newOrder;\n\n        public OrderChangedEventArgs(object[] previousOrder, object[] newOrder)\n        {\n            if (newOrder == null) throw new ArgumentNullException(\"newOrder\");\n\n            _previousOrder = previousOrder;\n            _newOrder = newOrder;\n        }\n\n        public object[] PreviousOrder\n        {\n            get { return _previousOrder; }\n        }\n\n        public object[] NewOrder\n        {\n            get { return _newOrder; }\n        }\n    }\n}"
  },
  {
    "path": "third_party/Dragablz/Dragablz/PositionMonitor.cs",
    "content": "﻿using System;\nusing System.Text;\nusing System.Threading.Tasks;\n\nnamespace Dragablz\n{\n    /// <summary>\n    /// Consumers can provide a position monitor to receive updates regarding the location of an item.    \n    /// </summary>\n    /// <remarks>\n    /// A <see cref=\"PositionMonitor\"/> can be used to listen to  changes \n    /// instead of routed events, which can be easier in a MVVM scenario.\n    /// </remarks>\n    public class PositionMonitor\n    {\n        /// <summary>\n        /// Raised when the X,Y coordinate of a <see cref=\"DragablzItem\"/> changes.\n        /// </summary>\n        public event EventHandler<LocationChangedEventArgs> LocationChanged;\n\n        internal virtual void OnLocationChanged(LocationChangedEventArgs e)\n        {\n            if (e == null) throw new ArgumentNullException(\"e\");\n\n            var handler = LocationChanged;\n            handler?.Invoke(this, e);\n        }\n\n        internal virtual void ItemsChanged() { }\n    }\n}\n"
  },
  {
    "path": "third_party/Dragablz/Dragablz/Properties/AssemblyInfo.cs",
    "content": "﻿using System.Reflection;\nusing System.Resources;\nusing System.Runtime.CompilerServices;\nusing System.Runtime.InteropServices;\nusing System.Windows;\nusing System.Windows.Markup;\n\n// General Information about an assembly is controlled through the following \n// set of attributes. Change these attribute values to modify the information\n// associated with an assembly.\n[assembly: AssemblyTitle(\"Dragablz\")]\n[assembly: AssemblyDescription(\"Dragable tabable\")]\n[assembly: AssemblyConfiguration(\"\")]\n[assembly: AssemblyCompany(\"Mulholland Software Ltd/James Willock\")]\n[assembly: AssemblyProduct(\"Dragablz\")]\n[assembly: AssemblyCopyright(\"Copyright © 2014\")]\n[assembly: AssemblyTrademark(\"\")]\n[assembly: AssemblyCulture(\"\")]\n[assembly: XmlnsPrefix(\"http://dragablz.net/winfx/xaml/dragablz\", \"dragablz\")]\n[assembly: XmlnsDefinition(\"http://dragablz.net/winfx/xaml/dragablz\", \n\t\"Dragablz\")]\n[assembly: XmlnsPrefix(\"http://dragablz.net/winfx/xaml/dockablz\", \"dockablz\")]\n[assembly: XmlnsDefinition(\"http://dragablz.net/winfx/xaml/dockablz\",\n    \"Dragablz.Dockablz\")]\n\n// Setting ComVisible to false makes the types in this assembly not visible \n// to COM components.  If you need to access a type in this assembly from \n// COM, set the ComVisible attribute to true on that type.\n[assembly: ComVisible(false)]\n\n//In order to begin building localizable applications, set \n//<UICulture>CultureYouAreCodingWith</UICulture> in your .csproj file\n//inside a <PropertyGroup>.  For example, if you are using US english\n//in your source files, set the <UICulture> to en-US.  Then uncomment\n//the NeutralResourceLanguage attribute below.  Update the \"en-US\" in\n//the line below to match the UICulture setting in the project file.\n\n//[assembly: NeutralResourcesLanguage(\"en-US\", UltimateResourceFallbackLocation.Satellite)]\n\n\n[assembly: ThemeInfo(\n    ResourceDictionaryLocation.None, //where theme specific resource dictionaries are located\n    //(used if a resource is not found in the page, \n    // or application resource dictionaries)\n    ResourceDictionaryLocation.SourceAssembly //where the generic resource dictionary is located\n    //(used if a resource is not found in the page, \n    // app, or any theme specific resource dictionaries)\n)]\n\n\n// Version information for an assembly consists of the following four values:\n//\n//      Major Version\n//      Minor Version \n//      Build Number\n//      Revision\n//\n// You can specify all the values or you can default the Build and Revision Numbers \n// by using the '*' as shown below:\n// [assembly: AssemblyVersion(\"1.0.*\")]\n[assembly: AssemblyVersion(\"0.0.0.0\")]\n[assembly: AssemblyFileVersion(\"0.0.0.0\")]\n\n[assembly: InternalsVisibleTo(\"Dragablz.Test\")]"
  },
  {
    "path": "third_party/Dragablz/Dragablz/Properties/Resources.Designer.cs",
    "content": "﻿//------------------------------------------------------------------------------\n// <auto-generated>\n//     This code was generated by a tool.\n//     Runtime Version:4.0.30319.34014\n//\n//     Changes to this file may cause incorrect behavior and will be lost if\n//     the code is regenerated.\n// </auto-generated>\n//------------------------------------------------------------------------------\n\nnamespace Dragablz.Properties {\n    using System;\n    \n    \n    /// <summary>\n    ///   A strongly-typed resource class, for looking up localized strings, etc.\n    /// </summary>\n    // This class was auto-generated by the StronglyTypedResourceBuilder\n    // class via a tool like ResGen or Visual Studio.\n    // To add or remove a member, edit your .ResX file then rerun ResGen\n    // with the /str option, or rebuild your VS project.\n    [global::System.CodeDom.Compiler.GeneratedCodeAttribute(\"System.Resources.Tools.StronglyTypedResourceBuilder\", \"4.0.0.0\")]\n    [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]\n    [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]\n    internal class Resources {\n        \n        private static global::System.Resources.ResourceManager resourceMan;\n        \n        private static global::System.Globalization.CultureInfo resourceCulture;\n        \n        [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute(\"Microsoft.Performance\", \"CA1811:AvoidUncalledPrivateCode\")]\n        internal Resources() {\n        }\n        \n        /// <summary>\n        ///   Returns the cached ResourceManager instance used by this class.\n        /// </summary>\n        [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]\n        internal static global::System.Resources.ResourceManager ResourceManager {\n            get {\n                if (object.ReferenceEquals(resourceMan, null)) {\n                    global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager(\"Dragablz.Properties.Resources\", typeof(Resources).Assembly);\n                    resourceMan = temp;\n                }\n                return resourceMan;\n            }\n        }\n        \n        /// <summary>\n        ///   Overrides the current thread's CurrentUICulture property for all\n        ///   resource lookups using this strongly typed resource class.\n        /// </summary>\n        [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]\n        internal static global::System.Globalization.CultureInfo Culture {\n            get {\n                return resourceCulture;\n            }\n            set {\n                resourceCulture = value;\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "third_party/Dragablz/Dragablz/Properties/Resources.resx",
    "content": "﻿<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<root>\n  <!-- \n    Microsoft ResX Schema \n    \n    Version 2.0\n    \n    The primary goals of this format is to allow a simple XML format \n    that is mostly human readable. The generation and parsing of the \n    various data types are done through the TypeConverter classes \n    associated with the data types.\n    \n    Example:\n    \n    ... ado.net/XML headers & schema ...\n    <resheader name=\"resmimetype\">text/microsoft-resx</resheader>\n    <resheader name=\"version\">2.0</resheader>\n    <resheader name=\"reader\">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>\n    <resheader name=\"writer\">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>\n    <data name=\"Name1\"><value>this is my long string</value><comment>this is a comment</comment></data>\n    <data name=\"Color1\" type=\"System.Drawing.Color, System.Drawing\">Blue</data>\n    <data name=\"Bitmap1\" mimetype=\"application/x-microsoft.net.object.binary.base64\">\n        <value>[base64 mime encoded serialized .NET Framework object]</value>\n    </data>\n    <data name=\"Icon1\" type=\"System.Drawing.Icon, System.Drawing\" mimetype=\"application/x-microsoft.net.object.bytearray.base64\">\n        <value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>\n        <comment>This is a comment</comment>\n    </data>\n                \n    There are any number of \"resheader\" rows that contain simple \n    name/value pairs.\n    \n    Each data row contains a name, and value. The row also contains a \n    type or mimetype. Type corresponds to a .NET class that support \n    text/value conversion through the TypeConverter architecture. \n    Classes that don't support this are serialized and stored with the \n    mimetype set.\n    \n    The mimetype is used for serialized objects, and tells the \n    ResXResourceReader how to depersist the object. This is currently not \n    extensible. For a given mimetype the value must be set accordingly:\n    \n    Note - application/x-microsoft.net.object.binary.base64 is the format \n    that the ResXResourceWriter will generate, however the reader can \n    read any of the formats listed below.\n    \n    mimetype: application/x-microsoft.net.object.binary.base64\n    value   : The object must be serialized with \n            : System.Serialization.Formatters.Binary.BinaryFormatter\n            : and then encoded with base64 encoding.\n    \n    mimetype: application/x-microsoft.net.object.soap.base64\n    value   : The object must be serialized with \n            : System.Runtime.Serialization.Formatters.Soap.SoapFormatter\n            : and then encoded with base64 encoding.\n\n    mimetype: application/x-microsoft.net.object.bytearray.base64\n    value   : The object must be serialized into a byte array \n            : using a System.ComponentModel.TypeConverter\n            : and then encoded with base64 encoding.\n    -->\n  <xsd:schema id=\"root\" xmlns=\"\" xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\" xmlns:msdata=\"urn:schemas-microsoft-com:xml-msdata\">\n    <xsd:element name=\"root\" msdata:IsDataSet=\"true\">\n      <xsd:complexType>\n        <xsd:choice maxOccurs=\"unbounded\">\n          <xsd:element name=\"metadata\">\n            <xsd:complexType>\n              <xsd:sequence>\n                <xsd:element name=\"value\" type=\"xsd:string\" minOccurs=\"0\" />\n              </xsd:sequence>\n              <xsd:attribute name=\"name\" type=\"xsd:string\" />\n              <xsd:attribute name=\"type\" type=\"xsd:string\" />\n              <xsd:attribute name=\"mimetype\" type=\"xsd:string\" />\n            </xsd:complexType>\n          </xsd:element>\n          <xsd:element name=\"assembly\">\n            <xsd:complexType>\n              <xsd:attribute name=\"alias\" type=\"xsd:string\" />\n              <xsd:attribute name=\"name\" type=\"xsd:string\" />\n            </xsd:complexType>\n          </xsd:element>\n          <xsd:element name=\"data\">\n            <xsd:complexType>\n              <xsd:sequence>\n                <xsd:element name=\"value\" type=\"xsd:string\" minOccurs=\"0\" msdata:Ordinal=\"1\" />\n                <xsd:element name=\"comment\" type=\"xsd:string\" minOccurs=\"0\" msdata:Ordinal=\"2\" />\n              </xsd:sequence>\n              <xsd:attribute name=\"name\" type=\"xsd:string\" msdata:Ordinal=\"1\" />\n              <xsd:attribute name=\"type\" type=\"xsd:string\" msdata:Ordinal=\"3\" />\n              <xsd:attribute name=\"mimetype\" type=\"xsd:string\" msdata:Ordinal=\"4\" />\n            </xsd:complexType>\n          </xsd:element>\n          <xsd:element name=\"resheader\">\n            <xsd:complexType>\n              <xsd:sequence>\n                <xsd:element name=\"value\" type=\"xsd:string\" minOccurs=\"0\" msdata:Ordinal=\"1\" />\n              </xsd:sequence>\n              <xsd:attribute name=\"name\" type=\"xsd:string\" use=\"required\" />\n            </xsd:complexType>\n          </xsd:element>\n        </xsd:choice>\n      </xsd:complexType>\n    </xsd:element>\n  </xsd:schema>\n  <resheader name=\"resmimetype\">\n    <value>text/microsoft-resx</value>\n  </resheader>\n  <resheader name=\"version\">\n    <value>2.0</value>\n  </resheader>\n  <resheader name=\"reader\">\n    <value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>\n  </resheader>\n  <resheader name=\"writer\">\n    <value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>\n  </resheader>\n</root>"
  },
  {
    "path": "third_party/Dragablz/Dragablz/Properties/Settings.Designer.cs",
    "content": "﻿//------------------------------------------------------------------------------\n// <auto-generated>\n//     This code was generated by a tool.\n//     Runtime Version:4.0.30319.34014\n//\n//     Changes to this file may cause incorrect behavior and will be lost if\n//     the code is regenerated.\n// </auto-generated>\n//------------------------------------------------------------------------------\n\nnamespace Dragablz.Properties {\n    \n    \n    [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]\n    [global::System.CodeDom.Compiler.GeneratedCodeAttribute(\"Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator\", \"12.0.0.0\")]\n    internal sealed partial class Settings : global::System.Configuration.ApplicationSettingsBase {\n        \n        private static Settings defaultInstance = ((Settings)(global::System.Configuration.ApplicationSettingsBase.Synchronized(new Settings())));\n        \n        public static Settings Default {\n            get {\n                return defaultInstance;\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "third_party/Dragablz/Dragablz/Properties/Settings.settings",
    "content": "﻿<?xml version='1.0' encoding='utf-8'?>\n<SettingsFile xmlns=\"uri:settings\" CurrentProfile=\"(Default)\">\n  <Profiles>\n    <Profile Name=\"(Default)\" />\n  </Profiles>\n  <Settings />\n</SettingsFile>"
  },
  {
    "path": "third_party/Dragablz/Dragablz/Referenceless/AnonymousDisposable.cs",
    "content": "﻿using System;\nusing System.Threading;\n\nnamespace Dragablz.Referenceless\n{\n    internal sealed class AnonymousDisposable : ICancelable, IDisposable\n    {\n        private volatile Action _dispose;\n\n        public bool IsDisposed\n        {\n            get\n            {\n                return this._dispose == null;\n            }\n        }\n\n        public AnonymousDisposable(Action dispose)\n        {\n            this._dispose = dispose;\n        }\n\n        public void Dispose()\n        {\n            var action = Interlocked.Exchange<Action>(ref _dispose, (Action)null);\n            if (action == null)\n                return;\n            action();\n        }\n    }\n}\n"
  },
  {
    "path": "third_party/Dragablz/Dragablz/Referenceless/DefaultDisposable.cs",
    "content": "﻿using System;\n\nnamespace Dragablz.Referenceless\n{\n    internal sealed class DefaultDisposable : IDisposable\n    {\n        public static readonly DefaultDisposable Instance = new DefaultDisposable();\n\n        static DefaultDisposable()\n        {\n        }\n\n        private DefaultDisposable()\n        {\n        }\n\n        public void Dispose()\n        {\n        }\n    }\n}\n"
  },
  {
    "path": "third_party/Dragablz/Dragablz/Referenceless/Disposable.cs",
    "content": "﻿using System;\n\nnamespace Dragablz.Referenceless\n{\n    internal static class Disposable\n    {\n        public static IDisposable Empty\n        {\n            get\n            {\n                return (IDisposable)DefaultDisposable.Instance;\n            }\n        }\n\n        public static IDisposable Create(Action dispose)\n        {\n            if (dispose == null)\n                throw new ArgumentNullException(\"dispose\");\n            else\n                return (IDisposable)new AnonymousDisposable(dispose);\n        }\n    }\n}\n"
  },
  {
    "path": "third_party/Dragablz/Dragablz/Referenceless/ICancelable.cs",
    "content": "﻿using System;\n\nnamespace Dragablz.Referenceless\n{\n    internal interface ICancelable : IDisposable\n    {\n        bool IsDisposed { get; }\n    }\n}\n"
  },
  {
    "path": "third_party/Dragablz/Dragablz/Referenceless/SerialDisposable.cs",
    "content": "﻿using System;\nusing System.Collections.Generic;\nusing System.Linq;\nusing System.Text;\nusing System.Threading.Tasks;\n\nnamespace Dragablz.Referenceless\n{\n    internal sealed class SerialDisposable : ICancelable, IDisposable\n    {\n        private readonly object _gate = new object();\n        private IDisposable _current;\n        private bool _disposed;\n\n        /// <summary>\n        /// Gets a value that indicates whether the object is disposed.\n        /// \n        /// </summary>\n        public bool IsDisposed\n        {\n            get\n            {\n                lock (this._gate)\n                    return this._disposed;\n            }\n        }\n\n        /// <summary>\n        /// Gets or sets the underlying disposable.\n        /// \n        /// </summary>\n        /// \n        /// <remarks>\n        /// If the SerialDisposable has already been disposed, assignment to this property causes immediate disposal of the given disposable object. Assigning this property disposes the previous disposable object.\n        /// </remarks>\n        public IDisposable Disposable\n        {\n            get\n            {\n                return this._current;\n            }\n            set\n            {\n                bool flag = false;\n                IDisposable disposable = (IDisposable)null;\n                lock (this._gate)\n                {\n                    flag = this._disposed;\n                    if (!flag)\n                    {\n                        disposable = this._current;\n                        this._current = value;\n                    }\n                }\n                if (disposable != null)\n                    disposable.Dispose();\n                if (!flag || value == null)\n                    return;\n                value.Dispose();\n            }\n        }\n\n        /// <summary>\n        /// Disposes the underlying disposable as well as all future replacements.\n        /// \n        /// </summary>\n        public void Dispose()\n        {\n            IDisposable disposable = (IDisposable)null;\n            lock (this._gate)\n            {\n                if (!this._disposed)\n                {\n                    this._disposed = true;\n                    disposable = this._current;\n                    this._current = (IDisposable)null;\n                }\n            }\n            if (disposable == null)\n                return;\n            disposable.Dispose();\n        }\n    }\n}\n"
  },
  {
    "path": "third_party/Dragablz/Dragablz/StackOrganiser.cs",
    "content": "﻿using System;\nusing System.Collections.Generic;\nusing System.Linq;\nusing System.Windows;\nusing System.Windows.Controls;\nusing System.Windows.Media.Animation;\nusing Dragablz.Core;\n\nnamespace Dragablz\n{\n    public abstract class StackOrganiser : IItemsOrganiser\n    {\n        private readonly Orientation _orientation;\n        private readonly double _itemOffset;\n        private readonly Func<DragablzItem, double> _getDesiredSize;\n        private readonly Func<DragablzItem, double> _getLocation;\n        private readonly DependencyProperty _canvasDependencyProperty;\n        private readonly Action<DragablzItem, double> _setLocation;\n\n        private readonly Dictionary<DragablzItem, double> _activeStoryboardTargetLocations =\n            new Dictionary<DragablzItem, double>();\n\n        protected StackOrganiser(Orientation orientation, double itemOffset = 0)\n        {\n            _orientation = orientation;\n            _itemOffset = itemOffset;\n\n            switch (orientation)\n            {\n                case Orientation.Horizontal:\n                    _getDesiredSize = item => item.DesiredSize.Width;\n                    _getLocation = item => item.X;\n                    _setLocation = (item, coord) => item.SetCurrentValue(DragablzItem.XProperty, coord);\n                    _canvasDependencyProperty = Canvas.LeftProperty;\n                    break;\n                case Orientation.Vertical:\n                    _getDesiredSize = item => item.DesiredSize.Height;\n                    _getLocation = item => item.Y;\n                    _setLocation = (item, coord) => item.SetCurrentValue(DragablzItem.YProperty, coord);\n                    _canvasDependencyProperty = Canvas.TopProperty;\n                    break;\n                default:\n                    throw new ArgumentOutOfRangeException(\"orientation\");\n            }\n        }\n\n        #region LocationInfo\n\n        private class LocationInfo\n        {\n            private readonly DragablzItem _item;\n            private readonly double _start;\n            private readonly double _mid;\n            private readonly double _end;\n\n            public LocationInfo(DragablzItem item, double start, double mid, double end)\n            {\n                _item = item;\n                _start = start;\n                _mid = mid;\n                _end = end;\n            }\n\n            public double Start\n            {\n                get { return _start; }\n            }\n\n            public double Mid\n            {\n                get { return _mid; }\n            }\n\n            public double End\n            {\n                get { return _end; }\n            }\n\n            public DragablzItem Item\n            {\n                get { return _item; }\n            }\n        }\n\n        #endregion\n\n        public virtual Orientation Orientation\n        {\n            get { return _orientation; }\n        }\n\n        public virtual void Organise(DragablzItemsControl requestor, Size measureBounds, IEnumerable<DragablzItem> items)\n        {\n            if (items == null) throw new ArgumentNullException(\"items\");\n\n            OrganiseInternal(\n                requestor, \n                measureBounds,\n                items.Select((di, idx) => new Tuple<int, DragablzItem>(idx, di))\n                        .OrderBy(tuple => tuple,\n                            MultiComparer<Tuple<int, DragablzItem>>.Ascending(tuple => _getLocation(tuple.Item2))\n                                .ThenAscending(tuple => tuple.Item1))\n                        .Select(tuple => tuple.Item2));            \n        }\n\n        public virtual void Organise(DragablzItemsControl requestor, Size measureBounds, IOrderedEnumerable<DragablzItem> items)\n        {\n            if (items == null) throw new ArgumentNullException(\"items\");\n\n            OrganiseInternal(\n                requestor,\n                measureBounds,\n                items);\n        }\n\n        private void OrganiseInternal(DragablzItemsControl requestor, Size measureBounds,\n            IEnumerable<DragablzItem> items)\n        {\n            var currentCoord = 0.0;\n            var z = int.MaxValue;\n            var logicalIndex = 0;\n            foreach (var newItem in items)\n            {\n                Panel.SetZIndex(newItem, newItem.IsSelected ? int.MaxValue : --z);\n                SetLocation(newItem, currentCoord);\n                newItem.LogicalIndex = logicalIndex++;\n                newItem.Measure(measureBounds);\n                var desiredSize = _getDesiredSize(newItem);\n                if (desiredSize == 0.0) desiredSize = 1.0; //no measure? create something to help sorting\n                currentCoord += desiredSize + _itemOffset;\n            }\n        }\n\n\n        public virtual void OrganiseOnMouseDownWithin(DragablzItemsControl requestor, Size measureBounds,\n            List<DragablzItem> siblingItems, DragablzItem dragablzItem)\n        {\n\n        }\n\n        private IDictionary<DragablzItem, LocationInfo> _siblingItemLocationOnDragStart;\n\n        public virtual void OrganiseOnDragStarted(DragablzItemsControl requestor, Size measureBounds,\n            IEnumerable<DragablzItem> siblingItems, DragablzItem dragItem)\n        {\n            if (siblingItems == null) throw new ArgumentNullException(\"siblingItems\");\n            if (dragItem == null) throw new ArgumentNullException(\"dragItem\");\n\n            _siblingItemLocationOnDragStart = siblingItems.Select(GetLocationInfo).ToDictionary(loc => loc.Item);\n        }\n\n        public virtual void OrganiseOnDrag(DragablzItemsControl requestor, Size measureBounds,\n            IEnumerable<DragablzItem> siblingItems, DragablzItem dragItem)\n        {\n            if (siblingItems == null) throw new ArgumentNullException(\"siblingItems\");\n            if (dragItem == null) throw new ArgumentNullException(\"dragItem\");\n\n            var currentLocations = siblingItems\n                .Select(GetLocationInfo)\n                .Union(new[] {GetLocationInfo(dragItem)})\n                .OrderBy(loc => loc.Item == dragItem ? loc.Start : _siblingItemLocationOnDragStart[loc.Item].Start);\n\n            var currentCoord = 0.0;\n            var zIndex = int.MaxValue;\n            foreach (var location in currentLocations)\n            {\n                if (!Equals(location.Item, dragItem))\n                {\n                    SendToLocation(location.Item, currentCoord);\n                    Panel.SetZIndex(location.Item, --zIndex);\n                }\n                currentCoord += _getDesiredSize(location.Item) + _itemOffset;                \n            }\n            Panel.SetZIndex(dragItem, int.MaxValue);\n        }\n\n        public virtual void OrganiseOnDragCompleted(DragablzItemsControl requestor, Size measureBounds,\n            IEnumerable<DragablzItem> siblingItems, DragablzItem dragItem)\n        {\n            if (siblingItems == null) throw new ArgumentNullException(\"siblingItems\");\n            var currentLocations = siblingItems\n                .Select(GetLocationInfo)\n                .Union(new[] {GetLocationInfo(dragItem)})\n                .OrderBy(loc => loc.Item == dragItem ? loc.Start : _siblingItemLocationOnDragStart[loc.Item].Start);\n\n            var currentCoord = 0.0;\n            var z = int.MaxValue;\n            var logicalIndex = 0;\n            foreach (var location in currentLocations)\n            {\n                SetLocation(location.Item, currentCoord);\n                currentCoord += _getDesiredSize(location.Item) + _itemOffset;\n                Panel.SetZIndex(location.Item, --z);\n                location.Item.LogicalIndex = logicalIndex++;\n            }\n            Panel.SetZIndex(dragItem, int.MaxValue);\n        }\n\n        public virtual Point ConstrainLocation(DragablzItemsControl requestor, Size measureBounds, Point itemCurrentLocation,\n            Size itemCurrentSize, Point itemDesiredLocation, Size itemDesiredSize)\n        {\n            var fixedItems = requestor.FixedItemCount;\n            var lowerBound = fixedItems == 0\n                ? -1d\n                : GetLocationInfo(requestor.DragablzItems()\n                    .Take(fixedItems)\n                    .Last()).End + _itemOffset - 1;\n\n            return new Point(\n                _orientation == Orientation.Vertical\n                    ? 0\n                    : Math.Min(Math.Max(lowerBound, itemDesiredLocation.X), (measureBounds.Width) + 1),\n                _orientation == Orientation.Horizontal\n                    ? 0\n                    : Math.Min(Math.Max(lowerBound, itemDesiredLocation.Y), (measureBounds.Height) + 1)\n                );\n        }\n\n        public virtual Size Measure(DragablzItemsControl requestor, Size availableSize, IEnumerable<DragablzItem> items)\n        {\n            if (items == null) throw new ArgumentNullException(\"items\");\n\n            var size = new Size(double.PositiveInfinity, double.PositiveInfinity);\n\n            double width = 0, height = 0;\n            var isFirst = true;\n            foreach (var dragablzItem in items)\n            {\n                dragablzItem.Measure(size);\n                if (_orientation == Orientation.Horizontal)\n                {\n                    width += !dragablzItem.IsLoaded ? dragablzItem.DesiredSize.Width : dragablzItem.ActualWidth;\n                    if (!isFirst)\n                        width += _itemOffset;\n                    height = Math.Max(height,\n                        !dragablzItem.IsLoaded ? dragablzItem.DesiredSize.Height : dragablzItem.ActualHeight);\n                }\n                else\n                {\n                    width = Math.Max(width,\n                        !dragablzItem.IsLoaded ? dragablzItem.DesiredSize.Width : dragablzItem.ActualWidth);\n                    height += !dragablzItem.IsLoaded ? dragablzItem.DesiredSize.Height : dragablzItem.ActualHeight;\n                    if (!isFirst)\n                        height += _itemOffset;\n                }\n\n                isFirst = false;\n            }\n\n            return new Size(Math.Max(width, 0), Math.Max(height, 0));\n        }\n\n        public virtual IEnumerable<DragablzItem> Sort(IEnumerable<DragablzItem> items)\n        {\n            if (items == null) throw new ArgumentNullException(\"items\");\n\n            return items.OrderBy(i => GetLocationInfo(i).Start);\n        }\n\n        private void SetLocation(DragablzItem dragablzItem, double location)\n        {                     \n            _setLocation(dragablzItem, location);\n        }\n        \n        private void SendToLocation(DragablzItem dragablzItem, double location)\n        {                        \n            double activeTarget;\n            if (Math.Abs(_getLocation(dragablzItem) - location) < 1.0\n                ||\n                _activeStoryboardTargetLocations.TryGetValue(dragablzItem, out activeTarget)\n                && Math.Abs(activeTarget - location) < 1.0)\n            {             \n                return;\n            }            \n\n            _activeStoryboardTargetLocations[dragablzItem] = location;\n\n            var storyboard = new Storyboard {FillBehavior = FillBehavior.Stop};\n            storyboard.WhenComplete(sb =>\n            {\n                _setLocation(dragablzItem, location);\n                sb.Remove(dragablzItem);\n                _activeStoryboardTargetLocations.Remove(dragablzItem);\n            });\n\n            var timeline = new DoubleAnimationUsingKeyFrames();\n            timeline.SetValue(Storyboard.TargetPropertyProperty, new PropertyPath(_canvasDependencyProperty));\n            timeline.KeyFrames.Add(\n                new EasingDoubleKeyFrame(location, KeyTime.FromTimeSpan(TimeSpan.FromMilliseconds(200)))\n                {\n                    EasingFunction = new CubicEase() { EasingMode = EasingMode.EaseOut }\n                });\n            storyboard.Children.Add(timeline);            \n            storyboard.Begin(dragablzItem, true);            \n        }\n\n        private LocationInfo GetLocationInfo(DragablzItem item)\n        {\n            var size = _getDesiredSize(item);\n            double startLocation;\n            if (!_activeStoryboardTargetLocations.TryGetValue(item, out startLocation))\n                startLocation = _getLocation(item);\n            var midLocation = startLocation + size / 2;\n            var endLocation = startLocation + size;\n\n            return new LocationInfo(item, startLocation, midLocation, endLocation);\n        }\n    }\n}"
  },
  {
    "path": "third_party/Dragablz/Dragablz/StackPositionMonitor.cs",
    "content": "﻿using System;\nusing System.Collections.Generic;\nusing System.Linq;\nusing System.Windows.Controls;\n\nnamespace Dragablz\n{\n    /// <summary>\n    /// A linear position monitor simplifies the montoring of the order of items, where they are laid out\n    /// horizontally or vertically (typically via a <see cref=\"StackOrganiser\"/>.\n    /// </summary>\n    public abstract class StackPositionMonitor : PositionMonitor\n    {\n        private readonly Func<DragablzItem, double> _getLocation;\n\n        protected StackPositionMonitor(Orientation orientation)\n        {\n            switch (orientation)\n            {\n                case Orientation.Horizontal:\n                    _getLocation = item => item.X;\n                    break;\n                case Orientation.Vertical:\n                    _getLocation = item => item.Y;\n                    break;\n                default:\n                    throw new ArgumentOutOfRangeException(\"orientation\");\n            }\n        }\n\n        public event EventHandler<OrderChangedEventArgs> OrderChanged;\n\n        internal virtual void OnOrderChanged(OrderChangedEventArgs e)\n        {\n            var handler = OrderChanged;\n            if (handler != null) handler(this, e);\n        }\n\n        internal IEnumerable<DragablzItem> Sort(IEnumerable<DragablzItem> items)\n        {\n            if (items == null) throw new ArgumentNullException(\"items\");\n\n            return items.OrderBy(i => _getLocation(i));\n        }\n    }\n}"
  },
  {
    "path": "third_party/Dragablz/Dragablz/StoryboardCompletionListener.cs",
    "content": "using System;\nusing System.Collections;\nusing System.Collections.Generic;\nusing System.Windows.Media.Animation;\n\nnamespace Dragablz\n{\n    internal class StoryboardCompletionListener\n    {\n        private readonly Storyboard _storyboard;\n        private readonly Action<Storyboard> _continuation;\n\n        public StoryboardCompletionListener(Storyboard storyboard, Action<Storyboard> continuation)\n        {\n            if (storyboard == null) throw new ArgumentNullException(\"storyboard\");\n            if (continuation == null) throw new ArgumentNullException(\"continuation\");\n\n            _storyboard = storyboard;\n            _continuation = continuation;\n\n            _storyboard.Completed += StoryboardOnCompleted;\n        }\n\n        private void StoryboardOnCompleted(object sender, EventArgs eventArgs)\n        {\n            _storyboard.Completed -= StoryboardOnCompleted;\n            _continuation(_storyboard);\n        }\n    }\n\n    internal static class StoryboardCompletionListenerExtension\n    {\n        private static readonly IDictionary<Storyboard, Action<Storyboard>> ContinuationIndex = new Dictionary<Storyboard, Action<Storyboard>>();        \n\n        public static void WhenComplete(this Storyboard storyboard, Action<Storyboard> continuation)\n        {\n// ReSharper disable once ObjectCreationAsStatement\n            new StoryboardCompletionListener(storyboard, continuation);\n        }        \n    }\n}"
  },
  {
    "path": "third_party/Dragablz/Dragablz/TabEmptiedResponse.cs",
    "content": "namespace Dragablz\n{\n    public enum TabEmptiedResponse\n    {\n        /// <summary>\n        /// Allow the Window to be closed automatically.\n        /// </summary>\n        CloseWindowOrLayoutBranch,\n        /// <summary>\n        /// The window will not be closed by the <see cref=\"TabablzControl\"/>, probably meaning the implementor will close the window manually\n        /// </summary>\n        DoNothing\n    }\n}"
  },
  {
    "path": "third_party/Dragablz/Dragablz/TabablzControl.cs",
    "content": "﻿using System;\nusing System.Collections;\nusing System.Collections.Generic;\nusing System.Collections.Specialized;\nusing System.ComponentModel;\nusing System.Linq;\nusing System.Windows;\nusing System.Windows.Automation.Peers;\nusing System.Windows.Controls;\nusing System.Windows.Controls.Primitives;\nusing System.Windows.Data;\nusing System.Windows.Input;\nusing System.Windows.Media;\nusing System.Windows.Threading;\nusing Dragablz.Core;\nusing Dragablz.Dockablz;\nusing Dragablz.Referenceless;\n\nnamespace Dragablz\n{\n    //original code specific to keeping visual tree \"alive\" sourced from http://stackoverflow.com/questions/12432062/binding-to-itemssource-of-tabcontrol-in-wpf    \n\n    /// <summary>\n    /// Extended tab control which supports tab repositioning, and drag and drop.  Also \n    /// uses the common WPF technique for pesisting the visual tree across tabs.\n    /// </summary>\n    [TemplatePart(Name = HeaderItemsControlPartName, Type = typeof(DragablzItemsControl))]\n    [TemplatePart(Name = ItemsHolderPartName, Type = typeof(Panel))]\n    public class TabablzControl : TabControl\n    {\n        /// <summary>\n        /// Template part.\n        /// </summary>\n        public const string HeaderItemsControlPartName = \"PART_HeaderItemsControl\";\n        /// <summary>\n        /// Template part.\n        /// </summary>\n        public const string ItemsHolderPartName = \"PART_ItemsHolder\";\n\n        /// <summary>\n        /// Routed command which can be used to close a tab.\n        /// </summary>\n        public static RoutedCommand CloseItemCommand = new RoutedUICommand(\"Close\", \"Close\", typeof(TabablzControl));\n\n        /// <summary>\n        /// Routed command which can be used to add a new tab.  See <see cref=\"NewItemFactory\"/>.\n        /// </summary>\n        public static RoutedCommand AddItemCommand = new RoutedUICommand(\"Add\", \"Add\", typeof(TabablzControl));\n\n        private static readonly HashSet<TabablzControl> LoadedInstances = new HashSet<TabablzControl>();\n        private static readonly HashSet<TabablzControl> VisibleInstances = new HashSet<TabablzControl>();\n\n        private Panel _itemsHolder;\n        private TabHeaderDragStartInformation _tabHeaderDragStartInformation;\n        private WeakReference _previousSelection;        \n        private DragablzItemsControl _dragablzItemsControl;\n        private IDisposable _templateSubscription;\n        private readonly SerialDisposable _windowSubscription = new SerialDisposable();\n\n        private InterTabTransfer _interTabTransfer;\n\n        static TabablzControl()\n        {\n            DefaultStyleKeyProperty.OverrideMetadata(typeof(TabablzControl), new FrameworkPropertyMetadata(typeof(TabablzControl)));\n            CommandManager.RegisterClassCommandBinding(typeof(FrameworkElement), new CommandBinding(CloseItemCommand, CloseItemClassHandler, CloseItemCanExecuteClassHandler));\n        }\n        \n        /// <summary>\n        /// Default constructor.\n        /// </summary>\n        public TabablzControl()\n        {            \n            AddHandler(DragablzItem.DragStarted, new DragablzDragStartedEventHandler(ItemDragStarted), true);\n            AddHandler(DragablzItem.PreviewDragDelta, new DragablzDragDeltaEventHandler(PreviewItemDragDelta), true);\n            AddHandler(DragablzItem.DragDelta, new DragablzDragDeltaEventHandler(ItemDragDelta), true);\n            AddHandler(DragablzItem.DragCompleted, new DragablzDragCompletedEventHandler(ItemDragCompleted), true);                        \n            CommandBindings.Add(new CommandBinding(AddItemCommand, AddItemHandler));                        \n\n            Loaded += OnLoaded;\n            Unloaded += OnUnloaded;            \n            IsVisibleChanged += OnIsVisibleChanged;            \n        }\n\n        public static readonly DependencyProperty CustomHeaderItemStyleProperty = DependencyProperty.Register(\n            \"CustomHeaderItemStyle\", typeof (Style), typeof (TabablzControl), new PropertyMetadata(default(Style)));\n\n        /// <summary>\n        /// Helper method which returns all the currently loaded instances.\n        /// </summary>\n        /// <returns></returns>\n        public static IEnumerable<TabablzControl> GetLoadedInstances()\n        {\n            return LoadedInstances.Union(VisibleInstances).Distinct().ToList();\n        }\n\n        /// <summary>\n        /// Helper method to close all tabs where the item is the tab's content (helpful with MVVM scenarios)\n        /// </summary>\n        /// <remarks>\n        /// In MVVM scenarios where you don't want to bind the routed command to your ViewModel,\n        /// with this helper method and embedding the TabablzControl in a UserControl, you can keep\n        /// the View-specific dependencies out of the ViewModel.\n        /// </remarks>\n        /// <param name=\"tabContentItem\">An existing Tab item content (a ViewModel in MVVM scenarios) which is backing a tab control</param>\n        public static void CloseItem(object tabContentItem)\n        {\n            if (tabContentItem == null) return; //Do nothing.\n\n            //Find all loaded TabablzControl instances with tabs backed by this item and close them\n            foreach(var tabWithItemContent in \n                GetLoadedInstances().SelectMany(tc => \n                tc._dragablzItemsControl.DragablzItems().Where(di => di.Content.Equals(tabContentItem)).Select(di => new { tc, di })))\n            {\n                TabablzControl.CloseItem(tabWithItemContent.di, tabWithItemContent.tc);\n            }\n        }\n\n        /// <summary>\n        /// Helper method to add an item next to an existing item.\n        /// </summary>\n        /// <remarks>\n        /// Due to the organisable nature of the control, the order of items may not reflect the order in the source collection.  This method\n        /// will add items to the source collection, managing their initial appearance on screen at the same time. \n        /// If you are using a <see cref=\"InterTabController.InterTabClient\"/> this will be used to add the item into the source collection.\n        /// </remarks>\n        /// <param name=\"item\">New item to add.</param>\n        /// <param name=\"nearItem\">Existing object/tab item content which defines which tab control should be used to add the object.</param>\n        /// <param name=\"addLocationHint\">Location, relative to the <paramref name=\"nearItem\"/> object</param>\n        public static void AddItem(object item, object nearItem, AddLocationHint addLocationHint)\n        {\n            if (nearItem == null) throw new ArgumentNullException(\"nearItem\");\n\n            var existingLocation = GetLoadedInstances().SelectMany(tabControl =>\n                (tabControl.ItemsSource ?? tabControl.Items).OfType<object>()\n                    .Select(existingObject => new {tabControl, existingObject}))\n                .SingleOrDefault(a => nearItem.Equals(a.existingObject));\n\n            if (existingLocation == null)\n                throw new ArgumentException(\"Did not find precisely one instance of adjacentTo\", \"nearItem\");            \n            \n            existingLocation.tabControl.AddToSource(item);\n            if (existingLocation.tabControl._dragablzItemsControl != null)\n                existingLocation.tabControl._dragablzItemsControl.MoveItem(new MoveItemRequest(item, nearItem, addLocationHint));\n        }\n\n        /// <summary>\n        /// Finds and selects an item.\n        /// </summary>\n        /// <param name=\"item\"></param>\n        public static void SelectItem(object item)\n        {\n            var existingLocation = GetLoadedInstances().SelectMany(tabControl =>\n                (tabControl.ItemsSource ?? tabControl.Items).OfType<object>()\n                    .Select(existingObject => new {tabControl, existingObject}))\n                    .FirstOrDefault(a => item.Equals(a.existingObject));\n\n            if (existingLocation == null) return;\n\n            existingLocation.tabControl.SelectedItem = item;\n        }        \n\n        /// <summary>\n        /// Style to apply to header items which are not their own item container (<see cref=\"TabItem\"/>).  Typically items bound via the <see cref=\"ItemsSource\"/> will use this style.\n        /// </summary>\n        [Obsolete]\n        public Style CustomHeaderItemStyle\n        {\n            get { return (Style) GetValue(CustomHeaderItemStyleProperty); }\n            set { SetValue(CustomHeaderItemStyleProperty, value); }\n        }\n\n        public static readonly DependencyProperty CustomHeaderItemTemplateProperty = DependencyProperty.Register(\n            \"CustomHeaderItemTemplate\", typeof (DataTemplate), typeof (TabablzControl), new PropertyMetadata(default(DataTemplate)));\n\n        [Obsolete(\"Prefer HeaderItemTemplate\")]\n        public DataTemplate CustomHeaderItemTemplate\n        {\n            get { return (DataTemplate) GetValue(CustomHeaderItemTemplateProperty); }\n            set { SetValue(CustomHeaderItemTemplateProperty, value); }\n        }\n\n        public static readonly DependencyProperty DefaultHeaderItemStyleProperty = DependencyProperty.Register(\n            \"DefaultHeaderItemStyle\", typeof (Style), typeof (TabablzControl), new PropertyMetadata(default(Style)));        \n\n        [Obsolete]\n        public Style DefaultHeaderItemStyle\n        {\n            get { return (Style) GetValue(DefaultHeaderItemStyleProperty); }\n            set { SetValue(DefaultHeaderItemStyleProperty, value); }\n        }\n\n        public static readonly DependencyProperty AdjacentHeaderItemOffsetProperty = DependencyProperty.Register(\n            \"AdjacentHeaderItemOffset\", typeof (double), typeof (TabablzControl), new PropertyMetadata(default(double), AdjacentHeaderItemOffsetPropertyChangedCallback));\n\n        private static void AdjacentHeaderItemOffsetPropertyChangedCallback(DependencyObject dependencyObject, DependencyPropertyChangedEventArgs dependencyPropertyChangedEventArgs)\n        {\n            dependencyObject.SetValue(HeaderItemsOrganiserProperty, new HorizontalOrganiser((double)dependencyPropertyChangedEventArgs.NewValue));\n        }\n\n        public double AdjacentHeaderItemOffset\n        {\n            get { return (double) GetValue(AdjacentHeaderItemOffsetProperty); }\n            set { SetValue(AdjacentHeaderItemOffsetProperty, value); }\n        }\n\n        public static readonly DependencyProperty HeaderItemsOrganiserProperty = DependencyProperty.Register(\n            \"HeaderItemsOrganiser\", typeof (IItemsOrganiser), typeof (TabablzControl), new PropertyMetadata(new HorizontalOrganiser()));\n\n        public IItemsOrganiser HeaderItemsOrganiser\n        {\n            get { return (IItemsOrganiser) GetValue(HeaderItemsOrganiserProperty); }\n            set { SetValue(HeaderItemsOrganiserProperty, value); }\n        }\n\n        public static readonly DependencyProperty HeaderMemberPathProperty = DependencyProperty.Register(\n            \"HeaderMemberPath\", typeof (string), typeof (TabablzControl), new PropertyMetadata(default(string)));\n\n        public string HeaderMemberPath\n        {\n            get { return (string) GetValue(HeaderMemberPathProperty); }\n            set { SetValue(HeaderMemberPathProperty, value); }\n        }\n\n        public static readonly DependencyProperty HeaderItemTemplateProperty = DependencyProperty.Register(\n            \"HeaderItemTemplate\", typeof (DataTemplate), typeof (TabablzControl), new PropertyMetadata(default(DataTemplate)));\n\n        public DataTemplate HeaderItemTemplate\n        {\n            get { return (DataTemplate) GetValue(HeaderItemTemplateProperty); }\n            set { SetValue(HeaderItemTemplateProperty, value); }\n        }\n\n        public static readonly DependencyProperty HeaderPrefixContentProperty = DependencyProperty.Register(\n            \"HeaderPrefixContent\", typeof (object), typeof (TabablzControl), new PropertyMetadata(default(object)));\n\n        public object HeaderPrefixContent\n        {\n            get { return (object) GetValue(HeaderPrefixContentProperty); }\n            set { SetValue(HeaderPrefixContentProperty, value); }\n        }\n\n        public static readonly DependencyProperty HeaderPrefixContentStringFormatProperty = DependencyProperty.Register(\n            \"HeaderPrefixContentStringFormat\", typeof (string), typeof (TabablzControl), new PropertyMetadata(default(string)));\n\n        public string HeaderPrefixContentStringFormat\n        {\n            get { return (string) GetValue(HeaderPrefixContentStringFormatProperty); }\n            set { SetValue(HeaderPrefixContentStringFormatProperty, value); }\n        }\n\n        public static readonly DependencyProperty HeaderPrefixContentTemplateProperty = DependencyProperty.Register(\n            \"HeaderPrefixContentTemplate\", typeof (DataTemplate), typeof (TabablzControl), new PropertyMetadata(default(DataTemplate)));\n\n        public DataTemplate HeaderPrefixContentTemplate\n        {\n            get { return (DataTemplate) GetValue(HeaderPrefixContentTemplateProperty); }\n            set { SetValue(HeaderPrefixContentTemplateProperty, value); }\n        }\n\n        public static readonly DependencyProperty HeaderPrefixContentTemplateSelectorProperty = DependencyProperty.Register(\n            \"HeaderPrefixContentTemplateSelector\", typeof (DataTemplateSelector), typeof (TabablzControl), new PropertyMetadata(default(DataTemplateSelector)));\n\n        public DataTemplateSelector HeaderPrefixContentTemplateSelector\n        {\n            get { return (DataTemplateSelector) GetValue(HeaderPrefixContentTemplateSelectorProperty); }\n            set { SetValue(HeaderPrefixContentTemplateSelectorProperty, value); }\n        }\n\n        public static readonly DependencyProperty HeaderSuffixContentProperty = DependencyProperty.Register(\n                    \"HeaderSuffixContent\", typeof(object), typeof(TabablzControl), new PropertyMetadata(default(object)));\n\n        public object HeaderSuffixContent\n        {\n            get { return (object)GetValue(HeaderSuffixContentProperty); }\n            set { SetValue(HeaderSuffixContentProperty, value); }\n        }\n\n        public static readonly DependencyProperty HeaderSuffixContentStringFormatProperty = DependencyProperty.Register(\n            \"HeaderSuffixContentStringFormat\", typeof(string), typeof(TabablzControl), new PropertyMetadata(default(string)));\n\n        public string HeaderSuffixContentStringFormat\n        {\n            get { return (string)GetValue(HeaderSuffixContentStringFormatProperty); }\n            set { SetValue(HeaderSuffixContentStringFormatProperty, value); }\n        }\n\n        public static readonly DependencyProperty HeaderSuffixContentTemplateProperty = DependencyProperty.Register(\n            \"HeaderSuffixContentTemplate\", typeof(DataTemplate), typeof(TabablzControl), new PropertyMetadata(default(DataTemplate)));\n\n        public DataTemplate HeaderSuffixContentTemplate\n        {\n            get { return (DataTemplate)GetValue(HeaderSuffixContentTemplateProperty); }\n            set { SetValue(HeaderSuffixContentTemplateProperty, value); }\n        }\n\n        public static readonly DependencyProperty HeaderSuffixContentTemplateSelectorProperty = DependencyProperty.Register(\n            \"HeaderSuffixContentTemplateSelector\", typeof(DataTemplateSelector), typeof(TabablzControl), new PropertyMetadata(default(DataTemplateSelector)));\n\n        public DataTemplateSelector HeaderSuffixContentTemplateSelector\n        {\n            get { return (DataTemplateSelector)GetValue(HeaderSuffixContentTemplateSelectorProperty); }\n            set { SetValue(HeaderSuffixContentTemplateSelectorProperty, value); }\n        }\n\n        public static readonly DependencyProperty ShowDefaultCloseButtonProperty = DependencyProperty.Register(\n            \"ShowDefaultCloseButton\", typeof (bool), typeof (TabablzControl), new PropertyMetadata(default(bool)));\n\n        /// <summary>\n        /// Indicates whether a default close button should be displayed.  If manually templating the tab header content the close command \n        /// can be called by executing the <see cref=\"TabablzControl.CloseItemCommand\"/> command (typically via a <see cref=\"Button\"/>).\n        /// </summary>\n        public bool ShowDefaultCloseButton\n        {\n            get { return (bool) GetValue(ShowDefaultCloseButtonProperty); }\n            set { SetValue(ShowDefaultCloseButtonProperty, value); }\n        }\n\n        public static readonly DependencyProperty ShowDefaultAddButtonProperty = DependencyProperty.Register(\n            \"ShowDefaultAddButton\", typeof (bool), typeof (TabablzControl), new PropertyMetadata(default(bool)));\n\n        /// <summary>\n        /// Indicates whether a default add button should be displayed.  Alternately an add button\n        /// could be added in <see cref=\"HeaderPrefixContent\"/> or <see cref=\"HeaderSuffixContent\"/>, utilising \n        /// <see cref=\"AddItemCommand\"/>.\n        /// </summary>\n        public bool ShowDefaultAddButton\n        {\n            get { return (bool) GetValue(ShowDefaultAddButtonProperty); }\n            set { SetValue(ShowDefaultAddButtonProperty, value); }\n        }\n\n        public static readonly DependencyProperty IsHeaderPanelVisibleProperty = DependencyProperty.Register(\n            \"IsHeaderPanelVisible\", typeof(bool), typeof(TabablzControl), new PropertyMetadata(true));\n\n        /// <summary>\n        /// Indicates wither the heaeder panel is visible.  Default is <c>true</c>.\n        /// </summary>\n        public bool IsHeaderPanelVisible\n        {\n            get { return (bool)GetValue(IsHeaderPanelVisibleProperty); }\n            set { SetValue(IsHeaderPanelVisibleProperty, value); }\n        }\n\n        public static readonly DependencyProperty AddLocationHintProperty = DependencyProperty.Register(\n            \"AddLocationHint\", typeof (AddLocationHint), typeof (TabablzControl), new PropertyMetadata(AddLocationHint.Last));\n\n        /// <summary>\n        /// Gets or sets the location to add new tab items in the header.\n        /// </summary>\n        /// <remarks>\n        /// The logical order of the header items might not add match the content of the source items,\n        /// so this property allows control of where new items should appear.\n        /// </remarks>\n        public AddLocationHint AddLocationHint\n        {\n            get { return (AddLocationHint) GetValue(AddLocationHintProperty); }\n            set { SetValue(AddLocationHintProperty, value); }\n        }\n\n        public static readonly DependencyProperty FixedHeaderCountProperty = DependencyProperty.Register(\n            \"FixedHeaderCount\", typeof (int), typeof (TabablzControl), new PropertyMetadata(default(int)));\n\n        /// <summary>\n        /// Allows a the first adjacent tabs to be fixed (no dragging, and default close button will not show).\n        /// </summary>\n        public int FixedHeaderCount\n        {\n            get { return (int) GetValue(FixedHeaderCountProperty); }\n            set { SetValue(FixedHeaderCountProperty, value); }\n        }\n\n        public static readonly DependencyProperty InterTabControllerProperty = DependencyProperty.Register(\n            \"InterTabController\", typeof (InterTabController), typeof (TabablzControl), new PropertyMetadata(null, InterTabControllerPropertyChangedCallback));\n\n        private static void InterTabControllerPropertyChangedCallback(DependencyObject dependencyObject, DependencyPropertyChangedEventArgs dependencyPropertyChangedEventArgs)\n        {\n            var instance = (TabablzControl)dependencyObject;\n            if (dependencyPropertyChangedEventArgs.OldValue != null)\n                instance.RemoveLogicalChild(dependencyPropertyChangedEventArgs.OldValue);\n            if (dependencyPropertyChangedEventArgs.NewValue != null)\n                instance.AddLogicalChild(dependencyPropertyChangedEventArgs.NewValue);\n        }\n\n        /// <summary>\n        /// An <see cref=\"InterTabController\"/> must be provided to enable tab tearing. Behaviour customisations can be applied\n        /// vie the controller.\n        /// </summary>\n        public InterTabController InterTabController\n        {\n            get { return (InterTabController) GetValue(InterTabControllerProperty); }\n            set { SetValue(InterTabControllerProperty, value); }\n        }\n\n        /// <summary>\n        /// Allows a factory to be provided for generating new items. Typically used in conjunction with <see cref=\"AddItemCommand\"/>.\n        /// </summary>\n        public static readonly DependencyProperty NewItemFactoryProperty = DependencyProperty.Register(\n            \"NewItemFactory\", typeof (Func<object>), typeof (TabablzControl), new PropertyMetadata(default(Func<object>)));\n\n        /// <summary>\n        /// Allows a factory to be provided for generating new items. Typically used in conjunction with <see cref=\"AddItemCommand\"/>.\n        /// </summary>\n        public Func<object> NewItemFactory\n        {\n            get { return (Func<object>) GetValue(NewItemFactoryProperty); }\n            set { SetValue(NewItemFactoryProperty, value); }\n        }\n\n        private static readonly DependencyPropertyKey IsEmptyPropertyKey =\n            DependencyProperty.RegisterReadOnly(\n                \"IsEmpty\", typeof (bool), typeof (TabablzControl),\n                new PropertyMetadata(true, OnIsEmptyChanged));\n\n        /// <summary>\n        /// Indicates if there are no current tab items.\n        /// </summary>\n        public static readonly DependencyProperty IsEmptyProperty =\n            IsEmptyPropertyKey.DependencyProperty;\n\n        /// <summary>\n        /// Indicates if there are no current tab items.\n        /// </summary>\n        public bool IsEmpty\n        {\n            get { return (bool) GetValue(IsEmptyProperty); }\n            private set { SetValue(IsEmptyPropertyKey, value); }\n        }\n\n        /// <summary>\n        /// Raised when <see cref=\"IsEmpty\"/> changes.\n        /// </summary>\n        public static readonly RoutedEvent IsEmptyChangedEvent =\n            EventManager.RegisterRoutedEvent(\n                \"IsEmptyChanged\",\n                RoutingStrategy.Bubble,\n                typeof (RoutedPropertyChangedEventHandler<bool>),\n                typeof (TabablzControl));\n\n        /// <summary>\n        /// Event handler to list to <see cref=\"IsEmptyChangedEvent\"/>.\n        /// </summary>\n        public event RoutedPropertyChangedEventHandler<bool> IsEmptyChanged\n        {\n            add { AddHandler(IsEmptyChangedEvent, value); }\n            remove { RemoveHandler(IsEmptyChangedEvent, value); }\n        }\n\n        private static void OnIsEmptyChanged(\n            DependencyObject d, DependencyPropertyChangedEventArgs e)\n        {\n            var instance = d as TabablzControl;\n            var args = new RoutedPropertyChangedEventArgs<bool>(\n                (bool) e.OldValue,\n                (bool) e.NewValue) {RoutedEvent = IsEmptyChangedEvent};\n            instance?.RaiseEvent(args);\n        } \n\n        /// <summary>\n        /// Optionally allows a close item hook to be bound in.  If this propety is provided, the func must return true for the close to continue.\n        /// </summary>\n        public static readonly DependencyProperty ClosingItemCallbackProperty = DependencyProperty.Register(\n            \"ClosingItemCallback\", typeof(ItemActionCallback), typeof(TabablzControl), new PropertyMetadata(default(ItemActionCallback)));\n\n        /// <summary>\n        /// Optionally allows a close item hook to be bound in.  If this propety is provided, the func must return true for the close to continue.\n        /// </summary>\n        public ItemActionCallback ClosingItemCallback\n        {\n            get { return (ItemActionCallback)GetValue(ClosingItemCallbackProperty); }\n            set { SetValue(ClosingItemCallbackProperty, value); }\n        }\n\n        /// <summary>\n        /// Set to <c>true</c> to have tabs automatically be moved to another tab is a window is closed, so that they arent lost.\n        /// Can be useful for fixed/persistant tabs that may have been dragged into another Window.  You can further control\n        /// this behaviour on a per tab item basis by providing <see cref=\"ConsolidatingOrphanedItemCallback\" />.\n        /// </summary>\n        public static readonly DependencyProperty ConsolidateOrphanedItemsProperty = DependencyProperty.Register(\n            \"ConsolidateOrphanedItems\", typeof (bool), typeof (TabablzControl), new PropertyMetadata(default(bool)));\n\n        /// <summary>\n        /// Set to <c>true</c> to have tabs automatically be moved to another tab is a window is closed, so that they arent lost.\n        /// Can be useful for fixed/persistant tabs that may have been dragged into another Window.  You can further control\n        /// this behaviour on a per tab item basis by providing <see cref=\"ConsolidatingOrphanedItemCallback\" />.\n        /// </summary>\n        public bool ConsolidateOrphanedItems\n        {\n            get { return (bool) GetValue(ConsolidateOrphanedItemsProperty); }\n            set { SetValue(ConsolidateOrphanedItemsProperty, value); }\n        }\n\n        /// <summary>\n        /// Assuming <see cref=\"ConsolidateOrphanedItems\"/> is set to <c>true</c>, consolidation of individual\n        /// tab items can be cancelled by providing this call back and cancelling the <see cref=\"ItemActionCallbackArgs{TOwner}\"/>\n        /// instance.\n        /// </summary>\n        public static readonly DependencyProperty ConsolidatingOrphanedItemCallbackProperty = DependencyProperty.Register(\n            \"ConsolidatingOrphanedItemCallback\", typeof (ItemActionCallback), typeof (TabablzControl), new PropertyMetadata(default(ItemActionCallback)));\n\n        /// <summary>\n        /// Assuming <see cref=\"ConsolidateOrphanedItems\"/> is set to <c>true</c>, consolidation of individual\n        /// tab items can be cancelled by providing this call back and cancelling the <see cref=\"ItemActionCallbackArgs{TOwner}\"/>\n        /// instance.\n        /// </summary>\n        public ItemActionCallback ConsolidatingOrphanedItemCallback\n        {\n            get { return (ItemActionCallback) GetValue(ConsolidatingOrphanedItemCallbackProperty); }\n            set { SetValue(ConsolidatingOrphanedItemCallbackProperty, value); }\n        }\n\n        \n\n        private static readonly DependencyPropertyKey IsDraggingWindowPropertyKey =\n            DependencyProperty.RegisterReadOnly(\n                \"IsDraggingWindow\", typeof (bool), typeof (TabablzControl),\n                new PropertyMetadata(default(bool), OnIsDraggingWindowChanged));\n\n        /// <summary>\n        /// Readonly dependency property which indicates whether the owning <see cref=\"Window\"/> \n        /// is currently dragged \n        /// </summary>\n        public static readonly DependencyProperty IsDraggingWindowProperty =\n            IsDraggingWindowPropertyKey.DependencyProperty;\n\n        /// <summary>\n        /// Readonly dependency property which indicates whether the owning <see cref=\"Window\"/> \n        /// is currently dragged \n        /// </summary>\n        public bool IsDraggingWindow\n        {\n            get { return (bool) GetValue(IsDraggingWindowProperty); }\n            private set { SetValue(IsDraggingWindowPropertyKey, value); }\n        }\n\n        /// <summary>\n        /// Event indicating <see cref=\"IsDraggingWindow\"/> has changed.\n        /// </summary>\n        public static readonly RoutedEvent IsDraggingWindowChangedEvent =\n            EventManager.RegisterRoutedEvent(\n                \"IsDraggingWindowChanged\",\n                RoutingStrategy.Bubble,\n                typeof (RoutedPropertyChangedEventHandler<bool>),\n                typeof (TabablzControl));\n\n        /// <summary>\n        /// Event indicating <see cref=\"IsDraggingWindow\"/> has changed.\n        /// </summary>\n        public event RoutedPropertyChangedEventHandler<bool> IsDraggingWindowChanged\n        {\n            add { AddHandler(IsDraggingWindowChangedEvent, value); }\n            remove { RemoveHandler(IsDraggingWindowChangedEvent, value); }\n        }\n\n        private static void OnIsDraggingWindowChanged(\n            DependencyObject d, DependencyPropertyChangedEventArgs e)\n        {\n            var instance = (TabablzControl) d;\n            var args = new RoutedPropertyChangedEventArgs<bool>(\n                (bool) e.OldValue,\n                (bool) e.NewValue)\n            {\n                RoutedEvent = IsDraggingWindowChangedEvent\n            };\n            instance.RaiseEvent(args);\n            \n        }\n\n        /// <summary>\n        /// Temporarily set by the framework if a users drag opration causes a Window to close (e.g if a tab is dragging into another tab).\n        /// </summary>\n        public static readonly DependencyProperty IsClosingAsPartOfDragOperationProperty = DependencyProperty.RegisterAttached(\n            \"IsClosingAsPartOfDragOperation\", typeof (bool), typeof (TabablzControl), new FrameworkPropertyMetadata(default(bool), FrameworkPropertyMetadataOptions.NotDataBindable));\n\n        internal static void SetIsClosingAsPartOfDragOperation(Window element, bool value)\n        {\n            element.SetValue(IsClosingAsPartOfDragOperationProperty, value);\n        }\n\n        /// <summary>\n        /// Helper method which can tell you if a <see cref=\"Window\"/> is being automatically closed due\n        /// to a user instigated drag operation (typically when a single tab is dropped into another window.\n        /// </summary>\n        /// <param name=\"element\"></param>\n        /// <returns></returns>\n        public static bool GetIsClosingAsPartOfDragOperation(Window element)\n        {\n            return (bool) element.GetValue(IsClosingAsPartOfDragOperationProperty);\n        }\n\n        /// <summary>\n        /// Provide a hint for how the header should size itself if there are no tabs left (and a Window is still open).\n        /// </summary>\n        public static readonly DependencyProperty EmptyHeaderSizingHintProperty = DependencyProperty.Register(\n            \"EmptyHeaderSizingHint\", typeof (EmptyHeaderSizingHint), typeof (TabablzControl), new PropertyMetadata(default(EmptyHeaderSizingHint)));\n\n        /// <summary>\n        /// Provide a hint for how the header should size itself if there are no tabs left (and a Window is still open).\n        /// </summary>\n        public EmptyHeaderSizingHint EmptyHeaderSizingHint\n        {\n            get { return (EmptyHeaderSizingHint) GetValue(EmptyHeaderSizingHintProperty); }\n            set { SetValue(EmptyHeaderSizingHintProperty, value); }\n        }\n\n        public static readonly DependencyProperty IsWrappingTabItemProperty = DependencyProperty.RegisterAttached(\n            \"IsWrappingTabItem\", typeof (bool), typeof (TabablzControl), new PropertyMetadata(default(bool)));\n\n        internal static void SetIsWrappingTabItem(DependencyObject element, bool value)\n        {\n            element.SetValue(IsWrappingTabItemProperty, value);\n        }\n\n        public static bool GetIsWrappingTabItem(DependencyObject element)\n        {\n            return (bool) element.GetValue(IsWrappingTabItemProperty);\n        }\n\n        /// <summary>\n        /// Adds an item to the source collection.  If the InterTabController.InterTabClient is set that instance will be deferred to.\n        /// Otherwise an attempt will be made to add to the <see cref=\"ItemsSource\" /> property, and lastly <see cref=\"Items\"/>.\n        /// </summary>\n        /// <param name=\"item\"></param>\n        public void AddToSource(object item)\n        {\n            if (item == null) throw new ArgumentNullException(\"item\");\n\n            var manualInterTabClient = InterTabController == null ? null : InterTabController.InterTabClient as IManualInterTabClient;\n            if (manualInterTabClient != null)\n            {\n                manualInterTabClient.Add(item);\n            }\n            else\n            {\n                CollectionTeaser collectionTeaser;\n                if (CollectionTeaser.TryCreate(ItemsSource, out collectionTeaser))\n                    collectionTeaser.Add(item);\n                else\n                    Items.Add(item);\n            }\n        }\n\n        /// <summary>\n        /// Removes an item from the source collection.  If the InterTabController.InterTabClient is set that instance will be deferred to.\n        /// Otherwise an attempt will be made to remove from the <see cref=\"ItemsSource\" /> property, and lastly <see cref=\"Items\"/>.\n        /// </summary>\n        /// <param name=\"item\"></param>\n        public void RemoveFromSource(object item)\n        {\n            if (item == null) throw new ArgumentNullException(\"item\");\n\n            var manualInterTabClient = InterTabController == null ? null : InterTabController.InterTabClient as IManualInterTabClient;\n            if (manualInterTabClient != null)\n            {\n                manualInterTabClient.Remove(item);\n            }\n            else\n            {\n                CollectionTeaser collectionTeaser;\n                if (CollectionTeaser.TryCreate(ItemsSource, out collectionTeaser))\n                    collectionTeaser.Remove(item);\n                else\n                    Items.Remove(item);\n            }\n        }\n\n        /// <summary>\n        /// Gets the header items, ordered according to their current visual position in the tab header.\n        /// </summary>\n        /// <returns></returns>\n        public IEnumerable<DragablzItem> GetOrderedHeaders()\n        {\n            return _dragablzItemsControl.ItemsOrganiser.Sort(_dragablzItemsControl.DragablzItems());\n        }\n\n        /// <summary>\n        /// Called when <see cref=\"M:System.Windows.FrameworkElement.ApplyTemplate\"/> is called.\n        /// </summary>\n        public override void OnApplyTemplate()\n        {\n            _templateSubscription?.Dispose();\n            _templateSubscription = Disposable.Empty;\n\n            _dragablzItemsControl = GetTemplateChild(HeaderItemsControlPartName) as DragablzItemsControl;\n            if (_dragablzItemsControl != null)\n            {\n                _dragablzItemsControl.ItemContainerGenerator.StatusChanged += ItemContainerGeneratorOnStatusChanged;\n                _templateSubscription =\n                    Disposable.Create(\n                        () =>\n                            _dragablzItemsControl.ItemContainerGenerator.StatusChanged -=\n                                ItemContainerGeneratorOnStatusChanged);                \n\n                _dragablzItemsControl.ContainerCustomisations = new ContainerCustomisations(null, PrepareChildContainerForItemOverride);\n            }\n\n            if (SelectedItem == null)\n                SetCurrentValue(SelectedItemProperty, Items.OfType<object>().FirstOrDefault());\n\n            _itemsHolder = GetTemplateChild(ItemsHolderPartName) as Panel;\n            UpdateSelectedItem();\n            MarkWrappedTabItems();\n            MarkInitialSelection();            \n\n            base.OnApplyTemplate();\n        }                \n\n        /// <summary>\n        /// update the visible child in the ItemsHolder\n        /// </summary>\n        /// <param name=\"e\"></param>\n        protected override void OnSelectionChanged(SelectionChangedEventArgs e)\n        {\n            if (e.RemovedItems.Count > 0 && e.AddedItems.Count > 0)\n                _previousSelection = new WeakReference(e.RemovedItems[0]);\n\n            base.OnSelectionChanged(e);\n            UpdateSelectedItem();\n\n            if (_dragablzItemsControl == null) return;\n\n            Func<IList, IEnumerable<DragablzItem>> notTabItems =\n                l =>\n                    l.Cast<object>()\n                        .Where(o => !(o is TabItem))\n                        .Select(o => _dragablzItemsControl.ItemContainerGenerator.ContainerFromItem(o))\n                        .OfType<DragablzItem>();            \n            foreach (var addedItem in notTabItems(e.AddedItems))\n            {\n                addedItem.IsSelected = true;\n                addedItem.BringIntoView();    \n            }\n            foreach (var removedItem in notTabItems(e.RemovedItems))\n            {\n                removedItem.IsSelected = false;\n            }\n\n            foreach (var tabItem in e.AddedItems.OfType<TabItem>().Select(t => _dragablzItemsControl.ItemContainerGenerator.ContainerFromItem(t)).OfType<DragablzItem>())\n            {                \n                tabItem.IsSelected = true;\n                tabItem.BringIntoView();\n            }            \n            foreach (var tabItem in e.RemovedItems.OfType<TabItem>().Select(t => _dragablzItemsControl.ItemContainerGenerator.ContainerFromItem(t)).OfType<DragablzItem>())\n            {\n                tabItem.IsSelected = false;                \n            }                           \n        }\n\n        /// <summary>\n        /// when the items change we remove any generated panel children and add any new ones as necessary\n        /// </summary>\n        /// <param name=\"e\"></param>\n        protected override void OnItemsChanged(NotifyCollectionChangedEventArgs e)\n        {\n            base.OnItemsChanged(e);\n\n            if (_itemsHolder == null)\n            {\n                return;\n            }\n\n            switch (e.Action)\n            {\n                case NotifyCollectionChangedAction.Reset:\n                    _itemsHolder.Children.Clear();\n\n                    if (Items.Count > 0)\n                    {\n                        SelectedItem = base.Items[0];\n                        UpdateSelectedItem();\n                    }\n\n                    break;\n\n                case NotifyCollectionChangedAction.Add:\n                    UpdateSelectedItem();\n                    if (e.NewItems.Count == 1 && Items.Count > 1 && _dragablzItemsControl != null && _interTabTransfer == null)\n                        _dragablzItemsControl.MoveItem(new MoveItemRequest(e.NewItems[0], SelectedItem, AddLocationHint));\n\n                    break;\n\n                case NotifyCollectionChangedAction.Remove:                    \n                    foreach (var item in e.OldItems)\n                    {                        \n                        var cp = FindChildContentPresenter(item);\n                        if (cp != null)\n                            _itemsHolder.Children.Remove(cp);\n                    }\n\n                    if (SelectedItem == null)\n                        RestorePreviousSelection();\n                    UpdateSelectedItem();\n                    break;\n\n                case NotifyCollectionChangedAction.Replace:\n                    throw new NotImplementedException(\"Replace not implemented yet\");\n            }\n\n            IsEmpty = Items.Count == 0;\n        }\n\n        /// <summary>\n        /// Provides class handling for the <see cref=\"E:System.Windows.ContentElement.KeyDown\"/> routed event that occurs when the user presses a key.\n        /// </summary>\n        /// <param name=\"e\">Provides data for <see cref=\"T:System.Windows.Input.KeyEventArgs\"/>.</param>\n        protected override void OnKeyDown(KeyEventArgs e)\n        {\n            var sortedDragablzItems = _dragablzItemsControl.ItemsOrganiser.Sort(_dragablzItemsControl.DragablzItems()).ToList();\n            DragablzItem selectDragablzItem = null;\n            switch (e.Key)\n            {\n                case Key.Tab:\n                    if (SelectedItem == null)\n                    {\n                        selectDragablzItem = sortedDragablzItems.FirstOrDefault();\n                        break;\n                    }\n\n                    if ((e.KeyboardDevice.Modifiers & ModifierKeys.Control) == ModifierKeys.Control)\n                    {\n                        var selectedDragablzItem = (DragablzItem)_dragablzItemsControl.ItemContainerGenerator.ContainerFromItem(SelectedItem);\n                        var selectedDragablzItemIndex = sortedDragablzItems.IndexOf(selectedDragablzItem);                        \n                        var direction = ((e.KeyboardDevice.Modifiers & ModifierKeys.Shift) == ModifierKeys.Shift)\n                            ? -1 : 1;\n                        var newIndex = selectedDragablzItemIndex + direction;\n                        if (newIndex < 0) newIndex = sortedDragablzItems.Count - 1;\n                        else if (newIndex == sortedDragablzItems.Count) newIndex = 0;\n\n                        selectDragablzItem = sortedDragablzItems[newIndex];\n                    }\n                    break;\n                case Key.Home:\n                    selectDragablzItem = sortedDragablzItems.FirstOrDefault();\n                    break;\n                case Key.End:\n                    selectDragablzItem = sortedDragablzItems.LastOrDefault();\n                    break;\n            }\n\n            if (selectDragablzItem != null)\n            {\n                var item = _dragablzItemsControl.ItemContainerGenerator.ItemFromContainer(selectDragablzItem);\n                SetCurrentValue(SelectedItemProperty, item);\n                e.Handled = true;\n            }\n\n            if (!e.Handled)\n                base.OnKeyDown(e); \n        }\n\n        /// <summary>\n        /// Provides an appropriate automation peer implementation for this control\n        /// as part of the WPF automation infrastructure.\n        /// </summary>\n        /// <returns>The type-specific System.Windows.Automation.Peers.AutomationPeer implementation.</returns>\n        protected override AutomationPeer OnCreateAutomationPeer()\n        {\n            return new FrameworkElementAutomationPeer(this);\n        }\n        \n        internal static TabablzControl GetOwnerOfHeaderItems(DragablzItemsControl itemsControl)\n        {\n            return LoadedInstances.FirstOrDefault(t => Equals(t._dragablzItemsControl, itemsControl));\n        }\n\n        private static void OnIsVisibleChanged(object sender, DependencyPropertyChangedEventArgs dependencyPropertyChangedEventArgs)\n        {\n            var tabablzControl = (TabablzControl) sender;\n            if (tabablzControl.IsVisible)\n                VisibleInstances.Add(tabablzControl);\n            else if (VisibleInstances.Contains(tabablzControl))\n                VisibleInstances.Remove(tabablzControl);\n        }\n\n        private void OnLoaded(object sender, RoutedEventArgs routedEventArgs)\n        {\n            LoadedInstances.Add(this);\n            var window = Window.GetWindow(this);\n            if (window == null) return; \n            window.Closing += WindowOnClosing;\n            _windowSubscription.Disposable = Disposable.Create(() => window.Closing -= WindowOnClosing);\n        }\n\n        private void WindowOnClosing(object sender, CancelEventArgs cancelEventArgs)\n        {\n            _windowSubscription.Disposable = Disposable.Empty;\n            if (!ConsolidateOrphanedItems || InterTabController == null) return;\n\n            var window = (Window)sender;\n\n            var orphanedItems = _dragablzItemsControl.DragablzItems();\n            if (ConsolidatingOrphanedItemCallback != null)\n            {\n                orphanedItems =\n                    orphanedItems.Where(\n                        di =>\n                        {\n                            var args = new ItemActionCallbackArgs<TabablzControl>(window, this, di);\n                            ConsolidatingOrphanedItemCallback(args);\n                            return !args.IsCancelled;\n                        }).ToList();\n            }\n\n            var target =\n                LoadedInstances.Except(this)\n                    .FirstOrDefault(\n                        other =>\n                            other.InterTabController != null &&\n                            other.InterTabController.Partition == InterTabController.Partition);\n            if (target == null) return;\n\n            foreach (var item in orphanedItems.Select(orphanedItem => _dragablzItemsControl.ItemContainerGenerator.ItemFromContainer(orphanedItem)))\n            {\n                RemoveFromSource(item);\n                target.AddToSource(item);\n            }\n        }\n\n        private void OnUnloaded(object sender, RoutedEventArgs routedEventArgs)\n        {\n            _windowSubscription.Disposable = Disposable.Empty;\n            LoadedInstances.Remove(this);\n        }\n\n        private void MarkWrappedTabItems()\n        {\n            if (_dragablzItemsControl == null) return;\n\n            foreach (var pair in _dragablzItemsControl.Items.OfType<TabItem>().Select(tabItem =>\n                new\n                {\n                    tabItem,\n                    dragablzItem = _dragablzItemsControl.ItemContainerGenerator.ContainerFromItem(tabItem) as DragablzItem\n                }).Where(a => a.dragablzItem != null))\n            {\n                var toolTipBinding = new Binding(\"ToolTip\") { Source = pair.tabItem };\n                BindingOperations.SetBinding(pair.dragablzItem, ToolTipProperty, toolTipBinding);\n                SetIsWrappingTabItem(pair.dragablzItem, true);\n            }\n        }\n\n        private void MarkInitialSelection()\n        {\n            if (_dragablzItemsControl == null ||\n                _dragablzItemsControl.ItemContainerGenerator.Status != GeneratorStatus.ContainersGenerated) return;\n\n            if (_dragablzItemsControl == null || SelectedItem == null) return;\n\n            var tabItem = SelectedItem as TabItem;\n            tabItem?.SetCurrentValue(IsSelectedProperty, true);\n\n            var containerFromItem =\n                _dragablzItemsControl.ItemContainerGenerator.ContainerFromItem(SelectedItem) as DragablzItem;\n\n            containerFromItem?.SetCurrentValue(DragablzItem.IsSelectedProperty, true);\n        }\n\n        private void ItemDragStarted(object sender, DragablzDragStartedEventArgs e)\n        {\n            if (!IsMyItem(e.DragablzItem)) return;\n\n            //the thumb may steal the user selection, so we will try and apply it manually\n            if (_dragablzItemsControl == null) return;\n\n            e.DragablzItem.IsDropTargetFound = false;\n\n            var sourceOfDragItemsControl = ItemsControlFromItemContainer(e.DragablzItem) as DragablzItemsControl;\n            if (sourceOfDragItemsControl == null || !Equals(sourceOfDragItemsControl, _dragablzItemsControl)) return;\n\n            var itemsControlOffset = Mouse.GetPosition(_dragablzItemsControl);\n            _tabHeaderDragStartInformation = new TabHeaderDragStartInformation(e.DragablzItem, itemsControlOffset.X,\n                itemsControlOffset.Y, e.DragStartedEventArgs.HorizontalOffset, e.DragStartedEventArgs.VerticalOffset);\n\n            foreach (var otherItem in _dragablzItemsControl.Containers<DragablzItem>().Except(e.DragablzItem))                \n                otherItem.IsSelected = false;                \n            e.DragablzItem.IsSelected = true;\n            e.DragablzItem.PartitionAtDragStart = InterTabController?.Partition;\n            var item = _dragablzItemsControl.ItemContainerGenerator.ItemFromContainer(e.DragablzItem);\n            var tabItem = item as TabItem;\n            if (tabItem != null)\n                tabItem.IsSelected = true;\n            SelectedItem = item;\n\n            if (ShouldDragWindow(sourceOfDragItemsControl))\n                IsDraggingWindow = true;\n        }\n\n        private bool ShouldDragWindow(DragablzItemsControl sourceOfDragItemsControl)\n        {\n            return (Items.Count == 1\n                    && (InterTabController == null || InterTabController.MoveWindowWithSolitaryTabs)\n                    && !Layout.IsContainedWithinBranch(sourceOfDragItemsControl));\n        }\n\n        private void PreviewItemDragDelta(object sender, DragablzDragDeltaEventArgs e)\n        {\n            if (_dragablzItemsControl == null) return;\n\n            var sourceOfDragItemsControl = ItemsControlFromItemContainer(e.DragablzItem) as DragablzItemsControl;\n            if (sourceOfDragItemsControl == null || !Equals(sourceOfDragItemsControl, _dragablzItemsControl)) return;\n\n            if (!ShouldDragWindow(sourceOfDragItemsControl)) return;\n\n            if (MonitorReentry(e)) return;\n\n            var myWindow = Window.GetWindow(this);\n            if (myWindow == null) return;\n\n            if (_interTabTransfer != null)\n            {\n                var cursorPos = Native.GetCursorPos().ToWpf();\n                if (_interTabTransfer.BreachOrientation == Orientation.Vertical)\n                {\n                    var vector = cursorPos - _interTabTransfer.DragStartWindowOffset;\n                    myWindow.Left = vector.X;\n                    myWindow.Top = vector.Y;\n                }\n                else\n                {\n                    var offset = e.DragablzItem.TranslatePoint(_interTabTransfer.OriginatorContainer.MouseAtDragStart, myWindow);\n                    var borderVector = myWindow.PointToScreen(new Point()).ToWpf() - new Point(myWindow.Left, myWindow.Top);\n                    offset.Offset(borderVector.X, borderVector.Y);\n                    myWindow.Left = cursorPos.X - offset.X;                    \n                    myWindow.Top = cursorPos.Y - offset.Y;\n                }                 \n            }\n            else\n            {\n                myWindow.Left += e.DragDeltaEventArgs.HorizontalChange;\n                myWindow.Top += e.DragDeltaEventArgs.VerticalChange;\n            }\n\n            e.Handled = true;\n        }\n\n        private bool MonitorReentry(DragablzDragDeltaEventArgs e)\n        {\n            var screenMousePosition = _dragablzItemsControl.PointToScreen(Mouse.GetPosition(_dragablzItemsControl));\n\n            var sourceTabablzControl = (TabablzControl) e.Source;\n            if (sourceTabablzControl.Items.Count > 1 && e.DragablzItem.LogicalIndex < sourceTabablzControl.FixedHeaderCount)\n            {                \n                return false;\n            }\n\n            var otherTabablzControls = LoadedInstances\n                .Where(\n                    tc =>\n                        tc != this && tc.InterTabController != null && InterTabController != null\n                        && Equals(tc.InterTabController.Partition, InterTabController.Partition)\n                        && tc._dragablzItemsControl != null)\n                .Select(tc =>\n                {\n                    var topLeft = tc._dragablzItemsControl.PointToScreen(new Point());\n                    var lastFixedItem = tc._dragablzItemsControl.DragablzItems()\n                        .OrderBy(di=> di.LogicalIndex)\n                        .Take(tc._dragablzItemsControl.FixedItemCount)\n                        .LastOrDefault();                    \n                    //TODO work this for vert tabs\n                    if (lastFixedItem != null)\n                        topLeft.Offset(lastFixedItem.X + lastFixedItem.ActualWidth, 0);\n                    var bottomRight =\n                        tc._dragablzItemsControl.PointToScreen(new Point(tc._dragablzItemsControl.ActualWidth,\n                            tc._dragablzItemsControl.ActualHeight));\n\n                    return new {tc, topLeft, bottomRight};\n                });\n\n\n            var target = Native.SortWindowsTopToBottom(Application.Current.Windows.OfType<Window>())\n                .Join(otherTabablzControls, w => w, a => Window.GetWindow(a.tc), (w, a) => a)\n                .FirstOrDefault(a => new Rect(a.topLeft, a.bottomRight).Contains(screenMousePosition));\n\n            if (target == null) return false;\n\n            var mousePositionOnItem = Mouse.GetPosition(e.DragablzItem);\n\n            var floatingItemSnapShots = this.VisualTreeDepthFirstTraversal()\n                .OfType<Layout>()\n                .SelectMany(l => l.FloatingDragablzItems().Select(FloatingItemSnapShot.Take))\n                .ToList();\n\n            e.DragablzItem.IsDropTargetFound = true;\n            var item = RemoveItem(e.DragablzItem);                \n\n            var interTabTransfer = new InterTabTransfer(item, e.DragablzItem, mousePositionOnItem, floatingItemSnapShots);\n            e.DragablzItem.IsDragging = false;\n\n            target.tc.ReceiveDrag(interTabTransfer);\n            e.Cancel = true;\n                \n            return true;\n        }\n\n        internal object RemoveItem(DragablzItem dragablzItem)\n        {\n            var item = _dragablzItemsControl.ItemContainerGenerator.ItemFromContainer(dragablzItem);\n\n            //stop the header shrinking if the tab stays open when empty\n            var minSize = EmptyHeaderSizingHint == EmptyHeaderSizingHint.PreviousTab\n                ? new Size(_dragablzItemsControl.ActualWidth, _dragablzItemsControl.ActualHeight)\n                : new Size();\n            \n            _dragablzItemsControl.MinHeight = 0;\n            _dragablzItemsControl.MinWidth = 0;\n\n            var contentPresenter = FindChildContentPresenter(item);\n            RemoveFromSource(item);\n            _itemsHolder.Children.Remove(contentPresenter);\n\n            if (Items.Count != 0) return item;\n\n            var window = Window.GetWindow(this);\n            if (window != null \n                && InterTabController != null                \n                && InterTabController.InterTabClient.TabEmptiedHandler(this, window) == TabEmptiedResponse.CloseWindowOrLayoutBranch)\n            {\n                if (Layout.ConsolidateBranch(this)) return item;\n\n                try\n                {\n                    SetIsClosingAsPartOfDragOperation(window, true);\n                    window.Close();\n                }\n                finally\n                {\n                    SetIsClosingAsPartOfDragOperation(window, false);\n                }                    \n            }\n            else\n            {\n                _dragablzItemsControl.MinHeight = minSize.Height;\n                _dragablzItemsControl.MinWidth = minSize.Width;\n            }\n            return item;\n        }\n\n        private void ItemDragCompleted(object sender, DragablzDragCompletedEventArgs e)\n        {\n            if (!IsMyItem(e.DragablzItem)) return;\n\n            _interTabTransfer = null;\n            _dragablzItemsControl.LockedMeasure = null;\n            IsDraggingWindow = false;\n        }\n\n        private void ItemDragDelta(object sender, DragablzDragDeltaEventArgs e)\n        {\n            if (!IsMyItem(e.DragablzItem)) return;                        \n            if (FixedHeaderCount > 0 &&\n                _dragablzItemsControl.ItemsOrganiser.Sort(_dragablzItemsControl.DragablzItems())\n                    .Take(FixedHeaderCount)\n                    .Contains(e.DragablzItem))                \n                return;\n\n            if (_tabHeaderDragStartInformation == null ||\n                !Equals(_tabHeaderDragStartInformation.DragItem, e.DragablzItem) || InterTabController == null) return;\n\n            if (InterTabController.InterTabClient == null)                    \n                throw new InvalidOperationException(\"An InterTabClient must be provided on an InterTabController.\");\n                \n            MonitorBreach(e);\n        }\n\n        private bool IsMyItem(DragablzItem item)\n        {\n            return _dragablzItemsControl != null && _dragablzItemsControl.DragablzItems().Contains(item);\n        }\n\n        private void MonitorBreach(DragablzDragDeltaEventArgs e)\n        {\n            var mousePositionOnHeaderItemsControl = Mouse.GetPosition(_dragablzItemsControl);\n\n            Orientation? breachOrientation = null;\n            if (mousePositionOnHeaderItemsControl.X < -InterTabController.HorizontalPopoutGrace\n                || (mousePositionOnHeaderItemsControl.X - _dragablzItemsControl.ActualWidth) > InterTabController.HorizontalPopoutGrace)\n                breachOrientation = Orientation.Horizontal;\n            else if (mousePositionOnHeaderItemsControl.Y < -InterTabController.VerticalPopoutGrace\n                     || (mousePositionOnHeaderItemsControl.Y - _dragablzItemsControl.ActualHeight) > InterTabController.VerticalPopoutGrace)\n                breachOrientation = Orientation.Vertical;\n\n            if (!breachOrientation.HasValue) return;\n\n            var newTabHost = InterTabController.InterTabClient.GetNewHost(InterTabController.InterTabClient,\n                InterTabController.Partition, this);\n            if (newTabHost?.TabablzControl == null || newTabHost.Container == null)\n                throw new ApplicationException(\"New tab host was not correctly provided\");\n\n            var item = _dragablzItemsControl.ItemContainerGenerator.ItemFromContainer(e.DragablzItem);\n            var isTransposing = IsTransposing(newTabHost.TabablzControl);\n\n            var myWindow = Window.GetWindow(this);\n            if (myWindow == null) throw new ApplicationException(\"Unable to find owning window.\");\n            var dragStartWindowOffset = ConfigureNewHostSizeAndGetDragStartWindowOffset(myWindow, newTabHost, e.DragablzItem, isTransposing);\n\n            var dragableItemHeaderPoint = e.DragablzItem.TranslatePoint(new Point(), _dragablzItemsControl);\n            var dragableItemSize = new Size(e.DragablzItem.ActualWidth, e.DragablzItem.ActualHeight);\n            var floatingItemSnapShots = this.VisualTreeDepthFirstTraversal()\n                .OfType<Layout>()\n                .SelectMany(l => l.FloatingDragablzItems().Select(FloatingItemSnapShot.Take))\n                .ToList();            \n\n            var interTabTransfer = new InterTabTransfer(item, e.DragablzItem, breachOrientation.Value, dragStartWindowOffset, e.DragablzItem.MouseAtDragStart, dragableItemHeaderPoint, dragableItemSize, floatingItemSnapShots, isTransposing);\n\n            if (myWindow.WindowState == WindowState.Maximized)\n            {\n                var desktopMousePosition = Native.GetCursorPos().ToWpf();\n                newTabHost.Container.Left = desktopMousePosition.X - dragStartWindowOffset.X;\n                newTabHost.Container.Top = desktopMousePosition.Y - dragStartWindowOffset.Y;\n            }\n            else\n            {\n                newTabHost.Container.Left = myWindow.Left;\n                newTabHost.Container.Top = myWindow.Top;\n            }\n            newTabHost.Container.Show();\n            var contentPresenter = FindChildContentPresenter(item);\n\n            //stop the header shrinking if the tab stays open when empty\n            var minSize = EmptyHeaderSizingHint == EmptyHeaderSizingHint.PreviousTab\n                ? new Size(_dragablzItemsControl.ActualWidth, _dragablzItemsControl.ActualHeight)\n                : new Size();\n            System.Diagnostics.Debug.WriteLine(\"B \" + minSize);\n\n            RemoveFromSource(item);\n            _itemsHolder.Children.Remove(contentPresenter);\n            if (Items.Count == 0)\n            {\n                _dragablzItemsControl.MinHeight = minSize.Height;\n                _dragablzItemsControl.MinWidth = minSize.Width;\n                Layout.ConsolidateBranch(this);\n            }\n\n            RestorePreviousSelection();\n\n            foreach (var dragablzItem in _dragablzItemsControl.DragablzItems())\n            {\n                dragablzItem.IsDragging = false;\n                dragablzItem.IsSiblingDragging = false;\n            }\n\n            newTabHost.TabablzControl.ReceiveDrag(interTabTransfer);\n            interTabTransfer.OriginatorContainer.IsDropTargetFound = true;\n            e.Cancel = true;\n        }\n\n        private bool IsTransposing(TabControl target)\n        {\n            return IsVertical(this) != IsVertical(target);\n        }\n\n        private static bool IsVertical(TabControl tabControl)\n        {\n            return tabControl.TabStripPlacement == Dock.Left\n                   || tabControl.TabStripPlacement == Dock.Right;\n        }\n\n        private void RestorePreviousSelection()\n        {\n            var previousSelection = _previousSelection?.Target;\n            if (previousSelection != null && Items.Contains(previousSelection))\n                SelectedItem = previousSelection;\n            else\n                SelectedItem = Items.OfType<object>().FirstOrDefault();\n        }\n\n        private Point ConfigureNewHostSizeAndGetDragStartWindowOffset(Window currentWindow, INewTabHost<Window> newTabHost, DragablzItem dragablzItem, bool isTransposing)\n        {\n            var layout = this.VisualTreeAncestory().OfType<Layout>().FirstOrDefault();\n            Point dragStartWindowOffset;\n            if (layout != null)\n            {\n                newTabHost.Container.Width = ActualWidth + Math.Max(0, currentWindow.RestoreBounds.Width - layout.ActualWidth);\n                newTabHost.Container.Height = ActualHeight + Math.Max(0, currentWindow.RestoreBounds.Height - layout.ActualHeight);\n                dragStartWindowOffset = dragablzItem.TranslatePoint(new Point(), this);\n                //dragStartWindowOffset.Offset(currentWindow.RestoreBounds.Width - layout.ActualWidth, currentWindow.RestoreBounds.Height - layout.ActualHeight);\n            }\n            else\n            {\n                if (newTabHost.Container.GetType() == currentWindow.GetType())\n                {\n                    newTabHost.Container.Width = currentWindow.RestoreBounds.Width;\n                    newTabHost.Container.Height = currentWindow.RestoreBounds.Height;\n                    dragStartWindowOffset = isTransposing ? new Point(dragablzItem.MouseAtDragStart.X, dragablzItem.MouseAtDragStart.Y) : dragablzItem.TranslatePoint(new Point(), currentWindow);\n                }\n                else\n                {\n                    newTabHost.Container.Width = ActualWidth;\n                    newTabHost.Container.Height = ActualHeight;\n                    dragStartWindowOffset = isTransposing ? new Point() : dragablzItem.TranslatePoint(new Point(), this);\n                    dragStartWindowOffset.Offset(dragablzItem.MouseAtDragStart.X, dragablzItem.MouseAtDragStart.Y);\n                    return dragStartWindowOffset;\n                }                \n            }            \n            \n            dragStartWindowOffset.Offset(dragablzItem.MouseAtDragStart.X, dragablzItem.MouseAtDragStart.Y);\n            var borderVector = currentWindow.PointToScreen(new Point()).ToWpf() - new Point(currentWindow.GetActualLeft(), currentWindow.GetActualTop());\n            dragStartWindowOffset.Offset(borderVector.X, borderVector.Y);\n            return dragStartWindowOffset;\n        }\n\n        internal void ReceiveDrag(InterTabTransfer interTabTransfer)\n        {\n            var myWindow = Window.GetWindow(this);\n            if (myWindow == null) throw new ApplicationException(\"Unable to find owning window.\");\n            myWindow.Activate();\n\n            _interTabTransfer = interTabTransfer;\n\n            if (Items.Count == 0)\n            {\n                if (interTabTransfer.IsTransposing)\n                    _dragablzItemsControl.LockedMeasure = new Size(\n                        interTabTransfer.ItemSize.Width,\n                        interTabTransfer.ItemSize.Height);\n                else\n                    _dragablzItemsControl.LockedMeasure = new Size(\n                        interTabTransfer.ItemPositionWithinHeader.X + interTabTransfer.ItemSize.Width,\n                        interTabTransfer.ItemPositionWithinHeader.Y + interTabTransfer.ItemSize.Height);\n            }\n\n            var lastFixedItem = _dragablzItemsControl.DragablzItems()\n                .OrderBy(i => i.LogicalIndex)\n                .Take(_dragablzItemsControl.FixedItemCount)\n                .LastOrDefault();\n\n            AddToSource(interTabTransfer.Item);\n            SelectedItem = interTabTransfer.Item;\n            \n            Dispatcher.BeginInvoke(new Action(() => Layout.RestoreFloatingItemSnapShots(this, interTabTransfer.FloatingItemSnapShots)), DispatcherPriority.Loaded);\n            _dragablzItemsControl.InstigateDrag(interTabTransfer.Item, newContainer =>\n            {\n                newContainer.PartitionAtDragStart = interTabTransfer.OriginatorContainer.PartitionAtDragStart;\n                newContainer.IsDropTargetFound = true;\n\n                if (interTabTransfer.TransferReason == InterTabTransferReason.Breach)\n                {\n                    if (interTabTransfer.IsTransposing)\n                    {\n                        newContainer.Y = 0;\n                        newContainer.X = 0;\n                    }\n                    else\n                    {\n                        newContainer.Y = interTabTransfer.OriginatorContainer.Y;\n                        newContainer.X = interTabTransfer.OriginatorContainer.X;\n                    }\n                }\n                else\n                {\n                    if (TabStripPlacement == Dock.Top || TabStripPlacement == Dock.Bottom)\n                    {\n                        var mouseXOnItemsControl = Native.GetCursorPos().X -\n                                                   _dragablzItemsControl.PointToScreen(new Point()).X;\n                        var newX = mouseXOnItemsControl - interTabTransfer.DragStartItemOffset.X;\n                        if (lastFixedItem != null)\n                        {\n                            newX = Math.Max(newX, lastFixedItem.X + lastFixedItem.ActualWidth);\n                        }\n                        newContainer.X = newX;\n                        newContainer.Y = 0;\n                    }\n                    else\n                    {\n                        var mouseYOnItemsControl = Native.GetCursorPos().Y -\n                                                   _dragablzItemsControl.PointToScreen(new Point()).Y;\n                        var newY = mouseYOnItemsControl - interTabTransfer.DragStartItemOffset.Y;\n                        if (lastFixedItem != null)\n                        {\n                            newY = Math.Max(newY, lastFixedItem.Y + lastFixedItem.ActualHeight);\n                        }\n                        newContainer.X = 0;\n                        newContainer.Y = newY;\n                    }\n                }\n                newContainer.MouseAtDragStart = interTabTransfer.DragStartItemOffset;\n            });\n        }                \n\n        /// <summary>\n        /// generate a ContentPresenter for the selected item\n        /// </summary>\n        private void UpdateSelectedItem()        \n        {            \n            if (_itemsHolder == null)\n            {\n                return;\n            }\n            \n            CreateChildContentPresenter(SelectedItem);            \n\n            // show the right child\n            var selectedContent = GetContent(SelectedItem);\n            foreach (ContentPresenter child in _itemsHolder.Children)\n            {\n                var isSelected = (child.Content == selectedContent);\n                child.Visibility = isSelected ? Visibility.Visible : Visibility.Collapsed;\n                child.IsEnabled = isSelected;\n            }\n        }\n\n        private static object GetContent(object item)\n        {\n            return (item is TabItem) ? ((TabItem) item).Content : item;\n        }\n\n        /// <summary>\n        /// create the child ContentPresenter for the given item (could be data or a TabItem)\n        /// </summary>\n        /// <param name=\"item\"></param>\n        /// <returns></returns>\n        private void CreateChildContentPresenter(object item)\n        {\n            if (item == null) return;            \n\n            var cp = FindChildContentPresenter(item);\n            if (cp != null) return;\n\n            // the actual child to be added.  cp.Tag is a reference to the TabItem\n            cp = new ContentPresenter\n            {\n                Content = GetContent(item),\n                ContentTemplate = ContentTemplate,\n                ContentTemplateSelector = ContentTemplateSelector,\n                ContentStringFormat = ContentStringFormat,\n                Visibility = Visibility.Collapsed,                \n            };\n            _itemsHolder.Children.Add(cp);         \n        }\n\n        /// <summary>\n        /// Find the CP for the given object.  data could be a TabItem or a piece of data\n        /// </summary>\n        /// <param name=\"data\"></param>\n        /// <returns></returns>\n        private ContentPresenter FindChildContentPresenter(object data)\n        {\n            if (data is TabItem)\n                data = ((TabItem) data).Content;\n\n            return data == null\n                ? null\n                : _itemsHolder?.Children.Cast<ContentPresenter>().FirstOrDefault(cp => cp.Content == data);\n        }\n\n        private void ItemContainerGeneratorOnStatusChanged(object sender, EventArgs eventArgs)\n        {\n            MarkWrappedTabItems();\n            MarkInitialSelection();\n        }\n\n        private static void CloseItem(DragablzItem item, TabablzControl owner)\n        {\n            if (item == null)\n                throw new ApplicationException(\"Valid DragablzItem to close is required.\");\n\n            if (owner == null)\n                throw new ApplicationException(\"Valid TabablzControl container is required.\");\n\n            if (!owner.IsMyItem(item))\n                throw new ApplicationException(\"TabablzControl container must be an owner of the DragablzItem to close\");\n\n            var cancel = false;\n            if (owner.ClosingItemCallback != null)\n            {\n                var callbackArgs = new ItemActionCallbackArgs<TabablzControl>(Window.GetWindow(owner), owner, item);\n                owner.ClosingItemCallback(callbackArgs);\n                cancel = callbackArgs.IsCancelled;\n            }\n\n            if (!cancel)\n                owner.RemoveItem(item);\n        }\n\n        private static void CloseItemCanExecuteClassHandler(object sender, CanExecuteRoutedEventArgs e)\n        {\n            e.CanExecute = FindOwner(e.Parameter, e.OriginalSource) != null;\n        }\n        private static void CloseItemClassHandler(object sender, ExecutedRoutedEventArgs e)\n        {\n            var owner = FindOwner(e.Parameter, e.OriginalSource);\n\n            if (owner == null) throw new ApplicationException(\"Unable to ascertain DragablzItem to close.\");\n\n            CloseItem(owner.Item1, owner.Item2);\n        }\n\n        private static Tuple<DragablzItem, TabablzControl> FindOwner(object eventParameter, object eventOriginalSource)\n        {\n            var dragablzItem = eventParameter as DragablzItem;\n            if (dragablzItem == null)\n            {\n                var dependencyObject = eventOriginalSource as DependencyObject;\n                dragablzItem = dependencyObject.VisualTreeAncestory().OfType<DragablzItem>().FirstOrDefault();\n                if (dragablzItem == null)\n                {\n                    var popup = dependencyObject.LogicalTreeAncestory().OfType<Popup>().LastOrDefault();\n                    if (popup?.PlacementTarget != null)\n                    {\n                        dragablzItem = popup.PlacementTarget.VisualTreeAncestory().OfType<DragablzItem>().FirstOrDefault();                        \n                    }\n                }\n            }\n\n            if (dragablzItem == null) return null;\n\n            var tabablzControl = LoadedInstances.FirstOrDefault(tc => tc.IsMyItem(dragablzItem));\n\n            return tabablzControl == null ? null : new Tuple<DragablzItem, TabablzControl>(dragablzItem, tabablzControl);\n        }        \n\n        private void AddItemHandler(object sender, ExecutedRoutedEventArgs e)\n        {            \n            if (NewItemFactory == null)\n                throw new InvalidOperationException(\"NewItemFactory must be provided.\");\n\n            var newItem = NewItemFactory();\n            if (newItem == null) throw new ApplicationException(\"NewItemFactory returned null.\");\n\n            AddToSource(newItem);\n            SelectedItem = newItem;\n\n            Dispatcher.BeginInvoke(new Action(_dragablzItemsControl.InvalidateMeasure), DispatcherPriority.Loaded);\n        }\n\n        private void PrepareChildContainerForItemOverride(DependencyObject dependencyObject, object o)\n        {\n            var dragablzItem = dependencyObject as DragablzItem;\n            if (dragablzItem != null && HeaderMemberPath != null)\n            {\n                var contentBinding = new Binding(HeaderMemberPath) { Source = o };\n                dragablzItem.SetBinding(ContentControl.ContentProperty, contentBinding);\n                dragablzItem.UnderlyingContent = o;\n            }\n\n            SetIsWrappingTabItem(dependencyObject, o is TabItem);            \n        }\n    }\n}\n"
  },
  {
    "path": "third_party/Dragablz/Dragablz/TabablzHeaderSizeConverter.cs",
    "content": "using System;\nusing System.Globalization;\nusing System.Linq;\nusing System.Windows;\nusing System.Windows.Controls;\nusing System.Windows.Data;\nusing System.Windows.Media;\n\nnamespace Dragablz\n{\n    /// <summary>\n    /// Provides a little help for sizing the header panel in the tab control\n    /// </summary>\n    public class TabablzHeaderSizeConverter : IMultiValueConverter\n    {        \n        public Orientation Orientation { get; set; }\n\n        /// <summary>\n        /// The first value should be the total size available size, typically the parent control size.  \n        /// The second value should be from <see cref=\"DragablzItemsControl.ItemsPresenterWidthProperty\"/> or (height equivalent)\n        /// All additional values should be siblings sizes (width or height) which will affect (reduce) the available size.\n        /// </summary>\n        /// <param name=\"values\"></param>\n        /// <param name=\"targetType\"></param>\n        /// <param name=\"parameter\"></param>\n        /// <param name=\"culture\"></param>\n        /// <returns></returns>\n        public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)\n        {\n            if (values == null) throw new ArgumentNullException(\"values\");\n\n            if (values.Length < 2) return Binding.DoNothing;\n\n            var val = values\n                .Skip(2)\n                .OfType<double>()\n                .Where(d => !double.IsInfinity(d) && !double.IsNaN(d))\n                .Aggregate(values.OfType<double>().First(), (current, diminish) => current - diminish);\n\n            var maxWidth = values.Take(2).OfType<double>().Min();\n\n            return Math.Min(Math.Max(val, 0), maxWidth);\n        }\n\n        public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture)\n        {\n            throw new NotImplementedException();\n        }\n    }\n}"
  },
  {
    "path": "third_party/Dragablz/Dragablz/TabablzItemStyleSelector.cs",
    "content": "﻿using System.Windows;\nusing System.Windows.Controls;\n\nnamespace Dragablz\n{\n    /// <summary>\n    /// Selects style to apply to a <see cref=\"DragablzItem\"/> according to the tab item content itself.\n    /// </summary>\n    public class TabablzItemStyleSelector : StyleSelector\n    {\n        private readonly Style _defaultHeaderItemStyle;\n        private readonly Style _customHeaderItemStyle;\n\n        public TabablzItemStyleSelector(Style defaultHeaderItemStyle, Style customHeaderItemStyle)\n        {\n            _defaultHeaderItemStyle = defaultHeaderItemStyle;\n            _customHeaderItemStyle = customHeaderItemStyle;\n        }\n\n        public override Style SelectStyle(object item, DependencyObject container)\n        {\n            if (item is TabItem) return _defaultHeaderItemStyle;\n\n            return _customHeaderItemStyle;\n        }\n    }\n}"
  },
  {
    "path": "third_party/Dragablz/Dragablz/Themes/BrushToRadialGradientBrushConverter.cs",
    "content": "﻿using System;\nusing System.Globalization;\nusing System.Windows;\nusing System.Windows.Data;\nusing System.Windows.Media;\n\nnamespace Dragablz.Themes\n{\n    public class BrushToRadialGradientBrushConverter : IValueConverter\n    {\n        public object Convert(object value, Type targetType, object parameter, CultureInfo culture)\n        {\n            var solidColorBrush = value as SolidColorBrush;\n            if (solidColorBrush == null) return Binding.DoNothing;\n\n            return new RadialGradientBrush(solidColorBrush.Color, Colors.Transparent)\n            {\n                Center = new Point(.5, .5),\n                GradientOrigin = new Point(.5, .5),\n                RadiusX = .5,\n                RadiusY = .5,\n                Opacity = .39\n            };\n        }\n\n        public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)\n        {\n            return Binding.DoNothing;\n        }\n    }\n}"
  },
  {
    "path": "third_party/Dragablz/Dragablz/Themes/Dockablz.xaml",
    "content": "﻿<ResourceDictionary xmlns=\"http://schemas.microsoft.com/winfx/2006/xaml/presentation\"\n                    xmlns:x=\"http://schemas.microsoft.com/winfx/2006/xaml\"\n                    xmlns:dockablz=\"clr-namespace:Dragablz.Dockablz\"\n                    xmlns:converters=\"clr-namespace:Dragablz.Converters\">\n\n\n\n</ResourceDictionary>"
  },
  {
    "path": "third_party/Dragablz/Dragablz/Themes/Generic.xaml",
    "content": "<ResourceDictionary\n    xmlns=\"http://schemas.microsoft.com/winfx/2006/xaml/presentation\"\n    xmlns:x=\"http://schemas.microsoft.com/winfx/2006/xaml\"\n    xmlns:local=\"clr-namespace:Dragablz\"\n    xmlns:dockablz=\"clr-namespace:Dragablz.Dockablz\"\n    xmlns:converters=\"clr-namespace:Dragablz.Converters\"\n    xmlns:themes=\"clr-namespace:Dragablz.Themes\">\n\n    <BooleanToVisibilityConverter x:Key=\"BooleanToVisibilityConverter\" />\n    <converters:EqualityToVisibilityConverter x:Key=\"EqualityToVisibilityConverter\" />\n    <converters:BooleanAndToVisibilityConverter x:Key=\"BooleanAndToVisibilityConverter\" />\n    <converters:EqualityToBooleanConverter x:Key=\"EqualityToBooleanConverter\" />\n    <converters:ShowDefaultCloseButtonConverter x:Key=\"ShowDefaultCloseButtonConverter\" />\n\n    <Style x:Key=\"FocusVisual\">\n        <Setter Property=\"Control.Template\">\n            <Setter.Value>\n                <ControlTemplate>\n                    <Rectangle Margin=\"2\" SnapsToDevicePixels=\"true\" Stroke=\"{DynamicResource {x:Static SystemColors.ControlTextBrushKey}}\" StrokeThickness=\"1\" StrokeDashArray=\"1 2\"/>\n                </ControlTemplate>\n            </Setter.Value>\n        </Setter>\n    </Style>\n\n    <Style TargetType=\"{x:Type themes:Ripple}\">\n        <Setter Property=\"RecognizesAccessKey\" Value=\"True\" />\n        <Setter Property=\"HorizontalAlignment\" Value=\"Stretch\" />\n        <Setter Property=\"VerticalAlignment\" Value=\"Stretch\" />\n        <Setter Property=\"HorizontalContentAlignment\" Value=\"Stretch\" />\n        <Setter Property=\"VerticalContentAlignment\" Value=\"Stretch\" />\n        <Setter Property=\"Background\" Value=\"Transparent\" />\n        <Setter Property=\"IsTabStop\" Value=\"False\" />\n        <Setter Property=\"ClipToBounds\" Value=\"{Binding RelativeSource={RelativeSource Self}, Path=(themes:RippleAssist.ClipToBounds)}\" />\n        <Setter Property=\"Feedback\" Value=\"{Binding RelativeSource={RelativeSource Self}, Path=Foreground}\" />\n        <Setter Property=\"Template\">\n            <Setter.Value>\n                <ControlTemplate TargetType=\"{x:Type themes:Ripple}\">\n                    <Grid Background=\"Transparent\">\n                        <VisualStateManager.VisualStateGroups>\n                            <VisualStateGroup x:Name=\"CommonStates\">\n                                <VisualStateGroup.Transitions>\n                                    <VisualTransition From=\"Normal\" To=\"MousePressed\">\n                                        <Storyboard>\n                                            <DoubleAnimationUsingKeyFrames Storyboard.TargetProperty=\"ScaleX\" Storyboard.TargetName=\"ScaleTransform\">\n                                                <EasingDoubleKeyFrame KeyTime=\"0\" Value=\"0\"/>\n                                                <EasingDoubleKeyFrame KeyTime=\"0:0:1.2\" Value=\"1\">\n                                                    <EasingDoubleKeyFrame.EasingFunction>\n                                                        <SineEase EasingMode=\"EaseIn\" />\n                                                    </EasingDoubleKeyFrame.EasingFunction>\n                                                </EasingDoubleKeyFrame>\n                                            </DoubleAnimationUsingKeyFrames>\n                                            <DoubleAnimationUsingKeyFrames Storyboard.TargetProperty=\"ScaleY\" Storyboard.TargetName=\"ScaleTransform\">\n                                                <EasingDoubleKeyFrame KeyTime=\"0\" Value=\"0\"/>\n                                                <EasingDoubleKeyFrame KeyTime=\"0:0:1.2\" Value=\"1\">\n                                                    <EasingDoubleKeyFrame.EasingFunction>\n                                                        <SineEase EasingMode=\"EaseIn\" />\n                                                    </EasingDoubleKeyFrame.EasingFunction>\n                                                </EasingDoubleKeyFrame>\n                                            </DoubleAnimationUsingKeyFrames>\n                                            <DoubleAnimationUsingKeyFrames Storyboard.TargetProperty=\"Opacity\" Storyboard.TargetName=\"ClickEllipse\">\n                                                <EasingDoubleKeyFrame KeyTime=\"0\" Value=\"0\"/>\n                                                <EasingDoubleKeyFrame KeyTime=\"0:0:0.05\" Value=\".26\"/>\n                                            </DoubleAnimationUsingKeyFrames>\n                                        </Storyboard>\n                                    </VisualTransition>\n                                    <VisualTransition From=\"MousePressed\" To=\"MouseOut\">\n                                        <Storyboard>\n                                            <DoubleAnimationUsingKeyFrames Storyboard.TargetProperty=\"ScaleX\" Storyboard.TargetName=\"ScaleTransform\">\n                                                <EasingDoubleKeyFrame KeyTime=\"0:0:0.12\" Value=\"0\">\n                                                    <EasingDoubleKeyFrame.EasingFunction>\n                                                        <SineEase EasingMode=\"EaseIn\" />\n                                                    </EasingDoubleKeyFrame.EasingFunction>\n                                                </EasingDoubleKeyFrame>\n                                            </DoubleAnimationUsingKeyFrames>\n                                            <DoubleAnimationUsingKeyFrames Storyboard.TargetProperty=\"ScaleY\" Storyboard.TargetName=\"ScaleTransform\">\n                                                <EasingDoubleKeyFrame KeyTime=\"0:0:0.12\" Value=\"0\">\n                                                    <EasingDoubleKeyFrame.EasingFunction>\n                                                        <SineEase EasingMode=\"EaseIn\" />\n                                                    </EasingDoubleKeyFrame.EasingFunction>\n                                                </EasingDoubleKeyFrame>\n                                            </DoubleAnimationUsingKeyFrames>\n                                            <DoubleAnimationUsingKeyFrames Storyboard.TargetProperty=\"Opacity\" Storyboard.TargetName=\"ClickEllipse\">\n                                                <EasingDoubleKeyFrame KeyTime=\"0:0:0.12\" Value=\"0\"/>\n                                            </DoubleAnimationUsingKeyFrames>\n                                        </Storyboard>\n                                    </VisualTransition>\n                                    <VisualTransition From=\"MousePressed\" To=\"Normal\">\n                                        <Storyboard>\n                                            <DoubleAnimationUsingKeyFrames Storyboard.TargetProperty=\"ScaleX\" Storyboard.TargetName=\"ScaleTransform\">\n                                                <EasingDoubleKeyFrame KeyTime=\"0:0:0.30\" Value=\"1\" x:Name=\"MousePressedToNormalScaleXKeyFrame\"/>\n                                                <EasingDoubleKeyFrame KeyTime=\"0:0:0.50\" Value=\"1\"/>\n                                                <EasingDoubleKeyFrame KeyTime=\"0:0:0.50\" Value=\"0\"/>\n                                            </DoubleAnimationUsingKeyFrames>\n                                            <DoubleAnimationUsingKeyFrames Storyboard.TargetProperty=\"ScaleY\" Storyboard.TargetName=\"ScaleTransform\">\n                                                <EasingDoubleKeyFrame KeyTime=\"0:0:0.30\" Value=\"1\" x:Name=\"MousePressedToNormalScaleYKeyFrame\"/>\n                                                <EasingDoubleKeyFrame KeyTime=\"0:0:0.50\" Value=\"1\"/>\n                                                <EasingDoubleKeyFrame KeyTime=\"0:0:0.50\" Value=\"0\"/>\n                                            </DoubleAnimationUsingKeyFrames>\n                                            <DoubleAnimationUsingKeyFrames Storyboard.TargetProperty=\"Opacity\" Storyboard.TargetName=\"ClickEllipse\">\n                                                <EasingDoubleKeyFrame KeyTime=\"0:0:0.05\" Value=\".26\"/>\n                                                <EasingDoubleKeyFrame KeyTime=\"0:0:0.30\" Value=\".26\"/>\n                                                <EasingDoubleKeyFrame KeyTime=\"0:0:0.50\" Value=\"0\">\n                                                    <EasingDoubleKeyFrame.EasingFunction>\n                                                        <SineEase EasingMode=\"EaseOut\" />\n                                                    </EasingDoubleKeyFrame.EasingFunction>\n                                                </EasingDoubleKeyFrame>\n                                            </DoubleAnimationUsingKeyFrames>\n                                        </Storyboard>\n                                    </VisualTransition>\n                                </VisualStateGroup.Transitions>\n                                <VisualState x:Name=\"Normal\">\n                                    <Storyboard>\n                                        <DoubleAnimation Storyboard.TargetProperty=\"ScaleX\" Storyboard.TargetName=\"ScaleTransform\" To=\"0\"/>\n                                        <DoubleAnimation Storyboard.TargetProperty=\"ScaleY\" Storyboard.TargetName=\"ScaleTransform\" To=\"0\"/>\n                                        <DoubleAnimation Storyboard.TargetProperty=\"Opacity\" Storyboard.TargetName=\"ClickEllipse\" To=\"0\"/>\n                                    </Storyboard>\n                                </VisualState>\n                                <VisualState x:Name=\"MousePressed\">\n                                    <Storyboard>\n                                        <DoubleAnimation Storyboard.TargetProperty=\"ScaleX\" Storyboard.TargetName=\"ScaleTransform\" To=\"1\"/>\n                                        <DoubleAnimation Storyboard.TargetProperty=\"ScaleY\" Storyboard.TargetName=\"ScaleTransform\" To=\"1\"/>\n                                        <DoubleAnimation Storyboard.TargetProperty=\"Opacity\" Storyboard.TargetName=\"ClickEllipse\" To=\"0.26\"/>\n                                    </Storyboard>\n                                </VisualState>\n                                <VisualState x:Name=\"MouseOut\">\n                                    <Storyboard>\n                                        <DoubleAnimation Storyboard.TargetProperty=\"ScaleX\" Storyboard.TargetName=\"ScaleTransform\" To=\"0\"/>\n                                        <DoubleAnimation Storyboard.TargetProperty=\"ScaleY\" Storyboard.TargetName=\"ScaleTransform\" To=\"0\"/>\n                                        <DoubleAnimation Storyboard.TargetProperty=\"Opacity\" Storyboard.TargetName=\"ClickEllipse\" To=\"0\"/>\n                                    </Storyboard>\n                                </VisualState>\n                            </VisualStateGroup>\n                        </VisualStateManager.VisualStateGroups>\n\n                        <Canvas IsHitTestVisible=\"False\" HorizontalAlignment=\"Stretch\" VerticalAlignment=\"Stretch\">\n                            <Ellipse x:Name=\"ClickEllipse\" Fill=\"{TemplateBinding Feedback}\" Opacity=\"0\" \n                                     Width=\"{Binding RelativeSource={RelativeSource TemplatedParent}, Path=RippleSize}\" \n                                     Height=\"{Binding RelativeSource={RelativeSource TemplatedParent}, Path=RippleSize}\" \n                                     Canvas.Left=\"{Binding RelativeSource={RelativeSource TemplatedParent}, Path=RippleX}\" \n                                     Canvas.Top=\"{Binding RelativeSource={RelativeSource TemplatedParent}, Path=RippleY}\"\n                                     RenderTransformOrigin=\".5,.5\">\n                                <Ellipse.RenderTransform>\n                                    <TransformGroup>\n                                        <ScaleTransform x:Name=\"ScaleTransform\" ScaleX=\"0\" ScaleY=\"0\" />\n                                        <SkewTransform/>\n                                        <RotateTransform/>\n                                        <TranslateTransform x:Name=\"TranslateTransform\"/>\n                                    </TransformGroup>\n                                </Ellipse.RenderTransform>\n                            </Ellipse>\n                        </Canvas>\n                        <ContentPresenter Content=\"{TemplateBinding Content}\"\n                                          ContentStringFormat=\"{TemplateBinding ContentStringFormat}\"\n                                          ContentTemplate=\"{TemplateBinding ContentTemplate}\"\n                                          ContentTemplateSelector=\"{TemplateBinding ContentTemplateSelector}\"\n                                          Margin=\"{TemplateBinding Padding}\"\n                                          HorizontalAlignment=\"{TemplateBinding HorizontalContentAlignment}\"\n                                          VerticalAlignment=\"{TemplateBinding VerticalContentAlignment}\"\n                                          RecognizesAccessKey=\"{TemplateBinding RecognizesAccessKey}\"\n                                          SnapsToDevicePixels=\"{TemplateBinding SnapsToDevicePixels}\" />\n                    </Grid>\n                </ControlTemplate>\n            </Setter.Value>\n        </Setter>\n    </Style>\n\n    <Style TargetType=\"{x:Type local:DragablzIcon}\">\n        <Setter Property=\"Width\" Value=\"16\" />\n        <Setter Property=\"Height\" Value=\"16\" />\n        <Setter Property=\"ToolTip\" Value=\"Dragablz\" />\n        <Setter Property=\"Background\" Value=\"Transparent\" />\n        <Setter Property=\"Template\">\n            <Setter.Value>\n                <ControlTemplate TargetType=\"{x:Type local:DragablzIcon}\">\n                    <Border Background=\"{TemplateBinding Background}\"\n                            BorderBrush=\"{TemplateBinding BorderBrush}\"\n                            BorderThickness=\"{TemplateBinding BorderThickness}\">\n                        <Path Data=\"M7.5937495,21.279167 L52.96875,21.279167 C60.812496,21.279167 67.34375,22.935417 72.5625,26.247917 C78.71875,30.154171 81.796875,35.794796 81.796875,43.169792 C81.796875,48.888542 79.8125,54.935417 75.84375,61.310417 C70.59375,69.716667 62.968746,76.232292 52.96875,80.857292 C43.75,85.107292 33.84375,87.232292 23.25,87.232292 L7.78125,87.232292 L24.75,39.138542 L41.671875,39.138542 L27.28125,79.732292 C33.4375,79.732292 39.539063,77.841667 45.585938,74.060417 C51.632809,70.279167 56.046871,65.607292 58.828125,60.044792 C61.328121,55.138542 62.578121,51.044792 62.578125,47.763542 C62.578121,42.388542 61.078121,38.529167 58.078125,36.185417 C55.390621,34.122921 51.265621,33.091671 45.703125,33.091667 L0.375,33.091667 z\" \n                              Fill=\"{TemplateBinding Foreground}\" \n                              Stretch=\"Uniform\" \n                              />\n                    </Border>\n                </ControlTemplate>\n            </Setter.Value>\n        </Setter>\n    </Style>\n\n    <Color x:Key=\"CloseCommandHighlightColor\">#e04343</Color>\n\n    <!-- these tab styles are as close as possible to the default .net styles, so the tab will fit straight in to an unstyled app -->\n    <SolidColorBrush x:Key=\"TabItem.Selected.Background\" Color=\"#FFFFFF\"/>\n    <SolidColorBrush x:Key=\"TabItem.Selected.Border\" Color=\"#ACACAC\"/>\n    <SolidColorBrush x:Key=\"Button.Static.Background\" Color=\"#FFDDDDDD\"/>\n    <SolidColorBrush x:Key=\"Button.Static.Border\" Color=\"#FF707070\"/>\n    <SolidColorBrush x:Key=\"Button.MouseOver.Background\" Color=\"#FFBEE6FD\"/>\n    <SolidColorBrush x:Key=\"Button.MouseOver.Border\" Color=\"#FF3C7FB1\"/>\n    <SolidColorBrush x:Key=\"Button.Pressed.Background\" Color=\"#FFC4E5F6\"/>\n    <SolidColorBrush x:Key=\"Button.Pressed.Border\" Color=\"#FF2C628B\"/>\n    <SolidColorBrush x:Key=\"Button.Disabled.Background\" Color=\"#FFF4F4F4\"/>\n    <SolidColorBrush x:Key=\"Button.Disabled.Border\" Color=\"#FFADB2B5\"/>\n    <SolidColorBrush x:Key=\"Button.Disabled.Foreground\" Color=\"#FF838383\"/>\n\n    <LinearGradientBrush x:Key=\"TabItem.Static.Background\" EndPoint=\"0,1\" StartPoint=\"0,0\">\n        <GradientStop Color=\"#F0F0F0\" Offset=\"0.0\"/>\n        <GradientStop Color=\"#E5E5E5\" Offset=\"1.0\"/>\n    </LinearGradientBrush>\n    <SolidColorBrush x:Key=\"TabItem.Static.Border\" Color=\"#ACACAC\"/>\n    <LinearGradientBrush x:Key=\"TabItem.MouseOver.Background\" EndPoint=\"0,1\" StartPoint=\"0,0\">\n        <GradientStop Color=\"#ECF4FC\" Offset=\"0.0\"/>\n        <GradientStop Color=\"#DCECFC\" Offset=\"1.0\"/>\n    </LinearGradientBrush>\n    <SolidColorBrush x:Key=\"TabItem.MouseOver.Border\" Color=\"#7EB4EA\"/>\n    <SolidColorBrush x:Key=\"TabItem.Disabled.Background\" Color=\"#F0F0F0\"/>\n    <SolidColorBrush x:Key=\"TabItem.Disabled.Border\" Color=\"#D9D9D9\"/>\n\n\n    <Style TargetType=\"{x:Type Thumb}\" x:Key=\"InvisibleThumbStyle\">\n        <Setter Property=\"Background\" Value=\"Transparent\" />\n        <Setter Property=\"Template\">\n            <Setter.Value>\n                <ControlTemplate>\n                    <Grid Background=\"{TemplateBinding Background}\" />\n                </ControlTemplate>\n            </Setter.Value>\n        </Setter>\n    </Style>\n\n    <Style TargetType=\"{x:Type themes:SystemCommandIcon}\">\n        <Setter Property=\"Width\" Value=\"10\" />\n        <Setter Property=\"Height\" Value=\"10\" />\n        <Setter Property=\"Margin\" Value=\"4 2 4 2\" />\n        <Setter Property=\"Template\">\n            <Setter.Value>\n                <ControlTemplate TargetType=\"{x:Type themes:SystemCommandIcon}\">\n                    <Path x:Name=\"Path\" \n                          Data=\"M0.5,71 L70,0.5 M0.5,1 L70,70.5\" \n                          Stretch=\"Uniform\"\n                          Stroke=\"{TemplateBinding Foreground}\"\n                          StrokeThickness=\"1.5\"\n                          StrokeStartLineCap=\"Square\" \n                          StrokeEndLineCap=\"Square\"\n                          SnapsToDevicePixels=\"True\"                          \n                          />\n                    <ControlTemplate.Triggers>\n                        <Trigger Property=\"SystemCommandType\" Value=\"MaximizeWindow\">\n                            <Setter TargetName=\"Path\" Property=\"Data\" Value=\"M2.5,2.5 L67.5,2.5 L67.5,68 L2.5,68 z\" />\n                            <Setter TargetName=\"Path\" Property=\"StrokeThickness\" Value=\"1.25\" />\n                            <Setter TargetName=\"Path\" Property=\"RenderOptions.EdgeMode\" Value=\"Aliased\" />\n                        </Trigger>\n                        <Trigger Property=\"SystemCommandType\" Value=\"MinimzeWindow\">\n                            <Setter TargetName=\"Path\" Property=\"Data\" Value=\"M165,40 L234.5,39.5\" />\n                            <Setter TargetName=\"Path\" Property=\"StrokeStartLineCap\" Value=\"Flat\" />\n                            <Setter TargetName=\"Path\" Property=\"StrokeEndLineCap\" Value=\"Flat\" />\n                            <Setter TargetName=\"Path\" Property=\"StrokeThickness\" Value=\"1.25\" />\n                            <Setter TargetName=\"Path\" Property=\"RenderOptions.EdgeMode\" Value=\"Aliased\" />\n                        </Trigger>\n                        <Trigger Property=\"SystemCommandType\" Value=\"RestoreWindow\">\n                            <Setter TargetName=\"Path\" Property=\"Data\" Value=\"M2.5,13 L57.576,13 L57.576,69 L2.5,69 z M12.424,2.5 L67.5,2.5 67.5,58.5 57.576,58.5 57.576,13 12.424,13 z\" />\n                            <Setter TargetName=\"Path\" Property=\"StrokeThickness\" Value=\"1.25\" />\n                            <Setter TargetName=\"Path\" Property=\"RenderOptions.EdgeMode\" Value=\"Aliased\" />\n                        </Trigger>\n                    </ControlTemplate.Triggers>\n                </ControlTemplate>\n            </Setter.Value>\n\n        </Setter>\n    </Style>\n\n    <Style TargetType=\"{x:Type Button}\" x:Key=\"MenuCommandButtonStyle\">\n        <Setter Property=\"FocusVisualStyle\" Value=\"{StaticResource FocusVisual}\"/>\n        <Setter Property=\"Background\" Value=\"Transparent\"/>\n        <Setter Property=\"BorderBrush\" Value=\"Transparent\"/>\n        <Setter Property=\"Foreground\" Value=\"{DynamicResource {x:Static SystemColors.ControlTextBrushKey}}\"/>\n        <Setter Property=\"BorderThickness\" Value=\"0\"/>\n        <Setter Property=\"HorizontalContentAlignment\" Value=\"Center\"/>\n        <Setter Property=\"VerticalContentAlignment\" Value=\"Center\"/>\n        <Setter Property=\"Padding\" Value=\"1\"/>\n        <Setter Property=\"Opacity\" Value=\".8\"/>\n        <Setter Property=\"Width\" Value=\"24\"/>\n        <Setter Property=\"Height\" Value=\"20\"/>\n        <Setter Property=\"Template\">\n            <Setter.Value>\n                <ControlTemplate TargetType=\"{x:Type Button}\">\n                    <Border x:Name=\"border\" BorderBrush=\"{TemplateBinding BorderBrush}\" BorderThickness=\"{TemplateBinding BorderThickness}\" Background=\"{TemplateBinding Background}\" SnapsToDevicePixels=\"true\">\n                        <ContentPresenter x:Name=\"contentPresenter\" Focusable=\"False\" HorizontalAlignment=\"{TemplateBinding HorizontalContentAlignment}\" Margin=\"{TemplateBinding Padding}\" RecognizesAccessKey=\"True\" SnapsToDevicePixels=\"{TemplateBinding SnapsToDevicePixels}\" VerticalAlignment=\"{TemplateBinding VerticalContentAlignment}\"/>\n                    </Border>\n                    <ControlTemplate.Triggers>\n                        <Trigger Property=\"IsDefaulted\" Value=\"true\">\n                            <Setter Property=\"BorderBrush\" TargetName=\"border\" Value=\"{DynamicResource {x:Static SystemColors.HighlightBrushKey}}\"/>\n                        </Trigger>\n                        <Trigger Property=\"IsEnabled\" Value=\"false\">\n                            <Setter Property=\"Background\" TargetName=\"border\" Value=\"{StaticResource Button.Disabled.Background}\"/>\n                            <Setter Property=\"BorderBrush\" TargetName=\"border\" Value=\"{StaticResource Button.Disabled.Border}\"/>\n                            <Setter Property=\"TextElement.Foreground\" TargetName=\"contentPresenter\" Value=\"{StaticResource Button.Disabled.Foreground}\"/>\n                        </Trigger>\n                    </ControlTemplate.Triggers>\n                </ControlTemplate>\n            </Setter.Value>\n        </Setter>\n        <Style.Triggers>\n            <Trigger Property=\"IsMouseOver\" Value=\"true\">\n                <Setter Property=\"Background\" Value=\"{x:Static local:DragablzColors.WindowGlassBrush}\"/>\n                <Setter Property=\"Foreground\" Value=\"{x:Static SystemColors.HighlightTextBrush}\" />\n            </Trigger>\n            <Trigger Property=\"IsPressed\" Value=\"true\">\n                <Setter Property=\"Opacity\" Value=\"1\"/>\n            </Trigger>\n        </Style.Triggers>\n    </Style>\n\n    <Style TargetType=\"{x:Type Button}\" x:Key=\"CloseMenuCommandButtonStyle\" BasedOn=\"{StaticResource MenuCommandButtonStyle}\">\n        <Setter Property=\"Background\">\n            <Setter.Value>\n                <SolidColorBrush Color=\"{x:Static SystemColors.ActiveBorderColor}\" />\n            </Setter.Value>\n        </Setter>\n        <Setter Property=\"Width\" Value=\"46\" />\n        <Setter Property=\"Margin\" Value=\"0 0 4 0\" />\n        <Setter Property=\"Foreground\" Value=\"{x:Static SystemColors.HighlightTextBrush}\" />\n        <Style.Triggers>\n            <Trigger Property=\"IsMouseOver\" Value=\"true\">\n                <Setter Property=\"Background\">\n                    <Setter.Value>\n                        <SolidColorBrush Color=\"{StaticResource CloseCommandHighlightColor}\" />\n                    </Setter.Value>\n                </Setter>\n                <Setter Property=\"Opacity\" Value=\"1\"/>\n            </Trigger>\n        </Style.Triggers>\n    </Style>\n\n    <Style TargetType=\"{x:Type Button}\" x:Key=\"CloseItemCommandButtonStyle\" BasedOn=\"{StaticResource MenuCommandButtonStyle}\">\n        <Setter Property=\"Template\">\n            <Setter.Value>\n                <ControlTemplate>\n                    <Grid>\n                        <Ellipse Width=\"{TemplateBinding Width}\"\n                                 Height=\"{TemplateBinding Height}\"\n                                 Fill=\"{TemplateBinding Background}\"/>\n                        <Path x:Name=\"Path\"\n                              Data=\"M0.5,71 L70,0.5 M0.5,1 L70,70.5\" \n                              Width=\"6\" Height=\"6\"\n                              Stretch=\"Uniform\"\n                              Stroke=\"{TemplateBinding Foreground}\"\n                              StrokeThickness=\"1.5\"\n                              StrokeStartLineCap=\"Square\" \n                              StrokeEndLineCap=\"Square\"\n                              SnapsToDevicePixels=\"True\" />\n                    </Grid>\n                </ControlTemplate>\n            </Setter.Value>\n        </Setter>\n        <Setter Property=\"Background\">\n            <Setter.Value>\n                <SolidColorBrush Color=\"{x:Static SystemColors.ActiveBorderColor}\" />\n            </Setter.Value>\n        </Setter>\n        <Setter Property=\"Width\" Value=\"12\" />\n        <Setter Property=\"Height\" Value=\"12\" />\n        <Setter Property=\"Margin\" Value=\"4 0 2 0\" />\n        <Setter Property=\"Foreground\" Value=\"{x:Static SystemColors.HighlightTextBrush}\" />\n        <Style.Triggers>\n            <Trigger Property=\"IsMouseOver\" Value=\"true\">\n                <Setter Property=\"Background\">\n                    <Setter.Value>\n                        <SolidColorBrush Color=\"{StaticResource CloseCommandHighlightColor}\" />\n                    </Setter.Value>\n                </Setter>\n                <Setter Property=\"Opacity\" Value=\"1\"/>\n            </Trigger>\n        </Style.Triggers>\n    </Style>\n\n    <Style TargetType=\"{x:Type Button}\" x:Key=\"AddItemCommandButtonStyle\" BasedOn=\"{StaticResource MenuCommandButtonStyle}\">\n        <Setter Property=\"Template\">\n            <Setter.Value>\n                <ControlTemplate>\n                    <Grid>\n                        <Ellipse Width=\"{TemplateBinding Width}\"\n                                 Height=\"{TemplateBinding Height}\"\n                                 Fill=\"{TemplateBinding Background}\"/>\n                        <Path x:Name=\"Path\"\n                              Data=\"M38,6L38.0003451911513,70.6666666666666 M70.3336667356886,38L5.50002465137562,38\" \n                              Width=\"6\" Height=\"6\"\n                              Stretch=\"Uniform\"\n                              Stroke=\"{TemplateBinding Foreground}\"\n                              StrokeThickness=\"1.5\"\n                              StrokeStartLineCap=\"Square\" \n                              StrokeEndLineCap=\"Square\"\n                              SnapsToDevicePixels=\"True\" />\n                    </Grid>\n                </ControlTemplate>\n            </Setter.Value>\n        </Setter>\n        <Setter Property=\"Background\">\n            <Setter.Value>\n                <SolidColorBrush Color=\"{x:Static SystemColors.ActiveBorderColor}\" />\n            </Setter.Value>\n        </Setter>\n        <Setter Property=\"Width\" Value=\"12\" />\n        <Setter Property=\"Height\" Value=\"12\" />\n        <Setter Property=\"Margin\" Value=\"4 0 2 0\" />\n        <Setter Property=\"Foreground\" Value=\"{x:Static SystemColors.HighlightTextBrush}\" />\n        <Style.Triggers>\n            <Trigger Property=\"IsMouseOver\" Value=\"true\">\n                <Setter Property=\"Background\" Value=\"{x:Static local:DragablzColors.WindowGlassBrush}\"/>\n                <Setter Property=\"Foreground\" Value=\"{x:Static SystemColors.HighlightTextBrush}\" />\n            </Trigger>\n            <Trigger Property=\"IsPressed\" Value=\"true\">\n                <Setter Property=\"Opacity\" Value=\"1\"/>\n            </Trigger>\n        </Style.Triggers>\n    </Style>\n\n    <Style TargetType=\"{x:Type Button}\" x:Key=\"HideDisabledButtonStyle\">\n        <Setter Property=\"Visibility\" Value=\"{Binding RelativeSource={RelativeSource TemplatedParent}, Path=(dockablz:Layout.IsFloatingInLayout), Converter={StaticResource BooleanToVisibilityConverter}}\" />\n        <Style.Triggers>\n            <Trigger Property=\"IsEnabled\" Value=\"False\">\n                <Setter Property=\"Visibility\" Value=\"Collapsed\" />\n            </Trigger>\n        </Style.Triggers>\n    </Style>\n\n    <ControlTemplate x:Key=\"WindowTemplateKey\" TargetType=\"{x:Type local:DragablzWindow}\">\n        <Border BorderBrush=\"{TemplateBinding BorderBrush}\" BorderThickness=\"{TemplateBinding BorderThickness}\" Background=\"{TemplateBinding Background}\">\n            <Grid>\n                <AdornerDecorator>\n                    <Grid>\n                        <Thumb Style=\"{StaticResource InvisibleThumbStyle}\"\n                                       x:Name=\"PART_WindowRestoreThumb\"/>\n                        <ContentPresenter/>\n                    </Grid>\n                </AdornerDecorator>\n                <ResizeGrip x:Name=\"WindowResizeGrip\" HorizontalAlignment=\"Right\" IsTabStop=\"false\" Visibility=\"Collapsed\" VerticalAlignment=\"Bottom\"/>\n            </Grid>\n        </Border>\n        <ControlTemplate.Triggers>\n            <Trigger Property=\"WindowState\" Value=\"Maximized\">\n                <Setter TargetName=\"PART_WindowRestoreThumb\" Property=\"IsHitTestVisible\" Value=\"True\" />\n            </Trigger>\n            <MultiTrigger>\n                <MultiTrigger.Conditions>\n                    <Condition Property=\"ResizeMode\" Value=\"CanResizeWithGrip\"/>\n                    <Condition Property=\"WindowState\" Value=\"Normal\"/>\n                </MultiTrigger.Conditions>\n                <Setter Property=\"Visibility\" TargetName=\"WindowResizeGrip\" Value=\"Visible\"/>\n            </MultiTrigger>\n        </ControlTemplate.Triggers>\n    </ControlTemplate>\n\n    <Style TargetType=\"{x:Type local:DragablzWindow}\">\n        <Setter Property=\"WindowStyle\" Value=\"None\" />\n        <Setter Property=\"AllowsTransparency\" Value=\"True\" />\n        <Setter Property=\"Foreground\" Value=\"{DynamicResource {x:Static SystemColors.WindowTextBrushKey}}\"/>\n        <Setter Property=\"Background\" Value=\"{x:Static local:DragablzColors.WindowInactiveBrush}\"/>\n        <Setter Property=\"BorderBrush\" Value=\"{x:Static SystemColors.ActiveBorderBrush}\" />\n        <Setter Property=\"BorderThickness\" Value=\"1\" />\n        <Setter Property=\"ResizeMode\" Value=\"CanResize\" />\n        <Setter Property=\"Template\">\n            <Setter.Value>\n                <ControlTemplate TargetType=\"{x:Type local:DragablzWindow}\">\n                    <Grid>\n                        <Border BorderBrush=\"{TemplateBinding BorderBrush}\" BorderThickness=\"{TemplateBinding BorderThickness}\" Background=\"{TemplateBinding Background}\">\n                            <AdornerDecorator>\n                                <Grid>\n                                    <Grid x:Name=\"PART_WindowSurface\" Background=\"Transparent\" />\n                                    <Thumb Style=\"{StaticResource InvisibleThumbStyle}\"\n                                           IsHitTestVisible=\"False\"\n                                           x:Name=\"PART_WindowRestoreThumb\"/>\n                                    <StackPanel x:Name=\"SystemCommandsPanel\" \n                                                HorizontalAlignment=\"Right\"\n                                                VerticalAlignment=\"Top\"\n                                                Orientation=\"Horizontal\">\n                                        <Button Command=\"{x:Static local:DragablzWindow.MinimizeWindowCommand}\"\n                                                Style=\"{StaticResource MenuCommandButtonStyle}\">\n                                            <themes:SystemCommandIcon SystemCommandType=\"MinimzeWindow\" />\n                                        </Button>\n                                        <Button Command=\"{x:Static local:DragablzWindow.RestoreWindowCommand}\"\n                                                Visibility=\"{TemplateBinding WindowState, Converter={StaticResource EqualityToVisibilityConverter}, ConverterParameter={x:Static WindowState.Maximized}}\"\n                                                Style=\"{StaticResource MenuCommandButtonStyle}\">\n                                            <themes:SystemCommandIcon SystemCommandType=\"RestoreWindow\" />\n                                        </Button>\n                                        <Button Command=\"{x:Static local:DragablzWindow.MaximizeWindowCommand}\"\n                                                Visibility=\"{TemplateBinding WindowState, Converter={StaticResource EqualityToVisibilityConverter}, ConverterParameter={x:Static WindowState.Normal}}\"\n                                                Style=\"{StaticResource MenuCommandButtonStyle}\">\n                                            <themes:SystemCommandIcon SystemCommandType=\"MaximizeWindow\" />\n                                        </Button>\n                                        <Button Command=\"{x:Static local:DragablzWindow.CloseWindowCommand}\"\n                                                Style=\"{StaticResource CloseMenuCommandButtonStyle}\"\n                                                x:Name=\"CloseWindowCommandButton\"\n                                                >\n                                            <themes:SystemCommandIcon SystemCommandType=\"CloseWindow\" />\n                                        </Button>\n                                    </StackPanel>\n                                    <ContentPresenter Margin=\"4\"/>\n                                </Grid>\n                            </AdornerDecorator>\n                        </Border>\n                        <Thumb Style=\"{StaticResource InvisibleThumbStyle}\"\n                               x:Name=\"PART_WindowResizeThumb\"/>\n                    </Grid>\n                    <ControlTemplate.Triggers>\n                        <Trigger Property=\"WindowState\" Value=\"Maximized\">\n                            <Setter TargetName=\"PART_WindowRestoreThumb\" Property=\"IsHitTestVisible\" Value=\"True\" />\n                        </Trigger>\n                        <Trigger Property=\"IsBeingDraggedByTab\" Value=\"True\">\n                            <Setter TargetName=\"SystemCommandsPanel\" Property=\"Visibility\" Value=\"Collapsed\"></Setter>\n                        </Trigger>\n                        <Trigger Property=\"IsActive\" Value=\"True\">\n                            <Setter TargetName=\"CloseWindowCommandButton\" Property=\"Background\">\n                                <Setter.Value>\n                                    <SolidColorBrush Color=\"{StaticResource CloseCommandHighlightColor}\" />\n                                </Setter.Value>\n                            </Setter>\n                        </Trigger>\n                    </ControlTemplate.Triggers>\n                </ControlTemplate>\n            </Setter.Value>\n        </Setter>\n        <Style.Triggers>\n            <Trigger Property=\"ResizeMode\" Value=\"CanResizeWithGrip\">\n                <Setter Property=\"Template\" Value=\"{StaticResource WindowTemplateKey}\"/>\n            </Trigger>\n            <Trigger Property=\"IsActive\" Value=\"True\">\n                <Setter Property=\"Background\" Value=\"{x:Static local:DragablzColors.WindowGlassBalancedBrush}\" />\n            </Trigger>\n            <Trigger Property=\"IsBeingDraggedByTab\" Value=\"True\">\n                <Setter Property=\"Background\" Value=\"Transparent\" />\n                <Setter Property=\"BorderBrush\" Value=\"Transparent\" />\n            </Trigger>\n        </Style.Triggers>\n    </Style>\n\n    <Style TargetType=\"{x:Type dockablz:DropZone}\">\n        <Setter Property=\"Opacity\" Value=\".25\" />\n        <Setter Property=\"Template\">\n            <Setter.Value>\n                <ControlTemplate TargetType=\"{x:Type dockablz:DropZone}\">\n                    <Grid>\n                        <Path Fill=\"{TemplateBinding Foreground}\" \n                              Visibility=\"{TemplateBinding Location, Converter={StaticResource EqualityToVisibilityConverter}, ConverterParameter={x:Static dockablz:DropZoneLocation.Top}}\"\n                              >\n                            <Path.Data>\n                                <PathGeometry>\n                                    <PathFigure x:Name=\"PathFigure\" StartPoint=\"160, 0\">\n                                        <ArcSegment SweepDirection=\"Clockwise\"\n                                                    Size=\"60,60\"\n                                                    Point=\"0, 0\"                                                \n                                                />\n                                    </PathFigure>\n                                </PathGeometry>\n                            </Path.Data>\n                        </Path>\n                        <Path Fill=\"{TemplateBinding Foreground}\" \n                              Visibility=\"{TemplateBinding Location, Converter={StaticResource EqualityToVisibilityConverter}, ConverterParameter={x:Static dockablz:DropZoneLocation.Right}}\"\n                              >\n                            <Path.Data>\n                                <PathGeometry>\n                                    <PathFigure StartPoint=\"60, 160\">\n                                        <ArcSegment SweepDirection=\"Clockwise\"\n                                                    Size=\"60,60\"\n                                                    Point=\"60, 0\"                                                \n                                                    />\n                                    </PathFigure>\n                                </PathGeometry>\n                            </Path.Data>\n                        </Path>\n                        <Path Fill=\"{TemplateBinding Foreground}\" \n                              Visibility=\"{TemplateBinding Location, Converter={StaticResource EqualityToVisibilityConverter}, ConverterParameter={x:Static dockablz:DropZoneLocation.Bottom}}\"\n                              >\n                            <Path.Data>\n                                <PathGeometry>\n                                    <PathFigure StartPoint=\"0, 60\">\n                                        <ArcSegment SweepDirection=\"Clockwise\"\n                                                    Size=\"60,60\"\n                                                    Point=\"160, 60\"                                                \n                                                    />\n                                    </PathFigure>\n                                </PathGeometry>\n                            </Path.Data>\n                        </Path>\n                        <Path Fill=\"{TemplateBinding Foreground}\" \n                              Visibility=\"{TemplateBinding Location, Converter={StaticResource EqualityToVisibilityConverter}, ConverterParameter={x:Static dockablz:DropZoneLocation.Left}}\"\n                              >\n                            <Path.Data>\n                                <PathGeometry>\n                                    <PathFigure StartPoint=\"0, 0\">\n                                        <ArcSegment SweepDirection=\"Clockwise\"\n                                                    Size=\"60,60\"\n                                                    Point=\"0, 160\"                                                \n                                                    />\n                                    </PathFigure>\n                                </PathGeometry>\n                            </Path.Data>\n                        </Path>\n                        <Ellipse Fill=\"{TemplateBinding Foreground}\"\n                                 Visibility=\"{TemplateBinding Location, Converter={StaticResource EqualityToVisibilityConverter}, ConverterParameter={x:Static dockablz:DropZoneLocation.Floating}}\"\n                                 Width=\"120\" Height=\"120\"\n                                 />\n                    </Grid>\n                </ControlTemplate>\n            </Setter.Value>\n        </Setter>\n        <Style.Triggers>\n            <Trigger Property=\"IsOffered\" Value=\"True\">\n                <Setter Property=\"Opacity\" Value=\"0.5\" />\n            </Trigger>\n        </Style.Triggers>\n    </Style>\n\n    <Style TargetType=\"{x:Type local:DragablzItemsControl}\">\n        <Setter Property=\"HorizontalAlignment\" Value=\"Left\" />\n        <Setter Property=\"VerticalAlignment\" Value=\"Top\" />\n        <Setter Property=\"ItemsPanel\">\n            <Setter.Value>\n                <ItemsPanelTemplate>\n                    <Canvas IsItemsHost=\"True\" />\n                </ItemsPanelTemplate>\n            </Setter.Value>\n        </Setter>\n        <Setter Property=\"Template\">\n            <Setter.Value>\n                <ControlTemplate TargetType=\"{x:Type local:DragablzItemsControl}\">\n                    <Border BorderThickness=\"{TemplateBinding Border.BorderThickness}\" Padding=\"{TemplateBinding Control.Padding}\" BorderBrush=\"{TemplateBinding Border.BorderBrush}\" Background=\"{TemplateBinding Panel.Background}\" SnapsToDevicePixels=\"True\">\n                        <ScrollViewer HorizontalScrollBarVisibility=\"Auto\" VerticalScrollBarVisibility=\"Auto\"\n                                      Width=\"{TemplateBinding ActualWidth}\"\n                                      Height=\"{TemplateBinding ActualHeight}\"\n                                      Background=\"{x:Null}\">\n                            <ItemsPresenter SnapsToDevicePixels=\"{TemplateBinding UIElement.SnapsToDevicePixels}\"\n                                            HorizontalAlignment=\"Left\"\n                                            VerticalAlignment=\"Top\"\n                                            Width=\"{TemplateBinding ItemsPresenterWidth}\"\n                                            Height=\"{TemplateBinding ItemsPresenterHeight}\"/>\n                        </ScrollViewer>\n                    </Border>\n                </ControlTemplate>\n            </Setter.Value>\n        </Setter>\n    </Style>\n\n    <ControlTemplate x:Key=\"TabablzScrollViewerControlTemplate\" TargetType=\"{x:Type ScrollViewer}\">\n        <Grid x:Name=\"Grid\" Background=\"{TemplateBinding Background}\">\n            <Grid.ColumnDefinitions>\n                <ColumnDefinition Width=\"*\"/>\n                <ColumnDefinition Width=\"Auto\"/>\n            </Grid.ColumnDefinitions>\n            <Grid.RowDefinitions>\n                <RowDefinition Height=\"*\"/>\n                <RowDefinition Height=\"Auto\"/>\n            </Grid.RowDefinitions>\n            <ScrollContentPresenter x:Name=\"PART_ScrollContentPresenter\" CanContentScroll=\"{TemplateBinding CanContentScroll}\" CanHorizontallyScroll=\"False\" CanVerticallyScroll=\"False\" ContentTemplate=\"{TemplateBinding ContentTemplate}\" Content=\"{TemplateBinding Content}\" Grid.Column=\"0\" Margin=\"{TemplateBinding Padding}\" Grid.Row=\"0\"/>\n            <ScrollBar x:Name=\"PART_VerticalScrollBar\" AutomationProperties.AutomationId=\"VerticalScrollBar\" Cursor=\"Arrow\" Grid.Column=\"0\" Maximum=\"{TemplateBinding ScrollableHeight}\" Minimum=\"0\" Grid.Row=\"1\" Visibility=\"{TemplateBinding ComputedVerticalScrollBarVisibility}\" Value=\"{Binding VerticalOffset, Mode=OneWay, RelativeSource={RelativeSource TemplatedParent}}\" ViewportSize=\"{TemplateBinding ViewportHeight}\"\n                       Margin=\"0 1 0 0\" />\n            <ScrollBar x:Name=\"PART_HorizontalScrollBar\" AutomationProperties.AutomationId=\"HorizontalScrollBar\" Cursor=\"Arrow\" Grid.Column=\"1\" Maximum=\"{TemplateBinding ScrollableWidth}\" Minimum=\"0\" Orientation=\"Horizontal\" Grid.Row=\"0\" Visibility=\"{TemplateBinding ComputedHorizontalScrollBarVisibility}\" Value=\"{Binding HorizontalOffset, Mode=OneWay, RelativeSource={RelativeSource TemplatedParent}}\" ViewportSize=\"{TemplateBinding ViewportWidth}\" \n                       Width=\"36\" Height=\"20\"\n                       Margin=\"1 0 0 0\" />\n        </Grid>\n    </ControlTemplate>\n\n    <Style TargetType=\"{x:Type local:DragablzItemsControl}\" x:Key=\"TabablzDragablzItemsControlStyle\">\n        <Setter Property=\"HorizontalAlignment\" Value=\"Left\" />\n        <Setter Property=\"VerticalAlignment\" Value=\"Top\" />\n        <Setter Property=\"ItemsPanel\">\n            <Setter.Value>\n                <ItemsPanelTemplate>\n                    <Canvas IsItemsHost=\"True\" />\n                </ItemsPanelTemplate>\n            </Setter.Value>\n        </Setter>\n        <Setter Property=\"Template\">\n            <Setter.Value>\n                <ControlTemplate TargetType=\"{x:Type local:DragablzItemsControl}\">\n                    <Border BorderThickness=\"{TemplateBinding Border.BorderThickness}\" Padding=\"{TemplateBinding Control.Padding}\" BorderBrush=\"{TemplateBinding Border.BorderBrush}\" Background=\"{TemplateBinding Panel.Background}\" SnapsToDevicePixels=\"True\">\n                        <ScrollViewer HorizontalScrollBarVisibility=\"Auto\" VerticalScrollBarVisibility=\"Auto\"\n                                      Width=\"{TemplateBinding ActualWidth}\"\n                                      Height=\"{TemplateBinding ActualHeight}\"\n                                      Template=\"{StaticResource TabablzScrollViewerControlTemplate}\">\n                            <ItemsPresenter SnapsToDevicePixels=\"{TemplateBinding UIElement.SnapsToDevicePixels}\"\n                                            HorizontalAlignment=\"Left\"\n                                            VerticalAlignment=\"Top\"\n                                            Width=\"{TemplateBinding ItemsPresenterWidth}\"\n                                            Height=\"{TemplateBinding ItemsPresenterHeight}\"/>\n                        </ScrollViewer>\n                    </Border>\n                </ControlTemplate>\n            </Setter.Value>\n        </Setter>\n    </Style>\n\n    <Style TargetType=\"{x:Type local:DragablzItem}\">\n        <Style.Setters>\n            <Setter Property=\"Canvas.Left\" Value=\"{Binding X, RelativeSource={RelativeSource Self}}\" />\n            <Setter Property=\"Canvas.Top\" Value=\"{Binding Y, RelativeSource={RelativeSource Self}}\" />\n            <Setter Property=\"Template\">\n                <Setter.Value>\n                    <ControlTemplate TargetType=\"{x:Type local:DragablzItem}\">\n                        <Border BorderThickness=\"{TemplateBinding Border.BorderThickness}\" Padding=\"{TemplateBinding Control.Padding}\" BorderBrush=\"{TemplateBinding Border.BorderBrush}\" Background=\"{TemplateBinding Panel.Background}\" SnapsToDevicePixels=\"True\">\n                            <Grid>\n                                <Grid.ColumnDefinitions>\n                                    <ColumnDefinition Width=\"Auto\" />\n                                    <ColumnDefinition Width=\"*\" />\n                                </Grid.ColumnDefinitions>\n                                <Thumb Width=\"30\" Height=\"30\" Background=\"Yellow\" x:Name=\"PART_Thumb\" VerticalAlignment=\"Center\" />\n                                <ContentPresenter Grid.Column=\"1\" Content=\"{TemplateBinding ContentControl.Content}\" ContentTemplate=\"{TemplateBinding ContentControl.ContentTemplate}\" ContentStringFormat=\"{TemplateBinding ContentControl.ContentStringFormat}\" HorizontalAlignment=\"{TemplateBinding Control.HorizontalContentAlignment}\" VerticalAlignment=\"{TemplateBinding Control.VerticalContentAlignment}\" SnapsToDevicePixels=\"{TemplateBinding UIElement.SnapsToDevicePixels}\" />\n                            </Grid>\n                        </Border>\n                    </ControlTemplate>\n                </Setter.Value>\n            </Setter>\n        </Style.Setters>\n        <Style.Triggers>\n            <Trigger Property=\"IsDragging\" Value=\"True\">\n                <Setter Property=\"Opacity\" Value=\".95\" />\n            </Trigger>\n            <Trigger Property=\"IsSiblingDragging\" Value=\"True\">\n                <Setter Property=\"Opacity\" Value=\".5\" />\n            </Trigger>\n        </Style.Triggers>\n    </Style>\n\n    <Style TargetType=\"{x:Type local:HeaderedDragablzItem}\">\n        <Style.Setters>\n            <Setter Property=\"Padding\" Value=\"2\"/>\n            <Setter Property=\"BorderBrush\" Value=\"{StaticResource TabItem.Static.Border}\" />\n            <Setter Property=\"BorderThickness\" Value=\"1\" />\n            <Setter Property=\"Canvas.Left\" Value=\"{Binding X, RelativeSource={RelativeSource Self}}\" />\n            <Setter Property=\"Canvas.Top\" Value=\"{Binding Y, RelativeSource={RelativeSource Self}}\" />\n            <Setter Property=\"Template\">\n                <Setter.Value>\n                    <ControlTemplate TargetType=\"{x:Type local:HeaderedDragablzItem}\">\n                        <Grid Margin=\"{TemplateBinding Margin}\">\n                            <Border Background=\"White\">\n                                <Border.Effect>\n                                    <DropShadowEffect BlurRadius=\"10\" ShadowDepth=\"5\" Direction=\"315\" Color=\"Black\" Opacity=\".5\" />\n                                </Border.Effect>\n                            </Border>\n                            <Border BorderThickness=\"{TemplateBinding Border.BorderThickness}\" Padding=\"{TemplateBinding Control.Padding}\" BorderBrush=\"{TemplateBinding Border.BorderBrush}\" Background=\"{TemplateBinding Panel.Background}\" SnapsToDevicePixels=\"True\">\n                                <DockPanel>\n                                    <Grid DockPanel.Dock=\"Top\" Background=\"{StaticResource TabItem.Static.Background}\">\n                                        <ContentPresenter Content=\"{TemplateBinding HeaderContent}\" \n                                                          ContentTemplate=\"{TemplateBinding HeaderContentTemplate}\" \n                                                          ContentStringFormat=\"{TemplateBinding ContentControl.ContentStringFormat}\" HorizontalAlignment=\"{TemplateBinding Control.HorizontalContentAlignment}\" \n                                                          ContentTemplateSelector=\"{TemplateBinding HeaderContentTemplateSelector}\"\n                                                          VerticalAlignment=\"{TemplateBinding Control.VerticalContentAlignment}\" \n                                                          SnapsToDevicePixels=\"{TemplateBinding UIElement.SnapsToDevicePixels}\"\n                                                          Margin=\"{TemplateBinding Control.Padding }\"\n                                                          />\n                                        <Thumb HorizontalAlignment=\"Stretch\" VerticalContentAlignment=\"Stretch\" x:Name=\"PART_Thumb\"\n                                               Style=\"{StaticResource InvisibleThumbStyle}\"\n                                               />\n                                    </Grid>\n                                    <ContentPresenter Content=\"{TemplateBinding ContentControl.Content}\" ContentTemplate=\"{TemplateBinding ContentControl.ContentTemplate}\" ContentStringFormat=\"{TemplateBinding ContentControl.ContentStringFormat}\" HorizontalAlignment=\"{TemplateBinding Control.HorizontalContentAlignment}\" VerticalAlignment=\"{TemplateBinding Control.VerticalContentAlignment}\" SnapsToDevicePixels=\"{TemplateBinding UIElement.SnapsToDevicePixels}\"\n                                                      Margin=\"{TemplateBinding Control.Padding }\"/>\n                                </DockPanel>\n                            </Border>\n                        </Grid>\n                    </ControlTemplate>\n                </Setter.Value>\n            </Setter>\n        </Style.Setters>\n    </Style>\n\n    <Style TargetType=\"{x:Type local:HeaderedDragablzItem}\" x:Key=\"ToolDragablzItemStyle\">\n        <Style.Setters>\n            <Setter Property=\"BorderBrush\" Value=\"{StaticResource TabItem.Static.Border}\" />\n            <Setter Property=\"BorderThickness\" Value=\"4\" />\n            <Setter Property=\"Canvas.Left\" Value=\"{Binding X, RelativeSource={RelativeSource Self}}\" />\n            <Setter Property=\"Canvas.Top\" Value=\"{Binding Y, RelativeSource={RelativeSource Self}}\" />\n            <Setter Property=\"HorizontalContentAlignment\" Value=\"Stretch\" />\n            <Setter Property=\"VerticalContentAlignment\" Value=\"Stretch\" />\n            <Setter Property=\"Template\">\n                <Setter.Value>\n                    <ControlTemplate TargetType=\"{x:Type local:HeaderedDragablzItem}\">\n                        <Grid Margin=\"{TemplateBinding Margin}\">\n                            <Border Background=\"White\">\n                                <Border.Effect>\n                                    <DropShadowEffect BlurRadius=\"10\" ShadowDepth=\"5\" Direction=\"315\" Color=\"Black\" Opacity=\".5\" />\n                                </Border.Effect>\n                            </Border>\n                            <Border BorderThickness=\"{TemplateBinding Border.BorderThickness}\" Padding=\"{TemplateBinding Control.Padding}\" BorderBrush=\"{TemplateBinding Border.BorderBrush}\" Background=\"{TemplateBinding Panel.Background}\" SnapsToDevicePixels=\"True\">\n                                <DockPanel>\n                                    <Grid DockPanel.Dock=\"Top\" Background=\"{StaticResource TabItem.Static.Background}\">\n                                        <Thumb HorizontalAlignment=\"Stretch\" VerticalContentAlignment=\"Stretch\" x:Name=\"PART_Thumb\"\n                                               Style=\"{StaticResource InvisibleThumbStyle}\"\n                                               />\n                                        <DockPanel Margin=\"{TemplateBinding Control.Padding }\">\n                                            <Button DockPanel.Dock=\"Right\"\n                                                    Command=\"{x:Static dockablz:Layout.CloseFloatingItem}\"\n                                                    CommandParameter=\"{Binding RelativeSource={RelativeSource TemplatedParent}}\"\n                                                    Margin=\"1 0 0 0\"\n                                                    Style=\"{StaticResource HideDisabledButtonStyle}\"\n                                                    >\n                                                <themes:SystemCommandIcon Height=\"10\" Width=\"10\" SystemCommandType=\"CloseWindow\" />\n                                            </Button>\n                                            <Button DockPanel.Dock=\"Right\"\n                                                    Command=\"{x:Static dockablz:Layout.UnfloatItemCommand}\"\n                                                    CommandParameter=\"{Binding RelativeSource={RelativeSource TemplatedParent}}\"\n                                                    Margin=\"1 0 0 0\"\n                                                    Style=\"{StaticResource HideDisabledButtonStyle}\"\n                                                    >\n                                                <Path Width=\"12\" Height=\"12\" Stretch=\"UniformToFill\" Fill=\"#000000\" Data=\"M 19 19 H 5 V 5 h 7 V 3 H 5 C 3.89 3 3 3.9 3 5 v 14 c 0 1.1 0.89 2 2 2 h 14 c 1.1 0 2 -0.9 2 -2 v -7 h -2 v 7 z M 14 3 v 2 h 3.59 L 7.76 14.83 9.17 16.24 19 6.41 V 10 h 2 V 3 h -7 z\" />\n                                            </Button>\n                                            <Button DockPanel.Dock=\"Right\"\n                                                    Command=\"{x:Static dockablz:Layout.MaximiseFloatingItem}\"\n                                                    CommandParameter=\"{Binding RelativeSource={RelativeSource TemplatedParent}}\"\n                                                    Margin=\"1 0 0 0\"\n                                                    Style=\"{StaticResource HideDisabledButtonStyle}\"\n                                                    >\n                                                <themes:SystemCommandIcon Height=\"10\" Width=\"10\" SystemCommandType=\"MaximizeWindow\" />\n                                            </Button>\n                                            <Button DockPanel.Dock=\"Right\"\n                                                    Command=\"{x:Static dockablz:Layout.RestoreFloatingItem}\"\n                                                    CommandParameter=\"{Binding RelativeSource={RelativeSource TemplatedParent}}\"\n                                                    Margin=\"1 0 0 0\"\n                                                    Style=\"{StaticResource HideDisabledButtonStyle}\"\n                                                    >\n                                                <themes:SystemCommandIcon Height=\"10\" Width=\"10\" SystemCommandType=\"RestoreWindow\" />\n                                            </Button>\n                                            <ContentPresenter Content=\"{TemplateBinding HeaderContent}\"                                                               \n                                                              ContentTemplate=\"{TemplateBinding HeaderContentTemplate}\" \n                                                              ContentStringFormat=\"{TemplateBinding ContentControl.ContentStringFormat}\" HorizontalAlignment=\"{TemplateBinding Control.HorizontalContentAlignment}\" \n                                                              ContentTemplateSelector=\"{TemplateBinding HeaderContentTemplateSelector}\"                                                          \n                                                              SnapsToDevicePixels=\"{TemplateBinding UIElement.SnapsToDevicePixels}\"                                                              \n                                                              IsHitTestVisible=\"False\"\n                                                          />\n                                        </DockPanel>\n                                    </Grid>\n                                    <ContentPresenter Content=\"{TemplateBinding ContentControl.Content}\" ContentTemplate=\"{TemplateBinding ContentControl.ContentTemplate}\" ContentStringFormat=\"{TemplateBinding ContentControl.ContentStringFormat}\" HorizontalAlignment=\"{TemplateBinding Control.HorizontalContentAlignment}\" VerticalAlignment=\"{TemplateBinding Control.VerticalContentAlignment}\" SnapsToDevicePixels=\"{TemplateBinding UIElement.SnapsToDevicePixels}\"\n                                                      Margin=\"{TemplateBinding Control.Padding }\"                                                      \n                                                      />\n                                </DockPanel>\n                            </Border>\n                            <Thumb Style=\"{StaticResource InvisibleThumbStyle}\"\n                                   Width=\"{Binding RelativeSource={RelativeSource TemplatedParent}, Path=BorderThickness.Left}\"\n                                   IsEnabled=\"{Binding Path=(dockablz:Layout.FloatingItemState), RelativeSource={RelativeSource TemplatedParent}, Converter={StaticResource EqualityToBooleanConverter}, ConverterParameter={x:Static WindowState.Normal}}\"\n                                   local:DragablzItem.SizeGrip=\"Left\"\n                                   HorizontalAlignment=\"Left\"\n                                   VerticalAlignment=\"Stretch\"\n                                   Cursor=\"SizeWE\"\n                                   />\n                            <Thumb Style=\"{StaticResource InvisibleThumbStyle}\"\n                                   Height=\"{Binding RelativeSource={RelativeSource TemplatedParent}, Path=BorderThickness.Top}\"\n                                   IsEnabled=\"{Binding Path=(dockablz:Layout.FloatingItemState), RelativeSource={RelativeSource TemplatedParent}, Converter={StaticResource EqualityToBooleanConverter}, ConverterParameter={x:Static WindowState.Normal}}\"\n                                   local:DragablzItem.SizeGrip=\"Top\"\n                                   HorizontalAlignment=\"Stretch\"\n                                   VerticalAlignment=\"Top\"\n                                   Cursor=\"SizeNS\"\n                                   />\n                            <Thumb Style=\"{StaticResource InvisibleThumbStyle}\"\n                                   Width=\"{Binding RelativeSource={RelativeSource TemplatedParent}, Path=BorderThickness.Right}\"\n                                   IsEnabled=\"{Binding Path=(dockablz:Layout.FloatingItemState), RelativeSource={RelativeSource TemplatedParent}, Converter={StaticResource EqualityToBooleanConverter}, ConverterParameter={x:Static WindowState.Normal}}\"\n                                   local:DragablzItem.SizeGrip=\"Right\"\n                                   HorizontalAlignment=\"Right\"\n                                   VerticalAlignment=\"Stretch\"\n                                   Cursor=\"SizeWE\"\n                                   />\n                            <Thumb Style=\"{StaticResource InvisibleThumbStyle}\"\n                                   Height=\"{Binding RelativeSource={RelativeSource TemplatedParent}, Path=BorderThickness.Bottom}\"\n                                   IsEnabled=\"{Binding Path=(dockablz:Layout.FloatingItemState), RelativeSource={RelativeSource TemplatedParent}, Converter={StaticResource EqualityToBooleanConverter}, ConverterParameter={x:Static WindowState.Normal}}\"\n                                   local:DragablzItem.SizeGrip=\"Bottom\"\n                                   HorizontalAlignment=\"Stretch\"\n                                   VerticalAlignment=\"Bottom\"\n                                   Cursor=\"SizeNS\"\n                                   />\n                            <Thumb Style=\"{StaticResource InvisibleThumbStyle}\"\n                                   Width=\"{Binding RelativeSource={RelativeSource TemplatedParent}, Path=BorderThickness.Right}\"\n                                   Height=\"{Binding RelativeSource={RelativeSource TemplatedParent}, Path=BorderThickness.Bottom}\"\n                                   IsEnabled=\"{Binding Path=(dockablz:Layout.FloatingItemState), RelativeSource={RelativeSource TemplatedParent}, Converter={StaticResource EqualityToBooleanConverter}, ConverterParameter={x:Static WindowState.Normal}}\"\n                                   local:DragablzItem.SizeGrip=\"TopLeft\"\n                                   HorizontalAlignment=\"Left\"\n                                   VerticalAlignment=\"Top\"\n                                   Cursor=\"SizeNWSE\"\n                                   />\n                            <Thumb Style=\"{StaticResource InvisibleThumbStyle}\"\n                                   Width=\"{Binding RelativeSource={RelativeSource TemplatedParent}, Path=BorderThickness.Right}\"\n                                   Height=\"{Binding RelativeSource={RelativeSource TemplatedParent}, Path=BorderThickness.Bottom}\"\n                                   IsEnabled=\"{Binding Path=(dockablz:Layout.FloatingItemState), RelativeSource={RelativeSource TemplatedParent}, Converter={StaticResource EqualityToBooleanConverter}, ConverterParameter={x:Static WindowState.Normal}}\"\n                                   local:DragablzItem.SizeGrip=\"TopRight\"\n                                   HorizontalAlignment=\"Right\"\n                                   VerticalAlignment=\"Top\"\n                                   Cursor=\"SizeNESW\"\n                                   />\n                            <Thumb Style=\"{StaticResource InvisibleThumbStyle}\"\n                                   Width=\"{Binding RelativeSource={RelativeSource TemplatedParent}, Path=BorderThickness.Right}\"\n                                   Height=\"{Binding RelativeSource={RelativeSource TemplatedParent}, Path=BorderThickness.Bottom}\"\n                                   IsEnabled=\"{Binding Path=(dockablz:Layout.FloatingItemState), RelativeSource={RelativeSource TemplatedParent}, Converter={StaticResource EqualityToBooleanConverter}, ConverterParameter={x:Static WindowState.Normal}}\"\n                                   local:DragablzItem.SizeGrip=\"BottomRight\"\n                                   HorizontalAlignment=\"Right\"\n                                   VerticalAlignment=\"Bottom\"\n                                   Cursor=\"SizeNWSE\"\n                                   />\n                            <Thumb Style=\"{StaticResource InvisibleThumbStyle}\"\n                                   Width=\"{Binding RelativeSource={RelativeSource TemplatedParent}, Path=BorderThickness.Right}\"\n                                   Height=\"{Binding RelativeSource={RelativeSource TemplatedParent}, Path=BorderThickness.Bottom}\"\n                                   IsEnabled=\"{Binding Path=(dockablz:Layout.FloatingItemState), RelativeSource={RelativeSource TemplatedParent}, Converter={StaticResource EqualityToBooleanConverter}, ConverterParameter={x:Static WindowState.Normal}}\"\n                                   local:DragablzItem.SizeGrip=\"BottomLeft\"                                   \n                                   HorizontalAlignment=\"Left\"\n                                   VerticalAlignment=\"Bottom\"\n                                   Cursor=\"SizeNESW\"\n                                   />\n                        </Grid>\n                    </ControlTemplate>\n                </Setter.Value>\n            </Setter>\n        </Style.Setters>\n        <Style.Triggers>\n            <Trigger Property=\"dockablz:Layout.FloatingItemState\" Value=\"Maximized\">\n                <Setter Property=\"BorderThickness\" Value=\"1\" />\n                <Setter Property=\"Canvas.Left\" Value=\"0\" />\n                <Setter Property=\"Canvas.Top\" Value=\"0\" />\n                <Setter Property=\"Width\" Value=\"{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type dockablz:Layout}}, Path=ActualWidth}\" />\n                <Setter Property=\"Height\" Value=\"{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type dockablz:Layout}}, Path=ActualHeight}\" />\n            </Trigger>\n        </Style.Triggers>\n    </Style>\n\n    <Style TargetType=\"{x:Type local:DragablzItem}\" x:Key=\"SizableFromBottomRightDragablzItemStyle\">\n        <Style.Setters>\n            <Setter Property=\"BorderBrush\" Value=\"{StaticResource TabItem.Static.Border}\" />\n            <Setter Property=\"BorderThickness\" Value=\"4\" />\n            <Setter Property=\"Canvas.Left\" Value=\"{Binding X, RelativeSource={RelativeSource Self}}\" />\n            <Setter Property=\"Canvas.Top\" Value=\"{Binding Y, RelativeSource={RelativeSource Self}}\" />\n            <Setter Property=\"Template\">\n                <Setter.Value>\n                    <ControlTemplate TargetType=\"{x:Type local:DragablzItem}\">\n                        <Grid Margin=\"{TemplateBinding Margin}\">\n                            <Border BorderThickness=\"{TemplateBinding Border.BorderThickness}\" Padding=\"{TemplateBinding Control.Padding}\" BorderBrush=\"{TemplateBinding Border.BorderBrush}\" Background=\"{TemplateBinding Panel.Background}\" SnapsToDevicePixels=\"True\">\n                                <ContentPresenter Content=\"{TemplateBinding ContentControl.Content}\" ContentTemplate=\"{TemplateBinding ContentControl.ContentTemplate}\" ContentStringFormat=\"{TemplateBinding ContentControl.ContentStringFormat}\" HorizontalAlignment=\"{TemplateBinding Control.HorizontalContentAlignment}\" VerticalAlignment=\"{TemplateBinding Control.VerticalContentAlignment}\" SnapsToDevicePixels=\"{TemplateBinding UIElement.SnapsToDevicePixels}\"\n                                                  Margin=\"{TemplateBinding Control.Padding }\"/>\n                            </Border>\n                            <Thumb Style=\"{StaticResource InvisibleThumbStyle}\"\n                                   Width=\"{Binding RelativeSource={RelativeSource TemplatedParent}, Path=BorderThickness.Right}\"\n                                   Height=\"{Binding RelativeSource={RelativeSource TemplatedParent}, Path=BorderThickness.Bottom}\"\n                                   local:DragablzItem.SizeGrip=\"BottomRight\"\n                                   HorizontalAlignment=\"Right\"\n                                   VerticalAlignment=\"Bottom\"\n                                   Cursor=\"SizeNWSE\"\n                                   />\n                        </Grid>\n                    </ControlTemplate>\n                </Setter.Value>\n            </Setter>\n        </Style.Setters>\n    </Style>\n\n    <Style TargetType=\"{x:Type local:DragablzItem}\" x:Key=\"FloatingDragablzItemStyle\">\n        <Style.Setters>\n            <Setter Property=\"BorderBrush\" Value=\"{StaticResource TabItem.Static.Border}\" />\n            <Setter Property=\"BorderThickness\" Value=\"4\" />\n            <Setter Property=\"Canvas.Left\" Value=\"{Binding X, RelativeSource={RelativeSource Self}}\" />\n            <Setter Property=\"Canvas.Top\" Value=\"{Binding Y, RelativeSource={RelativeSource Self}}\" />\n            <Setter Property=\"Template\">\n                <Setter.Value>\n                    <ControlTemplate TargetType=\"{x:Type local:DragablzItem}\">\n                        <Grid Margin=\"{TemplateBinding Margin}\">\n                            <Border Background=\"White\">\n                                <Border.Effect>\n                                    <DropShadowEffect BlurRadius=\"10\" ShadowDepth=\"5\" Direction=\"315\" Color=\"Black\" Opacity=\".5\" />\n                                </Border.Effect>\n                            </Border>\n                            <Border BorderThickness=\"{TemplateBinding Border.BorderThickness}\" Padding=\"{TemplateBinding Control.Padding}\" BorderBrush=\"{TemplateBinding Border.BorderBrush}\" Background=\"{TemplateBinding Panel.Background}\" SnapsToDevicePixels=\"True\">\n                                <Grid Cursor=\"ScrollAll\">\n                                    <ContentPresenter Content=\"{TemplateBinding ContentControl.Content}\" ContentTemplate=\"{TemplateBinding ContentControl.ContentTemplate}\" ContentStringFormat=\"{TemplateBinding ContentControl.ContentStringFormat}\" HorizontalAlignment=\"{TemplateBinding Control.HorizontalContentAlignment}\" VerticalAlignment=\"{TemplateBinding Control.VerticalContentAlignment}\" SnapsToDevicePixels=\"{TemplateBinding UIElement.SnapsToDevicePixels}\"\n                                                      Margin=\"{TemplateBinding Control.Padding }\"/>\n                                    <Thumb HorizontalAlignment=\"Stretch\" VerticalContentAlignment=\"Stretch\" x:Name=\"PART_Thumb\"\n                                           Style=\"{StaticResource InvisibleThumbStyle}\"\n                                           />\n                                </Grid>\n                            </Border>\n                            <Thumb Style=\"{StaticResource InvisibleThumbStyle}\"\n                                   Width=\"{Binding RelativeSource={RelativeSource TemplatedParent}, Path=BorderThickness.Left}\"\n                                   local:DragablzItem.SizeGrip=\"Left\"\n                                   HorizontalAlignment=\"Left\"\n                                   VerticalAlignment=\"Stretch\"\n                                   Cursor=\"SizeWE\"\n                                   />\n                            <Thumb Style=\"{StaticResource InvisibleThumbStyle}\"\n                                   Height=\"{Binding RelativeSource={RelativeSource TemplatedParent}, Path=BorderThickness.Top}\"\n                                   local:DragablzItem.SizeGrip=\"Top\"\n                                   HorizontalAlignment=\"Stretch\"\n                                   VerticalAlignment=\"Top\"\n                                   Cursor=\"SizeNS\"\n                                   />\n                            <Thumb Style=\"{StaticResource InvisibleThumbStyle}\"\n                                   Width=\"{Binding RelativeSource={RelativeSource TemplatedParent}, Path=BorderThickness.Right}\"\n                                   local:DragablzItem.SizeGrip=\"Right\"\n                                   HorizontalAlignment=\"Right\"\n                                   VerticalAlignment=\"Stretch\"\n                                   Cursor=\"SizeWE\"\n                                   />\n                            <Thumb Style=\"{StaticResource InvisibleThumbStyle}\"\n                                   Height=\"{Binding RelativeSource={RelativeSource TemplatedParent}, Path=BorderThickness.Bottom}\"\n                                   local:DragablzItem.SizeGrip=\"Bottom\"\n                                   HorizontalAlignment=\"Stretch\"\n                                   VerticalAlignment=\"Bottom\"\n                                   Cursor=\"SizeNS\"\n                                   />\n                            <Thumb Style=\"{StaticResource InvisibleThumbStyle}\"\n                                   Width=\"{Binding RelativeSource={RelativeSource TemplatedParent}, Path=BorderThickness.Right}\"\n                                   Height=\"{Binding RelativeSource={RelativeSource TemplatedParent}, Path=BorderThickness.Bottom}\"\n                                   local:DragablzItem.SizeGrip=\"TopLeft\"\n                                   HorizontalAlignment=\"Left\"\n                                   VerticalAlignment=\"Top\"\n                                   Cursor=\"SizeNWSE\"\n                                   />\n                            <Thumb Style=\"{StaticResource InvisibleThumbStyle}\"\n                                   Width=\"{Binding RelativeSource={RelativeSource TemplatedParent}, Path=BorderThickness.Right}\"\n                                   Height=\"{Binding RelativeSource={RelativeSource TemplatedParent}, Path=BorderThickness.Bottom}\"\n                                   local:DragablzItem.SizeGrip=\"TopRight\"\n                                   HorizontalAlignment=\"Right\"\n                                   VerticalAlignment=\"Top\"\n                                   Cursor=\"SizeNESW\"\n                                   />\n                            <Thumb Style=\"{StaticResource InvisibleThumbStyle}\"\n                                   Width=\"{Binding RelativeSource={RelativeSource TemplatedParent}, Path=BorderThickness.Right}\"\n                                   Height=\"{Binding RelativeSource={RelativeSource TemplatedParent}, Path=BorderThickness.Bottom}\"\n                                   local:DragablzItem.SizeGrip=\"BottomRight\"\n                                   HorizontalAlignment=\"Right\"\n                                   VerticalAlignment=\"Bottom\"\n                                   Cursor=\"SizeNWSE\"\n                                   />\n                            <Thumb Style=\"{StaticResource InvisibleThumbStyle}\"\n                                   Width=\"{Binding RelativeSource={RelativeSource TemplatedParent}, Path=BorderThickness.Right}\"\n                                   Height=\"{Binding RelativeSource={RelativeSource TemplatedParent}, Path=BorderThickness.Bottom}\"\n                                   local:DragablzItem.SizeGrip=\"BottomLeft\"\n                                   HorizontalAlignment=\"Left\"\n                                   VerticalAlignment=\"Bottom\"\n                                   Cursor=\"SizeNESW\"\n                                   />\n                        </Grid>\n                    </ControlTemplate>\n                </Setter.Value>\n            </Setter>\n        </Style.Setters>\n    </Style>\n\n    <Style x:Key=\"StandardEmbeddedButtonStyle\" TargetType=\"{x:Type Button}\">\n        <Setter Property=\"FocusVisualStyle\" Value=\"{StaticResource FocusVisual}\"/>\n        <Setter Property=\"Background\" Value=\"{StaticResource Button.Static.Background}\"/>\n        <Setter Property=\"BorderBrush\" Value=\"{StaticResource Button.Static.Border}\"/>\n        <Setter Property=\"Foreground\" Value=\"{DynamicResource {x:Static SystemColors.ControlTextBrushKey}}\"/>\n        <Setter Property=\"BorderThickness\" Value=\"1\"/>\n        <Setter Property=\"HorizontalContentAlignment\" Value=\"Center\"/>\n        <Setter Property=\"VerticalContentAlignment\" Value=\"Center\"/>\n        <Setter Property=\"Padding\" Value=\"1 -2 1 -2\"/>\n        <Setter Property=\"Template\">\n            <Setter.Value>\n                <ControlTemplate TargetType=\"{x:Type Button}\">\n                    <Border x:Name=\"border\" BorderBrush=\"{TemplateBinding BorderBrush}\" BorderThickness=\"{TemplateBinding BorderThickness}\" Background=\"{TemplateBinding Background}\" SnapsToDevicePixels=\"true\">\n                        <ContentPresenter x:Name=\"contentPresenter\" Focusable=\"False\" HorizontalAlignment=\"{TemplateBinding HorizontalContentAlignment}\" Margin=\"{TemplateBinding Padding}\" RecognizesAccessKey=\"True\" SnapsToDevicePixels=\"{TemplateBinding SnapsToDevicePixels}\" VerticalAlignment=\"{TemplateBinding VerticalContentAlignment}\"/>\n                    </Border>\n                    <ControlTemplate.Triggers>\n                        <Trigger Property=\"IsDefaulted\" Value=\"true\">\n                            <Setter Property=\"BorderBrush\" TargetName=\"border\" Value=\"{DynamicResource {x:Static SystemColors.HighlightBrushKey}}\"/>\n                        </Trigger>\n                        <Trigger Property=\"IsMouseOver\" Value=\"true\">\n                            <Setter Property=\"Background\" TargetName=\"border\" Value=\"{StaticResource Button.MouseOver.Background}\"/>\n                            <Setter Property=\"BorderBrush\" TargetName=\"border\" Value=\"{StaticResource Button.MouseOver.Border}\"/>\n                        </Trigger>\n                        <Trigger Property=\"IsPressed\" Value=\"true\">\n                            <Setter Property=\"Background\" TargetName=\"border\" Value=\"{StaticResource Button.Pressed.Background}\"/>\n                            <Setter Property=\"BorderBrush\" TargetName=\"border\" Value=\"{StaticResource Button.Pressed.Border}\"/>\n                        </Trigger>\n                        <Trigger Property=\"IsEnabled\" Value=\"false\">\n                            <Setter Property=\"Background\" TargetName=\"border\" Value=\"{StaticResource Button.Disabled.Background}\"/>\n                            <Setter Property=\"BorderBrush\" TargetName=\"border\" Value=\"{StaticResource Button.Disabled.Border}\"/>\n                            <Setter Property=\"TextElement.Foreground\" TargetName=\"contentPresenter\" Value=\"{StaticResource Button.Disabled.Foreground}\"/>\n                        </Trigger>\n                    </ControlTemplate.Triggers>\n                </ControlTemplate>\n            </Setter.Value>\n        </Setter>\n    </Style>\n\n    <Style x:Key=\"TrapezoidDragableTabItemStyle\"  TargetType=\"{x:Type local:DragablzItem}\">\n        <Setter Property=\"FocusVisualStyle\" Value=\"{StaticResource FocusVisual}\"/>\n        <Setter Property=\"Foreground\" Value=\"Black\"/>\n        <Setter Property=\"Background\" Value=\"{StaticResource TabItem.Static.Background}\"/>\n        <Setter Property=\"BorderBrush\" Value=\"{StaticResource TabItem.Static.Border}\"/>\n        <Setter Property=\"Margin\" Value=\"0 0 0 0\"/>\n        <Setter Property=\"HorizontalContentAlignment\" Value=\"Stretch\"/>\n        <Setter Property=\"VerticalContentAlignment\" Value=\"Stretch\"/>\n        <Setter Property=\"Template\">\n            <Setter.Value>\n                <ControlTemplate TargetType=\"{x:Type local:DragablzItem}\">\n                    <Grid x:Name=\"templateRoot\" SnapsToDevicePixels=\"true\" Margin=\"0 1 0 -1\">\n                        <local:Trapezoid x:Name=\"Trapezoid\" \n                                         BorderBrush=\"{TemplateBinding BorderBrush}\" \n                                         Background=\"{TemplateBinding Background}\"                                          \n                                         PenThickness=\"2\"\n                                         Margin=\"0 0 0 0\">\n                            <Grid>\n                                <Grid.ColumnDefinitions>\n                                    <ColumnDefinition Width=\"*\" />\n                                    <ColumnDefinition Width=\"Auto\" />\n                                </Grid.ColumnDefinitions>\n                                <ContentPresenter Content=\"{TemplateBinding ContentControl.Content}\" ContentTemplate=\"{TemplateBinding ContentControl.ContentTemplate}\" ContentStringFormat=\"{TemplateBinding ContentControl.ContentStringFormat}\" HorizontalAlignment=\"{TemplateBinding Control.HorizontalContentAlignment}\" VerticalAlignment=\"{TemplateBinding Control.VerticalContentAlignment}\" SnapsToDevicePixels=\"{TemplateBinding UIElement.SnapsToDevicePixels}\"\n                                                  Margin=\"{TemplateBinding Control.Padding}\"\n                                                  x:Name=\"contentPresenter\" />\n                                <Thumb Grid.Column=\"0\" HorizontalAlignment=\"Stretch\" VerticalContentAlignment=\"Stretch\" \n                                       x:Name=\"PART_Thumb\"\n                                       Style=\"{StaticResource InvisibleThumbStyle}\" />\n                                <Button Grid.Column=\"1\"\n                                        Style=\"{StaticResource CloseItemCommandButtonStyle}\"                                        \n                                        Command=\"{x:Static local:TabablzControl.CloseItemCommand}\"\n                                        CommandParameter=\"{Binding RelativeSource={RelativeSource TemplatedParent}}\">\n                                    <Button.Visibility>\n                                        <MultiBinding Converter=\"{StaticResource ShowDefaultCloseButtonConverter}\">\n                                            <Binding RelativeSource=\"{RelativeSource FindAncestor, AncestorType={x:Type local:TabablzControl}}\" Path=\"ShowDefaultCloseButton\" />\n                                            <Binding RelativeSource=\"{RelativeSource FindAncestor, AncestorType={x:Type local:TabablzControl}}\" Path=\"FixedHeaderCount\" />\n                                            <Binding RelativeSource=\"{RelativeSource TemplatedParent}\" Path=\"LogicalIndex\" />\n                                        </MultiBinding>\n                                    </Button.Visibility>\n                                </Button>\n                            </Grid>\n                        </local:Trapezoid>\n                    </Grid>\n                    <ControlTemplate.Triggers>\n                        <Trigger Property=\"local:TabablzControl.IsWrappingTabItem\" Value=\"True\">\n                            <Setter TargetName=\"contentPresenter\" Property=\"Content\" Value=\"{Binding RelativeSource={RelativeSource TemplatedParent}, Path=DataContext.Header}\" />\n                        </Trigger>\n                        <Trigger Property=\"IsSelected\" Value=\"True\">\n                            <Setter Property=\"Background\" Value=\"{StaticResource TabItem.Selected.Background}\" TargetName=\"Trapezoid\"/>\n                            <Setter Property=\"LongBasePenBrush\" Value=\"{StaticResource TabItem.Selected.Background}\" TargetName=\"Trapezoid\"/>\n                        </Trigger>\n                    </ControlTemplate.Triggers>\n                </ControlTemplate>\n            </Setter.Value>\n        </Setter>\n    </Style>\n\n    <!-- this style is effectively a duplicate of CoreTabItemStyle, allowing users to bind tabs in and immedietly get a standard tab look -->\n    <Style x:Key=\"StandardDragablzTabItemStyle\" TargetType=\"{x:Type local:DragablzItem}\">\n        <Setter Property=\"FocusVisualStyle\" Value=\"{StaticResource FocusVisual}\"/>\n        <Setter Property=\"Foreground\" Value=\"Black\"/>\n        <Setter Property=\"Background\" Value=\"{StaticResource TabItem.Static.Background}\"/>\n        <Setter Property=\"BorderBrush\" Value=\"{StaticResource TabItem.Static.Border}\"/>\n        <Setter Property=\"Margin\" Value=\"0\"/>\n        <Setter Property=\"Padding\" Value=\"6,2,6,2\"/>\n        <Setter Property=\"HorizontalContentAlignment\" Value=\"Stretch\"/>\n        <Setter Property=\"VerticalContentAlignment\" Value=\"Stretch\"/>\n        <Setter Property=\"Template\">\n            <Setter.Value>\n                <ControlTemplate TargetType=\"{x:Type local:DragablzItem}\">\n                    <Grid x:Name=\"templateRoot\" SnapsToDevicePixels=\"true\">\n                        <Border x:Name=\"mainBorder\" BorderBrush=\"{TemplateBinding BorderBrush}\" BorderThickness=\"1,1,1,0\" Background=\"{TemplateBinding Background}\" Margin=\"0 0 0 1\">\n                            <Border x:Name=\"innerBorder\" BorderBrush=\"{StaticResource TabItem.Selected.Border}\" BorderThickness=\"1,1,1,0\" Background=\"{StaticResource TabItem.Selected.Background}\" Margin=\"-1\" Opacity=\"0\"/>\n                        </Border>\n                        <ContentPresenter Content=\"{TemplateBinding ContentControl.Content}\" ContentTemplate=\"{TemplateBinding ContentControl.ContentTemplate}\" ContentStringFormat=\"{TemplateBinding ContentControl.ContentStringFormat}\" HorizontalAlignment=\"{TemplateBinding Control.HorizontalContentAlignment}\" VerticalAlignment=\"{TemplateBinding Control.VerticalContentAlignment}\" SnapsToDevicePixels=\"{TemplateBinding UIElement.SnapsToDevicePixels}\"\n                                          x:Name=\"contentPresenter\"\n                                          Margin=\"{TemplateBinding Control.Padding}\" />\n                        <Thumb HorizontalAlignment=\"Stretch\" VerticalContentAlignment=\"Stretch\" x:Name=\"PART_Thumb\"\n                               Style=\"{StaticResource InvisibleThumbStyle}\"/>\n                    </Grid>\n                    <ControlTemplate.Triggers>\n                        <Trigger Property=\"local:TabablzControl.IsWrappingTabItem\" Value=\"True\">\n                            <Setter TargetName=\"contentPresenter\" Property=\"Content\" Value=\"{Binding RelativeSource={RelativeSource TemplatedParent}, Path=DataContext.Header}\" />\n                        </Trigger>\n                        <MultiDataTrigger>\n                            <MultiDataTrigger.Conditions>\n                                <Condition Binding=\"{Binding IsMouseOver, RelativeSource={RelativeSource Self}}\" Value=\"true\"/>\n                                <Condition Binding=\"{Binding TabStripPlacement, RelativeSource={RelativeSource AncestorType={x:Type TabControl}}}\" Value=\"Left\"/>\n                            </MultiDataTrigger.Conditions>\n                            <Setter Property=\"Background\" TargetName=\"mainBorder\" Value=\"{StaticResource TabItem.MouseOver.Background}\"/>\n                            <Setter Property=\"BorderBrush\" TargetName=\"mainBorder\" Value=\"{StaticResource TabItem.MouseOver.Border}\"/>\n                            <Setter Property=\"BorderThickness\" TargetName=\"innerBorder\" Value=\"1,1,0,1\"/>\n                            <Setter Property=\"BorderThickness\" TargetName=\"mainBorder\" Value=\"1,1,0,1\"/>\n                        </MultiDataTrigger>\n                        <MultiDataTrigger>\n                            <MultiDataTrigger.Conditions>\n                                <Condition Binding=\"{Binding IsMouseOver, RelativeSource={RelativeSource Self}}\" Value=\"true\"/>\n                                <Condition Binding=\"{Binding TabStripPlacement, RelativeSource={RelativeSource AncestorType={x:Type TabControl}}}\" Value=\"Bottom\"/>\n                            </MultiDataTrigger.Conditions>\n                            <Setter Property=\"Background\" TargetName=\"mainBorder\" Value=\"{StaticResource TabItem.MouseOver.Background}\"/>\n                            <Setter Property=\"BorderBrush\" TargetName=\"mainBorder\" Value=\"{StaticResource TabItem.MouseOver.Border}\"/>\n                            <Setter Property=\"BorderThickness\" TargetName=\"innerBorder\" Value=\"1,0,1,1\"/>\n                            <Setter Property=\"BorderThickness\" TargetName=\"mainBorder\" Value=\"1,0,1,1\"/>\n                        </MultiDataTrigger>\n                        <MultiDataTrigger>\n                            <MultiDataTrigger.Conditions>\n                                <Condition Binding=\"{Binding IsMouseOver, RelativeSource={RelativeSource Self}}\" Value=\"true\"/>\n                                <Condition Binding=\"{Binding TabStripPlacement, RelativeSource={RelativeSource AncestorType={x:Type TabControl}}}\" Value=\"Right\"/>\n                            </MultiDataTrigger.Conditions>\n                            <Setter Property=\"Background\" TargetName=\"mainBorder\" Value=\"{StaticResource TabItem.MouseOver.Background}\"/>\n                            <Setter Property=\"BorderBrush\" TargetName=\"mainBorder\" Value=\"{StaticResource TabItem.MouseOver.Border}\"/>\n                            <Setter Property=\"BorderThickness\" TargetName=\"innerBorder\" Value=\"0,1,1,1\"/>\n                            <Setter Property=\"BorderThickness\" TargetName=\"mainBorder\" Value=\"0,1,1,1\"/>\n                        </MultiDataTrigger>\n                        <MultiDataTrigger>\n                            <MultiDataTrigger.Conditions>\n                                <Condition Binding=\"{Binding IsMouseOver, RelativeSource={RelativeSource Self}}\" Value=\"true\"/>\n                                <Condition Binding=\"{Binding TabStripPlacement, RelativeSource={RelativeSource AncestorType={x:Type TabControl}}}\" Value=\"Top\"/>\n                            </MultiDataTrigger.Conditions>\n                            <Setter Property=\"Background\" TargetName=\"mainBorder\" Value=\"{StaticResource TabItem.MouseOver.Background}\"/>\n                            <Setter Property=\"BorderBrush\" TargetName=\"mainBorder\" Value=\"{StaticResource TabItem.MouseOver.Border}\"/>\n                            <Setter Property=\"BorderThickness\" TargetName=\"innerBorder\" Value=\"1,1,1,0\"/>\n                            <Setter Property=\"BorderThickness\" TargetName=\"mainBorder\" Value=\"1,1,1,0\"/>\n                        </MultiDataTrigger>\n                        <MultiDataTrigger>\n                            <MultiDataTrigger.Conditions>\n                                <Condition Binding=\"{Binding IsEnabled, RelativeSource={RelativeSource Self}}\" Value=\"false\"/>\n                                <Condition Binding=\"{Binding TabStripPlacement, RelativeSource={RelativeSource AncestorType={x:Type TabControl}}}\" Value=\"Left\"/>\n                            </MultiDataTrigger.Conditions>\n                            <Setter Property=\"Opacity\" TargetName=\"contentPresenter\" Value=\"0.56\"/>\n                            <Setter Property=\"Background\" TargetName=\"mainBorder\" Value=\"{StaticResource TabItem.Disabled.Background}\"/>\n                            <Setter Property=\"BorderBrush\" TargetName=\"mainBorder\" Value=\"{StaticResource TabItem.Disabled.Border}\"/>\n                            <Setter Property=\"BorderThickness\" TargetName=\"innerBorder\" Value=\"1,1,0,1\"/>\n                            <Setter Property=\"BorderThickness\" TargetName=\"mainBorder\" Value=\"1,1,0,1\"/>\n                        </MultiDataTrigger>\n                        <MultiDataTrigger>\n                            <MultiDataTrigger.Conditions>\n                                <Condition Binding=\"{Binding IsEnabled, RelativeSource={RelativeSource Self}}\" Value=\"false\"/>\n                                <Condition Binding=\"{Binding TabStripPlacement, RelativeSource={RelativeSource AncestorType={x:Type TabControl}}}\" Value=\"Bottom\"/>\n                            </MultiDataTrigger.Conditions>\n                            <Setter Property=\"Opacity\" TargetName=\"contentPresenter\" Value=\"0.56\"/>\n                            <Setter Property=\"Background\" TargetName=\"mainBorder\" Value=\"{StaticResource TabItem.Disabled.Background}\"/>\n                            <Setter Property=\"BorderBrush\" TargetName=\"mainBorder\" Value=\"{StaticResource TabItem.Disabled.Border}\"/>\n                            <Setter Property=\"BorderThickness\" TargetName=\"innerBorder\" Value=\"1,0,1,1\"/>\n                            <Setter Property=\"BorderThickness\" TargetName=\"mainBorder\" Value=\"1,0,1,1\"/>\n                        </MultiDataTrigger>\n                        <MultiDataTrigger>\n                            <MultiDataTrigger.Conditions>\n                                <Condition Binding=\"{Binding IsEnabled, RelativeSource={RelativeSource Self}}\" Value=\"false\"/>\n                                <Condition Binding=\"{Binding TabStripPlacement, RelativeSource={RelativeSource AncestorType={x:Type TabControl}}}\" Value=\"Right\"/>\n                            </MultiDataTrigger.Conditions>\n                            <Setter Property=\"Opacity\" TargetName=\"contentPresenter\" Value=\"0.56\"/>\n                            <Setter Property=\"Background\" TargetName=\"mainBorder\" Value=\"{StaticResource TabItem.Disabled.Background}\"/>\n                            <Setter Property=\"BorderBrush\" TargetName=\"mainBorder\" Value=\"{StaticResource TabItem.Disabled.Border}\"/>\n                            <Setter Property=\"BorderThickness\" TargetName=\"innerBorder\" Value=\"0,1,1,1\"/>\n                            <Setter Property=\"BorderThickness\" TargetName=\"mainBorder\" Value=\"0,1,1,1\"/>\n                        </MultiDataTrigger>\n                        <MultiDataTrigger>\n                            <MultiDataTrigger.Conditions>\n                                <Condition Binding=\"{Binding IsEnabled, RelativeSource={RelativeSource Self}}\" Value=\"false\"/>\n                                <Condition Binding=\"{Binding TabStripPlacement, RelativeSource={RelativeSource AncestorType={x:Type TabControl}}}\" Value=\"Top\"/>\n                            </MultiDataTrigger.Conditions>\n                            <Setter Property=\"Opacity\" TargetName=\"contentPresenter\" Value=\"0.56\"/>\n                            <Setter Property=\"Background\" TargetName=\"mainBorder\" Value=\"{StaticResource TabItem.Disabled.Background}\"/>\n                            <Setter Property=\"BorderBrush\" TargetName=\"mainBorder\" Value=\"{StaticResource TabItem.Disabled.Border}\"/>\n                            <Setter Property=\"BorderThickness\" TargetName=\"innerBorder\" Value=\"1,1,1,0\"/>\n                            <Setter Property=\"BorderThickness\" TargetName=\"mainBorder\" Value=\"1,1,1,0\"/>\n                        </MultiDataTrigger>\n                        <MultiDataTrigger>\n                            <MultiDataTrigger.Conditions>\n                                <Condition Binding=\"{Binding IsSelected, RelativeSource={RelativeSource Self}}\" Value=\"false\"/>\n                                <Condition Binding=\"{Binding TabStripPlacement, RelativeSource={RelativeSource AncestorType={x:Type TabControl}}}\" Value=\"Left\"/>\n                            </MultiDataTrigger.Conditions>\n                            <Setter Property=\"BorderThickness\" TargetName=\"innerBorder\" Value=\"1,1,0,1\"/>\n                            <Setter Property=\"BorderThickness\" TargetName=\"mainBorder\" Value=\"1,1,0,1\"/>\n                        </MultiDataTrigger>\n                        <MultiDataTrigger>\n                            <MultiDataTrigger.Conditions>\n                                <Condition Binding=\"{Binding IsSelected, RelativeSource={RelativeSource Self}}\" Value=\"true\"/>\n                                <Condition Binding=\"{Binding TabStripPlacement, RelativeSource={RelativeSource AncestorType={x:Type TabControl}}}\" Value=\"Left\"/>\n                            </MultiDataTrigger.Conditions>\n                            <Setter Property=\"Panel.ZIndex\" Value=\"1\"/>\n                            <Setter Property=\"Margin\" Value=\"-2,-2,0,-2\"/>\n                            <Setter Property=\"Opacity\" TargetName=\"innerBorder\" Value=\"1\"/>\n                            <Setter Property=\"BorderThickness\" TargetName=\"innerBorder\" Value=\"1,1,0,1\"/>\n                            <Setter Property=\"BorderThickness\" TargetName=\"mainBorder\" Value=\"1,1,0,1\"/>\n                        </MultiDataTrigger>\n                        <MultiDataTrigger>\n                            <MultiDataTrigger.Conditions>\n                                <Condition Binding=\"{Binding IsSelected, RelativeSource={RelativeSource Self}}\" Value=\"false\"/>\n                                <Condition Binding=\"{Binding TabStripPlacement, RelativeSource={RelativeSource AncestorType={x:Type TabControl}}}\" Value=\"Bottom\"/>\n                            </MultiDataTrigger.Conditions>\n                            <Setter Property=\"BorderThickness\" TargetName=\"innerBorder\" Value=\"1,0,1,1\"/>\n                            <Setter Property=\"BorderThickness\" TargetName=\"mainBorder\" Value=\"1,0,1,1\"/>\n                        </MultiDataTrigger>\n                        <MultiDataTrigger>\n                            <MultiDataTrigger.Conditions>\n                                <Condition Binding=\"{Binding IsSelected, RelativeSource={RelativeSource Self}}\" Value=\"true\"/>\n                                <Condition Binding=\"{Binding TabStripPlacement, RelativeSource={RelativeSource AncestorType={x:Type TabControl}}}\" Value=\"Bottom\"/>\n                            </MultiDataTrigger.Conditions>\n                            <Setter Property=\"Panel.ZIndex\" Value=\"1\"/>\n                            <Setter Property=\"Margin\" Value=\"-2,0,-2,-2\"/>\n                            <Setter Property=\"Opacity\" TargetName=\"innerBorder\" Value=\"1\"/>\n                            <Setter Property=\"BorderThickness\" TargetName=\"innerBorder\" Value=\"1,0,1,1\"/>\n                            <Setter Property=\"BorderThickness\" TargetName=\"mainBorder\" Value=\"1,0,1,1\"/>\n                        </MultiDataTrigger>\n                        <MultiDataTrigger>\n                            <MultiDataTrigger.Conditions>\n                                <Condition Binding=\"{Binding IsSelected, RelativeSource={RelativeSource Self}}\" Value=\"false\"/>\n                                <Condition Binding=\"{Binding TabStripPlacement, RelativeSource={RelativeSource AncestorType={x:Type TabControl}}}\" Value=\"Right\"/>\n                            </MultiDataTrigger.Conditions>\n                            <Setter Property=\"BorderThickness\" TargetName=\"innerBorder\" Value=\"0,1,1,1\"/>\n                            <Setter Property=\"BorderThickness\" TargetName=\"mainBorder\" Value=\"0,1,1,1\"/>\n                        </MultiDataTrigger>\n                        <MultiDataTrigger>\n                            <MultiDataTrigger.Conditions>\n                                <Condition Binding=\"{Binding IsSelected, RelativeSource={RelativeSource Self}}\" Value=\"true\"/>\n                                <Condition Binding=\"{Binding TabStripPlacement, RelativeSource={RelativeSource AncestorType={x:Type TabControl}}}\" Value=\"Right\"/>\n                            </MultiDataTrigger.Conditions>\n                            <Setter Property=\"Panel.ZIndex\" Value=\"1\"/>\n                            <Setter Property=\"Margin\" Value=\"0,-2,-2,-2\"/>\n                            <Setter Property=\"Opacity\" TargetName=\"innerBorder\" Value=\"1\"/>\n                            <Setter Property=\"BorderThickness\" TargetName=\"innerBorder\" Value=\"0,1,1,1\"/>\n                            <Setter Property=\"BorderThickness\" TargetName=\"mainBorder\" Value=\"0,1,1,1\"/>\n                        </MultiDataTrigger>\n                        <MultiDataTrigger>\n                            <MultiDataTrigger.Conditions>\n                                <Condition Binding=\"{Binding IsSelected, RelativeSource={RelativeSource Self}}\" Value=\"false\"/>\n                                <Condition Binding=\"{Binding TabStripPlacement, RelativeSource={RelativeSource AncestorType={x:Type TabControl}}}\" Value=\"Top\"/>\n                            </MultiDataTrigger.Conditions>\n                            <Setter Property=\"BorderThickness\" TargetName=\"innerBorder\" Value=\"1,1,1,0\"/>\n                            <Setter Property=\"BorderThickness\" TargetName=\"mainBorder\" Value=\"1,1,1,0\"/>\n                        </MultiDataTrigger>\n                        <MultiDataTrigger>\n                            <MultiDataTrigger.Conditions>\n                                <Condition Binding=\"{Binding IsSelected, RelativeSource={RelativeSource Self}}\"                                            \n                                           Value=\"True\"/>\n                                <Condition Binding=\"{Binding TabStripPlacement, RelativeSource={RelativeSource AncestorType={x:Type TabControl}}}\" Value=\"Top\"/>\n                            </MultiDataTrigger.Conditions>\n                            <Setter Property=\"Panel.ZIndex\" Value=\"1\"/>\n                            <Setter Property=\"Margin\" Value=\"0,0,0,-2\"/>\n                            <Setter Property=\"Opacity\" TargetName=\"innerBorder\" Value=\"1\"/>\n                            <Setter Property=\"BorderThickness\" TargetName=\"innerBorder\" Value=\"1,1,1,0\"/>\n                            <Setter Property=\"BorderThickness\" TargetName=\"mainBorder\" Value=\"1,1,1,0\"/>\n                        </MultiDataTrigger>\n                    </ControlTemplate.Triggers>\n                </ControlTemplate>\n            </Setter.Value>\n        </Setter>\n    </Style>\n\n    <Style x:Key=\"StandardDragablzTabItemVerticalStyle\" TargetType=\"{x:Type local:DragablzItem}\">\n        <Setter Property=\"FocusVisualStyle\" Value=\"{StaticResource FocusVisual}\"/>\n        <Setter Property=\"Foreground\" Value=\"Black\"/>\n        <Setter Property=\"Background\" Value=\"{StaticResource TabItem.Static.Background}\"/>\n        <Setter Property=\"BorderBrush\" Value=\"{StaticResource TabItem.Static.Border}\"/>\n        <Setter Property=\"Margin\" Value=\"0\"/>\n        <Setter Property=\"Padding\" Value=\"6,2,6,2\"/>\n        <Setter Property=\"HorizontalContentAlignment\" Value=\"Stretch\"/>\n        <Setter Property=\"VerticalContentAlignment\" Value=\"Stretch\"/>\n        <Setter Property=\"Template\">\n            <Setter.Value>\n                <ControlTemplate TargetType=\"{x:Type local:DragablzItem}\">\n                    <Grid x:Name=\"templateRoot\" SnapsToDevicePixels=\"true\">\n                        <Border x:Name=\"mainBorder\" BorderBrush=\"{TemplateBinding BorderBrush}\" BorderThickness=\"1,1,1,1\" Background=\"{TemplateBinding Background}\">\n                            <Border x:Name=\"innerBorder\" BorderBrush=\"{StaticResource TabItem.Selected.Border}\" BorderThickness=\"1,1,0,1\" Background=\"{StaticResource TabItem.Selected.Background}\" Margin=\"-1\" Opacity=\"0\"/>\n                        </Border>\n                        <ContentPresenter Content=\"{TemplateBinding ContentControl.Content}\" ContentTemplate=\"{TemplateBinding ContentControl.ContentTemplate}\" ContentStringFormat=\"{TemplateBinding ContentControl.ContentStringFormat}\" HorizontalAlignment=\"{TemplateBinding Control.HorizontalContentAlignment}\" VerticalAlignment=\"{TemplateBinding Control.VerticalContentAlignment}\" SnapsToDevicePixels=\"{TemplateBinding UIElement.SnapsToDevicePixels}\"\n                                          x:Name=\"contentPresenter\"\n                                          Margin=\"{TemplateBinding Control.Padding}\" />\n                        <Thumb HorizontalAlignment=\"Stretch\" VerticalContentAlignment=\"Stretch\" x:Name=\"PART_Thumb\"\n                               Style=\"{StaticResource InvisibleThumbStyle}\"/>\n                    </Grid>\n                    <ControlTemplate.Triggers>\n                        <Trigger Property=\"local:TabablzControl.IsWrappingTabItem\" Value=\"True\">\n                            <Setter TargetName=\"contentPresenter\" Property=\"Content\" Value=\"{Binding RelativeSource={RelativeSource TemplatedParent}, Path=DataContext.Header}\" />\n                        </Trigger>\n                        <MultiDataTrigger>\n                            <MultiDataTrigger.Conditions>\n                                <Condition Binding=\"{Binding IsMouseOver, RelativeSource={RelativeSource Self}}\" Value=\"true\"/>\n                                <Condition Binding=\"{Binding TabStripPlacement, RelativeSource={RelativeSource AncestorType={x:Type TabControl}}}\" Value=\"Left\"/>\n                            </MultiDataTrigger.Conditions>\n                            <Setter Property=\"Background\" TargetName=\"mainBorder\" Value=\"{StaticResource TabItem.MouseOver.Background}\"/>\n                            <Setter Property=\"BorderBrush\" TargetName=\"mainBorder\" Value=\"{StaticResource TabItem.MouseOver.Border}\"/>\n                            <!--\n                            <Setter Property=\"BorderThickness\" TargetName=\"innerBorder\" Value=\"1,1,1,0\"/>\n                            <Setter Property=\"BorderThickness\" TargetName=\"mainBorder\" Value=\"1,1,1,0\"/>\n                            -->\n                        </MultiDataTrigger>\n                        <MultiDataTrigger>\n                            <MultiDataTrigger.Conditions>\n                                <Condition Binding=\"{Binding IsMouseOver, RelativeSource={RelativeSource Self}}\" Value=\"true\"/>\n                                <Condition Binding=\"{Binding TabStripPlacement, RelativeSource={RelativeSource AncestorType={x:Type TabControl}}}\" Value=\"Bottom\"/>\n                            </MultiDataTrigger.Conditions>\n                            <Setter Property=\"Background\" TargetName=\"mainBorder\" Value=\"{StaticResource TabItem.MouseOver.Background}\"/>\n                            <Setter Property=\"BorderBrush\" TargetName=\"mainBorder\" Value=\"{StaticResource TabItem.MouseOver.Border}\"/>\n                            <!--\n                            <Setter Property=\"BorderThickness\" TargetName=\"innerBorder\" Value=\"0,1,1,1\"/>\n                            <Setter Property=\"BorderThickness\" TargetName=\"mainBorder\" Value=\"0,1,1,1\"/>\n                            -->\n                        </MultiDataTrigger>\n                        <MultiDataTrigger>\n                            <MultiDataTrigger.Conditions>\n                                <Condition Binding=\"{Binding IsMouseOver, RelativeSource={RelativeSource Self}}\" Value=\"true\"/>\n                                <Condition Binding=\"{Binding TabStripPlacement, RelativeSource={RelativeSource AncestorType={x:Type TabControl}}}\" Value=\"Right\"/>\n                            </MultiDataTrigger.Conditions>\n                            <Setter Property=\"Background\" TargetName=\"mainBorder\" Value=\"{StaticResource TabItem.MouseOver.Background}\"/>\n                            <Setter Property=\"BorderBrush\" TargetName=\"mainBorder\" Value=\"{StaticResource TabItem.MouseOver.Border}\"/>\n                            <!--\n                            <Setter Property=\"BorderThickness\" TargetName=\"innerBorder\" Value=\"1,0,1,1\"/>\n                            <Setter Property=\"BorderThickness\" TargetName=\"mainBorder\" Value=\"1,0,1,1\"/>\n                            -->\n                        </MultiDataTrigger>\n                        <MultiDataTrigger>\n                            <MultiDataTrigger.Conditions>\n                                <Condition Binding=\"{Binding IsMouseOver, RelativeSource={RelativeSource Self}}\" Value=\"true\"/>\n                                <Condition Binding=\"{Binding TabStripPlacement, RelativeSource={RelativeSource AncestorType={x:Type TabControl}}}\" Value=\"Top\"/>\n                            </MultiDataTrigger.Conditions>\n                            <Setter Property=\"Background\" TargetName=\"mainBorder\" Value=\"{StaticResource TabItem.MouseOver.Background}\"/>\n                            <Setter Property=\"BorderBrush\" TargetName=\"mainBorder\" Value=\"{StaticResource TabItem.MouseOver.Border}\"/>\n                            <!--\n                            <Setter Property=\"BorderThickness\" TargetName=\"innerBorder\" Value=\"1,1,0,1\"/>\n                            <Setter Property=\"BorderThickness\" TargetName=\"mainBorder\" Value=\"1,1,0,1\"/>\n                            -->\n                        </MultiDataTrigger>\n                        <MultiDataTrigger>\n                            <MultiDataTrigger.Conditions>\n                                <Condition Binding=\"{Binding IsEnabled, RelativeSource={RelativeSource Self}}\" Value=\"false\"/>\n                                <Condition Binding=\"{Binding TabStripPlacement, RelativeSource={RelativeSource AncestorType={x:Type TabControl}}}\" Value=\"Left\"/>\n                            </MultiDataTrigger.Conditions>\n                            <Setter Property=\"Opacity\" TargetName=\"contentPresenter\" Value=\"0.56\"/>\n                            <Setter Property=\"Background\" TargetName=\"mainBorder\" Value=\"{StaticResource TabItem.Disabled.Background}\"/>\n                            <Setter Property=\"BorderBrush\" TargetName=\"mainBorder\" Value=\"{StaticResource TabItem.Disabled.Border}\"/>\n                            <!--\n                            <Setter Property=\"BorderThickness\" TargetName=\"innerBorder\" Value=\"1,1,1,0\"/>\n                            <Setter Property=\"BorderThickness\" TargetName=\"mainBorder\" Value=\"1,1,1,0\"/>\n                            -->\n                        </MultiDataTrigger>\n                        <MultiDataTrigger>\n                            <MultiDataTrigger.Conditions>\n                                <Condition Binding=\"{Binding IsEnabled, RelativeSource={RelativeSource Self}}\" Value=\"false\"/>\n                                <Condition Binding=\"{Binding TabStripPlacement, RelativeSource={RelativeSource AncestorType={x:Type TabControl}}}\" Value=\"Bottom\"/>\n                            </MultiDataTrigger.Conditions>\n                            <Setter Property=\"Opacity\" TargetName=\"contentPresenter\" Value=\"0.56\"/>\n                            <Setter Property=\"Background\" TargetName=\"mainBorder\" Value=\"{StaticResource TabItem.Disabled.Background}\"/>\n                            <Setter Property=\"BorderBrush\" TargetName=\"mainBorder\" Value=\"{StaticResource TabItem.Disabled.Border}\"/>\n                            <!--\n                            <Setter Property=\"BorderThickness\" TargetName=\"innerBorder\" Value=\"0,1,1,1\"/>\n                            <Setter Property=\"BorderThickness\" TargetName=\"mainBorder\" Value=\"0,1,1,1\"/>\n                            -->\n                        </MultiDataTrigger>\n                        <MultiDataTrigger>\n                            <MultiDataTrigger.Conditions>\n                                <Condition Binding=\"{Binding IsEnabled, RelativeSource={RelativeSource Self}}\" Value=\"false\"/>\n                                <Condition Binding=\"{Binding TabStripPlacement, RelativeSource={RelativeSource AncestorType={x:Type TabControl}}}\" Value=\"Right\"/>\n                            </MultiDataTrigger.Conditions>\n                            <Setter Property=\"Opacity\" TargetName=\"contentPresenter\" Value=\"0.56\"/>\n                            <Setter Property=\"Background\" TargetName=\"mainBorder\" Value=\"{StaticResource TabItem.Disabled.Background}\"/>\n                            <Setter Property=\"BorderBrush\" TargetName=\"mainBorder\" Value=\"{StaticResource TabItem.Disabled.Border}\"/>\n                            <!--\n                            <Setter Property=\"BorderThickness\" TargetName=\"innerBorder\" Value=\"1,0,1,1\"/>\n                            <Setter Property=\"BorderThickness\" TargetName=\"mainBorder\" Value=\"1,0,1,1\"/>\n                            -->\n                        </MultiDataTrigger>\n                        <MultiDataTrigger>\n                            <MultiDataTrigger.Conditions>\n                                <Condition Binding=\"{Binding IsEnabled, RelativeSource={RelativeSource Self}}\" Value=\"false\"/>\n                                <Condition Binding=\"{Binding TabStripPlacement, RelativeSource={RelativeSource AncestorType={x:Type TabControl}}}\" Value=\"Top\"/>\n                            </MultiDataTrigger.Conditions>\n                            <Setter Property=\"Opacity\" TargetName=\"contentPresenter\" Value=\"0.56\"/>\n                            <Setter Property=\"Background\" TargetName=\"mainBorder\" Value=\"{StaticResource TabItem.Disabled.Background}\"/>\n                            <Setter Property=\"BorderBrush\" TargetName=\"mainBorder\" Value=\"{StaticResource TabItem.Disabled.Border}\"/>\n                            <!--\n                            <Setter Property=\"BorderThickness\" TargetName=\"innerBorder\" Value=\"1,1,0,1\"/>\n                            <Setter Property=\"BorderThickness\" TargetName=\"mainBorder\" Value=\"1,1,0,1\"/>\n                            -->\n                        </MultiDataTrigger>\n                        <MultiDataTrigger>\n                            <MultiDataTrigger.Conditions>\n                                <Condition Binding=\"{Binding IsSelected, RelativeSource={RelativeSource Self}}\" Value=\"false\"/>\n                                <Condition Binding=\"{Binding TabStripPlacement, RelativeSource={RelativeSource AncestorType={x:Type TabControl}}}\" Value=\"Left\"/>\n                            </MultiDataTrigger.Conditions>\n                            <!--\n                            <Setter Property=\"BorderThickness\" TargetName=\"innerBorder\" Value=\"1,1,1,0\"/>\n                            <Setter Property=\"BorderThickness\" TargetName=\"mainBorder\" Value=\"1,1,1,0\"/>\n                            -->\n                        </MultiDataTrigger>\n                        <MultiDataTrigger>\n                            <MultiDataTrigger.Conditions>\n                                <Condition Binding=\"{Binding IsSelected, RelativeSource={RelativeSource Self}}\" Value=\"true\"/>\n                                <Condition Binding=\"{Binding TabStripPlacement, RelativeSource={RelativeSource AncestorType={x:Type TabControl}}}\" Value=\"Left\"/>\n                            </MultiDataTrigger.Conditions>\n                            <Setter Property=\"Panel.ZIndex\" Value=\"1\"/>\n                            <Setter Property=\"Opacity\" TargetName=\"innerBorder\" Value=\"1\"/>\n                            <!--\n                            <Setter Property=\"Margin\" Value=\"-2,-2,-2,0\"/>\n                            <Setter Property=\"BorderThickness\" TargetName=\"innerBorder\" Value=\"1,1,1,0\"/>\n                            <Setter Property=\"BorderThickness\" TargetName=\"mainBorder\" Value=\"1,1,1,0\"/>\n                            -->\n                        </MultiDataTrigger>\n                        <MultiDataTrigger>\n                            <MultiDataTrigger.Conditions>\n                                <Condition Binding=\"{Binding IsSelected, RelativeSource={RelativeSource Self}}\" Value=\"false\"/>\n                                <Condition Binding=\"{Binding TabStripPlacement, RelativeSource={RelativeSource AncestorType={x:Type TabControl}}}\" Value=\"Bottom\"/>\n                            </MultiDataTrigger.Conditions>\n                            <!--\n                            <Setter Property=\"BorderThickness\" TargetName=\"innerBorder\" Value=\"0,1,1,1\"/>\n                            <Setter Property=\"BorderThickness\" TargetName=\"mainBorder\" Value=\"0,1,1,1\"/>\n                            -->\n                        </MultiDataTrigger>\n                        <MultiDataTrigger>\n                            <MultiDataTrigger.Conditions>\n                                <Condition Binding=\"{Binding IsSelected, RelativeSource={RelativeSource Self}}\" Value=\"true\"/>\n                                <Condition Binding=\"{Binding TabStripPlacement, RelativeSource={RelativeSource AncestorType={x:Type TabControl}}}\" Value=\"Bottom\"/>\n                            </MultiDataTrigger.Conditions>\n                            <Setter Property=\"Panel.ZIndex\" Value=\"1\"/>\n                            <Setter Property=\"Opacity\" TargetName=\"innerBorder\" Value=\"1\"/>\n                            <!--\n                            <Setter Property=\"Margin\" Value=\"0,-2,-2,-2\"/>\n                            <Setter Property=\"BorderThickness\" TargetName=\"innerBorder\" Value=\"0,1,1,1\"/>\n                            <Setter Property=\"BorderThickness\" TargetName=\"mainBorder\" Value=\"0,1,1,1\"/>\n                            -->\n                        </MultiDataTrigger>\n                        <MultiDataTrigger>\n                            <MultiDataTrigger.Conditions>\n                                <Condition Binding=\"{Binding IsSelected, RelativeSource={RelativeSource Self}}\" Value=\"false\"/>\n                                <Condition Binding=\"{Binding TabStripPlacement, RelativeSource={RelativeSource AncestorType={x:Type TabControl}}}\" Value=\"Right\"/>\n                            </MultiDataTrigger.Conditions>\n                            <!--\n                            <Setter Property=\"BorderThickness\" TargetName=\"innerBorder\" Value=\"1,0,1,1\"/>\n                            <Setter Property=\"BorderThickness\" TargetName=\"mainBorder\" Value=\"1,0,1,1\"/>\n                            -->\n                        </MultiDataTrigger>\n                        <MultiDataTrigger>\n                            <MultiDataTrigger.Conditions>\n                                <Condition Binding=\"{Binding IsSelected, RelativeSource={RelativeSource Self}}\" Value=\"true\"/>\n                                <Condition Binding=\"{Binding TabStripPlacement, RelativeSource={RelativeSource AncestorType={x:Type TabControl}}}\" Value=\"Right\"/>\n                            </MultiDataTrigger.Conditions>\n                            <Setter Property=\"Panel.ZIndex\" Value=\"1\"/>\n                            <Setter Property=\"Opacity\" TargetName=\"innerBorder\" Value=\"1\"/>\n                            <!--\n                            <Setter Property=\"Margin\" Value=\"-2,0,-2,-2\"/>\n                            <Setter Property=\"BorderThickness\" TargetName=\"innerBorder\" Value=\"1,0,1,1\"/>\n                            <Setter Property=\"BorderThickness\" TargetName=\"mainBorder\" Value=\"1,0,1,1\"/>\n                            -->\n                        </MultiDataTrigger>\n                        <MultiDataTrigger>\n                            <MultiDataTrigger.Conditions>\n                                <Condition Binding=\"{Binding IsSelected, RelativeSource={RelativeSource Self}}\" Value=\"false\"/>\n                                <Condition Binding=\"{Binding TabStripPlacement, RelativeSource={RelativeSource AncestorType={x:Type TabControl}}}\" Value=\"Top\"/>\n                            </MultiDataTrigger.Conditions>\n                            <!--\n                            <Setter Property=\"BorderThickness\" TargetName=\"innerBorder\" Value=\"1,1,0,1\"/>\n                            <Setter Property=\"BorderThickness\" TargetName=\"mainBorder\" Value=\"1,1,0,1\"/>\n                            -->\n                        </MultiDataTrigger>\n                        <MultiDataTrigger>\n                            <MultiDataTrigger.Conditions>\n                                <Condition Binding=\"{Binding IsSelected, RelativeSource={RelativeSource Self}}\"                                            \n                                           Value=\"True\"/>\n                                <Condition Binding=\"{Binding TabStripPlacement, RelativeSource={RelativeSource AncestorType={x:Type TabControl}}}\" Value=\"Top\"/>\n                            </MultiDataTrigger.Conditions>\n                            <Setter Property=\"Panel.ZIndex\" Value=\"1\"/>\n                            <Setter Property=\"Margin\" Value=\"0,0,-2,0\"/>\n                            <Setter Property=\"Opacity\" TargetName=\"innerBorder\" Value=\"1\"/>\n                            <!--\n                            <Setter Property=\"BorderThickness\" TargetName=\"innerBorder\" Value=\"1,1,0,1\"/>\n                            <Setter Property=\"BorderThickness\" TargetName=\"mainBorder\" Value=\"1,1,0,1\"/>\n                            -->\n                        </MultiDataTrigger>\n                    </ControlTemplate.Triggers>\n                </ControlTemplate>\n            </Setter.Value>\n        </Setter>\n    </Style>\n    \n    <Style TargetType=\"{x:Type local:TabablzControl}\">\n        <Setter Property=\"Padding\" Value=\"2\"/>\n        <Setter Property=\"HorizontalContentAlignment\" Value=\"Center\"/>\n        <Setter Property=\"VerticalContentAlignment\" Value=\"Center\"/>\n        <Setter Property=\"Background\" Value=\"{StaticResource TabItem.Selected.Background}\"/>\n        <Setter Property=\"BorderBrush\" Value=\"{StaticResource TabItem.Selected.Border}\"/>\n        <Setter Property=\"BorderThickness\" Value=\"1\"/>\n        <Setter Property=\"Foreground\" Value=\"{DynamicResource {x:Static SystemColors.ControlTextBrushKey}}\"/>\n        <Setter Property=\"ItemContainerStyle\" Value=\"{StaticResource StandardDragablzTabItemStyle}\"/>\n        <Setter Property=\"Template\">\n            <Setter.Value>\n                <ControlTemplate TargetType=\"{x:Type local:TabablzControl}\">\n                    <Grid x:Name=\"templateRoot\" ClipToBounds=\"true\" SnapsToDevicePixels=\"true\" KeyboardNavigation.TabNavigation=\"Local\">\n                        <Grid.ColumnDefinitions>\n                            <ColumnDefinition x:Name=\"ColumnDefinition0\"/>\n                            <ColumnDefinition x:Name=\"ColumnDefinition1\" Width=\"0\"/>\n                        </Grid.ColumnDefinitions>\n                        <Grid.RowDefinitions>\n                            <RowDefinition x:Name=\"RowDefinition0\" Height=\"Auto\"/>\n                            <RowDefinition x:Name=\"RowDefinition1\" Height=\"*\"/>\n                        </Grid.RowDefinitions>\n                        <Border x:Name=\"contentPanel\" BorderBrush=\"{TemplateBinding BorderBrush}\" BorderThickness=\"{TemplateBinding BorderThickness}\" Background=\"{TemplateBinding Background}\" Grid.Column=\"0\" KeyboardNavigation.DirectionalNavigation=\"Contained\" Grid.Row=\"1\" KeyboardNavigation.TabIndex=\"2\" KeyboardNavigation.TabNavigation=\"Local\"\n                                Margin=\"0 -1 0 0\">\n                            <Grid x:Name=\"PART_ItemsHolder\" />\n                        </Border>\n                        <Grid Grid.Column=\"0\" Grid.Row=\"0\" Margin=\"0,2,2,0\" x:Name=\"HeaderContainerGrid\" Visibility=\"{TemplateBinding IsHeaderPanelVisible, Converter={StaticResource BooleanToVisibilityConverter}}\">\n                            <Grid.Resources>\n                                <Style TargetType=\"{x:Type Button}\" BasedOn=\"{StaticResource StandardEmbeddedButtonStyle}\"></Style>\n                            </Grid.Resources>\n                            <Grid.ColumnDefinitions>\n                                <ColumnDefinition Width=\"Auto\" />\n                                <ColumnDefinition Width=\"Auto\" />\n                                <ColumnDefinition Width=\"Auto\" />\n                                <ColumnDefinition Width=\"*\" />\n                            </Grid.ColumnDefinitions>\n                            <ContentControl Grid.Column=\"0\" x:Name=\"PrefixContentControl\" \n                                            Content=\"{TemplateBinding HeaderPrefixContent}\"\n                                            ContentStringFormat=\"{TemplateBinding HeaderPrefixContentStringFormat}\"\n                                            ContentTemplate=\"{TemplateBinding HeaderPrefixContentStringFormat}\"\n                                            ContentTemplateSelector=\"{TemplateBinding HeaderPrefixContentTemplateSelector}\"/>\n                            <local:DragablzItemsControl x:Name=\"PART_HeaderItemsControl\"                                                         \n                                                        Grid.Column=\"1\"\n                                                        ItemsSource=\"{Binding RelativeSource={RelativeSource TemplatedParent}, Path=Items}\"                                                                                                            \n                                                        ItemContainerStyle=\"{TemplateBinding ItemContainerStyle}\"\n                                                        ItemsOrganiser=\"{TemplateBinding HeaderItemsOrganiser}\"\n                                                        KeyboardNavigation.TabIndex=\"1\" Panel.ZIndex=\"1\"\n                                                        ItemTemplate=\"{TemplateBinding HeaderItemTemplate}\"\n                                                        FixedItemCount=\"{TemplateBinding FixedHeaderCount}\"\n                                                        Style=\"{StaticResource TabablzDragablzItemsControlStyle}\">\n                                <local:DragablzItemsControl.MaxWidth>\n                                    <MultiBinding>\n                                        <MultiBinding.Converter>\n                                            <local:TabablzHeaderSizeConverter Orientation=\"Horizontal\"/>\n                                        </MultiBinding.Converter>\n                                        <Binding RelativeSource=\"{RelativeSource TemplatedParent}\" Path=\"ActualWidth\" />\n                                        <Binding RelativeSource=\"{RelativeSource Self}\" Path=\"ItemsPresenterWidth\" />\n                                        <Binding ElementName=\"PrefixContentControl\" Path=\"ActualWidth\" />\n                                        <Binding ElementName=\"DefaultAddButton\" Path=\"DesiredSize.Width\" />\n                                        <Binding ElementName=\"SuffixContentControl\" Path=\"DesiredSize.Width\" />\n                                    </MultiBinding>\n                                </local:DragablzItemsControl.MaxWidth>\n                            </local:DragablzItemsControl>\n                            <Button Style=\"{StaticResource AddItemCommandButtonStyle}\"\n                                    x:Name=\"DefaultAddButton\"\n                                    Grid.Column=\"2\"\n                                    Command=\"{x:Static local:TabablzControl.AddItemCommand}\"\n                                    Visibility=\"{TemplateBinding ShowDefaultAddButton, Converter={StaticResource BooleanToVisibilityConverter}}\"\n                                    />\n                            <ContentControl Grid.Column=\"3\" x:Name=\"SuffixContentControl\" \n                                            Content=\"{TemplateBinding HeaderSuffixContent}\"\n                                            ContentStringFormat=\"{TemplateBinding HeaderSuffixContentStringFormat}\"\n                                            ContentTemplate=\"{TemplateBinding HeaderSuffixContentStringFormat}\"\n                                            ContentTemplateSelector=\"{TemplateBinding HeaderSuffixContentTemplateSelector}\"                                            \n                                            HorizontalAlignment=\"Stretch\"\n                                            />\n                        </Grid>\n                    </Grid>\n                    <ControlTemplate.Triggers>\n                        <Trigger Property=\"IsHeaderPanelVisible\" Value=\"False\">\n                            <Setter Property=\"Margin\" TargetName=\"contentPanel\" Value=\"0 0 0 0\"/>\n                        </Trigger> \n                        <Trigger Property=\"TabStripPlacement\" Value=\"Bottom\">\n                            <Setter Property=\"Grid.Row\" TargetName=\"PART_HeaderItemsControl\" Value=\"1\"/>\n                            <Setter Property=\"Grid.Row\" TargetName=\"contentPanel\" Value=\"0\"/>\n                            <Setter Property=\"Height\" TargetName=\"RowDefinition0\" Value=\"*\"/>\n                            <Setter Property=\"Height\" TargetName=\"RowDefinition1\" Value=\"Auto\"/>\n                            <Setter Property=\"Margin\" TargetName=\"PART_HeaderItemsControl\" Value=\"2,0,2,2\"/>\n                        </Trigger>\n                        <Trigger Property=\"TabStripPlacement\" Value=\"Left\">\n                            <Setter Property=\"Grid.Row\" TargetName=\"PART_HeaderItemsControl\" Value=\"0\"/>\n                            <Setter Property=\"Grid.Row\" TargetName=\"contentPanel\" Value=\"0\"/>\n                            <Setter Property=\"Grid.Column\" TargetName=\"PART_HeaderItemsControl\" Value=\"0\"/>\n                            <Setter Property=\"Grid.Column\" TargetName=\"contentPanel\" Value=\"1\"/>\n                            <Setter Property=\"Width\" TargetName=\"ColumnDefinition0\" Value=\"Auto\"/>\n                            <Setter Property=\"Width\" TargetName=\"ColumnDefinition1\" Value=\"*\"/>\n                            <Setter Property=\"Height\" TargetName=\"RowDefinition0\" Value=\"*\"/>\n                            <Setter Property=\"Height\" TargetName=\"RowDefinition1\" Value=\"0\"/>\n                            <Setter Property=\"Margin\" TargetName=\"PART_HeaderItemsControl\" Value=\"2,2,0,2\"/>\n                        </Trigger>\n                        <Trigger Property=\"TabStripPlacement\" Value=\"Right\">\n                            <Setter Property=\"Grid.Row\" TargetName=\"PART_HeaderItemsControl\" Value=\"0\"/>\n                            <Setter Property=\"Grid.Row\" TargetName=\"contentPanel\" Value=\"0\"/>\n                            <Setter Property=\"Grid.Column\" TargetName=\"PART_HeaderItemsControl\" Value=\"1\"/>\n                            <Setter Property=\"Grid.Column\" TargetName=\"contentPanel\" Value=\"0\"/>\n                            <Setter Property=\"Width\" TargetName=\"ColumnDefinition0\" Value=\"*\"/>\n                            <Setter Property=\"Width\" TargetName=\"ColumnDefinition1\" Value=\"Auto\"/>\n                            <Setter Property=\"Height\" TargetName=\"RowDefinition0\" Value=\"*\"/>\n                            <Setter Property=\"Height\" TargetName=\"RowDefinition1\" Value=\"0\"/>\n                            <Setter Property=\"Margin\" TargetName=\"PART_HeaderItemsControl\" Value=\"0,2,2,2\"/>\n                        </Trigger>\n                        <Trigger Property=\"IsEnabled\" Value=\"false\">\n                            <Setter Property=\"TextElement.Foreground\" TargetName=\"templateRoot\" Value=\"{DynamicResource {x:Static SystemColors.GrayTextBrushKey}}\"/>\n                        </Trigger>\n                        <Trigger Property=\"IsDraggingWindow\" Value=\"True\">\n                            <Setter TargetName=\"DefaultAddButton\" Property=\"Visibility\" Value=\"Collapsed\" />\n                        </Trigger>\n                    </ControlTemplate.Triggers>\n                </ControlTemplate>\n            </Setter.Value>\n        </Setter>\n        <Style.Triggers>\n            <Trigger Property=\"TabStripPlacement\" Value=\"Left\">\n                <Setter Property=\"HeaderItemsOrganiser\">\n                    <Setter.Value>\n                        <local:VerticalOrganiser />\n                    </Setter.Value>\n                </Setter>\n                <Setter Property=\"ItemContainerStyle\" Value=\"{StaticResource StandardDragablzTabItemVerticalStyle}\"></Setter>\n                <Setter Property=\"Template\">\n                    <Setter.Value>\n                        <ControlTemplate TargetType=\"{x:Type local:TabablzControl}\">\n                            <Grid x:Name=\"templateRoot\" ClipToBounds=\"true\" SnapsToDevicePixels=\"true\" KeyboardNavigation.TabNavigation=\"Local\">\n                                <Grid.ColumnDefinitions>\n                                    <ColumnDefinition x:Name=\"ColumnDefinition0\" Width=\"Auto\"/>\n                                    <ColumnDefinition x:Name=\"ColumnDefinition1\" Width=\"*\"/>\n                                </Grid.ColumnDefinitions>\n                                <Border x:Name=\"contentPanel\" BorderBrush=\"{TemplateBinding BorderBrush}\" BorderThickness=\"{TemplateBinding BorderThickness}\" Background=\"{TemplateBinding Background}\" Grid.Column=\"1\" KeyboardNavigation.DirectionalNavigation=\"Contained\" KeyboardNavigation.TabIndex=\"2\" KeyboardNavigation.TabNavigation=\"Local\" Margin=\"-1 0 0 0\">\n                                    <Grid x:Name=\"PART_ItemsHolder\" />\n                                </Border>\n                                <Grid Grid.Column=\"0\" x:Name=\"HeaderContainerGrid\" Visibility=\"{TemplateBinding IsHeaderPanelVisible, Converter={StaticResource BooleanToVisibilityConverter}}\">\n                                    <Grid.RowDefinitions>\n                                        <RowDefinition Height=\"Auto\" />\n                                        <RowDefinition Height=\"Auto\" />\n                                        <RowDefinition Height=\"Auto\" />\n                                        <RowDefinition Height=\"*\" />\n                                    </Grid.RowDefinitions>\n                                    <ContentControl Grid.Row=\"0\" x:Name=\"PrefixContentControl\" \n                                                    Content=\"{TemplateBinding HeaderPrefixContent}\"\n                                                    ContentStringFormat=\"{TemplateBinding HeaderPrefixContentStringFormat}\"\n                                                    ContentTemplate=\"{TemplateBinding HeaderPrefixContentStringFormat}\"\n                                                    ContentTemplateSelector=\"{TemplateBinding HeaderPrefixContentTemplateSelector}\"/>\n                                    <local:DragablzItemsControl x:Name=\"PART_HeaderItemsControl\"                                                         \n                                                                Grid.Row=\"1\"\n                                                                ItemsSource=\"{Binding RelativeSource={RelativeSource TemplatedParent}, Path=Items}\"                                                                                                            \n                                                                ItemContainerStyle=\"{TemplateBinding ItemContainerStyle}\"\n                                                                ItemsOrganiser=\"{TemplateBinding HeaderItemsOrganiser}\"\n                                                                KeyboardNavigation.TabIndex=\"1\" Panel.ZIndex=\"1\"\n                                                                ItemTemplate=\"{TemplateBinding HeaderItemTemplate}\"\n                                                                Style=\"{StaticResource TabablzDragablzItemsControlStyle}\">\n                                        <local:DragablzItemsControl.MaxHeight>\n                                            <MultiBinding>\n                                                <MultiBinding.Converter>\n                                                    <local:TabablzHeaderSizeConverter Orientation=\"Vertical\"/>\n                                                </MultiBinding.Converter>\n                                                <Binding RelativeSource=\"{RelativeSource TemplatedParent}\" Path=\"ActualHeight\" />\n                                                <Binding RelativeSource=\"{RelativeSource Self}\" Path=\"ItemsPresenterHeight\" />\n                                                <Binding ElementName=\"PrefixContentControl\" Path=\"ActualHeight\" />\n                                                <Binding ElementName=\"DefaultAddButton\" Path=\"DesiredSize.Height\" />\n                                                <Binding ElementName=\"SuffixContentControl\" Path=\"DesiredSize.Height\" />\n                                            </MultiBinding>\n                                        </local:DragablzItemsControl.MaxHeight>\n                                    </local:DragablzItemsControl>\n                                    <Button Style=\"{StaticResource AddItemCommandButtonStyle}\"\n                                            x:Name=\"DefaultAddButton\"\n                                            Grid.Row=\"2\"\n                                            Command=\"{x:Static local:TabablzControl.AddItemCommand}\"\n                                            Visibility=\"{TemplateBinding ShowDefaultAddButton, Converter={StaticResource BooleanToVisibilityConverter}}\" />\n                                    <ContentControl Grid.Row=\"3\" x:Name=\"SuffixContentControl\" \n                                                    Content=\"{TemplateBinding HeaderSuffixContent}\"\n                                                    ContentStringFormat=\"{TemplateBinding HeaderSuffixContentStringFormat}\"\n                                                    ContentTemplate=\"{TemplateBinding HeaderSuffixContentStringFormat}\"\n                                                    ContentTemplateSelector=\"{TemplateBinding HeaderSuffixContentTemplateSelector}\"\n                                                    VerticalAlignment=\"Top\" />\n                                </Grid>\n                            </Grid>\n                        </ControlTemplate>\n                    </Setter.Value>\n                </Setter>\n            </Trigger>\n        </Style.Triggers>\n    </Style>\n\n    <Style TargetType=\"{x:Type local:Trapezoid}\">\n        <Setter Property=\"HorizontalAlignment\" Value=\"Left\" />\n        <Setter Property=\"VerticalAlignment\" Value=\"Top\" />\n        <Setter Property=\"Padding\" Value=\"2 2 2 2\" />\n        <Setter Property=\"Background\" Value=\"{StaticResource TabItem.Static.Background}\" />\n        <Setter Property=\"PenBrush\" Value=\"{StaticResource TabItem.Static.Border}\" />\n        <Setter Property=\"PenThickness\" Value=\".5\" />\n        <Setter Property=\"Template\">\n            <Setter.Value>\n                <ControlTemplate TargetType=\"{x:Type local:Trapezoid}\">\n                    <ContentPresenter HorizontalAlignment=\"Center\" VerticalAlignment=\"Center\" />\n                </ControlTemplate>\n            </Setter.Value>\n        </Setter>\n    </Style>\n\n    <Style TargetType=\"{x:Type local:DragablzItemsControl}\" x:Key=\"FloatingDragablzItemsControlStyle\">\n        <Setter Property=\"Background\" Value=\"{x:Null}\" />\n        <Setter Property=\"HorizontalAlignment\" Value=\"Stretch\" />\n        <Setter Property=\"VerticalAlignment\" Value=\"Stretch\" />\n        <Setter Property=\"ItemsOrganiser\">\n            <Setter.Value>\n                <local:CanvasOrganiser />\n            </Setter.Value>\n        </Setter>\n        <Setter Property=\"ItemsPanel\">\n            <Setter.Value>\n                <ItemsPanelTemplate>\n                    <Canvas IsItemsHost=\"True\" ClipToBounds=\"True\" />\n                </ItemsPanelTemplate>\n            </Setter.Value>\n        </Setter>\n        <Setter Property=\"Template\">\n            <Setter.Value>\n                <ControlTemplate TargetType=\"{x:Type local:DragablzItemsControl}\">\n                    <Border BorderThickness=\"{TemplateBinding Border.BorderThickness}\" Padding=\"{TemplateBinding Control.Padding}\" BorderBrush=\"{TemplateBinding Border.BorderBrush}\" Background=\"{TemplateBinding Panel.Background}\" SnapsToDevicePixels=\"True\">\n                        <ItemsPresenter SnapsToDevicePixels=\"{TemplateBinding UIElement.SnapsToDevicePixels}\"\n                                        HorizontalAlignment=\"Left\"\n                                        VerticalAlignment=\"Top\"\n                                        Width=\"{TemplateBinding ItemsPresenterWidth}\"\n                                        Height=\"{TemplateBinding ItemsPresenterHeight}\"/>\n                    </Border>\n                </ControlTemplate>\n            </Setter.Value>\n        </Setter>\n    </Style>\n\n    <Style TargetType=\"dockablz:Layout\">\n        <Setter Property=\"FloatingItemsControlStyle\" Value=\"{StaticResource FloatingDragablzItemsControlStyle}\" />\n        <!--Setter Property=\"FloatingItemContainerStyle\" Value=\"{StaticResource FloatingDragablzItemStyle}\" /-->\n        <Setter Property=\"FloatingItemContainerStyleSelector\">\n            <Setter.Value>\n                <dockablz:CouldBeHeaderedStyleSelector NonHeaderedStyle=\"{StaticResource FloatingDragablzItemStyle}\"\n                                                       HeaderedStyle=\"{StaticResource ToolDragablzItemStyle}\" />\n            </Setter.Value>\n        </Setter>\n        <Setter Property=\"Template\">\n            <Setter.Value>\n                <ControlTemplate TargetType=\"dockablz:Layout\">\n                    <Border Background=\"{TemplateBinding Background}\"\n                            BorderBrush=\"{TemplateBinding BorderBrush}\"\n                            BorderThickness=\"{TemplateBinding BorderThickness}\">\n                        <Grid>\n                            <ContentPresenter Content=\"{TemplateBinding ContentControl.Content}\" ContentTemplate=\"{TemplateBinding ContentControl.ContentTemplate}\" ContentStringFormat=\"{TemplateBinding ContentControl.ContentStringFormat}\" />\n                            <ContentPresenter x:Name=\"PART_FloatContentPresenter\" Margin=\"{TemplateBinding FloatingItemsContainerMargin}\" />\n                            <dockablz:DropZone x:Name=\"PART_TopDropZone\" \n                                               VerticalAlignment=\"Top\" HorizontalAlignment=\"Center\"                                               \n                                               Location=\"Top\"                                               \n                                               Visibility=\"{TemplateBinding IsParticipatingInDrag, Converter={StaticResource BooleanToVisibilityConverter}}\"\n                                               />\n                            <dockablz:DropZone x:Name=\"PART_RightDropZone\" \n                                               VerticalAlignment=\"Center\" HorizontalAlignment=\"Right\"\n                                               Location=\"Right\"                                               \n                                               Visibility=\"{TemplateBinding IsParticipatingInDrag, Converter={StaticResource BooleanToVisibilityConverter}}\"\n                                               />\n                            <dockablz:DropZone x:Name=\"PART_BottomDropZone\" \n                                               VerticalAlignment=\"Bottom\" HorizontalAlignment=\"Center\"\n                                               Location=\"Bottom\"                                               \n                                               Visibility=\"{TemplateBinding IsParticipatingInDrag, Converter={StaticResource BooleanToVisibilityConverter}}\"\n                                               />\n                            <dockablz:DropZone x:Name=\"PART_LeftDropZone\" \n                                               VerticalAlignment=\"Center\" HorizontalAlignment=\"Left\"\n                                               Location=\"Left\"                                               \n                                               Visibility=\"{TemplateBinding IsParticipatingInDrag, Converter={StaticResource BooleanToVisibilityConverter}}\"\n                                               />\n                            <dockablz:DropZone x:Name=\"PART_FloatDropZone\" \n                                               VerticalAlignment=\"Center\" HorizontalAlignment=\"Center\"\n                                               Location=\"Floating\">\n                                <dockablz:DropZone.Visibility>\n                                    <MultiBinding Converter=\"{StaticResource BooleanAndToVisibilityConverter}\">\n                                        <Binding RelativeSource=\"{RelativeSource TemplatedParent}\" Path=\"IsParticipatingInDrag\" />\n                                        <Binding RelativeSource=\"{RelativeSource TemplatedParent}\" Path=\"IsFloatDropZoneEnabled\" />\n                                    </MultiBinding>\n                                </dockablz:DropZone.Visibility>\n                            </dockablz:DropZone>\n                        </Grid>\n                    </Border>\n                </ControlTemplate>\n            </Setter.Value>\n        </Setter>\n    </Style>\n\n    <Style TargetType=\"{x:Type dockablz:Branch}\">\n        <Setter Property=\"Template\">\n            <Setter.Value>\n                <ControlTemplate TargetType=\"{x:Type dockablz:Branch}\">\n                    <Border Background=\"{TemplateBinding Background}\"\n                            BorderBrush=\"{TemplateBinding BorderBrush}\"\n                            BorderThickness=\"{TemplateBinding BorderThickness}\">\n                        <Grid>\n                            <Grid.ColumnDefinitions>\n                                <ColumnDefinition Width=\"{Binding RelativeSource={RelativeSource TemplatedParent}, Path=FirstItemLength, Mode=TwoWay}\" />\n                                <ColumnDefinition Width=\"Auto\" />\n                                <ColumnDefinition Width=\"{Binding RelativeSource={RelativeSource TemplatedParent}, Path=SecondItemLength, Mode=TwoWay}\" />\n                            </Grid.ColumnDefinitions>\n                            <ContentPresenter x:Name=\"PART_FirstContentPresenter\" Content=\"{TemplateBinding FirstItem}\" />\n                            <GridSplitter Grid.Column=\"1\" ResizeDirection=\"Columns\" ResizeBehavior=\"PreviousAndNext\" \n                                          Width=\"5\"/>\n                            <ContentPresenter x:Name=\"PART_SecondContentPresenter\" Grid.Column=\"2\" Content=\"{TemplateBinding SecondItem}\" />\n                        </Grid>\n                    </Border>\n                </ControlTemplate>\n            </Setter.Value>\n        </Setter>\n        <Style.Triggers>\n            <Trigger Property=\"Orientation\" Value=\"Vertical\">\n                <Setter Property=\"Template\">\n                    <Setter.Value>\n                        <ControlTemplate TargetType=\"{x:Type dockablz:Branch}\">\n                            <Border Background=\"{TemplateBinding Background}\"\n                                    BorderBrush=\"{TemplateBinding BorderBrush}\"\n                                    BorderThickness=\"{TemplateBinding BorderThickness}\">\n                                <Grid>\n                                    <Grid.RowDefinitions>\n                                        <RowDefinition Height=\"{Binding RelativeSource={RelativeSource TemplatedParent}, Path=FirstItemLength, Mode=TwoWay}\" />\n                                        <RowDefinition Height=\"Auto\" />\n                                        <RowDefinition Height=\"{Binding RelativeSource={RelativeSource TemplatedParent}, Path=SecondItemLength, Mode=TwoWay}\" />\n                                    </Grid.RowDefinitions>\n                                    <ContentPresenter x:Name=\"PART_FirstContentPresenter\" Content=\"{TemplateBinding FirstItem}\" />\n                                    <GridSplitter Grid.Row=\"1\" ResizeDirection=\"Rows\" ResizeBehavior=\"PreviousAndNext\" Height=\"5\" HorizontalAlignment=\"Stretch\" />\n                                    <ContentPresenter x:Name=\"PART_SecondContentPresenter\" Grid.Row=\"2\" Content=\"{TemplateBinding SecondItem}\" />\n                                </Grid>\n                            </Border>\n                        </ControlTemplate>\n                    </Setter.Value>\n                </Setter>\n            </Trigger>\n        </Style.Triggers>\n    </Style>\n\n</ResourceDictionary> \n \n \n \n"
  },
  {
    "path": "third_party/Dragablz/Dragablz/Themes/MahApps.xaml",
    "content": "﻿<ResourceDictionary xmlns=\"http://schemas.microsoft.com/winfx/2006/xaml/presentation\"\n                    xmlns:x=\"http://schemas.microsoft.com/winfx/2006/xaml\"\n                    xmlns:dragablz=\"clr-namespace:Dragablz\"\n                    xmlns:dockablz=\"clr-namespace:Dragablz.Dockablz\"\n                    xmlns:converters=\"clr-namespace:Dragablz.Converters\">\n\n    <BooleanToVisibilityConverter x:Key=\"BooleanToVisibilityConverter\" />\n    <converters:EqualityToVisibilityConverter x:Key=\"EqualityToVisibilityConverter\" />\n    <converters:BooleanAndToVisibilityConverter x:Key=\"BooleanAndToVisibilityConverter\" />\n    <converters:EqualityToBooleanConverter x:Key=\"EqualityToBooleanConverter\" />\n    <converters:ShowDefaultCloseButtonConverter x:Key=\"ShowDefaultCloseButtonConverter\" />\n\n    <Style x:Key=\"MahAppsFocusVisual\">\n        <Setter Property=\"Control.Template\">\n            <Setter.Value>\n                <ControlTemplate>\n                    <Rectangle Margin=\"2\" SnapsToDevicePixels=\"true\" Stroke=\"{DynamicResource {x:Static SystemColors.ControlTextBrushKey}}\" StrokeThickness=\"1\" StrokeDashArray=\"1 2\"/>\n                </ControlTemplate>\n            </Setter.Value>\n        </Setter>\n    </Style>\n\n    <Style TargetType=\"{x:Type Thumb}\" x:Key=\"MahAppsInvisibleThumbStyle\">\n        <Setter Property=\"Background\" Value=\"Transparent\" />\n        <Setter Property=\"Template\">\n            <Setter.Value>\n                <ControlTemplate>\n                    <Grid Background=\"{TemplateBinding Background}\" />\n                </ControlTemplate>\n            </Setter.Value>\n        </Setter>\n    </Style>\n\n    <Style TargetType=\"{x:Type Button}\" x:Key=\"MahAppsMenuCommandButtonStyle\">\n        <Setter Property=\"FocusVisualStyle\" Value=\"{StaticResource MahAppsFocusVisual}\"/>\n        <Setter Property=\"Background\" Value=\"Transparent\"/>\n        <Setter Property=\"BorderBrush\" Value=\"Transparent\"/>\n        <Setter Property=\"Foreground\" Value=\"{DynamicResource {x:Static SystemColors.ControlTextBrushKey}}\"/>\n        <Setter Property=\"BorderThickness\" Value=\"0\"/>\n        <Setter Property=\"HorizontalContentAlignment\" Value=\"Center\"/>\n        <Setter Property=\"VerticalContentAlignment\" Value=\"Center\"/>\n        <Setter Property=\"Padding\" Value=\"1\"/>\n        <Setter Property=\"Opacity\" Value=\".8\"/>\n        <Setter Property=\"Width\" Value=\"24\"/>\n        <Setter Property=\"Height\" Value=\"20\"/>\n        <Setter Property=\"Template\">\n            <Setter.Value>\n                <ControlTemplate TargetType=\"{x:Type Button}\">\n                    <Border x:Name=\"border\" BorderBrush=\"{TemplateBinding BorderBrush}\" BorderThickness=\"{TemplateBinding BorderThickness}\" Background=\"{TemplateBinding Background}\" SnapsToDevicePixels=\"true\">\n                        <ContentPresenter x:Name=\"contentPresenter\" Focusable=\"False\" HorizontalAlignment=\"{TemplateBinding HorizontalContentAlignment}\" Margin=\"{TemplateBinding Padding}\" RecognizesAccessKey=\"True\" SnapsToDevicePixels=\"{TemplateBinding SnapsToDevicePixels}\" VerticalAlignment=\"{TemplateBinding VerticalContentAlignment}\"/>\n                    </Border>\n                    <ControlTemplate.Triggers>\n                        <Trigger Property=\"IsDefaulted\" Value=\"true\">\n                            <Setter Property=\"BorderBrush\" TargetName=\"border\" Value=\"{DynamicResource {x:Static SystemColors.HighlightBrushKey}}\"/>\n                        </Trigger>\n                        <Trigger Property=\"IsEnabled\" Value=\"false\">\n                            <Setter Property=\"Opacity\" TargetName=\"border\" Value=\".5\"/>\n                        </Trigger>\n                    </ControlTemplate.Triggers>\n                </ControlTemplate>\n            </Setter.Value>\n        </Setter>\n        <Style.Triggers>\n            <Trigger Property=\"IsMouseOver\" Value=\"true\">\n                <Setter Property=\"Background\" Value=\"{x:Static dragablz:DragablzColors.WindowGlassBrush}\"/>\n                <Setter Property=\"Foreground\" Value=\"{x:Static SystemColors.HighlightTextBrush}\" />\n            </Trigger>\n            <Trigger Property=\"IsPressed\" Value=\"true\">\n                <Setter Property=\"Opacity\" Value=\"1\"/>\n            </Trigger>\n        </Style.Triggers>\n    </Style>\n\n    <Style TargetType=\"{x:Type Button}\" x:Key=\"MahAppsCloseItemCommandButtonStyle\" BasedOn=\"{StaticResource MahAppsMenuCommandButtonStyle}\">\n        <Setter Property=\"Template\">\n            <Setter.Value>\n                <ControlTemplate>\n                    <Grid>\n                        <Ellipse Width=\"{TemplateBinding Width}\"\n                                 Height=\"{TemplateBinding Height}\"\n                                 Fill=\"{TemplateBinding Background}\"/>\n                        <Path x:Name=\"Path\"\n                              Data=\"M0.5,71 L70,0.5 M0.5,1 L70,70.5\" \n                              Width=\"6\" Height=\"6\"\n                              Stretch=\"Uniform\"\n                              Stroke=\"{TemplateBinding Foreground}\"\n                              StrokeThickness=\"1.5\"\n                              StrokeStartLineCap=\"Square\" \n                              StrokeEndLineCap=\"Square\"\n                              SnapsToDevicePixels=\"True\" />\n                    </Grid>\n                </ControlTemplate>\n            </Setter.Value>\n        </Setter>\n        <Setter Property=\"Background\">\n            <Setter.Value>\n                <SolidColorBrush Color=\"{x:Static SystemColors.ActiveBorderColor}\" />\n            </Setter.Value>\n        </Setter>\n        <Setter Property=\"Width\" Value=\"12\" />\n        <Setter Property=\"Height\" Value=\"12\" />\n        <Setter Property=\"Margin\" Value=\"4 0 2 0\" />\n        <Setter Property=\"Opacity\" Value=\".75\" />\n        <Setter Property=\"Foreground\" Value=\"{x:Static SystemColors.HighlightTextBrush}\" />\n        <Style.Triggers>\n            <Trigger Property=\"IsMouseOver\" Value=\"true\">\n                <Setter Property=\"Opacity\" Value=\"1\"/>\n            </Trigger>\n        </Style.Triggers>\n    </Style>\n\n    <Style TargetType=\"{x:Type Button}\" x:Key=\"AddItemCommandButtonStyle\" BasedOn=\"{StaticResource MahAppsMenuCommandButtonStyle}\">\n        <Setter Property=\"Template\">\n            <Setter.Value>\n                <ControlTemplate>\n                    <Grid>\n                        <Ellipse Width=\"{TemplateBinding Width}\"\n                                 Height=\"{TemplateBinding Height}\"\n                                 Fill=\"{TemplateBinding Background}\"/>\n                        <Path x:Name=\"Path\"\n                              Data=\"M38,6L38.0003451911513,70.6666666666666 M70.3336667356886,38L5.50002465137562,38\" \n                              Width=\"6\" Height=\"6\"\n                              Stretch=\"Uniform\"\n                              Stroke=\"{TemplateBinding Foreground}\"\n                              StrokeThickness=\"1.5\"\n                              StrokeStartLineCap=\"Square\" \n                              StrokeEndLineCap=\"Square\"\n                              SnapsToDevicePixels=\"True\" />\n                    </Grid>\n                </ControlTemplate>\n            </Setter.Value>\n        </Setter>\n        <Setter Property=\"Background\">\n            <Setter.Value>\n                <SolidColorBrush Color=\"{x:Static SystemColors.ActiveBorderColor}\" />\n            </Setter.Value>\n        </Setter>\n        <Setter Property=\"Width\" Value=\"12\" />\n        <Setter Property=\"Height\" Value=\"12\" />\n        <Setter Property=\"Margin\" Value=\"4 0 2 0\" />\n        <Setter Property=\"Foreground\" Value=\"{x:Static SystemColors.HighlightTextBrush}\" />\n        <Style.Triggers>\n            <Trigger Property=\"IsMouseOver\" Value=\"true\">\n                <Setter Property=\"Background\" Value=\"{x:Static dragablz:DragablzColors.WindowGlassBrush}\"/>\n                <Setter Property=\"Foreground\" Value=\"{x:Static SystemColors.HighlightTextBrush}\" />\n            </Trigger>\n            <Trigger Property=\"IsPressed\" Value=\"true\">\n                <Setter Property=\"Opacity\" Value=\"1\"/>\n            </Trigger>\n        </Style.Triggers>\n    </Style>\n\n    <Style x:Key=\"MahAppsTrapezoidDragableTabItemStyle\"  TargetType=\"{x:Type dragablz:DragablzItem}\">\n        <Setter Property=\"FocusVisualStyle\" Value=\"{StaticResource MahAppsFocusVisual}\"/>\n        <Setter Property=\"Foreground\" Value=\"{DynamicResource BlackBrush}\"/>\n        <Setter Property=\"Background\" Value=\"Transparent\"/>\n        <Setter Property=\"BorderBrush\" Value=\"Transparent\"/>\n        <Setter Property=\"Margin\" Value=\"0 0 0 0\"/>\n        <Setter Property=\"HorizontalContentAlignment\" Value=\"Stretch\"/>\n        <Setter Property=\"VerticalContentAlignment\" Value=\"Stretch\"/>\n        <Setter Property=\"Template\">\n            <Setter.Value>\n                <ControlTemplate TargetType=\"{x:Type dragablz:DragablzItem}\">                    \n                    <Grid x:Name=\"templateRoot\" SnapsToDevicePixels=\"true\" Margin=\"0 1 0 -1\">\n                        <dragablz:Trapezoid x:Name=\"Trapezoid\" \n                                            BorderBrush=\"{TemplateBinding BorderBrush}\" \n                                            Background=\"{TemplateBinding Background}\"                                          \n                                            LongBasePenBrush=\"{TemplateBinding Background}\"                                          \n                                            PenThickness=\"0\"\n                                            Margin=\"0 0 0 0\">                            \n                            <Grid>\n                                <Grid.ColumnDefinitions>\n                                    <ColumnDefinition Width=\"*\" />\n                                    <ColumnDefinition Width=\"Auto\" />\n                                </Grid.ColumnDefinitions>\n                                <ContentPresenter Content=\"{TemplateBinding ContentControl.Content}\" ContentTemplate=\"{TemplateBinding ContentControl.ContentTemplate}\" ContentStringFormat=\"{TemplateBinding ContentControl.ContentStringFormat}\" HorizontalAlignment=\"{TemplateBinding Control.HorizontalContentAlignment}\" VerticalAlignment=\"{TemplateBinding Control.VerticalContentAlignment}\" SnapsToDevicePixels=\"{TemplateBinding UIElement.SnapsToDevicePixels}\"\n                                                  Margin=\"{TemplateBinding Control.Padding }\"\n                                                  x:Name=\"contentPresenter\" />                                    \n                                <Thumb Grid.Column=\"0\" HorizontalAlignment=\"Stretch\" VerticalContentAlignment=\"Stretch\" \n                                       x:Name=\"PART_Thumb\"\n                                       Style=\"{StaticResource MahAppsInvisibleThumbStyle}\" />\n                                <Button Grid.Column=\"1\"\n                                        Style=\"{StaticResource MahAppsCloseItemCommandButtonStyle}\"                                        \n                                        Command=\"{x:Static dragablz:TabablzControl.CloseItemCommand}\"\n                                        CommandParameter=\"{Binding RelativeSource={RelativeSource TemplatedParent}}\">\n                                    <Button.Visibility>\n                                        <MultiBinding Converter=\"{StaticResource ShowDefaultCloseButtonConverter}\">\n                                            <Binding RelativeSource=\"{RelativeSource FindAncestor, AncestorType={x:Type dragablz:TabablzControl}}\" Path=\"ShowDefaultCloseButton\" />\n                                            <Binding RelativeSource=\"{RelativeSource FindAncestor, AncestorType={x:Type dragablz:TabablzControl}}\" Path=\"FixedHeaderCount\" />\n                                            <Binding RelativeSource=\"{RelativeSource TemplatedParent}\" Path=\"LogicalIndex\" />\n                                        </MultiBinding>\n                                    </Button.Visibility>\n                                </Button>\n                            </Grid>\n                        </dragablz:Trapezoid>\n                    </Grid>\n                    <ControlTemplate.Triggers>\n                        <Trigger Property=\"dragablz:TabablzControl.IsWrappingTabItem\" Value=\"True\">\n                            <Setter TargetName=\"contentPresenter\" Property=\"Content\" Value=\"{Binding RelativeSource={RelativeSource TemplatedParent}, Path=DataContext.Header}\" />\n                        </Trigger>\n                        <Trigger Property=\"IsMouseOver\" Value=\"True\">\n                            <Setter Property=\"Background\" Value=\"{DynamicResource AccentColorBrush3}\" TargetName=\"Trapezoid\"/>\n                            <Setter Property=\"LongBasePenBrush\" Value=\"{DynamicResource AccentColorBrush3}\" TargetName=\"Trapezoid\"/>\n                        </Trigger>\n                        <Trigger Property=\"IsSelected\" Value=\"True\">\n                            <Setter Property=\"Background\" Value=\"{DynamicResource AccentColorBrush}\" TargetName=\"Trapezoid\"/>\n                            <Setter Property=\"LongBasePenBrush\" Value=\"{DynamicResource AccentColorBrush}\" TargetName=\"Trapezoid\"/>\n                            <Setter Property=\"Foreground\" Value=\"{DynamicResource WhiteBrush}\"/>\n                        </Trigger>\n                    </ControlTemplate.Triggers>\n                </ControlTemplate>\n            </Setter.Value>\n        </Setter>\n    </Style>\n\n    <Style x:Key=\"MahAppsMetroBaseWindowButtonStyle\" TargetType=\"{x:Type Button}\">\n        <Setter Property=\"Background\" Value=\"{DynamicResource TransparentWhiteBrush}\" />\n        <Setter Property=\"Foreground\" Value=\"{DynamicResource WhiteColorBrush}\" />\n        <Setter Property=\"HorizontalContentAlignment\" Value=\"Center\" />\n        <Setter Property=\"VerticalContentAlignment\" Value=\"Center\" />\n        <Setter Property=\"Padding\" Value=\"1\" />\n        <Setter Property=\"Template\">\n            <Setter.Value>\n                <ControlTemplate TargetType=\"{x:Type Button}\">\n                    <Grid Background=\"{TemplateBinding Background}\">\n                        <ContentPresenter x:Name=\"contentPresenter\"\n                                          HorizontalAlignment=\"{TemplateBinding HorizontalContentAlignment}\"\n                                          Margin=\"{TemplateBinding Padding}\"\n                                          VerticalAlignment=\"{TemplateBinding VerticalContentAlignment}\"\n                                          SnapsToDevicePixels=\"{TemplateBinding SnapsToDevicePixels}\"\n                                          RecognizesAccessKey=\"True\"\n                                          Opacity=\"0.75\" />\n                    </Grid>\n                    <ControlTemplate.Triggers>\n                        <Trigger Property=\"IsMouseOver\" Value=\"True\">\n                            <Setter TargetName=\"contentPresenter\" Property=\"Opacity\" Value=\"1\" />\n                        </Trigger>\n                        <Trigger Property=\"IsMouseOver\" Value=\"False\">\n                            <Setter TargetName=\"contentPresenter\" Property=\"Opacity\" Value=\".5\" />\n                        </Trigger>\n                    </ControlTemplate.Triggers>\n                </ControlTemplate>\n            </Setter.Value>\n        </Setter>\n        <Style.Triggers>\n            <Trigger Property=\"IsMouseOver\" Value=\"True\">\n                <Setter Property=\"Background\" Value=\"{DynamicResource SemiTransparentWhiteBrush}\" />\n            </Trigger>\n            <Trigger Property=\"IsPressed\" Value=\"True\">\n                <Setter Property=\"Background\" Value=\"{DynamicResource HighlightBrush}\" />\n                <Setter Property=\"Foreground\" Value=\"White\" />\n            </Trigger>\n            <Trigger Property=\"IsEnabled\" Value=\"false\">\n                <Setter Property=\"Foreground\" Value=\"#ADADAD\" />\n            </Trigger>\n        </Style.Triggers>\n    </Style>\n\n    <Style x:Key=\"MahAppsToolWindowButtonStyle\" TargetType=\"{x:Type Button}\" BasedOn=\"{StaticResource MahAppsMetroBaseWindowButtonStyle}\">\n        <Setter Property=\"FocusVisualStyle\" Value=\"{x:Null}\" />\n        <Setter Property=\"IsTabStop\" Value=\"False\" />\n        <Setter Property=\"Width\" Value=\"30\" />\n        <Setter Property=\"MaxHeight\" Value=\"30\" />\n        <Setter Property=\"Padding\" Value=\"0\" />\n        <Style.Triggers>\n            <Trigger Property=\"IsEnabled\" Value=\"False\">\n                <Setter Property=\"Visibility\" Value=\"Collapsed\" />\n            </Trigger>\n        </Style.Triggers>\n    </Style>\n\n    <Style TargetType=\"{x:Type dragablz:HeaderedDragablzItem}\" x:Key=\"MahAppsToolDragablzItemStyle\">\n        <Style.Setters>\n            <Setter Property=\"BorderBrush\" Value=\"{DynamicResource AccentColorBrush2}\" />\n            <Setter Property=\"BorderThickness\" Value=\"4\" />\n            <Setter Property=\"Canvas.Left\" Value=\"{Binding X, RelativeSource={RelativeSource Self}}\" />\n            <Setter Property=\"Canvas.Top\" Value=\"{Binding Y, RelativeSource={RelativeSource Self}}\" />\n            <Setter Property=\"Template\">\n                <Setter.Value>\n                    <ControlTemplate TargetType=\"{x:Type dragablz:HeaderedDragablzItem}\">\n                        <Grid Margin=\"{TemplateBinding Margin}\">\n                            <Border Background=\"{DynamicResource WhiteColorBrush}\">\n                                <Border.Effect>\n                                    <DropShadowEffect BlurRadius=\"10\" ShadowDepth=\"5\" Direction=\"315\" Color=\"{DynamicResource AccentColor2}\" Opacity=\".5\" />\n                                </Border.Effect>\n                            </Border>\n                            <Border BorderThickness=\"{TemplateBinding Border.BorderThickness}\" Padding=\"{TemplateBinding Control.Padding}\" BorderBrush=\"{TemplateBinding Border.BorderBrush}\" Background=\"{TemplateBinding Panel.Background}\" SnapsToDevicePixels=\"True\">\n                                <DockPanel>\n                                    <Grid DockPanel.Dock=\"Top\" Background=\"{TemplateBinding BorderBrush}\">\n                                        <Thumb HorizontalAlignment=\"Stretch\" VerticalContentAlignment=\"Stretch\" x:Name=\"PART_Thumb\"\n                                               Style=\"{StaticResource MahAppsInvisibleThumbStyle}\"\n                                               />\n                                        <DockPanel Margin=\"{TemplateBinding Control.Padding }\">\n                                            <Button DockPanel.Dock=\"Right\"\n                                                    Command=\"{x:Static dockablz:Layout.CloseFloatingItem}\"\n                                                    CommandParameter=\"{Binding RelativeSource={RelativeSource TemplatedParent}}\"\n                                                    Margin=\"1 0 0 0\"\n                                                    Style=\"{DynamicResource MahAppsToolWindowButtonStyle}\"\n                                                    Focusable=\"False\"\n                                                    RenderOptions.EdgeMode=\"Aliased\"\n                                                    >\n                                                <Path Data=\"M 10.009,1.704 L 8.331,0.026 5.03,3.327 1.703,0 0,1.704 3.326,5.031 0.025,8.332 1.703,10.009 5.004,6.708 8.305,10.009 10.009,8.305 6.708,5.005\"\n                                                      SnapsToDevicePixels=\"True\"\n                                                      Fill=\"{Binding Path=Foreground, RelativeSource={RelativeSource AncestorType=Button}}\" />\n                                            </Button>\n                                            <Button DockPanel.Dock=\"Right\"\n                                                    Command=\"{x:Static dockablz:Layout.UnfloatItemCommand}\"\n                                                    CommandParameter=\"{Binding RelativeSource={RelativeSource TemplatedParent}}\"\n                                                    Margin=\"1 0 0 0\"\n                                                    Style=\"{DynamicResource MahAppsToolWindowButtonStyle}\"\n                                                    >\n                                                <Path Width=\"12\" Height=\"12\" Stretch=\"UniformToFill\" Fill=\"{Binding Path=Foreground, RelativeSource={RelativeSource AncestorType=Button}}\" Data=\"M 19 19 H 5 V 5 h 7 V 3 H 5 C 3.89 3 3 3.9 3 5 v 14 c 0 1.1 0.89 2 2 2 h 14 c 1.1 0 2 -0.9 2 -2 v -7 h -2 v 7 z M 14 3 v 2 h 3.59 L 7.76 14.83 9.17 16.24 19 6.41 V 10 h 2 V 3 h -7 z\" />\n                                            </Button>\n                                            <Button DockPanel.Dock=\"Right\"\n                                                    Command=\"{x:Static dockablz:Layout.MaximiseFloatingItem}\"\n                                                    CommandParameter=\"{Binding RelativeSource={RelativeSource TemplatedParent}}\"\n                                                    Margin=\"1 0 0 0\"\n                                                    Style=\"{DynamicResource MahAppsToolWindowButtonStyle}\"\n                                                    >\n                                                <Path Width=\"10\"\n                                                      Height=\"10\"\n                                                      Data=\"F1M0,0L0,9 9,9 9,0 0,0 0,3 8,3 8,8 1,8 1,3z\"\n                                                      SnapsToDevicePixels=\"True\"\n                                                      Fill=\"{Binding Path=Foreground, RelativeSource={RelativeSource AncestorType=Button}}\" />\n                                            </Button>\n                                            <Button DockPanel.Dock=\"Right\"\n                                                    Command=\"{x:Static dockablz:Layout.RestoreFloatingItem}\"\n                                                    CommandParameter=\"{Binding RelativeSource={RelativeSource TemplatedParent}}\"\n                                                    Margin=\"1 0 0 0\"\n                                                    Style=\"{DynamicResource MahAppsToolWindowButtonStyle}\"\n                                                    >\n                                                <Path Width=\"10\"\n                                                      Height=\"10\"\n                                                      Data=\"F1M0,10L0,3 3,3 3,0 10,0 10,2 4,2 4,3 7,3 7,6 6,6 6,5 1,5 1,10z M1,10L7,10 7,7 10,7 10,2 9,2 9,6 6,6 6,9 1,9z\"\n                                                      SnapsToDevicePixels=\"True\"\n                                                      Fill=\"{Binding Path=Foreground, RelativeSource={RelativeSource AncestorType=Button}}\" />\n                                            </Button>\n                                            <ContentPresenter Content=\"{TemplateBinding HeaderContent}\"                                                               \n                                                              ContentTemplate=\"{TemplateBinding HeaderContentTemplate}\" \n                                                              ContentStringFormat=\"{TemplateBinding ContentControl.ContentStringFormat}\" HorizontalAlignment=\"{TemplateBinding Control.HorizontalContentAlignment}\" \n                                                              ContentTemplateSelector=\"{TemplateBinding HeaderContentTemplateSelector}\"                                                          \n                                                              SnapsToDevicePixels=\"{TemplateBinding UIElement.SnapsToDevicePixels}\"\n                                                              IsHitTestVisible=\"False\"\n                                                          />\n                                        </DockPanel>\n                                    </Grid>\n                                    <ContentPresenter Content=\"{TemplateBinding ContentControl.Content}\" ContentTemplate=\"{TemplateBinding ContentControl.ContentTemplate}\" ContentStringFormat=\"{TemplateBinding ContentControl.ContentStringFormat}\" HorizontalAlignment=\"{TemplateBinding Control.HorizontalContentAlignment}\" VerticalAlignment=\"{TemplateBinding Control.VerticalContentAlignment}\" SnapsToDevicePixels=\"{TemplateBinding UIElement.SnapsToDevicePixels}\"\n                                                      Margin=\"{TemplateBinding Control.Padding }\"/>\n                                </DockPanel>\n                            </Border>\n                            <Thumb Style=\"{StaticResource MahAppsInvisibleThumbStyle}\"\n                                   Width=\"{Binding RelativeSource={RelativeSource TemplatedParent}, Path=BorderThickness.Left}\"\n                                   IsEnabled=\"{Binding Path=(dockablz:Layout.FloatingItemState), RelativeSource={RelativeSource TemplatedParent}, Converter={StaticResource EqualityToBooleanConverter}, ConverterParameter={x:Static WindowState.Normal}}\"\n                                   dragablz:DragablzItem.SizeGrip=\"Left\"\n                                   HorizontalAlignment=\"Left\"\n                                   VerticalAlignment=\"Stretch\"\n                                   Cursor=\"SizeWE\"\n                                   />\n                            <Thumb Style=\"{StaticResource MahAppsInvisibleThumbStyle}\"\n                                   Height=\"{Binding RelativeSource={RelativeSource TemplatedParent}, Path=BorderThickness.Top}\"\n                                   IsEnabled=\"{Binding Path=(dockablz:Layout.FloatingItemState), RelativeSource={RelativeSource TemplatedParent}, Converter={StaticResource EqualityToBooleanConverter}, ConverterParameter={x:Static WindowState.Normal}}\"\n                                   dragablz:DragablzItem.SizeGrip=\"Top\"\n                                   HorizontalAlignment=\"Stretch\"\n                                   VerticalAlignment=\"Top\"\n                                   Cursor=\"SizeNS\"\n                                   />\n                            <Thumb Style=\"{StaticResource MahAppsInvisibleThumbStyle}\"\n                                   Width=\"{Binding RelativeSource={RelativeSource TemplatedParent}, Path=BorderThickness.Right}\"\n                                   IsEnabled=\"{Binding Path=(dockablz:Layout.FloatingItemState), RelativeSource={RelativeSource TemplatedParent}, Converter={StaticResource EqualityToBooleanConverter}, ConverterParameter={x:Static WindowState.Normal}}\"\n                                   dragablz:DragablzItem.SizeGrip=\"Right\"\n                                   HorizontalAlignment=\"Right\"\n                                   VerticalAlignment=\"Stretch\"\n                                   Cursor=\"SizeWE\"\n                                   />\n                            <Thumb Style=\"{StaticResource MahAppsInvisibleThumbStyle}\"\n                                   Height=\"{Binding RelativeSource={RelativeSource TemplatedParent}, Path=BorderThickness.Bottom}\"\n                                   IsEnabled=\"{Binding Path=(dockablz:Layout.FloatingItemState), RelativeSource={RelativeSource TemplatedParent}, Converter={StaticResource EqualityToBooleanConverter}, ConverterParameter={x:Static WindowState.Normal}}\"\n                                   dragablz:DragablzItem.SizeGrip=\"Bottom\"\n                                   HorizontalAlignment=\"Stretch\"\n                                   VerticalAlignment=\"Bottom\"\n                                   Cursor=\"SizeNS\"\n                                   />\n                            <Thumb Style=\"{StaticResource MahAppsInvisibleThumbStyle}\"\n                                   Width=\"{Binding RelativeSource={RelativeSource TemplatedParent}, Path=BorderThickness.Right}\"\n                                   Height=\"{Binding RelativeSource={RelativeSource TemplatedParent}, Path=BorderThickness.Bottom}\"\n                                   IsEnabled=\"{Binding Path=(dockablz:Layout.FloatingItemState), RelativeSource={RelativeSource TemplatedParent}, Converter={StaticResource EqualityToBooleanConverter}, ConverterParameter={x:Static WindowState.Normal}}\"\n                                   dragablz:DragablzItem.SizeGrip=\"TopLeft\"\n                                   HorizontalAlignment=\"Left\"\n                                   VerticalAlignment=\"Top\"\n                                   Cursor=\"SizeNWSE\"\n                                   />\n                            <Thumb Style=\"{StaticResource MahAppsInvisibleThumbStyle}\"\n                                   Width=\"{Binding RelativeSource={RelativeSource TemplatedParent}, Path=BorderThickness.Right}\"\n                                   Height=\"{Binding RelativeSource={RelativeSource TemplatedParent}, Path=BorderThickness.Bottom}\"\n                                   IsEnabled=\"{Binding Path=(dockablz:Layout.FloatingItemState), RelativeSource={RelativeSource TemplatedParent}, Converter={StaticResource EqualityToBooleanConverter}, ConverterParameter={x:Static WindowState.Normal}}\"\n                                   dragablz:DragablzItem.SizeGrip=\"TopRight\"\n                                   HorizontalAlignment=\"Right\"\n                                   VerticalAlignment=\"Top\"\n                                   Cursor=\"SizeNESW\"\n                                   />\n                            <Thumb Style=\"{StaticResource MahAppsInvisibleThumbStyle}\"\n                                   Width=\"{Binding RelativeSource={RelativeSource TemplatedParent}, Path=BorderThickness.Right}\"\n                                   Height=\"{Binding RelativeSource={RelativeSource TemplatedParent}, Path=BorderThickness.Bottom}\"\n                                   IsEnabled=\"{Binding Path=(dockablz:Layout.FloatingItemState), RelativeSource={RelativeSource TemplatedParent}, Converter={StaticResource EqualityToBooleanConverter}, ConverterParameter={x:Static WindowState.Normal}}\"\n                                   dragablz:DragablzItem.SizeGrip=\"BottomRight\"\n                                   HorizontalAlignment=\"Right\"\n                                   VerticalAlignment=\"Bottom\"\n                                   Cursor=\"SizeNWSE\"\n                                   />\n                            <Thumb Style=\"{StaticResource MahAppsInvisibleThumbStyle}\"\n                                   Width=\"{Binding RelativeSource={RelativeSource TemplatedParent}, Path=BorderThickness.Right}\"\n                                   Height=\"{Binding RelativeSource={RelativeSource TemplatedParent}, Path=BorderThickness.Bottom}\"\n                                   IsEnabled=\"{Binding Path=(dockablz:Layout.FloatingItemState), RelativeSource={RelativeSource TemplatedParent}, Converter={StaticResource EqualityToBooleanConverter}, ConverterParameter={x:Static WindowState.Normal}}\"\n                                   dragablz:DragablzItem.SizeGrip=\"BottomLeft\"                                   \n                                   HorizontalAlignment=\"Left\"\n                                   VerticalAlignment=\"Bottom\"\n                                   Cursor=\"SizeNESW\"\n                                   />\n                        </Grid>\n                    </ControlTemplate>\n                </Setter.Value>\n            </Setter>\n        </Style.Setters>\n        <Style.Triggers>\n            <Trigger Property=\"dockablz:Layout.FloatingItemState\" Value=\"Maximized\">\n                <Setter Property=\"BorderThickness\" Value=\"1\" />\n                <Setter Property=\"Canvas.Left\" Value=\"0\" />\n                <Setter Property=\"Canvas.Top\" Value=\"0\" />\n                <Setter Property=\"Width\" Value=\"{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type dockablz:Layout}}, Path=ActualWidth}\" />\n                <Setter Property=\"Height\" Value=\"{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type dockablz:Layout}}, Path=ActualHeight}\" />\n            </Trigger>\n        </Style.Triggers>\n    </Style>    \n\n    <Style TargetType=\"{x:Type dragablz:TabablzControl}\" x:Key=\"MahAppsTabablzControlStyle\">\n        <Setter Property=\"Background\" Value=\"{DynamicResource WhiteColorBrush}\"/>\n        <Setter Property=\"BorderBrush\" Value=\"{DynamicResource AccentColorBrush}\"/>\n        <Setter Property=\"Foreground\" Value=\"{DynamicResource BlackColorBrush}\"/>\n        <Setter Property=\"AdjacentHeaderItemOffset\" Value=\"-12\" />\n        <Setter Property=\"ItemContainerStyle\" Value=\"{StaticResource MahAppsTrapezoidDragableTabItemStyle}\" />        \n    </Style>\n\n</ResourceDictionary>"
  },
  {
    "path": "third_party/Dragablz/Dragablz/Themes/MaterialDesign.xaml",
    "content": "﻿<ResourceDictionary xmlns=\"http://schemas.microsoft.com/winfx/2006/xaml/presentation\"\n                    xmlns:x=\"http://schemas.microsoft.com/winfx/2006/xaml\"\n                    xmlns:dragablz=\"clr-namespace:Dragablz\"\n                    xmlns:dockablz=\"clr-namespace:Dragablz.Dockablz\"\n                    xmlns:converters=\"clr-namespace:Dragablz.Converters\"\n                    xmlns:local=\"clr-namespace:Dragablz.Themes\">\n\n    <BooleanToVisibilityConverter x:Key=\"BooleanToVisibilityConverter\" />\n    <converters:EqualityToVisibilityConverter x:Key=\"EqualityToVisibilityConverter\" />\n    <converters:BooleanAndToVisibilityConverter x:Key=\"BooleanAndToVisibilityConverter\" />\n    <converters:EqualityToBooleanConverter x:Key=\"EqualityToBooleanConverter\" />\n    <converters:ShowDefaultCloseButtonConverter x:Key=\"ShowDefaultCloseButtonConverter\" />\n    <local:BrushToRadialGradientBrushConverter x:Key=\"BrushToRadialGradientBrushConverter\" />    \n\n    <Style x:Key=\"MaterialDesignFocusVisual\">\n        <Setter Property=\"Control.Template\">\n            <Setter.Value>\n                <ControlTemplate>\n                    <Rectangle Margin=\"2\" SnapsToDevicePixels=\"true\" Stroke=\"{DynamicResource {x:Static SystemColors.ControlTextBrushKey}}\" StrokeThickness=\"1\" StrokeDashArray=\"1 2\"/>\n                </ControlTemplate>\n            </Setter.Value>\n        </Setter>\n    </Style>\n\n    <Style TargetType=\"{x:Type Thumb}\" x:Key=\"MaterialDesignInvisibleThumbStyle\">\n        <Setter Property=\"Background\" Value=\"Transparent\" />\n        <Setter Property=\"Template\">\n            <Setter.Value>\n                <ControlTemplate>\n                    <Grid Background=\"{TemplateBinding Background}\" />\n                </ControlTemplate>\n            </Setter.Value>\n        </Setter>\n    </Style>\n\n    <Style TargetType=\"{x:Type Button}\" x:Key=\"MaterialDesignMenuCommandButtonStyle\">\n        <Setter Property=\"FocusVisualStyle\" Value=\"{StaticResource MaterialDesignFocusVisual}\"/>\n        <Setter Property=\"Background\" Value=\"Transparent\"/>\n        <Setter Property=\"BorderBrush\" Value=\"Transparent\"/>\n        <Setter Property=\"Foreground\" Value=\"{DynamicResource {x:Static SystemColors.ControlTextBrushKey}}\"/>\n        <Setter Property=\"BorderThickness\" Value=\"0\"/>\n        <Setter Property=\"HorizontalContentAlignment\" Value=\"Center\"/>\n        <Setter Property=\"VerticalContentAlignment\" Value=\"Center\"/>\n        <Setter Property=\"Padding\" Value=\"1\"/>\n        <Setter Property=\"Opacity\" Value=\".8\"/>\n        <Setter Property=\"Width\" Value=\"24\"/>\n        <Setter Property=\"Height\" Value=\"20\"/>\n        <Setter Property=\"Template\">\n            <Setter.Value>\n                <ControlTemplate TargetType=\"{x:Type Button}\">\n                    <Border x:Name=\"border\" BorderBrush=\"{TemplateBinding BorderBrush}\" BorderThickness=\"{TemplateBinding BorderThickness}\" Background=\"{TemplateBinding Background}\" SnapsToDevicePixels=\"true\">\n                        <ContentPresenter x:Name=\"contentPresenter\" Focusable=\"False\" HorizontalAlignment=\"{TemplateBinding HorizontalContentAlignment}\" Margin=\"{TemplateBinding Padding}\" RecognizesAccessKey=\"True\" SnapsToDevicePixels=\"{TemplateBinding SnapsToDevicePixels}\" VerticalAlignment=\"{TemplateBinding VerticalContentAlignment}\"/>\n                    </Border>\n                    <ControlTemplate.Triggers>\n                        <Trigger Property=\"IsDefaulted\" Value=\"true\">\n                            <Setter Property=\"BorderBrush\" TargetName=\"border\" Value=\"{DynamicResource {x:Static SystemColors.HighlightBrushKey}}\"/>\n                        </Trigger>\n                        <Trigger Property=\"IsEnabled\" Value=\"false\">\n                            <Setter Property=\"Opacity\" TargetName=\"border\" Value=\".5\"/>\n                        </Trigger>\n                    </ControlTemplate.Triggers>\n                </ControlTemplate>\n            </Setter.Value>\n        </Setter>\n        <Style.Triggers>\n            <Trigger Property=\"IsMouseOver\" Value=\"true\">\n                <Setter Property=\"Background\" Value=\"{x:Static dragablz:DragablzColors.WindowGlassBrush}\"/>\n                <Setter Property=\"Foreground\" Value=\"{x:Static SystemColors.HighlightTextBrush}\" />\n            </Trigger>\n            <Trigger Property=\"IsPressed\" Value=\"true\">\n                <Setter Property=\"Opacity\" Value=\"1\"/>\n            </Trigger>\n        </Style.Triggers>\n    </Style>\n\n    <Style TargetType=\"{x:Type Button}\" x:Key=\"MaterialDesignCloseItemCommandButtonStyle\" BasedOn=\"{StaticResource MaterialDesignMenuCommandButtonStyle}\">\n        <Setter Property=\"Template\">\n            <Setter.Value>\n                <ControlTemplate>\n                    <Grid>\n                        <Ellipse Width=\"{TemplateBinding Width}\"\n                                 Height=\"{TemplateBinding Height}\"\n                                 Fill=\"{TemplateBinding Background}\"/>\n                        <Path x:Name=\"Path\"\n                              Data=\"M0.5,71 L70,0.5 M0.5,1 L70,70.5\" \n                              Width=\"6\" Height=\"6\"\n                              Stretch=\"Uniform\"\n                              Stroke=\"{TemplateBinding Foreground}\"\n                              StrokeThickness=\"1.5\"\n                              StrokeStartLineCap=\"Square\" \n                              StrokeEndLineCap=\"Square\"\n                              SnapsToDevicePixels=\"True\" />\n                    </Grid>\n                </ControlTemplate>\n            </Setter.Value>\n        </Setter>\n        <Setter Property=\"Background\" Value=\"{DynamicResource PrimaryHueMidBrush}\" />\n        <Setter Property=\"Width\" Value=\"12\" />\n        <Setter Property=\"Height\" Value=\"12\" />\n        <Setter Property=\"Margin\" Value=\"4 0 2 0\" />\n        <Setter Property=\"Opacity\" Value=\".75\" />\n        <Setter Property=\"Foreground\" Value=\"{DynamicResource PrimaryHueMidForegroundBrush}\" />\n        <Style.Triggers>\n            <Trigger Property=\"IsMouseOver\" Value=\"true\">\n                <Setter Property=\"Background\" Value=\"{DynamicResource PrimaryHueLightBrush}\"/>\n                <Setter Property=\"Foreground\" Value=\"{DynamicResource PrimaryHueLightForegroundBrush}\" />\n            </Trigger>\n        </Style.Triggers>\n    </Style>\n\n    <Style TargetType=\"{x:Type Button}\" x:Key=\"MaterialDesignAddItemCommandButtonStyle\" BasedOn=\"{StaticResource MaterialDesignMenuCommandButtonStyle}\">\n        <Setter Property=\"Template\">\n            <Setter.Value>\n                <ControlTemplate>\n                    <Grid>\n                        <Ellipse Width=\"{TemplateBinding Width}\"\n                                 Height=\"{TemplateBinding Height}\"\n                                 Fill=\"{TemplateBinding Background}\"/>\n                        <Path x:Name=\"Path\"\n                              Data=\"M38,6L38.0003451911513,70.6666666666666 M70.3336667356886,38L5.50002465137562,38\" \n                              Width=\"6\" Height=\"6\"\n                              Stretch=\"Uniform\"\n                              Stroke=\"{TemplateBinding Foreground}\"\n                              StrokeThickness=\"1.5\"\n                              StrokeStartLineCap=\"Square\" \n                              StrokeEndLineCap=\"Square\"\n                              SnapsToDevicePixels=\"True\" />\n                    </Grid>\n                </ControlTemplate>\n            </Setter.Value>\n        </Setter>\n        <Setter Property=\"Background\" Value=\"{DynamicResource PrimaryHueMidBrush}\" />\n        <Setter Property=\"Width\" Value=\"12\" />\n        <Setter Property=\"Height\" Value=\"12\" />\n        <Setter Property=\"Margin\" Value=\"4 0 2 0\" />\n        <Setter Property=\"Foreground\" Value=\"{DynamicResource PrimaryHueMidForegroundBrush}\" />\n        <Style.Triggers>\n            <Trigger Property=\"IsMouseOver\" Value=\"true\">\n                <Setter Property=\"Background\" Value=\"{DynamicResource PrimaryHueLightBrush}\"/>\n                <Setter Property=\"Foreground\" Value=\"{DynamicResource PrimaryHueLightForegroundBrush}\" />\n            </Trigger>\n        </Style.Triggers>\n    </Style>\n\n    \n    \n    <Style x:Key=\"MaterialDesignDragableTabItemStyle\"  TargetType=\"{x:Type dragablz:DragablzItem}\">\n        <Setter Property=\"FocusVisualStyle\" Value=\"{StaticResource MaterialDesignFocusVisual}\"/>\n        <Setter Property=\"Foreground\" Value=\"{DynamicResource PrimaryHueMidForegroundBrush}\"/>\n        <Setter Property=\"Background\" Value=\"Transparent\"/>\n        <Setter Property=\"BorderBrush\" Value=\"Transparent\"/>\n        <Setter Property=\"local:MaterialDesignAssist.IndicatorBrush\" Value=\"{DynamicResource SecondaryAccentBrush}\" />\n        <Setter Property=\"Margin\" Value=\"0 0 0 0\"/>\n        <Setter Property=\"Padding\" Value=\"8\"/>\n        <Setter Property=\"MinWidth\" Value=\"80\" />\n        <Setter Property=\"Height\" Value=\"40\" />\n        <Setter Property=\"HorizontalContentAlignment\" Value=\"Center\"/>\n        <Setter Property=\"VerticalContentAlignment\" Value=\"Center\"/>\n        <Setter Property=\"TextBlock.FontWeight\" Value=\"Medium\" />\n        <Setter Property=\"Template\">\n            <Setter.Value>\n                <ControlTemplate TargetType=\"{x:Type dragablz:DragablzItem}\">\n                    <Grid x:Name=\"templateRoot\" SnapsToDevicePixels=\"true\">\n                        <Grid.RowDefinitions>\n                            <RowDefinition Height=\"*\" />\n                            <RowDefinition Height=\"Auto\" />\n                        </Grid.RowDefinitions>\n                        <Border BorderBrush=\"{TemplateBinding BorderBrush}\" \n                                Background=\"{TemplateBinding Background}\"                                          \n                                Margin=\"0 0 0 0\">\n                            <local:Ripple HorizontalContentAlignment=\"Stretch\" VerticalAlignment=\"Stretch\">\n                                <Grid>\n                                    <Grid.ColumnDefinitions>\n                                        <ColumnDefinition Width=\"*\" />\n                                        <ColumnDefinition Width=\"Auto\" />\n                                    </Grid.ColumnDefinitions>\n                                    <ContentPresenter Content=\"{TemplateBinding ContentControl.Content}\" ContentTemplate=\"{TemplateBinding ContentControl.ContentTemplate}\" ContentStringFormat=\"{TemplateBinding ContentControl.ContentStringFormat}\" HorizontalAlignment=\"{TemplateBinding Control.HorizontalContentAlignment}\" VerticalAlignment=\"{TemplateBinding Control.VerticalContentAlignment}\" SnapsToDevicePixels=\"{TemplateBinding UIElement.SnapsToDevicePixels}\"\n                                                      x:Name=\"contentPresenter\"                                                                                            \n                                                      Margin=\"{TemplateBinding Control.Padding}\"\n                                                      Opacity=\".87\"/>\n                                    <Thumb Grid.Column=\"0\" HorizontalAlignment=\"Stretch\" VerticalContentAlignment=\"Stretch\" \n                                           x:Name=\"PART_Thumb\"\n                                           Style=\"{StaticResource MaterialDesignInvisibleThumbStyle}\" />\n                                    <Button Grid.Column=\"1\"\n                                            Style=\"{StaticResource MaterialDesignCloseItemCommandButtonStyle}\"                                            \n                                            Command=\"{x:Static dragablz:TabablzControl.CloseItemCommand}\"\n                                            CommandParameter=\"{Binding RelativeSource={RelativeSource TemplatedParent}}\">\n                                        <Button.Visibility>\n                                            <MultiBinding Converter=\"{StaticResource ShowDefaultCloseButtonConverter}\">\n                                                <Binding RelativeSource=\"{RelativeSource FindAncestor, AncestorType={x:Type dragablz:TabablzControl}}\" Path=\"ShowDefaultCloseButton\" />\n                                                <Binding RelativeSource=\"{RelativeSource FindAncestor, AncestorType={x:Type dragablz:TabablzControl}}\" Path=\"FixedHeaderCount\" />\n                                                <Binding RelativeSource=\"{RelativeSource TemplatedParent}\" Path=\"LogicalIndex\" />\n                                            </MultiBinding>\n                                        </Button.Visibility>\n                                    </Button>\n                                </Grid>\n                            </local:Ripple>\n                        </Border>\n                        <Border x:Name=\"SelectionHighlightBorder\" Background=\"{Binding RelativeSource={RelativeSource TemplatedParent}, Path=(local:MaterialDesignAssist.IndicatorBrush)}\" Height=\"2\"\n                                Grid.Row=\"1\"\n                                Visibility=\"Hidden\"/>\n                    </Grid>\n                    <ControlTemplate.Triggers>\n                        <Trigger Property=\"dragablz:TabablzControl.IsWrappingTabItem\" Value=\"True\">\n                            <Setter TargetName=\"contentPresenter\" Property=\"Content\" Value=\"{Binding RelativeSource={RelativeSource TemplatedParent}, Path=DataContext.Header}\" />\n                        </Trigger>\n                        <Trigger Property=\"IsSelected\" Value=\"True\">\n                            <Setter TargetName=\"contentPresenter\" Property=\"Opacity\" Value=\"1\"/>\n                            <Setter TargetName=\"SelectionHighlightBorder\" Property=\"Visibility\" Value=\"Visible\" />\n                        </Trigger>                        \n                    </ControlTemplate.Triggers>\n                </ControlTemplate>\n            </Setter.Value>\n        </Setter>\n    </Style>\n\n    <Style x:Key=\"MaterialDesignDragableTabItemVerticalStyle\" TargetType=\"{x:Type dragablz:DragablzItem}\">\n        <Setter Property=\"FocusVisualStyle\" Value=\"{StaticResource MaterialDesignFocusVisual}\"/>\n        <Setter Property=\"Foreground\" Value=\"{DynamicResource PrimaryHueMidForegroundBrush}\"/>\n        <Setter Property=\"Background\" Value=\"Transparent\"/>\n        <Setter Property=\"BorderBrush\" Value=\"Transparent\"/>\n        <Setter Property=\"Margin\" Value=\"0 0 0 0\"/>\n        <Setter Property=\"Width\" Value=\"80\" />\n        <Setter Property=\"MinHeight\" Value=\"40\" />\n        <Setter Property=\"HorizontalContentAlignment\" Value=\"Center\"/>\n        <Setter Property=\"VerticalContentAlignment\" Value=\"Center\"/>\n        <Setter Property=\"TextBlock.FontWeight\" Value=\"Medium\" />\n        <Setter Property=\"Template\">\n            <Setter.Value>\n                <ControlTemplate TargetType=\"{x:Type dragablz:DragablzItem}\">\n                    <Grid x:Name=\"templateRoot\" SnapsToDevicePixels=\"true\">\n                        <Grid.ColumnDefinitions>\n                            <ColumnDefinition Width=\"*\" />\n                            <ColumnDefinition Width=\"Auto\" />\n                        </Grid.ColumnDefinitions>\n                        <Border BorderBrush=\"{TemplateBinding BorderBrush}\" \n                                Background=\"{TemplateBinding Background}\"                                          \n                                Margin=\"0 0 0 0\">\n                            <local:Ripple HorizontalContentAlignment=\"Stretch\" VerticalAlignment=\"Stretch\">\n                                <Grid>\n                                    <Grid.RowDefinitions>\n                                        <RowDefinition Height=\"*\" />\n                                        <RowDefinition Height=\"Auto\" />\n                                    </Grid.RowDefinitions>\n                                    <ContentPresenter Content=\"{TemplateBinding ContentControl.Content}\" ContentTemplate=\"{TemplateBinding ContentControl.ContentTemplate}\" ContentStringFormat=\"{TemplateBinding ContentControl.ContentStringFormat}\" HorizontalAlignment=\"{TemplateBinding Control.HorizontalContentAlignment}\" VerticalAlignment=\"{TemplateBinding Control.VerticalContentAlignment}\" SnapsToDevicePixels=\"{TemplateBinding UIElement.SnapsToDevicePixels}\"\n                                                      x:Name=\"contentPresenter\"\n                                                      RenderTransformOrigin=\".5, .5\">\n                                        <ContentPresenter.RenderTransform>\n                                            <RotateTransform Angle=\"{Binding RelativeSource={RelativeSource TemplatedParent}, Path=(dragablz:DragablzItem.ContentRotateTransformAngle)}\" />\n                                        </ContentPresenter.RenderTransform>\n                                    </ContentPresenter>\n                                    <Thumb Grid.Row=\"0\" HorizontalAlignment=\"Stretch\" VerticalContentAlignment=\"Stretch\" \n                                           x:Name=\"PART_Thumb\"\n                                           Style=\"{StaticResource MaterialDesignInvisibleThumbStyle}\" />\n                                    <Button Grid.Row=\"1\"\n                                            Style=\"{StaticResource MaterialDesignCloseItemCommandButtonStyle}\"                                        \n                                            Command=\"{x:Static dragablz:TabablzControl.CloseItemCommand}\"\n                                            CommandParameter=\"{Binding RelativeSource={RelativeSource TemplatedParent}}\">\n                                        <Button.Visibility>\n                                            <MultiBinding Converter=\"{StaticResource ShowDefaultCloseButtonConverter}\">\n                                                <Binding RelativeSource=\"{RelativeSource FindAncestor, AncestorType={x:Type dragablz:TabablzControl}}\" Path=\"ShowDefaultCloseButton\" />\n                                                <Binding RelativeSource=\"{RelativeSource FindAncestor, AncestorType={x:Type dragablz:TabablzControl}}\" Path=\"FixedHeaderCount\" />\n                                                <Binding RelativeSource=\"{RelativeSource TemplatedParent}\" Path=\"LogicalIndex\" />\n                                            </MultiBinding>\n                                        </Button.Visibility>\n                                    </Button>\n                                </Grid>\n                            </local:Ripple>\n                        </Border>\n                        <Border x:Name=\"SelectionHighlightBorder\" Background=\"{DynamicResource SecondaryAccentBrush}\" Width=\"2\"\n                                Grid.Column=\"1\"\n                                Visibility=\"Hidden\"/>\n                    </Grid>\n                    <ControlTemplate.Triggers>\n                        <Trigger Property=\"dragablz:TabablzControl.IsWrappingTabItem\" Value=\"True\">\n                            <Setter TargetName=\"contentPresenter\" Property=\"Content\" Value=\"{Binding RelativeSource={RelativeSource TemplatedParent}, Path=DataContext.Header}\" />\n                        </Trigger>\n                        <Trigger Property=\"IsSelected\" Value=\"True\">\n                            <Setter TargetName=\"contentPresenter\" Property=\"Opacity\" Value=\"1\"/>\n                            <Setter TargetName=\"SelectionHighlightBorder\" Property=\"Visibility\" Value=\"Visible\" />\n                        </Trigger>\n                    </ControlTemplate.Triggers>\n                </ControlTemplate>\n            </Setter.Value>\n        </Setter>\n    </Style>\n\n    <Style x:Key=\"MaterialDesignMetroBaseWindowButtonStyle\" TargetType=\"{x:Type Button}\">\n        <Setter Property=\"Background\" Value=\"{DynamicResource TransparentWhiteBrush}\" />\n        <Setter Property=\"Foreground\" Value=\"{DynamicResource WhiteColorBrush}\" />\n        <Setter Property=\"HorizontalContentAlignment\" Value=\"Center\" />\n        <Setter Property=\"VerticalContentAlignment\" Value=\"Center\" />\n        <Setter Property=\"Padding\" Value=\"1\" />\n        <Setter Property=\"Template\">\n            <Setter.Value>\n                <ControlTemplate TargetType=\"{x:Type Button}\">\n                    <Grid Background=\"{TemplateBinding Background}\">\n                        <ContentPresenter x:Name=\"contentPresenter\"\n                                          HorizontalAlignment=\"{TemplateBinding HorizontalContentAlignment}\"\n                                          Margin=\"{TemplateBinding Padding}\"\n                                          VerticalAlignment=\"{TemplateBinding VerticalContentAlignment}\"\n                                          SnapsToDevicePixels=\"{TemplateBinding SnapsToDevicePixels}\"\n                                          RecognizesAccessKey=\"True\"\n                                          Opacity=\"0.75\" />\n                    </Grid>\n                    <ControlTemplate.Triggers>\n                        <Trigger Property=\"IsMouseOver\" Value=\"True\">\n                            <Setter TargetName=\"contentPresenter\" Property=\"Opacity\" Value=\"1\" />\n                        </Trigger>\n                        <Trigger Property=\"IsMouseOver\" Value=\"False\">\n                            <Setter TargetName=\"contentPresenter\" Property=\"Opacity\" Value=\".5\" />\n                        </Trigger>\n                    </ControlTemplate.Triggers>\n                </ControlTemplate>\n            </Setter.Value>\n        </Setter>\n        <Style.Triggers>\n            <Trigger Property=\"IsMouseOver\" Value=\"True\">\n                <Setter Property=\"Background\" Value=\"{DynamicResource SemiTransparentWhiteBrush}\" />\n            </Trigger>\n            <Trigger Property=\"IsPressed\" Value=\"True\">\n                <Setter Property=\"Background\" Value=\"{DynamicResource HighlightBrush}\" />\n                <Setter Property=\"Foreground\" Value=\"White\" />\n            </Trigger>\n            <Trigger Property=\"IsEnabled\" Value=\"false\">\n                <Setter Property=\"Foreground\" Value=\"#ADADAD\" />\n            </Trigger>\n        </Style.Triggers>\n    </Style>\n\n    <Style x:Key=\"MaterialDesignToolWindowButtonStyle\" TargetType=\"{x:Type Button}\" BasedOn=\"{StaticResource MaterialDesignMetroBaseWindowButtonStyle}\">\n        <Setter Property=\"FocusVisualStyle\" Value=\"{x:Null}\" />\n        <Setter Property=\"IsTabStop\" Value=\"False\" />\n        <Setter Property=\"Width\" Value=\"30\" />\n        <Setter Property=\"MaxHeight\" Value=\"30\" />\n        <Setter Property=\"Padding\" Value=\"0\" />\n        <Style.Triggers>\n            <Trigger Property=\"IsEnabled\" Value=\"False\">\n                <Setter Property=\"Visibility\" Value=\"Collapsed\" />\n            </Trigger>\n        </Style.Triggers>\n    </Style>\n\n    <Style TargetType=\"{x:Type dragablz:HeaderedDragablzItem}\" x:Key=\"MaterialDesignToolDragablzItemStyle\">\n        <Style.Setters>\n            <Setter Property=\"BorderBrush\" Value=\"{DynamicResource AccentColorBrush2}\" />\n            <Setter Property=\"BorderThickness\" Value=\"4\" />\n            <Setter Property=\"Canvas.Left\" Value=\"{Binding X, RelativeSource={RelativeSource Self}}\" />\n            <Setter Property=\"Canvas.Top\" Value=\"{Binding Y, RelativeSource={RelativeSource Self}}\" />\n            <Setter Property=\"Template\">\n                <Setter.Value>\n                    <ControlTemplate TargetType=\"{x:Type dragablz:HeaderedDragablzItem}\">\n                        <Grid Margin=\"{TemplateBinding Margin}\">\n                            <Border Background=\"{DynamicResource WhiteColorBrush}\">\n                                <Border.Effect>\n                                    <DropShadowEffect BlurRadius=\"10\" ShadowDepth=\"5\" Direction=\"315\" Color=\"{DynamicResource AccentColor2}\" Opacity=\".5\" />\n                                </Border.Effect>\n                            </Border>\n                            <Border BorderThickness=\"{TemplateBinding Border.BorderThickness}\" Padding=\"{TemplateBinding Control.Padding}\" BorderBrush=\"{TemplateBinding Border.BorderBrush}\" Background=\"{TemplateBinding Panel.Background}\" SnapsToDevicePixels=\"True\">\n                                <DockPanel>\n                                    <Grid DockPanel.Dock=\"Top\" Background=\"{TemplateBinding BorderBrush}\">\n                                        <Thumb HorizontalAlignment=\"Stretch\" VerticalContentAlignment=\"Stretch\" x:Name=\"PART_Thumb\"\n                                               Style=\"{StaticResource MaterialDesignInvisibleThumbStyle}\"\n                                               />\n                                        <DockPanel Margin=\"{TemplateBinding Control.Padding }\">\n                                            <Button DockPanel.Dock=\"Right\"\n                                                    Command=\"{x:Static dockablz:Layout.CloseFloatingItem}\"\n                                                    CommandParameter=\"{Binding RelativeSource={RelativeSource TemplatedParent}}\"\n                                                    Margin=\"1 0 0 0\"\n                                                    Style=\"{DynamicResource MaterialDesignToolWindowButtonStyle}\"\n                                                    Focusable=\"False\"\n                                                    RenderOptions.EdgeMode=\"Aliased\"\n                                                    >\n                                                <Path Data=\"M 10.009,1.704 L 8.331,0.026 5.03,3.327 1.703,0 0,1.704 3.326,5.031 0.025,8.332 1.703,10.009 5.004,6.708 8.305,10.009 10.009,8.305 6.708,5.005\"\n                                                      SnapsToDevicePixels=\"True\"\n                                                      Fill=\"{Binding Path=Foreground, RelativeSource={RelativeSource AncestorType=Button}}\" />\n                                            </Button>\n                                            <Button DockPanel.Dock=\"Right\"\n                                                    Command=\"{x:Static dockablz:Layout.UnfloatItemCommand}\"\n                                                    CommandParameter=\"{Binding RelativeSource={RelativeSource TemplatedParent}}\"\n                                                    Margin=\"1 0 0 0\"\n                                                    Style=\"{DynamicResource MaterialDesignToolWindowButtonStyle}\"\n                                                    >\n                                                <Path Width=\"12\" Height=\"12\" Stretch=\"UniformToFill\" Fill=\"{Binding Path=Foreground, RelativeSource={RelativeSource AncestorType=Button}}\" Data=\"M 19 19 H 5 V 5 h 7 V 3 H 5 C 3.89 3 3 3.9 3 5 v 14 c 0 1.1 0.89 2 2 2 h 14 c 1.1 0 2 -0.9 2 -2 v -7 h -2 v 7 z M 14 3 v 2 h 3.59 L 7.76 14.83 9.17 16.24 19 6.41 V 10 h 2 V 3 h -7 z\" />\n                                            </Button>\n                                            <Button DockPanel.Dock=\"Right\"\n                                                    Command=\"{x:Static dockablz:Layout.MaximiseFloatingItem}\"\n                                                    CommandParameter=\"{Binding RelativeSource={RelativeSource TemplatedParent}}\"\n                                                    Margin=\"1 0 0 0\"\n                                                    Style=\"{DynamicResource MaterialDesignToolWindowButtonStyle}\"\n                                                    >\n                                                <Path Width=\"10\"\n                                                      Height=\"10\"\n                                                      Data=\"F1M0,0L0,9 9,9 9,0 0,0 0,3 8,3 8,8 1,8 1,3z\"\n                                                      SnapsToDevicePixels=\"True\"\n                                                      Fill=\"{Binding Path=Foreground, RelativeSource={RelativeSource AncestorType=Button}}\" />\n                                            </Button>\n                                            <Button DockPanel.Dock=\"Right\"\n                                                    Command=\"{x:Static dockablz:Layout.RestoreFloatingItem}\"\n                                                    CommandParameter=\"{Binding RelativeSource={RelativeSource TemplatedParent}}\"\n                                                    Margin=\"1 0 0 0\"\n                                                    Style=\"{DynamicResource MaterialDesignToolWindowButtonStyle}\"\n                                                    >\n                                                <Path Width=\"10\"\n                                                      Height=\"10\"\n                                                      Data=\"F1M0,10L0,3 3,3 3,0 10,0 10,2 4,2 4,3 7,3 7,6 6,6 6,5 1,5 1,10z M1,10L7,10 7,7 10,7 10,2 9,2 9,6 6,6 6,9 1,9z\"\n                                                      SnapsToDevicePixels=\"True\"\n                                                      Fill=\"{Binding Path=Foreground, RelativeSource={RelativeSource AncestorType=Button}}\" />\n                                            </Button>\n                                            <ContentPresenter Content=\"{TemplateBinding HeaderContent}\"                                                               \n                                                              ContentTemplate=\"{TemplateBinding HeaderContentTemplate}\" \n                                                              ContentStringFormat=\"{TemplateBinding ContentControl.ContentStringFormat}\" HorizontalAlignment=\"{TemplateBinding Control.HorizontalContentAlignment}\" \n                                                              ContentTemplateSelector=\"{TemplateBinding HeaderContentTemplateSelector}\"                                                          \n                                                              SnapsToDevicePixels=\"{TemplateBinding UIElement.SnapsToDevicePixels}\"\n                                                              IsHitTestVisible=\"False\"\n                                                          />\n                                        </DockPanel>\n                                    </Grid>\n                                    <ContentPresenter Content=\"{TemplateBinding ContentControl.Content}\" ContentTemplate=\"{TemplateBinding ContentControl.ContentTemplate}\" ContentStringFormat=\"{TemplateBinding ContentControl.ContentStringFormat}\" HorizontalAlignment=\"{TemplateBinding Control.HorizontalContentAlignment}\" VerticalAlignment=\"{TemplateBinding Control.VerticalContentAlignment}\" SnapsToDevicePixels=\"{TemplateBinding UIElement.SnapsToDevicePixels}\"\n                                                      Margin=\"{TemplateBinding Control.Padding }\"/>\n                                </DockPanel>\n                            </Border>\n                            <Thumb Style=\"{StaticResource MaterialDesignInvisibleThumbStyle}\"\n                                   Width=\"{Binding RelativeSource={RelativeSource TemplatedParent}, Path=BorderThickness.Left}\"\n                                   IsEnabled=\"{Binding Path=(dockablz:Layout.FloatingItemState), RelativeSource={RelativeSource TemplatedParent}, Converter={StaticResource EqualityToBooleanConverter}, ConverterParameter={x:Static WindowState.Normal}}\"\n                                   dragablz:DragablzItem.SizeGrip=\"Left\"\n                                   HorizontalAlignment=\"Left\"\n                                   VerticalAlignment=\"Stretch\"\n                                   Cursor=\"SizeWE\"\n                                   />\n                            <Thumb Style=\"{StaticResource MaterialDesignInvisibleThumbStyle}\"\n                                   Height=\"{Binding RelativeSource={RelativeSource TemplatedParent}, Path=BorderThickness.Top}\"\n                                   IsEnabled=\"{Binding Path=(dockablz:Layout.FloatingItemState), RelativeSource={RelativeSource TemplatedParent}, Converter={StaticResource EqualityToBooleanConverter}, ConverterParameter={x:Static WindowState.Normal}}\"\n                                   dragablz:DragablzItem.SizeGrip=\"Top\"\n                                   HorizontalAlignment=\"Stretch\"\n                                   VerticalAlignment=\"Top\"\n                                   Cursor=\"SizeNS\"\n                                   />\n                            <Thumb Style=\"{StaticResource MaterialDesignInvisibleThumbStyle}\"\n                                   Width=\"{Binding RelativeSource={RelativeSource TemplatedParent}, Path=BorderThickness.Right}\"\n                                   IsEnabled=\"{Binding Path=(dockablz:Layout.FloatingItemState), RelativeSource={RelativeSource TemplatedParent}, Converter={StaticResource EqualityToBooleanConverter}, ConverterParameter={x:Static WindowState.Normal}}\"\n                                   dragablz:DragablzItem.SizeGrip=\"Right\"\n                                   HorizontalAlignment=\"Right\"\n                                   VerticalAlignment=\"Stretch\"\n                                   Cursor=\"SizeWE\"\n                                   />\n                            <Thumb Style=\"{StaticResource MaterialDesignInvisibleThumbStyle}\"\n                                   Height=\"{Binding RelativeSource={RelativeSource TemplatedParent}, Path=BorderThickness.Bottom}\"\n                                   IsEnabled=\"{Binding Path=(dockablz:Layout.FloatingItemState), RelativeSource={RelativeSource TemplatedParent}, Converter={StaticResource EqualityToBooleanConverter}, ConverterParameter={x:Static WindowState.Normal}}\"\n                                   dragablz:DragablzItem.SizeGrip=\"Bottom\"\n                                   HorizontalAlignment=\"Stretch\"\n                                   VerticalAlignment=\"Bottom\"\n                                   Cursor=\"SizeNS\"\n                                   />\n                            <Thumb Style=\"{StaticResource MaterialDesignInvisibleThumbStyle}\"\n                                   Width=\"{Binding RelativeSource={RelativeSource TemplatedParent}, Path=BorderThickness.Right}\"\n                                   Height=\"{Binding RelativeSource={RelativeSource TemplatedParent}, Path=BorderThickness.Bottom}\"\n                                   IsEnabled=\"{Binding Path=(dockablz:Layout.FloatingItemState), RelativeSource={RelativeSource TemplatedParent}, Converter={StaticResource EqualityToBooleanConverter}, ConverterParameter={x:Static WindowState.Normal}}\"\n                                   dragablz:DragablzItem.SizeGrip=\"TopLeft\"\n                                   HorizontalAlignment=\"Left\"\n                                   VerticalAlignment=\"Top\"\n                                   Cursor=\"SizeNWSE\"\n                                   />\n                            <Thumb Style=\"{StaticResource MaterialDesignInvisibleThumbStyle}\"\n                                   Width=\"{Binding RelativeSource={RelativeSource TemplatedParent}, Path=BorderThickness.Right}\"\n                                   Height=\"{Binding RelativeSource={RelativeSource TemplatedParent}, Path=BorderThickness.Bottom}\"\n                                   IsEnabled=\"{Binding Path=(dockablz:Layout.FloatingItemState), RelativeSource={RelativeSource TemplatedParent}, Converter={StaticResource EqualityToBooleanConverter}, ConverterParameter={x:Static WindowState.Normal}}\"\n                                   dragablz:DragablzItem.SizeGrip=\"TopRight\"\n                                   HorizontalAlignment=\"Right\"\n                                   VerticalAlignment=\"Top\"\n                                   Cursor=\"SizeNESW\"\n                                   />\n                            <Thumb Style=\"{StaticResource MaterialDesignInvisibleThumbStyle}\"\n                                   Width=\"{Binding RelativeSource={RelativeSource TemplatedParent}, Path=BorderThickness.Right}\"\n                                   Height=\"{Binding RelativeSource={RelativeSource TemplatedParent}, Path=BorderThickness.Bottom}\"\n                                   IsEnabled=\"{Binding Path=(dockablz:Layout.FloatingItemState), RelativeSource={RelativeSource TemplatedParent}, Converter={StaticResource EqualityToBooleanConverter}, ConverterParameter={x:Static WindowState.Normal}}\"\n                                   dragablz:DragablzItem.SizeGrip=\"BottomRight\"\n                                   HorizontalAlignment=\"Right\"\n                                   VerticalAlignment=\"Bottom\"\n                                   Cursor=\"SizeNWSE\"\n                                   />\n                            <Thumb Style=\"{StaticResource MaterialDesignInvisibleThumbStyle}\"\n                                   Width=\"{Binding RelativeSource={RelativeSource TemplatedParent}, Path=BorderThickness.Right}\"\n                                   Height=\"{Binding RelativeSource={RelativeSource TemplatedParent}, Path=BorderThickness.Bottom}\"\n                                   IsEnabled=\"{Binding Path=(dockablz:Layout.FloatingItemState), RelativeSource={RelativeSource TemplatedParent}, Converter={StaticResource EqualityToBooleanConverter}, ConverterParameter={x:Static WindowState.Normal}}\"\n                                   dragablz:DragablzItem.SizeGrip=\"BottomLeft\"                                   \n                                   HorizontalAlignment=\"Left\"\n                                   VerticalAlignment=\"Bottom\"\n                                   Cursor=\"SizeNESW\"\n                                   />\n                        </Grid>\n                    </ControlTemplate>\n                </Setter.Value>\n            </Setter>\n        </Style.Setters>\n        <Style.Triggers>\n            <Trigger Property=\"dockablz:Layout.FloatingItemState\" Value=\"Maximized\">\n                <Setter Property=\"BorderThickness\" Value=\"1\" />\n                <Setter Property=\"Canvas.Left\" Value=\"0\" />\n                <Setter Property=\"Canvas.Top\" Value=\"0\" />\n                <Setter Property=\"Width\" Value=\"{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type dockablz:Layout}}, Path=ActualWidth}\" />\n                <Setter Property=\"Height\" Value=\"{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type dockablz:Layout}}, Path=ActualHeight}\" />\n            </Trigger>\n        </Style.Triggers>\n    </Style>\n\n    <ControlTemplate x:Key=\"TabablzScrollViewerControlTemplate\" TargetType=\"{x:Type ScrollViewer}\">\n        <Grid x:Name=\"Grid\" Background=\"{TemplateBinding Background}\">\n            <Grid.ColumnDefinitions>\n                <ColumnDefinition Width=\"*\"/>\n                <ColumnDefinition Width=\"Auto\"/>\n            </Grid.ColumnDefinitions>\n            <Grid.RowDefinitions>\n                <RowDefinition Height=\"*\"/>\n                <RowDefinition Height=\"Auto\"/>\n            </Grid.RowDefinitions>\n            <ScrollContentPresenter x:Name=\"PART_ScrollContentPresenter\" CanContentScroll=\"{TemplateBinding CanContentScroll}\" CanHorizontallyScroll=\"False\" CanVerticallyScroll=\"False\" ContentTemplate=\"{TemplateBinding ContentTemplate}\" Content=\"{TemplateBinding Content}\" Grid.Column=\"0\" Margin=\"{TemplateBinding Padding}\" Grid.Row=\"0\"/>\n            <ScrollBar x:Name=\"PART_VerticalScrollBar\" AutomationProperties.AutomationId=\"VerticalScrollBar\" Cursor=\"Arrow\" Grid.Column=\"0\" Maximum=\"{TemplateBinding ScrollableHeight}\" Minimum=\"0\" Grid.Row=\"1\" Visibility=\"{TemplateBinding ComputedVerticalScrollBarVisibility}\" Value=\"{Binding VerticalOffset, Mode=OneWay, RelativeSource={RelativeSource TemplatedParent}}\" ViewportSize=\"{TemplateBinding ViewportHeight}\"\n                       Margin=\"0 1 0 0\" />\n            <ScrollBar x:Name=\"PART_HorizontalScrollBar\" AutomationProperties.AutomationId=\"HorizontalScrollBar\" Cursor=\"Arrow\" Grid.Column=\"1\" Maximum=\"{TemplateBinding ScrollableWidth}\" Minimum=\"0\" Orientation=\"Horizontal\" Grid.Row=\"0\" Visibility=\"{TemplateBinding ComputedHorizontalScrollBarVisibility}\" Value=\"{Binding HorizontalOffset, Mode=OneWay, RelativeSource={RelativeSource TemplatedParent}}\" ViewportSize=\"{TemplateBinding ViewportWidth}\" \n                       Margin=\"1 0 0 0\" />\n        </Grid>\n    </ControlTemplate>\n\n    <Style TargetType=\"{x:Type dragablz:DragablzItemsControl}\" x:Key=\"TabablzDragablzItemsControlStyle\">\n        <Setter Property=\"HorizontalAlignment\" Value=\"Left\" />\n        <Setter Property=\"VerticalAlignment\" Value=\"Top\" />\n        <Setter Property=\"ItemsPanel\">\n            <Setter.Value>\n                <ItemsPanelTemplate>\n                    <Canvas IsItemsHost=\"True\" />\n                </ItemsPanelTemplate>\n            </Setter.Value>\n        </Setter>\n        <Setter Property=\"Template\">\n            <Setter.Value>\n                <ControlTemplate TargetType=\"{x:Type dragablz:DragablzItemsControl}\">\n                    <Border BorderThickness=\"{TemplateBinding Border.BorderThickness}\" Padding=\"{TemplateBinding Control.Padding}\" BorderBrush=\"{TemplateBinding Border.BorderBrush}\" Background=\"{TemplateBinding Panel.Background}\" SnapsToDevicePixels=\"True\">\n                        <ScrollViewer HorizontalScrollBarVisibility=\"Auto\" VerticalScrollBarVisibility=\"Auto\"\n                                      Width=\"{TemplateBinding ActualWidth}\"\n                                      Height=\"{TemplateBinding ActualHeight}\"\n                                      Template=\"{StaticResource TabablzScrollViewerControlTemplate}\">\n                            <ItemsPresenter SnapsToDevicePixels=\"{TemplateBinding UIElement.SnapsToDevicePixels}\"\n                                            HorizontalAlignment=\"Left\"\n                                            VerticalAlignment=\"Top\"\n                                            Width=\"{TemplateBinding ItemsPresenterWidth}\"\n                                            Height=\"{TemplateBinding ItemsPresenterHeight}\"/>\n                        </ScrollViewer>\n                    </Border>\n                </ControlTemplate>\n            </Setter.Value>\n        </Setter>\n    </Style>\n\n    <Style x:Key=\"StandardEmbeddedButtonStyle\" TargetType=\"{x:Type Button}\">\n        <Setter Property=\"Foreground\" Value=\"{DynamicResource {x:Static SystemColors.ControlTextBrushKey}}\"/>\n        <Setter Property=\"BorderThickness\" Value=\"1\"/>\n        <Setter Property=\"HorizontalContentAlignment\" Value=\"Center\"/>\n        <Setter Property=\"VerticalContentAlignment\" Value=\"Center\"/>\n        <Setter Property=\"Template\">\n            <Setter.Value>\n                <ControlTemplate TargetType=\"{x:Type Button}\">\n                    <Border x:Name=\"border\" BorderBrush=\"{TemplateBinding BorderBrush}\" BorderThickness=\"{TemplateBinding BorderThickness}\" Background=\"{TemplateBinding Background}\" SnapsToDevicePixels=\"true\">\n                        <ContentPresenter x:Name=\"contentPresenter\" Focusable=\"False\" HorizontalAlignment=\"{TemplateBinding HorizontalContentAlignment}\" Margin=\"{TemplateBinding Padding}\" RecognizesAccessKey=\"True\" SnapsToDevicePixels=\"{TemplateBinding SnapsToDevicePixels}\" VerticalAlignment=\"{TemplateBinding VerticalContentAlignment}\"/>\n                    </Border>\n                    <ControlTemplate.Triggers>\n                        <Trigger Property=\"IsDefaulted\" Value=\"true\">\n                            <Setter Property=\"BorderBrush\" TargetName=\"border\" Value=\"{DynamicResource {x:Static SystemColors.HighlightBrushKey}}\"/>\n                        </Trigger>\n                    </ControlTemplate.Triggers>\n                </ControlTemplate>\n            </Setter.Value>\n        </Setter>\n    </Style>\n\n    <Style TargetType=\"{x:Type dragablz:TabablzControl}\" x:Key=\"MaterialDesignTabablzControlStyle\">\n        <Setter Property=\"Background\" Value=\"{Binding RelativeSource={RelativeSource FindAncestor, AncestorType=Window}, Path=Background}\" />\n        <Setter Property=\"BorderBrush\" Value=\"{DynamicResource PrimaryHueMidBrush}\" />\n        <Setter Property=\"TextElement.Foreground\" Value=\"{Binding RelativeSource={RelativeSource FindAncestor, AncestorType=Window}, Path=(TextElement.Foreground)}\" />\n        <Setter Property=\"ItemContainerStyle\" Value=\"{StaticResource MaterialDesignDragableTabItemStyle}\" />\n        <Setter Property=\"Template\">\n            <Setter.Value>\n                <ControlTemplate TargetType=\"{x:Type dragablz:TabablzControl}\">\n                    <Grid x:Name=\"templateRoot\" ClipToBounds=\"true\" SnapsToDevicePixels=\"true\" KeyboardNavigation.TabNavigation=\"Local\">\n                        <Grid.RowDefinitions>\n                            <RowDefinition x:Name=\"RowDefinition0\" Height=\"Auto\"/>\n                            <RowDefinition x:Name=\"RowDefinition1\" Height=\"*\"/>\n                        </Grid.RowDefinitions>\n                        <Border x:Name=\"contentPanel\" BorderBrush=\"{TemplateBinding BorderBrush}\" BorderThickness=\"{TemplateBinding BorderThickness}\" Background=\"{TemplateBinding Background}\" Grid.Column=\"0\" KeyboardNavigation.DirectionalNavigation=\"Contained\" Grid.Row=\"1\" KeyboardNavigation.TabIndex=\"2\" KeyboardNavigation.TabNavigation=\"Local\"\n                                Margin=\"0 -1 0 0\">\n                            <Grid x:Name=\"PART_ItemsHolder\" />\n                        </Border>\n                        <Grid Grid.Column=\"0\" Grid.Row=\"0\" x:Name=\"HeaderContainerGrid\" Visibility=\"{TemplateBinding IsHeaderPanelVisible, Converter={StaticResource BooleanToVisibilityConverter}}\">\n                            <Grid.Resources>\n                                <Style TargetType=\"{x:Type Button}\" BasedOn=\"{StaticResource StandardEmbeddedButtonStyle}\"></Style>\n                            </Grid.Resources>\n                            <Grid.ColumnDefinitions>\n                                <ColumnDefinition Width=\"Auto\" />\n                                <ColumnDefinition Width=\"Auto\" />\n                                <ColumnDefinition Width=\"Auto\" />\n                                <ColumnDefinition Width=\"*\" />\n                            </Grid.ColumnDefinitions>\n                            <Border Background=\"{TemplateBinding BorderBrush}\" Grid.ColumnSpan=\"4\">\n                                <Border.Effect>\n                                    <DropShadowEffect BlurRadius=\"5\" ShadowDepth=\"2\" Direction=\"270\" Opacity=\".5\" />\n                                </Border.Effect>\n                            </Border>\n                            <ContentControl Grid.Column=\"0\" x:Name=\"PrefixContentControl\" \n                                            Content=\"{TemplateBinding HeaderPrefixContent}\"\n                                            ContentStringFormat=\"{TemplateBinding HeaderPrefixContentStringFormat}\"\n                                            ContentTemplate=\"{TemplateBinding HeaderPrefixContentStringFormat}\"\n                                            ContentTemplateSelector=\"{TemplateBinding HeaderPrefixContentTemplateSelector}\"/>\n                            <dragablz:DragablzItemsControl x:Name=\"PART_HeaderItemsControl\"                                                         \n                                                           Grid.Column=\"1\"\n                                                           FixedItemCount=\"{TemplateBinding FixedHeaderCount}\"\n                                                           ItemsSource=\"{Binding RelativeSource={RelativeSource TemplatedParent}, Path=Items}\"                                                                                                            \n                                                           ItemContainerStyle=\"{TemplateBinding ItemContainerStyle}\"\n                                                           ItemsOrganiser=\"{TemplateBinding HeaderItemsOrganiser}\"\n                                                           KeyboardNavigation.TabIndex=\"1\" Panel.ZIndex=\"1\"\n                                                           ItemTemplate=\"{TemplateBinding HeaderItemTemplate}\"\n                                                           Style=\"{StaticResource TabablzDragablzItemsControlStyle}\">\n                                <dragablz:DragablzItemsControl.MaxWidth>\n                                    <MultiBinding>\n                                        <MultiBinding.Converter>\n                                            <dragablz:TabablzHeaderSizeConverter Orientation=\"Horizontal\"/>\n                                        </MultiBinding.Converter>\n                                        <Binding RelativeSource=\"{RelativeSource TemplatedParent}\" Path=\"ActualWidth\" />\n                                        <Binding RelativeSource=\"{RelativeSource Self}\" Path=\"ItemsPresenterWidth\" />\n                                        <Binding ElementName=\"PrefixContentControl\" Path=\"ActualWidth\" />\n                                        <Binding ElementName=\"DefaultAddButton\" Path=\"DesiredSize.Width\" />\n                                        <Binding ElementName=\"SuffixContentControl\" Path=\"DesiredSize.Width\" />\n                                    </MultiBinding>\n                                </dragablz:DragablzItemsControl.MaxWidth>\n                            </dragablz:DragablzItemsControl>\n                            <Button Style=\"{StaticResource MaterialDesignAddItemCommandButtonStyle}\"\n                                    x:Name=\"DefaultAddButton\"\n                                    Grid.Column=\"2\"\n                                    Command=\"{x:Static dragablz:TabablzControl.AddItemCommand}\"\n                                    Visibility=\"{TemplateBinding ShowDefaultAddButton, Converter={StaticResource BooleanToVisibilityConverter}}\"\n                                    />\n                            <ContentControl Grid.Column=\"3\" x:Name=\"SuffixContentControl\" \n                                            Content=\"{TemplateBinding HeaderSuffixContent}\"\n                                            ContentStringFormat=\"{TemplateBinding HeaderSuffixContentStringFormat}\"\n                                            ContentTemplate=\"{TemplateBinding HeaderSuffixContentStringFormat}\"\n                                            ContentTemplateSelector=\"{TemplateBinding HeaderSuffixContentTemplateSelector}\"\n                                            HorizontalAlignment=\"Stretch\"\n                                            />\n                        </Grid>\n                    </Grid>\n                    <ControlTemplate.Triggers>\n                        <Trigger Property=\"TabStripPlacement\" Value=\"Bottom\">\n                            <Setter Property=\"Grid.Row\" TargetName=\"PART_HeaderItemsControl\" Value=\"1\"/>\n                            <Setter Property=\"Grid.Row\" TargetName=\"contentPanel\" Value=\"0\"/>\n                            <Setter Property=\"Height\" TargetName=\"RowDefinition0\" Value=\"*\"/>\n                            <Setter Property=\"Height\" TargetName=\"RowDefinition1\" Value=\"Auto\"/>\n                        </Trigger>\n                        <Trigger Property=\"IsEnabled\" Value=\"false\">\n                            <Setter Property=\"TextElement.Foreground\" TargetName=\"templateRoot\" Value=\"{DynamicResource {x:Static SystemColors.GrayTextBrushKey}}\"/>\n                        </Trigger>\n                        <Trigger Property=\"IsDraggingWindow\" Value=\"True\">\n                            <Setter TargetName=\"DefaultAddButton\" Property=\"Visibility\" Value=\"Hidden\" />\n                        </Trigger>\n                    </ControlTemplate.Triggers>\n                </ControlTemplate>\n            </Setter.Value>\n        </Setter>\n        <Style.Triggers>\n            <Trigger Property=\"TabStripPlacement\" Value=\"Left\">\n                <Setter Property=\"HeaderItemsOrganiser\">\n                    <Setter.Value>\n                        <dragablz:VerticalOrganiser />\n                    </Setter.Value>\n                </Setter>\n                <Setter Property=\"ItemContainerStyle\" Value=\"{StaticResource MaterialDesignDragableTabItemVerticalStyle}\" />\n                <Setter Property=\"Template\">\n                    <Setter.Value>\n                        <ControlTemplate TargetType=\"{x:Type dragablz:TabablzControl}\">\n                            <Grid x:Name=\"templateRoot\" ClipToBounds=\"true\" SnapsToDevicePixels=\"true\" KeyboardNavigation.TabNavigation=\"Local\">\n                                <Grid.ColumnDefinitions>\n                                    <ColumnDefinition x:Name=\"ColumnDefinition0\" Width=\"Auto\"/>\n                                    <ColumnDefinition x:Name=\"ColumnDefinition1\" Width=\"*\"/>\n                                </Grid.ColumnDefinitions>\n                                <Border x:Name=\"contentPanel\" BorderBrush=\"{TemplateBinding BorderBrush}\" BorderThickness=\"{TemplateBinding BorderThickness}\" Background=\"{TemplateBinding Background}\" Grid.Column=\"1\" KeyboardNavigation.DirectionalNavigation=\"Contained\" KeyboardNavigation.TabIndex=\"2\" KeyboardNavigation.TabNavigation=\"Local\" Margin=\"-1 0 0 0\">\n                                    <Grid x:Name=\"PART_ItemsHolder\" />\n                                </Border>\n                                <Grid Grid.Column=\"0\" x:Name=\"HeaderContainerGrid\" Visibility=\"{TemplateBinding IsHeaderPanelVisible, Converter={StaticResource BooleanToVisibilityConverter}}\">\n                                    <Grid.Resources>\n                                        <Style TargetType=\"{x:Type Button}\" BasedOn=\"{StaticResource StandardEmbeddedButtonStyle}\" />\n                                    </Grid.Resources>\n                                    <Grid.RowDefinitions>\n                                        <RowDefinition Height=\"Auto\" />\n                                        <RowDefinition Height=\"Auto\" />\n                                        <RowDefinition Height=\"Auto\" />\n                                        <RowDefinition Height=\"*\" />\n                                    </Grid.RowDefinitions>\n                                    <Border Background=\"{DynamicResource PrimaryHueMidBrush}\" Grid.RowSpan=\"4\">\n                                        <Border.Effect>\n                                            <DropShadowEffect BlurRadius=\"5\" ShadowDepth=\"2\" Direction=\"270\" Opacity=\".5\" />\n                                        </Border.Effect>\n                                    </Border>\n                                    <ContentControl Grid.Row=\"0\" x:Name=\"PrefixContentControl\" \n                                                                Content=\"{TemplateBinding HeaderPrefixContent}\"\n                                                                ContentStringFormat=\"{TemplateBinding HeaderPrefixContentStringFormat}\"\n                                                                ContentTemplate=\"{TemplateBinding HeaderPrefixContentStringFormat}\"\n                                                                ContentTemplateSelector=\"{TemplateBinding HeaderPrefixContentTemplateSelector}\"/>\n                                    <dragablz:DragablzItemsControl x:Name=\"PART_HeaderItemsControl\"                                                         \n                                                                   Grid.Row=\"1\"                                                                   \n                                                                   ItemsSource=\"{Binding RelativeSource={RelativeSource TemplatedParent}, Path=Items}\"                                                                                                            \n                                                                   ItemContainerStyle=\"{TemplateBinding ItemContainerStyle}\"\n                                                                   FixedItemCount=\"{TemplateBinding FixedHeaderCount}\"\n                                                                   ItemsOrganiser=\"{TemplateBinding HeaderItemsOrganiser}\"\n                                                                   KeyboardNavigation.TabIndex=\"1\" Panel.ZIndex=\"1\"\n                                                                   ItemTemplate=\"{TemplateBinding HeaderItemTemplate}\"\n                                                                   Style=\"{StaticResource TabablzDragablzItemsControlStyle}\">\n                                        <dragablz:DragablzItemsControl.MaxHeight>\n                                            <MultiBinding>\n                                                <MultiBinding.Converter>\n                                                    <dragablz:TabablzHeaderSizeConverter Orientation=\"Vertical\"/>\n                                                </MultiBinding.Converter>\n                                                <Binding RelativeSource=\"{RelativeSource TemplatedParent}\" Path=\"ActualHeight\" />\n                                                <Binding RelativeSource=\"{RelativeSource Self}\" Path=\"ItemsPresenterHeight\" />\n                                                <Binding ElementName=\"PrefixContentControl\" Path=\"ActualHeight\" />\n                                                <Binding ElementName=\"DefaultAddButton\" Path=\"DesiredSize.Height\" />\n                                                <Binding ElementName=\"SuffixContentControl\" Path=\"DesiredSize.Height\" />\n                                            </MultiBinding>\n                                        </dragablz:DragablzItemsControl.MaxHeight>\n                                    </dragablz:DragablzItemsControl>\n                                    <Button Style=\"{StaticResource MaterialDesignAddItemCommandButtonStyle}\"\n                                            x:Name=\"DefaultAddButton\"\n                                            Grid.Row=\"2\"\n                                            Command=\"{x:Static dragablz:TabablzControl.AddItemCommand}\"\n                                            Visibility=\"{TemplateBinding ShowDefaultAddButton, Converter={StaticResource BooleanToVisibilityConverter}}\" />\n                                    <ContentControl Grid.Row=\"3\" x:Name=\"SuffixContentControl\" \n                                                                Content=\"{TemplateBinding HeaderSuffixContent}\"\n                                                                ContentStringFormat=\"{TemplateBinding HeaderSuffixContentStringFormat}\"\n                                                                ContentTemplate=\"{TemplateBinding HeaderSuffixContentStringFormat}\"\n                                                                ContentTemplateSelector=\"{TemplateBinding HeaderSuffixContentTemplateSelector}\"\n                                                                VerticalAlignment=\"Top\" />\n                                </Grid>\n                            </Grid>\n                            <ControlTemplate.Triggers>\n                                <Trigger Property=\"IsEnabled\" Value=\"false\">\n                                    <Setter Property=\"TextElement.Foreground\" TargetName=\"templateRoot\" Value=\"{DynamicResource {x:Static SystemColors.GrayTextBrushKey}}\"/>\n                                </Trigger>\n                                <Trigger Property=\"IsDraggingWindow\" Value=\"True\">\n                                    <Setter TargetName=\"DefaultAddButton\" Property=\"Visibility\" Value=\"Hidden\" />\n                                </Trigger>\n                                <Trigger Property=\"TabStripPlacement\" Value=\"Right\">\n                                    <!-- TODO -->\n                                </Trigger>\n                            </ControlTemplate.Triggers>\n                        </ControlTemplate>\n                    </Setter.Value>\n                </Setter>\n            </Trigger>\n        </Style.Triggers>\n    </Style>\n\n    <Style x:Key=\"MaterialDesignAlternateDragableTabItemStyle\" TargetType=\"{x:Type dragablz:DragablzItem}\" BasedOn=\"{StaticResource MaterialDesignDragableTabItemStyle}\">\n        <Setter Property=\"Foreground\" Value=\"{DynamicResource MaterialDesignColumnHeader}\"/>\n        <Setter Property=\"local:MaterialDesignAssist.IndicatorBrush\" Value=\"{DynamicResource PrimaryHueMidBrush}\" />\n        <Style.Triggers>\n            <Trigger Property=\"IsSelected\" Value=\"True\">\n                <Setter Property=\"Foreground\" Value=\"{DynamicResource PrimaryHueMidBrush}\" />\n            </Trigger>\n            <MultiTrigger>\n                <MultiTrigger.Conditions>\n                    <Condition Property=\"IsSelected\" Value=\"False\" />\n                    <Condition Property=\"IsMouseOver\" Value=\"True\" />\n                </MultiTrigger.Conditions>\n                <Setter Property=\"Foreground\" Value=\"{DynamicResource MaterialDesignBody}\" />\n            </MultiTrigger>\n        </Style.Triggers>\n    </Style>\n\n    <Style TargetType=\"{x:Type dragablz:TabablzControl}\" x:Key=\"MaterialDesignAlternateTabablzControlStyle\" BasedOn=\"{StaticResource MaterialDesignTabablzControlStyle}\">\n        <Setter Property=\"BorderBrush\" Value=\"{DynamicResource MaterialDesignPaper}\" />\n        <Setter Property=\"ItemContainerStyle\" Value=\"{StaticResource MaterialDesignAlternateDragableTabItemStyle}\" />        \n    </Style>\n\n</ResourceDictionary>\n"
  },
  {
    "path": "third_party/Dragablz/Dragablz/Themes/MaterialDesignAssist.cs",
    "content": "﻿using System;\nusing System.Collections.Generic;\nusing System.Linq;\nusing System.Text;\nusing System.Threading.Tasks;\nusing System.Windows;\nusing System.Windows.Media;\n\nnamespace Dragablz.Themes\n{\n    /// <summary>\n    /// Helper propries for configuring the material design style.\n    /// </summary>\n    public static class MaterialDesignAssist\n    {\n        /// <summary>\n        /// Framework use only.\n        /// </summary>\n        public static readonly DependencyProperty IndicatorBrushProperty = DependencyProperty.RegisterAttached(\n            \"IndicatorBrush\", typeof (Brush), typeof (MaterialDesignAssist), new PropertyMetadata(default(Brush)));\n\n        /// <summary>\n        /// The indicator (underline) brush.\n        /// </summary>\n        /// <param name=\"element\"></param>\n        /// <param name=\"value\"></param>\n        public static void SetIndicatorBrush(DependencyObject element, Brush value)\n        {\n            element.SetValue(IndicatorBrushProperty, value);\n        }\n\n        /// <summary>\n        /// The indicator (underline) brush.\n        /// </summary>\n        /// <param name=\"element\"></param>\n        /// <returns></returns>\n        public static Brush GetIndicatorBrush(DependencyObject element)\n        {\n            return (Brush) element.GetValue(IndicatorBrushProperty);\n        }\n    }\n}\n"
  },
  {
    "path": "third_party/Dragablz/Dragablz/Themes/Ripple.cs",
    "content": "﻿using System;\nusing System.Collections.Generic;\nusing System.Linq;\nusing System.Text;\nusing System.Windows;\nusing System.Windows.Controls;\nusing System.Windows.Input;\nusing System.Windows.Media;\nusing System.Windows.Media.Animation;\n\nnamespace Dragablz.Themes\n{\n    [TemplateVisualState(GroupName = \"CommonStates\", Name = TemplateStateNormal)]\n    [TemplateVisualState(GroupName = \"CommonStates\", Name = TemplateStateMousePressed)]\n    [TemplateVisualState(GroupName = \"CommonStates\", Name = TemplateStateMouseOut)]\n    public class Ripple : ContentControl\n    {\n        public const string TemplateStateNormal = \"Normal\";\n        public const string TemplateStateMousePressed = \"MousePressed\";\n        public const string TemplateStateMouseOut = \"MouseOut\";\n\n        private static readonly HashSet<Ripple> PressedInstances = new HashSet<Ripple>();\n\n        static Ripple()\n        {\n            DefaultStyleKeyProperty.OverrideMetadata(typeof(Ripple), new FrameworkPropertyMetadata(typeof(Ripple)));\n\n            EventManager.RegisterClassHandler(typeof(Window), Mouse.PreviewMouseUpEvent, new MouseButtonEventHandler(MouseButtonEventHandler), true);\n            EventManager.RegisterClassHandler(typeof(Window), Mouse.MouseMoveEvent, new MouseEventHandler(MouseMouveEventHandler), true);\n            EventManager.RegisterClassHandler(typeof(UserControl), Mouse.PreviewMouseUpEvent, new MouseButtonEventHandler(MouseButtonEventHandler), true);\n            EventManager.RegisterClassHandler(typeof(UserControl), Mouse.MouseMoveEvent, new MouseEventHandler(MouseMouveEventHandler), true);\n        }\n\n        public Ripple()\n        {\n            SizeChanged += OnSizeChanged;\n        }\n\n        private static void MouseButtonEventHandler(object sender, MouseButtonEventArgs e)\n        {\n            foreach (var ripple in PressedInstances)\n            {\n                // adjust the transition scale time according to the current animated scale\n                var scaleTrans = ripple.Template.FindName(\"ScaleTransform\", ripple) as ScaleTransform;\n                if (scaleTrans != null)\n                {\n                    double currentScale = scaleTrans.ScaleX;\n                    var newTime = TimeSpan.FromMilliseconds(300 * (1.0 - currentScale));\n\n                    // change the scale animation according to the current scale\n                    var scaleXKeyFrame = ripple.Template.FindName(\"MousePressedToNormalScaleXKeyFrame\", ripple) as EasingDoubleKeyFrame;\n                    if (scaleXKeyFrame != null)\n                    {\n                        scaleXKeyFrame.KeyTime = KeyTime.FromTimeSpan(newTime);\n                    }\n                    var scaleYKeyFrame = ripple.Template.FindName(\"MousePressedToNormalScaleYKeyFrame\", ripple) as EasingDoubleKeyFrame;\n                    if (scaleYKeyFrame != null)\n                    {\n                        scaleYKeyFrame.KeyTime = KeyTime.FromTimeSpan(newTime);\n                    }\n                }\n\n                VisualStateManager.GoToState(ripple, TemplateStateNormal, true);\n            }\n            PressedInstances.Clear();\n        }\n\n        private static void MouseMouveEventHandler(object sender, MouseEventArgs e)\n        {\n            foreach (var ripple in PressedInstances.ToList())\n            {\n                var relativePosition = Mouse.GetPosition(ripple);\n                if (relativePosition.X < 0\n                    || relativePosition.Y < 0\n                    || relativePosition.X >= ripple.ActualWidth\n                    || relativePosition.Y >= ripple.ActualHeight)\n\n                {\n                    VisualStateManager.GoToState(ripple, TemplateStateMouseOut, true);\n                    PressedInstances.Remove(ripple);\n                }\n            }\n        }\n\n        public static readonly DependencyProperty FeedbackProperty = DependencyProperty.Register(\n            \"Feedback\", typeof(Brush), typeof(Ripple), new PropertyMetadata(default(Brush)));\n\n        public Brush Feedback\n        {\n            get { return (Brush)GetValue(FeedbackProperty); }\n            set { SetValue(FeedbackProperty, value); }\n        }\n\n        protected override void OnPreviewMouseLeftButtonDown(MouseButtonEventArgs e)\n        {\n            var point = e.GetPosition(this);\n\n            if (RippleAssist.GetIsCentered(this))\n            {\n                var innerContent = (Content as FrameworkElement);\n\n                if (innerContent != null)\n                {\n                    var position = innerContent.TransformToAncestor(this)\n                        .Transform(new Point(0, 0));\n\n                    RippleX = position.X + innerContent.ActualWidth / 2 - RippleSize / 2;\n                    RippleY = position.Y + innerContent.ActualHeight / 2 - RippleSize / 2;\n                }\n                else\n                {\n                    RippleX = ActualWidth / 2 - RippleSize / 2;\n                    RippleY = ActualHeight / 2 - RippleSize / 2;\n                }\n            }\n            else\n            {\n                RippleX = point.X - RippleSize / 2;\n                RippleY = point.Y - RippleSize / 2;\n            }\n\n            VisualStateManager.GoToState(this, TemplateStateNormal, false);\n            VisualStateManager.GoToState(this, TemplateStateMousePressed, true);\n            PressedInstances.Add(this);\n\n            base.OnPreviewMouseLeftButtonDown(e);\n        }\n\n        private static readonly DependencyPropertyKey RippleSizePropertyKey =\n            DependencyProperty.RegisterReadOnly(\n                \"RippleSize\", typeof(double), typeof(Ripple),\n                new PropertyMetadata(default(double)));\n\n        public static readonly DependencyProperty RippleSizeProperty =\n            RippleSizePropertyKey.DependencyProperty;\n\n        public double RippleSize\n        {\n            get { return (double)GetValue(RippleSizeProperty); }\n            private set { SetValue(RippleSizePropertyKey, value); }\n        }\n\n        private static readonly DependencyPropertyKey RippleXPropertyKey =\n            DependencyProperty.RegisterReadOnly(\n                \"RippleX\", typeof(double), typeof(Ripple),\n                new PropertyMetadata(default(double)));\n\n        public static readonly DependencyProperty RippleXProperty =\n            RippleXPropertyKey.DependencyProperty;\n\n        public double RippleX\n        {\n            get { return (double)GetValue(RippleXProperty); }\n            private set { SetValue(RippleXPropertyKey, value); }\n        }\n\n        private static readonly DependencyPropertyKey RippleYPropertyKey =\n            DependencyProperty.RegisterReadOnly(\n                \"RippleY\", typeof(double), typeof(Ripple),\n                new PropertyMetadata(default(double)));\n\n        public static readonly DependencyProperty RippleYProperty =\n            RippleYPropertyKey.DependencyProperty;\n\n        public double RippleY\n        {\n            get { return (double)GetValue(RippleYProperty); }\n            private set { SetValue(RippleYPropertyKey, value); }\n        }\n\n        /// <summary>\n        ///   The DependencyProperty for the RecognizesAccessKey property. \n        ///   Default Value: false \n        /// </summary> \n        public static readonly DependencyProperty RecognizesAccessKeyProperty =\n            DependencyProperty.Register(\n                \"RecognizesAccessKey\", typeof(bool), typeof(Ripple),\n                new PropertyMetadata(default(bool)));\n\n        /// <summary> \n        ///   Determine if Ripple should use AccessText in its style\n        /// </summary> \n        public bool RecognizesAccessKey\n        {\n            get { return (bool)GetValue(RecognizesAccessKeyProperty); }\n            set { SetValue(RecognizesAccessKeyProperty, value); }\n        }\n\n        public override void OnApplyTemplate()\n        {\n            base.OnApplyTemplate();\n\n            VisualStateManager.GoToState(this, TemplateStateNormal, false);\n        }\n\n        private void OnSizeChanged(object sender, SizeChangedEventArgs sizeChangedEventArgs)\n        {\n            var innerContent = (Content as FrameworkElement);\n\n            double width, height;\n\n            if (RippleAssist.GetIsCentered(this) && innerContent != null)\n            {\n                width = innerContent.ActualWidth;\n                height = innerContent.ActualHeight;\n            }\n            else\n            {\n                width = sizeChangedEventArgs.NewSize.Width;\n                height = sizeChangedEventArgs.NewSize.Height;\n            }\n\n            var radius = Math.Sqrt(Math.Pow(width, 2) + Math.Pow(height, 2));\n\n            RippleSize = 2 * radius * RippleAssist.GetRippleSizeMultiplier(this);\n        }\n    }\n}\n"
  },
  {
    "path": "third_party/Dragablz/Dragablz/Themes/RippleAssist.cs",
    "content": "﻿using System.Windows;\n\nnamespace Dragablz.Themes\n{\n    public static class RippleAssist\n    {\n        #region ClipToBound\n\n        public static readonly DependencyProperty ClipToBoundsProperty = DependencyProperty.RegisterAttached(\n            \"ClipToBounds\", typeof(bool), typeof(RippleAssist), new FrameworkPropertyMetadata(true, FrameworkPropertyMetadataOptions.Inherits));\n\n        public static void SetClipToBounds(DependencyObject element, bool value)\n        {\n            element.SetValue(ClipToBoundsProperty, value);\n        }\n\n        public static bool GetClipToBounds(DependencyObject element)\n        {\n            return (bool)element.GetValue(ClipToBoundsProperty);\n        }\n\n        #endregion\n\n        #region StayOnCenter\n\n        /// <summary>\n        /// Set to <c>true</c> to cause the ripple to originate from the centre of the \n        /// content.  Otherwise the effect will originate from the mouse down position.        \n        /// </summary>\n        public static readonly DependencyProperty IsCenteredProperty = DependencyProperty.RegisterAttached(\n            \"IsCentered\", typeof(bool), typeof(RippleAssist), new FrameworkPropertyMetadata(false, FrameworkPropertyMetadataOptions.Inherits));\n\n        /// <summary>\n        /// Set to <c>true</c> to cause the ripple to originate from the centre of the \n        /// content.  Otherwise the effect will originate from the mouse down position.        \n        /// </summary>\n        /// <param name=\"element\"></param>\n        /// <param name=\"value\"></param>\n        public static void SetIsCentered(DependencyObject element, bool value)\n        {\n            element.SetValue(IsCenteredProperty, value);\n        }\n\n        /// <summary>\n        /// Set to <c>true</c> to cause the ripple to originate from the centre of the \n        /// content.  Otherwise the effect will originate from the mouse down position.        \n        /// </summary>\n        /// <param name=\"element\"></param>        \n        public static bool GetIsCentered(DependencyObject element)\n        {\n            return (bool)element.GetValue(IsCenteredProperty);\n        }\n\n        #endregion\n\n        #region RippleSizeMultiplier\n\n        public static readonly DependencyProperty RippleSizeMultiplierProperty = DependencyProperty.RegisterAttached(\n            \"RippleSizeMultiplier\", typeof(double), typeof(RippleAssist), new FrameworkPropertyMetadata(1.0, FrameworkPropertyMetadataOptions.Inherits));\n\n        public static void SetRippleSizeMultiplier(DependencyObject element, double value)\n        {\n            element.SetValue(RippleSizeMultiplierProperty, value);\n        }\n\n        public static double GetRippleSizeMultiplier(DependencyObject element)\n        {\n            return (double)element.GetValue(RippleSizeMultiplierProperty);\n        }\n\n        #endregion\n\n    }\n}"
  },
  {
    "path": "third_party/Dragablz/Dragablz/Themes/SystemCommandIcon.cs",
    "content": "﻿using System;\nusing System.Collections.Generic;\nusing System.Linq;\nusing System.Text;\nusing System.Windows;\nusing System.Windows.Controls;\n\nnamespace Dragablz.Themes\n{\n    public enum SystemCommandType\n    {\n        CloseWindow,\n        MaximizeWindow,\n        MinimzeWindow,\n        RestoreWindow\n    }\n\n    public class SystemCommandIcon : Control\n    {\n        static SystemCommandIcon()\n        {\n            DefaultStyleKeyProperty.OverrideMetadata(typeof(SystemCommandIcon), new FrameworkPropertyMetadata(typeof(SystemCommandIcon)));\n        }\n\n        public static readonly DependencyProperty SystemCommandTypeProperty = DependencyProperty.Register(\n            \"SystemCommandType\", typeof (SystemCommandType), typeof (SystemCommandIcon), new PropertyMetadata(default(SystemCommandType)));\n\n        public SystemCommandType SystemCommandType\n        {\n            get { return (SystemCommandType) GetValue(SystemCommandTypeProperty); }\n            set { SetValue(SystemCommandTypeProperty, value); }\n        }\n    }\n}\n"
  },
  {
    "path": "third_party/Dragablz/Dragablz/Trapezoid.cs",
    "content": "﻿using System;\nusing System.Collections.Generic;\nusing System.Linq;\nusing System.Text;\nusing System.Threading.Tasks;\nusing System.Windows;\nusing System.Windows.Baml2006;\nusing System.Windows.Controls;\nusing System.Windows.Media;\n\nnamespace Dragablz\n{\n    public class Trapezoid : ContentControl\n    {\n        private PathGeometry _pathGeometry;\n\n        static Trapezoid()\n        {\n            DefaultStyleKeyProperty.OverrideMetadata(typeof(Trapezoid), new FrameworkPropertyMetadata(typeof(Trapezoid)));\n            BackgroundProperty.OverrideMetadata(typeof(Trapezoid), new FrameworkPropertyMetadata(Panel.BackgroundProperty.DefaultMetadata.DefaultValue,\n                        FrameworkPropertyMetadataOptions.AffectsRender));\n        }\n\n        public static readonly DependencyProperty PenBrushProperty = DependencyProperty.Register(\n            \"PenBrush\", typeof (Brush), typeof (Trapezoid), new FrameworkPropertyMetadata(new SolidColorBrush(Colors.Transparent), FrameworkPropertyMetadataOptions.AffectsMeasure));\n\n        public Brush PenBrush\n        {\n            get { return (Brush) GetValue(PenBrushProperty); }\n            set { SetValue(PenBrushProperty, value); }\n        }\n\n        public static readonly DependencyProperty LongBasePenBrushProperty = DependencyProperty.Register(\n            \"LongBasePenBrush\", typeof(Brush), typeof(Trapezoid), new FrameworkPropertyMetadata(new SolidColorBrush(Colors.Transparent), FrameworkPropertyMetadataOptions.AffectsMeasure));\n\n        public Brush LongBasePenBrush\n        {\n            get { return (Brush) GetValue(LongBasePenBrushProperty); }\n            set { SetValue(LongBasePenBrushProperty, value); }\n        }\n\n        public static readonly DependencyProperty PenThicknessProperty = DependencyProperty.Register(\n            \"PenThickness\", typeof (double), typeof (Trapezoid), new FrameworkPropertyMetadata(default(double), FrameworkPropertyMetadataOptions.AffectsMeasure));\n\n        public double PenThickness\n        {\n            get { return (double) GetValue(PenThicknessProperty); }\n            set { SetValue(PenThicknessProperty, value); }\n        }\n\n        protected override Size MeasureOverride(Size constraint)\n        {\n            var contentDesiredSize = base.MeasureOverride(constraint);\n\n            if (contentDesiredSize.Width == 0 || double.IsInfinity(contentDesiredSize.Width)\n                || contentDesiredSize.Height == 0 || double.IsInfinity(contentDesiredSize.Height))\n\n                return contentDesiredSize;\n\n            _pathGeometry = CreateGeometry(contentDesiredSize);\n            Clip = _pathGeometry;\n\n            return _pathGeometry.GetRenderBounds(new Pen(PenBrush, 1)\n            {\n                EndLineCap = PenLineCap.Flat,\n                MiterLimit = 1\n            }).Size;\n        }\n\n        private Pen CreatePen()\n        {\n            return new Pen(PenBrush, PenThickness)\n            {\n                EndLineCap = PenLineCap.Flat,\n                MiterLimit = 1\n            };\n        }\n\n        private static PathGeometry CreateGeometry(Size contentDesiredSize)\n        {\n            //TODO Make better :)  do some funky beziers or summit\n            const double cheapRadiusBig = 6.0;\n            const double cheapRadiusSmall = cheapRadiusBig/2;\n            \n            const int angle = 20;\n            const double radians = angle * (Math.PI / 180);\n\n            var startPoint = new Point(0, contentDesiredSize.Height + cheapRadiusSmall + cheapRadiusSmall);\n\n            //clockwise starting at bottom left\n            var bottomLeftSegment = new ArcSegment(new Point(startPoint.X + cheapRadiusSmall, startPoint.Y - cheapRadiusSmall),\n                new Size(cheapRadiusSmall, cheapRadiusSmall), 315, false, SweepDirection.Counterclockwise, true);\n            var triangleX = Math.Tan(radians) * (contentDesiredSize.Height);\n            var leftSegment = new LineSegment(new Point(bottomLeftSegment.Point.X + triangleX, bottomLeftSegment.Point.Y - contentDesiredSize.Height), true);\n            var topLeftSegment = new ArcSegment(new Point(leftSegment.Point.X + cheapRadiusBig, leftSegment.Point.Y - cheapRadiusSmall), new Size(cheapRadiusBig, cheapRadiusBig), 120, false, SweepDirection.Clockwise, true);\n            var topSegment = new LineSegment(new Point(contentDesiredSize.Width + cheapRadiusBig + cheapRadiusBig, 0), true);\n            var topRightSegment = new ArcSegment(new Point(contentDesiredSize.Width + cheapRadiusBig + cheapRadiusBig + cheapRadiusBig, cheapRadiusSmall), new Size(cheapRadiusBig, cheapRadiusBig), 40, false, SweepDirection.Clockwise, true);\n\n            triangleX = Math.Tan(radians) * (contentDesiredSize.Height);\n            //triangleX = Math.Tan(radians)*(contentDesiredSize.Height - topRightSegment.Point.Y);\n            var rightSegment =\n                new LineSegment(new Point(topRightSegment.Point.X + triangleX,\n                    topRightSegment.Point.Y + contentDesiredSize.Height), true);\n\n            var bottomRightPoint = new Point(rightSegment.Point.X + cheapRadiusSmall,\n                rightSegment.Point.Y + cheapRadiusSmall);\n            var bottomRightSegment = new ArcSegment(bottomRightPoint,\n                new Size(cheapRadiusSmall, cheapRadiusSmall), 25, false, SweepDirection.Counterclockwise, true);\n            var bottomLeftPoint = new Point(0, bottomRightSegment.Point.Y);\n            var bottomSegment = new LineSegment(bottomLeftPoint, true);            \n\n            var pathSegmentCollection = new PathSegmentCollection\n            {\n                bottomLeftSegment, leftSegment, topLeftSegment, topSegment, topRightSegment, rightSegment, bottomRightSegment, bottomSegment\n            };\n            var pathFigure = new PathFigure(startPoint, pathSegmentCollection, true)\n            {\n                IsFilled = true\n            };\n            var pathFigureCollection = new PathFigureCollection\n            {\n                pathFigure\n            };\n            var geometryGroup = new PathGeometry(pathFigureCollection);            \n            geometryGroup.Freeze();                        \n\n            return geometryGroup;\n        }\n\n        protected override void OnRender(DrawingContext drawingContext)\n        {\n            base.OnRender(drawingContext);                        \n            drawingContext.DrawGeometry(Background, CreatePen(), _pathGeometry);\n\n            if (_pathGeometry == null) return;\n            drawingContext.DrawGeometry(Background, new Pen(LongBasePenBrush, PenThickness)\n            {\n                EndLineCap = PenLineCap.Flat,\n                MiterLimit = 1\n            }, new LineGeometry(_pathGeometry.Bounds.BottomLeft + new Vector(3, 0), _pathGeometry.Bounds.BottomRight + new Vector(-3, 0)));\n        }\n    }\n}\n"
  },
  {
    "path": "third_party/Dragablz/Dragablz/VerticalOrganiser.cs",
    "content": "﻿using System.Windows.Controls;\n\nnamespace Dragablz\n{\n    public class VerticalOrganiser : StackOrganiser\n    {\n        public VerticalOrganiser() : base(Orientation.Vertical)\n        {\n        }\n    }\n}"
  },
  {
    "path": "third_party/Dragablz/Dragablz/VerticalPositionMonitor.cs",
    "content": "﻿using System.Windows.Controls;\n\nnamespace Dragablz\n{\n    public class VerticalPositionMonitor : StackPositionMonitor\n    {\n        public VerticalPositionMonitor() : base(Orientation.Vertical)\n        {\n        }\n    }\n}"
  },
  {
    "path": "third_party/Get-ProcessHackerSources.ps1",
    "content": "<#\n.SYNOPSIS\nRetrieve ProcessHacker source code and apply a patch for CLR compilation\n\n.DESCRIPTION\nDependencies relies on a slightly modified version of phlib which fixes bugs when compiling with the /clr option (for a C++/CLI DLL target). It also modify the project's output folder for binaries and compilation objects.\n\nOne day I'll be able to upstream thoses changes and therefore only use  ProcessHacker's sdk, but until them I use this patching routine to keep the source relatively up-to-date.\n\n#>\n\nPush-Location\n\nWrite-Host -ForegroundColor Blue \"Checkout out ProcessHackerSources\";\n&git clone https://github.com/processhacker2/processhacker2.git \"tmp\"\n&cd tmp;\n&git checkout -b \"Dependencies\" d7342929f1426e597b95e0c20a9b9651d406f410\nWrite-Host -ForegroundColor Green \"Checkout out ProcessHackerSources OK\";\n\nWrite-Host -ForegroundColor Blue \"Pathching ProcessHackerSources\";\n&git am -3  \"../Ph-d7342929f1426e597b95e0c20a9b9651d406f410-__acrt_fp_format-bug-and-specify-CLR-compilation.patch\"\nWrite-Host -ForegroundColor Green \"Pathching ProcessHackerSources OK\";\n\nWrite-Host -ForegroundColor Blue \"Exporting src folders\";\nCopy-Item -Force -Recurse  \"phlib\" \"../\"\nCopy-Item -Force -Recurse  \"phnt\" \"../\"\nCopy-Item -Force -Recurse  \"tools/peview\" \"../\"\nWrite-Host -ForegroundColor Green \"Exporting src folders OK\";\n\n\nWrite-Host -ForegroundColor Blue \"Cleanup\";\n&cd \"../\";\nRemove-Item -Recurse -Force \"tmp\";\nWrite-Host -ForegroundColor Green \"Cleanup OK\";\n\nPop-Location"
  },
  {
    "path": "third_party/Ph-d7342929f1426e597b95e0c20a9b9651d406f410-__acrt_fp_format-bug-and-specify-CLR-compilation.patch",
    "content": "From 2113c249617e4649a5fe42e77ba695db652f0cb6 Mon Sep 17 00:00:00 2001\nFrom: lucasg <lucas.georges@outlook.com>\nDate: Sat, 22 Jul 2017 13:20:59 +0200\nSubject: [PATCH] Fix __acrt_fp_format bug and specify CLR compilation\n\n---\n phlib/format.c                    |  5 +++-\n phlib/format_i.h                  |  9 -------\n phlib/include/phbase.h            | 12 +++++++---\n phlib/include/phbasesup.h         |  2 +-\n phlib/phlib.vcxproj               | 26 ++++++++++----------\n phnt/include/ntexapi.h            |  9 +++++--\n phnt/include/phnt_ntdef.h         |  4 +++-\n tools/peview/peview.rc            |  2 +-\n tools/peview/peview.vcxproj       | 50 +++++++++++++++++++--------------------\n tools/peview/resources/phappres.h | 34 ++++++++++++++++++++++++++\n tools/peview/resources/phapprev.h |  6 +++++\n tools/peview/version.rc           | 35 +++++++++++++++++++++++++++\n 12 files changed, 138 insertions(+), 56 deletions(-)\n create mode 100644 tools/peview/resources/phappres.h\n create mode 100644 tools/peview/resources/phapprev.h\n create mode 100644 tools/peview/version.rc\n\ndiff --git a/phlib/format.c b/phlib/format.c\nindex b45fd38..b705370 100644\n--- a/phlib/format.c\n+++ b/phlib/format.c\n@@ -45,9 +45,10 @@ extern ULONG PhMaxSizeUnit;\n #define PHP_FORMAT_PAD 0x4\n \n // Internal CRT routine needed for floating-point conversion\n-\n+#if 0\n errno_t __cdecl _cfltcvt_l(double *arg, char *buffer, size_t sizeInBytes,\n     int format, int precision, int caps, _locale_t plocinfo);\n+#endif\n \n // Keep in sync with PhSizeUnitNames\n static PH_STRINGREF PhpSizeUnitNamesCounted[7] =\n@@ -66,6 +67,7 @@ static WCHAR PhpFormatDecimalSeparator = '.';\n static WCHAR PhpFormatThousandSeparator = ',';\n static _locale_t PhpFormatUserLocale = NULL;\n \n+#if 0\n #if (_MSC_VER >= 1900)\n \n // See Source\\10.0.10150.0\\ucrt\\convert\\cvt.cpp in SDK v10.\n@@ -94,6 +96,7 @@ static errno_t __cdecl _cfltcvt_l(double *arg, char *buffer, size_t sizeInBytes,\n }\n \n #endif\n+#endif\n \n // From Source\\10.0.10150.0\\ucrt\\inc\\corecrt_internal_stdio_output.h in SDK v10.\n VOID PhpCropZeros(\ndiff --git a/phlib/format_i.h b/phlib/format_i.h\nindex 31a5771..e98d3a0 100644\n--- a/phlib/format_i.h\n+++ b/phlib/format_i.h\n@@ -311,15 +311,6 @@ CommonInt64Format:\n         \\\n         value = (Format)->u.Double; \\\n         temp = (PSTR)tempBuffer + 1; /* leave one character so we can insert a prefix if needed */ \\\n-        _cfltcvt_l( \\\n-            &value, \\\n-            temp, \\\n-            sizeof(tempBuffer) - 1, \\\n-            c, \\\n-            precision, \\\n-            !!((Format)->Type & FormatUpperCase), \\\n-            PhpFormatUserLocale \\\n-            ); \\\n         \\\n         /* if (((Format)->Type & FormatForceDecimalPoint) && precision == 0) */ \\\n              /* _forcdecpt_l(tempBufferAnsi, PhpFormatUserLocale); */ \\\ndiff --git a/phlib/include/phbase.h b/phlib/include/phbase.h\nindex 15ad67e..3a40f2a 100644\n--- a/phlib/include/phbase.h\n+++ b/phlib/include/phbase.h\n@@ -17,11 +17,17 @@\n #define _CRT_SECURE_NO_WARNINGS\n #endif\n \n-#if !defined(_PHLIB_)\n+#if defined(_PHLIB_)\n+#define PHLIBAPI\n+#elif defined(_PHDLL_)\n+#define PHLIBAPI __declspec(dllexport)\n+#else\n+#if defined(__cplusplus)\n #define PHLIBAPI __declspec(dllimport)\n #else\n-#define PHLIBAPI\n-#endif\n+#define PHLIBAPI \n+#endif //  defined(__cplusplus)\n+#endif //  defined(_PHLIB_)\n \n #include <phnt_windows.h>\n #include <phnt.h>\ndiff --git a/phlib/include/phbasesup.h b/phlib/include/phbasesup.h\nindex b2c6a18..6cbafe7 100644\n--- a/phlib/include/phbasesup.h\n+++ b/phlib/include/phbasesup.h\n@@ -114,7 +114,7 @@ PhGetModuleProcAddress(\n {\n     HMODULE module;\n \n-    module = PhGetDllHandle(ModuleName);\n+    module = (HMODULE) PhGetDllHandle(ModuleName);\n \n     if (module)\n         return PhGetProcedureAddress(module, ProcName, 0);\ndiff --git a/phlib/phlib.vcxproj b/phlib/phlib.vcxproj\nindex e395b22..6a120e2 100644\n--- a/phlib/phlib.vcxproj\n+++ b/phlib/phlib.vcxproj\n@@ -1,4 +1,4 @@\n-<?xml version=\"1.0\" encoding=\"utf-8\"?>\n+﻿<?xml version=\"1.0\" encoding=\"utf-8\"?>\n <Project DefaultTargets=\"Build\" ToolsVersion=\"15.0\" xmlns=\"http://schemas.microsoft.com/developer/msbuild/2003\">\n   <ItemGroup Label=\"ProjectConfigurations\">\n     <ProjectConfiguration Include=\"Debug|Win32\">\n@@ -64,19 +64,19 @@\n   </ImportGroup>\n   <PropertyGroup Label=\"UserMacros\" />\n   <PropertyGroup>\n-    <OutDir Condition=\"'$(Configuration)|$(Platform)'=='Debug|Win32'\">$(ProjectDir)bin\\$(Configuration)$(PlatformArchitecture)\\</OutDir>\n-    <IntDir Condition=\"'$(Configuration)|$(Platform)'=='Debug|Win32'\">$(ProjectDir)obj\\$(Configuration)$(PlatformArchitecture)\\</IntDir>\n-    <OutDir Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">$(ProjectDir)bin\\$(Configuration)$(PlatformArchitecture)\\</OutDir>\n-    <IntDir Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">$(ProjectDir)obj\\$(Configuration)$(PlatformArchitecture)\\</IntDir>\n-    <OutDir Condition=\"'$(Configuration)|$(Platform)'=='Release|Win32'\">$(ProjectDir)bin\\$(Configuration)$(PlatformArchitecture)\\</OutDir>\n-    <IntDir Condition=\"'$(Configuration)|$(Platform)'=='Release|Win32'\">$(ProjectDir)obj\\$(Configuration)$(PlatformArchitecture)\\</IntDir>\n-    <OutDir Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\">$(ProjectDir)bin\\$(Configuration)$(PlatformArchitecture)\\</OutDir>\n-    <IntDir Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\">$(ProjectDir)obj\\$(Configuration)$(PlatformArchitecture)\\</IntDir>\n+    <OutDir Condition=\"'$(Configuration)|$(Platform)'=='Debug|Win32'\">$(SolutionDir)bin\\$(Configuration)$(PlatformArchitecture)\\</OutDir>\n+    <IntDir Condition=\"'$(Configuration)|$(Platform)'=='Debug|Win32'\">$(SolutionDir)obj\\$(ProjectName)\\$(Configuration)$(PlatformArchitecture)\\</IntDir>\n+    <OutDir Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">$(SolutionDir)bin\\$(Configuration)$(PlatformArchitecture)\\</OutDir>\n+    <IntDir Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">$(SolutionDir)obj\\$(ProjectName)\\$(Configuration)$(PlatformArchitecture)\\</IntDir>\n+    <OutDir Condition=\"'$(Configuration)|$(Platform)'=='Release|Win32'\">$(SolutionDir)bin\\$(Configuration)$(PlatformArchitecture)\\</OutDir>\n+    <IntDir Condition=\"'$(Configuration)|$(Platform)'=='Release|Win32'\">$(SolutionDir)obj\\$(ProjectName)\\$(Configuration)$(PlatformArchitecture)\\</IntDir>\n+    <OutDir Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\">$(SolutionDir)bin\\$(Configuration)$(PlatformArchitecture)\\</OutDir>\n+    <IntDir Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\">$(SolutionDir)obj\\$(ProjectName)\\$(Configuration)$(PlatformArchitecture)\\</IntDir>\n   </PropertyGroup>\n   <ItemDefinitionGroup Condition=\"'$(Configuration)|$(Platform)'=='Debug|Win32'\">\n     <ClCompile>\n       <Optimization>Disabled</Optimization>\n-      <AdditionalIncludeDirectories>$(SolutionDir)phnt\\include;include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>\n+      <AdditionalIncludeDirectories>$(SolutionDir)third_party\\phnt\\include;include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>\n       <PreprocessorDefinitions>DEBUG;_PHLIB_;%(PreprocessorDefinitions)</PreprocessorDefinitions>\n       <StringPooling>true</StringPooling>\n       <BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks>\n@@ -91,7 +91,7 @@\n   <ItemDefinitionGroup Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">\n     <ClCompile>\n       <Optimization>Disabled</Optimization>\n-      <AdditionalIncludeDirectories>$(SolutionDir)phnt\\include;include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>\n+      <AdditionalIncludeDirectories>$(SolutionDir)third_party\\phnt\\include;include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>\n       <PreprocessorDefinitions>DEBUG;_PHLIB_;%(PreprocessorDefinitions)</PreprocessorDefinitions>\n       <StringPooling>true</StringPooling>\n       <BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks>\n@@ -107,7 +107,7 @@\n     <ClCompile>\n       <Optimization>MaxSpeed</Optimization>\n       <IntrinsicFunctions>true</IntrinsicFunctions>\n-      <AdditionalIncludeDirectories>$(SolutionDir)phnt\\include;include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>\n+      <AdditionalIncludeDirectories>$(SolutionDir)third_party\\phnt\\include;include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>\n       <PreprocessorDefinitions>WIN32;NDEBUG;_WINDOWS;_PHLIB_;%(PreprocessorDefinitions)</PreprocessorDefinitions>\n       <StringPooling>true</StringPooling>\n       <RuntimeLibrary>MultiThreaded</RuntimeLibrary>\n@@ -125,7 +125,7 @@\n     <ClCompile>\n       <Optimization>MaxSpeed</Optimization>\n       <IntrinsicFunctions>true</IntrinsicFunctions>\n-      <AdditionalIncludeDirectories>$(SolutionDir)phnt\\include;include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>\n+      <AdditionalIncludeDirectories>$(SolutionDir)third_party\\phnt\\include;include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>\n       <PreprocessorDefinitions>WIN64;NDEBUG;_WINDOWS;_PHLIB_;%(PreprocessorDefinitions)</PreprocessorDefinitions>\n       <StringPooling>true</StringPooling>\n       <RuntimeLibrary>MultiThreaded</RuntimeLibrary>\ndiff --git a/phnt/include/ntexapi.h b/phnt/include/ntexapi.h\nindex 5a42dbf..80821b3 100644\n--- a/phnt/include/ntexapi.h\n+++ b/phnt/include/ntexapi.h\n@@ -3438,7 +3438,9 @@ FORCEINLINE ULONGLONG NtGetTickCount64()\n         if (tickCount.HighPart == (ULONG)USER_SHARED_DATA->TickCount.High2Time)\n             break;\n \n-        YieldProcessor();\n+#ifndef _MANAGED\n+\t\tYieldProcessor();\n+#endif // !_MANAGED\n     }\n \n #endif\n@@ -3465,7 +3467,10 @@ FORCEINLINE ULONG NtGetTickCount()\n         if (tickCount.HighPart == (ULONG)USER_SHARED_DATA->TickCount.High2Time)\n             break;\n \n-        YieldProcessor();\n+#ifndef _MANAGED\n+\t\tYieldProcessor();\n+#endif // !_MANAGED\n+        \n     }\n \n     return (ULONG)((UInt32x32To64(tickCount.LowPart, USER_SHARED_DATA->TickCountMultiplier) >> 24) +\ndiff --git a/phnt/include/phnt_ntdef.h b/phnt/include/phnt_ntdef.h\nindex 36cc781..93f911d 100644\n--- a/phnt/include/phnt_ntdef.h\n+++ b/phnt/include/phnt_ntdef.h\n@@ -71,7 +71,9 @@ typedef LARGE_INTEGER PHYSICAL_ADDRESS, *PPHYSICAL_ADDRESS;\n \n // Functions\n \n-#ifndef _WIN64\n+#ifdef _MANAGED\n+#define FASTCALL __stdcall\n+#elif !defined(_WIN64)\n #define FASTCALL __fastcall\n #else\n #define FASTCALL\ndiff --git a/tools/peview/peview.rc b/tools/peview/peview.rc\nindex c9dd19a..318adce 100644\n--- a/tools/peview/peview.rc\n+++ b/tools/peview/peview.rc\n@@ -8,7 +8,7 @@\n // Generated from the TEXTINCLUDE 2 resource.\n //\n #include \"winres.h\"\n-#include \"../../ProcessHacker/include/phappres.h\"\n+#include \"resources/phappres.h\"\n /////////////////////////////////////////////////////////////////////////////\n #undef APSTUDIO_READONLY_SYMBOLS\n \ndiff --git a/tools/peview/peview.vcxproj b/tools/peview/peview.vcxproj\nindex a5a6ae5..1bc3d72 100644\n--- a/tools/peview/peview.vcxproj\n+++ b/tools/peview/peview.vcxproj\n@@ -65,16 +65,16 @@\n   <PropertyGroup Label=\"UserMacros\" />\n   <PropertyGroup>\n     <OutDir Condition=\"'$(Configuration)|$(Platform)'=='Debug|Win32'\">$(SolutionDir)bin\\$(Configuration)$(PlatformArchitecture)\\</OutDir>\n-    <IntDir Condition=\"'$(Configuration)|$(Platform)'=='Debug|Win32'\">$(ProjectDir)obj\\$(Configuration)$(PlatformArchitecture)\\</IntDir>\n+    <IntDir Condition=\"'$(Configuration)|$(Platform)'=='Debug|Win32'\">$(SolutionDir)obj\\$(ProjectName)\\$(Configuration)$(PlatformArchitecture)\\</IntDir>\n     <LinkIncremental Condition=\"'$(Configuration)|$(Platform)'=='Debug|Win32'\">false</LinkIncremental>\n     <OutDir Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">$(SolutionDir)bin\\$(Configuration)$(PlatformArchitecture)\\</OutDir>\n-    <IntDir Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">$(ProjectDir)obj\\$(Configuration)$(PlatformArchitecture)\\</IntDir>\n+    <IntDir Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">$(SolutionDir)obj\\$(ProjectName)\\$(Configuration)$(PlatformArchitecture)\\</IntDir>\n     <LinkIncremental Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">false</LinkIncremental>\n     <OutDir Condition=\"'$(Configuration)|$(Platform)'=='Release|Win32'\">$(SolutionDir)bin\\$(Configuration)$(PlatformArchitecture)\\</OutDir>\n-    <IntDir Condition=\"'$(Configuration)|$(Platform)'=='Release|Win32'\">$(ProjectDir)obj\\$(Configuration)$(PlatformArchitecture)\\</IntDir>\n+    <IntDir Condition=\"'$(Configuration)|$(Platform)'=='Release|Win32'\">$(SolutionDir)obj\\$(ProjectName)\\$(Configuration)$(PlatformArchitecture)\\</IntDir>\n     <LinkIncremental Condition=\"'$(Configuration)|$(Platform)'=='Release|Win32'\">false</LinkIncremental>\n     <OutDir Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\">$(SolutionDir)bin\\$(Configuration)$(PlatformArchitecture)\\</OutDir>\n-    <IntDir Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\">$(ProjectDir)obj\\$(Configuration)$(PlatformArchitecture)\\</IntDir>\n+    <IntDir Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\">$(SolutionDir)obj\\$(ProjectName)\\$(Configuration)$(PlatformArchitecture)\\</IntDir>\n     <LinkIncremental Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\">false</LinkIncremental>\n   </PropertyGroup>\n   <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Debug|Win32'\" />\n@@ -84,8 +84,8 @@\n   <ItemDefinitionGroup Condition=\"'$(Configuration)|$(Platform)'=='Debug|Win32'\">\n     <ClCompile>\n       <Optimization>Disabled</Optimization>\n-      <AdditionalIncludeDirectories>..\\..\\phnt\\include;..\\..\\phlib\\include;include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>\n-      <PreprocessorDefinitions>_PHLIB_;_WINDOWS;WIN32;DEBUG;%(PreprocessorDefinitions);$(ExternalCompilerOptions)</PreprocessorDefinitions>\n+      <AdditionalIncludeDirectories>$(SolutionDir)third_party\\phnt\\include;$(SolutionDir)third_party\\phlib\\include;include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>\n+      <PreprocessorDefinitions>_PHLIB_;_WINDOWS;WIN32;DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>\n       <BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks>\n       <RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>\n       <WarningLevel>Level3</WarningLevel>\n@@ -96,8 +96,8 @@\n       <StringPooling>true</StringPooling>\n     </ClCompile>\n     <Link>\n-      <AdditionalDependencies>noarg.obj;noenv.obj;phlib.lib;ntdll.lib;uxtheme.lib;windowscodecs.lib;%(AdditionalDependencies)</AdditionalDependencies>\n-      <AdditionalLibraryDirectories>..\\..\\phlib\\bin\\$(Configuration)$(PlatformArchitecture);%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>\n+      <AdditionalDependencies>noarg.obj;noenv.obj;$(OutputPath)phlib.lib;ntdll.lib;uxtheme.lib;windowscodecs.lib;%(AdditionalDependencies)</AdditionalDependencies>\n+      <AdditionalLibraryDirectories>%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>\n       <AdditionalManifestDependencies>\n       </AdditionalManifestDependencies>\n       <GenerateDebugInformation>true</GenerateDebugInformation>\n@@ -106,15 +106,15 @@\n       <MinimumRequiredVersion>6.01</MinimumRequiredVersion>\n     </Link>\n     <ResourceCompile>\n-      <AdditionalIncludeDirectories>..\\..\\phnt\\include;..\\..\\phlib\\include;include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>\n+      <AdditionalIncludeDirectories>$(SolutionDir)third_party\\phnt\\include;$(SolutionDir)third_party\\phlib\\include;include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>\n       <PreprocessorDefinitions>_UNICODE;UNICODE;%(PreprocessorDefinitions);$(ExternalCompilerOptions)</PreprocessorDefinitions>\n     </ResourceCompile>\n   </ItemDefinitionGroup>\n   <ItemDefinitionGroup Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">\n     <ClCompile>\n       <Optimization>Disabled</Optimization>\n-      <AdditionalIncludeDirectories>..\\..\\phnt\\include;..\\..\\phlib\\include;include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>\n-      <PreprocessorDefinitions>_PHLIB_;_WINDOWS;WIN64;DEBUG;%(PreprocessorDefinitions);$(ExternalCompilerOptions)</PreprocessorDefinitions>\n+      <AdditionalIncludeDirectories>$(SolutionDir)third_party\\phnt\\include;$(SolutionDir)third_party\\phlib\\include;include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>\n+      <PreprocessorDefinitions>_PHLIB_;_WINDOWS;WIN64;DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>\n       <BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks>\n       <RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>\n       <WarningLevel>Level3</WarningLevel>\n@@ -125,8 +125,8 @@\n       <StringPooling>true</StringPooling>\n     </ClCompile>\n     <Link>\n-      <AdditionalDependencies>noarg.obj;noenv.obj;phlib.lib;ntdll.lib;uxtheme.lib;windowscodecs.lib;%(AdditionalDependencies)</AdditionalDependencies>\n-      <AdditionalLibraryDirectories>..\\..\\phlib\\bin\\$(Configuration)$(PlatformArchitecture);%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>\n+      <AdditionalDependencies>noarg.obj;noenv.obj;$(OutputPath)phlib.lib;ntdll.lib;uxtheme.lib;windowscodecs.lib;%(AdditionalDependencies)</AdditionalDependencies>\n+      <AdditionalLibraryDirectories>%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>\n       <AdditionalManifestDependencies>\n       </AdditionalManifestDependencies>\n       <GenerateDebugInformation>true</GenerateDebugInformation>\n@@ -135,7 +135,7 @@\n       <MinimumRequiredVersion>6.01</MinimumRequiredVersion>\n     </Link>\n     <ResourceCompile>\n-      <AdditionalIncludeDirectories>..\\..\\phnt\\include;..\\..\\phlib\\include;include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>\n+      <AdditionalIncludeDirectories>$(SolutionDir)third_party\\phnt\\include;$(SolutionDir)third_party\\phlib\\include;include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>\n       <PreprocessorDefinitions>_UNICODE;UNICODE;%(PreprocessorDefinitions);$(ExternalCompilerOptions)</PreprocessorDefinitions>\n     </ResourceCompile>\n   </ItemDefinitionGroup>\n@@ -143,8 +143,8 @@\n     <ClCompile>\n       <Optimization>MaxSpeed</Optimization>\n       <IntrinsicFunctions>true</IntrinsicFunctions>\n-      <AdditionalIncludeDirectories>..\\..\\phnt\\include;..\\..\\phlib\\include;include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>\n-      <PreprocessorDefinitions>_PHLIB_;_WINDOWS;WIN32;NDEBUG;%(PreprocessorDefinitions);$(ExternalCompilerOptions)</PreprocessorDefinitions>\n+      <AdditionalIncludeDirectories>$(SolutionDir)third_party\\phnt\\include;$(SolutionDir)third_party\\phlib\\include;include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>\n+      <PreprocessorDefinitions>_PHLIB_;_WINDOWS;WIN32;NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>\n       <RuntimeLibrary>MultiThreaded</RuntimeLibrary>\n       <FunctionLevelLinking>true</FunctionLevelLinking>\n       <WarningLevel>Level3</WarningLevel>\n@@ -157,8 +157,8 @@\n       <SDLCheck>true</SDLCheck>\n     </ClCompile>\n     <Link>\n-      <AdditionalDependencies>noarg.obj;noenv.obj;phlib.lib;ntdll.lib;uxtheme.lib;windowscodecs.lib;%(AdditionalDependencies)</AdditionalDependencies>\n-      <AdditionalLibraryDirectories>..\\..\\phlib\\bin\\$(Configuration)$(PlatformArchitecture);%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>\n+      <AdditionalDependencies>noarg.obj;noenv.obj;$(OutputPath)phlib.lib;ntdll.lib;uxtheme.lib;windowscodecs.lib;%(AdditionalDependencies)</AdditionalDependencies>\n+      <AdditionalLibraryDirectories>%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>\n       <AdditionalManifestDependencies>\n       </AdditionalManifestDependencies>\n       <GenerateDebugInformation>true</GenerateDebugInformation>\n@@ -170,7 +170,7 @@\n       <MinimumRequiredVersion>6.01</MinimumRequiredVersion>\n     </Link>\n     <ResourceCompile>\n-      <AdditionalIncludeDirectories>..\\..\\phnt\\include;..\\..\\phlib\\include;include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>\n+      <AdditionalIncludeDirectories>$(SolutionDir)third_party\\phnt\\include;$(SolutionDir)third_party\\phlib\\include;include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>\n       <PreprocessorDefinitions>_UNICODE;UNICODE;%(PreprocessorDefinitions);$(ExternalCompilerOptions)</PreprocessorDefinitions>\n     </ResourceCompile>\n   </ItemDefinitionGroup>\n@@ -178,8 +178,8 @@\n     <ClCompile>\n       <Optimization>MaxSpeed</Optimization>\n       <IntrinsicFunctions>true</IntrinsicFunctions>\n-      <AdditionalIncludeDirectories>..\\..\\phnt\\include;..\\..\\phlib\\include;include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>\n-      <PreprocessorDefinitions>_PHLIB_;_WINDOWS;WIN64;DEBUG;%(PreprocessorDefinitions);$(ExternalCompilerOptions)</PreprocessorDefinitions>\n+      <AdditionalIncludeDirectories>$(SolutionDir)third_party\\phnt\\include;$(SolutionDir)third_party\\phlib\\include;include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>\n+      <PreprocessorDefinitions>_PHLIB_;_WINDOWS;WIN64;DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>\n       <RuntimeLibrary>MultiThreaded</RuntimeLibrary>\n       <FunctionLevelLinking>true</FunctionLevelLinking>\n       <WarningLevel>Level3</WarningLevel>\n@@ -191,8 +191,8 @@\n       <SDLCheck>true</SDLCheck>\n     </ClCompile>\n     <Link>\n-      <AdditionalDependencies>noarg.obj;noenv.obj;phlib.lib;ntdll.lib;uxtheme.lib;windowscodecs.lib;%(AdditionalDependencies)</AdditionalDependencies>\n-      <AdditionalLibraryDirectories>..\\..\\phlib\\bin\\$(Configuration)$(PlatformArchitecture);%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>\n+      <AdditionalDependencies>noarg.obj;noenv.obj;$(OutputPath)phlib.lib;ntdll.lib;uxtheme.lib;windowscodecs.lib;%(AdditionalDependencies)</AdditionalDependencies>\n+      <AdditionalLibraryDirectories>%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>\n       <AdditionalManifestDependencies>\n       </AdditionalManifestDependencies>\n       <GenerateDebugInformation>true</GenerateDebugInformation>\n@@ -204,7 +204,7 @@\n       <MinimumRequiredVersion>6.01</MinimumRequiredVersion>\n     </Link>\n     <ResourceCompile>\n-      <AdditionalIncludeDirectories>..\\..\\phnt\\include;..\\..\\phlib\\include;include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>\n+      <AdditionalIncludeDirectories>$(SolutionDir)third_party\\phnt\\include;$(SolutionDir)third_party\\phlib\\include;include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>\n       <PreprocessorDefinitions>_UNICODE;UNICODE;%(PreprocessorDefinitions);$(ExternalCompilerOptions)</PreprocessorDefinitions>\n     </ResourceCompile>\n   </ItemDefinitionGroup>\n@@ -236,7 +236,7 @@\n     <ResourceCompile Include=\"peview.rc\" />\n   </ItemGroup>\n   <ItemGroup>\n-    <ProjectReference Include=\"..\\..\\phlib\\phlib.vcxproj\">\n+    <ProjectReference Include=\"..\\phlib\\phlib.vcxproj\">\n       <Project>{477d0215-f252-41a1-874b-f27e3ea1ed17}</Project>\n       <ReferenceOutputAssembly>false</ReferenceOutputAssembly>\n     </ProjectReference>\ndiff --git a/tools/peview/resources/phappres.h b/tools/peview/resources/phappres.h\nnew file mode 100644\nindex 0000000..3f8215d\n--- /dev/null\n+++ b/tools/peview/resources/phappres.h\n@@ -0,0 +1,34 @@\n+// Notes:\n+// * Do not use /* comments */ since ISPP is buggy and it will throw an error.\n+\n+#ifndef PH_PHAPPRES_H\n+#define PH_PHAPPRES_H\n+\n+#include \"phapprev.h\"\n+\n+#define PHAPP_VERSION_MAJOR 3\n+#define PHAPP_VERSION_MINOR 0\n+#define PHAPP_VERSION_BUILD 0\n+\n+#if (PHAPP_VERSION_BUILD == 0)\n+#define TWO_DIGIT_VER   1\n+#else\n+#define THREE_DIGIT_VER 1\n+#endif\n+\n+#define DO_MAKE_STR(x) #x\n+#define MAKE_STR(x)    DO_MAKE_STR(x)\n+\n+#ifndef ISPP_INVOKED\n+\n+#if defined(TWO_DIGIT_VER)\n+#define PHAPP_VERSION_STRING MAKE_STR(PHAPP_VERSION_MAJOR) \".\" MAKE_STR(PHAPP_VERSION_MINOR) \".0\" \".\" MAKE_STR(PHAPP_VERSION_REVISION)\n+#elif defined(THREE_DIGIT_VER)\n+#define PHAPP_VERSION_STRING MAKE_STR(PHAPP_VERSION_MAJOR) \".\" MAKE_STR(PHAPP_VERSION_MINOR) \".\" MAKE_STR(PHAPP_VERSION_BUILD) \".\" MAKE_STR(PHAPP_VERSION_REVISION)\n+#endif\n+\n+#define PHAPP_VERSION_NUMBER PHAPP_VERSION_MAJOR,PHAPP_VERSION_MINOR,PHAPP_VERSION_BUILD,PHAPP_VERSION_REVISION\n+\n+#endif // ISPP_INVOKED\n+\n+#endif // PHAPPRES_H\ndiff --git a/tools/peview/resources/phapprev.h b/tools/peview/resources/phapprev.h\nnew file mode 100644\nindex 0000000..fc00f3f\n--- /dev/null\n+++ b/tools/peview/resources/phapprev.h\n@@ -0,0 +1,6 @@\n+#ifndef PHAPPREV_H \n+#define PHAPPREV_H \n+\n+#define PHAPP_VERSION_REVISION 618\n+\n+#endif // PHAPPREV_H\ndiff --git a/tools/peview/version.rc b/tools/peview/version.rc\nnew file mode 100644\nindex 0000000..47b7ac7\n--- /dev/null\n+++ b/tools/peview/version.rc\n@@ -0,0 +1,35 @@\n+#include \"winres.h\"\n+#include \"resources/phappres.h\"\n+\n+VS_VERSION_INFO VERSIONINFO\n+ FILEVERSION PHAPP_VERSION_NUMBER\n+ PRODUCTVERSION PHAPP_VERSION_NUMBER\n+ FILEFLAGSMASK 0x17L\n+#ifdef _DEBUG\n+ FILEFLAGS 0x1L\n+#else\n+ FILEFLAGS 0x0L\n+#endif\n+ FILEOS 0x4L\n+ FILETYPE 0x1L\n+ FILESUBTYPE 0x0L\n+BEGIN\n+    BLOCK \"StringFileInfo\"\n+    BEGIN\n+        BLOCK \"0c0904b0\"\n+        BEGIN\n+            VALUE \"CompanyName\", \"wj32\"\n+            VALUE \"FileDescription\", \"PE Viewer\"\n+            VALUE \"FileVersion\", PHAPP_VERSION_STRING\n+            VALUE \"InternalName\", \"peview\"\n+            VALUE \"LegalCopyright\", \"Licensed under the GNU GPL, v3.\"\n+            VALUE \"OriginalFilename\", \"peview.exe\"\n+            VALUE \"ProductName\", \"Process Hacker\"\n+            VALUE \"ProductVersion\", PHAPP_VERSION_STRING\n+        END\n+    END\n+    BLOCK \"VarFileInfo\"\n+    BEGIN\n+        VALUE \"Translation\", 0xc09, 1200\n+    END\n+END\n-- \n2.9.3.windows.1\n\n"
  },
  {
    "path": "third_party/Ph-dc6a8a94f7e4b381090b46eb8e1b9fd7de052dbe-__acrt_fp_format-bug-and-specify-CLR-compilation.patch",
    "content": "From 530569dbacff0ac42516d64719b983ba04503919 Mon Sep 17 00:00:00 2001\nFrom: lucasg <lucas.georges@outlook.com>\nDate: Sat, 22 Jul 2017 13:20:59 +0200\nSubject: [PATCH] Fix __acrt_fp_format bug and specify CLR compilation\n\n---\n phlib/format.c                    |  5 ++++-\n phlib/format_i.h                  |  9 ---------\n phlib/include/phbase.h            | 12 +++++++++---\n phlib/native.c                    | 18 ------------------\n phlib/phlib.vcxproj               | 18 +++++++++---------\n phnt/include/ntexapi.h            |  9 +++++++--\n phnt/include/phnt_ntdef.h         |  4 +++-\n tools/peview/peview.rc            |  2 +-\n tools/peview/peview.vcxproj       | 34 +++++++++++++++++-----------------\n tools/peview/resources/phappres.h | 34 ++++++++++++++++++++++++++++++++++\n tools/peview/resources/phapprev.h |  6 ++++++\n tools/peview/version.rc           |  2 +-\n 12 files changed, 91 insertions(+), 62 deletions(-)\n create mode 100644 tools/peview/resources/phappres.h\n create mode 100644 tools/peview/resources/phapprev.h\n\ndiff --git a/phlib/format.c b/phlib/format.c\nindex b45fd38..b705370 100644\n--- a/phlib/format.c\n+++ b/phlib/format.c\n@@ -45,9 +45,10 @@ extern ULONG PhMaxSizeUnit;\n #define PHP_FORMAT_PAD 0x4\n \n // Internal CRT routine needed for floating-point conversion\n-\n+#if 0\n errno_t __cdecl _cfltcvt_l(double *arg, char *buffer, size_t sizeInBytes,\n     int format, int precision, int caps, _locale_t plocinfo);\n+#endif\n \n // Keep in sync with PhSizeUnitNames\n static PH_STRINGREF PhpSizeUnitNamesCounted[7] =\n@@ -66,6 +67,7 @@ static WCHAR PhpFormatDecimalSeparator = '.';\n static WCHAR PhpFormatThousandSeparator = ',';\n static _locale_t PhpFormatUserLocale = NULL;\n \n+#if 0\n #if (_MSC_VER >= 1900)\n \n // See Source\\10.0.10150.0\\ucrt\\convert\\cvt.cpp in SDK v10.\n@@ -94,6 +96,7 @@ static errno_t __cdecl _cfltcvt_l(double *arg, char *buffer, size_t sizeInBytes,\n }\n \n #endif\n+#endif\n \n // From Source\\10.0.10150.0\\ucrt\\inc\\corecrt_internal_stdio_output.h in SDK v10.\n VOID PhpCropZeros(\ndiff --git a/phlib/format_i.h b/phlib/format_i.h\nindex 31a5771..e98d3a0 100644\n--- a/phlib/format_i.h\n+++ b/phlib/format_i.h\n@@ -311,15 +311,6 @@ CommonInt64Format:\n         \\\n         value = (Format)->u.Double; \\\n         temp = (PSTR)tempBuffer + 1; /* leave one character so we can insert a prefix if needed */ \\\n-        _cfltcvt_l( \\\n-            &value, \\\n-            temp, \\\n-            sizeof(tempBuffer) - 1, \\\n-            c, \\\n-            precision, \\\n-            !!((Format)->Type & FormatUpperCase), \\\n-            PhpFormatUserLocale \\\n-            ); \\\n         \\\n         /* if (((Format)->Type & FormatForceDecimalPoint) && precision == 0) */ \\\n              /* _forcdecpt_l(tempBufferAnsi, PhpFormatUserLocale); */ \\\ndiff --git a/phlib/include/phbase.h b/phlib/include/phbase.h\nindex 15ad67e..3a40f2a 100644\n--- a/phlib/include/phbase.h\n+++ b/phlib/include/phbase.h\n@@ -17,11 +17,17 @@\n #define _CRT_SECURE_NO_WARNINGS\n #endif\n \n-#if !defined(_PHLIB_)\n+#if defined(_PHLIB_)\n+#define PHLIBAPI\n+#elif defined(_PHDLL_)\n+#define PHLIBAPI __declspec(dllexport)\n+#else\n+#if defined(__cplusplus)\n #define PHLIBAPI __declspec(dllimport)\n #else\n-#define PHLIBAPI\n-#endif\n+#define PHLIBAPI \n+#endif //  defined(__cplusplus)\n+#endif //  defined(_PHLIB_)\n \n #include <phnt_windows.h>\n #include <phnt.h>\ndiff --git a/phlib/native.c b/phlib/native.c\nindex 056c2a6..6a70c8f 100644\n--- a/phlib/native.c\n+++ b/phlib/native.c\n@@ -3136,24 +3136,6 @@ BOOLEAN NTAPI PhpEnumProcessModulesCallback(\n         }\n     }\n \n-    if (WindowsVersion >= WINDOWS_8)\n-    {\n-        LDR_DDAG_NODE ldrDagNode = { 0 };\n-\n-        if (NT_SUCCESS(NtReadVirtualMemory(\n-            ProcessHandle,\n-            Entry->DdagNode,\n-            &ldrDagNode,\n-            sizeof(LDR_DDAG_NODE),\n-            NULL\n-            )))\n-        {\n-            // HACK: Fixup the module load count (64bit only).\n-            // Temp fix until PhpModuleQueryWorker can be updated with Stage2. \n-            Entry->ObsoleteLoadCount = (USHORT)ldrDagNode.LoadCount;\n-        }\n-    }\n-\n     // Execute the callback.\n     cont = parameters->Callback(Entry, parameters->Context);\n \ndiff --git a/phlib/phlib.vcxproj b/phlib/phlib.vcxproj\nindex cf67c67..257d0f2 100644\n--- a/phlib/phlib.vcxproj\n+++ b/phlib/phlib.vcxproj\n@@ -1,4 +1,4 @@\n-<?xml version=\"1.0\" encoding=\"utf-8\"?>\n+﻿<?xml version=\"1.0\" encoding=\"utf-8\"?>\n <Project DefaultTargets=\"Build\" ToolsVersion=\"15.0\" xmlns=\"http://schemas.microsoft.com/developer/msbuild/2003\">\n   <ItemGroup Label=\"ProjectConfigurations\">\n     <ProjectConfiguration Include=\"Debug|Win32\">\n@@ -64,14 +64,14 @@\n   </ImportGroup>\n   <PropertyGroup Label=\"UserMacros\" />\n   <PropertyGroup>\n-    <OutDir Condition=\"'$(Configuration)|$(Platform)'=='Debug|Win32'\">$(ProjectDir)bin\\$(Configuration)$(PlatformArchitecture)\\</OutDir>\n-    <IntDir Condition=\"'$(Configuration)|$(Platform)'=='Debug|Win32'\">$(ProjectDir)obj\\$(Configuration)$(PlatformArchitecture)\\</IntDir>\n-    <OutDir Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">$(ProjectDir)bin\\$(Configuration)$(PlatformArchitecture)\\</OutDir>\n-    <IntDir Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">$(ProjectDir)obj\\$(Configuration)$(PlatformArchitecture)\\</IntDir>\n-    <OutDir Condition=\"'$(Configuration)|$(Platform)'=='Release|Win32'\">$(ProjectDir)bin\\$(Configuration)$(PlatformArchitecture)\\</OutDir>\n-    <IntDir Condition=\"'$(Configuration)|$(Platform)'=='Release|Win32'\">$(ProjectDir)obj\\$(Configuration)$(PlatformArchitecture)\\</IntDir>\n-    <OutDir Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\">$(ProjectDir)bin\\$(Configuration)$(PlatformArchitecture)\\</OutDir>\n-    <IntDir Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\">$(ProjectDir)obj\\$(Configuration)$(PlatformArchitecture)\\</IntDir>\n+    <OutDir Condition=\"'$(Configuration)|$(Platform)'=='Debug|Win32'\">$(SolutionDir)bin\\$(Configuration)$(PlatformArchitecture)\\</OutDir>\n+    <IntDir Condition=\"'$(Configuration)|$(Platform)'=='Debug|Win32'\">$(SolutionDir)obj\\$(ProjectName)\\$(Configuration)$(PlatformArchitecture)\\</IntDir>\n+    <OutDir Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">$(SolutionDir)bin\\$(Configuration)$(PlatformArchitecture)\\</OutDir>\n+    <IntDir Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">$(SolutionDir)obj\\$(ProjectName)\\$(Configuration)$(PlatformArchitecture)\\</IntDir>\n+    <OutDir Condition=\"'$(Configuration)|$(Platform)'=='Release|Win32'\">$(SolutionDir)bin\\$(Configuration)$(PlatformArchitecture)\\</OutDir>\n+    <IntDir Condition=\"'$(Configuration)|$(Platform)'=='Release|Win32'\">$(SolutionDir)obj\\$(ProjectName)\\$(Configuration)$(PlatformArchitecture)\\</IntDir>\n+    <OutDir Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\">$(SolutionDir)bin\\$(Configuration)$(PlatformArchitecture)\\</OutDir>\n+    <IntDir Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\">$(SolutionDir)obj\\$(ProjectName)\\$(Configuration)$(PlatformArchitecture)\\</IntDir>\n   </PropertyGroup>\n   <ItemDefinitionGroup Condition=\"'$(Configuration)|$(Platform)'=='Debug|Win32'\">\n     <ClCompile>\ndiff --git a/phnt/include/ntexapi.h b/phnt/include/ntexapi.h\nindex 8fad61a..5b9ab96 100644\n--- a/phnt/include/ntexapi.h\n+++ b/phnt/include/ntexapi.h\n@@ -3138,7 +3138,9 @@ FORCEINLINE ULONGLONG NtGetTickCount64()\n         if (tickCount.HighPart == (ULONG)USER_SHARED_DATA->TickCount.High2Time)\n             break;\n \n-        YieldProcessor();\n+#ifndef _MANAGED\n+\t\tYieldProcessor();\n+#endif // !_MANAGED\n     }\n \n #endif\n@@ -3165,7 +3167,10 @@ FORCEINLINE ULONG NtGetTickCount()\n         if (tickCount.HighPart == (ULONG)USER_SHARED_DATA->TickCount.High2Time)\n             break;\n \n-        YieldProcessor();\n+#ifndef _MANAGED\n+\t\tYieldProcessor();\n+#endif // !_MANAGED\n+        \n     }\n \n     return (ULONG)((UInt32x32To64(tickCount.LowPart, USER_SHARED_DATA->TickCountMultiplier) >> 24) +\ndiff --git a/phnt/include/phnt_ntdef.h b/phnt/include/phnt_ntdef.h\nindex 36cc781..93f911d 100644\n--- a/phnt/include/phnt_ntdef.h\n+++ b/phnt/include/phnt_ntdef.h\n@@ -71,7 +71,9 @@ typedef LARGE_INTEGER PHYSICAL_ADDRESS, *PPHYSICAL_ADDRESS;\n \n // Functions\n \n-#ifndef _WIN64\n+#ifdef _MANAGED\n+#define FASTCALL __stdcall\n+#elif !defined(_WIN64)\n #define FASTCALL __fastcall\n #else\n #define FASTCALL\ndiff --git a/tools/peview/peview.rc b/tools/peview/peview.rc\nindex 4a1db83..8d373fb 100644\n--- a/tools/peview/peview.rc\n+++ b/tools/peview/peview.rc\n@@ -8,7 +8,7 @@\n // Generated from the TEXTINCLUDE 2 resource.\n //\n #include \"winres.h\"\n-#include \"../../ProcessHacker/include/phappres.h\"\n+#include \"resources/phappres.h\"\n /////////////////////////////////////////////////////////////////////////////\n #undef APSTUDIO_READONLY_SYMBOLS\n \ndiff --git a/tools/peview/peview.vcxproj b/tools/peview/peview.vcxproj\nindex 1ce6cc5..6a51635 100644\n--- a/tools/peview/peview.vcxproj\n+++ b/tools/peview/peview.vcxproj\n@@ -65,16 +65,16 @@\n   <PropertyGroup Label=\"UserMacros\" />\n   <PropertyGroup>\n     <OutDir Condition=\"'$(Configuration)|$(Platform)'=='Debug|Win32'\">$(SolutionDir)bin\\$(Configuration)$(PlatformArchitecture)\\</OutDir>\n-    <IntDir Condition=\"'$(Configuration)|$(Platform)'=='Debug|Win32'\">$(ProjectDir)obj\\$(Configuration)$(PlatformArchitecture)\\</IntDir>\n+    <IntDir Condition=\"'$(Configuration)|$(Platform)'=='Debug|Win32'\">$(SolutionDir)obj\\$(ProjectName)\\$(Configuration)$(PlatformArchitecture)\\</IntDir>\n     <LinkIncremental Condition=\"'$(Configuration)|$(Platform)'=='Debug|Win32'\">false</LinkIncremental>\n     <OutDir Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">$(SolutionDir)bin\\$(Configuration)$(PlatformArchitecture)\\</OutDir>\n-    <IntDir Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">$(ProjectDir)obj\\$(Configuration)$(PlatformArchitecture)\\</IntDir>\n+    <IntDir Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">$(SolutionDir)obj\\$(ProjectName)\\$(Configuration)$(PlatformArchitecture)\\</IntDir>\n     <LinkIncremental Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">false</LinkIncremental>\n     <OutDir Condition=\"'$(Configuration)|$(Platform)'=='Release|Win32'\">$(SolutionDir)bin\\$(Configuration)$(PlatformArchitecture)\\</OutDir>\n-    <IntDir Condition=\"'$(Configuration)|$(Platform)'=='Release|Win32'\">$(ProjectDir)obj\\$(Configuration)$(PlatformArchitecture)\\</IntDir>\n+    <IntDir Condition=\"'$(Configuration)|$(Platform)'=='Release|Win32'\">$(SolutionDir)obj\\$(ProjectName)\\$(Configuration)$(PlatformArchitecture)\\</IntDir>\n     <LinkIncremental Condition=\"'$(Configuration)|$(Platform)'=='Release|Win32'\">false</LinkIncremental>\n     <OutDir Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\">$(SolutionDir)bin\\$(Configuration)$(PlatformArchitecture)\\</OutDir>\n-    <IntDir Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\">$(ProjectDir)obj\\$(Configuration)$(PlatformArchitecture)\\</IntDir>\n+    <IntDir Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\">$(SolutionDir)obj\\$(ProjectName)\\$(Configuration)$(PlatformArchitecture)\\</IntDir>\n     <LinkIncremental Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\">false</LinkIncremental>\n   </PropertyGroup>\n   <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Debug|Win32'\" />\n@@ -84,7 +84,7 @@\n   <ItemDefinitionGroup Condition=\"'$(Configuration)|$(Platform)'=='Debug|Win32'\">\n     <ClCompile>\n       <Optimization>Disabled</Optimization>\n-      <AdditionalIncludeDirectories>..\\..\\phnt\\include;..\\..\\phlib\\include;include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>\n+      <AdditionalIncludeDirectories>$(SolutionDir)phlib\\phnt\\include;$(SolutionDir)phlib\\include;include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>\n       <PreprocessorDefinitions>_PHLIB_;_WINDOWS;WIN32;DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>\n       <BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks>\n       <RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>\n@@ -96,8 +96,8 @@\n       <StringPooling>true</StringPooling>\n     </ClCompile>\n     <Link>\n-      <AdditionalDependencies>noarg.obj;noenv.obj;phlib.lib;ntdll.lib;uxtheme.lib;windowscodecs.lib;%(AdditionalDependencies)</AdditionalDependencies>\n-      <AdditionalLibraryDirectories>..\\..\\phlib\\bin\\$(Configuration)$(PlatformArchitecture);%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>\n+      <AdditionalDependencies>noarg.obj;noenv.obj;$(OutputPath)phlib.lib;ntdll.lib;uxtheme.lib;windowscodecs.lib;%(AdditionalDependencies)</AdditionalDependencies>\n+      <AdditionalLibraryDirectories>%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>\n       <AdditionalManifestDependencies>\n       </AdditionalManifestDependencies>\n       <GenerateDebugInformation>true</GenerateDebugInformation>\n@@ -109,7 +109,7 @@\n   <ItemDefinitionGroup Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">\n     <ClCompile>\n       <Optimization>Disabled</Optimization>\n-      <AdditionalIncludeDirectories>..\\..\\phnt\\include;..\\..\\phlib\\include;include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>\n+      <AdditionalIncludeDirectories>$(SolutionDir)phlib\\phnt\\include;$(SolutionDir)phlib\\include;include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>\n       <PreprocessorDefinitions>_PHLIB_;_WINDOWS;WIN64;DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>\n       <BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks>\n       <RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>\n@@ -121,8 +121,8 @@\n       <StringPooling>true</StringPooling>\n     </ClCompile>\n     <Link>\n-      <AdditionalDependencies>noarg.obj;noenv.obj;phlib.lib;ntdll.lib;uxtheme.lib;windowscodecs.lib;%(AdditionalDependencies)</AdditionalDependencies>\n-      <AdditionalLibraryDirectories>..\\..\\phlib\\bin\\$(Configuration)$(PlatformArchitecture);%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>\n+      <AdditionalDependencies>noarg.obj;noenv.obj;$(OutputPath)phlib.lib;ntdll.lib;uxtheme.lib;windowscodecs.lib;%(AdditionalDependencies)</AdditionalDependencies>\n+      <AdditionalLibraryDirectories>%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>\n       <AdditionalManifestDependencies>\n       </AdditionalManifestDependencies>\n       <GenerateDebugInformation>true</GenerateDebugInformation>\n@@ -135,7 +135,7 @@\n     <ClCompile>\n       <Optimization>MaxSpeed</Optimization>\n       <IntrinsicFunctions>true</IntrinsicFunctions>\n-      <AdditionalIncludeDirectories>..\\..\\phnt\\include;..\\..\\phlib\\include;include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>\n+      <AdditionalIncludeDirectories>$(SolutionDir)phlib\\phnt\\include;$(SolutionDir)phlib\\include;include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>\n       <PreprocessorDefinitions>_PHLIB_;_WINDOWS;WIN32;NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>\n       <RuntimeLibrary>MultiThreaded</RuntimeLibrary>\n       <FunctionLevelLinking>true</FunctionLevelLinking>\n@@ -149,8 +149,8 @@\n       <SDLCheck>true</SDLCheck>\n     </ClCompile>\n     <Link>\n-      <AdditionalDependencies>noarg.obj;noenv.obj;phlib.lib;ntdll.lib;uxtheme.lib;windowscodecs.lib;%(AdditionalDependencies)</AdditionalDependencies>\n-      <AdditionalLibraryDirectories>..\\..\\phlib\\bin\\$(Configuration)$(PlatformArchitecture);%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>\n+      <AdditionalDependencies>noarg.obj;noenv.obj;$(OutputPath)phlib.lib;ntdll.lib;uxtheme.lib;windowscodecs.lib;%(AdditionalDependencies)</AdditionalDependencies>\n+      <AdditionalLibraryDirectories>%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>\n       <AdditionalManifestDependencies>\n       </AdditionalManifestDependencies>\n       <GenerateDebugInformation>true</GenerateDebugInformation>\n@@ -166,7 +166,7 @@\n     <ClCompile>\n       <Optimization>MaxSpeed</Optimization>\n       <IntrinsicFunctions>true</IntrinsicFunctions>\n-      <AdditionalIncludeDirectories>..\\..\\phnt\\include;..\\..\\phlib\\include;include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>\n+      <AdditionalIncludeDirectories>$(SolutionDir)phlib\\phnt\\include;$(SolutionDir)phlib\\include;include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>\n       <PreprocessorDefinitions>_PHLIB_;_WINDOWS;WIN64;DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>\n       <RuntimeLibrary>MultiThreaded</RuntimeLibrary>\n       <FunctionLevelLinking>true</FunctionLevelLinking>\n@@ -179,8 +179,8 @@\n       <SDLCheck>true</SDLCheck>\n     </ClCompile>\n     <Link>\n-      <AdditionalDependencies>noarg.obj;noenv.obj;phlib.lib;ntdll.lib;uxtheme.lib;windowscodecs.lib;%(AdditionalDependencies)</AdditionalDependencies>\n-      <AdditionalLibraryDirectories>..\\..\\phlib\\bin\\$(Configuration)$(PlatformArchitecture);%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>\n+      <AdditionalDependencies>noarg.obj;noenv.obj;$(OutputPath)phlib.lib;ntdll.lib;uxtheme.lib;windowscodecs.lib;%(AdditionalDependencies)</AdditionalDependencies>\n+      <AdditionalLibraryDirectories>%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>\n       <AdditionalManifestDependencies>\n       </AdditionalManifestDependencies>\n       <GenerateDebugInformation>true</GenerateDebugInformation>\n@@ -221,7 +221,7 @@\n     <ResourceCompile Include=\"version.rc\" />\n   </ItemGroup>\n   <ItemGroup>\n-    <ProjectReference Include=\"..\\..\\phlib\\phlib.vcxproj\">\n+    <ProjectReference Include=\"..\\phlib\\phlib.vcxproj\">\n       <Project>{477d0215-f252-41a1-874b-f27e3ea1ed17}</Project>\n       <ReferenceOutputAssembly>false</ReferenceOutputAssembly>\n     </ProjectReference>\ndiff --git a/tools/peview/resources/phappres.h b/tools/peview/resources/phappres.h\nnew file mode 100644\nindex 0000000..3f8215d\n--- /dev/null\n+++ b/tools/peview/resources/phappres.h\n@@ -0,0 +1,34 @@\n+// Notes:\n+// * Do not use /* comments */ since ISPP is buggy and it will throw an error.\n+\n+#ifndef PH_PHAPPRES_H\n+#define PH_PHAPPRES_H\n+\n+#include \"phapprev.h\"\n+\n+#define PHAPP_VERSION_MAJOR 3\n+#define PHAPP_VERSION_MINOR 0\n+#define PHAPP_VERSION_BUILD 0\n+\n+#if (PHAPP_VERSION_BUILD == 0)\n+#define TWO_DIGIT_VER   1\n+#else\n+#define THREE_DIGIT_VER 1\n+#endif\n+\n+#define DO_MAKE_STR(x) #x\n+#define MAKE_STR(x)    DO_MAKE_STR(x)\n+\n+#ifndef ISPP_INVOKED\n+\n+#if defined(TWO_DIGIT_VER)\n+#define PHAPP_VERSION_STRING MAKE_STR(PHAPP_VERSION_MAJOR) \".\" MAKE_STR(PHAPP_VERSION_MINOR) \".0\" \".\" MAKE_STR(PHAPP_VERSION_REVISION)\n+#elif defined(THREE_DIGIT_VER)\n+#define PHAPP_VERSION_STRING MAKE_STR(PHAPP_VERSION_MAJOR) \".\" MAKE_STR(PHAPP_VERSION_MINOR) \".\" MAKE_STR(PHAPP_VERSION_BUILD) \".\" MAKE_STR(PHAPP_VERSION_REVISION)\n+#endif\n+\n+#define PHAPP_VERSION_NUMBER PHAPP_VERSION_MAJOR,PHAPP_VERSION_MINOR,PHAPP_VERSION_BUILD,PHAPP_VERSION_REVISION\n+\n+#endif // ISPP_INVOKED\n+\n+#endif // PHAPPRES_H\ndiff --git a/tools/peview/resources/phapprev.h b/tools/peview/resources/phapprev.h\nnew file mode 100644\nindex 0000000..fc00f3f\n--- /dev/null\n+++ b/tools/peview/resources/phapprev.h\n@@ -0,0 +1,6 @@\n+#ifndef PHAPPREV_H \n+#define PHAPPREV_H \n+\n+#define PHAPP_VERSION_REVISION 618\n+\n+#endif // PHAPPREV_H\ndiff --git a/tools/peview/version.rc b/tools/peview/version.rc\nindex 1e412bb..47b7ac7 100644\n--- a/tools/peview/version.rc\n+++ b/tools/peview/version.rc\n@@ -1,5 +1,5 @@\n #include \"winres.h\"\n-#include \"../../ProcessHacker/include/phappres.h\"\n+#include \"resources/phappres.h\"\n \n VS_VERSION_INFO VERSIONINFO\n  FILEVERSION PHAPP_VERSION_NUMBER\n-- \n2.9.3.windows.1\n\n"
  },
  {
    "path": "third_party/demumble/CMakeLists.txt",
    "content": "cmake_minimum_required(VERSION 3.1.0 FATAL_ERROR)\nproject(demumble C CXX)\nadd_definitions(-D_LIBCXXABI_FUNC_VIS=)\n\n# TODO: Also do this for gcc once gcc 4.9 is common.\nif (UNIX AND CMAKE_GENERATOR STREQUAL \"Ninja\" AND\n    CMAKE_CXX_COMPILER_ID MATCHES \"Clang\")\n  set(CMAKE_C_FLAGS \"$CMAKE_C_FLAGS -fdiagnostics-color -Wall\")\n  set(CMAKE_CXX_FLAGS \"$CMAKE_CXX_FLAGS -fdiagnostics-color -Wall\")\nendif()\n\n# 10.9 chosen somewhat arbitrary; it's the first target where clang defaults\n# to libc++ and ld64 defaults to stripping __TEXT,__eh_frame.\nif (APPLE)\n  set(CMAKE_C_FLAGS \"$CMAKE_C_FLAGS -mmacosx-version-min=10.9\")\n  set(CMAKE_CXX_FLAGS \"$CMAKE_CXX_FLAGS -mmacosx-version-min=10.9\")\nendif()\n\n# This is apparently the simplest way to statically link the CRT in CMake:\nif (WIN32)\n  string(TOUPPER \"${CMAKE_BUILD_TYPE}\" build)\n  foreach(lang C CXX)\n    set(flag_var \"CMAKE_${lang}_FLAGS_${build}\")\n    if(${flag_var} MATCHES \"/MD\")\n      string(REGEX REPLACE \"/MD\" \"/MT\" ${flag_var} \"${${flag_var}}\")\n    endif()\n  endforeach()\nendif()\n\nadd_executable(demumble\n               demumble.cc\n               third_party/wine/undname.c\n               third_party/libcxxabi/cxa_demangle.cpp\n)\nset_target_properties(demumble PROPERTIES CXX_STANDARD 11\n                                          CXX_STANDARD_REQUIRED ON)\n"
  },
  {
    "path": "third_party/demumble/LICENSE",
    "content": "\n                                 Apache License\n                           Version 2.0, January 2010\n                        http://www.apache.org/licenses/\n\n   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION\n\n   1. Definitions.\n\n      \"License\" shall mean the terms and conditions for use, reproduction,\n      and distribution as defined by Sections 1 through 9 of this document.\n\n      \"Licensor\" shall mean the copyright owner or entity authorized by\n      the copyright owner that is granting the License.\n\n      \"Legal Entity\" shall mean the union of the acting entity and all\n      other entities that control, are controlled by, or are under common\n      control with that entity. For the purposes of this definition,\n      \"control\" means (i) the power, direct or indirect, to cause the\n      direction or management of such entity, whether by contract or\n      otherwise, or (ii) ownership of fifty percent (50%) or more of the\n      outstanding shares, or (iii) beneficial ownership of such entity.\n\n      \"You\" (or \"Your\") shall mean an individual or Legal Entity\n      exercising permissions granted by this License.\n\n      \"Source\" form shall mean the preferred form for making modifications,\n      including but not limited to software source code, documentation\n      source, and configuration files.\n\n      \"Object\" form shall mean any form resulting from mechanical\n      transformation or translation of a Source form, including but\n      not limited to compiled object code, generated documentation,\n      and conversions to other media types.\n\n      \"Work\" shall mean the work of authorship, whether in Source or\n      Object form, made available under the License, as indicated by a\n      copyright notice that is included in or attached to the work\n      (an example is provided in the Appendix below).\n\n      \"Derivative Works\" shall mean any work, whether in Source or Object\n      form, that is based on (or derived from) the Work and for which the\n      editorial revisions, annotations, elaborations, or other modifications\n      represent, as a whole, an original work of authorship. For the purposes\n      of this License, Derivative Works shall not include works that remain\n      separable from, or merely link (or bind by name) to the interfaces of,\n      the Work and Derivative Works thereof.\n\n      \"Contribution\" shall mean any work of authorship, including\n      the original version of the Work and any modifications or additions\n      to that Work or Derivative Works thereof, that is intentionally\n      submitted to Licensor for inclusion in the Work by the copyright owner\n      or by an individual or Legal Entity authorized to submit on behalf of\n      the copyright owner. For the purposes of this definition, \"submitted\"\n      means any form of electronic, verbal, or written communication sent\n      to the Licensor or its representatives, including but not limited to\n      communication on electronic mailing lists, source code control systems,\n      and issue tracking systems that are managed by, or on behalf of, the\n      Licensor for the purpose of discussing and improving the Work, but\n      excluding communication that is conspicuously marked or otherwise\n      designated in writing by the copyright owner as \"Not a Contribution.\"\n\n      \"Contributor\" shall mean Licensor and any individual or Legal Entity\n      on behalf of whom a Contribution has been received by Licensor and\n      subsequently incorporated within the Work.\n\n   2. Grant of Copyright License. Subject to the terms and conditions of\n      this License, each Contributor hereby grants to You a perpetual,\n      worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n      copyright license to reproduce, prepare Derivative Works of,\n      publicly display, publicly perform, sublicense, and distribute the\n      Work and such Derivative Works in Source or Object form.\n\n   3. Grant of Patent License. Subject to the terms and conditions of\n      this License, each Contributor hereby grants to You a perpetual,\n      worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n      (except as stated in this section) patent license to make, have made,\n      use, offer to sell, sell, import, and otherwise transfer the Work,\n      where such license applies only to those patent claims licensable\n      by such Contributor that are necessarily infringed by their\n      Contribution(s) alone or by combination of their Contribution(s)\n      with the Work to which such Contribution(s) was submitted. If You\n      institute patent litigation against any entity (including a\n      cross-claim or counterclaim in a lawsuit) alleging that the Work\n      or a Contribution incorporated within the Work constitutes direct\n      or contributory patent infringement, then any patent licenses\n      granted to You under this License for that Work shall terminate\n      as of the date such litigation is filed.\n\n   4. Redistribution. You may reproduce and distribute copies of the\n      Work or Derivative Works thereof in any medium, with or without\n      modifications, and in Source or Object form, provided that You\n      meet the following conditions:\n\n      (a) You must give any other recipients of the Work or\n          Derivative Works a copy of this License; and\n\n      (b) You must cause any modified files to carry prominent notices\n          stating that You changed the files; and\n\n      (c) You must retain, in the Source form of any Derivative Works\n          that You distribute, all copyright, patent, trademark, and\n          attribution notices from the Source form of the Work,\n          excluding those notices that do not pertain to any part of\n          the Derivative Works; and\n\n      (d) If the Work includes a \"NOTICE\" text file as part of its\n          distribution, then any Derivative Works that You distribute must\n          include a readable copy of the attribution notices contained\n          within such NOTICE file, excluding those notices that do not\n          pertain to any part of the Derivative Works, in at least one\n          of the following places: within a NOTICE text file distributed\n          as part of the Derivative Works; within the Source form or\n          documentation, if provided along with the Derivative Works; or,\n          within a display generated by the Derivative Works, if and\n          wherever such third-party notices normally appear. The contents\n          of the NOTICE file are for informational purposes only and\n          do not modify the License. You may add Your own attribution\n          notices within Derivative Works that You distribute, alongside\n          or as an addendum to the NOTICE text from the Work, provided\n          that such additional attribution notices cannot be construed\n          as modifying the License.\n\n      You may add Your own copyright statement to Your modifications and\n      may provide additional or different license terms and conditions\n      for use, reproduction, or distribution of Your modifications, or\n      for any such Derivative Works as a whole, provided Your use,\n      reproduction, and distribution of the Work otherwise complies with\n      the conditions stated in this License.\n\n   5. Submission of Contributions. Unless You explicitly state otherwise,\n      any Contribution intentionally submitted for inclusion in the Work\n      by You to the Licensor shall be under the terms and conditions of\n      this License, without any additional terms or conditions.\n      Notwithstanding the above, nothing herein shall supersede or modify\n      the terms of any separate license agreement you may have executed\n      with Licensor regarding such Contributions.\n\n   6. Trademarks. This License does not grant permission to use the trade\n      names, trademarks, service marks, or product names of the Licensor,\n      except as required for reasonable and customary use in describing the\n      origin of the Work and reproducing the content of the NOTICE file.\n\n   7. Disclaimer of Warranty. Unless required by applicable law or\n      agreed to in writing, Licensor provides the Work (and each\n      Contributor provides its Contributions) on an \"AS IS\" BASIS,\n      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or\n      implied, including, without limitation, any warranties or conditions\n      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A\n      PARTICULAR PURPOSE. You are solely responsible for determining the\n      appropriateness of using or redistributing the Work and assume any\n      risks associated with Your exercise of permissions under this License.\n\n   8. Limitation of Liability. In no event and under no legal theory,\n      whether in tort (including negligence), contract, or otherwise,\n      unless required by applicable law (such as deliberate and grossly\n      negligent acts) or agreed to in writing, shall any Contributor be\n      liable to You for damages, including any direct, indirect, special,\n      incidental, or consequential damages of any character arising as a\n      result of this License or out of the use or inability to use the\n      Work (including but not limited to damages for loss of goodwill,\n      work stoppage, computer failure or malfunction, or any and all\n      other commercial damages or losses), even if such Contributor\n      has been advised of the possibility of such damages.\n\n   9. Accepting Warranty or Additional Liability. While redistributing\n      the Work or Derivative Works thereof, You may choose to offer,\n      and charge a fee for, acceptance of support, warranty, indemnity,\n      or other liability obligations and/or rights consistent with this\n      License. However, in accepting such obligations, You may act only\n      on Your own behalf and on Your sole responsibility, not on behalf\n      of any other Contributor, and only if You agree to indemnify,\n      defend, and hold each Contributor harmless for any liability\n      incurred by, or claims asserted against, such Contributor by reason\n      of your accepting any such warranty or additional liability.\n\n   END OF TERMS AND CONDITIONS\n\n   APPENDIX: How to apply the Apache License to your work.\n\n      To apply the Apache License to your work, attach the following\n      boilerplate notice, with the fields enclosed by brackets \"[]\"\n      replaced with your own identifying information. (Don't include\n      the brackets!)  The text should be enclosed in the appropriate\n      comment syntax for the file format. We also recommend that a\n      file or class name and description of purpose be included on the\n      same \"printed page\" as the copyright notice for easier\n      identification within third-party archives.\n\n   Copyright [yyyy] [name of copyright owner]\n\n   Licensed under the Apache License, Version 2.0 (the \"License\");\n   you may not use this file except in compliance with the License.\n   You may obtain a copy of the License at\n\n       http://www.apache.org/licenses/LICENSE-2.0\n\n   Unless required by applicable law or agreed to in writing, software\n   distributed under the License is distributed on an \"AS IS\" BASIS,\n   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n   See the License for the specific language governing permissions and\n   limitations under the License.\n"
  },
  {
    "path": "third_party/demumble/README.md",
    "content": "# demumble\n\n`demumble` demangles both POSIX and Visual Studio symbols. It runs on both\nPOSIX and Windows.\n\n    $ ./demumble _Z4funcPci\n    func(char*, int)\n    $ ./demumble \"?Fx_i@@YAHP6AHH@Z@Z\"\n    int __cdecl Fx_i(int (__cdecl*)(int))\n    \n## Download\n\nThere are prebuilt x64 binaries for Linux, Mac (10.9+), and Windows on the\n[releases page](https://github.com/nico/demumble/releases).\n\n## But why\n\nIt has several nice features that c++filt lacks (and lacks many of c++filt's\nfeatures I never use).\n\nSmart about underscores: C++ symbols have an additional leading underscore on\nOS X. `operator new` is mangled as `_Znw` on Linux but `__Znw` on Mac. OS X's\nc++filt automatically strips one leading underscore, but Linux's c++filt\ndoesn't. So if you want to demangle a Linux symbol on OS X, you need to pass\n`-n` to tell it to not strip the underscore, and if you want to demangle an OS\nX symbol on Linux you likewise need to pass `-_`. demumble just does the right\nthing:\n\n    $ c++filt _Znw\n    _Znw\n    $ c++filt __Znw\n    operator new\n    $ demumble _Znw\n    operator new\n    $ demumble __Znw\n    operator new\n\nSmart about filtering: Both c++filt and demumble can work as a stdin filter.\ndemumble only demangles function symbols (which never look like other words),\nwhile c++filt defaults to demangling type names too, which are likely to look\nlike regular words. demumble does demangle types when they're passed as args:\n\n    $ echo 'I like Pi and _Znw' | c++filt\n    I like int* and _Znw\n    $ echo 'I like Pi and _Znw' | demumble\n    I like Pi and operator new\n    $ c++filt Pi\n    int*\n    $ demumble Pi\n    int*\n\nCross-platform: demumble runs on Windows. demumble can demangle Windows-style\nsymbols (also when running on non-Windows).\n\n    $ demumble '??2@YAPEAX_K@Z'\n    void * __ptr64 __cdecl operator new(unsigned __int64)\n    $ c++filt '??2@YAPEAX_K@Z'\n    ??2@YAPEAX_K@Z\n\ndemumble also has a flag to make it print only things that look like symbols.\nFor example, print demangled names of all functions defined in a bitcode file:\n\n    $ grep '^define' bitcode-win.ll  | demumble -m | head -1\n    unsigned int __cdecl v8::RoundUpToPowerOfTwo32(unsigned int)\n\n## Build instructions\n\nUse cmake to build: `cmake -G Ninja && ninja`\n\nRun tests after building: `python demumble_test.py`\n\n`cxa_demangle.cpp` needs more C++11 than Visual Studio 2013 supports, so\nto build on Windows you need to use Visual Studion 2015 or use clang-cl\nas C++ compiler like so:\n\n    cmake -G Ninja -DCMAKE_CXX_COMPILER=path/to/llvm-build/bin/clang-cl.exe\n"
  },
  {
    "path": "third_party/demumble/RELEASING",
    "content": "Push new release branch:\n1. Make sure branches 'master' and 'release' are synced up locally\n2. update src/demumble.cc with new version (with \".git\"), then\n       git commit -am 'mark this 1.0.0.git'\n3. git checkout release; git merge master\n4. fix version number in src/version.cc (it will likely conflict in the above)\n5. commit, tag, push (don't forget to push --tags)\n       git commit -am v1.0.0; git push origin release\n       git tag v1.0.0; git push --tags\n       # Push the 1.0.0.git change on master too:\n       git checkout master; git push origin master\n6. Add binaries to https://github.com/nico/demumble/releases\n   Build them with `-DCMAKE_BUILD_TYPE=Release`, strip after building.\n"
  },
  {
    "path": "third_party/demumble/demumble.vcxproj",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<Project DefaultTargets=\"Build\" ToolsVersion=\"15.0\" xmlns=\"http://schemas.microsoft.com/developer/msbuild/2003\">\n  <ItemGroup Label=\"ProjectConfigurations\">\n    <ProjectConfiguration Include=\"Appx|Win32\">\n      <Configuration>Appx</Configuration>\n      <Platform>Win32</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"Appx|x64\">\n      <Configuration>Appx</Configuration>\n      <Platform>x64</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"Debug|Win32\">\n      <Configuration>Debug</Configuration>\n      <Platform>Win32</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"Release|Win32\">\n      <Configuration>Release</Configuration>\n      <Platform>Win32</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"Debug|x64\">\n      <Configuration>Debug</Configuration>\n      <Platform>x64</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"Release|x64\">\n      <Configuration>Release</Configuration>\n      <Platform>x64</Platform>\n    </ProjectConfiguration>\n  </ItemGroup>\n  <PropertyGroup Label=\"Globals\">\n    <VCProjectVersion>15.0</VCProjectVersion>\n    <ProjectGuid>{BE4A9759-A412-44CB-887D-FEFBEF1ABBF1}</ProjectGuid>\n    <RootNamespace>demumble</RootNamespace>\n    <WindowsTargetPlatformVersion>10.0</WindowsTargetPlatformVersion>\n  </PropertyGroup>\n  <Import Project=\"$(VCTargetsPath)\\Microsoft.Cpp.Default.props\" />\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Debug|Win32'\" Label=\"Configuration\">\n    <ConfigurationType>StaticLibrary</ConfigurationType>\n    <UseDebugLibraries>true</UseDebugLibraries>\n    <PlatformToolset>v142</PlatformToolset>\n    <CharacterSet>MultiByte</CharacterSet>\n    <SpectreMitigation>false</SpectreMitigation>\n  </PropertyGroup>\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Release|Win32'\" Label=\"Configuration\">\n    <ConfigurationType>StaticLibrary</ConfigurationType>\n    <UseDebugLibraries>false</UseDebugLibraries>\n    <PlatformToolset>v142</PlatformToolset>\n    <WholeProgramOptimization>true</WholeProgramOptimization>\n    <CharacterSet>MultiByte</CharacterSet>\n    <SpectreMitigation>false</SpectreMitigation>\n  </PropertyGroup>\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Appx|Win32'\" Label=\"Configuration\">\n    <ConfigurationType>StaticLibrary</ConfigurationType>\n    <UseDebugLibraries>false</UseDebugLibraries>\n    <PlatformToolset>v142</PlatformToolset>\n    <WholeProgramOptimization>true</WholeProgramOptimization>\n    <CharacterSet>MultiByte</CharacterSet>\n    <SpectreMitigation>false</SpectreMitigation>\n  </PropertyGroup>\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\" Label=\"Configuration\">\n    <ConfigurationType>StaticLibrary</ConfigurationType>\n    <UseDebugLibraries>true</UseDebugLibraries>\n    <PlatformToolset>v142</PlatformToolset>\n    <CharacterSet>MultiByte</CharacterSet>\n    <SpectreMitigation>false</SpectreMitigation>\n  </PropertyGroup>\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\" Label=\"Configuration\">\n    <ConfigurationType>StaticLibrary</ConfigurationType>\n    <UseDebugLibraries>false</UseDebugLibraries>\n    <PlatformToolset>v142</PlatformToolset>\n    <WholeProgramOptimization>true</WholeProgramOptimization>\n    <CharacterSet>MultiByte</CharacterSet>\n    <SpectreMitigation>false</SpectreMitigation>\n  </PropertyGroup>\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Appx|x64'\" Label=\"Configuration\">\n    <ConfigurationType>StaticLibrary</ConfigurationType>\n    <UseDebugLibraries>false</UseDebugLibraries>\n    <PlatformToolset>v142</PlatformToolset>\n    <WholeProgramOptimization>true</WholeProgramOptimization>\n    <CharacterSet>MultiByte</CharacterSet>\n    <SpectreMitigation>false</SpectreMitigation>\n  </PropertyGroup>\n  <Import Project=\"$(VCTargetsPath)\\Microsoft.Cpp.props\" />\n  <ImportGroup Label=\"ExtensionSettings\">\n  </ImportGroup>\n  <ImportGroup Label=\"Shared\">\n  </ImportGroup>\n  <ImportGroup Label=\"PropertySheets\" Condition=\"'$(Configuration)|$(Platform)'=='Debug|Win32'\">\n    <Import Project=\"$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props\" Condition=\"exists('$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props')\" Label=\"LocalAppDataPlatform\" />\n  </ImportGroup>\n  <ImportGroup Label=\"PropertySheets\" Condition=\"'$(Configuration)|$(Platform)'=='Release|Win32'\">\n    <Import Project=\"$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props\" Condition=\"exists('$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props')\" Label=\"LocalAppDataPlatform\" />\n  </ImportGroup>\n  <ImportGroup Condition=\"'$(Configuration)|$(Platform)'=='Appx|Win32'\" Label=\"PropertySheets\">\n    <Import Project=\"$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props\" Condition=\"exists('$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props')\" Label=\"LocalAppDataPlatform\" />\n  </ImportGroup>\n  <ImportGroup Label=\"PropertySheets\" Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">\n    <Import Project=\"$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props\" Condition=\"exists('$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props')\" Label=\"LocalAppDataPlatform\" />\n  </ImportGroup>\n  <ImportGroup Label=\"PropertySheets\" Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\">\n    <Import Project=\"$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props\" Condition=\"exists('$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props')\" Label=\"LocalAppDataPlatform\" />\n  </ImportGroup>\n  <ImportGroup Condition=\"'$(Configuration)|$(Platform)'=='Appx|x64'\" Label=\"PropertySheets\">\n    <Import Project=\"$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props\" Condition=\"exists('$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props')\" Label=\"LocalAppDataPlatform\" />\n  </ImportGroup>\n  <PropertyGroup Label=\"UserMacros\" />\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Debug|Win32'\">\n    <IntDir>$(SolutionDir)obj\\$(ProjectName)\\$(Configuration)$(PlatformArchitecture)\\</IntDir>\n    <OutDir>$(SolutionDir)bin\\$(Configuration)$(PlatformArchitecture)\\</OutDir>\n  </PropertyGroup>\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Release|Win32'\">\n    <IntDir>$(SolutionDir)obj\\$(ProjectName)\\$(Configuration)$(PlatformArchitecture)\\</IntDir>\n    <OutDir>$(SolutionDir)bin\\$(Configuration)$(PlatformArchitecture)\\</OutDir>\n  </PropertyGroup>\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Appx|Win32'\">\n    <IntDir>$(SolutionDir)obj\\$(ProjectName)\\$(Configuration)$(PlatformArchitecture)\\</IntDir>\n    <OutDir>$(SolutionDir)bin\\$(Configuration)$(PlatformArchitecture)\\</OutDir>\n  </PropertyGroup>\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">\n    <IntDir>$(SolutionDir)obj\\$(ProjectName)\\$(Configuration)$(PlatformArchitecture)\\</IntDir>\n    <OutDir>$(SolutionDir)bin\\$(Configuration)$(PlatformArchitecture)\\</OutDir>\n  </PropertyGroup>\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\">\n    <IntDir>$(SolutionDir)obj\\$(ProjectName)\\$(Configuration)$(PlatformArchitecture)\\</IntDir>\n    <OutDir>$(SolutionDir)bin\\$(Configuration)$(PlatformArchitecture)\\</OutDir>\n  </PropertyGroup>\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Appx|x64'\">\n    <IntDir>$(SolutionDir)obj\\$(ProjectName)\\$(Configuration)$(PlatformArchitecture)\\</IntDir>\n    <OutDir>$(SolutionDir)bin\\$(Configuration)$(PlatformArchitecture)\\</OutDir>\n  </PropertyGroup>\n  <ItemDefinitionGroup Condition=\"'$(Configuration)|$(Platform)'=='Debug|Win32'\">\n    <ClCompile>\n      <WarningLevel>Level3</WarningLevel>\n      <Optimization>Disabled</Optimization>\n      <SDLCheck>true</SDLCheck>\n      <ConformanceMode>true</ConformanceMode>\n      <PreprocessorDefinitions>_MBCS;_LIBCXXABI_FUNC_VIS=;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions>\n    </ClCompile>\n  </ItemDefinitionGroup>\n  <ItemDefinitionGroup Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">\n    <ClCompile>\n      <WarningLevel>Level3</WarningLevel>\n      <Optimization>Disabled</Optimization>\n      <SDLCheck>true</SDLCheck>\n      <ConformanceMode>true</ConformanceMode>\n      <PreprocessorDefinitions>_MBCS;_LIBCXXABI_FUNC_VIS=;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions>\n    </ClCompile>\n  </ItemDefinitionGroup>\n  <ItemDefinitionGroup Condition=\"'$(Configuration)|$(Platform)'=='Release|Win32'\">\n    <ClCompile>\n      <WarningLevel>Level3</WarningLevel>\n      <Optimization>MaxSpeed</Optimization>\n      <FunctionLevelLinking>true</FunctionLevelLinking>\n      <IntrinsicFunctions>true</IntrinsicFunctions>\n      <SDLCheck>true</SDLCheck>\n      <ConformanceMode>true</ConformanceMode>\n      <PreprocessorDefinitions>_MBCS;_LIBCXXABI_FUNC_VIS=;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions>\n    </ClCompile>\n    <Link>\n      <EnableCOMDATFolding>true</EnableCOMDATFolding>\n      <OptimizeReferences>true</OptimizeReferences>\n    </Link>\n  </ItemDefinitionGroup>\n  <ItemDefinitionGroup Condition=\"'$(Configuration)|$(Platform)'=='Appx|Win32'\">\n    <ClCompile>\n      <WarningLevel>Level3</WarningLevel>\n      <Optimization>MaxSpeed</Optimization>\n      <FunctionLevelLinking>true</FunctionLevelLinking>\n      <IntrinsicFunctions>true</IntrinsicFunctions>\n      <SDLCheck>true</SDLCheck>\n      <ConformanceMode>true</ConformanceMode>\n      <PreprocessorDefinitions>_MBCS;_LIBCXXABI_FUNC_VIS=;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions>\n    </ClCompile>\n    <Link>\n      <EnableCOMDATFolding>true</EnableCOMDATFolding>\n      <OptimizeReferences>true</OptimizeReferences>\n    </Link>\n  </ItemDefinitionGroup>\n  <ItemDefinitionGroup Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\">\n    <ClCompile>\n      <WarningLevel>Level3</WarningLevel>\n      <Optimization>MaxSpeed</Optimization>\n      <FunctionLevelLinking>true</FunctionLevelLinking>\n      <IntrinsicFunctions>true</IntrinsicFunctions>\n      <SDLCheck>true</SDLCheck>\n      <ConformanceMode>true</ConformanceMode>\n      <PreprocessorDefinitions>_MBCS;_LIBCXXABI_FUNC_VIS=;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions>\n    </ClCompile>\n    <Link>\n      <EnableCOMDATFolding>true</EnableCOMDATFolding>\n      <OptimizeReferences>true</OptimizeReferences>\n    </Link>\n  </ItemDefinitionGroup>\n  <ItemDefinitionGroup Condition=\"'$(Configuration)|$(Platform)'=='Appx|x64'\">\n    <ClCompile>\n      <WarningLevel>Level3</WarningLevel>\n      <Optimization>MaxSpeed</Optimization>\n      <FunctionLevelLinking>true</FunctionLevelLinking>\n      <IntrinsicFunctions>true</IntrinsicFunctions>\n      <SDLCheck>true</SDLCheck>\n      <ConformanceMode>true</ConformanceMode>\n      <PreprocessorDefinitions>_MBCS;_LIBCXXABI_FUNC_VIS=;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions>\n    </ClCompile>\n    <Link>\n      <EnableCOMDATFolding>true</EnableCOMDATFolding>\n      <OptimizeReferences>true</OptimizeReferences>\n    </Link>\n  </ItemDefinitionGroup>\n  <ItemGroup>\n    <ClCompile Include=\"third_party\\libcxxabi\\cxa_demangle.cpp\" />\n    <ClCompile Include=\"third_party\\wine\\undname.c\" />\n  </ItemGroup>\n  <Import Project=\"$(VCTargetsPath)\\Microsoft.Cpp.targets\" />\n  <ImportGroup Label=\"ExtensionTargets\">\n  </ImportGroup>\n</Project>"
  },
  {
    "path": "third_party/demumble/demumble.vcxproj.filters",
    "content": "﻿<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<Project ToolsVersion=\"4.0\" xmlns=\"http://schemas.microsoft.com/developer/msbuild/2003\">\n  <ItemGroup>\n    <Filter Include=\"Source Files\">\n      <UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier>\n      <Extensions>cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx</Extensions>\n    </Filter>\n    <Filter Include=\"Header Files\">\n      <UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier>\n      <Extensions>h;hh;hpp;hxx;hm;inl;inc;xsd</Extensions>\n    </Filter>\n    <Filter Include=\"Resource Files\">\n      <UniqueIdentifier>{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}</UniqueIdentifier>\n      <Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms</Extensions>\n    </Filter>\n  </ItemGroup>\n  <ItemGroup>\n    <ClCompile Include=\"third_party\\libcxxabi\\cxa_demangle.cpp\">\n      <Filter>Source Files</Filter>\n    </ClCompile>\n    <ClCompile Include=\"third_party\\wine\\undname.c\">\n      <Filter>Source Files</Filter>\n    </ClCompile>\n  </ItemGroup>\n</Project>"
  },
  {
    "path": "third_party/demumble/third_party/libcxxabi/LICENSE.txt",
    "content": "http://libcxxabi.llvm.org/\nAll of the code in libc++abi is dual licensed under the MIT license and the\nUIUC License (a BSD-like license).\n\nhttp://llvm.org/docs/DeveloperPolicy.html#license\n\n\nThe University of Illinois/NCSA Open Source License (NCSA)\n\nPermission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the \"Software\"), to deal with the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:\n\nRedistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimers.\nRedistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimers in the documentation and/or other materials provided with the distribution.\nNeither the names of <Name of Development Group, Name of Institution>, nor the names of its contributors may be used to endorse or promote products derived from this Software without specific prior written permission.\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE CONTRIBUTORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS WITH THE SOFTWARE.\n\n\n\nThe MIT License (MIT)\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in\nall copies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\nTHE SOFTWARE.\n"
  },
  {
    "path": "third_party/demumble/third_party/libcxxabi/cxa_demangle.cpp",
    "content": "//===-------------------------- cxa_demangle.cpp --------------------------===//\n//\n//                     The LLVM Compiler Infrastructure\n//\n// This file is dual licensed under the MIT and the University of Illinois Open\n// Source Licenses. See LICENSE.TXT for details.\n//\n//===----------------------------------------------------------------------===//\n\n#define _LIBCPP_EXTERN_TEMPLATE(...)\n#define _LIBCPP_NO_EXCEPTIONS\n\n#include <vector>\n#include <algorithm>\n#include <string>\n#include <numeric>\n#include <cstdlib>\n#include <cstring>\n#include <cctype>\n\n#ifdef _MSC_VER\n// snprintf is implemented in VS 2015\n#if _MSC_VER < 1900\n#define snprintf _snprintf_s\n#endif\n#endif\n\nnamespace __cxxabiv1\n{\n\nnamespace\n{\n\nenum\n{\n    unknown_error = -4,\n    invalid_args = -3,\n    invalid_mangled_name,\n    memory_alloc_failure,\n    success\n};\n\ntemplate <class C>\n    const char* parse_type(const char* first, const char* last, C& db);\ntemplate <class C>\n    const char* parse_encoding(const char* first, const char* last, C& db);\ntemplate <class C>\n    const char* parse_name(const char* first, const char* last, C& db,\n                           bool* ends_with_template_args = 0);\ntemplate <class C>\n    const char* parse_expression(const char* first, const char* last, C& db);\ntemplate <class C>\n    const char* parse_template_args(const char* first, const char* last, C& db);\ntemplate <class C>\n    const char* parse_operator_name(const char* first, const char* last, C& db);\ntemplate <class C>\n    const char* parse_unqualified_name(const char* first, const char* last, C& db);\ntemplate <class C>\n    const char* parse_decltype(const char* first, const char* last, C& db);\n\ntemplate <class C>\nvoid\nprint_stack(const C& db)\n{\n    fprintf(stderr, \"---------\\n\");\n    fprintf(stderr, \"names:\\n\");\n    for (auto& s : db.names)\n        fprintf(stderr, \"{%s#%s}\\n\", s.first.c_str(), s.second.c_str());\n    int i = -1;\n    fprintf(stderr, \"subs:\\n\");\n    for (auto& v : db.subs)\n    {\n        if (i >= 0)\n            fprintf(stderr, \"S%i_ = {\", i);\n        else\n            fprintf(stderr, \"S_  = {\");\n        for (auto& s : v)\n            fprintf(stderr, \"{%s#%s}\", s.first.c_str(), s.second.c_str());\n        fprintf(stderr, \"}\\n\");\n        ++i;\n    }\n    fprintf(stderr, \"template_param:\\n\");\n    for (auto& t : db.template_param)\n    {\n        fprintf(stderr, \"--\\n\");\n        i = -1;\n        for (auto& v : t)\n        {\n            if (i >= 0)\n                fprintf(stderr, \"T%i_ = {\", i);\n            else\n                fprintf(stderr, \"T_  = {\");\n            for (auto& s : v)\n                fprintf(stderr, \"{%s#%s}\", s.first.c_str(), s.second.c_str());\n            fprintf(stderr, \"}\\n\");\n            ++i;\n        }\n    }\n    fprintf(stderr, \"---------\\n\\n\");\n}\n\ntemplate <class C>\nvoid\nprint_state(const char* msg, const char* first, const char* last, const C& db)\n{\n    fprintf(stderr, \"%s: \", msg);\n    for (; first != last; ++first)\n        fprintf(stderr, \"%c\", *first);\n    fprintf(stderr, \"\\n\");\n    print_stack(db);\n}\n\n// <number> ::= [n] <non-negative decimal integer>\n\nconst char*\nparse_number(const char* first, const char* last)\n{\n    if (first != last)\n    {\n        const char* t = first;\n        if (*t == 'n')\n            ++t;\n        if (t != last)\n        {\n            if (*t == '0')\n            {\n                first = t+1;\n            }\n            else if ('1' <= *t && *t <= '9')\n            {\n                first = t+1;\n                while (first != last && std::isdigit(*first))\n                    ++first;\n            }\n        }\n    }\n    return first;\n}\n\ntemplate <class Float>\nstruct float_data;\n\ntemplate <>\nstruct float_data<float>\n{\n    static const size_t mangled_size = 8;\n    static const size_t max_demangled_size = 24;\n    static constexpr const char* spec = \"%af\";\n};\n\nconstexpr const char* float_data<float>::spec;\n\ntemplate <>\nstruct float_data<double>\n{\n    static const size_t mangled_size = 16;\n    static const size_t max_demangled_size = 32;\n    static constexpr const char* spec = \"%a\";\n};\n\nconstexpr const char* float_data<double>::spec;\n\ntemplate <>\nstruct float_data<long double>\n{\n#if defined(__mips__) && defined(__mips_n64) || defined(__aarch64__) || \\\n    defined(__wasm__)\n    static const size_t mangled_size = 32;\n#elif defined(__arm__) || defined(__mips__) || defined(__hexagon__)\n    static const size_t mangled_size = 16;\n#else\n    static const size_t mangled_size = 20;  // May need to be adjusted to 16 or 24 on other platforms\n#endif\n    static const size_t max_demangled_size = 40;\n    static constexpr const char* spec = \"%LaL\";\n};\n\nconstexpr const char* float_data<long double>::spec;\n\ntemplate <class Float, class C>\nconst char*\nparse_floating_number(const char* first, const char* last, C& db)\n{\n    const size_t N = float_data<Float>::mangled_size;\n    if (static_cast<std::size_t>(last - first) > N)\n    {\n        last = first + N;\n        union\n        {\n            Float value;\n            char buf[sizeof(Float)];\n        };\n        const char* t = first;\n        char* e = buf;\n        for (; t != last; ++t, ++e)\n        {\n            if (!isxdigit(*t))\n                return first;\n            unsigned d1 = isdigit(*t) ? static_cast<unsigned>(*t - '0') :\n                                        static_cast<unsigned>(*t - 'a' + 10);\n            ++t;\n            unsigned d0 = isdigit(*t) ? static_cast<unsigned>(*t - '0') :\n                                        static_cast<unsigned>(*t - 'a' + 10);\n            *e = static_cast<char>((d1 << 4) + d0);\n        }\n        if (*t == 'E')\n        {\n#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__\n            std::reverse(buf, e);\n#endif\n            char num[float_data<Float>::max_demangled_size] = {0};\n            int n = snprintf(num, sizeof(num), float_data<Float>::spec, value);\n            if (static_cast<std::size_t>(n) >= sizeof(num))\n                return first;\n            db.names.push_back(typename C::String(num, static_cast<std::size_t>(n)));\n            first = t+1;\n        }\n    }\n    return first;\n}\n\n// <source-name> ::= <positive length number> <identifier>\n\ntemplate <class C>\nconst char*\nparse_source_name(const char* first, const char* last, C& db)\n{\n    if (first != last)\n    {\n        char c = *first;\n        if (isdigit(c) && first+1 != last)\n        {\n            const char* t = first+1;\n            size_t n = static_cast<size_t>(c - '0');\n            for (c = *t; isdigit(c); c = *t)\n            {\n                n = n * 10 + static_cast<size_t>(c - '0');\n                if (++t == last)\n                    return first;\n            }\n            if (static_cast<size_t>(last - t) >= n)\n            {\n                typename C::String r(t, n);\n                if (r.substr(0, 10) == \"_GLOBAL__N\")\n                    db.names.push_back(\"(anonymous namespace)\");\n                else\n                    db.names.push_back(std::move(r));\n                first = t + n;\n            }\n        }\n    }\n    return first;\n}\n\n// <substitution> ::= S <seq-id> _\n//                ::= S_\n// <substitution> ::= Sa # ::std::allocator\n// <substitution> ::= Sb # ::std::basic_string\n// <substitution> ::= Ss # ::std::basic_string < char,\n//                                               ::std::char_traits<char>,\n//                                               ::std::allocator<char> >\n// <substitution> ::= Si # ::std::basic_istream<char,  std::char_traits<char> >\n// <substitution> ::= So # ::std::basic_ostream<char,  std::char_traits<char> >\n// <substitution> ::= Sd # ::std::basic_iostream<char, std::char_traits<char> >\n\ntemplate <class C>\nconst char*\nparse_substitution(const char* first, const char* last, C& db)\n{\n    if (last - first >= 2)\n    {\n        if (*first == 'S')\n        {\n            switch (first[1])\n            {\n            case 'a':\n                db.names.push_back(\"std::allocator\");\n                first += 2;\n                break;\n            case 'b':\n                db.names.push_back(\"std::basic_string\");\n                first += 2;\n                break;\n            case 's':\n                db.names.push_back(\"std::string\");\n                first += 2;\n                break;\n            case 'i':\n                db.names.push_back(\"std::istream\");\n                first += 2;\n                break;\n            case 'o':\n                db.names.push_back(\"std::ostream\");\n                first += 2;\n                break;\n            case 'd':\n                db.names.push_back(\"std::iostream\");\n                first += 2;\n                break;\n            case '_':\n                if (!db.subs.empty())\n                {\n                    for (const auto& n : db.subs.front())\n                        db.names.push_back(n);\n                    first += 2;\n                }\n                break;\n            default:\n                if (std::isdigit(first[1]) || std::isupper(first[1]))\n                {\n                    size_t sub = 0;\n                    const char* t = first+1;\n                    if (std::isdigit(*t))\n                        sub = static_cast<size_t>(*t - '0');\n                    else\n                        sub = static_cast<size_t>(*t - 'A') + 10;\n                    for (++t; t != last && (std::isdigit(*t) || std::isupper(*t)); ++t)\n                    {\n                        sub *= 36;\n                        if (std::isdigit(*t))\n                            sub += static_cast<size_t>(*t - '0');\n                        else\n                            sub += static_cast<size_t>(*t - 'A') + 10;\n                    }\n                    if (t == last || *t != '_')\n                        return first;\n                    ++sub;\n                    if (sub < db.subs.size())\n                    {\n                        for (const auto& n : db.subs[sub])\n                            db.names.push_back(n);\n                        first = t+1;\n                    }\n                }\n                break;\n            }\n        }\n    }\n    return first;\n}\n\n// <builtin-type> ::= v    # void\n//                ::= w    # wchar_t\n//                ::= b    # bool\n//                ::= c    # char\n//                ::= a    # signed char\n//                ::= h    # unsigned char\n//                ::= s    # short\n//                ::= t    # unsigned short\n//                ::= i    # int\n//                ::= j    # unsigned int\n//                ::= l    # long\n//                ::= m    # unsigned long\n//                ::= x    # long long, __int64\n//                ::= y    # unsigned long long, __int64\n//                ::= n    # __int128\n//                ::= o    # unsigned __int128\n//                ::= f    # float\n//                ::= d    # double\n//                ::= e    # long double, __float80\n//                ::= g    # __float128\n//                ::= z    # ellipsis\n//                ::= Dd   # IEEE 754r decimal floating point (64 bits)\n//                ::= De   # IEEE 754r decimal floating point (128 bits)\n//                ::= Df   # IEEE 754r decimal floating point (32 bits)\n//                ::= Dh   # IEEE 754r half-precision floating point (16 bits)\n//                ::= Di   # char32_t\n//                ::= Ds   # char16_t\n//                ::= Da   # auto (in dependent new-expressions)\n//                ::= Dc   # decltype(auto)\n//                ::= Dn   # std::nullptr_t (i.e., decltype(nullptr))\n//                ::= u <source-name>    # vendor extended type\n\ntemplate <class C>\nconst char*\nparse_builtin_type(const char* first, const char* last, C& db)\n{\n    if (first != last)\n    {\n        switch (*first)\n        {\n        case 'v':\n            db.names.push_back(\"void\");\n            ++first;\n            break;\n        case 'w':\n            db.names.push_back(\"wchar_t\");\n            ++first;\n            break;\n        case 'b':\n            db.names.push_back(\"bool\");\n            ++first;\n            break;\n        case 'c':\n            db.names.push_back(\"char\");\n            ++first;\n            break;\n        case 'a':\n            db.names.push_back(\"signed char\");\n            ++first;\n            break;\n        case 'h':\n            db.names.push_back(\"unsigned char\");\n            ++first;\n            break;\n        case 's':\n            db.names.push_back(\"short\");\n            ++first;\n            break;\n        case 't':\n            db.names.push_back(\"unsigned short\");\n            ++first;\n            break;\n        case 'i':\n            db.names.push_back(\"int\");\n            ++first;\n            break;\n        case 'j':\n            db.names.push_back(\"unsigned int\");\n            ++first;\n            break;\n        case 'l':\n            db.names.push_back(\"long\");\n            ++first;\n            break;\n        case 'm':\n            db.names.push_back(\"unsigned long\");\n            ++first;\n            break;\n        case 'x':\n            db.names.push_back(\"long long\");\n            ++first;\n            break;\n        case 'y':\n            db.names.push_back(\"unsigned long long\");\n            ++first;\n            break;\n        case 'n':\n            db.names.push_back(\"__int128\");\n            ++first;\n            break;\n        case 'o':\n            db.names.push_back(\"unsigned __int128\");\n            ++first;\n            break;\n        case 'f':\n            db.names.push_back(\"float\");\n            ++first;\n            break;\n        case 'd':\n            db.names.push_back(\"double\");\n            ++first;\n            break;\n        case 'e':\n            db.names.push_back(\"long double\");\n            ++first;\n            break;\n        case 'g':\n            db.names.push_back(\"__float128\");\n            ++first;\n            break;\n        case 'z':\n            db.names.push_back(\"...\");\n            ++first;\n            break;\n        case 'u':\n            {\n                const char*t = parse_source_name(first+1, last, db);\n                if (t != first+1)\n                    first = t;\n            }\n            break;\n        case 'D':\n            if (first+1 != last)\n            {\n                switch (first[1])\n                {\n                case 'd':\n                    db.names.push_back(\"decimal64\");\n                    first += 2;\n                    break;\n                case 'e':\n                    db.names.push_back(\"decimal128\");\n                    first += 2;\n                    break;\n                case 'f':\n                    db.names.push_back(\"decimal32\");\n                    first += 2;\n                    break;\n                case 'h':\n                    db.names.push_back(\"decimal16\");\n                    first += 2;\n                    break;\n                case 'i':\n                    db.names.push_back(\"char32_t\");\n                    first += 2;\n                    break;\n                case 's':\n                    db.names.push_back(\"char16_t\");\n                    first += 2;\n                    break;\n                case 'a':\n                    db.names.push_back(\"auto\");\n                    first += 2;\n                    break;\n                case 'c':\n                    db.names.push_back(\"decltype(auto)\");\n                    first += 2;\n                    break;\n                case 'n':\n                    db.names.push_back(\"std::nullptr_t\");\n                    first += 2;\n                    break;\n                }\n            }\n            break;\n        }\n    }\n    return first;\n}\n\n// <CV-qualifiers> ::= [r] [V] [K]\n\nconst char*\nparse_cv_qualifiers(const char* first, const char* last, unsigned& cv)\n{\n    cv = 0;\n    if (first != last)\n    {\n        if (*first == 'r')\n        {\n            cv |= 4;\n            ++first;\n        }\n        if (*first == 'V')\n        {\n            cv |= 2;\n            ++first;\n        }\n        if (*first == 'K')\n        {\n            cv |= 1;\n            ++first;\n        }\n    }\n    return first;\n}\n\n// <template-param> ::= T_    # first template parameter\n//                  ::= T <parameter-2 non-negative number> _\n\ntemplate <class C>\nconst char*\nparse_template_param(const char* first, const char* last, C& db)\n{\n    if (last - first >= 2)\n    {\n        if (*first == 'T')\n        {\n            if (first[1] == '_')\n            {\n                if (db.template_param.empty())\n                    return first;\n                if (!db.template_param.back().empty())\n                {\n                    for (auto& t : db.template_param.back().front())\n                        db.names.push_back(t);\n                    first += 2;\n                }\n                else\n                {\n                    db.names.push_back(\"T_\");\n                    first += 2;\n                    db.fix_forward_references = true;\n                }\n            }\n            else if (isdigit(first[1]))\n            {\n                const char* t = first+1;\n                size_t sub = static_cast<size_t>(*t - '0');\n                for (++t; t != last && isdigit(*t); ++t)\n                {\n                    sub *= 10;\n                    sub += static_cast<size_t>(*t - '0');\n                }\n                if (t == last || *t != '_' || db.template_param.empty())\n                    return first;\n                ++sub;\n                if (sub < db.template_param.back().size())\n                {\n                    for (auto& temp : db.template_param.back()[sub])\n                        db.names.push_back(temp);\n                    first = t+1;\n                }\n                else\n                {\n                    db.names.push_back(typename C::String(first, t+1));\n                    first = t+1;\n                    db.fix_forward_references = true;\n                }\n            }\n        }\n    }\n    return first;\n}\n\n// cc <type> <expression>                               # const_cast<type> (expression)\n\ntemplate <class C>\nconst char*\nparse_const_cast_expr(const char* first, const char* last, C& db)\n{\n    if (last - first >= 3 && first[0] == 'c' && first[1] == 'c')\n    {\n        const char* t = parse_type(first+2, last, db);\n        if (t != first+2)\n        {\n            const char* t1 = parse_expression(t, last, db);\n            if (t1 != t)\n            {\n                if (db.names.size() < 2)\n                    return first;\n                auto expr = db.names.back().move_full();\n                db.names.pop_back();\n                db.names.back() = \"const_cast<\" + db.names.back().move_full() + \">(\" + expr + \")\";\n                first = t1;\n            }\n        }\n    }\n    return first;\n}\n\n// dc <type> <expression>                               # dynamic_cast<type> (expression)\n\ntemplate <class C>\nconst char*\nparse_dynamic_cast_expr(const char* first, const char* last, C& db)\n{\n    if (last - first >= 3 && first[0] == 'd' && first[1] == 'c')\n    {\n        const char* t = parse_type(first+2, last, db);\n        if (t != first+2)\n        {\n            const char* t1 = parse_expression(t, last, db);\n            if (t1 != t)\n            {\n                if (db.names.size() < 2)\n                    return first;\n                auto expr = db.names.back().move_full();\n                db.names.pop_back();\n                db.names.back() = \"dynamic_cast<\" + db.names.back().move_full() + \">(\" + expr + \")\";\n                first = t1;\n            }\n        }\n    }\n    return first;\n}\n\n// rc <type> <expression>                               # reinterpret_cast<type> (expression)\n\ntemplate <class C>\nconst char*\nparse_reinterpret_cast_expr(const char* first, const char* last, C& db)\n{\n    if (last - first >= 3 && first[0] == 'r' && first[1] == 'c')\n    {\n        const char* t = parse_type(first+2, last, db);\n        if (t != first+2)\n        {\n            const char* t1 = parse_expression(t, last, db);\n            if (t1 != t)\n            {\n                if (db.names.size() < 2)\n                    return first;\n                auto expr = db.names.back().move_full();\n                db.names.pop_back();\n                db.names.back() = \"reinterpret_cast<\" + db.names.back().move_full() + \">(\" + expr + \")\";\n                first = t1;\n            }\n        }\n    }\n    return first;\n}\n\n// sc <type> <expression>                               # static_cast<type> (expression)\n\ntemplate <class C>\nconst char*\nparse_static_cast_expr(const char* first, const char* last, C& db)\n{\n    if (last - first >= 3 && first[0] == 's' && first[1] == 'c')\n    {\n        const char* t = parse_type(first+2, last, db);\n        if (t != first+2)\n        {\n            const char* t1 = parse_expression(t, last, db);\n            if (t1 != t)\n            {\n                if (db.names.size() < 2)\n                    return first;\n                auto expr = db.names.back().move_full();\n                db.names.pop_back();\n                db.names.back() = \"static_cast<\" + db.names.back().move_full() + \">(\" + expr + \")\";\n                first = t1;\n            }\n        }\n    }\n    return first;\n}\n\n// sp <expression>                                  # pack expansion\n\ntemplate <class C>\nconst char*\nparse_pack_expansion(const char* first, const char* last, C& db)\n{\n    if (last - first >= 3 && first[0] == 's' && first[1] == 'p')\n    {\n        const char* t = parse_expression(first+2, last, db);\n        if (t != first+2)\n            first = t;\n    }\n    return first;\n}\n\n// st <type>                                            # sizeof (a type)\n\ntemplate <class C>\nconst char*\nparse_sizeof_type_expr(const char* first, const char* last, C& db)\n{\n    if (last - first >= 3 && first[0] == 's' && first[1] == 't')\n    {\n        const char* t = parse_type(first+2, last, db);\n        if (t != first+2)\n        {\n            if (db.names.empty())\n                return first;\n            db.names.back() = \"sizeof (\" + db.names.back().move_full() + \")\";\n            first = t;\n        }\n    }\n    return first;\n}\n\n// sz <expr>                                            # sizeof (a expression)\n\ntemplate <class C>\nconst char*\nparse_sizeof_expr_expr(const char* first, const char* last, C& db)\n{\n    if (last - first >= 3 && first[0] == 's' && first[1] == 'z')\n    {\n        const char* t = parse_expression(first+2, last, db);\n        if (t != first+2)\n        {\n            if (db.names.empty())\n                return first;\n            db.names.back() = \"sizeof (\" + db.names.back().move_full() + \")\";\n            first = t;\n        }\n    }\n    return first;\n}\n\n// sZ <template-param>                                  # size of a parameter pack\n\ntemplate <class C>\nconst char*\nparse_sizeof_param_pack_expr(const char* first, const char* last, C& db)\n{\n    if (last - first >= 3 && first[0] == 's' && first[1] == 'Z' && first[2] == 'T')\n    {\n        size_t k0 = db.names.size();\n        const char* t = parse_template_param(first+2, last, db);\n        size_t k1 = db.names.size();\n        if (t != first+2)\n        {\n            typename C::String tmp(\"sizeof...(\");\n            size_t k = k0;\n            if (k != k1)\n            {\n                tmp += db.names[k].move_full();\n                for (++k; k != k1; ++k)\n                    tmp += \", \" + db.names[k].move_full();\n            }\n            tmp += \")\";\n            for (; k1 != k0; --k1)\n                db.names.pop_back();\n            db.names.push_back(std::move(tmp));\n            first = t;\n        }\n    }\n    return first;\n}\n\n// <function-param> ::= fp <top-level CV-qualifiers> _                                     # L == 0, first parameter\n//                  ::= fp <top-level CV-qualifiers> <parameter-2 non-negative number> _   # L == 0, second and later parameters\n//                  ::= fL <L-1 non-negative number> p <top-level CV-qualifiers> _         # L > 0, first parameter\n//                  ::= fL <L-1 non-negative number> p <top-level CV-qualifiers> <parameter-2 non-negative number> _   # L > 0, second and later parameters\n\ntemplate <class C>\nconst char*\nparse_function_param(const char* first, const char* last, C& db)\n{\n    if (last - first >= 3 && *first == 'f')\n    {\n        if (first[1] == 'p')\n        {\n            unsigned cv;\n            const char* t = parse_cv_qualifiers(first+2, last, cv);\n            const char* t1 = parse_number(t, last);\n            if (t1 != last && *t1 == '_')\n            {\n                db.names.push_back(\"fp\" + typename C::String(t, t1));\n                first = t1+1;\n            }\n        }\n        else if (first[1] == 'L')\n        {\n            unsigned cv;\n            const char* t0 = parse_number(first+2, last);\n            if (t0 != last && *t0 == 'p')\n            {\n                ++t0;\n                const char* t = parse_cv_qualifiers(t0, last, cv);\n                const char* t1 = parse_number(t, last);\n                if (t1 != last && *t1 == '_')\n                {\n                    db.names.push_back(\"fp\" + typename C::String(t, t1));\n                    first = t1+1;\n                }\n            }\n        }\n    }\n    return first;\n}\n\n// sZ <function-param>                                  # size of a function parameter pack\n\ntemplate <class C>\nconst char*\nparse_sizeof_function_param_pack_expr(const char* first, const char* last, C& db)\n{\n    if (last - first >= 3 && first[0] == 's' && first[1] == 'Z' && first[2] == 'f')\n    {\n        const char* t = parse_function_param(first+2, last, db);\n        if (t != first+2)\n        {\n            if (db.names.empty())\n                return first;\n            db.names.back() = \"sizeof...(\" + db.names.back().move_full() + \")\";\n            first = t;\n        }\n    }\n    return first;\n}\n\n// te <expression>                                      # typeid (expression)\n// ti <type>                                            # typeid (type)\n\ntemplate <class C>\nconst char*\nparse_typeid_expr(const char* first, const char* last, C& db)\n{\n    if (last - first >= 3 && first[0] == 't' && (first[1] == 'e' || first[1] == 'i'))\n    {\n        const char* t;\n        if (first[1] == 'e')\n            t = parse_expression(first+2, last, db);\n        else\n            t = parse_type(first+2, last, db);\n        if (t != first+2)\n        {\n            if (db.names.empty())\n                return first;\n            db.names.back() = \"typeid(\" + db.names.back().move_full() + \")\";\n            first = t;\n        }\n    }\n    return first;\n}\n\n// tw <expression>                                      # throw expression\n\ntemplate <class C>\nconst char*\nparse_throw_expr(const char* first, const char* last, C& db)\n{\n    if (last - first >= 3 && first[0] == 't' && first[1] == 'w')\n    {\n        const char* t = parse_expression(first+2, last, db);\n        if (t != first+2)\n        {\n            if (db.names.empty())\n                return first;\n            db.names.back() = \"throw \" + db.names.back().move_full();\n            first = t;\n        }\n    }\n    return first;\n}\n\n// ds <expression> <expression>                         # expr.*expr\n\ntemplate <class C>\nconst char*\nparse_dot_star_expr(const char* first, const char* last, C& db)\n{\n    if (last - first >= 3 && first[0] == 'd' && first[1] == 's')\n    {\n        const char* t = parse_expression(first+2, last, db);\n        if (t != first+2)\n        {\n            const char* t1 = parse_expression(t, last, db);\n            if (t1 != t)\n            {\n                if (db.names.size() < 2)\n                    return first;\n                auto expr = db.names.back().move_full();\n                db.names.pop_back();\n                db.names.back().first += \".*\" + expr;\n                first = t1;\n            }\n        }\n    }\n    return first;\n}\n\n// <simple-id> ::= <source-name> [ <template-args> ]\n\ntemplate <class C>\nconst char*\nparse_simple_id(const char* first, const char* last, C& db)\n{\n    if (first != last)\n    {\n        const char* t = parse_source_name(first, last, db);\n        if (t != first)\n        {\n            const char* t1 = parse_template_args(t, last, db);\n            if (t1 != t)\n            {\n                if (db.names.size() < 2)\n                    return first;\n                auto args = db.names.back().move_full();\n                db.names.pop_back();\n                db.names.back().first += std::move(args);\n            }\n            first = t1;\n        }\n        else\n            first = t;\n    }\n    return first;\n}\n\n// <unresolved-type> ::= <template-param>\n//                   ::= <decltype>\n//                   ::= <substitution>\n\ntemplate <class C>\nconst char*\nparse_unresolved_type(const char* first, const char* last, C& db)\n{\n    if (first != last)\n    {\n        const char* t = first;\n        switch (*first)\n        {\n        case 'T':\n          {\n            size_t k0 = db.names.size();\n            t = parse_template_param(first, last, db);\n            size_t k1 = db.names.size();\n            if (t != first && k1 == k0 + 1)\n            {\n                db.subs.push_back(typename C::sub_type(1, db.names.back(), db.names.get_allocator()));\n                first = t;\n            }\n            else\n            {\n                for (; k1 != k0; --k1)\n                    db.names.pop_back();\n            }\n            break;\n          }\n        case 'D':\n            t = parse_decltype(first, last, db);\n            if (t != first)\n            {\n                if (db.names.empty())\n                    return first;\n                db.subs.push_back(typename C::sub_type(1, db.names.back(), db.names.get_allocator()));\n                first = t;\n            }\n            break;\n        case 'S':\n            t = parse_substitution(first, last, db);\n            if (t != first)\n                first = t;\n            else\n            {\n                if (last - first > 2 && first[1] == 't')\n                {\n                    t = parse_unqualified_name(first+2, last, db);\n                    if (t != first+2)\n                    {\n                        if (db.names.empty())\n                            return first;\n                        db.names.back().first.insert(0, \"std::\");\n                        db.subs.push_back(typename C::sub_type(1, db.names.back(), db.names.get_allocator()));\n                        first = t;\n                    }\n                }\n            }\n            break;\n       }\n    }\n    return first;\n}\n\n// <destructor-name> ::= <unresolved-type>                               # e.g., ~T or ~decltype(f())\n//                   ::= <simple-id>                                     # e.g., ~A<2*N>\n\ntemplate <class C>\nconst char*\nparse_destructor_name(const char* first, const char* last, C& db)\n{\n    if (first != last)\n    {\n        const char* t = parse_unresolved_type(first, last, db);\n        if (t == first)\n            t = parse_simple_id(first, last, db);\n        if (t != first)\n        {\n            if (db.names.empty())\n                return first;\n            db.names.back().first.insert(0, \"~\");\n            first = t;\n        }\n    }\n    return first;\n}\n\n// <base-unresolved-name> ::= <simple-id>                                # unresolved name\n//          extension     ::= <operator-name>                            # unresolved operator-function-id\n//          extension     ::= <operator-name> <template-args>            # unresolved operator template-id\n//                        ::= on <operator-name>                         # unresolved operator-function-id\n//                        ::= on <operator-name> <template-args>         # unresolved operator template-id\n//                        ::= dn <destructor-name>                       # destructor or pseudo-destructor;\n//                                                                         # e.g. ~X or ~X<N-1>\n\ntemplate <class C>\nconst char*\nparse_base_unresolved_name(const char* first, const char* last, C& db)\n{\n    if (last - first >= 2)\n    {\n        if ((first[0] == 'o' || first[0] == 'd') && first[1] == 'n')\n        {\n            if (first[0] == 'o')\n            {\n                const char* t = parse_operator_name(first+2, last, db);\n                if (t != first+2)\n                {\n                    first = parse_template_args(t, last, db);\n                    if (first != t)\n                    {\n                        if (db.names.size() < 2)\n                            return first;\n                        auto args = db.names.back().move_full();\n                        db.names.pop_back();\n                        db.names.back().first += std::move(args);\n                    }\n                }\n            }\n            else\n            {\n                const char* t = parse_destructor_name(first+2, last, db);\n                if (t != first+2)\n                    first = t;\n            }\n        }\n        else\n        {\n            const char* t = parse_simple_id(first, last, db);\n            if (t == first)\n            {\n                t = parse_operator_name(first, last, db);\n                if (t != first)\n                {\n                    first = parse_template_args(t, last, db);\n                    if (first != t)\n                    {\n                        if (db.names.size() < 2)\n                            return first;\n                        auto args = db.names.back().move_full();\n                        db.names.pop_back();\n                        db.names.back().first += std::move(args);\n                    }\n                }\n            }\n            else\n                first = t;\n        }\n    }\n    return first;\n}\n\n// <unresolved-qualifier-level> ::= <simple-id>\n\ntemplate <class C>\nconst char*\nparse_unresolved_qualifier_level(const char* first, const char* last, C& db)\n{\n    return parse_simple_id(first, last, db);\n}\n\n// <unresolved-name>\n//  extension        ::= srN <unresolved-type> [<template-args>] <unresolved-qualifier-level>* E <base-unresolved-name>\n//                   ::= [gs] <base-unresolved-name>                     # x or (with \"gs\") ::x\n//                   ::= [gs] sr <unresolved-qualifier-level>+ E <base-unresolved-name>  \n//                                                                       # A::x, N::y, A<T>::z; \"gs\" means leading \"::\"\n//                   ::= sr <unresolved-type> <base-unresolved-name>     # T::x / decltype(p)::x\n//  extension        ::= sr <unresolved-type> <template-args> <base-unresolved-name>\n//                                                                       # T::N::x /decltype(p)::N::x\n//  (ignored)        ::= srN <unresolved-type>  <unresolved-qualifier-level>+ E <base-unresolved-name>\n\ntemplate <class C>\nconst char*\nparse_unresolved_name(const char* first, const char* last, C& db)\n{\n    if (last - first > 2)\n    {\n        const char* t = first;\n        bool global = false;\n        if (t[0] == 'g' && t[1] == 's')\n        {\n            global = true;\n            t += 2;\n        }\n        const char* t2 = parse_base_unresolved_name(t, last, db);\n        if (t2 != t)\n        {\n            if (global)\n            {\n                if (db.names.empty())\n                    return first;\n                db.names.back().first.insert(0, \"::\");\n            }\n            first = t2;\n        }\n        else if (last - t > 2 && t[0] == 's' && t[1] == 'r')\n        {\n            if (t[2] == 'N')\n            {\n                t += 3;\n                const char* t1 = parse_unresolved_type(t, last, db);\n                if (t1 == t || t1 == last)\n                    return first;\n                t = t1;\n                t1 = parse_template_args(t, last, db);\n                if (t1 != t)\n                {\n                    if (db.names.size() < 2)\n                        return first;\n                    auto args = db.names.back().move_full();\n                    db.names.pop_back();\n                    db.names.back().first += std::move(args);\n                    t = t1;\n                    if (t == last)\n                    {\n                        db.names.pop_back();\n                        return first;\n                    }\n                }\n                while (*t != 'E')\n                {\n                    t1 = parse_unresolved_qualifier_level(t, last, db);\n                    if (t1 == t || t1 == last || db.names.size() < 2)\n                        return first;\n                    auto s = db.names.back().move_full();\n                    db.names.pop_back();\n                    db.names.back().first += \"::\" + std::move(s);\n                    t = t1;\n                }\n                ++t;\n                t1 = parse_base_unresolved_name(t, last, db);\n                if (t1 == t)\n                {\n                    if (!db.names.empty())\n                        db.names.pop_back();\n                    return first;\n                }\n                if (db.names.size() < 2)\n                    return first;\n                auto s = db.names.back().move_full();\n                db.names.pop_back();\n                db.names.back().first += \"::\" + std::move(s);\n                first = t1;\n            }\n            else\n            {\n                t += 2;\n                const char* t1 = parse_unresolved_type(t, last, db);\n                if (t1 != t)\n                {\n                    t = t1;\n                    t1 = parse_template_args(t, last, db);\n                    if (t1 != t)\n                    {\n                        if (db.names.size() < 2)\n                            return first;\n                        auto args = db.names.back().move_full();\n                        db.names.pop_back();\n                        db.names.back().first += std::move(args);\n                        t = t1;\n                    }\n                    t1 = parse_base_unresolved_name(t, last, db);\n                    if (t1 == t)\n                    {\n                        if (!db.names.empty())\n                            db.names.pop_back();\n                        return first;\n                    }\n                    if (db.names.size() < 2)\n                        return first;\n                    auto s = db.names.back().move_full();\n                    db.names.pop_back();\n                    db.names.back().first += \"::\" + std::move(s);\n                    first = t1;\n                }\n                else\n                {\n                    t1 = parse_unresolved_qualifier_level(t, last, db);\n                    if (t1 == t || t1 == last)\n                        return first;\n                    t = t1;\n                    if (global)\n                    {\n                        if (db.names.empty())\n                            return first;\n                        db.names.back().first.insert(0, \"::\");\n                    }\n                    while (*t != 'E')\n                    {\n                        t1 = parse_unresolved_qualifier_level(t, last, db);\n                        if (t1 == t || t1 == last || db.names.size() < 2)\n                            return first;\n                        auto s = db.names.back().move_full();\n                        db.names.pop_back();\n                        db.names.back().first += \"::\" + std::move(s);\n                        t = t1;\n                    }\n                    ++t;\n                    t1 = parse_base_unresolved_name(t, last, db);\n                    if (t1 == t)\n                    {\n                        if (!db.names.empty())\n                            db.names.pop_back();\n                        return first;\n                    }\n                    if (db.names.size() < 2)\n                        return first;\n                    auto s = db.names.back().move_full();\n                    db.names.pop_back();\n                    db.names.back().first += \"::\" + std::move(s);\n                    first = t1;\n                }\n            }\n        }\n    }\n    return first;\n}\n\n// dt <expression> <unresolved-name>                    # expr.name\n\ntemplate <class C>\nconst char*\nparse_dot_expr(const char* first, const char* last, C& db)\n{\n    if (last - first >= 3 && first[0] == 'd' && first[1] == 't')\n    {\n        const char* t = parse_expression(first+2, last, db);\n        if (t != first+2)\n        {\n            const char* t1 = parse_unresolved_name(t, last, db);\n            if (t1 != t)\n            {\n                if (db.names.size() < 2)\n                    return first;\n                auto name = db.names.back().move_full();\n                db.names.pop_back();\n                db.names.back().first += \".\" + name;\n                first = t1;\n            }\n        }\n    }\n    return first;\n}\n\n// cl <expression>+ E                                   # call\n\ntemplate <class C>\nconst char*\nparse_call_expr(const char* first, const char* last, C& db)\n{\n    if (last - first >= 4 && first[0] == 'c' && first[1] == 'l')\n    {\n        const char* t = parse_expression(first+2, last, db);\n        if (t != first+2)\n        {\n            if (t == last)\n                return first;\n            if (db.names.empty())\n                return first;\n            db.names.back().first += db.names.back().second;\n            db.names.back().second = typename C::String();\n            db.names.back().first.append(\"(\");\n            bool first_expr = true;\n            while (*t != 'E')\n            {\n                const char* t1 = parse_expression(t, last, db);\n                if (t1 == t || t1 == last)\n                    return first;\n                if (db.names.empty())\n                    return first;\n                auto tmp = db.names.back().move_full();\n                db.names.pop_back();\n                if (!tmp.empty())\n                {\n                    if (db.names.empty())\n                        return first;\n                    if (!first_expr)\n                    {\n                        db.names.back().first.append(\", \");\n                        first_expr = false;\n                    }\n                    db.names.back().first.append(tmp);\n                }\n                t = t1;\n            }\n            ++t;\n            if (db.names.empty())\n                return first;\n            db.names.back().first.append(\")\");\n            first = t;\n        }\n    }\n    return first;\n}\n\n// [gs] nw <expression>* _ <type> E                     # new (expr-list) type\n// [gs] nw <expression>* _ <type> <initializer>         # new (expr-list) type (init)\n// [gs] na <expression>* _ <type> E                     # new[] (expr-list) type\n// [gs] na <expression>* _ <type> <initializer>         # new[] (expr-list) type (init)\n// <initializer> ::= pi <expression>* E                 # parenthesized initialization\n\ntemplate <class C>\nconst char*\nparse_new_expr(const char* first, const char* last, C& db)\n{\n    if (last - first >= 4)\n    {\n        const char* t = first;\n        bool parsed_gs = false;\n        if (t[0] == 'g' && t[1] == 's')\n        {\n            t += 2;\n            parsed_gs = true;\n        }\n        if (t[0] == 'n' && (t[1] == 'w' || t[1] == 'a'))\n        {\n            bool is_array = t[1] == 'a';\n            t += 2;\n            if (t == last)\n                return first;\n            bool has_expr_list = false;\n            bool first_expr = true;\n            while (*t != '_')\n            {\n                const char* t1 = parse_expression(t, last, db);\n                if (t1 == t || t1 == last)\n                    return first;\n                has_expr_list = true;\n                if (!first_expr)\n                {\n                    if (db.names.empty())\n                        return first;\n                    auto tmp = db.names.back().move_full();\n                    db.names.pop_back();\n                    if (!tmp.empty())\n                    {\n                        if (db.names.empty())\n                            return first;\n                        db.names.back().first.append(\", \");\n                        db.names.back().first.append(tmp);\n                        first_expr = false;\n                    }\n                }\n                t = t1;\n            }\n            ++t;\n            const char* t1 = parse_type(t, last, db);\n            if (t1 == t || t1 == last)\n                return first;\n            t = t1;\n            bool has_init = false;\n            if (last - t >= 3 && t[0] == 'p' && t[1] == 'i')\n            {\n                t += 2;\n                has_init = true;\n                first_expr = true;\n                while (*t != 'E')\n                {\n                    t1 = parse_expression(t, last, db);\n                    if (t1 == t || t1 == last)\n                        return first;\n                    if (!first_expr)\n                    {\n                        if (db.names.empty())\n                            return first;\n                        auto tmp = db.names.back().move_full();\n                        db.names.pop_back();\n                        if (!tmp.empty())\n                        {\n                            if (db.names.empty())\n                                return first;\n                            db.names.back().first.append(\", \");\n                            db.names.back().first.append(tmp);\n                            first_expr = false;\n                        }\n                    }\n                    t = t1;\n                }\n            }\n            if (*t != 'E')\n                return first;\n            typename C::String init_list;\n            if (has_init)\n            {\n                if (db.names.empty())\n                    return first;\n                init_list = db.names.back().move_full();\n                db.names.pop_back();\n            }\n            if (db.names.empty())\n                return first;\n            auto type = db.names.back().move_full();\n            db.names.pop_back();\n            typename C::String expr_list;\n            if (has_expr_list)\n            {\n                if (db.names.empty())\n                    return first;\n                expr_list = db.names.back().move_full();\n                db.names.pop_back();\n            }\n            typename C::String r;\n            if (parsed_gs)\n                r = \"::\";\n            if (is_array)\n                r += \"[] \";\n            else\n                r += \" \";\n            if (has_expr_list)\n                r += \"(\" + expr_list + \") \";\n            r += type;\n            if (has_init)\n                r += \" (\" + init_list + \")\";\n            db.names.push_back(std::move(r));\n            first = t+1;\n        }\n    }\n    return first;\n}\n\n// cv <type> <expression>                               # conversion with one argument\n// cv <type> _ <expression>* E                          # conversion with a different number of arguments\n\ntemplate <class C>\nconst char*\nparse_conversion_expr(const char* first, const char* last, C& db)\n{\n    if (last - first >= 3 && first[0] == 'c' && first[1] == 'v')\n    {\n        bool try_to_parse_template_args = db.try_to_parse_template_args;\n        db.try_to_parse_template_args = false;\n        const char* t = parse_type(first+2, last, db);\n        db.try_to_parse_template_args = try_to_parse_template_args;\n        if (t != first+2 && t != last)\n        {\n            if (*t != '_')\n            {\n                const char* t1 = parse_expression(t, last, db);\n                if (t1 == t)\n                    return first;\n                t = t1;\n            }\n            else\n            {\n                ++t;\n                if (t == last)\n                    return first;\n                if (*t == 'E')\n                    db.names.emplace_back();\n                else\n                {\n                    bool first_expr = true;\n                    while (*t != 'E')\n                    {\n                        const char* t1 = parse_expression(t, last, db);\n                        if (t1 == t || t1 == last)\n                            return first;\n                        if (!first_expr)\n                        {\n                            if (db.names.empty())\n                                return first;\n                            auto tmp = db.names.back().move_full();\n                            db.names.pop_back();\n                            if (!tmp.empty())\n                            {\n                                if (db.names.empty())\n                                    return first;\n                                db.names.back().first.append(\", \");\n                                db.names.back().first.append(tmp);\n                                first_expr = false;\n                            }\n                        }\n                        t = t1;\n                    }\n                }\n                ++t;\n            }\n            if (db.names.size() < 2)\n                return first;\n            auto tmp = db.names.back().move_full();\n            db.names.pop_back();\n            db.names.back() = \"(\" + db.names.back().move_full() + \")(\" + tmp + \")\";\n            first = t;\n        }\n    }\n    return first;\n}\n\n// pt <expression> <expression>                    # expr->name\n\ntemplate <class C>\nconst char*\nparse_arrow_expr(const char* first, const char* last, C& db)\n{\n    if (last - first >= 3 && first[0] == 'p' && first[1] == 't')\n    {\n        const char* t = parse_expression(first+2, last, db);\n        if (t != first+2)\n        {\n            const char* t1 = parse_expression(t, last, db);\n            if (t1 != t)\n            {\n                if (db.names.size() < 2)\n                    return first;\n                auto tmp = db.names.back().move_full();\n                db.names.pop_back();\n                db.names.back().first += \"->\";\n                db.names.back().first += tmp;\n                first = t1;\n            }\n        }\n    }\n    return first;\n}\n\n//  <ref-qualifier> ::= R                   # & ref-qualifier\n//  <ref-qualifier> ::= O                   # && ref-qualifier\n\n// <function-type> ::= F [Y] <bare-function-type> [<ref-qualifier>] E\n\ntemplate <class C>\nconst char*\nparse_function_type(const char* first, const char* last, C& db)\n{\n    if (first != last && *first == 'F')\n    {\n        const char* t = first+1;\n        if (t != last)\n        {\n            if (*t == 'Y')\n            {\n                /* extern \"C\" */\n                if (++t == last)\n                    return first;\n            }\n            const char* t1 = parse_type(t, last, db);\n            if (t1 != t)\n            {\n                t = t1;\n                typename C::String sig(\"(\");\n                int ref_qual = 0;\n                while (true)\n                {\n                    if (t == last)\n                    {\n                        db.names.pop_back();\n                        return first;\n                    }\n                    if (*t == 'E')\n                    {\n                        ++t;\n                        break;\n                    }\n                    if (*t == 'v')\n                    {\n                        ++t;\n                        continue;\n                    }\n                    if (*t == 'R' && t+1 != last && t[1] == 'E')\n                    {\n                        ref_qual = 1;\n                        ++t;\n                        continue;\n                    }\n                    if (*t == 'O' && t+1 != last && t[1] == 'E')\n                    {\n                        ref_qual = 2;\n                        ++t;\n                        continue;\n                    }\n                    size_t k0 = db.names.size();\n                    t1 = parse_type(t, last, db);\n                    size_t k1 = db.names.size();\n                    if (t1 == t || t1 == last)\n                        return first;\n                    for (size_t k = k0; k < k1; ++k)\n                    {\n                        if (sig.size() > 1)\n                            sig += \", \";\n                        sig += db.names[k].move_full();\n                    }\n                    for (size_t k = k0; k < k1; ++k)\n                        db.names.pop_back();\n                    t = t1;\n                }\n                sig += \")\";\n                switch (ref_qual)\n                {\n                case 1:\n                    sig += \" &\";\n                    break;\n                case 2:\n                    sig += \" &&\";\n                    break;\n                }\n                if (db.names.empty())\n                    return first;\n                db.names.back().first += \" \";\n                db.names.back().second.insert(0, sig);\n                first = t;\n            }\n        }\n    }\n    return first;\n}\n\n// <pointer-to-member-type> ::= M <class type> <member type>\n\ntemplate <class C>\nconst char*\nparse_pointer_to_member_type(const char* first, const char* last, C& db)\n{\n    if (first != last && *first == 'M')\n    {\n        const char* t = parse_type(first+1, last, db);\n        if (t != first+1)\n        {\n            const char* t2 = parse_type(t, last, db);\n            if (t2 != t)\n            {\n                if (db.names.size() < 2)\n                    return first;\n                auto func = std::move(db.names.back());\n                db.names.pop_back();\n                auto class_type = std::move(db.names.back());\n                if (!func.second.empty() && func.second.front() == '(')\n                {\n                    db.names.back().first = std::move(func.first) + \"(\" + class_type.move_full() + \"::*\";\n                    db.names.back().second = \")\" + std::move(func.second);\n                }\n                else\n                {\n                    db.names.back().first = std::move(func.first) + \" \" + class_type.move_full() + \"::*\";\n                    db.names.back().second = std::move(func.second);\n                }\n                first = t2;\n            }\n        }\n    }\n    return first;\n}\n\n// <array-type> ::= A <positive dimension number> _ <element type>\n//              ::= A [<dimension expression>] _ <element type>\n\ntemplate <class C>\nconst char*\nparse_array_type(const char* first, const char* last, C& db)\n{\n    if (first != last && *first == 'A' && first+1 != last)\n    {\n        if (first[1] == '_')\n        {\n            const char* t = parse_type(first+2, last, db);\n            if (t != first+2)\n            {\n                if (db.names.empty())\n                    return first;\n                if (db.names.back().second.substr(0, 2) == \" [\")\n                    db.names.back().second.erase(0, 1);\n                db.names.back().second.insert(0, \" []\");\n                first = t;\n            }\n        }\n        else if ('1' <= first[1] && first[1] <= '9')\n        {\n            const char* t = parse_number(first+1, last);\n            if (t != last && *t == '_')\n            {\n                const char* t2 = parse_type(t+1, last, db);\n                if (t2 != t+1)\n                {\n                    if (db.names.empty())\n                        return first;\n                    if (db.names.back().second.substr(0, 2) == \" [\")\n                        db.names.back().second.erase(0, 1);\n                    db.names.back().second.insert(0, \" [\" + typename C::String(first+1, t) + \"]\");\n                    first = t2;\n                }\n            }\n        }\n        else\n        {\n            const char* t = parse_expression(first+1, last, db);\n            if (t != first+1 && t != last && *t == '_')\n            {\n                const char* t2 = parse_type(++t, last, db);\n                if (t2 != t)\n                {\n                    if (db.names.size() < 2)\n                        return first;\n                    auto type = std::move(db.names.back());\n                    db.names.pop_back();\n                    auto expr = std::move(db.names.back());\n                    db.names.back().first = std::move(type.first);\n                    if (type.second.substr(0, 2) == \" [\")\n                        type.second.erase(0, 1);\n                    db.names.back().second = \" [\" + expr.move_full() + \"]\" + std::move(type.second);\n                    first = t2;\n                }\n            }\n        }\n    }\n    return first;\n}\n\n// <decltype>  ::= Dt <expression> E  # decltype of an id-expression or class member access (C++0x)\n//             ::= DT <expression> E  # decltype of an expression (C++0x)\n\ntemplate <class C>\nconst char*\nparse_decltype(const char* first, const char* last, C& db)\n{\n    if (last - first >= 4 && first[0] == 'D')\n    {\n        switch (first[1])\n        {\n        case 't':\n        case 'T':\n            {\n                const char* t = parse_expression(first+2, last, db);\n                if (t != first+2 && t != last && *t == 'E')\n                {\n                    if (db.names.empty())\n                        return first;\n                    db.names.back() = \"decltype(\" + db.names.back().move_full() + \")\";\n                    first = t+1;\n                }\n            }\n            break;\n        }\n    }\n    return first;\n}\n\n// extension:\n// <vector-type>           ::= Dv <positive dimension number> _\n//                                    <extended element type>\n//                         ::= Dv [<dimension expression>] _ <element type>\n// <extended element type> ::= <element type>\n//                         ::= p # AltiVec vector pixel\n\ntemplate <class C>\nconst char*\nparse_vector_type(const char* first, const char* last, C& db)\n{\n    if (last - first > 3 && first[0] == 'D' && first[1] == 'v')\n    {\n        if ('1' <= first[2] && first[2] <= '9')\n        {\n            const char* t = parse_number(first+2, last);\n            if (t == last || *t != '_')\n                return first;\n            const char* num = first + 2;\n            size_t sz = static_cast<size_t>(t - num);\n            if (++t != last)\n            {\n                if (*t != 'p')\n                {\n                    const char* t1 = parse_type(t, last, db);\n                    if (t1 != t)\n                    {\n                        if (db.names.empty())\n                            return first;\n                        db.names.back().first += \" vector[\" + typename C::String(num, sz) + \"]\";\n                        first = t1;\n                    }\n                }\n                else\n                {\n                    ++t;\n                    db.names.push_back(\"pixel vector[\" + typename C::String(num, sz) + \"]\");\n                    first = t;\n                }\n            }\n        }\n        else\n        {\n            typename C::String num;\n            const char* t1 = first+2;\n            if (*t1 != '_')\n            {\n                const char* t = parse_expression(t1, last, db);\n                if (t != t1)\n                {\n                    if (db.names.empty())\n                        return first;\n                    num = db.names.back().move_full();\n                    db.names.pop_back();\n                    t1 = t;\n                }\n            }\n            if (t1 != last && *t1 == '_' && ++t1 != last)\n            {\n                const char* t = parse_type(t1, last, db);\n                if (t != t1)\n                {\n                    if (db.names.empty())\n                        return first;\n                    db.names.back().first += \" vector[\" + num + \"]\";\n                    first = t;\n                }\n            }\n        }\n    }\n    return first;\n}\n\n// <type> ::= <builtin-type>\n//        ::= <function-type>\n//        ::= <class-enum-type>\n//        ::= <array-type>\n//        ::= <pointer-to-member-type>\n//        ::= <template-param>\n//        ::= <template-template-param> <template-args>\n//        ::= <decltype>\n//        ::= <substitution>\n//        ::= <CV-qualifiers> <type>\n//        ::= P <type>        # pointer-to\n//        ::= R <type>        # reference-to\n//        ::= O <type>        # rvalue reference-to (C++0x)\n//        ::= C <type>        # complex pair (C 2000)\n//        ::= G <type>        # imaginary (C 2000)\n//        ::= Dp <type>       # pack expansion (C++0x)\n//        ::= U <source-name> <type>  # vendor extended type qualifier\n// extension := U <objc-name> <objc-type>  # objc-type<identifier>\n// extension := <vector-type> # <vector-type> starts with Dv\n\n// <objc-name> ::= <k0 number> objcproto <k1 number> <identifier>  # k0 = 9 + <number of digits in k1> + k1\n// <objc-type> := <source-name>  # PU<11+>objcproto 11objc_object<source-name> 11objc_object -> id<source-name>\n\ntemplate <class C>\nconst char*\nparse_type(const char* first, const char* last, C& db)\n{\n    if (first != last)\n    {\n        switch (*first)\n        {\n            case 'r':\n            case 'V':\n            case 'K':\n              {\n                unsigned cv = 0;\n                const char* t = parse_cv_qualifiers(first, last, cv);\n                if (t != first)\n                {\n                    bool is_function = *t == 'F';\n                    size_t k0 = db.names.size();\n                    const char* t1 = parse_type(t, last, db);\n                    size_t k1 = db.names.size();\n                    if (t1 != t)\n                    {\n                        if (is_function)\n                            db.subs.pop_back();\n                        db.subs.emplace_back(db.names.get_allocator());\n                        for (size_t k = k0; k < k1; ++k)\n                        {\n                            if (is_function)\n                            {\n                                size_t p = db.names[k].second.size();\n                                if (db.names[k].second[p-2] == '&')\n                                    p -= 3;\n                                else if (db.names[k].second.back() == '&')\n                                    p -= 2;\n                                if (cv & 1)\n                                {\n                                    db.names[k].second.insert(p, \" const\");\n                                    p += 6;\n                                }\n                                if (cv & 2)\n                                {\n                                    db.names[k].second.insert(p, \" volatile\");\n                                    p += 9;\n                                }\n                                if (cv & 4)\n                                    db.names[k].second.insert(p, \" restrict\");\n                            }\n                            else\n                            {\n                                if (cv & 1)\n                                    db.names[k].first.append(\" const\");\n                                if (cv & 2)\n                                    db.names[k].first.append(\" volatile\");\n                                if (cv & 4)\n                                    db.names[k].first.append(\" restrict\");\n                            }\n                            db.subs.back().push_back(db.names[k]);\n                        }\n                        first = t1;\n                    }\n                }\n              }\n                break;\n            default:\n              {\n                const char* t = parse_builtin_type(first, last, db);\n                if (t != first)\n                {\n                    first = t;\n                }\n                else\n                {\n                    switch (*first)\n                    {\n                    case 'A':\n                        t = parse_array_type(first, last, db);\n                        if (t != first)\n                        {\n                            if (db.names.empty())\n                                return first;\n                            first = t;\n                            db.subs.push_back(typename C::sub_type(1, db.names.back(), db.names.get_allocator()));\n                        }\n                        break;\n                    case 'C':\n                        t = parse_type(first+1, last, db);\n                        if (t != first+1)\n                        {\n                            if (db.names.empty())\n                                return first;\n                            db.names.back().first.append(\" complex\");\n                            first = t;\n                            db.subs.push_back(typename C::sub_type(1, db.names.back(), db.names.get_allocator()));\n                        }\n                        break;\n                    case 'F':\n                        t = parse_function_type(first, last, db);\n                        if (t != first)\n                        {\n                            if (db.names.empty())\n                                return first;\n                            first = t;\n                            db.subs.push_back(typename C::sub_type(1, db.names.back(), db.names.get_allocator()));\n                        }\n                        break;\n                    case 'G':\n                        t = parse_type(first+1, last, db);\n                        if (t != first+1)\n                        {\n                            if (db.names.empty())\n                                return first;\n                            db.names.back().first.append(\" imaginary\");\n                            first = t;\n                            db.subs.push_back(typename C::sub_type(1, db.names.back(), db.names.get_allocator()));\n                        }\n                        break;\n                    case 'M':\n                        t = parse_pointer_to_member_type(first, last, db);\n                        if (t != first)\n                        {\n                            if (db.names.empty())\n                                return first;\n                            first = t;\n                            db.subs.push_back(typename C::sub_type(1, db.names.back(), db.names.get_allocator()));\n                        }\n                        break;\n                    case 'O':\n                      {\n                        size_t k0 = db.names.size();\n                        t = parse_type(first+1, last, db);\n                        size_t k1 = db.names.size();\n                        if (t != first+1)\n                        {\n                            db.subs.emplace_back(db.names.get_allocator());\n                            for (size_t k = k0; k < k1; ++k)\n                            {\n                                if (db.names[k].second.substr(0, 2) == \" [\")\n                                {\n                                    db.names[k].first += \" (\";\n                                    db.names[k].second.insert(0, \")\");\n                                }\n                                else if (!db.names[k].second.empty() &&\n                                          db.names[k].second.front() == '(')\n                                {\n                                    db.names[k].first += \"(\";\n                                    db.names[k].second.insert(0, \")\");\n                                }\n                                db.names[k].first.append(\"&&\");\n                                db.subs.back().push_back(db.names[k]);\n                            }\n                            first = t;\n                        }\n                        break;\n                      }\n                    case 'P':\n                      {\n                        size_t k0 = db.names.size();\n                        t = parse_type(first+1, last, db);\n                        size_t k1 = db.names.size();\n                        if (t != first+1)\n                        {\n                            db.subs.emplace_back(db.names.get_allocator());\n                            for (size_t k = k0; k < k1; ++k)\n                            {\n                                if (db.names[k].second.substr(0, 2) == \" [\")\n                                {\n                                    db.names[k].first += \" (\";\n                                    db.names[k].second.insert(0, \")\");\n                                }\n                                else if (!db.names[k].second.empty() &&\n                                          db.names[k].second.front() == '(')\n                                {\n                                    db.names[k].first += \"(\";\n                                    db.names[k].second.insert(0, \")\");\n                                }\n                                if (first[1] != 'U' || db.names[k].first.substr(0, 12) != \"objc_object<\")\n                                {\n                                    db.names[k].first.append(\"*\");\n                                }\n                                else\n                                {\n                                    db.names[k].first.replace(0, 11, \"id\");\n                                }\n                                db.subs.back().push_back(db.names[k]);\n                            }\n                            first = t;\n                        }\n                        break;\n                      }\n                    case 'R':\n                      {\n                        size_t k0 = db.names.size();\n                        t = parse_type(first+1, last, db);\n                        size_t k1 = db.names.size();\n                        if (t != first+1)\n                        {\n                            db.subs.emplace_back(db.names.get_allocator());\n                            for (size_t k = k0; k < k1; ++k)\n                            {\n                                if (db.names[k].second.substr(0, 2) == \" [\")\n                                {\n                                    db.names[k].first += \" (\";\n                                    db.names[k].second.insert(0, \")\");\n                                }\n                                else if (!db.names[k].second.empty() &&\n                                          db.names[k].second.front() == '(')\n                                {\n                                    db.names[k].first += \"(\";\n                                    db.names[k].second.insert(0, \")\");\n                                }\n                                db.names[k].first.append(\"&\");\n                                db.subs.back().push_back(db.names[k]);\n                            }\n                            first = t;\n                        }\n                        break;\n                      }\n                    case 'T':\n                      {\n                        size_t k0 = db.names.size();\n                        t = parse_template_param(first, last, db);\n                        size_t k1 = db.names.size();\n                        if (t != first)\n                        {\n                            db.subs.emplace_back(db.names.get_allocator());\n                            for (size_t k = k0; k < k1; ++k)\n                                db.subs.back().push_back(db.names[k]);\n                            if (db.try_to_parse_template_args && k1 == k0+1)\n                            {\n                                const char* t1 = parse_template_args(t, last, db);\n                                if (t1 != t)\n                                {\n                                    auto args = db.names.back().move_full();\n                                    db.names.pop_back();\n                                    db.names.back().first += std::move(args);\n                                    db.subs.push_back(typename C::sub_type(1, db.names.back(), db.names.get_allocator()));\n                                    t = t1;\n                                }\n                            }\n                            first = t;\n                        }\n                        break;\n                      }\n                    case 'U':\n                        if (first+1 != last)\n                        {\n                            t = parse_source_name(first+1, last, db);\n                            if (t != first+1)\n                            {\n                                const char* t2 = parse_type(t, last, db);\n                                if (t2 != t)\n                                {\n                                    if (db.names.size() < 2)\n                                        return first;\n                                    auto type = db.names.back().move_full();\n                                    db.names.pop_back();\n                                    if (db.names.back().first.substr(0, 9) != \"objcproto\")\n                                    {\n                                        db.names.back() = type + \" \" + db.names.back().move_full();\n                                    }\n                                    else\n                                    {\n                                        auto proto = db.names.back().move_full();\n                                        db.names.pop_back();\n                                        t = parse_source_name(proto.data() + 9, proto.data() + proto.size(), db);\n                                        if (t != proto.data() + 9)\n                                        {\n                                            db.names.back() = type + \"<\" + db.names.back().move_full() + \">\";\n                                        }\n                                        else\n                                        {\n                                            db.names.push_back(type + \" \" + proto);\n                                        }\n                                    }\n                                    db.subs.push_back(typename C::sub_type(1, db.names.back(), db.names.get_allocator()));\n                                    first = t2;\n                                }\n                            }\n                        }\n                        break;\n                    case 'S':\n                        if (first+1 != last && first[1] == 't')\n                        {\n                            t = parse_name(first, last, db);\n                            if (t != first)\n                            {\n                                if (db.names.empty())\n                                    return first;\n                                db.subs.push_back(typename C::sub_type(1, db.names.back(), db.names.get_allocator()));\n                                first = t;\n                            }\n                        }\n                        else\n                        {\n                            t = parse_substitution(first, last, db);\n                            if (t != first)\n                            {\n                                first = t;\n                                // Parsed a substitution.  If the substitution is a\n                                //  <template-param> it might be followed by <template-args>.\n                                t = parse_template_args(first, last, db);\n                                if (t != first)\n                                {\n                                    if (db.names.size() < 2)\n                                        return first;\n                                    auto template_args = db.names.back().move_full();\n                                    db.names.pop_back();\n                                    db.names.back().first += template_args;\n                                    // Need to create substitution for <template-template-param> <template-args>\n                                    db.subs.push_back(typename C::sub_type(1, db.names.back(), db.names.get_allocator()));\n                                    first = t;\n                                }\n                            }\n                        }\n                        break;\n                    case 'D':\n                        if (first+1 != last)\n                        {\n                            switch (first[1])\n                            {\n                            case 'p':\n                              {\n                                size_t k0 = db.names.size();\n                                t = parse_type(first+2, last, db);\n                                size_t k1 = db.names.size();\n                                if (t != first+2)\n                                {\n                                    db.subs.emplace_back(db.names.get_allocator());\n                                    for (size_t k = k0; k < k1; ++k)\n                                        db.subs.back().push_back(db.names[k]);\n                                    first = t;\n                                    return first;\n                                }\n                                break;\n                              }\n                            case 't':\n                            case 'T':\n                                t = parse_decltype(first, last, db);\n                                if (t != first)\n                                {\n                                    if (db.names.empty())\n                                        return first;\n                                    db.subs.push_back(typename C::sub_type(1, db.names.back(), db.names.get_allocator()));\n                                    first = t;\n                                    return first;\n                                }\n                                break;\n                            case 'v':\n                                t = parse_vector_type(first, last, db);\n                                if (t != first)\n                                {\n                                    if (db.names.empty())\n                                        return first;\n                                    db.subs.push_back(typename C::sub_type(1, db.names.back(), db.names.get_allocator()));\n                                    first = t;\n                                    return first;\n                                }\n                                break;\n                            }\n                        }\n                        // drop through\n                    default:\n                        // must check for builtin-types before class-enum-types to avoid\n                        // ambiguities with operator-names\n                        t = parse_builtin_type(first, last, db);\n                        if (t != first)\n                        {\n                            first = t;\n                        }\n                        else\n                        {\n                            t = parse_name(first, last, db);\n                            if (t != first)\n                            {\n                                if (db.names.empty())\n                                    return first;\n                                db.subs.push_back(typename C::sub_type(1, db.names.back(), db.names.get_allocator()));\n                                first = t;\n                            }\n                        }\n                        break;\n                    }\n              }\n                break;\n            }\n        }\n    }\n    return first;\n}\n\n//   <operator-name>\n//                   ::= aa    # &&            \n//                   ::= ad    # & (unary)     \n//                   ::= an    # &             \n//                   ::= aN    # &=            \n//                   ::= aS    # =             \n//                   ::= cl    # ()            \n//                   ::= cm    # ,             \n//                   ::= co    # ~             \n//                   ::= cv <type>    # (cast)        \n//                   ::= da    # delete[]      \n//                   ::= de    # * (unary)     \n//                   ::= dl    # delete        \n//                   ::= dv    # /             \n//                   ::= dV    # /=            \n//                   ::= eo    # ^             \n//                   ::= eO    # ^=            \n//                   ::= eq    # ==            \n//                   ::= ge    # >=            \n//                   ::= gt    # >             \n//                   ::= ix    # []            \n//                   ::= le    # <=            \n//                   ::= li <source-name>  # operator \"\"\n//                   ::= ls    # <<            \n//                   ::= lS    # <<=           \n//                   ::= lt    # <             \n//                   ::= mi    # -             \n//                   ::= mI    # -=            \n//                   ::= ml    # *             \n//                   ::= mL    # *=            \n//                   ::= mm    # -- (postfix in <expression> context)           \n//                   ::= na    # new[]\n//                   ::= ne    # !=            \n//                   ::= ng    # - (unary)     \n//                   ::= nt    # !             \n//                   ::= nw    # new           \n//                   ::= oo    # ||            \n//                   ::= or    # |             \n//                   ::= oR    # |=            \n//                   ::= pm    # ->*           \n//                   ::= pl    # +             \n//                   ::= pL    # +=            \n//                   ::= pp    # ++ (postfix in <expression> context)\n//                   ::= ps    # + (unary)\n//                   ::= pt    # ->            \n//                   ::= qu    # ?             \n//                   ::= rm    # %             \n//                   ::= rM    # %=            \n//                   ::= rs    # >>            \n//                   ::= rS    # >>=           \n//                   ::= v <digit> <source-name>        # vendor extended operator\n\ntemplate <class C>\nconst char*\nparse_operator_name(const char* first, const char* last, C& db)\n{\n    if (last - first >= 2)\n    {\n        switch (first[0])\n        {\n        case 'a':\n            switch (first[1])\n            {\n            case 'a':\n                db.names.push_back(\"operator&&\");\n                first += 2;\n                break;\n            case 'd':\n            case 'n':\n                db.names.push_back(\"operator&\");\n                first += 2;\n                break;\n            case 'N':\n                db.names.push_back(\"operator&=\");\n                first += 2;\n                break;\n            case 'S':\n                db.names.push_back(\"operator=\");\n                first += 2;\n                break;\n            }\n            break;\n        case 'c':\n            switch (first[1])\n            {\n            case 'l':\n                db.names.push_back(\"operator()\");\n                first += 2;\n                break;\n            case 'm':\n                db.names.push_back(\"operator,\");\n                first += 2;\n                break;\n            case 'o':\n                db.names.push_back(\"operator~\");\n                first += 2;\n                break;\n            case 'v':\n                {\n                    bool try_to_parse_template_args = db.try_to_parse_template_args;\n                    db.try_to_parse_template_args = false;\n                    const char* t = parse_type(first+2, last, db);\n                    db.try_to_parse_template_args = try_to_parse_template_args;\n                    if (t != first+2)\n                    {\n                        if (db.names.empty())\n                            return first;\n                        db.names.back().first.insert(0, \"operator \");\n                        db.parsed_ctor_dtor_cv = true;\n                        first = t;\n                    }\n                }\n                break;\n            }\n            break;\n        case 'd':\n            switch (first[1])\n            {\n            case 'a':\n                db.names.push_back(\"operator delete[]\");\n                first += 2;\n                break;\n            case 'e':\n                db.names.push_back(\"operator*\");\n                first += 2;\n                break;\n            case 'l':\n                db.names.push_back(\"operator delete\");\n                first += 2;\n                break;\n            case 'v':\n                db.names.push_back(\"operator/\");\n                first += 2;\n                break;\n            case 'V':\n                db.names.push_back(\"operator/=\");\n                first += 2;\n                break;\n            }\n            break;\n        case 'e':\n            switch (first[1])\n            {\n            case 'o':\n                db.names.push_back(\"operator^\");\n                first += 2;\n                break;\n            case 'O':\n                db.names.push_back(\"operator^=\");\n                first += 2;\n                break;\n            case 'q':\n                db.names.push_back(\"operator==\");\n                first += 2;\n                break;\n            }\n            break;\n        case 'g':\n            switch (first[1])\n            {\n            case 'e':\n                db.names.push_back(\"operator>=\");\n                first += 2;\n                break;\n            case 't':\n                db.names.push_back(\"operator>\");\n                first += 2;\n                break;\n            }\n            break;\n        case 'i':\n            if (first[1] == 'x')\n            {\n                db.names.push_back(\"operator[]\");\n                first += 2;\n            }\n            break;\n        case 'l':\n            switch (first[1])\n            {\n            case 'e':\n                db.names.push_back(\"operator<=\");\n                first += 2;\n                break;\n            case 'i':\n                {\n                    const char* t = parse_source_name(first+2, last, db);\n                    if (t != first+2)\n                    {\n                        if (db.names.empty())\n                            return first;\n                        db.names.back().first.insert(0, \"operator\\\"\\\" \");\n                        first = t;\n                    }\n                }\n                break;\n            case 's':\n                db.names.push_back(\"operator<<\");\n                first += 2;\n                break;\n            case 'S':\n                db.names.push_back(\"operator<<=\");\n                first += 2;\n                break;\n            case 't':\n                db.names.push_back(\"operator<\");\n                first += 2;\n                break;\n            }\n            break;\n        case 'm':\n            switch (first[1])\n            {\n            case 'i':\n                db.names.push_back(\"operator-\");\n                first += 2;\n                break;\n            case 'I':\n                db.names.push_back(\"operator-=\");\n                first += 2;\n                break;\n            case 'l':\n                db.names.push_back(\"operator*\");\n                first += 2;\n                break;\n            case 'L':\n                db.names.push_back(\"operator*=\");\n                first += 2;\n                break;\n            case 'm':\n                db.names.push_back(\"operator--\");\n                first += 2;\n                break;\n            }\n            break;\n        case 'n':\n            switch (first[1])\n            {\n            case 'a':\n                db.names.push_back(\"operator new[]\");\n                first += 2;\n                break;\n            case 'e':\n                db.names.push_back(\"operator!=\");\n                first += 2;\n                break;\n            case 'g':\n                db.names.push_back(\"operator-\");\n                first += 2;\n                break;\n            case 't':\n                db.names.push_back(\"operator!\");\n                first += 2;\n                break;\n            case 'w':\n                db.names.push_back(\"operator new\");\n                first += 2;\n                break;\n            }\n            break;\n        case 'o':\n            switch (first[1])\n            {\n            case 'o':\n                db.names.push_back(\"operator||\");\n                first += 2;\n                break;\n            case 'r':\n                db.names.push_back(\"operator|\");\n                first += 2;\n                break;\n            case 'R':\n                db.names.push_back(\"operator|=\");\n                first += 2;\n                break;\n            }\n            break;\n        case 'p':\n            switch (first[1])\n            {\n            case 'm':\n                db.names.push_back(\"operator->*\");\n                first += 2;\n                break;\n            case 'l':\n                db.names.push_back(\"operator+\");\n                first += 2;\n                break;\n            case 'L':\n                db.names.push_back(\"operator+=\");\n                first += 2;\n                break;\n            case 'p':\n                db.names.push_back(\"operator++\");\n                first += 2;\n                break;\n            case 's':\n                db.names.push_back(\"operator+\");\n                first += 2;\n                break;\n            case 't':\n                db.names.push_back(\"operator->\");\n                first += 2;\n                break;\n            }\n            break;\n        case 'q':\n            if (first[1] == 'u')\n            {\n                db.names.push_back(\"operator?\");\n                first += 2;\n            }\n            break;\n        case 'r':\n            switch (first[1])\n            {\n            case 'm':\n                db.names.push_back(\"operator%\");\n                first += 2;\n                break;\n            case 'M':\n                db.names.push_back(\"operator%=\");\n                first += 2;\n                break;\n            case 's':\n                db.names.push_back(\"operator>>\");\n                first += 2;\n                break;\n            case 'S':\n                db.names.push_back(\"operator>>=\");\n                first += 2;\n                break;\n            }\n            break;\n        case 'v':\n            if (std::isdigit(first[1]))\n            {\n                const char* t = parse_source_name(first+2, last, db);\n                if (t != first+2)\n                {\n                    if (db.names.empty())\n                        return first;\n                    db.names.back().first.insert(0, \"operator \");\n                    first = t;\n                }\n            }\n            break;\n        }\n    }\n    return first;\n}\n\ntemplate <class C>\nconst char*\nparse_integer_literal(const char* first, const char* last, const typename C::String& lit, C& db)\n{\n    const char* t = parse_number(first, last);\n    if (t != first && t != last && *t == 'E')\n    {\n        if (lit.size() > 3)\n            db.names.push_back(\"(\" + lit + \")\");\n        else\n            db.names.emplace_back();\n        if (*first == 'n')\n        {\n            db.names.back().first += '-';\n            ++first;\n        }\n        db.names.back().first.append(first, t);\n        if (lit.size() <= 3)\n            db.names.back().first += lit;\n        first = t+1;\n    }\n    return first;\n}\n\n// <expr-primary> ::= L <type> <value number> E                          # integer literal\n//                ::= L <type> <value float> E                           # floating literal\n//                ::= L <string type> E                                  # string literal\n//                ::= L <nullptr type> E                                 # nullptr literal (i.e., \"LDnE\")\n//                ::= L <type> <real-part float> _ <imag-part float> E   # complex floating point literal (C 2000)\n//                ::= L <mangled-name> E                                 # external name\n\ntemplate <class C>\nconst char*\nparse_expr_primary(const char* first, const char* last, C& db)\n{\n    if (last - first >= 4 && *first == 'L')\n    {\n        switch (first[1])\n        {\n        case 'w':\n            {\n            const char* t = parse_integer_literal(first+2, last, \"wchar_t\", db);\n            if (t != first+2)\n                first = t;\n            }\n            break;\n        case 'b':\n            if (first[3] == 'E')\n            {\n                switch (first[2])\n                {\n                case '0':\n                    db.names.push_back(\"false\");\n                    first += 4;\n                    break;\n                case '1':\n                    db.names.push_back(\"true\");\n                    first += 4;\n                    break;\n                }\n            }\n            break;\n        case 'c':\n            {\n            const char* t = parse_integer_literal(first+2, last, \"char\", db);\n            if (t != first+2)\n                first = t;\n            }\n            break;\n        case 'a':\n            {\n            const char* t = parse_integer_literal(first+2, last, \"signed char\", db);\n            if (t != first+2)\n                first = t;\n            }\n            break;\n        case 'h':\n            {\n            const char* t = parse_integer_literal(first+2, last, \"unsigned char\", db);\n            if (t != first+2)\n                first = t;\n            }\n            break;\n        case 's':\n            {\n            const char* t = parse_integer_literal(first+2, last, \"short\", db);\n            if (t != first+2)\n                first = t;\n            }\n            break;\n        case 't':\n            {\n            const char* t = parse_integer_literal(first+2, last, \"unsigned short\", db);\n            if (t != first+2)\n                first = t;\n            }\n            break;\n        case 'i':\n            {\n            const char* t = parse_integer_literal(first+2, last, \"\", db);\n            if (t != first+2)\n                first = t;\n            }\n            break;\n        case 'j':\n            {\n            const char* t = parse_integer_literal(first+2, last, \"u\", db);\n            if (t != first+2)\n                first = t;\n            }\n            break;\n        case 'l':\n            {\n            const char* t = parse_integer_literal(first+2, last, \"l\", db);\n            if (t != first+2)\n                first = t;\n            }\n            break;\n        case 'm':\n            {\n            const char* t = parse_integer_literal(first+2, last, \"ul\", db);\n            if (t != first+2)\n                first = t;\n            }\n            break;\n        case 'x':\n            {\n            const char* t = parse_integer_literal(first+2, last, \"ll\", db);\n            if (t != first+2)\n                first = t;\n            }\n            break;\n        case 'y':\n            {\n            const char* t = parse_integer_literal(first+2, last, \"ull\", db);\n            if (t != first+2)\n                first = t;\n            }\n            break;\n        case 'n':\n            {\n            const char* t = parse_integer_literal(first+2, last, \"__int128\", db);\n            if (t != first+2)\n                first = t;\n            }\n            break;\n        case 'o':\n            {\n            const char* t = parse_integer_literal(first+2, last, \"unsigned __int128\", db);\n            if (t != first+2)\n                first = t;\n            }\n            break;\n        case 'f':\n            {\n            const char* t = parse_floating_number<float>(first+2, last, db);\n            if (t != first+2)\n                first = t;\n            }\n            break;\n        case 'd':\n            {\n            const char* t = parse_floating_number<double>(first+2, last, db);\n            if (t != first+2)\n                first = t;\n            }\n            break;\n         case 'e':\n            {\n            const char* t = parse_floating_number<long double>(first+2, last, db);\n            if (t != first+2)\n                first = t;\n            }\n            break;\n        case '_':\n            if (first[2] == 'Z')\n            {\n                const char* t = parse_encoding(first+3, last, db);\n                if (t != first+3 && t != last && *t == 'E')\n                    first = t+1;\n            }\n            break;\n        case 'T':\n            // Invalid mangled name per\n            //   http://sourcerytools.com/pipermail/cxx-abi-dev/2011-August/002422.html\n            break;\n        default:\n            {\n                // might be named type\n                const char* t = parse_type(first+1, last, db);\n                if (t != first+1 && t != last)\n                {\n                    if (*t != 'E')\n                    {\n                        const char* n = t;\n                        for (; n != last && isdigit(*n); ++n)\n                            ;\n                        if (n != t && n != last && *n == 'E')\n                        {\n                            if (db.names.empty())\n                                return first;\n                            db.names.back() = \"(\" + db.names.back().move_full() + \")\" + typename C::String(t, n);\n                            first = n+1;\n                            break;\n                        }\n                    }\n                    else\n                    {\n                        first = t+1;\n                        break;\n                    }\n                }\n            }\n        }\n    }\n    return first;\n}\n\ntemplate <class String>\nString\nbase_name(String& s)\n{\n    if (s.empty())\n        return s;\n    if (s == \"std::string\")\n    {\n        s = \"std::basic_string<char, std::char_traits<char>, std::allocator<char> >\";\n        return \"basic_string\";\n    }\n    if (s == \"std::istream\")\n    {\n        s = \"std::basic_istream<char, std::char_traits<char> >\";\n        return \"basic_istream\";\n    }\n    if (s == \"std::ostream\")\n    {\n        s = \"std::basic_ostream<char, std::char_traits<char> >\";\n        return \"basic_ostream\";\n    }\n    if (s == \"std::iostream\")\n    {\n        s = \"std::basic_iostream<char, std::char_traits<char> >\";\n        return \"basic_iostream\";\n    }\n    const char* const pf = s.data();\n    const char* pe = pf + s.size();\n    if (pe[-1] == '>')\n    {\n        unsigned c = 1;\n        while (true)\n        {\n            if (--pe == pf)\n                return String();\n            if (pe[-1] == '<')\n            {\n                if (--c == 0)\n                {\n                    --pe;\n                    break;\n                }\n            }\n            else if (pe[-1] == '>')\n                ++c;\n        }\n    }\n    const char* p0 = pe - 1;\n    for (; p0 != pf; --p0)\n    {\n        if (*p0 == ':')\n        {\n            ++p0;\n            break;\n        }\n    }\n    return String(p0, pe);\n}\n\n// <ctor-dtor-name> ::= C1    # complete object constructor\n//                  ::= C2    # base object constructor\n//                  ::= C3    # complete object allocating constructor\n//   extension      ::= C5    # ?\n//                  ::= D0    # deleting destructor\n//                  ::= D1    # complete object destructor\n//                  ::= D2    # base object destructor\n//   extension      ::= D5    # ?\n\ntemplate <class C>\nconst char*\nparse_ctor_dtor_name(const char* first, const char* last, C& db)\n{\n    if (last-first >= 2 && !db.names.empty())\n    {\n        switch (first[0])\n        {\n        case 'C':\n            switch (first[1])\n            {\n            case '1':\n            case '2':\n            case '3':\n            case '5':\n                if (db.names.empty())\n                    return first;\n                db.names.push_back(base_name(db.names.back().first));\n                first += 2;\n                db.parsed_ctor_dtor_cv = true;\n                break;\n            }\n            break;\n        case 'D':\n            switch (first[1])\n            {\n            case '0':\n            case '1':\n            case '2':\n            case '5':\n                if (db.names.empty())\n                    return first;\n                db.names.push_back(\"~\" + base_name(db.names.back().first));\n                first += 2;\n                db.parsed_ctor_dtor_cv = true;\n                break;\n            }\n            break;\n        }\n    }\n    return first;\n}\n\n// <unnamed-type-name> ::= Ut [ <nonnegative number> ] _\n//                     ::= <closure-type-name>\n// \n// <closure-type-name> ::= Ul <lambda-sig> E [ <nonnegative number> ] _ \n// \n// <lambda-sig> ::= <parameter type>+  # Parameter types or \"v\" if the lambda has no parameters\n\ntemplate <class C>\nconst char*\nparse_unnamed_type_name(const char* first, const char* last, C& db)\n{\n    if (last - first > 2 && first[0] == 'U')\n    {\n        char type = first[1];\n        switch (type)\n        {\n        case 't':\n          {\n            db.names.push_back(typename C::String(\"'unnamed\"));\n            const char* t0 = first+2;\n            if (t0 == last)\n            {\n                db.names.pop_back();\n                return first;\n            }\n            if (std::isdigit(*t0))\n            {\n                const char* t1 = t0 + 1;\n                while (t1 != last && std::isdigit(*t1))\n                    ++t1;\n                db.names.back().first.append(t0, t1);\n                t0 = t1;\n            }\n            db.names.back().first.push_back('\\'');\n            if (t0 == last || *t0 != '_')\n            {\n                db.names.pop_back();\n                return first;\n            }\n            first = t0 + 1;\n          }\n            break;\n        case 'l':\n          {\n            db.names.push_back(typename C::String(\"'lambda'(\"));\n            const char* t0 = first+2;\n            if (first[2] == 'v')\n            {\n                db.names.back().first += ')';\n                ++t0;\n            }\n            else\n            {\n                const char* t1 = parse_type(t0, last, db);\n                if (t1 == t0)\n                {\n                    db.names.pop_back();\n                    return first;\n                }\n                if (db.names.size() < 2)\n                    return first;\n                auto tmp = db.names.back().move_full();\n                db.names.pop_back();\n                db.names.back().first.append(tmp);\n                t0 = t1;\n                while (true)\n                {\n                    t1 = parse_type(t0, last, db);\n                    if (t1 == t0)\n                        break;\n                    if (db.names.size() < 2)\n                        return first;\n                    tmp = db.names.back().move_full();\n                    db.names.pop_back();\n                    if (!tmp.empty())\n                    {\n                        db.names.back().first.append(\", \");\n                        db.names.back().first.append(tmp);\n                    }\n                    t0 = t1;\n                }\n                db.names.back().first.append(\")\");\n            }\n            if (t0 == last || *t0 != 'E')\n            {\n                db.names.pop_back();\n                return first;\n            }\n            ++t0;\n            if (t0 == last)\n            {\n                db.names.pop_back();\n                return first;\n            }\n            if (std::isdigit(*t0))\n            {\n                const char* t1 = t0 + 1;\n                while (t1 != last && std::isdigit(*t1))\n                    ++t1;\n                db.names.back().first.insert(db.names.back().first.begin()+7, t0, t1);\n                t0 = t1;\n            }\n            if (t0 == last || *t0 != '_')\n            {\n                db.names.pop_back();\n                return first;\n            }\n            first = t0 + 1;\n          }\n            break;\n        }\n    }\n    return first;\n}\n\n// <unqualified-name> ::= <operator-name>\n//                    ::= <ctor-dtor-name>\n//                    ::= <source-name>   \n//                    ::= <unnamed-type-name>\n\ntemplate <class C>\nconst char*\nparse_unqualified_name(const char* first, const char* last, C& db)\n{\n    if (first != last)\n    {\n        const char* t;\n        switch (*first)\n        {\n        case 'C':\n        case 'D':\n            t = parse_ctor_dtor_name(first, last, db);\n            if (t != first)\n                first = t;\n            break;\n        case 'U':\n            t = parse_unnamed_type_name(first, last, db);\n            if (t != first)\n                first = t;\n            break;\n        case '1':\n        case '2':\n        case '3':\n        case '4':\n        case '5':\n        case '6':\n        case '7':\n        case '8':\n        case '9':\n            t = parse_source_name(first, last, db);\n            if (t != first)\n                first = t;\n            break;\n        default:\n            t = parse_operator_name(first, last, db);\n            if (t != first)\n                first = t;\n            break;\n        };\n    }\n    return first;\n}\n\n// <unscoped-name> ::= <unqualified-name>\n//                 ::= St <unqualified-name>   # ::std::\n// extension       ::= StL<unqualified-name>\n\ntemplate <class C>\nconst char*\nparse_unscoped_name(const char* first, const char* last, C& db)\n{\n    if (last - first >= 2)\n    {\n        const char* t0 = first;\n        bool St = false;\n        if (first[0] == 'S' && first[1] == 't')\n        {\n            t0 += 2;\n            St = true;\n            if (t0 != last && *t0 == 'L')\n                ++t0;\n        }\n        const char* t1 = parse_unqualified_name(t0, last, db);\n        if (t1 != t0)\n        {\n            if (St)\n            {\n                if (db.names.empty())\n                    return first;\n                db.names.back().first.insert(0, \"std::\");\n            }\n            first = t1;\n        }\n    }\n    return first;\n}\n\n// at <type>                                            # alignof (a type)\n\ntemplate <class C>\nconst char*\nparse_alignof_type(const char* first, const char* last, C& db)\n{\n    if (last - first >= 3 && first[0] == 'a' && first[1] == 't')\n    {\n        const char* t = parse_type(first+2, last, db);\n        if (t != first+2)\n        {\n            if (db.names.empty())\n                return first;\n            db.names.back().first = \"alignof (\" + db.names.back().move_full() + \")\";\n            first = t;\n        }\n    }\n    return first;\n}\n\n// az <expression>                                            # alignof (a expression)\n\ntemplate <class C>\nconst char*\nparse_alignof_expr(const char* first, const char* last, C& db)\n{\n    if (last - first >= 3 && first[0] == 'a' && first[1] == 'z')\n    {\n        const char* t = parse_expression(first+2, last, db);\n        if (t != first+2)\n        {\n            if (db.names.empty())\n                return first;\n            db.names.back().first = \"alignof (\" + db.names.back().move_full() + \")\";\n            first = t;\n        }\n    }\n    return first;\n}\n\ntemplate <class C>\nconst char*\nparse_noexcept_expression(const char* first, const char* last, C& db)\n{\n    const char* t1 = parse_expression(first, last, db);\n    if (t1 != first)\n    {\n        if (db.names.empty())\n            return first;\n        db.names.back().first =  \"noexcept (\" + db.names.back().move_full() + \")\";\n        first = t1;\n    }\n    return first;\n}\n\ntemplate <class C>\nconst char*\nparse_prefix_expression(const char* first, const char* last, const typename C::String& op, C& db)\n{\n    const char* t1 = parse_expression(first, last, db);\n    if (t1 != first)\n    {\n        if (db.names.empty())\n            return first;\n        db.names.back().first =  op + \"(\" + db.names.back().move_full() + \")\";\n        first = t1;\n    }\n    return first;\n}\n\ntemplate <class C>\nconst char*\nparse_binary_expression(const char* first, const char* last, const typename C::String& op, C& db)\n{\n    const char* t1 = parse_expression(first, last, db);\n    if (t1 != first)\n    {\n        const char* t2 = parse_expression(t1, last, db);\n        if (t2 != t1)\n        {\n            if (db.names.size() < 2)\n                return first;\n            auto op2 = db.names.back().move_full();\n            db.names.pop_back();\n            auto op1 = db.names.back().move_full();\n            auto& nm = db.names.back().first;\n            nm.clear();\n            if (op == \">\")\n                nm += '(';\n            nm += \"(\" + op1 + \") \" + op + \" (\" + op2 + \")\";\n            if (op == \">\")\n                nm += ')';\n            first = t2;\n        }\n        else\n            db.names.pop_back();\n    }\n    return first;\n}\n\n// <expression> ::= <unary operator-name> <expression>\n//              ::= <binary operator-name> <expression> <expression>\n//              ::= <ternary operator-name> <expression> <expression> <expression>\n//              ::= cl <expression>+ E                                   # call\n//              ::= cv <type> <expression>                               # conversion with one argument\n//              ::= cv <type> _ <expression>* E                          # conversion with a different number of arguments\n//              ::= [gs] nw <expression>* _ <type> E                     # new (expr-list) type\n//              ::= [gs] nw <expression>* _ <type> <initializer>         # new (expr-list) type (init)\n//              ::= [gs] na <expression>* _ <type> E                     # new[] (expr-list) type\n//              ::= [gs] na <expression>* _ <type> <initializer>         # new[] (expr-list) type (init)\n//              ::= [gs] dl <expression>                                 # delete expression\n//              ::= [gs] da <expression>                                 # delete[] expression\n//              ::= pp_ <expression>                                     # prefix ++\n//              ::= mm_ <expression>                                     # prefix --\n//              ::= ti <type>                                            # typeid (type)\n//              ::= te <expression>                                      # typeid (expression)\n//              ::= dc <type> <expression>                               # dynamic_cast<type> (expression)\n//              ::= sc <type> <expression>                               # static_cast<type> (expression)\n//              ::= cc <type> <expression>                               # const_cast<type> (expression)\n//              ::= rc <type> <expression>                               # reinterpret_cast<type> (expression)\n//              ::= st <type>                                            # sizeof (a type)\n//              ::= sz <expression>                                      # sizeof (an expression)\n//              ::= at <type>                                            # alignof (a type)\n//              ::= az <expression>                                      # alignof (an expression)\n//              ::= nx <expression>                                      # noexcept (expression)\n//              ::= <template-param>\n//              ::= <function-param>\n//              ::= dt <expression> <unresolved-name>                    # expr.name\n//              ::= pt <expression> <unresolved-name>                    # expr->name\n//              ::= ds <expression> <expression>                         # expr.*expr\n//              ::= sZ <template-param>                                  # size of a parameter pack\n//              ::= sZ <function-param>                                  # size of a function parameter pack\n//              ::= sp <expression>                                      # pack expansion\n//              ::= tw <expression>                                      # throw expression\n//              ::= tr                                                   # throw with no operand (rethrow)\n//              ::= <unresolved-name>                                    # f(p), N::f(p), ::f(p),\n//                                                                       # freestanding dependent name (e.g., T::x),\n//                                                                       # objectless nonstatic member reference\n//              ::= <expr-primary>\n\ntemplate <class C>\nconst char*\nparse_expression(const char* first, const char* last, C& db)\n{\n    if (last - first >= 2)\n    {\n        const char* t = first;\n        bool parsed_gs = false;\n        if (last - first >= 4 && t[0] == 'g' && t[1] == 's')\n        {\n            t += 2;\n            parsed_gs = true;\n        }\n        switch (*t)\n        {\n        case 'L':\n            first = parse_expr_primary(first, last, db);\n            break;\n        case 'T':\n            first = parse_template_param(first, last, db);\n            break;\n        case 'f':\n            first = parse_function_param(first, last, db);\n            break;\n        case 'a':\n            switch (t[1])\n            {\n            case 'a':\n                t = parse_binary_expression(first+2, last, \"&&\", db);\n                if (t != first+2)\n                    first = t;\n                break;\n            case 'd':\n                t = parse_prefix_expression(first+2, last, \"&\", db);\n                if (t != first+2)\n                    first = t;\n                break;\n            case 'n':\n                t = parse_binary_expression(first+2, last, \"&\", db);\n                if (t != first+2)\n                    first = t;\n                break;\n            case 'N':\n                t = parse_binary_expression(first+2, last, \"&=\", db);\n                if (t != first+2)\n                    first = t;\n                break;\n            case 'S':\n                t = parse_binary_expression(first+2, last, \"=\", db);\n                if (t != first+2)\n                    first = t;\n                break;\n            case 't':\n                first = parse_alignof_type(first, last, db);\n                break;\n            case 'z':\n                first = parse_alignof_expr(first, last, db);\n                break;\n            }\n            break;\n        case 'c':\n            switch (t[1])\n            {\n            case 'c':\n                first = parse_const_cast_expr(first, last, db);\n                break;\n            case 'l':\n                first = parse_call_expr(first, last, db);\n                break;\n            case 'm':\n                t = parse_binary_expression(first+2, last, \",\", db);\n                if (t != first+2)\n                    first = t;\n                break;\n            case 'o':\n                t = parse_prefix_expression(first+2, last, \"~\", db);\n                if (t != first+2)\n                    first = t;\n                break;\n            case 'v':\n                first = parse_conversion_expr(first, last, db);\n                break;\n            }\n            break;\n        case 'd':\n            switch (t[1])\n            {\n            case 'a':\n                {\n                    const char* t1 = parse_expression(t+2, last, db);\n                    if (t1 != t+2)\n                    {\n                        if (db.names.empty())\n                            return first;\n                        db.names.back().first = (parsed_gs ? typename C::String(\"::\") : typename C::String()) +\n                                          \"delete[] \" + db.names.back().move_full();\n                        first = t1;\n                    }\n                }\n                break;\n            case 'c':\n                first = parse_dynamic_cast_expr(first, last, db);\n                break;\n            case 'e':\n                t = parse_prefix_expression(first+2, last, \"*\", db);\n                if (t != first+2)\n                    first = t;\n                break;\n            case 'l':\n                {\n                    const char* t1 = parse_expression(t+2, last, db);\n                    if (t1 != t+2)\n                    {\n                        if (db.names.empty())\n                            return first;\n                        db.names.back().first = (parsed_gs ? typename C::String(\"::\") : typename C::String()) +\n                                          \"delete \" + db.names.back().move_full();\n                        first = t1;\n                    }\n                }\n                break;\n            case 'n':\n                return parse_unresolved_name(first, last, db);\n            case 's':\n                first = parse_dot_star_expr(first, last, db);\n                break;\n            case 't':\n                first = parse_dot_expr(first, last, db);\n                break;\n            case 'v':\n                t = parse_binary_expression(first+2, last, \"/\", db);\n                if (t != first+2)\n                    first = t;\n                break;\n            case 'V':\n                t = parse_binary_expression(first+2, last, \"/=\", db);\n                if (t != first+2)\n                    first = t;\n                break;\n            }\n            break;\n        case 'e':\n            switch (t[1])\n            {\n            case 'o':\n                t = parse_binary_expression(first+2, last, \"^\", db);\n                if (t != first+2)\n                    first = t;\n                break;\n            case 'O':\n                t = parse_binary_expression(first+2, last, \"^=\", db);\n                if (t != first+2)\n                    first = t;\n                break;\n            case 'q':\n                t = parse_binary_expression(first+2, last, \"==\", db);\n                if (t != first+2)\n                    first = t;\n                break;\n            }\n            break;\n        case 'g':\n            switch (t[1])\n            {\n            case 'e':\n                t = parse_binary_expression(first+2, last, \">=\", db);\n                if (t != first+2)\n                    first = t;\n                break;\n            case 't':\n                t = parse_binary_expression(first+2, last, \">\", db);\n                if (t != first+2)\n                    first = t;\n                break;\n            }\n            break;\n        case 'i':\n            if (t[1] == 'x')\n            {\n                const char* t1 = parse_expression(first+2, last, db);\n                if (t1 != first+2)\n                {\n                    const char* t2 = parse_expression(t1, last, db);\n                    if (t2 != t1)\n                    {\n                        if (db.names.size() < 2)\n                            return first;\n                        auto op2 = db.names.back().move_full();\n                        db.names.pop_back();\n                        auto op1 = db.names.back().move_full();\n                        db.names.back() = \"(\" + op1 + \")[\" + op2 + \"]\";\n                        first = t2;\n                    }\n                    else\n                        db.names.pop_back();\n                }\n            }\n            break;\n        case 'l':\n            switch (t[1])\n            {\n            case 'e':\n                t = parse_binary_expression(first+2, last, \"<=\", db);\n                if (t != first+2)\n                    first = t;\n                break;\n            case 's':\n                t = parse_binary_expression(first+2, last, \"<<\", db);\n                if (t != first+2)\n                    first = t;\n                break;\n            case 'S':\n                t = parse_binary_expression(first+2, last, \"<<=\", db);\n                if (t != first+2)\n                    first = t;\n                break;\n            case 't':\n                t = parse_binary_expression(first+2, last, \"<\", db);\n                if (t != first+2)\n                    first = t;\n                break;\n            }\n            break;\n        case 'm':\n            switch (t[1])\n            {\n            case 'i':\n                t = parse_binary_expression(first+2, last, \"-\", db);\n                if (t != first+2)\n                    first = t;\n                break;\n            case 'I':\n                t = parse_binary_expression(first+2, last, \"-=\", db);\n                if (t != first+2)\n                    first = t;\n                break;\n            case 'l':\n                t = parse_binary_expression(first+2, last, \"*\", db);\n                if (t != first+2)\n                    first = t;\n                break;\n            case 'L':\n                t = parse_binary_expression(first+2, last, \"*=\", db);\n                if (t != first+2)\n                    first = t;\n                break;\n            case 'm':\n                if (first+2 != last && first[2] == '_')\n                {\n                    t = parse_prefix_expression(first+3, last, \"--\", db);\n                    if (t != first+3)\n                        first = t;\n                }\n                else\n                {\n                    const char* t1 = parse_expression(first+2, last, db);\n                    if (t1 != first+2)\n                    {\n                        if (db.names.empty())\n                            return first;\n                        db.names.back() = \"(\" + db.names.back().move_full() + \")--\";\n                        first = t1;\n                    }\n                }\n                break;\n            }\n            break;\n        case 'n':\n            switch (t[1])\n            {\n            case 'a':\n            case 'w':\n                first = parse_new_expr(first, last, db);\n                break;\n            case 'e':\n                t = parse_binary_expression(first+2, last, \"!=\", db);\n                if (t != first+2)\n                    first = t;\n                break;\n            case 'g':\n                t = parse_prefix_expression(first+2, last, \"-\", db);\n                if (t != first+2)\n                    first = t;\n                break;\n            case 't':\n                t = parse_prefix_expression(first+2, last, \"!\", db);\n                if (t != first+2)\n                    first = t;\n                break;\n            case 'x':\n                t = parse_noexcept_expression(first+2, last, db);\n                if (t != first+2)\n                    first = t;\n                break;\n            }\n            break;\n        case 'o':\n            switch (t[1])\n            {\n            case 'n':\n                return parse_unresolved_name(first, last, db);\n            case 'o':\n                t = parse_binary_expression(first+2, last, \"||\", db);\n                if (t != first+2)\n                    first = t;\n                break;\n            case 'r':\n                t = parse_binary_expression(first+2, last, \"|\", db);\n                if (t != first+2)\n                    first = t;\n                break;\n            case 'R':\n                t = parse_binary_expression(first+2, last, \"|=\", db);\n                if (t != first+2)\n                    first = t;\n                break;\n            }\n            break;\n        case 'p':\n            switch (t[1])\n            {\n            case 'm':\n                t = parse_binary_expression(first+2, last, \"->*\", db);\n                if (t != first+2)\n                    first = t;\n                break;\n            case 'l':\n                t = parse_binary_expression(first+2, last, \"+\", db);\n                if (t != first+2)\n                    first = t;\n                break;\n            case 'L':\n                t = parse_binary_expression(first+2, last, \"+=\", db);\n                if (t != first+2)\n                    first = t;\n                break;\n            case 'p':\n                if (first+2 != last && first[2] == '_')\n                {\n                    t = parse_prefix_expression(first+3, last, \"++\", db);\n                    if (t != first+3)\n                        first = t;\n                }\n                else\n                {\n                    const char* t1 = parse_expression(first+2, last, db);\n                    if (t1 != first+2)\n                    {\n                        if (db.names.empty())\n                            return first;\n                        db.names.back() = \"(\" + db.names.back().move_full() + \")++\";\n                        first = t1;\n                    }\n                }\n                break;\n            case 's':\n                t = parse_prefix_expression(first+2, last, \"+\", db);\n                if (t != first+2)\n                    first = t;\n                break;\n            case 't':\n                first = parse_arrow_expr(first, last, db);\n                break;\n            }\n            break;\n        case 'q':\n            if (t[1] == 'u')\n            {\n                const char* t1 = parse_expression(first+2, last, db);\n                if (t1 != first+2)\n                {\n                    const char* t2 = parse_expression(t1, last, db);\n                    if (t2 != t1)\n                    {\n                        const char* t3 = parse_expression(t2, last, db);\n                        if (t3 != t2)\n                        {\n                            if (db.names.size() < 3)\n                                return first;\n                            auto op3 = db.names.back().move_full();\n                            db.names.pop_back();\n                            auto op2 = db.names.back().move_full();\n                            db.names.pop_back();\n                            auto op1 = db.names.back().move_full();\n                            db.names.back() = \"(\" + op1 + \") ? (\" + op2 + \") : (\" + op3 + \")\";\n                            first = t3;\n                        }\n                        else\n                        {\n                            db.names.pop_back();\n                            db.names.pop_back();\n                        }\n                    }\n                    else\n                        db.names.pop_back();\n                }\n            }\n            break;\n        case 'r':\n            switch (t[1])\n            {\n            case 'c':\n                first = parse_reinterpret_cast_expr(first, last, db);\n                break;\n            case 'm':\n                t = parse_binary_expression(first+2, last, \"%\", db);\n                if (t != first+2)\n                    first = t;\n                break;\n            case 'M':\n                t = parse_binary_expression(first+2, last, \"%=\", db);\n                if (t != first+2)\n                    first = t;\n                break;\n            case 's':\n                t = parse_binary_expression(first+2, last, \">>\", db);\n                if (t != first+2)\n                    first = t;\n                break;\n            case 'S':\n                t = parse_binary_expression(first+2, last, \">>=\", db);\n                if (t != first+2)\n                    first = t;\n                break;\n            }\n            break;\n        case 's':\n            switch (t[1])\n            {\n            case 'c':\n                first = parse_static_cast_expr(first, last, db);\n                break;\n            case 'p':\n                first = parse_pack_expansion(first, last, db);\n                break;\n            case 'r':\n                return parse_unresolved_name(first, last, db);\n            case 't':\n                first = parse_sizeof_type_expr(first, last, db);\n                break;\n            case 'z':\n                first = parse_sizeof_expr_expr(first, last, db);\n                break;\n            case 'Z':\n                if (last - t >= 3)\n                {\n                    switch (t[2])\n                    {\n                    case 'T':\n                        first = parse_sizeof_param_pack_expr(first, last, db);\n                        break;\n                    case 'f':\n                        first = parse_sizeof_function_param_pack_expr(first, last, db);\n                        break;\n                    }\n                }\n                break;\n            }\n            break;\n        case 't':\n            switch (t[1])\n            {\n            case 'e':\n            case 'i':\n                first = parse_typeid_expr(first, last, db);\n                break;\n            case 'r':\n                db.names.push_back(\"throw\");\n                first += 2;\n                break;\n            case 'w':\n                first = parse_throw_expr(first, last, db);\n                break;\n            }\n            break;\n        case '1':\n        case '2':\n        case '3':\n        case '4':\n        case '5':\n        case '6':\n        case '7':\n        case '8':\n        case '9':\n            return parse_unresolved_name(first, last, db);\n        }\n    }\n    return first;\n}\n\n// <template-arg> ::= <type>                                             # type or template\n//                ::= X <expression> E                                   # expression\n//                ::= <expr-primary>                                     # simple expressions\n//                ::= J <template-arg>* E                                # argument pack\n//                ::= LZ <encoding> E                                    # extension\n\ntemplate <class C>\nconst char*\nparse_template_arg(const char* first, const char* last, C& db)\n{\n    if (first != last)\n    {\n        const char* t;\n        switch (*first)\n        {\n        case 'X':\n            t = parse_expression(first+1, last, db);\n            if (t != first+1)\n            {\n                if (t != last && *t == 'E')\n                    first = t+1;\n            }\n            break;\n        case 'J':\n            t = first+1;\n            if (t == last)\n                return first;\n            while (*t != 'E')\n            {\n                const char* t1 = parse_template_arg(t, last, db);\n                if (t1 == t)\n                    return first;\n                t = t1;\n            }\n            first = t+1;\n            break;\n        case 'L':\n            // <expr-primary> or LZ <encoding> E\n            if (first+1 != last && first[1] == 'Z')\n            {\n                t = parse_encoding(first+2, last, db);\n                if (t != first+2 && t != last && *t == 'E')\n                    first = t+1;\n            }\n            else\n                first = parse_expr_primary(first, last, db);\n            break;\n        default:\n            // <type>\n            first = parse_type(first, last, db);\n            break;\n        }\n    }\n    return first;\n}\n\n// <template-args> ::= I <template-arg>* E\n//     extension, the abi says <template-arg>+\n\ntemplate <class C>\nconst char*\nparse_template_args(const char* first, const char* last, C& db)\n{\n    if (last - first >= 2 && *first == 'I')\n    {\n        if (db.tag_templates)\n            db.template_param.back().clear();\n        const char* t = first+1;\n        typename C::String args(\"<\");\n        while (*t != 'E')\n        {\n            if (db.tag_templates)\n                db.template_param.emplace_back(db.names.get_allocator());\n            size_t k0 = db.names.size();\n            const char* t1 = parse_template_arg(t, last, db);\n            size_t k1 = db.names.size();\n            if (db.tag_templates)\n                db.template_param.pop_back();\n            if (t1 == t || t1 == last)\n                return first;\n            if (db.tag_templates)\n            {\n                db.template_param.back().emplace_back(db.names.get_allocator());\n                for (size_t k = k0; k < k1; ++k)\n                    db.template_param.back().back().push_back(db.names[k]);\n            }\n            for (size_t k = k0; k < k1; ++k)\n            {\n                if (args.size() > 1)\n                    args += \", \";\n                args += db.names[k].move_full();\n            }\n            for (; k1 != k0; --k1)\n                db.names.pop_back();\n            t = t1;\n        }\n        first = t + 1;\n        if (args.back() != '>')\n            args += \">\";\n        else\n            args += \" >\";\n        db.names.push_back(std::move(args));\n        \n    }\n    return first;\n}\n\n// <nested-name> ::= N [<CV-qualifiers>] [<ref-qualifier>] <prefix> <unqualified-name> E\n//               ::= N [<CV-qualifiers>] [<ref-qualifier>] <template-prefix> <template-args> E\n// \n// <prefix> ::= <prefix> <unqualified-name>\n//          ::= <template-prefix> <template-args>\n//          ::= <template-param>\n//          ::= <decltype>\n//          ::= # empty\n//          ::= <substitution>\n//          ::= <prefix> <data-member-prefix>\n//  extension ::= L\n// \n// <template-prefix> ::= <prefix> <template unqualified-name>\n//                   ::= <template-param>\n//                   ::= <substitution>\n\ntemplate <class C>\nconst char*\nparse_nested_name(const char* first, const char* last, C& db,\n                  bool* ends_with_template_args)\n{\n    if (first != last && *first == 'N')\n    {\n        unsigned cv;\n        const char* t0 = parse_cv_qualifiers(first+1, last, cv);\n        if (t0 == last)\n            return first;\n        db.ref = 0;\n        if (*t0 == 'R')\n        {\n            db.ref = 1;\n            ++t0;\n        }\n        else if (*t0 == 'O')\n        {\n            db.ref = 2;\n            ++t0;\n        }\n        db.names.emplace_back();\n        if (last - t0 >= 2 && t0[0] == 'S' && t0[1] == 't')\n        {\n            t0 += 2;\n            db.names.back().first = \"std\";\n        }\n        if (t0 == last)\n        {\n            db.names.pop_back();\n            return first;\n        }\n        bool pop_subs = false;\n        bool component_ends_with_template_args = false;\n        while (*t0 != 'E')\n        {\n            component_ends_with_template_args = false;\n            const char* t1;\n            switch (*t0)\n            {\n            case 'S':\n                if (t0 + 1 != last && t0[1] == 't')\n                    goto do_parse_unqualified_name;\n                t1 = parse_substitution(t0, last, db);\n                if (t1 != t0 && t1 != last)\n                {\n                    auto name = db.names.back().move_full();\n                    db.names.pop_back();\n                    if (!db.names.back().first.empty())\n                    {\n                        db.names.back().first += \"::\" + name;\n                        db.subs.push_back(typename C::sub_type(1, db.names.back(), db.names.get_allocator()));\n                    }\n                    else\n                        db.names.back().first = name;\n                    pop_subs = true;\n                    t0 = t1;\n                }\n                else\n                    return first;\n                break;\n            case 'T':\n                t1 = parse_template_param(t0, last, db);\n                if (t1 != t0 && t1 != last)\n                {\n                    auto name = db.names.back().move_full();\n                    db.names.pop_back();\n                    if (!db.names.back().first.empty())\n                        db.names.back().first += \"::\" + name;\n                    else\n                        db.names.back().first = name;\n                    db.subs.push_back(typename C::sub_type(1, db.names.back(), db.names.get_allocator()));\n                    pop_subs = true;\n                    t0 = t1;\n                }\n                else\n                    return first;\n                break;\n            case 'D':\n                if (t0 + 1 != last && t0[1] != 't' && t0[1] != 'T')\n                    goto do_parse_unqualified_name;\n                t1 = parse_decltype(t0, last, db);\n                if (t1 != t0 && t1 != last)\n                {\n                    auto name = db.names.back().move_full();\n                    db.names.pop_back();\n                    if (!db.names.back().first.empty())\n                        db.names.back().first += \"::\" + name;\n                    else\n                        db.names.back().first = name;\n                    db.subs.push_back(typename C::sub_type(1, db.names.back(), db.names.get_allocator()));\n                    pop_subs = true;\n                    t0 = t1;\n                }\n                else\n                    return first;\n                break;\n            case 'I':\n                t1 = parse_template_args(t0, last, db);\n                if (t1 != t0 && t1 != last)\n                {\n                    auto name = db.names.back().move_full();\n                    db.names.pop_back();\n                    db.names.back().first += name;\n                    db.subs.push_back(typename C::sub_type(1, db.names.back(), db.names.get_allocator()));\n                    t0 = t1;\n                    component_ends_with_template_args = true;\n                }\n                else\n                    return first;\n                break;\n            case 'L':\n                if (++t0 == last)\n                    return first;\n                break;\n            default:\n            do_parse_unqualified_name:\n                t1 = parse_unqualified_name(t0, last, db);\n                if (t1 != t0 && t1 != last)\n                {\n                    auto name = db.names.back().move_full();\n                    db.names.pop_back();\n                    if (!db.names.back().first.empty())\n                        db.names.back().first += \"::\" + name;\n                    else\n                        db.names.back().first = name;\n                    db.subs.push_back(typename C::sub_type(1, db.names.back(), db.names.get_allocator()));\n                    pop_subs = true;\n                    t0 = t1;\n                }\n                else\n                    return first;\n            }\n        }\n        first = t0 + 1;\n        db.cv = cv;\n        if (pop_subs && !db.subs.empty())\n            db.subs.pop_back();\n        if (ends_with_template_args)\n            *ends_with_template_args = component_ends_with_template_args;\n    }\n    return first;\n}\n\n// <discriminator> := _ <non-negative number>      # when number < 10\n//                 := __ <non-negative number> _   # when number >= 10\n//  extension      := decimal-digit+               # at the end of string\n\nconst char*\nparse_discriminator(const char* first, const char* last)\n{\n    // parse but ignore discriminator\n    if (first != last)\n    {\n        if (*first == '_')\n        {\n            const char* t1 = first+1;\n            if (t1 != last)\n            {\n                if (std::isdigit(*t1))\n                    first = t1+1;\n                else if (*t1 == '_')\n                {\n                    for (++t1; t1 != last && std::isdigit(*t1); ++t1)\n                        ;\n                    if (t1 != last && *t1 == '_')\n                        first = t1 + 1;\n                }\n            }\n        }\n        else if (std::isdigit(*first))\n        {\n            const char* t1 = first+1;\n            for (; t1 != last && std::isdigit(*t1); ++t1)\n                ;\n            if (t1 == last)\n                first = last;\n        }\n    }\n    return first;\n}\n\n// <local-name> := Z <function encoding> E <entity name> [<discriminator>]\n//              := Z <function encoding> E s [<discriminator>]\n//              := Z <function encoding> Ed [ <parameter number> ] _ <entity name>\n\ntemplate <class C>\nconst char*\nparse_local_name(const char* first, const char* last, C& db,\n                 bool* ends_with_template_args)\n{\n    if (first != last && *first == 'Z')\n    {\n        const char* t = parse_encoding(first+1, last, db);\n        if (t != first+1 && t != last && *t == 'E' && ++t != last)\n        {\n            switch (*t)\n            {\n            case 's':\n                first = parse_discriminator(t+1, last);\n                if (db.names.empty())\n                    return first;\n                db.names.back().first.append(\"::string literal\");\n                break;\n            case 'd':\n                if (++t != last)\n                {\n                    const char* t1 = parse_number(t, last);\n                    if (t1 != last && *t1 == '_')\n                    {\n                        t = t1 + 1;\n                        t1 = parse_name(t, last, db,\n                                        ends_with_template_args);\n                        if (t1 != t)\n                        {\n                            if (db.names.size() < 2)\n                                return first;\n                            auto name = db.names.back().move_full();\n                            db.names.pop_back();\n                            db.names.back().first.append(\"::\");\n                            db.names.back().first.append(name);\n                            first = t1;\n                        }\n                        else\n                            db.names.pop_back();\n                    }\n                }\n                break;\n            default:\n                {\n                    const char* t1 = parse_name(t, last, db,\n                                                ends_with_template_args);\n                    if (t1 != t)\n                    {\n                        // parse but ignore discriminator\n                        first = parse_discriminator(t1, last);\n                        if (db.names.size() < 2)\n                            return first;\n                        auto name = db.names.back().move_full();\n                        db.names.pop_back();\n                        db.names.back().first.append(\"::\");\n                        db.names.back().first.append(name);\n                    }\n                    else\n                        db.names.pop_back();\n                }\n                break;\n            }\n        }\n    }\n    return first;\n}\n\n// <name> ::= <nested-name> // N\n//        ::= <local-name> # See Scope Encoding below  // Z\n//        ::= <unscoped-template-name> <template-args>\n//        ::= <unscoped-name>\n\n// <unscoped-template-name> ::= <unscoped-name>\n//                          ::= <substitution>\n\ntemplate <class C>\nconst char*\nparse_name(const char* first, const char* last, C& db,\n           bool* ends_with_template_args)\n{\n    if (last - first >= 2)\n    {\n        const char* t0 = first;\n        // extension: ignore L here\n        if (*t0 == 'L')\n            ++t0;\n        switch (*t0)\n        {\n        case 'N':\n          {\n            const char* t1 = parse_nested_name(t0, last, db,\n                                               ends_with_template_args);\n            if (t1 != t0)\n                first = t1;\n            break;\n          }\n        case 'Z':\n          {\n            const char* t1 = parse_local_name(t0, last, db,\n                                              ends_with_template_args);\n            if (t1 != t0)\n                first = t1;\n            break;\n          }\n        default:\n          {\n            const char* t1 = parse_unscoped_name(t0, last, db);\n            if (t1 != t0)\n            {\n                if (t1 != last && *t1 == 'I')  // <unscoped-template-name> <template-args>\n                {\n                    if (db.names.empty())\n                        return first;\n                    db.subs.push_back(typename C::sub_type(1, db.names.back(), db.names.get_allocator()));\n                    t0 = t1;\n                    t1 = parse_template_args(t0, last, db);\n                    if (t1 != t0)\n                    {\n                        if (db.names.size() < 2)\n                            return first;\n                        auto tmp = db.names.back().move_full();\n                        db.names.pop_back();\n                        db.names.back().first += tmp;\n                        first = t1;\n                        if (ends_with_template_args)\n                            *ends_with_template_args = true;\n                    }\n                }\n                else   // <unscoped-name>\n                    first = t1;\n            }\n            else\n            {   // try <substitution> <template-args>\n                t1 = parse_substitution(t0, last, db);\n                if (t1 != t0 && t1 != last && *t1 == 'I')\n                {\n                    t0 = t1;\n                    t1 = parse_template_args(t0, last, db);\n                    if (t1 != t0)\n                    {\n                        if (db.names.size() < 2)\n                            return first;\n                        auto tmp = db.names.back().move_full();\n                        db.names.pop_back();\n                        db.names.back().first += tmp;\n                        first = t1;\n                        if (ends_with_template_args)\n                            *ends_with_template_args = true;\n                    }\n                }\n            }\n            break;\n          }\n        }\n    }\n    return first;\n}\n\n// <call-offset> ::= h <nv-offset> _\n//               ::= v <v-offset> _\n// \n// <nv-offset> ::= <offset number>\n//               # non-virtual base override\n// \n// <v-offset>  ::= <offset number> _ <virtual offset number>\n//               # virtual base override, with vcall offset\n\nconst char*\nparse_call_offset(const char* first, const char* last)\n{\n    if (first != last)\n    {\n        switch (*first)\n        {\n        case 'h':\n            {\n            const char* t = parse_number(first + 1, last);\n            if (t != first + 1 && t != last && *t == '_')\n                first = t + 1;\n            }\n            break;\n        case 'v':\n            {\n            const char* t = parse_number(first + 1, last);\n            if (t != first + 1 && t != last && *t == '_')\n            {\n                const char* t2 = parse_number(++t, last);\n                if (t2 != t && t2 != last && *t2 == '_')\n                    first = t2 + 1;\n            }\n            }\n            break;\n        }\n    }\n    return first;\n}\n\n// <special-name> ::= TV <type>    # virtual table\n//                ::= TT <type>    # VTT structure (construction vtable index)\n//                ::= TI <type>    # typeinfo structure\n//                ::= TS <type>    # typeinfo name (null-terminated byte string)\n//                ::= Tc <call-offset> <call-offset> <base encoding>\n//                    # base is the nominal target function of thunk\n//                    # first call-offset is 'this' adjustment\n//                    # second call-offset is result adjustment\n//                ::= T <call-offset> <base encoding>\n//                    # base is the nominal target function of thunk\n//                ::= GV <object name> # Guard variable for one-time initialization\n//                                     # No <type>\n//      extension ::= TC <first type> <number> _ <second type> # construction vtable for second-in-first\n//      extension ::= GR <object name> # reference temporary for object\n\ntemplate <class C>\nconst char*\nparse_special_name(const char* first, const char* last, C& db)\n{\n    if (last - first > 2)\n    {\n        const char* t;\n        switch (*first)\n        {\n        case 'T':\n            switch (first[1])\n            {\n            case 'V':\n                // TV <type>    # virtual table\n                t = parse_type(first+2, last, db);\n                if (t != first+2)\n                {\n                    if (db.names.empty())\n                        return first;\n                    db.names.back().first.insert(0, \"vtable for \");\n                    first = t;\n                }\n                break;\n            case 'T':\n                // TT <type>    # VTT structure (construction vtable index)\n                t = parse_type(first+2, last, db);\n                if (t != first+2)\n                {\n                    if (db.names.empty())\n                        return first;\n                    db.names.back().first.insert(0, \"VTT for \");\n                    first = t;\n                }\n                break;\n            case 'I':\n                // TI <type>    # typeinfo structure\n                t = parse_type(first+2, last, db);\n                if (t != first+2)\n                {\n                    if (db.names.empty())\n                        return first;\n                    db.names.back().first.insert(0, \"typeinfo for \");\n                    first = t;\n                }\n                break;\n            case 'S':\n                // TS <type>    # typeinfo name (null-terminated byte string)\n                t = parse_type(first+2, last, db);\n                if (t != first+2)\n                {\n                    if (db.names.empty())\n                        return first;\n                    db.names.back().first.insert(0, \"typeinfo name for \");\n                    first = t;\n                }\n                break;\n            case 'c':\n                // Tc <call-offset> <call-offset> <base encoding>\n              {\n                const char* t0 = parse_call_offset(first+2, last);\n                if (t0 == first+2)\n                    break;\n                const char* t1 = parse_call_offset(t0, last);\n                if (t1 == t0)\n                    break;\n                t = parse_encoding(t1, last, db);\n                if (t != t1)\n                {\n                    if (db.names.empty())\n                        return first;\n                    db.names.back().first.insert(0, \"covariant return thunk to \");\n                    first = t;\n                }\n              }\n                break;\n            case 'C':\n                // extension ::= TC <first type> <number> _ <second type> # construction vtable for second-in-first\n                t = parse_type(first+2, last, db);\n                if (t != first+2)\n                {\n                    const char* t0 = parse_number(t, last);\n                    if (t0 != t && t0 != last && *t0 == '_')\n                    {\n                        const char* t1 = parse_type(++t0, last, db);\n                        if (t1 != t0)\n                        {\n                            if (db.names.size() < 2)\n                                return first;\n                            auto left = db.names.back().move_full();\n                            db.names.pop_back();\n                            db.names.back().first = \"construction vtable for \" +\n                                                    std::move(left) + \"-in-\" +\n                                                    db.names.back().move_full();\n                            first = t1;\n                        }\n                    }\n                }\n                break;\n            default:\n                // T <call-offset> <base encoding>\n                {\n                const char* t0 = parse_call_offset(first+1, last);\n                if (t0 == first+1)\n                    break;\n                t = parse_encoding(t0, last, db);\n                if (t != t0)\n                {\n                    if (db.names.empty())\n                        return first;\n                    if (first[1] == 'v')\n                    {\n                        db.names.back().first.insert(0, \"virtual thunk to \");\n                        first = t;\n                    }\n                    else\n                    {\n                        db.names.back().first.insert(0, \"non-virtual thunk to \");\n                        first = t;\n                    }\n                }\n                }\n                break;\n            }\n            break;\n        case 'G':\n            switch (first[1])\n            {\n            case 'V':\n                // GV <object name> # Guard variable for one-time initialization\n                t = parse_name(first+2, last, db);\n                if (t != first+2)\n                {\n                    if (db.names.empty())\n                        return first;\n                    db.names.back().first.insert(0, \"guard variable for \");\n                    first = t;\n                }\n                break;\n            case 'R':\n                // extension ::= GR <object name> # reference temporary for object\n                t = parse_name(first+2, last, db);\n                if (t != first+2)\n                {\n                    if (db.names.empty())\n                        return first;\n                    db.names.back().first.insert(0, \"reference temporary for \");\n                    first = t;\n                }\n                break;\n            }\n            break;\n        }\n    }\n    return first;\n}\n\ntemplate <class T>\nclass save_value\n{\n    T& restore_;\n    T original_value_;\npublic:\n    save_value(T& restore)\n        : restore_(restore),\n          original_value_(restore)\n        {}\n\n    ~save_value()\n    {\n        restore_ = std::move(original_value_);\n    }\n\n    save_value(const save_value&) = delete;\n    save_value& operator=(const save_value&) = delete;\n};\n\n// <encoding> ::= <function name> <bare-function-type>\n//            ::= <data name>\n//            ::= <special-name>\n\ntemplate <class C>\nconst char*\nparse_encoding(const char* first, const char* last, C& db)\n{\n    if (first != last)\n    {\n        save_value<decltype(db.encoding_depth)> su(db.encoding_depth);\n        ++db.encoding_depth;\n        save_value<decltype(db.tag_templates)> sb(db.tag_templates);\n        if (db.encoding_depth > 1)\n            db.tag_templates = true;\n        switch (*first)\n        {\n        case 'G':\n        case 'T':\n            first = parse_special_name(first, last, db);\n            break;\n        default:\n          {\n            bool ends_with_template_args = false;\n            const char* t = parse_name(first, last, db,\n                                       &ends_with_template_args);\n            unsigned cv = db.cv;\n            unsigned ref = db.ref;\n            if (t != first)\n            {\n                if (t != last && *t != 'E' && *t != '.')\n                {\n                    save_value<bool> sb2(db.tag_templates);\n                    db.tag_templates = false;\n                    const char* t2;\n                    typename C::String ret2;\n                    if (db.names.empty())\n                        return first;\n                    const typename C::String& nm = db.names.back().first;\n                    if (nm.empty())\n                        return first;\n                    if (!db.parsed_ctor_dtor_cv && ends_with_template_args)\n                    {\n                        t2 = parse_type(t, last, db);\n                        if (t2 == t)\n                            return first;\n                        if (db.names.size() < 2)\n                            return first;\n                        auto ret1 = std::move(db.names.back().first);\n                        ret2 = std::move(db.names.back().second);\n                        if (ret2.empty())\n                            ret1 += ' ';\n                        db.names.pop_back();\n                        db.names.back().first.insert(0, ret1);\n                        t = t2;\n                    }\n                    db.names.back().first += '(';\n                    if (t != last && *t == 'v')\n                    {\n                        ++t;\n                    }\n                    else\n                    {\n                        bool first_arg = true;\n                        while (true)\n                        {\n                            size_t k0 = db.names.size();\n                            t2 = parse_type(t, last, db);\n                            size_t k1 = db.names.size();\n                            if (t2 == t)\n                                break;\n                            if (k1 > k0)\n                            {\n                                typename C::String tmp;\n                                for (size_t k = k0; k < k1; ++k)\n                                {\n                                    if (!tmp.empty())\n                                        tmp += \", \";\n                                    tmp += db.names[k].move_full();\n                                }\n                                for (size_t k = k0; k < k1; ++k)\n                                    db.names.pop_back();\n                                if (!tmp.empty())\n                                {\n                                    if (db.names.empty())\n                                        return first;\n                                    if (!first_arg)\n                                        db.names.back().first += \", \";\n                                    else\n                                        first_arg = false;\n                                    db.names.back().first += tmp;\n                                }\n                            }\n                            t = t2;\n                        }\n                    }\n                    if (db.names.empty())\n                        return first;\n                    db.names.back().first += ')';\n                    if (cv & 1)\n                        db.names.back().first.append(\" const\");\n                    if (cv & 2)\n                        db.names.back().first.append(\" volatile\");\n                    if (cv & 4)\n                        db.names.back().first.append(\" restrict\");\n                    if (ref == 1)\n                        db.names.back().first.append(\" &\");\n                    else if (ref == 2)\n                        db.names.back().first.append(\" &&\");\n                    db.names.back().first += ret2;\n                    first = t;\n                }\n                else\n                    first = t;\n            }\n            break;\n          }\n        }\n    }\n    return first;\n}\n\n// _block_invoke\n// _block_invoke<decimal-digit>+\n// _block_invoke_<decimal-digit>+\n\ntemplate <class C>\nconst char*\nparse_block_invoke(const char* first, const char* last, C& db)\n{\n    if (last - first >= 13)\n    {\n        const char test[] = \"_block_invoke\";\n        const char* t = first;\n        for (int i = 0; i < 13; ++i, ++t)\n        {\n            if (*t != test[i])\n                return first;\n        }\n        if (t != last)\n        {\n            if (*t == '_')\n            {\n                // must have at least 1 decimal digit\n                if (++t == last || !std::isdigit(*t))\n                    return first;\n                ++t;\n            }\n            // parse zero or more digits\n            while (t != last && isdigit(*t))\n                ++t;\n        }\n        if (db.names.empty())\n            return first;\n        db.names.back().first.insert(0, \"invocation function for block in \");\n        first = t;\n    }\n    return first;\n}\n\n// extension\n// <dot-suffix> := .<anything and everything>\n\ntemplate <class C>\nconst char*\nparse_dot_suffix(const char* first, const char* last, C& db)\n{\n    if (first != last && *first == '.')\n    {\n        if (db.names.empty())\n            return first;\n        db.names.back().first += \" (\" + typename C::String(first, last) + \")\";\n        first = last;\n    }\n    return first;\n}\n\n// <block-involcaton-function> ___Z<encoding>_block_invoke\n// <block-involcaton-function> ___Z<encoding>_block_invoke<decimal-digit>+\n// <block-involcaton-function> ___Z<encoding>_block_invoke_<decimal-digit>+\n// <mangled-name> ::= _Z<encoding>\n//                ::= <type>\n\ntemplate <class C>\nvoid\ndemangle(const char* first, const char* last, C& db, int& status)\n{\n    if (first >= last)\n    {\n        status = invalid_mangled_name;\n        return;\n    }\n    if (*first == '_')\n    {\n        if (last - first >= 4)\n        {\n            if (first[1] == 'Z')\n            {\n                const char* t = parse_encoding(first+2, last, db);\n                if (t != first+2 && t != last && *t == '.')\n                    t = parse_dot_suffix(t, last, db);\n                if (t != last)\n                    status = invalid_mangled_name;\n            }\n            else if (first[1] == '_' && first[2] == '_' && first[3] == 'Z')\n            {\n                const char* t = parse_encoding(first+4, last, db);\n                if (t != first+4 && t != last)\n                {\n                    const char* t1 = parse_block_invoke(t, last, db);\n                    if (t1 != last)\n                        status = invalid_mangled_name;\n                }\n                else\n                    status = invalid_mangled_name;\n            }\n            else\n                status = invalid_mangled_name;\n        }\n        else\n            status = invalid_mangled_name;\n    }\n    else\n    {\n        const char* t = parse_type(first, last, db);\n        if (t != last)\n            status = invalid_mangled_name;\n    }\n    if (status == success && db.names.empty())\n        status = invalid_mangled_name;\n}\n\ntemplate <std::size_t N>\nclass arena\n{\n    static const std::size_t alignment = 16;\n    alignas(alignment) char buf_[N];\n    char* ptr_;\n\n    std::size_t \n    align_up(std::size_t n) noexcept\n        {return (n + (alignment-1)) & ~(alignment-1);}\n\n    bool\n    pointer_in_buffer(char* p) noexcept\n        {return buf_ <= p && p <= buf_ + N;}\n\npublic:\n    arena() noexcept : ptr_(buf_) {}\n    ~arena() {ptr_ = nullptr;}\n    arena(const arena&) = delete;\n    arena& operator=(const arena&) = delete;\n\n    char* allocate(std::size_t n);\n    void deallocate(char* p, std::size_t n) noexcept;\n\n    static constexpr std::size_t size() {return N;}\n    std::size_t used() const {return static_cast<std::size_t>(ptr_ - buf_);}\n    void reset() {ptr_ = buf_;}\n};\n\ntemplate <std::size_t N>\nchar*\narena<N>::allocate(std::size_t n)\n{\n    n = align_up(n);\n    if (static_cast<std::size_t>(buf_ + N - ptr_) >= n)\n    {\n        char* r = ptr_;\n        ptr_ += n;\n        return r;\n    }\n    return static_cast<char*>(std::malloc(n));\n}\n\ntemplate <std::size_t N>\nvoid\narena<N>::deallocate(char* p, std::size_t n) noexcept\n{\n    if (pointer_in_buffer(p))\n    {\n        n = align_up(n);\n        if (p + n == ptr_)\n            ptr_ = p;\n    }\n    else\n        std::free(p);\n}\n\ntemplate <class T, std::size_t N>\nclass short_alloc\n{\n    arena<N>& a_;\npublic:\n    typedef T value_type;\n\npublic:\n    template <class _Up> struct rebind {typedef short_alloc<_Up, N> other;};\n\n    short_alloc(arena<N>& a) noexcept : a_(a) {}\n    template <class U>\n        short_alloc(const short_alloc<U, N>& a) noexcept\n            : a_(a.a_) {}\n    short_alloc(const short_alloc&) = default;\n    short_alloc& operator=(const short_alloc&) = delete;\n\n    T* allocate(std::size_t n)\n    {\n        return reinterpret_cast<T*>(a_.allocate(n*sizeof(T)));\n    }\n    void deallocate(T* p, std::size_t n) noexcept\n    {\n        a_.deallocate(reinterpret_cast<char*>(p), n*sizeof(T));\n    }\n\n    template <class T1, std::size_t N1, class U, std::size_t M>\n    friend\n    bool\n    operator==(const short_alloc<T1, N1>& x, const short_alloc<U, M>& y) noexcept;\n\n    template <class U, std::size_t M> friend class short_alloc;\n};\n\ntemplate <class T, std::size_t N, class U, std::size_t M>\ninline\nbool\noperator==(const short_alloc<T, N>& x, const short_alloc<U, M>& y) noexcept\n{\n    return N == M && &x.a_ == &y.a_;\n}\n\ntemplate <class T, std::size_t N, class U, std::size_t M>\ninline\nbool\noperator!=(const short_alloc<T, N>& x, const short_alloc<U, M>& y) noexcept\n{\n    return !(x == y);\n}\n\ntemplate <class T>\nclass malloc_alloc\n{\npublic:\n    typedef T value_type;\n    typedef T& reference;\n    typedef const T& const_reference;\n    typedef T* pointer;\n    typedef const T* const_pointer;\n    typedef std::size_t size_type;\n    typedef std::ptrdiff_t difference_type;\n\n    malloc_alloc() = default;\n    template <class U> malloc_alloc(const malloc_alloc<U>&) noexcept {}\n\n    T* allocate(std::size_t n)\n    {\n        return static_cast<T*>(std::malloc(n*sizeof(T)));\n    }\n    void deallocate(T* p, std::size_t) noexcept\n    {\n        std::free(p);\n    }\n\n    template <class U> struct rebind { using other = malloc_alloc<U>; };\n    template <class U, class... Args>\n    void construct(U* p, Args&&... args)\n    {\n        ::new ((void*)p) U(std::forward<Args>(args)...);\n    }\n    void destroy(T* p)\n    {\n        p->~T();\n    }\n};\n\ntemplate <class T, class U>\ninline\nbool\noperator==(const malloc_alloc<T>&, const malloc_alloc<U>&) noexcept\n{\n    return true;\n}\n\ntemplate <class T, class U>\ninline\nbool\noperator!=(const malloc_alloc<T>& x, const malloc_alloc<U>& y) noexcept\n{\n    return !(x == y);\n}\n\nconst size_t bs = 4 * 1024;\ntemplate <class T> using Alloc = short_alloc<T, bs>;\ntemplate <class T> using Vector = std::vector<T, Alloc<T>>;\n\ntemplate <class StrT>\nstruct string_pair\n{\n    StrT first;\n    StrT second;\n\n    string_pair() = default;\n    string_pair(StrT f) : first(std::move(f)) {}\n    string_pair(StrT f, StrT s)\n        : first(std::move(f)), second(std::move(s)) {}\n    template <size_t N>\n        string_pair(const char (&s)[N]) : first(s, N-1) {}\n\n    size_t size() const {return first.size() + second.size();}\n    StrT full() const {return first + second;}\n    StrT move_full() {return std::move(first) + std::move(second);}\n};\n\nstruct Db\n{\n    typedef std::basic_string<char, std::char_traits<char>,\n                              malloc_alloc<char>> String;\n    typedef Vector<string_pair<String>> sub_type;\n    typedef Vector<sub_type> template_param_type;\n    sub_type names;\n    template_param_type subs;\n    Vector<template_param_type> template_param;\n    unsigned cv;\n    unsigned ref;\n    unsigned encoding_depth;\n    bool parsed_ctor_dtor_cv;\n    bool tag_templates;\n    bool fix_forward_references;\n    bool try_to_parse_template_args;\n\n    template <size_t N>\n    Db(arena<N>& ar) :\n        names(ar),\n        subs(0, names, ar),\n        template_param(0, subs, ar)\n    {}\n};\n\n}  // unnamed namespace\n\nextern \"C\" _LIBCXXABI_FUNC_VIS char *\n__cxa_demangle(const char *mangled_name, char *buf, size_t *n, int *status) {\n    if (mangled_name == nullptr || (buf != nullptr && n == nullptr))\n    {\n        if (status)\n            *status = invalid_args;\n        return nullptr;\n    }\n    size_t internal_size = buf != nullptr ? *n : 0;\n    arena<bs> a;\n    Db db(a);\n    db.cv = 0;\n    db.ref = 0;\n    db.encoding_depth = 0;\n    db.parsed_ctor_dtor_cv = false;\n    db.tag_templates = true;\n    db.template_param.emplace_back(a);\n    db.fix_forward_references = false;\n    db.try_to_parse_template_args = true;\n    int internal_status = success;\n    size_t len = std::strlen(mangled_name);\n    demangle(mangled_name, mangled_name + len, db,\n             internal_status);\n    if (internal_status == success && db.fix_forward_references &&\n           !db.template_param.empty() && !db.template_param.front().empty())\n    {\n        db.fix_forward_references = false;\n        db.tag_templates = false;\n        db.names.clear();\n        db.subs.clear();\n        demangle(mangled_name, mangled_name + len, db, internal_status);\n        if (db.fix_forward_references)\n            internal_status = invalid_mangled_name;\n    }\n    if (internal_status == success)\n    {\n        size_t sz = db.names.back().size() + 1;\n        if (sz > internal_size)\n        {\n            char* newbuf = static_cast<char*>(std::realloc(buf, sz));\n            if (newbuf == nullptr)\n            {\n                internal_status = memory_alloc_failure;\n                buf = nullptr;\n            }\n            else\n            {\n                buf = newbuf;\n                if (n != nullptr)\n                    *n = sz;\n            }\n        }\n        if (buf != nullptr)\n        {\n            db.names.back().first += db.names.back().second;\n            std::memcpy(buf, db.names.back().first.data(), sz-1);\n            buf[sz-1] = char(0);\n        }\n    }\n    else\n        buf = nullptr;\n    if (status)\n        *status = internal_status;\n    return buf;\n}\n\n}  // __cxxabiv1\n"
  },
  {
    "path": "third_party/demumble/third_party/wine/LICENSE.txt",
    "content": "https://www.winehq.org/license\n\nWine License\nCopyright (c) 1993-2015 the Wine project authors (see the file AUTHORS for a complete list)\n\nWine is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version.\n\nThis program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.\n\nA copy of the GNU Lesser General Public License is included in the Wine distribution in the file COPYING.LIB. If you did not receive this copy, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.\n\nGNU Lesser General Public License\n\nVersion 2.1, February 1999\n\nCopyright (C) 1991, 1999 Free Software Foundation, Inc.\n59 Temple Place, Suite 330, Boston, MA  02111-1307  USA\nEveryone is permitted to copy and distribute verbatim copies\nof this license document, but changing it is not allowed.\n\n[This is the first released version of the Lesser GPL.  It also counts\n as the successor of the GNU Library Public License, version 2, hence\n the version number 2.1.]\nPreamble\n\nThe licenses for most software are designed to take away your freedom to share and change it. By contrast, the GNU General Public Licenses are intended to guarantee your freedom to share and change free software--to make sure the software is free for all its users.\n\nThis license, the Lesser General Public License, applies to some specially designated software packages--typically libraries--of the Free Software Foundation and other authors who decide to use it. You can use it too, but we suggest you first think carefully about whether this license or the ordinary General Public License is the better strategy to use in any particular case, based on the explanations below.\n\nWhen we speak of free software, we are referring to freedom of use, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for this service if you wish); that you receive source code or can get it if you want it; that you can change the software and use pieces of it in new free programs; and that you are informed that you can do these things.\n\nTo protect your rights, we need to make restrictions that forbid distributors to deny you these rights or to ask you to surrender these rights. These restrictions translate to certain responsibilities for you if you distribute copies of the library or if you modify it.\n\nFor example, if you distribute copies of the library, whether gratis or for a fee, you must give the recipients all the rights that we gave you. You must make sure that they, too, receive or can get the source code. If you link other code with the library, you must provide complete object files to the recipients, so that they can relink them with the library after making changes to the library and recompiling it. And you must show them these terms so they know their rights.\n\nWe protect your rights with a two-step method: (1) we copyright the library, and (2) we offer you this license, which gives you legal permission to copy, distribute and/or modify the library.\n\nTo protect each distributor, we want to make it very clear that there is no warranty for the free library. Also, if the library is modified by someone else and passed on, the recipients should know that what they have is not the original version, so that the original author's reputation will not be affected by problems that might be introduced by others.\n\nFinally, software patents pose a constant threat to the existence of any free program. We wish to make sure that a company cannot effectively restrict the users of a free program by obtaining a restrictive license from a patent holder. Therefore, we insist that any patent license obtained for a version of the library must be consistent with the full freedom of use specified in this license.\n\nMost GNU software, including some libraries, is covered by the ordinary GNU General Public License. This license, the GNU Lesser General Public License, applies to certain designated libraries, and is quite different from the ordinary General Public License. We use this license for certain libraries in order to permit linking those libraries into non-free programs.\n\nWhen a program is linked with a library, whether statically or using a shared library, the combination of the two is legally speaking a combined work, a derivative of the original library. The ordinary General Public License therefore permits such linking only if the entire combination fits its criteria of freedom. The Lesser General Public License permits more lax criteria for linking other code with the library.\n\nWe call this license the \"Lesser\" General Public License because it does Less to protect the user's freedom than the ordinary General Public License. It also provides other free software developers Less of an advantage over competing non-free programs. These disadvantages are the reason we use the ordinary General Public License for many libraries. However, the Lesser license provides advantages in certain special circumstances.\n\nFor example, on rare occasions, there may be a special need to encourage the widest possible use of a certain library, so that it becomes a de-facto standard. To achieve this, non-free programs must be allowed to use the library. A more frequent case is that a free library does the same job as widely used non-free libraries. In this case, there is little to gain by limiting the free library to free software only, so we use the Lesser General Public License.\n\nIn other cases, permission to use a particular library in non-free programs enables a greater number of people to use a large body of free software. For example, permission to use the GNU C Library in non-free programs enables many more people to use the whole GNU operating system, as well as its variant, the GNU/Linux operating system.\n\nAlthough the Lesser General Public License is Less protective of the users' freedom, it does ensure that the user of a program that is linked with the Library has the freedom and the wherewithal to run that program using a modified version of the Library.\n\nThe precise terms and conditions for copying, distribution and modification follow. Pay close attention to the difference between a \"work based on the library\" and a \"work that uses the library\". The former contains code derived from the library, whereas the latter must be combined with the library in order to run.\n\nTERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION\n\n0. This License Agreement applies to any software library or other program which contains a notice placed by the copyright holder or other authorized party saying it may be distributed under the terms of this Lesser General Public License (also called \"this License\"). Each licensee is addressed as \"you\".\n\nA \"library\" means a collection of software functions and/or data prepared so as to be conveniently linked with application programs (which use some of those functions and data) to form executables.\n\nThe \"Library\", below, refers to any such software library or work which has been distributed under these terms. A \"work based on the Library\" means either the Library or any derivative work under copyright law: that is to say, a work containing the Library or a portion of it, either verbatim or with modifications and/or translated straightforwardly into another language. (Hereinafter, translation is included without limitation in the term \"modification\".)\n\n\"Source code\" for a work means the preferred form of the work for making modifications to it. For a library, complete source code means all the source code for all modules it contains, plus any associated interface definition files, plus the scripts used to control compilation and installation of the library.\n\nActivities other than copying, distribution and modification are not covered by this License; they are outside its scope. The act of running a program using the Library is not restricted, and output from such a program is covered only if its contents constitute a work based on the Library (independent of the use of the Library in a tool for writing it). Whether that is true depends on what the Library does and what the program that uses the Library does.\n\n1. You may copy and distribute verbatim copies of the Library's complete source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice and disclaimer of warranty; keep intact all the notices that refer to this License and to the absence of any warranty; and distribute a copy of this License along with the Library.\n\nYou may charge a fee for the physical act of transferring a copy, and you may at your option offer warranty protection in exchange for a fee.\n\n2. You may modify your copy or copies of the Library or any portion of it, thus forming a work based on the Library, and copy and distribute such modifications or work under the terms of Section 1 above, provided that you also meet all of these conditions:\n\na) The modified work must itself be a software library.\nb) You must cause the files modified to carry prominent notices stating that you changed the files and the date of any change.\nc) You must cause the whole of the work to be licensed at no charge to all third parties under the terms of this License.\nd) If a facility in the modified Library refers to a function or a table of data to be supplied by an application program that uses the facility, other than as an argument passed when the facility is invoked, then you must make a good faith effort to ensure that, in the event an application does not supply such function or table, the facility still operates, and performs whatever part of its purpose remains meaningful.\n(For example, a function in a library to compute square roots has a purpose that is entirely well-defined independent of the application. Therefore, Subsection 2d requires that any application-supplied function or table used by this function must be optional: if the application does not supply it, the square root function must still compute square roots.)\n\nThese requirements apply to the modified work as a whole. If identifiable sections of that work are not derived from the Library, and can be reasonably considered independent and separate works in themselves, then this License, and its terms, do not apply to those sections when you distribute them as separate works. But when you distribute the same sections as part of a whole which is a work based on the Library, the distribution of the whole must be on the terms of this License, whose permissions for other licensees extend to the entire whole, and thus to each and every part regardless of who wrote it.\n\nThus, it is not the intent of this section to claim rights or contest your rights to work written entirely by you; rather, the intent is to exercise the right to control the distribution of derivative or collective works based on the Library.\n\nIn addition, mere aggregation of another work not based on the Library with the Library (or with a work based on the Library) on a volume of a storage or distribution medium does not bring the other work under the scope of this License.\n\n3. You may opt to apply the terms of the ordinary GNU General Public License instead of this License to a given copy of the Library. To do this, you must alter all the notices that refer to this License, so that they refer to the ordinary GNU General Public License, version 2, instead of to this License. (If a newer version than version 2 of the ordinary GNU General Public License has appeared, then you can specify that version instead if you wish.) Do not make any other change in these notices.\n\nOnce this change is made in a given copy, it is irreversible for that copy, so the ordinary GNU General Public License applies to all subsequent copies and derivative works made from that copy.\n\nThis option is useful when you wish to copy part of the code of the Library into a program that is not a library.\n\n4. You may copy and distribute the Library (or a portion or derivative of it, under Section 2) in object code or executable form under the terms of Sections 1 and 2 above provided that you accompany it with the complete corresponding machine-readable source code, which must be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange.\n\nIf distribution of object code is made by offering access to copy from a designated place, then offering equivalent access to copy the source code from the same place satisfies the requirement to distribute the source code, even though third parties are not compelled to copy the source along with the object code.\n\n5. A program that contains no derivative of any portion of the Library, but is designed to work with the Library by being compiled or linked with it, is called a \"work that uses the Library\". Such a work, in isolation, is not a derivative work of the Library, and therefore falls outside the scope of this License.\n\nHowever, linking a \"work that uses the Library\" with the Library creates an executable that is a derivative of the Library (because it contains portions of the Library), rather than a \"work that uses the library\". The executable is therefore covered by this License. Section 6 states terms for distribution of such executables.\n\nWhen a \"work that uses the Library\" uses material from a header file that is part of the Library, the object code for the work may be a derivative work of the Library even though the source code is not. Whether this is true is especially significant if the work can be linked without the Library, or if the work is itself a library. The threshold for this to be true is not precisely defined by law.\n\nIf such an object file uses only numerical parameters, data structure layouts and accessors, and small macros and small inline functions (ten lines or less in length), then the use of the object file is unrestricted, regardless of whether it is legally a derivative work. (Executables containing this object code plus portions of the Library will still fall under Section 6.)\n\nOtherwise, if the work is a derivative of the Library, you may distribute the object code for the work under the terms of Section 6. Any executables containing that work also fall under Section 6, whether or not they are linked directly with the Library itself.\n\n6. As an exception to the Sections above, you may also combine or link a \"work that uses the Library\" with the Library to produce a work containing portions of the Library, and distribute that work under terms of your choice, provided that the terms permit modification of the work for the customer's own use and reverse engineering for debugging such modifications.\n\nYou must give prominent notice with each copy of the work that the Library is used in it and that the Library and its use are covered by this License. You must supply a copy of this License. If the work during execution displays copyright notices, you must include the copyright notice for the Library among them, as well as a reference directing the user to the copy of this License. Also, you must do one of these things:\n\na) Accompany the work with the complete corresponding machine-readable source code for the Library including whatever changes were used in the work (which must be distributed under Sections 1 and 2 above); and, if the work is an executable linked with the Library, with the complete machine-readable \"work that uses the Library\", as object code and/or source code, so that the user can modify the Library and then relink to produce a modified executable containing the modified Library. (It is understood that the user who changes the contents of definitions files in the Library will not necessarily be able to recompile the application to use the modified definitions.)\nb) Use a suitable shared library mechanism for linking with the Library. A suitable mechanism is one that (1) uses at run time a copy of the library already present on the user's computer system, rather than copying library functions into the executable, and (2) will operate properly with a modified version of the library, if the user installs one, as long as the modified version is interface-compatible with the version that the work was made with.\nc) Accompany the work with a written offer, valid for at least three years, to give the same user the materials specified in Subsection 6a, above, for a charge no more than the cost of performing this distribution.\nd) If distribution of the work is made by offering access to copy from a designated place, offer equivalent access to copy the above specified materials from the same place.\ne) Verify that the user has already received a copy of these materials or that you have already sent this user a copy.\nFor an executable, the required form of the \"work that uses the Library\" must include any data and utility programs needed for reproducing the executable from it. However, as a special exception, the materials to be distributed need not include anything that is normally distributed (in either source or binary form) with the major components (compiler, kernel, and so on) of the operating system on which the executable runs, unless that component itself accompanies the executable.\n\nIt may happen that this requirement contradicts the license restrictions of other proprietary libraries that do not normally accompany the operating system. Such a contradiction means you cannot use both them and the Library together in an executable that you distribute.\n\n7. You may place library facilities that are a work based on the Library side-by-side in a single library together with other library facilities not covered by this License, and distribute such a combined library, provided that the separate distribution of the work based on the Library and of the other library facilities is otherwise permitted, and provided that you do these two things:\n\na) Accompany the combined library with a copy of the same work based on the Library, uncombined with any other library facilities. This must be distributed under the terms of the Sections above.\nb) Give prominent notice with the combined library of the fact that part of it is a work based on the Library, and explaining where to find the accompanying uncombined form of the same work.\n8. You may not copy, modify, sublicense, link with, or distribute the Library except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense, link with, or distribute the Library is void, and will automatically terminate your rights under this License. However, parties who have received copies, or rights, from you under this License will not have their licenses terminated so long as such parties remain in full compliance.\n\n9. You are not required to accept this License, since you have not signed it. However, nothing else grants you permission to modify or distribute the Library or its derivative works. These actions are prohibited by law if you do not accept this License. Therefore, by modifying or distributing the Library (or any work based on the Library), you indicate your acceptance of this License to do so, and all its terms and conditions for copying, distributing or modifying the Library or works based on it.\n\n10. Each time you redistribute the Library (or any work based on the Library), the recipient automatically receives a license from the original licensor to copy, distribute, link with or modify the Library subject to these terms and conditions. You may not impose any further restrictions on the recipients' exercise of the rights granted herein. You are not responsible for enforcing compliance by third parties with this License.\n\n11. If, as a consequence of a court judgment or allegation of patent infringement or for any other reason (not limited to patent issues), conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot distribute so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not distribute the Library at all. For example, if a patent license would not permit royalty-free redistribution of the Library by all those who receive copies directly or indirectly through you, then the only way you could satisfy both it and this License would be to refrain entirely from distribution of the Library.\n\nIf any portion of this section is held invalid or unenforceable under any particular circumstance, the balance of the section is intended to apply, and the section as a whole is intended to apply in other circumstances.\n\nIt is not the purpose of this section to induce you to infringe any patents or other property right claims or to contest validity of any such claims; this section has the sole purpose of protecting the integrity of the free software distribution system which is implemented by public license practices. Many people have made generous contributions to the wide range of software distributed through that system in reliance on consistent application of that system; it is up to the author/donor to decide if he or she is willing to distribute software through any other system and a licensee cannot impose that choice.\n\nThis section is intended to make thoroughly clear what is believed to be a consequence of the rest of this License.\n\n12. If the distribution and/or use of the Library is restricted in certain countries either by patents or by copyrighted interfaces, the original copyright holder who places the Library under this License may add an explicit geographical distribution limitation excluding those countries, so that distribution is permitted only in or among countries not thus excluded. In such case, this License incorporates the limitation as if written in the body of this License.\n\n13. The Free Software Foundation may publish revised and/or new versions of the Lesser General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns.\n\nEach version is given a distinguishing version number. If the Library specifies a version number of this License which applies to it and \"any later version\", you have the option of following the terms and conditions either of that version or of any later version published by the Free Software Foundation. If the Library does not specify a license version number, you may choose any version ever published by the Free Software Foundation.\n\n14. If you wish to incorporate parts of the Library into other free programs whose distribution conditions are incompatible with these, write to the author to ask for permission. For software which is copyrighted by the Free Software Foundation, write to the Free Software Foundation; we sometimes make exceptions for this. Our decision will be guided by the two goals of preserving the free status of all derivatives of our free software and of promoting the sharing and reuse of software generally.\n\nNO WARRANTY\n\n15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE LIBRARY \"AS IS\" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.\n\n16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.\n\nEND OF TERMS AND CONDITIONS\n\nHow to Apply These Terms to Your New Libraries\n\nIf you develop a new library, and you want it to be of the greatest possible use to the public, we recommend making it free software that everyone can redistribute and change. You can do so by permitting redistribution under these terms (or, alternatively, under the terms of the ordinary General Public License).\n\nTo apply these terms, attach the following notices to the library. It is safest to attach them to the start of each source file to most effectively convey the exclusion of warranty; and each file should have at least the \"copyright\" line and a pointer to where the full notice is found.\n\none line to give the library's name and an idea of what it does.\nCopyright (C) year  name of author\n\nThis library is free software; you can redistribute it and/or\nmodify it under the terms of the GNU Lesser General Public\nLicense as published by the Free Software Foundation; either\nversion 2.1 of the License, or (at your option) any later version.\n\nThis library is distributed in the hope that it will be useful,\nbut WITHOUT ANY WARRANTY; without even the implied warranty of\nMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\nLesser General Public License for more details.\n\nYou should have received a copy of the GNU Lesser General Public\nLicense along with this library; if not, write to the Free Software\nFoundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA\nAlso add information on how to contact you by electronic and paper mail.\n\nYou should also get your employer (if you work as a programmer) or your school, if any, to sign a \"copyright disclaimer\" for the library, if necessary. Here is a sample; alter the names:\n\nYoyodyne, Inc., hereby disclaims all copyright interest in\nthe library `Frob' (a library for tweaking knobs) written\nby James Random Hacker.\n\nsignature of Ty Coon, 1 April 1990\nTy Coon, President of Vice\n\n"
  },
  {
    "path": "third_party/demumble/third_party/wine/undname.c",
    "content": "/*\n *  Demangle VC++ symbols into C function prototypes\n *\n *  Copyright 2000 Jon Griffiths\n *            2004 Eric Pouech\n *\n * This library is free software; you can redistribute it and/or\n * modify it under the terms of the GNU Lesser General Public\n * License as published by the Free Software Foundation; either\n * version 2.1 of the License, or (at your option) any later version.\n *\n * This library is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n * Lesser General Public License for more details.\n *\n * You should have received a copy of the GNU Lesser General Public\n * License along with this library; if not, write to the Free Software\n * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA\n */\n\n#ifdef UPSTREAM_CODE\n#include \"config.h\"\n#include \"wine/port.h\"\n\n#include <assert.h>\n#include <stdio.h>\n#include <stdlib.h>\n#include \"msvcrt.h\"\n\n#include \"wine/debug.h\"\n\nWINE_DEFAULT_DEBUG_CHANNEL(msvcrt);\n#else\n#include <assert.h>\n#include <ctype.h>\n#include <stdarg.h>\n#include <stdio.h>\n#include <stdlib.h>\n#include <string.h>\n\n#define TRACE(...)\n#define WARN(...)\n#define ERR(...)\n#define CDECL\ntypedef int BOOL;\nconst BOOL FALSE = 0;\nconst BOOL TRUE = 1;\ntypedef char CHAR;\ntypedef void* (*malloc_func_t)(size_t);\ntypedef void (*free_func_t)(void*);\n\nchar* lstrcpynA(char* out, const char* in, int n) {\n  exit(1); /* not executed in demumbler */\n}\n\n/* __unDName/__unDNameEx flags */\n#define UNDNAME_COMPLETE                 (0x0000)\n#define UNDNAME_NO_LEADING_UNDERSCORES   (0x0001) /* Don't show __ in calling convention */\n#define UNDNAME_NO_MS_KEYWORDS           (0x0002) /* Don't show calling convention at all */\n#define UNDNAME_NO_FUNCTION_RETURNS      (0x0004) /* Don't show function/method return value */\n#define UNDNAME_NO_ALLOCATION_MODEL      (0x0008)\n#define UNDNAME_NO_ALLOCATION_LANGUAGE   (0x0010)\n#define UNDNAME_NO_MS_THISTYPE           (0x0020)\n#define UNDNAME_NO_CV_THISTYPE           (0x0040)\n#define UNDNAME_NO_THISTYPE              (0x0060)\n#define UNDNAME_NO_ACCESS_SPECIFIERS     (0x0080) /* Don't show access specifier (public/protected/private) */\n#define UNDNAME_NO_THROW_SIGNATURES      (0x0100)\n#define UNDNAME_NO_MEMBER_TYPE           (0x0200) /* Don't show static/virtual specifier */\n#define UNDNAME_NO_RETURN_UDT_MODEL      (0x0400)\n#define UNDNAME_32_BIT_DECODE            (0x0800)\n#define UNDNAME_NAME_ONLY                (0x1000) /* Only report the variable/method name */\n#define UNDNAME_NO_ARGUMENTS             (0x2000) /* Don't show method arguments */\n#define UNDNAME_NO_SPECIAL_SYMS          (0x4000)\n#define UNDNAME_NO_COMPLEX_TYPE          (0x8000)\n#endif\n\n/* TODO:\n * - document a bit (grammar + functions)\n * - back-port this new code into tools/winedump/msmangle.c\n */\n\n/* How data types modifiers are stored:\n * M (in the following definitions) is defined for \n * 'A', 'B', 'C' and 'D' as follows\n *      {<A>}:  \"\"\n *      {<B>}:  \"const \"\n *      {<C>}:  \"volatile \"\n *      {<D>}:  \"const volatile \"\n *\n *      in arguments:\n *              P<M>x   {<M>}x*\n *              Q<M>x   {<M>}x* const\n *              A<M>x   {<M>}x&\n *      in data fields:\n *              same as for arguments and also the following\n *              ?<M>x   {<M>}x\n *              \n */\n\nstruct array\n{\n    unsigned            start;          /* first valid reference in array */\n    unsigned            num;            /* total number of used elts */\n    unsigned            max;\n    unsigned            alloc;\n    char**              elts;\n};\n\n/* Structure holding a parsed symbol */\nstruct parsed_symbol\n{\n    unsigned            flags;          /* the UNDNAME_ flags used for demangling */\n    malloc_func_t       mem_alloc_ptr;  /* internal allocator */\n    free_func_t         mem_free_ptr;   /* internal deallocator */\n\n    const char*         current;        /* pointer in input (mangled) string */\n    char*               result;         /* demangled string */\n\n    struct array        names;          /* array of names for back reference */\n    struct array        stack;          /* stack of parsed strings */\n\n    void*               alloc_list;     /* linked list of allocated blocks */\n    unsigned            avail_in_first; /* number of available bytes in head block */\n};\n\n/* Type for parsing mangled types */\nstruct datatype_t\n{\n    const char*         left;\n    const char*         right;\n};\n\nstatic BOOL symbol_demangle(struct parsed_symbol* sym);\n\n/******************************************************************\n *\t\tund_alloc\n *\n * Internal allocator. Uses a simple linked list of large blocks\n * where we use a poor-man allocator. It's fast, and since all\n * allocation is pool, memory management is easy (esp. freeing).\n */\nstatic void*    und_alloc(struct parsed_symbol* sym, unsigned int len)\n{\n    void*       ptr;\n\n#define BLOCK_SIZE      1024\n#define AVAIL_SIZE      (1024 - sizeof(void*))\n\n    if (len > AVAIL_SIZE)\n    {\n        /* allocate a specific block */\n        ptr = sym->mem_alloc_ptr(sizeof(void*) + len);\n        if (!ptr) return NULL;\n        *(void**)ptr = sym->alloc_list;\n        sym->alloc_list = ptr;\n        sym->avail_in_first = 0;\n        ptr = (char*)sym->alloc_list + sizeof(void*);\n    }\n    else \n    {\n        if (len > sym->avail_in_first)\n        {\n            /* add a new block */\n            ptr = sym->mem_alloc_ptr(BLOCK_SIZE);\n            if (!ptr) return NULL;\n            *(void**)ptr = sym->alloc_list;\n            sym->alloc_list = ptr;\n            sym->avail_in_first = AVAIL_SIZE;\n        }\n        /* grab memory from head block */\n        ptr = (char*)sym->alloc_list + BLOCK_SIZE - sym->avail_in_first;\n        sym->avail_in_first -= len;\n    }\n    return ptr;\n#undef BLOCK_SIZE\n#undef AVAIL_SIZE\n}\n\n/******************************************************************\n *\t\tund_free\n * Frees all the blocks in the list of large blocks allocated by\n * und_alloc.\n */\nstatic void und_free_all(struct parsed_symbol* sym)\n{\n    void*       next;\n\n    while (sym->alloc_list)\n    {\n        next = *(void**)sym->alloc_list;\n        if(sym->mem_free_ptr) sym->mem_free_ptr(sym->alloc_list);\n        sym->alloc_list = next;\n    }\n    sym->avail_in_first = 0;\n}\n\n/******************************************************************\n *\t\tstr_array_init\n * Initialises an array of strings\n */\nstatic void str_array_init(struct array* a)\n{\n    a->start = a->num = a->max = a->alloc = 0;\n    a->elts = NULL;\n}\n\n/******************************************************************\n *\t\tstr_array_push\n * Adding a new string to an array\n */\nstatic BOOL str_array_push(struct parsed_symbol* sym, const char* ptr, int len,\n                           struct array* a)\n{\n    char**      new;\n\n    assert(ptr);\n    assert(a);\n\n    if (!a->alloc)\n    {\n        new = und_alloc(sym, (a->alloc = 32) * sizeof(a->elts[0]));\n        if (!new) return FALSE;\n        a->elts = new;\n    }\n    else if (a->max >= a->alloc)\n    {\n        new = und_alloc(sym, (a->alloc * 2) * sizeof(a->elts[0]));\n        if (!new) return FALSE;\n        memcpy(new, a->elts, a->alloc * sizeof(a->elts[0]));\n        a->alloc *= 2;\n        a->elts = new;\n    }\n    if (len == -1) len = strlen(ptr);\n    a->elts[a->num] = und_alloc(sym, len + 1);\n    assert(a->elts[a->num]);\n    memcpy(a->elts[a->num], ptr, len);\n    a->elts[a->num][len] = '\\0'; \n    if (++a->num >= a->max) a->max = a->num;\n    {\n        int i;\n        char c;\n\n        for (i = a->max - 1; i >= 0; i--)\n        {\n            c = '>';\n            if (i < a->start) c = '-';\n            else if (i >= a->num) c = '}';\n            TRACE(\"%p\\t%d%c %s\\n\", a, i, c, a->elts[i]);\n        }\n    }\n\n    return TRUE;\n}\n\n/******************************************************************\n *\t\tstr_array_get_ref\n * Extracts a reference from an existing array (doing proper type\n * checking)\n */\nstatic char* str_array_get_ref(struct array* cref, unsigned idx)\n{\n    assert(cref);\n    if (cref->start + idx >= cref->max)\n    {\n        WARN(\"Out of bounds: %p %d + %d >= %d\\n\", \n              cref, cref->start, idx, cref->max);\n        return NULL;\n    }\n    TRACE(\"Returning %p[%d] => %s\\n\", \n          cref, idx, cref->elts[cref->start + idx]);\n    return cref->elts[cref->start + idx];\n}\n\n/******************************************************************\n *\t\tstr_printf\n * Helper for printf type of command (only %s and %c are implemented) \n * while dynamically allocating the buffer\n */\nstatic char* str_printf(struct parsed_symbol* sym, const char* format, ...)\n{\n    va_list      args;\n    unsigned int len = 1, i, sz;\n    char*        tmp;\n    char*        p;\n    char*        t;\n\n    va_start(args, format);\n    for (i = 0; format[i]; i++)\n    {\n        if (format[i] == '%')\n        {\n            switch (format[++i])\n            {\n            case 's': t = va_arg(args, char*); if (t) len += strlen(t); break;\n            case 'c': (void)va_arg(args, int); len++; break;\n            default: i--; /* fall through */\n            case '%': len++; break;\n            }\n        }\n        else len++;\n    }\n    va_end(args);\n    if (!(tmp = und_alloc(sym, len))) return NULL;\n    va_start(args, format);\n    for (p = tmp, i = 0; format[i]; i++)\n    {\n        if (format[i] == '%')\n        {\n            switch (format[++i])\n            {\n            case 's':\n                t = va_arg(args, char*);\n                if (t)\n                {\n                    sz = strlen(t);\n                    memcpy(p, t, sz);\n                    p += sz;\n                }\n                break;\n            case 'c':\n                *p++ = (char)va_arg(args, int);\n                break;\n            default: i--; /* fall through */\n            case '%': *p++ = '%'; break;\n            }\n        }\n        else *p++ = format[i];\n    }\n    va_end(args);\n    *p = '\\0';\n    return tmp;\n}\n\n/* forward declaration */\nstatic BOOL demangle_datatype(struct parsed_symbol* sym, struct datatype_t* ct,\n                              struct array* pmt, BOOL in_args);\n\nstatic const char* get_number(struct parsed_symbol* sym)\n{\n    char*       ptr;\n    BOOL        sgn = FALSE;\n\n    if (*sym->current == '?')\n    {\n        sgn = TRUE;\n        sym->current++;\n    }\n    if (*sym->current >= '0' && *sym->current <= '8')\n    {\n        ptr = und_alloc(sym, 3);\n        if (sgn) ptr[0] = '-';\n        ptr[sgn ? 1 : 0] = *sym->current + 1;\n        ptr[sgn ? 2 : 1] = '\\0';\n        sym->current++;\n    }\n    else if (*sym->current == '9')\n    {\n        ptr = und_alloc(sym, 4);\n        if (sgn) ptr[0] = '-';\n        ptr[sgn ? 1 : 0] = '1';\n        ptr[sgn ? 2 : 1] = '0';\n        ptr[sgn ? 3 : 2] = '\\0';\n        sym->current++;\n    }\n    else if (*sym->current >= 'A' && *sym->current <= 'P')\n    {\n        int ret = 0;\n\n        while (*sym->current >= 'A' && *sym->current <= 'P')\n        {\n            ret *= 16;\n            ret += *sym->current++ - 'A';\n        }\n        if (*sym->current != '@') return NULL;\n\n        ptr = und_alloc(sym, 17);\n        sprintf(ptr, \"%s%u\", sgn ? \"-\" : \"\", ret);\n        sym->current++;\n    }\n    else return NULL;\n    return ptr;\n}\n\n/******************************************************************\n *\t\tget_args\n * Parses a list of function/method arguments, creates a string corresponding\n * to the arguments' list.\n */\nstatic char* get_args(struct parsed_symbol* sym, struct array* pmt_ref, BOOL z_term, \n                      char open_char, char close_char)\n\n{\n    struct datatype_t   ct;\n    struct array        arg_collect;\n    char*               args_str = NULL;\n    char*               last;\n    unsigned int        i;\n\n    str_array_init(&arg_collect);\n\n    /* Now come the function arguments */\n    while (*sym->current)\n    {\n        /* Decode each data type and append it to the argument list */\n        if (*sym->current == '@')\n        {\n            sym->current++;\n            break;\n        }\n        if (!demangle_datatype(sym, &ct, pmt_ref, TRUE))\n            return NULL;\n        /* 'void' terminates an argument list in a function */\n        if (z_term && !strcmp(ct.left, \"void\")) break;\n        if (!str_array_push(sym, str_printf(sym, \"%s%s\", ct.left, ct.right), -1,\n                            &arg_collect))\n            return NULL;\n        if (!strcmp(ct.left, \"...\")) break;\n    }\n    /* Functions are always terminated by 'Z'. If we made it this far and\n     * don't find it, we have incorrectly identified a data type.\n     */\n    if (z_term && *sym->current++ != 'Z') return NULL;\n\n    if (arg_collect.num == 0 || \n        (arg_collect.num == 1 && !strcmp(arg_collect.elts[0], \"void\")))        \n        return str_printf(sym, \"%cvoid%c\", open_char, close_char);\n    for (i = 1; i < arg_collect.num; i++)\n    {\n        args_str = str_printf(sym, \"%s,%s\", args_str, arg_collect.elts[i]);\n    }\n\n    last = args_str ? args_str : arg_collect.elts[0];\n    if (close_char == '>' && last[strlen(last) - 1] == '>')\n        args_str = str_printf(sym, \"%c%s%s %c\", \n                              open_char, arg_collect.elts[0], args_str, close_char);\n    else\n        args_str = str_printf(sym, \"%c%s%s%c\", \n                              open_char, arg_collect.elts[0], args_str, close_char);\n    \n    return args_str;\n}\n\n/******************************************************************\n *\t\tget_modifier\n * Parses the type modifier. Always returns static strings.\n */\nstatic BOOL get_modifier(struct parsed_symbol *sym, const char **ret, const char **ptr_modif)\n{\n    *ptr_modif = NULL;\n    if (*sym->current == 'E')\n    {\n        if (!(sym->flags & UNDNAME_NO_MS_KEYWORDS))\n        {\n            *ptr_modif = \"__ptr64\";\n            if (sym->flags & UNDNAME_NO_LEADING_UNDERSCORES)\n                *ptr_modif = *ptr_modif + 2;\n        }\n        sym->current++;\n    }\n    switch (*sym->current++)\n    {\n    case 'A': *ret = NULL; break;\n    case 'B': *ret = \"const\"; break;\n    case 'C': *ret = \"volatile\"; break;\n    case 'D': *ret = \"const volatile\"; break;\n    default: return FALSE;\n    }\n    return TRUE;\n}\n\nstatic BOOL get_modified_type(struct datatype_t *ct, struct parsed_symbol* sym,\n                              struct array *pmt_ref, char modif, BOOL in_args)\n{\n    const char* modifier;\n    const char* str_modif;\n    const char *ptr_modif = \"\";\n\n    if (*sym->current == 'E')\n    {\n        if (!(sym->flags & UNDNAME_NO_MS_KEYWORDS))\n        {\n            if (sym->flags & UNDNAME_NO_LEADING_UNDERSCORES)\n                ptr_modif = \" ptr64\";\n            else\n                ptr_modif = \" __ptr64\";\n        }\n        sym->current++;\n    }\n\n    switch (modif)\n    {\n    case 'A': str_modif = str_printf(sym, \" &%s\", ptr_modif); break;\n    case 'B': str_modif = str_printf(sym, \" &%s volatile\", ptr_modif); break;\n    case 'P': str_modif = str_printf(sym, \" *%s\", ptr_modif); break;\n    case 'Q': str_modif = str_printf(sym, \" *%s const\", ptr_modif); break;\n    case 'R': str_modif = str_printf(sym, \" *%s volatile\", ptr_modif); break;\n    case 'S': str_modif = str_printf(sym, \" *%s const volatile\", ptr_modif); break;\n    case '?': str_modif = \"\"; break;\n    default: return FALSE;\n    }\n\n    if (get_modifier(sym, &modifier, &ptr_modif))\n    {\n        unsigned            mark = sym->stack.num;\n        struct datatype_t   sub_ct;\n\n        /* multidimensional arrays */\n        if (*sym->current == 'Y')\n        {\n            const char* n1;\n            int num;\n\n            sym->current++;\n            if (!(n1 = get_number(sym))) return FALSE;\n            num = atoi(n1);\n\n            if (str_modif[0] == ' ' && !modifier)\n                str_modif++;\n\n            if (modifier)\n            {\n                str_modif = str_printf(sym, \" (%s%s)\", modifier, str_modif);\n                modifier = NULL;\n            }\n            else\n                str_modif = str_printf(sym, \" (%s)\", str_modif);\n\n            while (num--)\n                str_modif = str_printf(sym, \"%s[%s]\", str_modif, get_number(sym));\n        }\n\n        /* Recurse to get the referred-to type */\n        if (!demangle_datatype(sym, &sub_ct, pmt_ref, FALSE))\n            return FALSE;\n        if (modifier)\n            ct->left = str_printf(sym, \"%s %s%s\", sub_ct.left, modifier, str_modif );\n        else\n        {\n            /* don't insert a space between duplicate '*' */\n            if (!in_args && str_modif[0] && str_modif[1] == '*' && sub_ct.left[strlen(sub_ct.left)-1] == '*')\n                str_modif++;\n            ct->left = str_printf(sym, \"%s%s\", sub_ct.left, str_modif );\n        }\n        ct->right = sub_ct.right;\n        sym->stack.num = mark;\n    }\n    return TRUE;\n}\n\n/******************************************************************\n *             get_literal_string\n * Gets the literal name from the current position in the mangled\n * symbol to the first '@' character. It pushes the parsed name to\n * the symbol names stack and returns a pointer to it or NULL in\n * case of an error.\n */\nstatic char* get_literal_string(struct parsed_symbol* sym)\n{\n    const char *ptr = sym->current;\n\n    do {\n        if (!((*sym->current >= 'A' && *sym->current <= 'Z') ||\n              (*sym->current >= 'a' && *sym->current <= 'z') ||\n              (*sym->current >= '0' && *sym->current <= '9') ||\n              *sym->current == '_' || *sym->current == '$')) {\n            TRACE(\"Failed at '%c' in %s\\n\", *sym->current, ptr);\n            return NULL;\n        }\n    } while (*++sym->current != '@');\n    sym->current++;\n    if (!str_array_push(sym, ptr, sym->current - 1 - ptr, &sym->names))\n        return NULL;\n\n    return str_array_get_ref(&sym->names, sym->names.num - sym->names.start - 1);\n}\n\n/******************************************************************\n *\t\tget_template_name\n * Parses a name with a template argument list and returns it as\n * a string.\n * In a template argument list the back reference to the names\n * table is separately created. '0' points to the class component\n * name with the template arguments.  We use the same stack array\n * to hold the names but save/restore the stack state before/after\n * parsing the template argument list.\n */\nstatic char* get_template_name(struct parsed_symbol* sym)\n{\n    char *name, *args;\n    unsigned num_mark = sym->names.num;\n    unsigned start_mark = sym->names.start;\n    unsigned stack_mark = sym->stack.num;\n    struct array array_pmt;\n\n    sym->names.start = sym->names.num;\n    if (!(name = get_literal_string(sym))) {\n        sym->names.start = start_mark;\n        return NULL;\n    }\n    str_array_init(&array_pmt);\n    args = get_args(sym, &array_pmt, FALSE, '<', '>');\n    if (args != NULL)\n        name = str_printf(sym, \"%s%s\", name, args);\n    sym->names.num = num_mark;\n    sym->names.start = start_mark;\n    sym->stack.num = stack_mark;\n    return name;\n}\n\n/******************************************************************\n *\t\tget_class\n * Parses class as a list of parent-classes, terminated by '@' and stores the\n * result in 'a' array. Each parent-classes, as well as the inner element\n * (either field/method name or class name), are represented in the mangled\n * name by a literal name ([a-zA-Z0-9_]+ terminated by '@') or a back reference\n * ([0-9]) or a name with template arguments ('?$' literal name followed by the\n * template argument list). The class name components appear in the reverse\n * order in the mangled name, e.g aaa@bbb@ccc@@ will be demangled to\n * ccc::bbb::aaa\n * For each of these class name components a string will be allocated in the\n * array.\n */\nstatic BOOL get_class(struct parsed_symbol* sym)\n{\n    const char* name = NULL;\n\n    while (*sym->current != '@')\n    {\n        switch (*sym->current)\n        {\n        case '\\0': return FALSE;\n\n        case '0': case '1': case '2': case '3':\n        case '4': case '5': case '6': case '7':\n        case '8': case '9':\n            name = str_array_get_ref(&sym->names, *sym->current++ - '0');\n            break;\n        case '?':\n            switch (*++sym->current)\n            {\n            case '$':\n                sym->current++;\n                if ((name = get_template_name(sym)) &&\n                    !str_array_push(sym, name, -1, &sym->names))\n                    return FALSE;\n                break;\n            case '?':\n                {\n                    struct array stack = sym->stack;\n                    unsigned int start = sym->names.start;\n                    unsigned int num = sym->names.num;\n\n                    str_array_init( &sym->stack );\n                    if (symbol_demangle( sym )) name = str_printf( sym, \"`%s'\", sym->result );\n                    sym->names.start = start;\n                    sym->names.num = num;\n                    sym->stack = stack;\n                }\n                break;\n            default:\n                if (!(name = get_number( sym ))) return FALSE;\n                name = str_printf( sym, \"`%s'\", name );\n                break;\n            }\n            break;\n        default:\n            name = get_literal_string(sym);\n            break;\n        }\n        if (!name || !str_array_push(sym, name, -1, &sym->stack))\n            return FALSE;\n    }\n    sym->current++;\n    return TRUE;\n}\n\n/******************************************************************\n *\t\tget_class_string\n * From an array collected by get_class in sym->stack, constructs the\n * corresponding (allocated) string\n */\nstatic char* get_class_string(struct parsed_symbol* sym, int start)\n{\n    int          i;\n    unsigned int len, sz;\n    char*        ret;\n    struct array *a = &sym->stack;\n\n    for (len = 0, i = start; i < a->num; i++)\n    {\n        assert(a->elts[i]);\n        len += 2 + strlen(a->elts[i]);\n    }\n    if (!(ret = und_alloc(sym, len - 1))) return NULL;\n    for (len = 0, i = a->num - 1; i >= start; i--)\n    {\n        sz = strlen(a->elts[i]);\n        memcpy(ret + len, a->elts[i], sz);\n        len += sz;\n        if (i > start)\n        {\n            ret[len++] = ':';\n            ret[len++] = ':';\n        }\n    }\n    ret[len] = '\\0';\n    return ret;\n}\n\n/******************************************************************\n *            get_class_name\n * Wrapper around get_class and get_class_string.\n */\nstatic char* get_class_name(struct parsed_symbol* sym)\n{\n    unsigned    mark = sym->stack.num;\n    char*       s = NULL;\n\n    if (get_class(sym))\n        s = get_class_string(sym, mark);\n    sym->stack.num = mark;\n    return s;\n}\n\n/******************************************************************\n *\t\tget_calling_convention\n * Returns a static string corresponding to the calling convention described\n * by char 'ch'. Sets export to TRUE iff the calling convention is exported.\n */\nstatic BOOL get_calling_convention(char ch, const char** call_conv,\n                                   const char** exported, unsigned flags)\n{\n    *call_conv = *exported = NULL;\n\n    if (!(flags & (UNDNAME_NO_MS_KEYWORDS | UNDNAME_NO_ALLOCATION_LANGUAGE)))\n    {\n        if (flags & UNDNAME_NO_LEADING_UNDERSCORES)\n        {\n            if (((ch - 'A') % 2) == 1) *exported = \"dll_export \";\n            switch (ch)\n            {\n            case 'A': case 'B': *call_conv = \"cdecl\"; break;\n            case 'C': case 'D': *call_conv = \"pascal\"; break;\n            case 'E': case 'F': *call_conv = \"thiscall\"; break;\n            case 'G': case 'H': *call_conv = \"stdcall\"; break;\n            case 'I': case 'J': *call_conv = \"fastcall\"; break;\n            case 'K': case 'L': break;\n            case 'M': *call_conv = \"clrcall\"; break;\n            default: ERR(\"Unknown calling convention %c\\n\", ch); return FALSE;\n            }\n        }\n        else\n        {\n            if (((ch - 'A') % 2) == 1) *exported = \"__dll_export \";\n            switch (ch)\n            {\n            case 'A': case 'B': *call_conv = \"__cdecl\"; break;\n            case 'C': case 'D': *call_conv = \"__pascal\"; break;\n            case 'E': case 'F': *call_conv = \"__thiscall\"; break;\n            case 'G': case 'H': *call_conv = \"__stdcall\"; break;\n            case 'I': case 'J': *call_conv = \"__fastcall\"; break;\n            case 'K': case 'L': break;\n            case 'M': *call_conv = \"__clrcall\"; break;\n            default: ERR(\"Unknown calling convention %c\\n\", ch); return FALSE;\n            }\n        }\n    }\n    return TRUE;\n}\n\n/*******************************************************************\n *         get_simple_type\n * Return a string containing an allocated string for a simple data type\n */\nstatic const char* get_simple_type(char c)\n{\n    const char* type_string;\n    \n    switch (c)\n    {\n    case 'C': type_string = \"signed char\"; break;\n    case 'D': type_string = \"char\"; break;\n    case 'E': type_string = \"unsigned char\"; break;\n    case 'F': type_string = \"short\"; break;\n    case 'G': type_string = \"unsigned short\"; break;\n    case 'H': type_string = \"int\"; break;\n    case 'I': type_string = \"unsigned int\"; break;\n    case 'J': type_string = \"long\"; break;\n    case 'K': type_string = \"unsigned long\"; break;\n    case 'M': type_string = \"float\"; break;\n    case 'N': type_string = \"double\"; break;\n    case 'O': type_string = \"long double\"; break;\n    case 'X': type_string = \"void\"; break;\n    case 'Z': type_string = \"...\"; break;\n    default:  type_string = NULL; break;\n    }\n    return type_string;\n}\n\n/*******************************************************************\n *         get_extended_type\n * Return a string containing an allocated string for a simple data type\n */\nstatic const char* get_extended_type(char c)\n{\n    const char* type_string;\n    \n    switch (c)\n    {\n    case 'D': type_string = \"__int8\"; break;\n    case 'E': type_string = \"unsigned __int8\"; break;\n    case 'F': type_string = \"__int16\"; break;\n    case 'G': type_string = \"unsigned __int16\"; break;\n    case 'H': type_string = \"__int32\"; break;\n    case 'I': type_string = \"unsigned __int32\"; break;\n    case 'J': type_string = \"__int64\"; break;\n    case 'K': type_string = \"unsigned __int64\"; break;\n    case 'L': type_string = \"__int128\"; break;\n    case 'M': type_string = \"unsigned __int128\"; break;\n    case 'N': type_string = \"bool\"; break;\n    case 'W': type_string = \"wchar_t\"; break;\n    default:  type_string = NULL; break;\n    }\n    return type_string;\n}\n\n/*******************************************************************\n *         demangle_datatype\n *\n * Attempt to demangle a C++ data type, which may be datatype.\n * a datatype type is made up of a number of simple types. e.g:\n * char** = (pointer to (pointer to (char)))\n */\nstatic BOOL demangle_datatype(struct parsed_symbol* sym, struct datatype_t* ct,\n                              struct array* pmt_ref, BOOL in_args)\n{\n    char                dt;\n    BOOL                add_pmt = TRUE;\n\n    assert(ct);\n    ct->left = ct->right = NULL;\n    \n    switch (dt = *sym->current++)\n    {\n    case '_':\n        /* MS type: __int8,__int16 etc */\n        ct->left = get_extended_type(*sym->current++);\n        break;\n    case 'C': case 'D': case 'E': case 'F': case 'G':\n    case 'H': case 'I': case 'J': case 'K': case 'M':\n    case 'N': case 'O': case 'X': case 'Z':\n        /* Simple data types */\n        ct->left = get_simple_type(dt);\n        add_pmt = FALSE;\n        break;\n    case 'T': /* union */\n    case 'U': /* struct */\n    case 'V': /* class */\n    case 'Y': /* cointerface */\n        /* Class/struct/union/cointerface */\n        {\n            const char* struct_name = NULL;\n            const char* type_name = NULL;\n\n            if (!(struct_name = get_class_name(sym)))\n                goto done;\n            if (!(sym->flags & UNDNAME_NO_COMPLEX_TYPE)) \n            {\n                switch (dt)\n                {\n                case 'T': type_name = \"union \";  break;\n                case 'U': type_name = \"struct \"; break;\n                case 'V': type_name = \"class \";  break;\n                case 'Y': type_name = \"cointerface \"; break;\n                }\n            }\n            ct->left = str_printf(sym, \"%s%s\", type_name, struct_name);\n        }\n        break;\n    case '?':\n        /* not all the time is seems */\n        if (in_args)\n        {\n            const char*   ptr;\n            if (!(ptr = get_number(sym))) goto done;\n            ct->left = str_printf(sym, \"`template-parameter-%s'\", ptr);\n        }\n        else\n        {\n            if (!get_modified_type(ct, sym, pmt_ref, '?', in_args)) goto done;\n        }\n        break;\n    case 'A': /* reference */\n    case 'B': /* volatile reference */\n        if (!get_modified_type(ct, sym, pmt_ref, dt, in_args)) goto done;\n        break;\n    case 'Q': /* const pointer */\n    case 'R': /* volatile pointer */\n    case 'S': /* const volatile pointer */\n        if (!get_modified_type(ct, sym, pmt_ref, in_args ? dt : 'P', in_args)) goto done;\n        break;\n    case 'P': /* Pointer */\n        if (isdigit(*sym->current))\n\t{\n            /* FIXME: P6 = Function pointer, others who knows.. */\n            if (*sym->current++ == '6')\n            {\n                char*                   args = NULL;\n                const char*             call_conv;\n                const char*             exported;\n                struct datatype_t       sub_ct;\n                unsigned                mark = sym->stack.num;\n\n                if (!get_calling_convention(*sym->current++,\n                                            &call_conv, &exported, \n                                            sym->flags & ~UNDNAME_NO_ALLOCATION_LANGUAGE) ||\n                    !demangle_datatype(sym, &sub_ct, pmt_ref, FALSE))\n                    goto done;\n\n                args = get_args(sym, pmt_ref, TRUE, '(', ')');\n                if (!args) goto done;\n                sym->stack.num = mark;\n\n                ct->left  = str_printf(sym, \"%s%s (%s*\", \n                                       sub_ct.left, sub_ct.right, call_conv);\n                ct->right = str_printf(sym, \")%s\", args);\n            }\n            else goto done;\n\t}\n\telse if (!get_modified_type(ct, sym, pmt_ref, 'P', in_args)) goto done;\n        break;\n    case 'W':\n        if (*sym->current == '4')\n        {\n            char*               enum_name;\n            sym->current++;\n            if (!(enum_name = get_class_name(sym)))\n                goto done;\n            if (sym->flags & UNDNAME_NO_COMPLEX_TYPE)\n                ct->left = enum_name;\n            else\n                ct->left = str_printf(sym, \"enum %s\", enum_name);\n        }\n        else goto done;\n        break;\n    case '0': case '1': case '2': case '3': case '4':\n    case '5': case '6': case '7': case '8': case '9':\n        /* Referring back to previously parsed type */\n        /* left and right are pushed as two separate strings */\n        ct->left = str_array_get_ref(pmt_ref, (dt - '0') * 2);\n        ct->right = str_array_get_ref(pmt_ref, (dt - '0') * 2 + 1);\n        if (!ct->left) goto done;\n        add_pmt = FALSE;\n        break;\n    case '$':\n        switch (*sym->current++)\n        {\n        case '0':\n            if (!(ct->left = get_number(sym))) goto done;\n            break;\n        case 'D':\n            {\n                const char*   ptr;\n                if (!(ptr = get_number(sym))) goto done;\n                ct->left = str_printf(sym, \"`template-parameter%s'\", ptr);\n            }\n            break;\n        case 'F':\n            {\n                const char*   p1;\n                const char*   p2;\n                if (!(p1 = get_number(sym))) goto done;\n                if (!(p2 = get_number(sym))) goto done;\n                ct->left = str_printf(sym, \"{%s,%s}\", p1, p2);\n            }\n            break;\n        case 'G':\n            {\n                const char*   p1;\n                const char*   p2;\n                const char*   p3;\n                if (!(p1 = get_number(sym))) goto done;\n                if (!(p2 = get_number(sym))) goto done;\n                if (!(p3 = get_number(sym))) goto done;\n                ct->left = str_printf(sym, \"{%s,%s,%s}\", p1, p2, p3);\n            }\n            break;\n        case 'Q':\n            {\n                const char*   ptr;\n                if (!(ptr = get_number(sym))) goto done;\n                ct->left = str_printf(sym, \"`non-type-template-parameter%s'\", ptr);\n            }\n            break;\n        case '$':\n            if (*sym->current == 'C')\n            {\n                const char *ptr, *ptr_modif;\n\n                sym->current++;\n                if (!get_modifier(sym, &ptr, &ptr_modif)) goto done;\n                if (!demangle_datatype(sym, ct, pmt_ref, in_args)) goto done;\n                ct->left = str_printf(sym, \"%s %s\", ct->left, ptr);\n            }\n            break;\n        }\n        break;\n    default :\n        ERR(\"Unknown type %c\\n\", dt);\n        break;\n    }\n    if (add_pmt && pmt_ref && in_args)\n    {\n        /* left and right are pushed as two separate strings */\n        if (!str_array_push(sym, ct->left ? ct->left : \"\", -1, pmt_ref) ||\n            !str_array_push(sym, ct->right ? ct->right : \"\", -1, pmt_ref))\n            return FALSE;\n    }\ndone:\n    \n    return ct->left != NULL;\n}\n\n/******************************************************************\n *\t\thandle_data\n * Does the final parsing and handling for a variable or a field in\n * a class.\n */\nstatic BOOL handle_data(struct parsed_symbol* sym)\n{\n    const char*         access = NULL;\n    const char*         member_type = NULL;\n    const char*         modifier = NULL;\n    const char*         ptr_modif;\n    struct datatype_t   ct;\n    char*               name = NULL;\n    BOOL                ret = FALSE;\n\n    /* 0 private static\n     * 1 protected static\n     * 2 public static\n     * 3 private non-static\n     * 4 protected non-static\n     * 5 public non-static\n     * 6 ?? static\n     * 7 ?? static\n     */\n\n    if (!(sym->flags & UNDNAME_NO_ACCESS_SPECIFIERS))\n    {\n        /* we only print the access for static members */\n        switch (*sym->current)\n        {\n        case '0': access = \"private: \"; break;\n        case '1': access = \"protected: \"; break;\n        case '2': access = \"public: \"; break;\n        } \n    }\n\n    if (!(sym->flags & UNDNAME_NO_MEMBER_TYPE))\n    {\n        if (*sym->current >= '0' && *sym->current <= '2')\n            member_type = \"static \";\n    }\n\n    name = get_class_string(sym, 0);\n\n    switch (*sym->current++)\n    {\n    case '0': case '1': case '2':\n    case '3': case '4': case '5':\n        {\n            unsigned mark = sym->stack.num;\n            struct array pmt;\n\n            str_array_init(&pmt);\n\n            if (!demangle_datatype(sym, &ct, &pmt, FALSE)) goto done;\n            if (!get_modifier(sym, &modifier, &ptr_modif)) goto done;\n            if (modifier && ptr_modif) modifier = str_printf(sym, \"%s %s\", modifier, ptr_modif);\n            else if (!modifier) modifier = ptr_modif;\n            sym->stack.num = mark;\n        }\n        break;\n    case '6' : /* compiler generated static */\n    case '7' : /* compiler generated static */\n        ct.left = ct.right = NULL;\n        if (!get_modifier(sym, &modifier, &ptr_modif)) goto done;\n        if (*sym->current != '@')\n        {\n            char*       cls = NULL;\n\n            if (!(cls = get_class_name(sym)))\n                goto done;\n            ct.right = str_printf(sym, \"{for `%s'}\", cls);\n        }\n        break;\n    case '8':\n    case '9':\n        modifier = ct.left = ct.right = NULL;\n        break;\n    default: goto done;\n    }\n    if (sym->flags & UNDNAME_NAME_ONLY) ct.left = ct.right = modifier = NULL;\n\n    sym->result = str_printf(sym, \"%s%s%s%s%s%s%s%s\", access,\n                             member_type, ct.left, \n                             modifier && ct.left ? \" \" : NULL, modifier, \n                             modifier || ct.left ? \" \" : NULL, name, ct.right);\n    ret = TRUE;\ndone:\n    return ret;\n}\n\n/******************************************************************\n *\t\thandle_method\n * Does the final parsing and handling for a function or a method in\n * a class.\n */\nstatic BOOL handle_method(struct parsed_symbol* sym, BOOL cast_op)\n{\n    char                accmem;\n    const char*         access = NULL;\n    int                 access_id = -1;\n    const char*         member_type = NULL;\n    struct datatype_t   ct_ret;\n    const char*         call_conv;\n    const char*         modifier = NULL;\n    const char*         exported;\n    const char*         args_str = NULL;\n    const char*         name = NULL;\n    BOOL                ret = FALSE, has_args = TRUE, has_ret = TRUE;\n    unsigned            mark;\n    struct array        array_pmt;\n\n    /* FIXME: why 2 possible letters for each option?\n     * 'A' private:\n     * 'B' private:\n     * 'C' private: static\n     * 'D' private: static\n     * 'E' private: virtual\n     * 'F' private: virtual\n     * 'G' private: thunk\n     * 'H' private: thunk\n     * 'I' protected:\n     * 'J' protected:\n     * 'K' protected: static\n     * 'L' protected: static\n     * 'M' protected: virtual\n     * 'N' protected: virtual\n     * 'O' protected: thunk\n     * 'P' protected: thunk\n     * 'Q' public:\n     * 'R' public:\n     * 'S' public: static\n     * 'T' public: static\n     * 'U' public: virtual\n     * 'V' public: virtual\n     * 'W' public: thunk\n     * 'X' public: thunk\n     * 'Y'\n     * 'Z'\n     * \"$0\" private: thunk vtordisp\n     * \"$1\" private: thunk vtordisp\n     * \"$2\" protected: thunk vtordisp\n     * \"$3\" protected: thunk vtordisp\n     * \"$4\" public: thunk vtordisp\n     * \"$5\" public: thunk vtordisp\n     * \"$B\" vcall thunk\n     * \"$R\" thunk vtordispex\n     */\n    accmem = *sym->current++;\n    if (accmem == '$')\n    {\n        if (*sym->current >= '0' && *sym->current <= '5')\n            access_id = (*sym->current - '0') / 2;\n        else if (*sym->current == 'R')\n            access_id = (sym->current[1] - '0') / 2;\n        else if (*sym->current != 'B')\n            goto done;\n    }\n    else if (accmem >= 'A' && accmem <= 'Z')\n        access_id = (accmem - 'A') / 8;\n    else\n        goto done;\n\n    switch (access_id)\n    {\n    case 0: access = \"private: \"; break;\n    case 1: access = \"protected: \"; break;\n    case 2: access = \"public: \"; break;\n    }\n    if (accmem == '$' || (accmem - 'A') % 8 == 6 || (accmem - 'A') % 8 == 7)\n        access = str_printf(sym, \"[thunk]:%s\", access ? access : \" \");\n\n    if (accmem == '$' && *sym->current != 'B')\n        member_type = \"virtual \";\n    else if (accmem <= 'X')\n    {\n        switch ((accmem - 'A') % 8)\n        {\n        case 2: case 3: member_type = \"static \"; break;\n        case 4: case 5: case 6: case 7: member_type = \"virtual \"; break;\n        }\n    }\n\n    if (sym->flags & UNDNAME_NO_ACCESS_SPECIFIERS)\n        access = NULL;\n    if (sym->flags & UNDNAME_NO_MEMBER_TYPE)\n        member_type = NULL;\n\n    name = get_class_string(sym, 0);\n\n    if (accmem == '$' && *sym->current == 'B') /* vcall thunk */\n    {\n        const char *n;\n\n        sym->current++;\n        n = get_number(sym);\n\n        if(!n || *sym->current++ != 'A') goto done;\n        name = str_printf(sym, \"%s{%s,{flat}}' }'\", name, n);\n        has_args = FALSE;\n        has_ret = FALSE;\n    }\n    else if (accmem == '$' && *sym->current == 'R') /* vtordispex thunk */\n    {\n        const char *n1, *n2, *n3, *n4;\n\n        sym->current += 2;\n        n1 = get_number(sym);\n        n2 = get_number(sym);\n        n3 = get_number(sym);\n        n4 = get_number(sym);\n\n        if(!n1 || !n2 || !n3 || !n4) goto done;\n        name = str_printf(sym, \"%s`vtordispex{%s,%s,%s,%s}' \", name, n1, n2, n3, n4);\n    }\n    else if (accmem == '$') /* vtordisp thunk */\n    {\n        const char *n1, *n2;\n\n        sym->current++;\n        n1 = get_number(sym);\n        n2 = get_number(sym);\n\n        if (!n1 || !n2) goto done;\n        name = str_printf(sym, \"%s`vtordisp{%s,%s}' \", name, n1, n2);\n    }\n    else if ((accmem - 'A') % 8 == 6 || (accmem - 'A') % 8 == 7) /* a thunk */\n        name = str_printf(sym, \"%s`adjustor{%s}' \", name, get_number(sym));\n\n    if (has_args && (accmem == '$' ||\n                (accmem <= 'X' && (accmem - 'A') % 8 != 2 && (accmem - 'A') % 8 != 3)))\n    {\n        const char *ptr_modif;\n        /* Implicit 'this' pointer */\n        /* If there is an implicit this pointer, const modifier follows */\n        if (!get_modifier(sym, &modifier, &ptr_modif)) goto done;\n        if (modifier || ptr_modif) modifier = str_printf(sym, \"%s %s\", modifier, ptr_modif);\n    }\n\n    if (!get_calling_convention(*sym->current++, &call_conv, &exported,\n                                sym->flags))\n        goto done;\n\n    str_array_init(&array_pmt);\n\n    /* Return type, or @ if 'void' */\n    if (has_ret && *sym->current == '@')\n    {\n        ct_ret.left = \"void\";\n        ct_ret.right = NULL;\n        sym->current++;\n    }\n    else if (has_ret)\n    {\n        if (!demangle_datatype(sym, &ct_ret, &array_pmt, FALSE))\n            goto done;\n    }\n    if (!has_ret || sym->flags & UNDNAME_NO_FUNCTION_RETURNS)\n        ct_ret.left = ct_ret.right = NULL;\n    if (cast_op)\n    {\n        name = str_printf(sym, \"%s%s%s\", name, ct_ret.left, ct_ret.right);\n        ct_ret.left = ct_ret.right = NULL;\n    }\n\n    mark = sym->stack.num;\n    if (has_args && !(args_str = get_args(sym, &array_pmt, TRUE, '(', ')'))) goto done;\n    if (sym->flags & UNDNAME_NAME_ONLY) args_str = modifier = NULL;\n    if (sym->flags & UNDNAME_NO_THISTYPE) modifier = NULL;\n    sym->stack.num = mark;\n\n    /* Note: '()' after 'Z' means 'throws', but we don't care here\n     * Yet!!! FIXME\n     */\n    sym->result = str_printf(sym, \"%s%s%s%s%s%s%s%s%s%s%s\",\n                             access, member_type, ct_ret.left,\n                             (ct_ret.left && !ct_ret.right) ? \" \" : NULL,\n                             call_conv, call_conv ? \" \" : NULL, exported,\n                             name, args_str, modifier, ct_ret.right);\n    ret = TRUE;\ndone:\n    return ret;\n}\n\n/*******************************************************************\n *         symbol_demangle\n * Demangle a C++ linker symbol\n */\nstatic BOOL symbol_demangle(struct parsed_symbol* sym)\n{\n    BOOL                ret = FALSE;\n    unsigned            do_after = 0;\n    static CHAR         dashed_null[] = \"--null--\";\n\n    /* FIXME seems wrong as name, as it demangles a simple data type */\n    if (sym->flags & UNDNAME_NO_ARGUMENTS)\n    {\n        struct datatype_t   ct;\n\n        if (demangle_datatype(sym, &ct, NULL, FALSE))\n        {\n            sym->result = str_printf(sym, \"%s%s\", ct.left, ct.right);\n            ret = TRUE;\n        }\n        goto done;\n    }\n\n    /* MS mangled names always begin with '?' */\n    if (*sym->current != '?') return FALSE;\n    sym->current++;\n\n    /* Then function name or operator code */\n    if (*sym->current == '?' && (sym->current[1] != '$' || sym->current[2] == '?'))\n    {\n        const char* function_name = NULL;\n\n        if (sym->current[1] == '$')\n        {\n            do_after = 6;\n            sym->current += 2;\n        }\n\n        /* C++ operator code (one character, or two if the first is '_') */\n        switch (*++sym->current)\n        {\n        case '0': do_after = 1; break;\n        case '1': do_after = 2; break;\n        case '2': function_name = \"operator new\"; break;\n        case '3': function_name = \"operator delete\"; break;\n        case '4': function_name = \"operator=\"; break;\n        case '5': function_name = \"operator>>\"; break;\n        case '6': function_name = \"operator<<\"; break;\n        case '7': function_name = \"operator!\"; break;\n        case '8': function_name = \"operator==\"; break;\n        case '9': function_name = \"operator!=\"; break;\n        case 'A': function_name = \"operator[]\"; break;\n        case 'B': function_name = \"operator \"; do_after = 3; break;\n        case 'C': function_name = \"operator->\"; break;\n        case 'D': function_name = \"operator*\"; break;\n        case 'E': function_name = \"operator++\"; break;\n        case 'F': function_name = \"operator--\"; break;\n        case 'G': function_name = \"operator-\"; break;\n        case 'H': function_name = \"operator+\"; break;\n        case 'I': function_name = \"operator&\"; break;\n        case 'J': function_name = \"operator->*\"; break;\n        case 'K': function_name = \"operator/\"; break;\n        case 'L': function_name = \"operator%\"; break;\n        case 'M': function_name = \"operator<\"; break;\n        case 'N': function_name = \"operator<=\"; break;\n        case 'O': function_name = \"operator>\"; break;\n        case 'P': function_name = \"operator>=\"; break;\n        case 'Q': function_name = \"operator,\"; break;\n        case 'R': function_name = \"operator()\"; break;\n        case 'S': function_name = \"operator~\"; break;\n        case 'T': function_name = \"operator^\"; break;\n        case 'U': function_name = \"operator|\"; break;\n        case 'V': function_name = \"operator&&\"; break;\n        case 'W': function_name = \"operator||\"; break;\n        case 'X': function_name = \"operator*=\"; break;\n        case 'Y': function_name = \"operator+=\"; break;\n        case 'Z': function_name = \"operator-=\"; break;\n        case '_':\n            switch (*++sym->current)\n            {\n            case '0': function_name = \"operator/=\"; break;\n            case '1': function_name = \"operator%=\"; break;\n            case '2': function_name = \"operator>>=\"; break;\n            case '3': function_name = \"operator<<=\"; break;\n            case '4': function_name = \"operator&=\"; break;\n            case '5': function_name = \"operator|=\"; break;\n            case '6': function_name = \"operator^=\"; break;\n            case '7': function_name = \"`vftable'\"; break;\n            case '8': function_name = \"`vbtable'\"; break;\n            case '9': function_name = \"`vcall'\"; break;\n            case 'A': function_name = \"`typeof'\"; break;\n            case 'B': function_name = \"`local static guard'\"; break;\n            case 'C': function_name = \"`string'\"; do_after = 4; break;\n            case 'D': function_name = \"`vbase destructor'\"; break;\n            case 'E': function_name = \"`vector deleting destructor'\"; break;\n            case 'F': function_name = \"`default constructor closure'\"; break;\n            case 'G': function_name = \"`scalar deleting destructor'\"; break;\n            case 'H': function_name = \"`vector constructor iterator'\"; break;\n            case 'I': function_name = \"`vector destructor iterator'\"; break;\n            case 'J': function_name = \"`vector vbase constructor iterator'\"; break;\n            case 'K': function_name = \"`virtual displacement map'\"; break;\n            case 'L': function_name = \"`eh vector constructor iterator'\"; break;\n            case 'M': function_name = \"`eh vector destructor iterator'\"; break;\n            case 'N': function_name = \"`eh vector vbase constructor iterator'\"; break;\n            case 'O': function_name = \"`copy constructor closure'\"; break;\n            case 'R':\n                sym->flags |= UNDNAME_NO_FUNCTION_RETURNS;\n                switch (*++sym->current)\n                {\n                case '0':\n                    {\n                        struct datatype_t       ct;\n                        struct array pmt;\n\n                        sym->current++;\n                        str_array_init(&pmt);\n                        demangle_datatype(sym, &ct, &pmt, FALSE);\n                        function_name = str_printf(sym, \"%s%s `RTTI Type Descriptor'\",\n                                                   ct.left, ct.right);\n                        sym->current--;\n                    }\n                    break;\n                case '1':\n                    {\n                        const char* n1, *n2, *n3, *n4;\n                        sym->current++;\n                        n1 = get_number(sym);\n                        n2 = get_number(sym);\n                        n3 = get_number(sym);\n                        n4 = get_number(sym);\n                        sym->current--;\n                        function_name = str_printf(sym, \"`RTTI Base Class Descriptor at (%s,%s,%s,%s)'\",\n                                                   n1, n2, n3, n4);\n                    }\n                    break;\n                case '2': function_name = \"`RTTI Base Class Array'\"; break;\n                case '3': function_name = \"`RTTI Class Hierarchy Descriptor'\"; break;\n                case '4': function_name = \"`RTTI Complete Object Locator'\"; break;\n                default:\n                    ERR(\"Unknown RTTI operator: _R%c\\n\", *sym->current);\n                    break;\n                }\n                break;\n            case 'S': function_name = \"`local vftable'\"; break;\n            case 'T': function_name = \"`local vftable constructor closure'\"; break;\n            case 'U': function_name = \"operator new[]\"; break;\n            case 'V': function_name = \"operator delete[]\"; break;\n            case 'X': function_name = \"`placement delete closure'\"; break;\n            case 'Y': function_name = \"`placement delete[] closure'\"; break;\n            default:\n                ERR(\"Unknown operator: _%c\\n\", *sym->current);\n                return FALSE;\n            }\n            break;\n        default:\n            /* FIXME: Other operators */\n            ERR(\"Unknown operator: %c\\n\", *sym->current);\n            return FALSE;\n        }\n        sym->current++;\n        switch (do_after)\n        {\n        case 1: case 2:\n            if (!str_array_push(sym, dashed_null, -1, &sym->stack))\n                return FALSE;\n            break;\n        case 4:\n            sym->result = (char*)function_name;\n            ret = TRUE;\n            goto done;\n        case 6:\n            {\n                char *args;\n                struct array array_pmt;\n\n                str_array_init(&array_pmt);\n                args = get_args(sym, &array_pmt, FALSE, '<', '>');\n                if (args != NULL) function_name = str_printf(sym, \"%s%s\", function_name, args);\n                sym->names.num = 0;\n            }\n            /* fall through */\n        default:\n            if (!str_array_push(sym, function_name, -1, &sym->stack))\n                return FALSE;\n            break;\n        }\n    }\n    else if (*sym->current == '$')\n    {\n        /* Strange construct, it's a name with a template argument list\n           and that's all. */\n        sym->current++;\n        ret = (sym->result = get_template_name(sym)) != NULL;\n        goto done;\n    }\n    else if (*sym->current == '?' && sym->current[1] == '$')\n        do_after = 5;\n\n    /* Either a class name, or '@' if the symbol is not a class member */\n    switch (*sym->current)\n    {\n    case '@': sym->current++; break;\n    case '$': break;\n    default:\n        /* Class the function is associated with, terminated by '@@' */\n        if (!get_class(sym)) goto done;\n        break;\n    }\n\n    switch (do_after)\n    {\n    case 0: default: break;\n    case 1: case 2:\n        /* it's time to set the member name for ctor & dtor */\n        if (sym->stack.num <= 1) goto done;\n        if (do_after == 1)\n            sym->stack.elts[0] = sym->stack.elts[1];\n        else\n            sym->stack.elts[0] = str_printf(sym, \"~%s\", sym->stack.elts[1]);\n        /* ctors and dtors don't have return type */\n        sym->flags |= UNDNAME_NO_FUNCTION_RETURNS;\n        break;\n    case 3:\n        sym->flags &= ~UNDNAME_NO_FUNCTION_RETURNS;\n        break;\n    case 5:\n        sym->names.start++;\n        break;\n    }\n\n    /* Function/Data type and access level */\n    if (*sym->current >= '0' && *sym->current <= '9')\n        ret = handle_data(sym);\n    else if ((*sym->current >= 'A' && *sym->current <= 'Z') || *sym->current == '$')\n        ret = handle_method(sym, do_after == 3);\n    else ret = FALSE;\ndone:\n    if (ret) assert(sym->result);\n    else WARN(\"Failed at %s\\n\", sym->current);\n\n    return ret;\n}\n\n/*********************************************************************\n *\t\t__unDNameEx (MSVCRT.@)\n *\n * Demangle a C++ identifier.\n *\n * PARAMS\n *  buffer   [O] If not NULL, the place to put the demangled string\n *  mangled  [I] Mangled name of the function\n *  buflen   [I] Length of buffer\n *  memget   [I] Function to allocate memory with\n *  memfree  [I] Function to free memory with\n *  unknown  [?] Unknown, possibly a call back\n *  flags    [I] Flags determining demangled format\n *\n * RETURNS\n *  Success: A string pointing to the unmangled name, allocated with memget.\n *  Failure: NULL.\n */\nchar* CDECL __unDNameEx(char* buffer, const char* mangled, int buflen,\n                        malloc_func_t memget, free_func_t memfree,\n                        void* unknown, unsigned short int flags)\n{\n    struct parsed_symbol        sym;\n    const char*                 result;\n\n    TRACE(\"(%p,%s,%d,%p,%p,%p,%x)\\n\",\n          buffer, mangled, buflen, memget, memfree, unknown, flags);\n    \n    /* The flags details is not documented by MS. However, it looks exactly\n     * like the UNDNAME_ manifest constants from imagehlp.h and dbghelp.h\n     * So, we copied those (on top of the file)\n     */\n    memset(&sym, 0, sizeof(struct parsed_symbol));\n    if (flags & UNDNAME_NAME_ONLY)\n        flags |= UNDNAME_NO_FUNCTION_RETURNS | UNDNAME_NO_ACCESS_SPECIFIERS |\n            UNDNAME_NO_MEMBER_TYPE | UNDNAME_NO_ALLOCATION_LANGUAGE |\n            UNDNAME_NO_COMPLEX_TYPE;\n\n    sym.flags         = flags;\n    sym.mem_alloc_ptr = memget;\n    sym.mem_free_ptr  = memfree;\n    sym.current       = mangled;\n    str_array_init( &sym.names );\n    str_array_init( &sym.stack );\n\n    result = symbol_demangle(&sym) ? sym.result : mangled;\n#ifndef UPSTREAM_CODE\n    if (result != mangled) {\n#endif\n    if (buffer && buflen)\n    {\n        lstrcpynA( buffer, result, buflen);\n    }\n    else\n    {\n        buffer = memget(strlen(result) + 1);\n        if (buffer) strcpy(buffer, result);\n    }\n#ifndef UPSTREAM_CODE\n    }\n#endif\n\n    und_free_all(&sym);\n\n    return buffer;\n}\n\n\n/*********************************************************************\n *\t\t__unDName (MSVCRT.@)\n */\nchar* CDECL __unDName(char* buffer, const char* mangled, int buflen,\n                      malloc_func_t memget, free_func_t memfree,\n                      unsigned short int flags)\n{\n    return __unDNameEx(buffer, mangled, buflen, memget, memfree, NULL, flags);\n}\n"
  },
  {
    "path": "third_party/llvm-demangle/README.md",
    "content": "copied from llvm master commit 77c5e43bd2babdfeaf60abc7dd37b3587a147c42"
  },
  {
    "path": "third_party/llvm-demangle/include/llvm/Demangle/Compiler.h",
    "content": "//===--- Compiler.h ---------------------------------------------*- C++ -*-===//\n//\n//                     The LLVM Compiler Infrastructure\n//\n// This file is distributed under the University of Illinois Open Source\n// License. See LICENSE.TXT for details.\n//\n//\n// This file contains a variety of feature test macros copied from\n// include/llvm/Support/Compiler.h so that LLVMDemangle does not need to take\n// a dependency on LLVMSupport.\n//===----------------------------------------------------------------------===//\n\n#ifndef LLVM_DEMANGLE_COMPILER_H\n#define LLVM_DEMANGLE_COMPILER_H\n\n#ifdef _MSC_VER\n// snprintf is implemented in VS 2015\n#if _MSC_VER < 1900\n#define snprintf _snprintf_s\n#endif\n#endif\n\n#ifndef __has_feature\n#define __has_feature(x) 0\n#endif\n\n#ifndef __has_cpp_attribute\n#define __has_cpp_attribute(x) 0\n#endif\n\n#ifndef __has_attribute\n#define __has_attribute(x) 0\n#endif\n\n#ifndef __has_builtin\n#define __has_builtin(x) 0\n#endif\n\n#ifndef LLVM_GNUC_PREREQ\n#if defined(__GNUC__) && defined(__GNUC_MINOR__) && defined(__GNUC_PATCHLEVEL__)\n#define LLVM_GNUC_PREREQ(maj, min, patch)                                      \\\n  ((__GNUC__ << 20) + (__GNUC_MINOR__ << 10) + __GNUC_PATCHLEVEL__ >=          \\\n   ((maj) << 20) + ((min) << 10) + (patch))\n#elif defined(__GNUC__) && defined(__GNUC_MINOR__)\n#define LLVM_GNUC_PREREQ(maj, min, patch)                                      \\\n  ((__GNUC__ << 20) + (__GNUC_MINOR__ << 10) >= ((maj) << 20) + ((min) << 10))\n#else\n#define LLVM_GNUC_PREREQ(maj, min, patch) 0\n#endif\n#endif\n\n#if __has_attribute(used) || LLVM_GNUC_PREREQ(3, 1, 0)\n#define LLVM_ATTRIBUTE_USED __attribute__((__used__))\n#else\n#define LLVM_ATTRIBUTE_USED\n#endif\n\n#if __has_builtin(__builtin_unreachable) || LLVM_GNUC_PREREQ(4, 5, 0)\n#define LLVM_BUILTIN_UNREACHABLE __builtin_unreachable()\n#elif defined(_MSC_VER)\n#define LLVM_BUILTIN_UNREACHABLE __assume(false)\n#endif\n\n#if __has_attribute(noinline) || LLVM_GNUC_PREREQ(3, 4, 0)\n#define LLVM_ATTRIBUTE_NOINLINE __attribute__((noinline))\n#elif defined(_MSC_VER)\n#define LLVM_ATTRIBUTE_NOINLINE __declspec(noinline)\n#else\n#define LLVM_ATTRIBUTE_NOINLINE\n#endif\n\n#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)\n#define LLVM_DUMP_METHOD LLVM_ATTRIBUTE_NOINLINE LLVM_ATTRIBUTE_USED\n#else\n#define LLVM_DUMP_METHOD LLVM_ATTRIBUTE_NOINLINE\n#endif\n\n#if __cplusplus > 201402L && __has_cpp_attribute(fallthrough)\n#define LLVM_FALLTHROUGH [[fallthrough]]\n#elif __has_cpp_attribute(gnu::fallthrough)\n#define LLVM_FALLTHROUGH [[gnu::fallthrough]]\n#elif !__cplusplus\n// Workaround for llvm.org/PR23435, since clang 3.6 and below emit a spurious\n// error when __has_cpp_attribute is given a scoped attribute in C mode.\n#define LLVM_FALLTHROUGH\n#elif __has_cpp_attribute(clang::fallthrough)\n#define LLVM_FALLTHROUGH [[clang::fallthrough]]\n#else\n#define LLVM_FALLTHROUGH\n#endif\n\n#endif\n"
  },
  {
    "path": "third_party/llvm-demangle/include/llvm/Demangle/Demangle.h",
    "content": "//===--- Demangle.h ---------------------------------------------*- C++ -*-===//\n//\n//                     The LLVM Compiler Infrastructure\n//\n// This file is distributed under the University of Illinois Open Source\n// License. See LICENSE.TXT for details.\n//\n//===----------------------------------------------------------------------===//\n\n#ifndef LLVM_DEMANGLE_DEMANGLE_H\n#define LLVM_DEMANGLE_DEMANGLE_H\n\n#include <cstddef>\n\nnamespace llvm {\n/// This is a llvm local version of __cxa_demangle. Other than the name and\n/// being in the llvm namespace it is identical.\n///\n/// The mangled_name is demangled into buf and returned. If the buffer is not\n/// large enough, realloc is used to expand it.\n///\n/// The *status will be set to a value from the following enumeration\nenum : int {\n  demangle_unknown_error = -4,\n  demangle_invalid_args = -3,\n  demangle_invalid_mangled_name = -2,\n  demangle_memory_alloc_failure = -1,\n  demangle_success = 0,\n};\n\nchar *itaniumDemangle(const char *mangled_name, char *buf, size_t *n,\n                      int *status);\n\n/// Calls the callback \\c Callback with \\c Ctx as an argument whenever a type is\n/// encountered. Returns true if \\c MangledName couldn't be parsed.\nbool itaniumFindTypesInMangledName(const char *MangledName, void *Ctx,\n                                   void (*Callback)(void *, const char *));\n\n\nenum MSDemangleFlags { MSDF_None = 0, MSDF_DumpBackrefs = 1 << 0 };\nchar *microsoftDemangle(const char *mangled_name, char *buf, size_t *n,\n                        int *status, MSDemangleFlags Flags = MSDF_None);\n\n/// \"Partial\" demangler. This supports demangling a string into an AST\n/// (typically an intermediate stage in itaniumDemangle) and querying certain\n/// properties or partially printing the demangled name.\nstruct ItaniumPartialDemangler {\n  ItaniumPartialDemangler();\n\n  ItaniumPartialDemangler(ItaniumPartialDemangler &&Other);\n  ItaniumPartialDemangler &operator=(ItaniumPartialDemangler &&Other);\n\n  /// Demangle into an AST. Subsequent calls to the rest of the member functions\n  /// implicitly operate on the AST this produces.\n  /// \\return true on error, false otherwise\n  bool partialDemangle(const char *MangledName);\n\n  /// Just print the entire mangled name into Buf. Buf and N behave like the\n  /// second and third parameters to itaniumDemangle.\n  char *finishDemangle(char *Buf, size_t *N) const;\n\n  /// Get the base name of a function. This doesn't include trailing template\n  /// arguments, ie for \"a::b<int>\" this function returns \"b\".\n  char *getFunctionBaseName(char *Buf, size_t *N) const;\n\n  /// Get the context name for a function. For \"a::b::c\", this function returns\n  /// \"a::b\".\n  char *getFunctionDeclContextName(char *Buf, size_t *N) const;\n\n  /// Get the entire name of this function.\n  char *getFunctionName(char *Buf, size_t *N) const;\n\n  /// Get the parameters for this function.\n  char *getFunctionParameters(char *Buf, size_t *N) const;\n  char *getFunctionReturnType(char *Buf, size_t *N) const;\n\n  /// If this function has any any cv or reference qualifiers. These imply that\n  /// the function is a non-static member function.\n  bool hasFunctionQualifiers() const;\n\n  /// If this symbol describes a constructor or destructor.\n  bool isCtorOrDtor() const;\n\n  /// If this symbol describes a function.\n  bool isFunction() const;\n\n  /// If this symbol describes a variable.\n  bool isData() const;\n\n  /// If this symbol is a <special-name>. These are generally implicitly\n  /// generated by the implementation, such as vtables and typeinfo names.\n  bool isSpecialName() const;\n\n  ~ItaniumPartialDemangler();\nprivate:\n  void *RootNode;\n  void *Context;\n};\n} // namespace llvm\n\n#endif\n"
  },
  {
    "path": "third_party/llvm-demangle/include/llvm/Demangle/ItaniumDemangle.h",
    "content": "//===------------------------- ItaniumDemangle.h ----------------*- C++ -*-===//\n//\n//                     The LLVM Compiler Infrastructure\n//\n// This file is dual licensed under the MIT and the University of Illinois Open\n// Source Licenses. See LICENSE.TXT for details.\n//\n//===----------------------------------------------------------------------===//\n\n#ifndef LLVM_DEMANGLE_ITANIUMDEMANGLE_H\n#define LLVM_DEMANGLE_ITANIUMDEMANGLE_H\n\n// FIXME: (possibly) incomplete list of features that clang mangles that this\n// file does not yet support:\n//   - C++ modules TS\n\n#include \"llvm/Demangle/Compiler.h\"\n#include \"llvm/Demangle/StringView.h\"\n#include \"llvm/Demangle/Utility.h\"\n\n#include <cassert>\n#include <cctype>\n#include <cstdio>\n#include <cstdlib>\n#include <cstring>\n#include <numeric>\n#include <utility>\n\n#define FOR_EACH_NODE_KIND(X) \\\n    X(NodeArrayNode) \\\n    X(DotSuffix) \\\n    X(VendorExtQualType) \\\n    X(QualType) \\\n    X(ConversionOperatorType) \\\n    X(PostfixQualifiedType) \\\n    X(ElaboratedTypeSpefType) \\\n    X(NameType) \\\n    X(AbiTagAttr) \\\n    X(EnableIfAttr) \\\n    X(ObjCProtoName) \\\n    X(PointerType) \\\n    X(ReferenceType) \\\n    X(PointerToMemberType) \\\n    X(ArrayType) \\\n    X(FunctionType) \\\n    X(NoexceptSpec) \\\n    X(DynamicExceptionSpec) \\\n    X(FunctionEncoding) \\\n    X(LiteralOperator) \\\n    X(SpecialName) \\\n    X(CtorVtableSpecialName) \\\n    X(QualifiedName) \\\n    X(NestedName) \\\n    X(LocalName) \\\n    X(VectorType) \\\n    X(PixelVectorType) \\\n    X(ParameterPack) \\\n    X(TemplateArgumentPack) \\\n    X(ParameterPackExpansion) \\\n    X(TemplateArgs) \\\n    X(ForwardTemplateReference) \\\n    X(NameWithTemplateArgs) \\\n    X(GlobalQualifiedName) \\\n    X(StdQualifiedName) \\\n    X(ExpandedSpecialSubstitution) \\\n    X(SpecialSubstitution) \\\n    X(CtorDtorName) \\\n    X(DtorName) \\\n    X(UnnamedTypeName) \\\n    X(ClosureTypeName) \\\n    X(StructuredBindingName) \\\n    X(BinaryExpr) \\\n    X(ArraySubscriptExpr) \\\n    X(PostfixExpr) \\\n    X(ConditionalExpr) \\\n    X(MemberExpr) \\\n    X(EnclosingExpr) \\\n    X(CastExpr) \\\n    X(SizeofParamPackExpr) \\\n    X(CallExpr) \\\n    X(NewExpr) \\\n    X(DeleteExpr) \\\n    X(PrefixExpr) \\\n    X(FunctionParam) \\\n    X(ConversionExpr) \\\n    X(InitListExpr) \\\n    X(FoldExpr) \\\n    X(ThrowExpr) \\\n    X(BoolExpr) \\\n    X(IntegerCastExpr) \\\n    X(IntegerLiteral) \\\n    X(FloatLiteral) \\\n    X(DoubleLiteral) \\\n    X(LongDoubleLiteral) \\\n    X(BracedExpr) \\\n    X(BracedRangeExpr)\n\nnamespace llvm {\nnamespace itanium_demangle {\n// Base class of all AST nodes. The AST is built by the parser, then is\n// traversed by the printLeft/Right functions to produce a demangled string.\nclass Node {\npublic:\n  enum Kind : unsigned char {\n#define ENUMERATOR(NodeKind) K ## NodeKind,\n    FOR_EACH_NODE_KIND(ENUMERATOR)\n#undef ENUMERATOR\n  };\n\n  /// Three-way bool to track a cached value. Unknown is possible if this node\n  /// has an unexpanded parameter pack below it that may affect this cache.\n  enum class Cache : unsigned char { Yes, No, Unknown, };\n\nprivate:\n  Kind K;\n\n  // FIXME: Make these protected.\npublic:\n  /// Tracks if this node has a component on its right side, in which case we\n  /// need to call printRight.\n  Cache RHSComponentCache;\n\n  /// Track if this node is a (possibly qualified) array type. This can affect\n  /// how we format the output string.\n  Cache ArrayCache;\n\n  /// Track if this node is a (possibly qualified) function type. This can\n  /// affect how we format the output string.\n  Cache FunctionCache;\n\npublic:\n  Node(Kind K_, Cache RHSComponentCache_ = Cache::No,\n       Cache ArrayCache_ = Cache::No, Cache FunctionCache_ = Cache::No)\n      : K(K_), RHSComponentCache(RHSComponentCache_), ArrayCache(ArrayCache_),\n        FunctionCache(FunctionCache_) {}\n\n  /// Visit the most-derived object corresponding to this object.\n  template<typename Fn> void visit(Fn F) const;\n\n  // The following function is provided by all derived classes:\n  //\n  // Call F with arguments that, when passed to the constructor of this node,\n  // would construct an equivalent node.\n  //template<typename Fn> void match(Fn F) const;\n\n  bool hasRHSComponent(OutputStream &S) const {\n    if (RHSComponentCache != Cache::Unknown)\n      return RHSComponentCache == Cache::Yes;\n    return hasRHSComponentSlow(S);\n  }\n\n  bool hasArray(OutputStream &S) const {\n    if (ArrayCache != Cache::Unknown)\n      return ArrayCache == Cache::Yes;\n    return hasArraySlow(S);\n  }\n\n  bool hasFunction(OutputStream &S) const {\n    if (FunctionCache != Cache::Unknown)\n      return FunctionCache == Cache::Yes;\n    return hasFunctionSlow(S);\n  }\n\n  Kind getKind() const { return K; }\n\n  virtual bool hasRHSComponentSlow(OutputStream &) const { return false; }\n  virtual bool hasArraySlow(OutputStream &) const { return false; }\n  virtual bool hasFunctionSlow(OutputStream &) const { return false; }\n\n  // Dig through \"glue\" nodes like ParameterPack and ForwardTemplateReference to\n  // get at a node that actually represents some concrete syntax.\n  virtual const Node *getSyntaxNode(OutputStream &) const {\n    return this;\n  }\n\n  void print(OutputStream &S) const {\n    printLeft(S);\n    if (RHSComponentCache != Cache::No)\n      printRight(S);\n  }\n\n  // Print the \"left\" side of this Node into OutputStream.\n  virtual void printLeft(OutputStream &) const = 0;\n\n  // Print the \"right\". This distinction is necessary to represent C++ types\n  // that appear on the RHS of their subtype, such as arrays or functions.\n  // Since most types don't have such a component, provide a default\n  // implementation.\n  virtual void printRight(OutputStream &) const {}\n\n  virtual StringView getBaseName() const { return StringView(); }\n\n  // Silence compiler warnings, this dtor will never be called.\n  virtual ~Node() = default;\n\n#ifndef NDEBUG\n  LLVM_DUMP_METHOD void dump() const;\n#endif\n};\n\nclass NodeArray {\n  Node **Elements;\n  size_t NumElements;\n\npublic:\n  NodeArray() : Elements(nullptr), NumElements(0) {}\n  NodeArray(Node **Elements_, size_t NumElements_)\n      : Elements(Elements_), NumElements(NumElements_) {}\n\n  bool empty() const { return NumElements == 0; }\n  size_t size() const { return NumElements; }\n\n  Node **begin() const { return Elements; }\n  Node **end() const { return Elements + NumElements; }\n\n  Node *operator[](size_t Idx) const { return Elements[Idx]; }\n\n  void printWithComma(OutputStream &S) const {\n    bool FirstElement = true;\n    for (size_t Idx = 0; Idx != NumElements; ++Idx) {\n      size_t BeforeComma = S.getCurrentPosition();\n      if (!FirstElement)\n        S += \", \";\n      size_t AfterComma = S.getCurrentPosition();\n      Elements[Idx]->print(S);\n\n      // Elements[Idx] is an empty parameter pack expansion, we should erase the\n      // comma we just printed.\n      if (AfterComma == S.getCurrentPosition()) {\n        S.setCurrentPosition(BeforeComma);\n        continue;\n      }\n\n      FirstElement = false;\n    }\n  }\n};\n\nstruct NodeArrayNode : Node {\n  NodeArray Array;\n  NodeArrayNode(NodeArray Array_) : Node(KNodeArrayNode), Array(Array_) {}\n\n  template<typename Fn> void match(Fn F) const { F(Array); }\n\n  void printLeft(OutputStream &S) const override {\n    Array.printWithComma(S);\n  }\n};\n\nclass DotSuffix final : public Node {\n  const Node *Prefix;\n  const StringView Suffix;\n\npublic:\n  DotSuffix(const Node *Prefix_, StringView Suffix_)\n      : Node(KDotSuffix), Prefix(Prefix_), Suffix(Suffix_) {}\n\n  template<typename Fn> void match(Fn F) const { F(Prefix, Suffix); }\n\n  void printLeft(OutputStream &s) const override {\n    Prefix->print(s);\n    s += \" (\";\n    s += Suffix;\n    s += \")\";\n  }\n};\n\nclass VendorExtQualType final : public Node {\n  const Node *Ty;\n  StringView Ext;\n\npublic:\n  VendorExtQualType(const Node *Ty_, StringView Ext_)\n      : Node(KVendorExtQualType), Ty(Ty_), Ext(Ext_) {}\n\n  template<typename Fn> void match(Fn F) const { F(Ty, Ext); }\n\n  void printLeft(OutputStream &S) const override {\n    Ty->print(S);\n    S += \" \";\n    S += Ext;\n  }\n};\n\nenum FunctionRefQual : unsigned char {\n  FrefQualNone,\n  FrefQualLValue,\n  FrefQualRValue,\n};\n\nenum Qualifiers {\n  QualNone = 0,\n  QualConst = 0x1,\n  QualVolatile = 0x2,\n  QualRestrict = 0x4,\n};\n\ninline Qualifiers operator|=(Qualifiers &Q1, Qualifiers Q2) {\n  return Q1 = static_cast<Qualifiers>(Q1 | Q2);\n}\n\nclass QualType : public Node {\nprotected:\n  const Qualifiers Quals;\n  const Node *Child;\n\n  void printQuals(OutputStream &S) const {\n    if (Quals & QualConst)\n      S += \" const\";\n    if (Quals & QualVolatile)\n      S += \" volatile\";\n    if (Quals & QualRestrict)\n      S += \" restrict\";\n  }\n\npublic:\n  QualType(const Node *Child_, Qualifiers Quals_)\n      : Node(KQualType, Child_->RHSComponentCache,\n             Child_->ArrayCache, Child_->FunctionCache),\n        Quals(Quals_), Child(Child_) {}\n\n  template<typename Fn> void match(Fn F) const { F(Child, Quals); }\n\n  bool hasRHSComponentSlow(OutputStream &S) const override {\n    return Child->hasRHSComponent(S);\n  }\n  bool hasArraySlow(OutputStream &S) const override {\n    return Child->hasArray(S);\n  }\n  bool hasFunctionSlow(OutputStream &S) const override {\n    return Child->hasFunction(S);\n  }\n\n  void printLeft(OutputStream &S) const override {\n    Child->printLeft(S);\n    printQuals(S);\n  }\n\n  void printRight(OutputStream &S) const override { Child->printRight(S); }\n};\n\nclass ConversionOperatorType final : public Node {\n  const Node *Ty;\n\npublic:\n  ConversionOperatorType(const Node *Ty_)\n      : Node(KConversionOperatorType), Ty(Ty_) {}\n\n  template<typename Fn> void match(Fn F) const { F(Ty); }\n\n  void printLeft(OutputStream &S) const override {\n    S += \"operator \";\n    Ty->print(S);\n  }\n};\n\nclass PostfixQualifiedType final : public Node {\n  const Node *Ty;\n  const StringView Postfix;\n\npublic:\n  PostfixQualifiedType(Node *Ty_, StringView Postfix_)\n      : Node(KPostfixQualifiedType), Ty(Ty_), Postfix(Postfix_) {}\n\n  template<typename Fn> void match(Fn F) const { F(Ty, Postfix); }\n\n  void printLeft(OutputStream &s) const override {\n    Ty->printLeft(s);\n    s += Postfix;\n  }\n};\n\nclass NameType final : public Node {\n  const StringView Name;\n\npublic:\n  NameType(StringView Name_) : Node(KNameType), Name(Name_) {}\n\n  template<typename Fn> void match(Fn F) const { F(Name); }\n\n  StringView getName() const { return Name; }\n  StringView getBaseName() const override { return Name; }\n\n  void printLeft(OutputStream &s) const override { s += Name; }\n};\n\nclass ElaboratedTypeSpefType : public Node {\n  StringView Kind;\n  Node *Child;\npublic:\n  ElaboratedTypeSpefType(StringView Kind_, Node *Child_)\n      : Node(KElaboratedTypeSpefType), Kind(Kind_), Child(Child_) {}\n\n  template<typename Fn> void match(Fn F) const { F(Kind, Child); }\n\n  void printLeft(OutputStream &S) const override {\n    S += Kind;\n    S += ' ';\n    Child->print(S);\n  }\n};\n\nstruct AbiTagAttr : Node {\n  Node *Base;\n  StringView Tag;\n\n  AbiTagAttr(Node* Base_, StringView Tag_)\n      : Node(KAbiTagAttr, Base_->RHSComponentCache,\n             Base_->ArrayCache, Base_->FunctionCache),\n        Base(Base_), Tag(Tag_) {}\n\n  template<typename Fn> void match(Fn F) const { F(Base, Tag); }\n\n  void printLeft(OutputStream &S) const override {\n    Base->printLeft(S);\n    S += \"[abi:\";\n    S += Tag;\n    S += \"]\";\n  }\n};\n\nclass EnableIfAttr : public Node {\n  NodeArray Conditions;\npublic:\n  EnableIfAttr(NodeArray Conditions_)\n      : Node(KEnableIfAttr), Conditions(Conditions_) {}\n\n  template<typename Fn> void match(Fn F) const { F(Conditions); }\n\n  void printLeft(OutputStream &S) const override {\n    S += \" [enable_if:\";\n    Conditions.printWithComma(S);\n    S += ']';\n  }\n};\n\nclass ObjCProtoName : public Node {\n  const Node *Ty;\n  StringView Protocol;\n\n  friend class PointerType;\n\npublic:\n  ObjCProtoName(const Node *Ty_, StringView Protocol_)\n      : Node(KObjCProtoName), Ty(Ty_), Protocol(Protocol_) {}\n\n  template<typename Fn> void match(Fn F) const { F(Ty, Protocol); }\n\n  bool isObjCObject() const {\n    return Ty->getKind() == KNameType &&\n           static_cast<const NameType *>(Ty)->getName() == \"objc_object\";\n  }\n\n  void printLeft(OutputStream &S) const override {\n    Ty->print(S);\n    S += \"<\";\n    S += Protocol;\n    S += \">\";\n  }\n};\n\nclass PointerType final : public Node {\n  const Node *Pointee;\n\npublic:\n  PointerType(const Node *Pointee_)\n      : Node(KPointerType, Pointee_->RHSComponentCache),\n        Pointee(Pointee_) {}\n\n  template<typename Fn> void match(Fn F) const { F(Pointee); }\n\n  bool hasRHSComponentSlow(OutputStream &S) const override {\n    return Pointee->hasRHSComponent(S);\n  }\n\n  void printLeft(OutputStream &s) const override {\n    // We rewrite objc_object<SomeProtocol>* into id<SomeProtocol>.\n    if (Pointee->getKind() != KObjCProtoName ||\n        !static_cast<const ObjCProtoName *>(Pointee)->isObjCObject()) {\n      Pointee->printLeft(s);\n      if (Pointee->hasArray(s))\n        s += \" \";\n      if (Pointee->hasArray(s) || Pointee->hasFunction(s))\n        s += \"(\";\n      s += \"*\";\n    } else {\n      const auto *objcProto = static_cast<const ObjCProtoName *>(Pointee);\n      s += \"id<\";\n      s += objcProto->Protocol;\n      s += \">\";\n    }\n  }\n\n  void printRight(OutputStream &s) const override {\n    if (Pointee->getKind() != KObjCProtoName ||\n        !static_cast<const ObjCProtoName *>(Pointee)->isObjCObject()) {\n      if (Pointee->hasArray(s) || Pointee->hasFunction(s))\n        s += \")\";\n      Pointee->printRight(s);\n    }\n  }\n};\n\nenum class ReferenceKind {\n  LValue,\n  RValue,\n};\n\n// Represents either a LValue or an RValue reference type.\nclass ReferenceType : public Node {\n  const Node *Pointee;\n  ReferenceKind RK;\n\n  mutable bool Printing = false;\n\n  // Dig through any refs to refs, collapsing the ReferenceTypes as we go. The\n  // rule here is rvalue ref to rvalue ref collapses to a rvalue ref, and any\n  // other combination collapses to a lvalue ref.\n  std::pair<ReferenceKind, const Node *> collapse(OutputStream &S) const {\n    auto SoFar = std::make_pair(RK, Pointee);\n    for (;;) {\n      const Node *SN = SoFar.second->getSyntaxNode(S);\n      if (SN->getKind() != KReferenceType)\n        break;\n      auto *RT = static_cast<const ReferenceType *>(SN);\n      SoFar.second = RT->Pointee;\n      SoFar.first = std::min(SoFar.first, RT->RK);\n    }\n    return SoFar;\n  }\n\npublic:\n  ReferenceType(const Node *Pointee_, ReferenceKind RK_)\n      : Node(KReferenceType, Pointee_->RHSComponentCache),\n        Pointee(Pointee_), RK(RK_) {}\n\n  template<typename Fn> void match(Fn F) const { F(Pointee, RK); }\n\n  bool hasRHSComponentSlow(OutputStream &S) const override {\n    return Pointee->hasRHSComponent(S);\n  }\n\n  void printLeft(OutputStream &s) const override {\n    if (Printing)\n      return;\n    SwapAndRestore<bool> SavePrinting(Printing, true);\n    std::pair<ReferenceKind, const Node *> Collapsed = collapse(s);\n    Collapsed.second->printLeft(s);\n    if (Collapsed.second->hasArray(s))\n      s += \" \";\n    if (Collapsed.second->hasArray(s) || Collapsed.second->hasFunction(s))\n      s += \"(\";\n\n    s += (Collapsed.first == ReferenceKind::LValue ? \"&\" : \"&&\");\n  }\n  void printRight(OutputStream &s) const override {\n    if (Printing)\n      return;\n    SwapAndRestore<bool> SavePrinting(Printing, true);\n    std::pair<ReferenceKind, const Node *> Collapsed = collapse(s);\n    if (Collapsed.second->hasArray(s) || Collapsed.second->hasFunction(s))\n      s += \")\";\n    Collapsed.second->printRight(s);\n  }\n};\n\nclass PointerToMemberType final : public Node {\n  const Node *ClassType;\n  const Node *MemberType;\n\npublic:\n  PointerToMemberType(const Node *ClassType_, const Node *MemberType_)\n      : Node(KPointerToMemberType, MemberType_->RHSComponentCache),\n        ClassType(ClassType_), MemberType(MemberType_) {}\n\n  template<typename Fn> void match(Fn F) const { F(ClassType, MemberType); }\n\n  bool hasRHSComponentSlow(OutputStream &S) const override {\n    return MemberType->hasRHSComponent(S);\n  }\n\n  void printLeft(OutputStream &s) const override {\n    MemberType->printLeft(s);\n    if (MemberType->hasArray(s) || MemberType->hasFunction(s))\n      s += \"(\";\n    else\n      s += \" \";\n    ClassType->print(s);\n    s += \"::*\";\n  }\n\n  void printRight(OutputStream &s) const override {\n    if (MemberType->hasArray(s) || MemberType->hasFunction(s))\n      s += \")\";\n    MemberType->printRight(s);\n  }\n};\n\nclass NodeOrString {\n  const void *First;\n  const void *Second;\n\npublic:\n  /* implicit */ NodeOrString(StringView Str) {\n    const char *FirstChar = Str.begin();\n    const char *SecondChar = Str.end();\n    if (SecondChar == nullptr) {\n      assert(FirstChar == SecondChar);\n      ++FirstChar, ++SecondChar;\n    }\n    First = static_cast<const void *>(FirstChar);\n    Second = static_cast<const void *>(SecondChar);\n  }\n\n  /* implicit */ NodeOrString(Node *N)\n      : First(static_cast<const void *>(N)), Second(nullptr) {}\n  NodeOrString() : First(nullptr), Second(nullptr) {}\n\n  bool isString() const { return Second && First; }\n  bool isNode() const { return First && !Second; }\n  bool isEmpty() const { return !First && !Second; }\n\n  StringView asString() const {\n    assert(isString());\n    return StringView(static_cast<const char *>(First),\n                      static_cast<const char *>(Second));\n  }\n\n  const Node *asNode() const {\n    assert(isNode());\n    return static_cast<const Node *>(First);\n  }\n};\n\nclass ArrayType final : public Node {\n  const Node *Base;\n  NodeOrString Dimension;\n\npublic:\n  ArrayType(const Node *Base_, NodeOrString Dimension_)\n      : Node(KArrayType,\n             /*RHSComponentCache=*/Cache::Yes,\n             /*ArrayCache=*/Cache::Yes),\n        Base(Base_), Dimension(Dimension_) {}\n\n  template<typename Fn> void match(Fn F) const { F(Base, Dimension); }\n\n  bool hasRHSComponentSlow(OutputStream &) const override { return true; }\n  bool hasArraySlow(OutputStream &) const override { return true; }\n\n  void printLeft(OutputStream &S) const override { Base->printLeft(S); }\n\n  void printRight(OutputStream &S) const override {\n    if (S.back() != ']')\n      S += \" \";\n    S += \"[\";\n    if (Dimension.isString())\n      S += Dimension.asString();\n    else if (Dimension.isNode())\n      Dimension.asNode()->print(S);\n    S += \"]\";\n    Base->printRight(S);\n  }\n};\n\nclass FunctionType final : public Node {\n  const Node *Ret;\n  NodeArray Params;\n  Qualifiers CVQuals;\n  FunctionRefQual RefQual;\n  const Node *ExceptionSpec;\n\npublic:\n  FunctionType(const Node *Ret_, NodeArray Params_, Qualifiers CVQuals_,\n               FunctionRefQual RefQual_, const Node *ExceptionSpec_)\n      : Node(KFunctionType,\n             /*RHSComponentCache=*/Cache::Yes, /*ArrayCache=*/Cache::No,\n             /*FunctionCache=*/Cache::Yes),\n        Ret(Ret_), Params(Params_), CVQuals(CVQuals_), RefQual(RefQual_),\n        ExceptionSpec(ExceptionSpec_) {}\n\n  template<typename Fn> void match(Fn F) const {\n    F(Ret, Params, CVQuals, RefQual, ExceptionSpec);\n  }\n\n  bool hasRHSComponentSlow(OutputStream &) const override { return true; }\n  bool hasFunctionSlow(OutputStream &) const override { return true; }\n\n  // Handle C++'s ... quirky decl grammar by using the left & right\n  // distinction. Consider:\n  //   int (*f(float))(char) {}\n  // f is a function that takes a float and returns a pointer to a function\n  // that takes a char and returns an int. If we're trying to print f, start\n  // by printing out the return types's left, then print our parameters, then\n  // finally print right of the return type.\n  void printLeft(OutputStream &S) const override {\n    Ret->printLeft(S);\n    S += \" \";\n  }\n\n  void printRight(OutputStream &S) const override {\n    S += \"(\";\n    Params.printWithComma(S);\n    S += \")\";\n    Ret->printRight(S);\n\n    if (CVQuals & QualConst)\n      S += \" const\";\n    if (CVQuals & QualVolatile)\n      S += \" volatile\";\n    if (CVQuals & QualRestrict)\n      S += \" restrict\";\n\n    if (RefQual == FrefQualLValue)\n      S += \" &\";\n    else if (RefQual == FrefQualRValue)\n      S += \" &&\";\n\n    if (ExceptionSpec != nullptr) {\n      S += ' ';\n      ExceptionSpec->print(S);\n    }\n  }\n};\n\nclass NoexceptSpec : public Node {\n  const Node *E;\npublic:\n  NoexceptSpec(const Node *E_) : Node(KNoexceptSpec), E(E_) {}\n\n  template<typename Fn> void match(Fn F) const { F(E); }\n\n  void printLeft(OutputStream &S) const override {\n    S += \"noexcept(\";\n    E->print(S);\n    S += \")\";\n  }\n};\n\nclass DynamicExceptionSpec : public Node {\n  NodeArray Types;\npublic:\n  DynamicExceptionSpec(NodeArray Types_)\n      : Node(KDynamicExceptionSpec), Types(Types_) {}\n\n  template<typename Fn> void match(Fn F) const { F(Types); }\n\n  void printLeft(OutputStream &S) const override {\n    S += \"throw(\";\n    Types.printWithComma(S);\n    S += ')';\n  }\n};\n\nclass FunctionEncoding final : public Node {\n  const Node *Ret;\n  const Node *Name;\n  NodeArray Params;\n  const Node *Attrs;\n  Qualifiers CVQuals;\n  FunctionRefQual RefQual;\n\npublic:\n  FunctionEncoding(const Node *Ret_, const Node *Name_, NodeArray Params_,\n                   const Node *Attrs_, Qualifiers CVQuals_,\n                   FunctionRefQual RefQual_)\n      : Node(KFunctionEncoding,\n             /*RHSComponentCache=*/Cache::Yes, /*ArrayCache=*/Cache::No,\n             /*FunctionCache=*/Cache::Yes),\n        Ret(Ret_), Name(Name_), Params(Params_), Attrs(Attrs_),\n        CVQuals(CVQuals_), RefQual(RefQual_) {}\n\n  template<typename Fn> void match(Fn F) const {\n    F(Ret, Name, Params, Attrs, CVQuals, RefQual);\n  }\n\n  Qualifiers getCVQuals() const { return CVQuals; }\n  FunctionRefQual getRefQual() const { return RefQual; }\n  NodeArray getParams() const { return Params; }\n  const Node *getReturnType() const { return Ret; }\n\n  bool hasRHSComponentSlow(OutputStream &) const override { return true; }\n  bool hasFunctionSlow(OutputStream &) const override { return true; }\n\n  const Node *getName() const { return Name; }\n\n  void printLeft(OutputStream &S) const override {\n    if (Ret) {\n      Ret->printLeft(S);\n      if (!Ret->hasRHSComponent(S))\n        S += \" \";\n    }\n    Name->print(S);\n  }\n\n  void printRight(OutputStream &S) const override {\n    S += \"(\";\n    Params.printWithComma(S);\n    S += \")\";\n    if (Ret)\n      Ret->printRight(S);\n\n    if (CVQuals & QualConst)\n      S += \" const\";\n    if (CVQuals & QualVolatile)\n      S += \" volatile\";\n    if (CVQuals & QualRestrict)\n      S += \" restrict\";\n\n    if (RefQual == FrefQualLValue)\n      S += \" &\";\n    else if (RefQual == FrefQualRValue)\n      S += \" &&\";\n\n    if (Attrs != nullptr)\n      Attrs->print(S);\n  }\n};\n\nclass LiteralOperator : public Node {\n  const Node *OpName;\n\npublic:\n  LiteralOperator(const Node *OpName_)\n      : Node(KLiteralOperator), OpName(OpName_) {}\n\n  template<typename Fn> void match(Fn F) const { F(OpName); }\n\n  void printLeft(OutputStream &S) const override {\n    S += \"operator\\\"\\\" \";\n    OpName->print(S);\n  }\n};\n\nclass SpecialName final : public Node {\n  const StringView Special;\n  const Node *Child;\n\npublic:\n  SpecialName(StringView Special_, const Node *Child_)\n      : Node(KSpecialName), Special(Special_), Child(Child_) {}\n\n  template<typename Fn> void match(Fn F) const { F(Special, Child); }\n\n  void printLeft(OutputStream &S) const override {\n    S += Special;\n    Child->print(S);\n  }\n};\n\nclass CtorVtableSpecialName final : public Node {\n  const Node *FirstType;\n  const Node *SecondType;\n\npublic:\n  CtorVtableSpecialName(const Node *FirstType_, const Node *SecondType_)\n      : Node(KCtorVtableSpecialName),\n        FirstType(FirstType_), SecondType(SecondType_) {}\n\n  template<typename Fn> void match(Fn F) const { F(FirstType, SecondType); }\n\n  void printLeft(OutputStream &S) const override {\n    S += \"construction vtable for \";\n    FirstType->print(S);\n    S += \"-in-\";\n    SecondType->print(S);\n  }\n};\n\nstruct NestedName : Node {\n  Node *Qual;\n  Node *Name;\n\n  NestedName(Node *Qual_, Node *Name_)\n      : Node(KNestedName), Qual(Qual_), Name(Name_) {}\n\n  template<typename Fn> void match(Fn F) const { F(Qual, Name); }\n\n  StringView getBaseName() const override { return Name->getBaseName(); }\n\n  void printLeft(OutputStream &S) const override {\n    Qual->print(S);\n    S += \"::\";\n    Name->print(S);\n  }\n};\n\nstruct LocalName : Node {\n  Node *Encoding;\n  Node *Entity;\n\n  LocalName(Node *Encoding_, Node *Entity_)\n      : Node(KLocalName), Encoding(Encoding_), Entity(Entity_) {}\n\n  template<typename Fn> void match(Fn F) const { F(Encoding, Entity); }\n\n  void printLeft(OutputStream &S) const override {\n    Encoding->print(S);\n    S += \"::\";\n    Entity->print(S);\n  }\n};\n\nclass QualifiedName final : public Node {\n  // qualifier::name\n  const Node *Qualifier;\n  const Node *Name;\n\npublic:\n  QualifiedName(const Node *Qualifier_, const Node *Name_)\n      : Node(KQualifiedName), Qualifier(Qualifier_), Name(Name_) {}\n\n  template<typename Fn> void match(Fn F) const { F(Qualifier, Name); }\n\n  StringView getBaseName() const override { return Name->getBaseName(); }\n\n  void printLeft(OutputStream &S) const override {\n    Qualifier->print(S);\n    S += \"::\";\n    Name->print(S);\n  }\n};\n\nclass VectorType final : public Node {\n  const Node *BaseType;\n  const NodeOrString Dimension;\n\npublic:\n  VectorType(const Node *BaseType_, NodeOrString Dimension_)\n      : Node(KVectorType), BaseType(BaseType_),\n        Dimension(Dimension_) {}\n\n  template<typename Fn> void match(Fn F) const { F(BaseType, Dimension); }\n\n  void printLeft(OutputStream &S) const override {\n    BaseType->print(S);\n    S += \" vector[\";\n    if (Dimension.isNode())\n      Dimension.asNode()->print(S);\n    else if (Dimension.isString())\n      S += Dimension.asString();\n    S += \"]\";\n  }\n};\n\nclass PixelVectorType final : public Node {\n  const NodeOrString Dimension;\n\npublic:\n  PixelVectorType(NodeOrString Dimension_)\n      : Node(KPixelVectorType), Dimension(Dimension_) {}\n\n  template<typename Fn> void match(Fn F) const { F(Dimension); }\n\n  void printLeft(OutputStream &S) const override {\n    // FIXME: This should demangle as \"vector pixel\".\n    S += \"pixel vector[\";\n    S += Dimension.asString();\n    S += \"]\";\n  }\n};\n\n/// An unexpanded parameter pack (either in the expression or type context). If\n/// this AST is correct, this node will have a ParameterPackExpansion node above\n/// it.\n///\n/// This node is created when some <template-args> are found that apply to an\n/// <encoding>, and is stored in the TemplateParams table. In order for this to\n/// appear in the final AST, it has to referenced via a <template-param> (ie,\n/// T_).\nclass ParameterPack final : public Node {\n  NodeArray Data;\n\n  // Setup OutputStream for a pack expansion unless we're already expanding one.\n  void initializePackExpansion(OutputStream &S) const {\n    if (S.CurrentPackMax == std::numeric_limits<unsigned>::max()) {\n      S.CurrentPackMax = static_cast<unsigned>(Data.size());\n      S.CurrentPackIndex = 0;\n    }\n  }\n\npublic:\n  ParameterPack(NodeArray Data_) : Node(KParameterPack), Data(Data_) {\n    ArrayCache = FunctionCache = RHSComponentCache = Cache::Unknown;\n    if (std::all_of(Data.begin(), Data.end(), [](Node* P) {\n          return P->ArrayCache == Cache::No;\n        }))\n      ArrayCache = Cache::No;\n    if (std::all_of(Data.begin(), Data.end(), [](Node* P) {\n          return P->FunctionCache == Cache::No;\n        }))\n      FunctionCache = Cache::No;\n    if (std::all_of(Data.begin(), Data.end(), [](Node* P) {\n          return P->RHSComponentCache == Cache::No;\n        }))\n      RHSComponentCache = Cache::No;\n  }\n\n  template<typename Fn> void match(Fn F) const { F(Data); }\n\n  bool hasRHSComponentSlow(OutputStream &S) const override {\n    initializePackExpansion(S);\n    size_t Idx = S.CurrentPackIndex;\n    return Idx < Data.size() && Data[Idx]->hasRHSComponent(S);\n  }\n  bool hasArraySlow(OutputStream &S) const override {\n    initializePackExpansion(S);\n    size_t Idx = S.CurrentPackIndex;\n    return Idx < Data.size() && Data[Idx]->hasArray(S);\n  }\n  bool hasFunctionSlow(OutputStream &S) const override {\n    initializePackExpansion(S);\n    size_t Idx = S.CurrentPackIndex;\n    return Idx < Data.size() && Data[Idx]->hasFunction(S);\n  }\n  const Node *getSyntaxNode(OutputStream &S) const override {\n    initializePackExpansion(S);\n    size_t Idx = S.CurrentPackIndex;\n    return Idx < Data.size() ? Data[Idx]->getSyntaxNode(S) : this;\n  }\n\n  void printLeft(OutputStream &S) const override {\n    initializePackExpansion(S);\n    size_t Idx = S.CurrentPackIndex;\n    if (Idx < Data.size())\n      Data[Idx]->printLeft(S);\n  }\n  void printRight(OutputStream &S) const override {\n    initializePackExpansion(S);\n    size_t Idx = S.CurrentPackIndex;\n    if (Idx < Data.size())\n      Data[Idx]->printRight(S);\n  }\n};\n\n/// A variadic template argument. This node represents an occurrence of\n/// J<something>E in some <template-args>. It isn't itself unexpanded, unless\n/// one of it's Elements is. The parser inserts a ParameterPack into the\n/// TemplateParams table if the <template-args> this pack belongs to apply to an\n/// <encoding>.\nclass TemplateArgumentPack final : public Node {\n  NodeArray Elements;\npublic:\n  TemplateArgumentPack(NodeArray Elements_)\n      : Node(KTemplateArgumentPack), Elements(Elements_) {}\n\n  template<typename Fn> void match(Fn F) const { F(Elements); }\n\n  NodeArray getElements() const { return Elements; }\n\n  void printLeft(OutputStream &S) const override {\n    Elements.printWithComma(S);\n  }\n};\n\n/// A pack expansion. Below this node, there are some unexpanded ParameterPacks\n/// which each have Child->ParameterPackSize elements.\nclass ParameterPackExpansion final : public Node {\n  const Node *Child;\n\npublic:\n  ParameterPackExpansion(const Node *Child_)\n      : Node(KParameterPackExpansion), Child(Child_) {}\n\n  template<typename Fn> void match(Fn F) const { F(Child); }\n\n  const Node *getChild() const { return Child; }\n\n  void printLeft(OutputStream &S) const override {\n    constexpr unsigned Max = std::numeric_limits<unsigned>::max();\n    SwapAndRestore<unsigned> SavePackIdx(S.CurrentPackIndex, Max);\n    SwapAndRestore<unsigned> SavePackMax(S.CurrentPackMax, Max);\n    size_t StreamPos = S.getCurrentPosition();\n\n    // Print the first element in the pack. If Child contains a ParameterPack,\n    // it will set up S.CurrentPackMax and print the first element.\n    Child->print(S);\n\n    // No ParameterPack was found in Child. This can occur if we've found a pack\n    // expansion on a <function-param>.\n    if (S.CurrentPackMax == Max) {\n      S += \"...\";\n      return;\n    }\n\n    // We found a ParameterPack, but it has no elements. Erase whatever we may\n    // of printed.\n    if (S.CurrentPackMax == 0) {\n      S.setCurrentPosition(StreamPos);\n      return;\n    }\n\n    // Else, iterate through the rest of the elements in the pack.\n    for (unsigned I = 1, E = S.CurrentPackMax; I < E; ++I) {\n      S += \", \";\n      S.CurrentPackIndex = I;\n      Child->print(S);\n    }\n  }\n};\n\nclass TemplateArgs final : public Node {\n  NodeArray Params;\n\npublic:\n  TemplateArgs(NodeArray Params_) : Node(KTemplateArgs), Params(Params_) {}\n\n  template<typename Fn> void match(Fn F) const { F(Params); }\n\n  NodeArray getParams() { return Params; }\n\n  void printLeft(OutputStream &S) const override {\n    S += \"<\";\n    Params.printWithComma(S);\n    if (S.back() == '>')\n      S += \" \";\n    S += \">\";\n  }\n};\n\n/// A forward-reference to a template argument that was not known at the point\n/// where the template parameter name was parsed in a mangling.\n///\n/// This is created when demangling the name of a specialization of a\n/// conversion function template:\n///\n/// \\code\n/// struct A {\n///   template<typename T> operator T*();\n/// };\n/// \\endcode\n///\n/// When demangling a specialization of the conversion function template, we\n/// encounter the name of the template (including the \\c T) before we reach\n/// the template argument list, so we cannot substitute the parameter name\n/// for the corresponding argument while parsing. Instead, we create a\n/// \\c ForwardTemplateReference node that is resolved after we parse the\n/// template arguments.\nstruct ForwardTemplateReference : Node {\n  size_t Index;\n  Node *Ref = nullptr;\n\n  // If we're currently printing this node. It is possible (though invalid) for\n  // a forward template reference to refer to itself via a substitution. This\n  // creates a cyclic AST, which will stack overflow printing. To fix this, bail\n  // out if more than one print* function is active.\n  mutable bool Printing = false;\n\n  ForwardTemplateReference(size_t Index_)\n      : Node(KForwardTemplateReference, Cache::Unknown, Cache::Unknown,\n             Cache::Unknown),\n        Index(Index_) {}\n\n  // We don't provide a matcher for these, because the value of the node is\n  // not determined by its construction parameters, and it generally needs\n  // special handling.\n  template<typename Fn> void match(Fn F) const = delete;\n\n  bool hasRHSComponentSlow(OutputStream &S) const override {\n    if (Printing)\n      return false;\n    SwapAndRestore<bool> SavePrinting(Printing, true);\n    return Ref->hasRHSComponent(S);\n  }\n  bool hasArraySlow(OutputStream &S) const override {\n    if (Printing)\n      return false;\n    SwapAndRestore<bool> SavePrinting(Printing, true);\n    return Ref->hasArray(S);\n  }\n  bool hasFunctionSlow(OutputStream &S) const override {\n    if (Printing)\n      return false;\n    SwapAndRestore<bool> SavePrinting(Printing, true);\n    return Ref->hasFunction(S);\n  }\n  const Node *getSyntaxNode(OutputStream &S) const override {\n    if (Printing)\n      return this;\n    SwapAndRestore<bool> SavePrinting(Printing, true);\n    return Ref->getSyntaxNode(S);\n  }\n\n  void printLeft(OutputStream &S) const override {\n    if (Printing)\n      return;\n    SwapAndRestore<bool> SavePrinting(Printing, true);\n    Ref->printLeft(S);\n  }\n  void printRight(OutputStream &S) const override {\n    if (Printing)\n      return;\n    SwapAndRestore<bool> SavePrinting(Printing, true);\n    Ref->printRight(S);\n  }\n};\n\nstruct NameWithTemplateArgs : Node {\n  // name<template_args>\n  Node *Name;\n  Node *TemplateArgs;\n\n  NameWithTemplateArgs(Node *Name_, Node *TemplateArgs_)\n      : Node(KNameWithTemplateArgs), Name(Name_), TemplateArgs(TemplateArgs_) {}\n\n  template<typename Fn> void match(Fn F) const { F(Name, TemplateArgs); }\n\n  StringView getBaseName() const override { return Name->getBaseName(); }\n\n  void printLeft(OutputStream &S) const override {\n    Name->print(S);\n    TemplateArgs->print(S);\n  }\n};\n\nclass GlobalQualifiedName final : public Node {\n  Node *Child;\n\npublic:\n  GlobalQualifiedName(Node* Child_)\n      : Node(KGlobalQualifiedName), Child(Child_) {}\n\n  template<typename Fn> void match(Fn F) const { F(Child); }\n\n  StringView getBaseName() const override { return Child->getBaseName(); }\n\n  void printLeft(OutputStream &S) const override {\n    S += \"::\";\n    Child->print(S);\n  }\n};\n\nstruct StdQualifiedName : Node {\n  Node *Child;\n\n  StdQualifiedName(Node *Child_) : Node(KStdQualifiedName), Child(Child_) {}\n\n  template<typename Fn> void match(Fn F) const { F(Child); }\n\n  StringView getBaseName() const override { return Child->getBaseName(); }\n\n  void printLeft(OutputStream &S) const override {\n    S += \"std::\";\n    Child->print(S);\n  }\n};\n\nenum class SpecialSubKind {\n  allocator,\n  basic_string,\n  string,\n  istream,\n  ostream,\n  iostream,\n};\n\nclass ExpandedSpecialSubstitution final : public Node {\n  SpecialSubKind SSK;\n\npublic:\n  ExpandedSpecialSubstitution(SpecialSubKind SSK_)\n      : Node(KExpandedSpecialSubstitution), SSK(SSK_) {}\n\n  template<typename Fn> void match(Fn F) const { F(SSK); }\n\n  StringView getBaseName() const override {\n    switch (SSK) {\n    case SpecialSubKind::allocator:\n      return StringView(\"allocator\");\n    case SpecialSubKind::basic_string:\n      return StringView(\"basic_string\");\n    case SpecialSubKind::string:\n      return StringView(\"basic_string\");\n    case SpecialSubKind::istream:\n      return StringView(\"basic_istream\");\n    case SpecialSubKind::ostream:\n      return StringView(\"basic_ostream\");\n    case SpecialSubKind::iostream:\n      return StringView(\"basic_iostream\");\n    }\n    LLVM_BUILTIN_UNREACHABLE;\n  }\n\n  void printLeft(OutputStream &S) const override {\n    switch (SSK) {\n    case SpecialSubKind::allocator:\n      S += \"std::allocator\";\n      break;\n    case SpecialSubKind::basic_string:\n      S += \"std::basic_string\";\n      break;\n    case SpecialSubKind::string:\n      S += \"std::basic_string<char, std::char_traits<char>, \"\n           \"std::allocator<char> >\";\n      break;\n    case SpecialSubKind::istream:\n      S += \"std::basic_istream<char, std::char_traits<char> >\";\n      break;\n    case SpecialSubKind::ostream:\n      S += \"std::basic_ostream<char, std::char_traits<char> >\";\n      break;\n    case SpecialSubKind::iostream:\n      S += \"std::basic_iostream<char, std::char_traits<char> >\";\n      break;\n    }\n  }\n};\n\nclass SpecialSubstitution final : public Node {\npublic:\n  SpecialSubKind SSK;\n\n  SpecialSubstitution(SpecialSubKind SSK_)\n      : Node(KSpecialSubstitution), SSK(SSK_) {}\n\n  template<typename Fn> void match(Fn F) const { F(SSK); }\n\n  StringView getBaseName() const override {\n    switch (SSK) {\n    case SpecialSubKind::allocator:\n      return StringView(\"allocator\");\n    case SpecialSubKind::basic_string:\n      return StringView(\"basic_string\");\n    case SpecialSubKind::string:\n      return StringView(\"string\");\n    case SpecialSubKind::istream:\n      return StringView(\"istream\");\n    case SpecialSubKind::ostream:\n      return StringView(\"ostream\");\n    case SpecialSubKind::iostream:\n      return StringView(\"iostream\");\n    }\n    LLVM_BUILTIN_UNREACHABLE;\n  }\n\n  void printLeft(OutputStream &S) const override {\n    switch (SSK) {\n    case SpecialSubKind::allocator:\n      S += \"std::allocator\";\n      break;\n    case SpecialSubKind::basic_string:\n      S += \"std::basic_string\";\n      break;\n    case SpecialSubKind::string:\n      S += \"std::string\";\n      break;\n    case SpecialSubKind::istream:\n      S += \"std::istream\";\n      break;\n    case SpecialSubKind::ostream:\n      S += \"std::ostream\";\n      break;\n    case SpecialSubKind::iostream:\n      S += \"std::iostream\";\n      break;\n    }\n  }\n};\n\nclass CtorDtorName final : public Node {\n  const Node *Basename;\n  const bool IsDtor;\n  const int Variant;\n\npublic:\n  CtorDtorName(const Node *Basename_, bool IsDtor_, int Variant_)\n      : Node(KCtorDtorName), Basename(Basename_), IsDtor(IsDtor_),\n        Variant(Variant_) {}\n\n  template<typename Fn> void match(Fn F) const { F(Basename, IsDtor, Variant); }\n\n  void printLeft(OutputStream &S) const override {\n    if (IsDtor)\n      S += \"~\";\n    S += Basename->getBaseName();\n  }\n};\n\nclass DtorName : public Node {\n  const Node *Base;\n\npublic:\n  DtorName(const Node *Base_) : Node(KDtorName), Base(Base_) {}\n\n  template<typename Fn> void match(Fn F) const { F(Base); }\n\n  void printLeft(OutputStream &S) const override {\n    S += \"~\";\n    Base->printLeft(S);\n  }\n};\n\nclass UnnamedTypeName : public Node {\n  const StringView Count;\n\npublic:\n  UnnamedTypeName(StringView Count_) : Node(KUnnamedTypeName), Count(Count_) {}\n\n  template<typename Fn> void match(Fn F) const { F(Count); }\n\n  void printLeft(OutputStream &S) const override {\n    S += \"'unnamed\";\n    S += Count;\n    S += \"\\'\";\n  }\n};\n\nclass ClosureTypeName : public Node {\n  NodeArray Params;\n  StringView Count;\n\npublic:\n  ClosureTypeName(NodeArray Params_, StringView Count_)\n      : Node(KClosureTypeName), Params(Params_), Count(Count_) {}\n\n  template<typename Fn> void match(Fn F) const { F(Params, Count); }\n\n  void printLeft(OutputStream &S) const override {\n    S += \"\\'lambda\";\n    S += Count;\n    S += \"\\'(\";\n    Params.printWithComma(S);\n    S += \")\";\n  }\n};\n\nclass StructuredBindingName : public Node {\n  NodeArray Bindings;\npublic:\n  StructuredBindingName(NodeArray Bindings_)\n      : Node(KStructuredBindingName), Bindings(Bindings_) {}\n\n  template<typename Fn> void match(Fn F) const { F(Bindings); }\n\n  void printLeft(OutputStream &S) const override {\n    S += '[';\n    Bindings.printWithComma(S);\n    S += ']';\n  }\n};\n\n// -- Expression Nodes --\n\nclass BinaryExpr : public Node {\n  const Node *LHS;\n  const StringView InfixOperator;\n  const Node *RHS;\n\npublic:\n  BinaryExpr(const Node *LHS_, StringView InfixOperator_, const Node *RHS_)\n      : Node(KBinaryExpr), LHS(LHS_), InfixOperator(InfixOperator_), RHS(RHS_) {\n  }\n\n  template<typename Fn> void match(Fn F) const { F(LHS, InfixOperator, RHS); }\n\n  void printLeft(OutputStream &S) const override {\n    // might be a template argument expression, then we need to disambiguate\n    // with parens.\n    if (InfixOperator == \">\")\n      S += \"(\";\n\n    S += \"(\";\n    LHS->print(S);\n    S += \") \";\n    S += InfixOperator;\n    S += \" (\";\n    RHS->print(S);\n    S += \")\";\n\n    if (InfixOperator == \">\")\n      S += \")\";\n  }\n};\n\nclass ArraySubscriptExpr : public Node {\n  const Node *Op1;\n  const Node *Op2;\n\npublic:\n  ArraySubscriptExpr(const Node *Op1_, const Node *Op2_)\n      : Node(KArraySubscriptExpr), Op1(Op1_), Op2(Op2_) {}\n\n  template<typename Fn> void match(Fn F) const { F(Op1, Op2); }\n\n  void printLeft(OutputStream &S) const override {\n    S += \"(\";\n    Op1->print(S);\n    S += \")[\";\n    Op2->print(S);\n    S += \"]\";\n  }\n};\n\nclass PostfixExpr : public Node {\n  const Node *Child;\n  const StringView Operator;\n\npublic:\n  PostfixExpr(const Node *Child_, StringView Operator_)\n      : Node(KPostfixExpr), Child(Child_), Operator(Operator_) {}\n\n  template<typename Fn> void match(Fn F) const { F(Child, Operator); }\n\n  void printLeft(OutputStream &S) const override {\n    S += \"(\";\n    Child->print(S);\n    S += \")\";\n    S += Operator;\n  }\n};\n\nclass ConditionalExpr : public Node {\n  const Node *Cond;\n  const Node *Then;\n  const Node *Else;\n\npublic:\n  ConditionalExpr(const Node *Cond_, const Node *Then_, const Node *Else_)\n      : Node(KConditionalExpr), Cond(Cond_), Then(Then_), Else(Else_) {}\n\n  template<typename Fn> void match(Fn F) const { F(Cond, Then, Else); }\n\n  void printLeft(OutputStream &S) const override {\n    S += \"(\";\n    Cond->print(S);\n    S += \") ? (\";\n    Then->print(S);\n    S += \") : (\";\n    Else->print(S);\n    S += \")\";\n  }\n};\n\nclass MemberExpr : public Node {\n  const Node *LHS;\n  const StringView Kind;\n  const Node *RHS;\n\npublic:\n  MemberExpr(const Node *LHS_, StringView Kind_, const Node *RHS_)\n      : Node(KMemberExpr), LHS(LHS_), Kind(Kind_), RHS(RHS_) {}\n\n  template<typename Fn> void match(Fn F) const { F(LHS, Kind, RHS); }\n\n  void printLeft(OutputStream &S) const override {\n    LHS->print(S);\n    S += Kind;\n    RHS->print(S);\n  }\n};\n\nclass EnclosingExpr : public Node {\n  const StringView Prefix;\n  const Node *Infix;\n  const StringView Postfix;\n\npublic:\n  EnclosingExpr(StringView Prefix_, Node *Infix_, StringView Postfix_)\n      : Node(KEnclosingExpr), Prefix(Prefix_), Infix(Infix_),\n        Postfix(Postfix_) {}\n\n  template<typename Fn> void match(Fn F) const { F(Prefix, Infix, Postfix); }\n\n  void printLeft(OutputStream &S) const override {\n    S += Prefix;\n    Infix->print(S);\n    S += Postfix;\n  }\n};\n\nclass CastExpr : public Node {\n  // cast_kind<to>(from)\n  const StringView CastKind;\n  const Node *To;\n  const Node *From;\n\npublic:\n  CastExpr(StringView CastKind_, const Node *To_, const Node *From_)\n      : Node(KCastExpr), CastKind(CastKind_), To(To_), From(From_) {}\n\n  template<typename Fn> void match(Fn F) const { F(CastKind, To, From); }\n\n  void printLeft(OutputStream &S) const override {\n    S += CastKind;\n    S += \"<\";\n    To->printLeft(S);\n    S += \">(\";\n    From->printLeft(S);\n    S += \")\";\n  }\n};\n\nclass SizeofParamPackExpr : public Node {\n  const Node *Pack;\n\npublic:\n  SizeofParamPackExpr(const Node *Pack_)\n      : Node(KSizeofParamPackExpr), Pack(Pack_) {}\n\n  template<typename Fn> void match(Fn F) const { F(Pack); }\n\n  void printLeft(OutputStream &S) const override {\n    S += \"sizeof...(\";\n    ParameterPackExpansion PPE(Pack);\n    PPE.printLeft(S);\n    S += \")\";\n  }\n};\n\nclass CallExpr : public Node {\n  const Node *Callee;\n  NodeArray Args;\n\npublic:\n  CallExpr(const Node *Callee_, NodeArray Args_)\n      : Node(KCallExpr), Callee(Callee_), Args(Args_) {}\n\n  template<typename Fn> void match(Fn F) const { F(Callee, Args); }\n\n  void printLeft(OutputStream &S) const override {\n    Callee->print(S);\n    S += \"(\";\n    Args.printWithComma(S);\n    S += \")\";\n  }\n};\n\nclass NewExpr : public Node {\n  // new (expr_list) type(init_list)\n  NodeArray ExprList;\n  Node *Type;\n  NodeArray InitList;\n  bool IsGlobal; // ::operator new ?\n  bool IsArray;  // new[] ?\npublic:\n  NewExpr(NodeArray ExprList_, Node *Type_, NodeArray InitList_, bool IsGlobal_,\n          bool IsArray_)\n      : Node(KNewExpr), ExprList(ExprList_), Type(Type_), InitList(InitList_),\n        IsGlobal(IsGlobal_), IsArray(IsArray_) {}\n\n  template<typename Fn> void match(Fn F) const {\n    F(ExprList, Type, InitList, IsGlobal, IsArray);\n  }\n\n  void printLeft(OutputStream &S) const override {\n    if (IsGlobal)\n      S += \"::operator \";\n    S += \"new\";\n    if (IsArray)\n      S += \"[]\";\n    S += ' ';\n    if (!ExprList.empty()) {\n      S += \"(\";\n      ExprList.printWithComma(S);\n      S += \")\";\n    }\n    Type->print(S);\n    if (!InitList.empty()) {\n      S += \"(\";\n      InitList.printWithComma(S);\n      S += \")\";\n    }\n\n  }\n};\n\nclass DeleteExpr : public Node {\n  Node *Op;\n  bool IsGlobal;\n  bool IsArray;\n\npublic:\n  DeleteExpr(Node *Op_, bool IsGlobal_, bool IsArray_)\n      : Node(KDeleteExpr), Op(Op_), IsGlobal(IsGlobal_), IsArray(IsArray_) {}\n\n  template<typename Fn> void match(Fn F) const { F(Op, IsGlobal, IsArray); }\n\n  void printLeft(OutputStream &S) const override {\n    if (IsGlobal)\n      S += \"::\";\n    S += \"delete\";\n    if (IsArray)\n      S += \"[] \";\n    Op->print(S);\n  }\n};\n\nclass PrefixExpr : public Node {\n  StringView Prefix;\n  Node *Child;\n\npublic:\n  PrefixExpr(StringView Prefix_, Node *Child_)\n      : Node(KPrefixExpr), Prefix(Prefix_), Child(Child_) {}\n\n  template<typename Fn> void match(Fn F) const { F(Prefix, Child); }\n\n  void printLeft(OutputStream &S) const override {\n    S += Prefix;\n    S += \"(\";\n    Child->print(S);\n    S += \")\";\n  }\n};\n\nclass FunctionParam : public Node {\n  StringView Number;\n\npublic:\n  FunctionParam(StringView Number_) : Node(KFunctionParam), Number(Number_) {}\n\n  template<typename Fn> void match(Fn F) const { F(Number); }\n\n  void printLeft(OutputStream &S) const override {\n    S += \"fp\";\n    S += Number;\n  }\n};\n\nclass ConversionExpr : public Node {\n  const Node *Type;\n  NodeArray Expressions;\n\npublic:\n  ConversionExpr(const Node *Type_, NodeArray Expressions_)\n      : Node(KConversionExpr), Type(Type_), Expressions(Expressions_) {}\n\n  template<typename Fn> void match(Fn F) const { F(Type, Expressions); }\n\n  void printLeft(OutputStream &S) const override {\n    S += \"(\";\n    Type->print(S);\n    S += \")(\";\n    Expressions.printWithComma(S);\n    S += \")\";\n  }\n};\n\nclass InitListExpr : public Node {\n  const Node *Ty;\n  NodeArray Inits;\npublic:\n  InitListExpr(const Node *Ty_, NodeArray Inits_)\n      : Node(KInitListExpr), Ty(Ty_), Inits(Inits_) {}\n\n  template<typename Fn> void match(Fn F) const { F(Ty, Inits); }\n\n  void printLeft(OutputStream &S) const override {\n    if (Ty)\n      Ty->print(S);\n    S += '{';\n    Inits.printWithComma(S);\n    S += '}';\n  }\n};\n\nclass BracedExpr : public Node {\n  const Node *Elem;\n  const Node *Init;\n  bool IsArray;\npublic:\n  BracedExpr(const Node *Elem_, const Node *Init_, bool IsArray_)\n      : Node(KBracedExpr), Elem(Elem_), Init(Init_), IsArray(IsArray_) {}\n\n  template<typename Fn> void match(Fn F) const { F(Elem, Init, IsArray); }\n\n  void printLeft(OutputStream &S) const override {\n    if (IsArray) {\n      S += '[';\n      Elem->print(S);\n      S += ']';\n    } else {\n      S += '.';\n      Elem->print(S);\n    }\n    if (Init->getKind() != KBracedExpr && Init->getKind() != KBracedRangeExpr)\n      S += \" = \";\n    Init->print(S);\n  }\n};\n\nclass BracedRangeExpr : public Node {\n  const Node *First;\n  const Node *Last;\n  const Node *Init;\npublic:\n  BracedRangeExpr(const Node *First_, const Node *Last_, const Node *Init_)\n      : Node(KBracedRangeExpr), First(First_), Last(Last_), Init(Init_) {}\n\n  template<typename Fn> void match(Fn F) const { F(First, Last, Init); }\n\n  void printLeft(OutputStream &S) const override {\n    S += '[';\n    First->print(S);\n    S += \" ... \";\n    Last->print(S);\n    S += ']';\n    if (Init->getKind() != KBracedExpr && Init->getKind() != KBracedRangeExpr)\n      S += \" = \";\n    Init->print(S);\n  }\n};\n\nclass FoldExpr : public Node {\n  const Node *Pack, *Init;\n  StringView OperatorName;\n  bool IsLeftFold;\n\npublic:\n  FoldExpr(bool IsLeftFold_, StringView OperatorName_, const Node *Pack_,\n           const Node *Init_)\n      : Node(KFoldExpr), Pack(Pack_), Init(Init_), OperatorName(OperatorName_),\n        IsLeftFold(IsLeftFold_) {}\n\n  template<typename Fn> void match(Fn F) const {\n    F(IsLeftFold, OperatorName, Pack, Init);\n  }\n\n  void printLeft(OutputStream &S) const override {\n    auto PrintPack = [&] {\n      S += '(';\n      ParameterPackExpansion(Pack).print(S);\n      S += ')';\n    };\n\n    S += '(';\n\n    if (IsLeftFold) {\n      // init op ... op pack\n      if (Init != nullptr) {\n        Init->print(S);\n        S += ' ';\n        S += OperatorName;\n        S += ' ';\n      }\n      // ... op pack\n      S += \"... \";\n      S += OperatorName;\n      S += ' ';\n      PrintPack();\n    } else { // !IsLeftFold\n      // pack op ...\n      PrintPack();\n      S += ' ';\n      S += OperatorName;\n      S += \" ...\";\n      // pack op ... op init\n      if (Init != nullptr) {\n        S += ' ';\n        S += OperatorName;\n        S += ' ';\n        Init->print(S);\n      }\n    }\n    S += ')';\n  }\n};\n\nclass ThrowExpr : public Node {\n  const Node *Op;\n\npublic:\n  ThrowExpr(const Node *Op_) : Node(KThrowExpr), Op(Op_) {}\n\n  template<typename Fn> void match(Fn F) const { F(Op); }\n\n  void printLeft(OutputStream &S) const override {\n    S += \"throw \";\n    Op->print(S);\n  }\n};\n\nclass BoolExpr : public Node {\n  bool Value;\n\npublic:\n  BoolExpr(bool Value_) : Node(KBoolExpr), Value(Value_) {}\n\n  template<typename Fn> void match(Fn F) const { F(Value); }\n\n  void printLeft(OutputStream &S) const override {\n    S += Value ? StringView(\"true\") : StringView(\"false\");\n  }\n};\n\nclass IntegerCastExpr : public Node {\n  // ty(integer)\n  const Node *Ty;\n  StringView Integer;\n\npublic:\n  IntegerCastExpr(const Node *Ty_, StringView Integer_)\n      : Node(KIntegerCastExpr), Ty(Ty_), Integer(Integer_) {}\n\n  template<typename Fn> void match(Fn F) const { F(Ty, Integer); }\n\n  void printLeft(OutputStream &S) const override {\n    S += \"(\";\n    Ty->print(S);\n    S += \")\";\n    S += Integer;\n  }\n};\n\nclass IntegerLiteral : public Node {\n  StringView Type;\n  StringView Value;\n\npublic:\n  IntegerLiteral(StringView Type_, StringView Value_)\n      : Node(KIntegerLiteral), Type(Type_), Value(Value_) {}\n\n  template<typename Fn> void match(Fn F) const { F(Type, Value); }\n\n  void printLeft(OutputStream &S) const override {\n    if (Type.size() > 3) {\n      S += \"(\";\n      S += Type;\n      S += \")\";\n    }\n\n    if (Value[0] == 'n') {\n      S += \"-\";\n      S += Value.dropFront(1);\n    } else\n      S += Value;\n\n    if (Type.size() <= 3)\n      S += Type;\n  }\n};\n\ntemplate <class Float> struct FloatData;\n\nnamespace float_literal_impl {\nconstexpr Node::Kind getFloatLiteralKind(float *) {\n  return Node::KFloatLiteral;\n}\nconstexpr Node::Kind getFloatLiteralKind(double *) {\n  return Node::KDoubleLiteral;\n}\nconstexpr Node::Kind getFloatLiteralKind(long double *) {\n  return Node::KLongDoubleLiteral;\n}\n}\n\ntemplate <class Float> class FloatLiteralImpl : public Node {\n  const StringView Contents;\n\n  static constexpr Kind KindForClass =\n      float_literal_impl::getFloatLiteralKind((Float *)nullptr);\n\npublic:\n  FloatLiteralImpl(StringView Contents_)\n      : Node(KindForClass), Contents(Contents_) {}\n\n  template<typename Fn> void match(Fn F) const { F(Contents); }\n\n  void printLeft(OutputStream &s) const override {\n    const char *first = Contents.begin();\n    const char *last = Contents.end() + 1;\n\n    const size_t N = FloatData<Float>::mangled_size;\n    if (static_cast<std::size_t>(last - first) > N) {\n      last = first + N;\n      union {\n        Float value;\n        char buf[sizeof(Float)];\n      };\n      const char *t = first;\n      char *e = buf;\n      for (; t != last; ++t, ++e) {\n        unsigned d1 = isdigit(*t) ? static_cast<unsigned>(*t - '0')\n                                  : static_cast<unsigned>(*t - 'a' + 10);\n        ++t;\n        unsigned d0 = isdigit(*t) ? static_cast<unsigned>(*t - '0')\n                                  : static_cast<unsigned>(*t - 'a' + 10);\n        *e = static_cast<char>((d1 << 4) + d0);\n      }\n#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__\n      std::reverse(buf, e);\n#endif\n      char num[FloatData<Float>::max_demangled_size] = {0};\n      int n = snprintf(num, sizeof(num), FloatData<Float>::spec, value);\n      s += StringView(num, num + n);\n    }\n  }\n};\n\nusing FloatLiteral = FloatLiteralImpl<float>;\nusing DoubleLiteral = FloatLiteralImpl<double>;\nusing LongDoubleLiteral = FloatLiteralImpl<long double>;\n\n/// Visit the node. Calls \\c F(P), where \\c P is the node cast to the\n/// appropriate derived class.\ntemplate<typename Fn>\nvoid Node::visit(Fn F) const {\n  switch (K) {\n#define CASE(X) case K ## X: return F(static_cast<const X*>(this));\n    FOR_EACH_NODE_KIND(CASE)\n#undef CASE\n  }\n  assert(0 && \"unknown mangling node kind\");\n}\n\n/// Determine the kind of a node from its type.\ntemplate<typename NodeT> struct NodeKind;\n#define SPECIALIZATION(X) \\\n  template<> struct NodeKind<X> { \\\n    static constexpr Node::Kind Kind = Node::K##X; \\\n    static constexpr const char *name() { return #X; } \\\n  };\nFOR_EACH_NODE_KIND(SPECIALIZATION)\n#undef SPECIALIZATION\n\n#undef FOR_EACH_NODE_KIND\n\ntemplate <class T, size_t N>\nclass PODSmallVector {\n  static_assert(std::is_pod<T>::value,\n                \"T is required to be a plain old data type\");\n\n  T* First;\n  T* Last;\n  T* Cap;\n  T Inline[N];\n\n  bool isInline() const { return First == Inline; }\n\n  void clearInline() {\n    First = Inline;\n    Last = Inline;\n    Cap = Inline + N;\n  }\n\n  void reserve(size_t NewCap) {\n    size_t S = size();\n    if (isInline()) {\n      auto* Tmp = static_cast<T*>(std::malloc(NewCap * sizeof(T)));\n      if (Tmp == nullptr)\n        std::terminate();\n      std::copy(First, Last, Tmp);\n      First = Tmp;\n    } else {\n      First = static_cast<T*>(std::realloc(First, NewCap * sizeof(T)));\n      if (First == nullptr)\n        std::terminate();\n    }\n    Last = First + S;\n    Cap = First + NewCap;\n  }\n\npublic:\n  PODSmallVector() : First(Inline), Last(First), Cap(Inline + N) {}\n\n  PODSmallVector(const PODSmallVector&) = delete;\n  PODSmallVector& operator=(const PODSmallVector&) = delete;\n\n  PODSmallVector(PODSmallVector&& Other) : PODSmallVector() {\n    if (Other.isInline()) {\n      std::copy(Other.begin(), Other.end(), First);\n      Last = First + Other.size();\n      Other.clear();\n      return;\n    }\n\n    First = Other.First;\n    Last = Other.Last;\n    Cap = Other.Cap;\n    Other.clearInline();\n  }\n\n  PODSmallVector& operator=(PODSmallVector&& Other) {\n    if (Other.isInline()) {\n      if (!isInline()) {\n        std::free(First);\n        clearInline();\n      }\n      std::copy(Other.begin(), Other.end(), First);\n      Last = First + Other.size();\n      Other.clear();\n      return *this;\n    }\n\n    if (isInline()) {\n      First = Other.First;\n      Last = Other.Last;\n      Cap = Other.Cap;\n      Other.clearInline();\n      return *this;\n    }\n\n    std::swap(First, Other.First);\n    std::swap(Last, Other.Last);\n    std::swap(Cap, Other.Cap);\n    Other.clear();\n    return *this;\n  }\n\n  void push_back(const T& Elem) {\n    if (Last == Cap)\n      reserve(size() * 2);\n    *Last++ = Elem;\n  }\n\n  void pop_back() {\n    assert(Last != First && \"Popping empty vector!\");\n    --Last;\n  }\n\n  void dropBack(size_t Index) {\n    assert(Index <= size() && \"dropBack() can't expand!\");\n    Last = First + Index;\n  }\n\n  T* begin() { return First; }\n  T* end() { return Last; }\n\n  bool empty() const { return First == Last; }\n  size_t size() const { return static_cast<size_t>(Last - First); }\n  T& back() {\n    assert(Last != First && \"Calling back() on empty vector!\");\n    return *(Last - 1);\n  }\n  T& operator[](size_t Index) {\n    assert(Index < size() && \"Invalid access!\");\n    return *(begin() + Index);\n  }\n  void clear() { Last = First; }\n\n  ~PODSmallVector() {\n    if (!isInline())\n      std::free(First);\n  }\n};\n\ntemplate <typename Alloc>\nstruct Db {\n  const char *First;\n  const char *Last;\n\n  // Name stack, this is used by the parser to hold temporary names that were\n  // parsed. The parser collapses multiple names into new nodes to construct\n  // the AST. Once the parser is finished, names.size() == 1.\n  PODSmallVector<Node *, 32> Names;\n\n  // Substitution table. Itanium supports name substitutions as a means of\n  // compression. The string \"S42_\" refers to the 44nd entry (base-36) in this\n  // table.\n  PODSmallVector<Node *, 32> Subs;\n\n  // Template parameter table. Like the above, but referenced like \"T42_\".\n  // This has a smaller size compared to Subs and Names because it can be\n  // stored on the stack.\n  PODSmallVector<Node *, 8> TemplateParams;\n\n  // Set of unresolved forward <template-param> references. These can occur in a\n  // conversion operator's type, and are resolved in the enclosing <encoding>.\n  PODSmallVector<ForwardTemplateReference *, 4> ForwardTemplateRefs;\n\n  void (*TypeCallback)(void *, const char *) = nullptr;\n  void *TypeCallbackContext = nullptr;\n\n  bool TryToParseTemplateArgs = true;\n  bool PermitForwardTemplateReferences = false;\n  bool ParsingLambdaParams = false;\n\n  Alloc ASTAllocator;\n\n  Db(const char *First_, const char *Last_) : First(First_), Last(Last_) {}\n\n  void reset(const char *First_, const char *Last_) {\n    First = First_;\n    Last = Last_;\n    Names.clear();\n    Subs.clear();\n    TemplateParams.clear();\n    ParsingLambdaParams = false;\n    TryToParseTemplateArgs = true;\n    PermitForwardTemplateReferences = false;\n    ASTAllocator.reset();\n  }\n\n  template <class T, class... Args> Node *make(Args &&... args) {\n    return ASTAllocator.template makeNode<T>(std::forward<Args>(args)...);\n  }\n\n  template <class It> NodeArray makeNodeArray(It begin, It end) {\n    size_t sz = static_cast<size_t>(end - begin);\n    void *mem = ASTAllocator.allocateNodeArray(sz);\n    Node **data = new (mem) Node *[sz];\n    std::copy(begin, end, data);\n    return NodeArray(data, sz);\n  }\n\n  NodeArray popTrailingNodeArray(size_t FromPosition) {\n    assert(FromPosition <= Names.size());\n    NodeArray res =\n        makeNodeArray(Names.begin() + (long)FromPosition, Names.end());\n    Names.dropBack(FromPosition);\n    return res;\n  }\n\n  bool consumeIf(StringView S) {\n    if (StringView(First, Last).startsWith(S)) {\n      First += S.size();\n      return true;\n    }\n    return false;\n  }\n\n  bool consumeIf(char C) {\n    if (First != Last && *First == C) {\n      ++First;\n      return true;\n    }\n    return false;\n  }\n\n  char consume() { return First != Last ? *First++ : '\\0'; }\n\n  char look(unsigned Lookahead = 0) {\n    if (static_cast<size_t>(Last - First) <= Lookahead)\n      return '\\0';\n    return First[Lookahead];\n  }\n\n  size_t numLeft() const { return static_cast<size_t>(Last - First); }\n\n  StringView parseNumber(bool AllowNegative = false);\n  Qualifiers parseCVQualifiers();\n  bool parsePositiveInteger(size_t *Out);\n  StringView parseBareSourceName();\n\n  bool parseSeqId(size_t *Out);\n  Node *parseSubstitution();\n  Node *parseTemplateParam();\n  Node *parseTemplateArgs(bool TagTemplates = false);\n  Node *parseTemplateArg();\n\n  /// Parse the <expr> production.\n  Node *parseExpr();\n  Node *parsePrefixExpr(StringView Kind);\n  Node *parseBinaryExpr(StringView Kind);\n  Node *parseIntegerLiteral(StringView Lit);\n  Node *parseExprPrimary();\n  template <class Float> Node *parseFloatingLiteral();\n  Node *parseFunctionParam();\n  Node *parseNewExpr();\n  Node *parseConversionExpr();\n  Node *parseBracedExpr();\n  Node *parseFoldExpr();\n\n  /// Parse the <type> production.\n  Node *parseType();\n  Node *parseFunctionType();\n  Node *parseVectorType();\n  Node *parseDecltype();\n  Node *parseArrayType();\n  Node *parsePointerToMemberType();\n  Node *parseClassEnumType();\n  Node *parseQualifiedType();\n\n  Node *parseEncoding();\n  bool parseCallOffset();\n  Node *parseSpecialName();\n\n  /// Holds some extra information about a <name> that is being parsed. This\n  /// information is only pertinent if the <name> refers to an <encoding>.\n  struct NameState {\n    bool CtorDtorConversion = false;\n    bool EndsWithTemplateArgs = false;\n    Qualifiers CVQualifiers = QualNone;\n    FunctionRefQual ReferenceQualifier = FrefQualNone;\n    size_t ForwardTemplateRefsBegin;\n\n    NameState(Db *Enclosing)\n        : ForwardTemplateRefsBegin(Enclosing->ForwardTemplateRefs.size()) {}\n  };\n\n  bool resolveForwardTemplateRefs(NameState &State) {\n    size_t I = State.ForwardTemplateRefsBegin;\n    size_t E = ForwardTemplateRefs.size();\n    for (; I < E; ++I) {\n      size_t Idx = ForwardTemplateRefs[I]->Index;\n      if (Idx >= TemplateParams.size())\n        return true;\n      ForwardTemplateRefs[I]->Ref = TemplateParams[Idx];\n    }\n    ForwardTemplateRefs.dropBack(State.ForwardTemplateRefsBegin);\n    return false;\n  }\n\n  /// Parse the <name> production>\n  Node *parseName(NameState *State = nullptr);\n  Node *parseLocalName(NameState *State);\n  Node *parseOperatorName(NameState *State);\n  Node *parseUnqualifiedName(NameState *State);\n  Node *parseUnnamedTypeName(NameState *State);\n  Node *parseSourceName(NameState *State);\n  Node *parseUnscopedName(NameState *State);\n  Node *parseNestedName(NameState *State);\n  Node *parseCtorDtorName(Node *&SoFar, NameState *State);\n\n  Node *parseAbiTags(Node *N);\n\n  /// Parse the <unresolved-name> production.\n  Node *parseUnresolvedName();\n  Node *parseSimpleId();\n  Node *parseBaseUnresolvedName();\n  Node *parseUnresolvedType();\n  Node *parseDestructorName();\n\n  /// Top-level entry point into the parser.\n  Node *parse();\n};\n\nconst char* parse_discriminator(const char* first, const char* last);\n\n// <name> ::= <nested-name> // N\n//        ::= <local-name> # See Scope Encoding below  // Z\n//        ::= <unscoped-template-name> <template-args>\n//        ::= <unscoped-name>\n//\n// <unscoped-template-name> ::= <unscoped-name>\n//                          ::= <substitution>\ntemplate<typename Alloc> Node *Db<Alloc>::parseName(NameState *State) {\n  consumeIf('L'); // extension\n\n  if (look() == 'N')\n    return parseNestedName(State);\n  if (look() == 'Z')\n    return parseLocalName(State);\n\n  //        ::= <unscoped-template-name> <template-args>\n  if (look() == 'S' && look(1) != 't') {\n    Node *S = parseSubstitution();\n    if (S == nullptr)\n      return nullptr;\n    if (look() != 'I')\n      return nullptr;\n    Node *TA = parseTemplateArgs(State != nullptr);\n    if (TA == nullptr)\n      return nullptr;\n    if (State) State->EndsWithTemplateArgs = true;\n    return make<NameWithTemplateArgs>(S, TA);\n  }\n\n  Node *N = parseUnscopedName(State);\n  if (N == nullptr)\n    return nullptr;\n  //        ::= <unscoped-template-name> <template-args>\n  if (look() == 'I') {\n    Subs.push_back(N);\n    Node *TA = parseTemplateArgs(State != nullptr);\n    if (TA == nullptr)\n      return nullptr;\n    if (State) State->EndsWithTemplateArgs = true;\n    return make<NameWithTemplateArgs>(N, TA);\n  }\n  //        ::= <unscoped-name>\n  return N;\n}\n\n// <local-name> := Z <function encoding> E <entity name> [<discriminator>]\n//              := Z <function encoding> E s [<discriminator>]\n//              := Z <function encoding> Ed [ <parameter number> ] _ <entity name>\ntemplate<typename Alloc> Node *Db<Alloc>::parseLocalName(NameState *State) {\n  if (!consumeIf('Z'))\n    return nullptr;\n  Node *Encoding = parseEncoding();\n  if (Encoding == nullptr || !consumeIf('E'))\n    return nullptr;\n\n  if (consumeIf('s')) {\n    First = parse_discriminator(First, Last);\n    auto *StringLitName = make<NameType>(\"string literal\");\n    if (!StringLitName)\n      return nullptr;\n    return make<LocalName>(Encoding, StringLitName);\n  }\n\n  if (consumeIf('d')) {\n    parseNumber(true);\n    if (!consumeIf('_'))\n      return nullptr;\n    Node *N = parseName(State);\n    if (N == nullptr)\n      return nullptr;\n    return make<LocalName>(Encoding, N);\n  }\n\n  Node *Entity = parseName(State);\n  if (Entity == nullptr)\n    return nullptr;\n  First = parse_discriminator(First, Last);\n  return make<LocalName>(Encoding, Entity);\n}\n\n// <unscoped-name> ::= <unqualified-name>\n//                 ::= St <unqualified-name>   # ::std::\n// extension       ::= StL<unqualified-name>\ntemplate<typename Alloc> Node *Db<Alloc>::parseUnscopedName(NameState *State) {\n if (consumeIf(\"StL\") || consumeIf(\"St\")) {\n   Node *R = parseUnqualifiedName(State);\n   if (R == nullptr)\n     return nullptr;\n   return make<StdQualifiedName>(R);\n }\n return parseUnqualifiedName(State);\n}\n\n// <unqualified-name> ::= <operator-name> [abi-tags]\n//                    ::= <ctor-dtor-name>\n//                    ::= <source-name>\n//                    ::= <unnamed-type-name>\n//                    ::= DC <source-name>+ E      # structured binding declaration\ntemplate<typename Alloc>\nNode *Db<Alloc>::parseUnqualifiedName(NameState *State) {\n  // <ctor-dtor-name>s are special-cased in parseNestedName().\n  Node *Result;\n  if (look() == 'U')\n    Result = parseUnnamedTypeName(State);\n  else if (look() >= '1' && look() <= '9')\n    Result = parseSourceName(State);\n  else if (consumeIf(\"DC\")) {\n    size_t BindingsBegin = Names.size();\n    do {\n      Node *Binding = parseSourceName(State);\n      if (Binding == nullptr)\n        return nullptr;\n      Names.push_back(Binding);\n    } while (!consumeIf('E'));\n    Result = make<StructuredBindingName>(popTrailingNodeArray(BindingsBegin));\n  } else\n    Result = parseOperatorName(State);\n  if (Result != nullptr)\n    Result = parseAbiTags(Result);\n  return Result;\n}\n\n// <unnamed-type-name> ::= Ut [<nonnegative number>] _\n//                     ::= <closure-type-name>\n//\n// <closure-type-name> ::= Ul <lambda-sig> E [ <nonnegative number> ] _\n//\n// <lambda-sig> ::= <parameter type>+  # Parameter types or \"v\" if the lambda has no parameters\ntemplate<typename Alloc> Node *Db<Alloc>::parseUnnamedTypeName(NameState *) {\n  if (consumeIf(\"Ut\")) {\n    StringView Count = parseNumber();\n    if (!consumeIf('_'))\n      return nullptr;\n    return make<UnnamedTypeName>(Count);\n  }\n  if (consumeIf(\"Ul\")) {\n    NodeArray Params;\n    SwapAndRestore<bool> SwapParams(ParsingLambdaParams, true);\n    if (!consumeIf(\"vE\")) {\n      size_t ParamsBegin = Names.size();\n      do {\n        Node *P = parseType();\n        if (P == nullptr)\n          return nullptr;\n        Names.push_back(P);\n      } while (!consumeIf('E'));\n      Params = popTrailingNodeArray(ParamsBegin);\n    }\n    StringView Count = parseNumber();\n    if (!consumeIf('_'))\n      return nullptr;\n    return make<ClosureTypeName>(Params, Count);\n  }\n  return nullptr;\n}\n\n// <source-name> ::= <positive length number> <identifier>\ntemplate<typename Alloc> Node *Db<Alloc>::parseSourceName(NameState *) {\n  size_t Length = 0;\n  if (parsePositiveInteger(&Length))\n    return nullptr;\n  if (numLeft() < Length || Length == 0)\n    return nullptr;\n  StringView Name(First, First + Length);\n  First += Length;\n  if (Name.startsWith(\"_GLOBAL__N\"))\n    return make<NameType>(\"(anonymous namespace)\");\n  return make<NameType>(Name);\n}\n\n//   <operator-name> ::= aa    # &&\n//                   ::= ad    # & (unary)\n//                   ::= an    # &\n//                   ::= aN    # &=\n//                   ::= aS    # =\n//                   ::= cl    # ()\n//                   ::= cm    # ,\n//                   ::= co    # ~\n//                   ::= cv <type>    # (cast)\n//                   ::= da    # delete[]\n//                   ::= de    # * (unary)\n//                   ::= dl    # delete\n//                   ::= dv    # /\n//                   ::= dV    # /=\n//                   ::= eo    # ^\n//                   ::= eO    # ^=\n//                   ::= eq    # ==\n//                   ::= ge    # >=\n//                   ::= gt    # >\n//                   ::= ix    # []\n//                   ::= le    # <=\n//                   ::= li <source-name>  # operator \"\"\n//                   ::= ls    # <<\n//                   ::= lS    # <<=\n//                   ::= lt    # <\n//                   ::= mi    # -\n//                   ::= mI    # -=\n//                   ::= ml    # *\n//                   ::= mL    # *=\n//                   ::= mm    # -- (postfix in <expression> context)\n//                   ::= na    # new[]\n//                   ::= ne    # !=\n//                   ::= ng    # - (unary)\n//                   ::= nt    # !\n//                   ::= nw    # new\n//                   ::= oo    # ||\n//                   ::= or    # |\n//                   ::= oR    # |=\n//                   ::= pm    # ->*\n//                   ::= pl    # +\n//                   ::= pL    # +=\n//                   ::= pp    # ++ (postfix in <expression> context)\n//                   ::= ps    # + (unary)\n//                   ::= pt    # ->\n//                   ::= qu    # ?\n//                   ::= rm    # %\n//                   ::= rM    # %=\n//                   ::= rs    # >>\n//                   ::= rS    # >>=\n//                   ::= ss    # <=> C++2a\n//                   ::= v <digit> <source-name>        # vendor extended operator\ntemplate<typename Alloc> Node *Db<Alloc>::parseOperatorName(NameState *State) {\n  switch (look()) {\n  case 'a':\n    switch (look(1)) {\n    case 'a':\n      First += 2;\n      return make<NameType>(\"operator&&\");\n    case 'd':\n    case 'n':\n      First += 2;\n      return make<NameType>(\"operator&\");\n    case 'N':\n      First += 2;\n      return make<NameType>(\"operator&=\");\n    case 'S':\n      First += 2;\n      return make<NameType>(\"operator=\");\n    }\n    return nullptr;\n  case 'c':\n    switch (look(1)) {\n    case 'l':\n      First += 2;\n      return make<NameType>(\"operator()\");\n    case 'm':\n      First += 2;\n      return make<NameType>(\"operator,\");\n    case 'o':\n      First += 2;\n      return make<NameType>(\"operator~\");\n    //                   ::= cv <type>    # (cast)\n    case 'v': {\n      First += 2;\n      SwapAndRestore<bool> SaveTemplate(TryToParseTemplateArgs, false);\n      // If we're parsing an encoding, State != nullptr and the conversion\n      // operators' <type> could have a <template-param> that refers to some\n      // <template-arg>s further ahead in the mangled name.\n      SwapAndRestore<bool> SavePermit(PermitForwardTemplateReferences,\n                                      PermitForwardTemplateReferences ||\n                                          State != nullptr);\n      Node* Ty = parseType();\n      if (Ty == nullptr)\n        return nullptr;\n      if (State) State->CtorDtorConversion = true;\n      return make<ConversionOperatorType>(Ty);\n    }\n    }\n    return nullptr;\n  case 'd':\n    switch (look(1)) {\n    case 'a':\n      First += 2;\n      return make<NameType>(\"operator delete[]\");\n    case 'e':\n      First += 2;\n      return make<NameType>(\"operator*\");\n    case 'l':\n      First += 2;\n      return make<NameType>(\"operator delete\");\n    case 'v':\n      First += 2;\n      return make<NameType>(\"operator/\");\n    case 'V':\n      First += 2;\n      return make<NameType>(\"operator/=\");\n    }\n    return nullptr;\n  case 'e':\n    switch (look(1)) {\n    case 'o':\n      First += 2;\n      return make<NameType>(\"operator^\");\n    case 'O':\n      First += 2;\n      return make<NameType>(\"operator^=\");\n    case 'q':\n      First += 2;\n      return make<NameType>(\"operator==\");\n    }\n    return nullptr;\n  case 'g':\n    switch (look(1)) {\n    case 'e':\n      First += 2;\n      return make<NameType>(\"operator>=\");\n    case 't':\n      First += 2;\n      return make<NameType>(\"operator>\");\n    }\n    return nullptr;\n  case 'i':\n    if (look(1) == 'x') {\n      First += 2;\n      return make<NameType>(\"operator[]\");\n    }\n    return nullptr;\n  case 'l':\n    switch (look(1)) {\n    case 'e':\n      First += 2;\n      return make<NameType>(\"operator<=\");\n    //                   ::= li <source-name>  # operator \"\"\n    case 'i': {\n      First += 2;\n      Node *SN = parseSourceName(State);\n      if (SN == nullptr)\n        return nullptr;\n      return make<LiteralOperator>(SN);\n    }\n    case 's':\n      First += 2;\n      return make<NameType>(\"operator<<\");\n    case 'S':\n      First += 2;\n      return make<NameType>(\"operator<<=\");\n    case 't':\n      First += 2;\n      return make<NameType>(\"operator<\");\n    }\n    return nullptr;\n  case 'm':\n    switch (look(1)) {\n    case 'i':\n      First += 2;\n      return make<NameType>(\"operator-\");\n    case 'I':\n      First += 2;\n      return make<NameType>(\"operator-=\");\n    case 'l':\n      First += 2;\n      return make<NameType>(\"operator*\");\n    case 'L':\n      First += 2;\n      return make<NameType>(\"operator*=\");\n    case 'm':\n      First += 2;\n      return make<NameType>(\"operator--\");\n    }\n    return nullptr;\n  case 'n':\n    switch (look(1)) {\n    case 'a':\n      First += 2;\n      return make<NameType>(\"operator new[]\");\n    case 'e':\n      First += 2;\n      return make<NameType>(\"operator!=\");\n    case 'g':\n      First += 2;\n      return make<NameType>(\"operator-\");\n    case 't':\n      First += 2;\n      return make<NameType>(\"operator!\");\n    case 'w':\n      First += 2;\n      return make<NameType>(\"operator new\");\n    }\n    return nullptr;\n  case 'o':\n    switch (look(1)) {\n    case 'o':\n      First += 2;\n      return make<NameType>(\"operator||\");\n    case 'r':\n      First += 2;\n      return make<NameType>(\"operator|\");\n    case 'R':\n      First += 2;\n      return make<NameType>(\"operator|=\");\n    }\n    return nullptr;\n  case 'p':\n    switch (look(1)) {\n    case 'm':\n      First += 2;\n      return make<NameType>(\"operator->*\");\n    case 'l':\n      First += 2;\n      return make<NameType>(\"operator+\");\n    case 'L':\n      First += 2;\n      return make<NameType>(\"operator+=\");\n    case 'p':\n      First += 2;\n      return make<NameType>(\"operator++\");\n    case 's':\n      First += 2;\n      return make<NameType>(\"operator+\");\n    case 't':\n      First += 2;\n      return make<NameType>(\"operator->\");\n    }\n    return nullptr;\n  case 'q':\n    if (look(1) == 'u') {\n      First += 2;\n      return make<NameType>(\"operator?\");\n    }\n    return nullptr;\n  case 'r':\n    switch (look(1)) {\n    case 'm':\n      First += 2;\n      return make<NameType>(\"operator%\");\n    case 'M':\n      First += 2;\n      return make<NameType>(\"operator%=\");\n    case 's':\n      First += 2;\n      return make<NameType>(\"operator>>\");\n    case 'S':\n      First += 2;\n      return make<NameType>(\"operator>>=\");\n    }\n    return nullptr;\n  case 's':\n    if (look(1) == 's') {\n      First += 2;\n      return make<NameType>(\"operator<=>\");\n    }\n    return nullptr;\n  // ::= v <digit> <source-name>        # vendor extended operator\n  case 'v':\n    if (std::isdigit(look(1))) {\n      First += 2;\n      Node *SN = parseSourceName(State);\n      if (SN == nullptr)\n        return nullptr;\n      return make<ConversionOperatorType>(SN);\n    }\n    return nullptr;\n  }\n  return nullptr;\n}\n\n// <ctor-dtor-name> ::= C1  # complete object constructor\n//                  ::= C2  # base object constructor\n//                  ::= C3  # complete object allocating constructor\n//   extension      ::= C5    # ?\n//                  ::= D0  # deleting destructor\n//                  ::= D1  # complete object destructor\n//                  ::= D2  # base object destructor\n//   extension      ::= D5    # ?\ntemplate<typename Alloc>\nNode *Db<Alloc>::parseCtorDtorName(Node *&SoFar, NameState *State) {\n  if (SoFar->getKind() == Node::KSpecialSubstitution) {\n    auto SSK = static_cast<SpecialSubstitution *>(SoFar)->SSK;\n    switch (SSK) {\n    case SpecialSubKind::string:\n    case SpecialSubKind::istream:\n    case SpecialSubKind::ostream:\n    case SpecialSubKind::iostream:\n      SoFar = make<ExpandedSpecialSubstitution>(SSK);\n      if (!SoFar)\n        return nullptr;\n    default:\n      break;\n    }\n  }\n\n  if (consumeIf('C')) {\n    bool IsInherited = consumeIf('I');\n    if (look() != '1' && look() != '2' && look() != '3' && look() != '5')\n      return nullptr;\n    int Variant = look() - '0';\n    ++First;\n    if (State) State->CtorDtorConversion = true;\n    if (IsInherited) {\n      if (parseName(State) == nullptr)\n        return nullptr;\n    }\n    return make<CtorDtorName>(SoFar, false, Variant);\n  }\n\n  if (look() == 'D' &&\n      (look(1) == '0' || look(1) == '1' || look(1) == '2' || look(1) == '5')) {\n    int Variant = look(1) - '0';\n    First += 2;\n    if (State) State->CtorDtorConversion = true;\n    return make<CtorDtorName>(SoFar, true, Variant);\n  }\n\n  return nullptr;\n}\n\n// <nested-name> ::= N [<CV-Qualifiers>] [<ref-qualifier>] <prefix> <unqualified-name> E\n//               ::= N [<CV-Qualifiers>] [<ref-qualifier>] <template-prefix> <template-args> E\n//\n// <prefix> ::= <prefix> <unqualified-name>\n//          ::= <template-prefix> <template-args>\n//          ::= <template-param>\n//          ::= <decltype>\n//          ::= # empty\n//          ::= <substitution>\n//          ::= <prefix> <data-member-prefix>\n//  extension ::= L\n//\n// <data-member-prefix> := <member source-name> [<template-args>] M\n//\n// <template-prefix> ::= <prefix> <template unqualified-name>\n//                   ::= <template-param>\n//                   ::= <substitution>\ntemplate<typename Alloc> Node *Db<Alloc>::parseNestedName(NameState *State) {\n  if (!consumeIf('N'))\n    return nullptr;\n\n  Qualifiers CVTmp = parseCVQualifiers();\n  if (State) State->CVQualifiers = CVTmp;\n\n  if (consumeIf('O')) {\n    if (State) State->ReferenceQualifier = FrefQualRValue;\n  } else if (consumeIf('R')) {\n    if (State) State->ReferenceQualifier = FrefQualLValue;\n  } else\n    if (State) State->ReferenceQualifier = FrefQualNone;\n\n  Node *SoFar = nullptr;\n  auto PushComponent = [&](Node *Comp) {\n    if (!Comp) return false;\n    if (SoFar) SoFar = make<NestedName>(SoFar, Comp);\n    else       SoFar = Comp;\n    if (State) State->EndsWithTemplateArgs = false;\n    return SoFar != nullptr;\n  };\n\n  if (consumeIf(\"St\")) {\n    SoFar = make<NameType>(\"std\");\n    if (!SoFar)\n      return nullptr;\n  }\n\n  while (!consumeIf('E')) {\n    consumeIf('L'); // extension\n\n    // <data-member-prefix> := <member source-name> [<template-args>] M\n    if (consumeIf('M')) {\n      if (SoFar == nullptr)\n        return nullptr;\n      continue;\n    }\n\n    //          ::= <template-param>\n    if (look() == 'T') {\n      if (!PushComponent(parseTemplateParam()))\n        return nullptr;\n      Subs.push_back(SoFar);\n      continue;\n    }\n\n    //          ::= <template-prefix> <template-args>\n    if (look() == 'I') {\n      Node *TA = parseTemplateArgs(State != nullptr);\n      if (TA == nullptr || SoFar == nullptr)\n        return nullptr;\n      SoFar = make<NameWithTemplateArgs>(SoFar, TA);\n      if (!SoFar)\n        return nullptr;\n      if (State) State->EndsWithTemplateArgs = true;\n      Subs.push_back(SoFar);\n      continue;\n    }\n\n    //          ::= <decltype>\n    if (look() == 'D' && (look(1) == 't' || look(1) == 'T')) {\n      if (!PushComponent(parseDecltype()))\n        return nullptr;\n      Subs.push_back(SoFar);\n      continue;\n    }\n\n    //          ::= <substitution>\n    if (look() == 'S' && look(1) != 't') {\n      Node *S = parseSubstitution();\n      if (!PushComponent(S))\n        return nullptr;\n      if (SoFar != S)\n        Subs.push_back(S);\n      continue;\n    }\n\n    // Parse an <unqualified-name> thats actually a <ctor-dtor-name>.\n    if (look() == 'C' || (look() == 'D' && look(1) != 'C')) {\n      if (SoFar == nullptr)\n        return nullptr;\n      if (!PushComponent(parseCtorDtorName(SoFar, State)))\n        return nullptr;\n      SoFar = parseAbiTags(SoFar);\n      if (SoFar == nullptr)\n        return nullptr;\n      Subs.push_back(SoFar);\n      continue;\n    }\n\n    //          ::= <prefix> <unqualified-name>\n    if (!PushComponent(parseUnqualifiedName(State)))\n      return nullptr;\n    Subs.push_back(SoFar);\n  }\n\n  if (SoFar == nullptr || Subs.empty())\n    return nullptr;\n\n  Subs.pop_back();\n  return SoFar;\n}\n\n// <simple-id> ::= <source-name> [ <template-args> ]\ntemplate<typename Alloc> Node *Db<Alloc>::parseSimpleId() {\n  Node *SN = parseSourceName(/*NameState=*/nullptr);\n  if (SN == nullptr)\n    return nullptr;\n  if (look() == 'I') {\n    Node *TA = parseTemplateArgs();\n    if (TA == nullptr)\n      return nullptr;\n    return make<NameWithTemplateArgs>(SN, TA);\n  }\n  return SN;\n}\n\n// <destructor-name> ::= <unresolved-type>  # e.g., ~T or ~decltype(f())\n//                   ::= <simple-id>        # e.g., ~A<2*N>\ntemplate<typename Alloc> Node *Db<Alloc>::parseDestructorName() {\n  Node *Result;\n  if (std::isdigit(look()))\n    Result = parseSimpleId();\n  else\n    Result = parseUnresolvedType();\n  if (Result == nullptr)\n    return nullptr;\n  return make<DtorName>(Result);\n}\n\n// <unresolved-type> ::= <template-param>\n//                   ::= <decltype>\n//                   ::= <substitution>\ntemplate<typename Alloc> Node *Db<Alloc>::parseUnresolvedType() {\n  if (look() == 'T') {\n    Node *TP = parseTemplateParam();\n    if (TP == nullptr)\n      return nullptr;\n    Subs.push_back(TP);\n    return TP;\n  }\n  if (look() == 'D') {\n    Node *DT = parseDecltype();\n    if (DT == nullptr)\n      return nullptr;\n    Subs.push_back(DT);\n    return DT;\n  }\n  return parseSubstitution();\n}\n\n// <base-unresolved-name> ::= <simple-id>                                # unresolved name\n//          extension     ::= <operator-name>                            # unresolved operator-function-id\n//          extension     ::= <operator-name> <template-args>            # unresolved operator template-id\n//                        ::= on <operator-name>                         # unresolved operator-function-id\n//                        ::= on <operator-name> <template-args>         # unresolved operator template-id\n//                        ::= dn <destructor-name>                       # destructor or pseudo-destructor;\n//                                                                         # e.g. ~X or ~X<N-1>\ntemplate<typename Alloc> Node *Db<Alloc>::parseBaseUnresolvedName() {\n  if (std::isdigit(look()))\n    return parseSimpleId();\n\n  if (consumeIf(\"dn\"))\n    return parseDestructorName();\n\n  consumeIf(\"on\");\n\n  Node *Oper = parseOperatorName(/*NameState=*/nullptr);\n  if (Oper == nullptr)\n    return nullptr;\n  if (look() == 'I') {\n    Node *TA = parseTemplateArgs();\n    if (TA == nullptr)\n      return nullptr;\n    return make<NameWithTemplateArgs>(Oper, TA);\n  }\n  return Oper;\n}\n\n// <unresolved-name>\n//  extension        ::= srN <unresolved-type> [<template-args>] <unresolved-qualifier-level>* E <base-unresolved-name>\n//                   ::= [gs] <base-unresolved-name>                     # x or (with \"gs\") ::x\n//                   ::= [gs] sr <unresolved-qualifier-level>+ E <base-unresolved-name>\n//                                                                       # A::x, N::y, A<T>::z; \"gs\" means leading \"::\"\n//                   ::= sr <unresolved-type> <base-unresolved-name>     # T::x / decltype(p)::x\n//  extension        ::= sr <unresolved-type> <template-args> <base-unresolved-name>\n//                                                                       # T::N::x /decltype(p)::N::x\n//  (ignored)        ::= srN <unresolved-type>  <unresolved-qualifier-level>+ E <base-unresolved-name>\n//\n// <unresolved-qualifier-level> ::= <simple-id>\ntemplate<typename Alloc> Node *Db<Alloc>::parseUnresolvedName() {\n  Node *SoFar = nullptr;\n\n  // srN <unresolved-type> [<template-args>] <unresolved-qualifier-level>* E <base-unresolved-name>\n  // srN <unresolved-type>                   <unresolved-qualifier-level>+ E <base-unresolved-name>\n  if (consumeIf(\"srN\")) {\n    SoFar = parseUnresolvedType();\n    if (SoFar == nullptr)\n      return nullptr;\n\n    if (look() == 'I') {\n      Node *TA = parseTemplateArgs();\n      if (TA == nullptr)\n        return nullptr;\n      SoFar = make<NameWithTemplateArgs>(SoFar, TA);\n      if (!SoFar)\n        return nullptr;\n    }\n\n    while (!consumeIf('E')) {\n      Node *Qual = parseSimpleId();\n      if (Qual == nullptr)\n        return nullptr;\n      SoFar = make<QualifiedName>(SoFar, Qual);\n      if (!SoFar)\n        return nullptr;\n    }\n\n    Node *Base = parseBaseUnresolvedName();\n    if (Base == nullptr)\n      return nullptr;\n    return make<QualifiedName>(SoFar, Base);\n  }\n\n  bool Global = consumeIf(\"gs\");\n\n  // [gs] <base-unresolved-name>                     # x or (with \"gs\") ::x\n  if (!consumeIf(\"sr\")) {\n    SoFar = parseBaseUnresolvedName();\n    if (SoFar == nullptr)\n      return nullptr;\n    if (Global)\n      SoFar = make<GlobalQualifiedName>(SoFar);\n    return SoFar;\n  }\n\n  // [gs] sr <unresolved-qualifier-level>+ E   <base-unresolved-name>\n  if (std::isdigit(look())) {\n    do {\n      Node *Qual = parseSimpleId();\n      if (Qual == nullptr)\n        return nullptr;\n      if (SoFar)\n        SoFar = make<QualifiedName>(SoFar, Qual);\n      else if (Global)\n        SoFar = make<GlobalQualifiedName>(Qual);\n      else\n        SoFar = Qual;\n      if (!SoFar)\n        return nullptr;\n    } while (!consumeIf('E'));\n  }\n  //      sr <unresolved-type>                 <base-unresolved-name>\n  //      sr <unresolved-type> <template-args> <base-unresolved-name>\n  else {\n    SoFar = parseUnresolvedType();\n    if (SoFar == nullptr)\n      return nullptr;\n\n    if (look() == 'I') {\n      Node *TA = parseTemplateArgs();\n      if (TA == nullptr)\n        return nullptr;\n      SoFar = make<NameWithTemplateArgs>(SoFar, TA);\n      if (!SoFar)\n        return nullptr;\n    }\n  }\n\n  assert(SoFar != nullptr);\n\n  Node *Base = parseBaseUnresolvedName();\n  if (Base == nullptr)\n    return nullptr;\n  return make<QualifiedName>(SoFar, Base);\n}\n\n// <abi-tags> ::= <abi-tag> [<abi-tags>]\n// <abi-tag> ::= B <source-name>\ntemplate<typename Alloc> Node *Db<Alloc>::parseAbiTags(Node *N) {\n  while (consumeIf('B')) {\n    StringView SN = parseBareSourceName();\n    if (SN.empty())\n      return nullptr;\n    N = make<AbiTagAttr>(N, SN);\n    if (!N)\n      return nullptr;\n  }\n  return N;\n}\n\n// <number> ::= [n] <non-negative decimal integer>\ntemplate<typename Alloc>\nStringView Db<Alloc>::parseNumber(bool AllowNegative) {\n  const char *Tmp = First;\n  if (AllowNegative)\n    consumeIf('n');\n  if (numLeft() == 0 || !std::isdigit(*First))\n    return StringView();\n  while (numLeft() != 0 && std::isdigit(*First))\n    ++First;\n  return StringView(Tmp, First);\n}\n\n// <positive length number> ::= [0-9]*\ntemplate<typename Alloc> bool Db<Alloc>::parsePositiveInteger(size_t *Out) {\n  *Out = 0;\n  if (look() < '0' || look() > '9')\n    return true;\n  while (look() >= '0' && look() <= '9') {\n    *Out *= 10;\n    *Out += static_cast<size_t>(consume() - '0');\n  }\n  return false;\n}\n\ntemplate<typename Alloc> StringView Db<Alloc>::parseBareSourceName() {\n  size_t Int = 0;\n  if (parsePositiveInteger(&Int) || numLeft() < Int)\n    return StringView();\n  StringView R(First, First + Int);\n  First += Int;\n  return R;\n}\n\n// <function-type> ::= [<CV-qualifiers>] [<exception-spec>] [Dx] F [Y] <bare-function-type> [<ref-qualifier>] E\n//\n// <exception-spec> ::= Do                # non-throwing exception-specification (e.g., noexcept, throw())\n//                  ::= DO <expression> E # computed (instantiation-dependent) noexcept\n//                  ::= Dw <type>+ E      # dynamic exception specification with instantiation-dependent types\n//\n// <ref-qualifier> ::= R                   # & ref-qualifier\n// <ref-qualifier> ::= O                   # && ref-qualifier\ntemplate<typename Alloc> Node *Db<Alloc>::parseFunctionType() {\n  Qualifiers CVQuals = parseCVQualifiers();\n\n  Node *ExceptionSpec = nullptr;\n  if (consumeIf(\"Do\")) {\n    ExceptionSpec = make<NameType>(\"noexcept\");\n    if (!ExceptionSpec)\n      return nullptr;\n  } else if (consumeIf(\"DO\")) {\n    Node *E = parseExpr();\n    if (E == nullptr || !consumeIf('E'))\n      return nullptr;\n    ExceptionSpec = make<NoexceptSpec>(E);\n    if (!ExceptionSpec)\n      return nullptr;\n  } else if (consumeIf(\"Dw\")) {\n    size_t SpecsBegin = Names.size();\n    while (!consumeIf('E')) {\n      Node *T = parseType();\n      if (T == nullptr)\n        return nullptr;\n      Names.push_back(T);\n    }\n    ExceptionSpec =\n      make<DynamicExceptionSpec>(popTrailingNodeArray(SpecsBegin));\n    if (!ExceptionSpec)\n      return nullptr;\n  }\n\n  consumeIf(\"Dx\"); // transaction safe\n\n  if (!consumeIf('F'))\n    return nullptr;\n  consumeIf('Y'); // extern \"C\"\n  Node *ReturnType = parseType();\n  if (ReturnType == nullptr)\n    return nullptr;\n\n  FunctionRefQual ReferenceQualifier = FrefQualNone;\n  size_t ParamsBegin = Names.size();\n  while (true) {\n    if (consumeIf('E'))\n      break;\n    if (consumeIf('v'))\n      continue;\n    if (consumeIf(\"RE\")) {\n      ReferenceQualifier = FrefQualLValue;\n      break;\n    }\n    if (consumeIf(\"OE\")) {\n      ReferenceQualifier = FrefQualRValue;\n      break;\n    }\n    Node *T = parseType();\n    if (T == nullptr)\n      return nullptr;\n    Names.push_back(T);\n  }\n\n  NodeArray Params = popTrailingNodeArray(ParamsBegin);\n  return make<FunctionType>(ReturnType, Params, CVQuals,\n                            ReferenceQualifier, ExceptionSpec);\n}\n\n// extension:\n// <vector-type>           ::= Dv <positive dimension number> _ <extended element type>\n//                         ::= Dv [<dimension expression>] _ <element type>\n// <extended element type> ::= <element type>\n//                         ::= p # AltiVec vector pixel\ntemplate<typename Alloc> Node *Db<Alloc>::parseVectorType() {\n  if (!consumeIf(\"Dv\"))\n    return nullptr;\n  if (look() >= '1' && look() <= '9') {\n    StringView DimensionNumber = parseNumber();\n    if (!consumeIf('_'))\n      return nullptr;\n    if (consumeIf('p'))\n      return make<PixelVectorType>(DimensionNumber);\n    Node *ElemType = parseType();\n    if (ElemType == nullptr)\n      return nullptr;\n    return make<VectorType>(ElemType, DimensionNumber);\n  }\n\n  if (!consumeIf('_')) {\n    Node *DimExpr = parseExpr();\n    if (!DimExpr)\n      return nullptr;\n    if (!consumeIf('_'))\n      return nullptr;\n    Node *ElemType = parseType();\n    if (!ElemType)\n      return nullptr;\n    return make<VectorType>(ElemType, DimExpr);\n  }\n  Node *ElemType = parseType();\n  if (!ElemType)\n    return nullptr;\n  return make<VectorType>(ElemType, StringView());\n}\n\n// <decltype>  ::= Dt <expression> E  # decltype of an id-expression or class member access (C++0x)\n//             ::= DT <expression> E  # decltype of an expression (C++0x)\ntemplate<typename Alloc> Node *Db<Alloc>::parseDecltype() {\n  if (!consumeIf('D'))\n    return nullptr;\n  if (!consumeIf('t') && !consumeIf('T'))\n    return nullptr;\n  Node *E = parseExpr();\n  if (E == nullptr)\n    return nullptr;\n  if (!consumeIf('E'))\n    return nullptr;\n  return make<EnclosingExpr>(\"decltype(\", E, \")\");\n}\n\n// <array-type> ::= A <positive dimension number> _ <element type>\n//              ::= A [<dimension expression>] _ <element type>\ntemplate<typename Alloc> Node *Db<Alloc>::parseArrayType() {\n  if (!consumeIf('A'))\n    return nullptr;\n\n  NodeOrString Dimension;\n\n  if (std::isdigit(look())) {\n    Dimension = parseNumber();\n    if (!consumeIf('_'))\n      return nullptr;\n  } else if (!consumeIf('_')) {\n    Node *DimExpr = parseExpr();\n    if (DimExpr == nullptr)\n      return nullptr;\n    if (!consumeIf('_'))\n      return nullptr;\n    Dimension = DimExpr;\n  }\n\n  Node *Ty = parseType();\n  if (Ty == nullptr)\n    return nullptr;\n  return make<ArrayType>(Ty, Dimension);\n}\n\n// <pointer-to-member-type> ::= M <class type> <member type>\ntemplate<typename Alloc> Node *Db<Alloc>::parsePointerToMemberType() {\n  if (!consumeIf('M'))\n    return nullptr;\n  Node *ClassType = parseType();\n  if (ClassType == nullptr)\n    return nullptr;\n  Node *MemberType = parseType();\n  if (MemberType == nullptr)\n    return nullptr;\n  return make<PointerToMemberType>(ClassType, MemberType);\n}\n\n// <class-enum-type> ::= <name>     # non-dependent type name, dependent type name, or dependent typename-specifier\n//                   ::= Ts <name>  # dependent elaborated type specifier using 'struct' or 'class'\n//                   ::= Tu <name>  # dependent elaborated type specifier using 'union'\n//                   ::= Te <name>  # dependent elaborated type specifier using 'enum'\ntemplate<typename Alloc> Node *Db<Alloc>::parseClassEnumType() {\n  StringView ElabSpef;\n  if (consumeIf(\"Ts\"))\n    ElabSpef = \"struct\";\n  else if (consumeIf(\"Tu\"))\n    ElabSpef = \"union\";\n  else if (consumeIf(\"Te\"))\n    ElabSpef = \"enum\";\n\n  Node *Name = parseName();\n  if (Name == nullptr)\n    return nullptr;\n\n  if (!ElabSpef.empty())\n    return make<ElaboratedTypeSpefType>(ElabSpef, Name);\n\n  return Name;\n}\n\n// <qualified-type>     ::= <qualifiers> <type>\n// <qualifiers> ::= <extended-qualifier>* <CV-qualifiers>\n// <extended-qualifier> ::= U <source-name> [<template-args>] # vendor extended type qualifier\ntemplate<typename Alloc> Node *Db<Alloc>::parseQualifiedType() {\n  if (consumeIf('U')) {\n    StringView Qual = parseBareSourceName();\n    if (Qual.empty())\n      return nullptr;\n\n    // FIXME parse the optional <template-args> here!\n\n    // extension            ::= U <objc-name> <objc-type>  # objc-type<identifier>\n    if (Qual.startsWith(\"objcproto\")) {\n      StringView ProtoSourceName = Qual.dropFront(std::strlen(\"objcproto\"));\n      StringView Proto;\n      {\n        SwapAndRestore<const char *> SaveFirst(First, ProtoSourceName.begin()),\n                                     SaveLast(Last, ProtoSourceName.end());\n        Proto = parseBareSourceName();\n      }\n      if (Proto.empty())\n        return nullptr;\n      Node *Child = parseQualifiedType();\n      if (Child == nullptr)\n        return nullptr;\n      return make<ObjCProtoName>(Child, Proto);\n    }\n\n    Node *Child = parseQualifiedType();\n    if (Child == nullptr)\n      return nullptr;\n    return make<VendorExtQualType>(Child, Qual);\n  }\n\n  Qualifiers Quals = parseCVQualifiers();\n  Node *Ty = parseType();\n  if (Ty == nullptr)\n    return nullptr;\n  if (Quals != QualNone)\n    Ty = make<QualType>(Ty, Quals);\n  return Ty;\n}\n\n// <type>      ::= <builtin-type>\n//             ::= <qualified-type>\n//             ::= <function-type>\n//             ::= <class-enum-type>\n//             ::= <array-type>\n//             ::= <pointer-to-member-type>\n//             ::= <template-param>\n//             ::= <template-template-param> <template-args>\n//             ::= <decltype>\n//             ::= P <type>        # pointer\n//             ::= R <type>        # l-value reference\n//             ::= O <type>        # r-value reference (C++11)\n//             ::= C <type>        # complex pair (C99)\n//             ::= G <type>        # imaginary (C99)\n//             ::= <substitution>  # See Compression below\n// extension   ::= U <objc-name> <objc-type>  # objc-type<identifier>\n// extension   ::= <vector-type> # <vector-type> starts with Dv\n//\n// <objc-name> ::= <k0 number> objcproto <k1 number> <identifier>  # k0 = 9 + <number of digits in k1> + k1\n// <objc-type> ::= <source-name>  # PU<11+>objcproto 11objc_object<source-name> 11objc_object -> id<source-name>\ntemplate<typename Alloc> Node *Db<Alloc>::parseType() {\n  Node *Result = nullptr;\n\n  if (TypeCallback != nullptr)\n    TypeCallback(TypeCallbackContext, First);\n\n  switch (look()) {\n  //             ::= <qualified-type>\n  case 'r':\n  case 'V':\n  case 'K': {\n    unsigned AfterQuals = 0;\n    if (look(AfterQuals) == 'r') ++AfterQuals;\n    if (look(AfterQuals) == 'V') ++AfterQuals;\n    if (look(AfterQuals) == 'K') ++AfterQuals;\n\n    if (look(AfterQuals) == 'F' ||\n        (look(AfterQuals) == 'D' &&\n         (look(AfterQuals + 1) == 'o' || look(AfterQuals + 1) == 'O' ||\n          look(AfterQuals + 1) == 'w' || look(AfterQuals + 1) == 'x'))) {\n      Result = parseFunctionType();\n      break;\n    }\n    LLVM_FALLTHROUGH;\n  }\n  case 'U': {\n    Result = parseQualifiedType();\n    break;\n  }\n  // <builtin-type> ::= v    # void\n  case 'v':\n    ++First;\n    return make<NameType>(\"void\");\n  //                ::= w    # wchar_t\n  case 'w':\n    ++First;\n    return make<NameType>(\"wchar_t\");\n  //                ::= b    # bool\n  case 'b':\n    ++First;\n    return make<NameType>(\"bool\");\n  //                ::= c    # char\n  case 'c':\n    ++First;\n    return make<NameType>(\"char\");\n  //                ::= a    # signed char\n  case 'a':\n    ++First;\n    return make<NameType>(\"signed char\");\n  //                ::= h    # unsigned char\n  case 'h':\n    ++First;\n    return make<NameType>(\"unsigned char\");\n  //                ::= s    # short\n  case 's':\n    ++First;\n    return make<NameType>(\"short\");\n  //                ::= t    # unsigned short\n  case 't':\n    ++First;\n    return make<NameType>(\"unsigned short\");\n  //                ::= i    # int\n  case 'i':\n    ++First;\n    return make<NameType>(\"int\");\n  //                ::= j    # unsigned int\n  case 'j':\n    ++First;\n    return make<NameType>(\"unsigned int\");\n  //                ::= l    # long\n  case 'l':\n    ++First;\n    return make<NameType>(\"long\");\n  //                ::= m    # unsigned long\n  case 'm':\n    ++First;\n    return make<NameType>(\"unsigned long\");\n  //                ::= x    # long long, __int64\n  case 'x':\n    ++First;\n    return make<NameType>(\"long long\");\n  //                ::= y    # unsigned long long, __int64\n  case 'y':\n    ++First;\n    return make<NameType>(\"unsigned long long\");\n  //                ::= n    # __int128\n  case 'n':\n    ++First;\n    return make<NameType>(\"__int128\");\n  //                ::= o    # unsigned __int128\n  case 'o':\n    ++First;\n    return make<NameType>(\"unsigned __int128\");\n  //                ::= f    # float\n  case 'f':\n    ++First;\n    return make<NameType>(\"float\");\n  //                ::= d    # double\n  case 'd':\n    ++First;\n    return make<NameType>(\"double\");\n  //                ::= e    # long double, __float80\n  case 'e':\n    ++First;\n    return make<NameType>(\"long double\");\n  //                ::= g    # __float128\n  case 'g':\n    ++First;\n    return make<NameType>(\"__float128\");\n  //                ::= z    # ellipsis\n  case 'z':\n    ++First;\n    return make<NameType>(\"...\");\n\n  // <builtin-type> ::= u <source-name>    # vendor extended type\n  case 'u': {\n    ++First;\n    StringView Res = parseBareSourceName();\n    if (Res.empty())\n      return nullptr;\n    return make<NameType>(Res);\n  }\n  case 'D':\n    switch (look(1)) {\n    //                ::= Dd   # IEEE 754r decimal floating point (64 bits)\n    case 'd':\n      First += 2;\n      return make<NameType>(\"decimal64\");\n    //                ::= De   # IEEE 754r decimal floating point (128 bits)\n    case 'e':\n      First += 2;\n      return make<NameType>(\"decimal128\");\n    //                ::= Df   # IEEE 754r decimal floating point (32 bits)\n    case 'f':\n      First += 2;\n      return make<NameType>(\"decimal32\");\n    //                ::= Dh   # IEEE 754r half-precision floating point (16 bits)\n    case 'h':\n      First += 2;\n      return make<NameType>(\"decimal16\");\n    //                ::= Di   # char32_t\n    case 'i':\n      First += 2;\n      return make<NameType>(\"char32_t\");\n    //                ::= Ds   # char16_t\n    case 's':\n      First += 2;\n      return make<NameType>(\"char16_t\");\n    //                ::= Da   # auto (in dependent new-expressions)\n    case 'a':\n      First += 2;\n      return make<NameType>(\"auto\");\n    //                ::= Dc   # decltype(auto)\n    case 'c':\n      First += 2;\n      return make<NameType>(\"decltype(auto)\");\n    //                ::= Dn   # std::nullptr_t (i.e., decltype(nullptr))\n    case 'n':\n      First += 2;\n      return make<NameType>(\"std::nullptr_t\");\n\n    //             ::= <decltype>\n    case 't':\n    case 'T': {\n      Result = parseDecltype();\n      break;\n    }\n    // extension   ::= <vector-type> # <vector-type> starts with Dv\n    case 'v': {\n      Result = parseVectorType();\n      break;\n    }\n    //           ::= Dp <type>       # pack expansion (C++0x)\n    case 'p': {\n      First += 2;\n      Node *Child = parseType();\n      if (!Child)\n        return nullptr;\n      Result = make<ParameterPackExpansion>(Child);\n      break;\n    }\n    // Exception specifier on a function type.\n    case 'o':\n    case 'O':\n    case 'w':\n    // Transaction safe function type.\n    case 'x':\n      Result = parseFunctionType();\n      break;\n    }\n    break;\n  //             ::= <function-type>\n  case 'F': {\n    Result = parseFunctionType();\n    break;\n  }\n  //             ::= <array-type>\n  case 'A': {\n    Result = parseArrayType();\n    break;\n  }\n  //             ::= <pointer-to-member-type>\n  case 'M': {\n    Result = parsePointerToMemberType();\n    break;\n  }\n  //             ::= <template-param>\n  case 'T': {\n    // This could be an elaborate type specifier on a <class-enum-type>.\n    if (look(1) == 's' || look(1) == 'u' || look(1) == 'e') {\n      Result = parseClassEnumType();\n      break;\n    }\n\n    Result = parseTemplateParam();\n    if (Result == nullptr)\n      return nullptr;\n\n    // Result could be either of:\n    //   <type>        ::= <template-param>\n    //   <type>        ::= <template-template-param> <template-args>\n    //\n    //   <template-template-param> ::= <template-param>\n    //                             ::= <substitution>\n    //\n    // If this is followed by some <template-args>, and we're permitted to\n    // parse them, take the second production.\n\n    if (TryToParseTemplateArgs && look() == 'I') {\n      Node *TA = parseTemplateArgs();\n      if (TA == nullptr)\n        return nullptr;\n      Result = make<NameWithTemplateArgs>(Result, TA);\n    }\n    break;\n  }\n  //             ::= P <type>        # pointer\n  case 'P': {\n    ++First;\n    Node *Ptr = parseType();\n    if (Ptr == nullptr)\n      return nullptr;\n    Result = make<PointerType>(Ptr);\n    break;\n  }\n  //             ::= R <type>        # l-value reference\n  case 'R': {\n    ++First;\n    Node *Ref = parseType();\n    if (Ref == nullptr)\n      return nullptr;\n    Result = make<ReferenceType>(Ref, ReferenceKind::LValue);\n    break;\n  }\n  //             ::= O <type>        # r-value reference (C++11)\n  case 'O': {\n    ++First;\n    Node *Ref = parseType();\n    if (Ref == nullptr)\n      return nullptr;\n    Result = make<ReferenceType>(Ref, ReferenceKind::RValue);\n    break;\n  }\n  //             ::= C <type>        # complex pair (C99)\n  case 'C': {\n    ++First;\n    Node *P = parseType();\n    if (P == nullptr)\n      return nullptr;\n    Result = make<PostfixQualifiedType>(P, \" complex\");\n    break;\n  }\n  //             ::= G <type>        # imaginary (C99)\n  case 'G': {\n    ++First;\n    Node *P = parseType();\n    if (P == nullptr)\n      return P;\n    Result = make<PostfixQualifiedType>(P, \" imaginary\");\n    break;\n  }\n  //             ::= <substitution>  # See Compression below\n  case 'S': {\n    if (look(1) && look(1) != 't') {\n      Node *Sub = parseSubstitution();\n      if (Sub == nullptr)\n        return nullptr;\n\n      // Sub could be either of:\n      //   <type>        ::= <substitution>\n      //   <type>        ::= <template-template-param> <template-args>\n      //\n      //   <template-template-param> ::= <template-param>\n      //                             ::= <substitution>\n      //\n      // If this is followed by some <template-args>, and we're permitted to\n      // parse them, take the second production.\n\n      if (TryToParseTemplateArgs && look() == 'I') {\n        Node *TA = parseTemplateArgs();\n        if (TA == nullptr)\n          return nullptr;\n        Result = make<NameWithTemplateArgs>(Sub, TA);\n        break;\n      }\n\n      // If all we parsed was a substitution, don't re-insert into the\n      // substitution table.\n      return Sub;\n    }\n    LLVM_FALLTHROUGH;\n  }\n  //        ::= <class-enum-type>\n  default: {\n    Result = parseClassEnumType();\n    break;\n  }\n  }\n\n  // If we parsed a type, insert it into the substitution table. Note that all\n  // <builtin-type>s and <substitution>s have already bailed out, because they\n  // don't get substitutions.\n  if (Result != nullptr)\n    Subs.push_back(Result);\n  return Result;\n}\n\ntemplate<typename Alloc> Node *Db<Alloc>::parsePrefixExpr(StringView Kind) {\n  Node *E = parseExpr();\n  if (E == nullptr)\n    return nullptr;\n  return make<PrefixExpr>(Kind, E);\n}\n\ntemplate<typename Alloc> Node *Db<Alloc>::parseBinaryExpr(StringView Kind) {\n  Node *LHS = parseExpr();\n  if (LHS == nullptr)\n    return nullptr;\n  Node *RHS = parseExpr();\n  if (RHS == nullptr)\n    return nullptr;\n  return make<BinaryExpr>(LHS, Kind, RHS);\n}\n\ntemplate<typename Alloc> Node *Db<Alloc>::parseIntegerLiteral(StringView Lit) {\n  StringView Tmp = parseNumber(true);\n  if (!Tmp.empty() && consumeIf('E'))\n    return make<IntegerLiteral>(Lit, Tmp);\n  return nullptr;\n}\n\n// <CV-Qualifiers> ::= [r] [V] [K]\ntemplate<typename Alloc> Qualifiers Db<Alloc>::parseCVQualifiers() {\n  Qualifiers CVR = QualNone;\n  if (consumeIf('r'))\n    CVR |= QualRestrict;\n  if (consumeIf('V'))\n    CVR |= QualVolatile;\n  if (consumeIf('K'))\n    CVR |= QualConst;\n  return CVR;\n}\n\n// <function-param> ::= fp <top-level CV-Qualifiers> _                                     # L == 0, first parameter\n//                  ::= fp <top-level CV-Qualifiers> <parameter-2 non-negative number> _   # L == 0, second and later parameters\n//                  ::= fL <L-1 non-negative number> p <top-level CV-Qualifiers> _         # L > 0, first parameter\n//                  ::= fL <L-1 non-negative number> p <top-level CV-Qualifiers> <parameter-2 non-negative number> _   # L > 0, second and later parameters\ntemplate<typename Alloc> Node *Db<Alloc>::parseFunctionParam() {\n  if (consumeIf(\"fp\")) {\n    parseCVQualifiers();\n    StringView Num = parseNumber();\n    if (!consumeIf('_'))\n      return nullptr;\n    return make<FunctionParam>(Num);\n  }\n  if (consumeIf(\"fL\")) {\n    if (parseNumber().empty())\n      return nullptr;\n    if (!consumeIf('p'))\n      return nullptr;\n    parseCVQualifiers();\n    StringView Num = parseNumber();\n    if (!consumeIf('_'))\n      return nullptr;\n    return make<FunctionParam>(Num);\n  }\n  return nullptr;\n}\n\n// [gs] nw <expression>* _ <type> E                     # new (expr-list) type\n// [gs] nw <expression>* _ <type> <initializer>         # new (expr-list) type (init)\n// [gs] na <expression>* _ <type> E                     # new[] (expr-list) type\n// [gs] na <expression>* _ <type> <initializer>         # new[] (expr-list) type (init)\n// <initializer> ::= pi <expression>* E                 # parenthesized initialization\ntemplate<typename Alloc> Node *Db<Alloc>::parseNewExpr() {\n  bool Global = consumeIf(\"gs\");\n  bool IsArray = look(1) == 'a';\n  if (!consumeIf(\"nw\") && !consumeIf(\"na\"))\n    return nullptr;\n  size_t Exprs = Names.size();\n  while (!consumeIf('_')) {\n    Node *Ex = parseExpr();\n    if (Ex == nullptr)\n      return nullptr;\n    Names.push_back(Ex);\n  }\n  NodeArray ExprList = popTrailingNodeArray(Exprs);\n  Node *Ty = parseType();\n  if (Ty == nullptr)\n    return Ty;\n  if (consumeIf(\"pi\")) {\n    size_t InitsBegin = Names.size();\n    while (!consumeIf('E')) {\n      Node *Init = parseExpr();\n      if (Init == nullptr)\n        return Init;\n      Names.push_back(Init);\n    }\n    NodeArray Inits = popTrailingNodeArray(InitsBegin);\n    return make<NewExpr>(ExprList, Ty, Inits, Global, IsArray);\n  } else if (!consumeIf('E'))\n    return nullptr;\n  return make<NewExpr>(ExprList, Ty, NodeArray(), Global, IsArray);\n}\n\n// cv <type> <expression>                               # conversion with one argument\n// cv <type> _ <expression>* E                          # conversion with a different number of arguments\ntemplate<typename Alloc> Node *Db<Alloc>::parseConversionExpr() {\n  if (!consumeIf(\"cv\"))\n    return nullptr;\n  Node *Ty;\n  {\n    SwapAndRestore<bool> SaveTemp(TryToParseTemplateArgs, false);\n    Ty = parseType();\n  }\n\n  if (Ty == nullptr)\n    return nullptr;\n\n  if (consumeIf('_')) {\n    size_t ExprsBegin = Names.size();\n    while (!consumeIf('E')) {\n      Node *E = parseExpr();\n      if (E == nullptr)\n        return E;\n      Names.push_back(E);\n    }\n    NodeArray Exprs = popTrailingNodeArray(ExprsBegin);\n    return make<ConversionExpr>(Ty, Exprs);\n  }\n\n  Node *E[1] = {parseExpr()};\n  if (E[0] == nullptr)\n    return nullptr;\n  return make<ConversionExpr>(Ty, makeNodeArray(E, E + 1));\n}\n\n// <expr-primary> ::= L <type> <value number> E                          # integer literal\n//                ::= L <type> <value float> E                           # floating literal\n//                ::= L <string type> E                                  # string literal\n//                ::= L <nullptr type> E                                 # nullptr literal (i.e., \"LDnE\")\n// FIXME:         ::= L <type> <real-part float> _ <imag-part float> E   # complex floating point literal (C 2000)\n//                ::= L <mangled-name> E                                 # external name\ntemplate<typename Alloc> Node *Db<Alloc>::parseExprPrimary() {\n  if (!consumeIf('L'))\n    return nullptr;\n  switch (look()) {\n  case 'w':\n    ++First;\n    return parseIntegerLiteral(\"wchar_t\");\n  case 'b':\n    if (consumeIf(\"b0E\"))\n      return make<BoolExpr>(0);\n    if (consumeIf(\"b1E\"))\n      return make<BoolExpr>(1);\n    return nullptr;\n  case 'c':\n    ++First;\n    return parseIntegerLiteral(\"char\");\n  case 'a':\n    ++First;\n    return parseIntegerLiteral(\"signed char\");\n  case 'h':\n    ++First;\n    return parseIntegerLiteral(\"unsigned char\");\n  case 's':\n    ++First;\n    return parseIntegerLiteral(\"short\");\n  case 't':\n    ++First;\n    return parseIntegerLiteral(\"unsigned short\");\n  case 'i':\n    ++First;\n    return parseIntegerLiteral(\"\");\n  case 'j':\n    ++First;\n    return parseIntegerLiteral(\"u\");\n  case 'l':\n    ++First;\n    return parseIntegerLiteral(\"l\");\n  case 'm':\n    ++First;\n    return parseIntegerLiteral(\"ul\");\n  case 'x':\n    ++First;\n    return parseIntegerLiteral(\"ll\");\n  case 'y':\n    ++First;\n    return parseIntegerLiteral(\"ull\");\n  case 'n':\n    ++First;\n    return parseIntegerLiteral(\"__int128\");\n  case 'o':\n    ++First;\n    return parseIntegerLiteral(\"unsigned __int128\");\n  case 'f':\n    ++First;\n    return parseFloatingLiteral<float>();\n  case 'd':\n    ++First;\n    return parseFloatingLiteral<double>();\n  case 'e':\n    ++First;\n    return parseFloatingLiteral<long double>();\n  case '_':\n    if (consumeIf(\"_Z\")) {\n      Node *R = parseEncoding();\n      if (R != nullptr && consumeIf('E'))\n        return R;\n    }\n    return nullptr;\n  case 'T':\n    // Invalid mangled name per\n    //   http://sourcerytools.com/pipermail/cxx-abi-dev/2011-August/002422.html\n    return nullptr;\n  default: {\n    // might be named type\n    Node *T = parseType();\n    if (T == nullptr)\n      return nullptr;\n    StringView N = parseNumber();\n    if (!N.empty()) {\n      if (!consumeIf('E'))\n        return nullptr;\n      return make<IntegerCastExpr>(T, N);\n    }\n    if (consumeIf('E'))\n      return T;\n    return nullptr;\n  }\n  }\n}\n\n// <braced-expression> ::= <expression>\n//                     ::= di <field source-name> <braced-expression>    # .name = expr\n//                     ::= dx <index expression> <braced-expression>     # [expr] = expr\n//                     ::= dX <range begin expression> <range end expression> <braced-expression>\ntemplate<typename Alloc> Node *Db<Alloc>::parseBracedExpr() {\n  if (look() == 'd') {\n    switch (look(1)) {\n    case 'i': {\n      First += 2;\n      Node *Field = parseSourceName(/*NameState=*/nullptr);\n      if (Field == nullptr)\n        return nullptr;\n      Node *Init = parseBracedExpr();\n      if (Init == nullptr)\n        return nullptr;\n      return make<BracedExpr>(Field, Init, /*isArray=*/false);\n    }\n    case 'x': {\n      First += 2;\n      Node *Index = parseExpr();\n      if (Index == nullptr)\n        return nullptr;\n      Node *Init = parseBracedExpr();\n      if (Init == nullptr)\n        return nullptr;\n      return make<BracedExpr>(Index, Init, /*isArray=*/true);\n    }\n    case 'X': {\n      First += 2;\n      Node *RangeBegin = parseExpr();\n      if (RangeBegin == nullptr)\n        return nullptr;\n      Node *RangeEnd = parseExpr();\n      if (RangeEnd == nullptr)\n        return nullptr;\n      Node *Init = parseBracedExpr();\n      if (Init == nullptr)\n        return nullptr;\n      return make<BracedRangeExpr>(RangeBegin, RangeEnd, Init);\n    }\n    }\n  }\n  return parseExpr();\n}\n\n// (not yet in the spec)\n// <fold-expr> ::= fL <binary-operator-name> <expression> <expression>\n//             ::= fR <binary-operator-name> <expression> <expression>\n//             ::= fl <binary-operator-name> <expression>\n//             ::= fr <binary-operator-name> <expression>\ntemplate<typename Alloc> Node *Db<Alloc>::parseFoldExpr() {\n  if (!consumeIf('f'))\n    return nullptr;\n\n  char FoldKind = look();\n  bool IsLeftFold, HasInitializer;\n  HasInitializer = FoldKind == 'L' || FoldKind == 'R';\n  if (FoldKind == 'l' || FoldKind == 'L')\n    IsLeftFold = true;\n  else if (FoldKind == 'r' || FoldKind == 'R')\n    IsLeftFold = false;\n  else\n    return nullptr;\n  ++First;\n\n  // FIXME: This map is duplicated in parseOperatorName and parseExpr.\n  StringView OperatorName;\n  if      (consumeIf(\"aa\")) OperatorName = \"&&\";\n  else if (consumeIf(\"an\")) OperatorName = \"&\";\n  else if (consumeIf(\"aN\")) OperatorName = \"&=\";\n  else if (consumeIf(\"aS\")) OperatorName = \"=\";\n  else if (consumeIf(\"cm\")) OperatorName = \",\";\n  else if (consumeIf(\"ds\")) OperatorName = \".*\";\n  else if (consumeIf(\"dv\")) OperatorName = \"/\";\n  else if (consumeIf(\"dV\")) OperatorName = \"/=\";\n  else if (consumeIf(\"eo\")) OperatorName = \"^\";\n  else if (consumeIf(\"eO\")) OperatorName = \"^=\";\n  else if (consumeIf(\"eq\")) OperatorName = \"==\";\n  else if (consumeIf(\"ge\")) OperatorName = \">=\";\n  else if (consumeIf(\"gt\")) OperatorName = \">\";\n  else if (consumeIf(\"le\")) OperatorName = \"<=\";\n  else if (consumeIf(\"ls\")) OperatorName = \"<<\";\n  else if (consumeIf(\"lS\")) OperatorName = \"<<=\";\n  else if (consumeIf(\"lt\")) OperatorName = \"<\";\n  else if (consumeIf(\"mi\")) OperatorName = \"-\";\n  else if (consumeIf(\"mI\")) OperatorName = \"-=\";\n  else if (consumeIf(\"ml\")) OperatorName = \"*\";\n  else if (consumeIf(\"mL\")) OperatorName = \"*=\";\n  else if (consumeIf(\"ne\")) OperatorName = \"!=\";\n  else if (consumeIf(\"oo\")) OperatorName = \"||\";\n  else if (consumeIf(\"or\")) OperatorName = \"|\";\n  else if (consumeIf(\"oR\")) OperatorName = \"|=\";\n  else if (consumeIf(\"pl\")) OperatorName = \"+\";\n  else if (consumeIf(\"pL\")) OperatorName = \"+=\";\n  else if (consumeIf(\"rm\")) OperatorName = \"%\";\n  else if (consumeIf(\"rM\")) OperatorName = \"%=\";\n  else if (consumeIf(\"rs\")) OperatorName = \">>\";\n  else if (consumeIf(\"rS\")) OperatorName = \">>=\";\n  else return nullptr;\n\n  Node *Pack = parseExpr(), *Init = nullptr;\n  if (Pack == nullptr)\n    return nullptr;\n  if (HasInitializer) {\n    Init = parseExpr();\n    if (Init == nullptr)\n      return nullptr;\n  }\n\n  if (IsLeftFold && Init)\n    std::swap(Pack, Init);\n\n  return make<FoldExpr>(IsLeftFold, OperatorName, Pack, Init);\n}\n\n// <expression> ::= <unary operator-name> <expression>\n//              ::= <binary operator-name> <expression> <expression>\n//              ::= <ternary operator-name> <expression> <expression> <expression>\n//              ::= cl <expression>+ E                                   # call\n//              ::= cv <type> <expression>                               # conversion with one argument\n//              ::= cv <type> _ <expression>* E                          # conversion with a different number of arguments\n//              ::= [gs] nw <expression>* _ <type> E                     # new (expr-list) type\n//              ::= [gs] nw <expression>* _ <type> <initializer>         # new (expr-list) type (init)\n//              ::= [gs] na <expression>* _ <type> E                     # new[] (expr-list) type\n//              ::= [gs] na <expression>* _ <type> <initializer>         # new[] (expr-list) type (init)\n//              ::= [gs] dl <expression>                                 # delete expression\n//              ::= [gs] da <expression>                                 # delete[] expression\n//              ::= pp_ <expression>                                     # prefix ++\n//              ::= mm_ <expression>                                     # prefix --\n//              ::= ti <type>                                            # typeid (type)\n//              ::= te <expression>                                      # typeid (expression)\n//              ::= dc <type> <expression>                               # dynamic_cast<type> (expression)\n//              ::= sc <type> <expression>                               # static_cast<type> (expression)\n//              ::= cc <type> <expression>                               # const_cast<type> (expression)\n//              ::= rc <type> <expression>                               # reinterpret_cast<type> (expression)\n//              ::= st <type>                                            # sizeof (a type)\n//              ::= sz <expression>                                      # sizeof (an expression)\n//              ::= at <type>                                            # alignof (a type)\n//              ::= az <expression>                                      # alignof (an expression)\n//              ::= nx <expression>                                      # noexcept (expression)\n//              ::= <template-param>\n//              ::= <function-param>\n//              ::= dt <expression> <unresolved-name>                    # expr.name\n//              ::= pt <expression> <unresolved-name>                    # expr->name\n//              ::= ds <expression> <expression>                         # expr.*expr\n//              ::= sZ <template-param>                                  # size of a parameter pack\n//              ::= sZ <function-param>                                  # size of a function parameter pack\n//              ::= sP <template-arg>* E                                 # sizeof...(T), size of a captured template parameter pack from an alias template\n//              ::= sp <expression>                                      # pack expansion\n//              ::= tw <expression>                                      # throw expression\n//              ::= tr                                                   # throw with no operand (rethrow)\n//              ::= <unresolved-name>                                    # f(p), N::f(p), ::f(p),\n//                                                                       # freestanding dependent name (e.g., T::x),\n//                                                                       # objectless nonstatic member reference\n//              ::= fL <binary-operator-name> <expression> <expression>\n//              ::= fR <binary-operator-name> <expression> <expression>\n//              ::= fl <binary-operator-name> <expression>\n//              ::= fr <binary-operator-name> <expression>\n//              ::= <expr-primary>\ntemplate<typename Alloc> Node *Db<Alloc>::parseExpr() {\n  bool Global = consumeIf(\"gs\");\n  if (numLeft() < 2)\n    return nullptr;\n\n  switch (*First) {\n  case 'L':\n    return parseExprPrimary();\n  case 'T':\n    return parseTemplateParam();\n  case 'f': {\n    // Disambiguate a fold expression from a <function-param>.\n    if (look(1) == 'p' || (look(1) == 'L' && std::isdigit(look(2))))\n      return parseFunctionParam();\n    return parseFoldExpr();\n  }\n  case 'a':\n    switch (First[1]) {\n    case 'a':\n      First += 2;\n      return parseBinaryExpr(\"&&\");\n    case 'd':\n      First += 2;\n      return parsePrefixExpr(\"&\");\n    case 'n':\n      First += 2;\n      return parseBinaryExpr(\"&\");\n    case 'N':\n      First += 2;\n      return parseBinaryExpr(\"&=\");\n    case 'S':\n      First += 2;\n      return parseBinaryExpr(\"=\");\n    case 't': {\n      First += 2;\n      Node *Ty = parseType();\n      if (Ty == nullptr)\n        return nullptr;\n      return make<EnclosingExpr>(\"alignof (\", Ty, \")\");\n    }\n    case 'z': {\n      First += 2;\n      Node *Ty = parseExpr();\n      if (Ty == nullptr)\n        return nullptr;\n      return make<EnclosingExpr>(\"alignof (\", Ty, \")\");\n    }\n    }\n    return nullptr;\n  case 'c':\n    switch (First[1]) {\n    // cc <type> <expression>                               # const_cast<type>(expression)\n    case 'c': {\n      First += 2;\n      Node *Ty = parseType();\n      if (Ty == nullptr)\n        return Ty;\n      Node *Ex = parseExpr();\n      if (Ex == nullptr)\n        return Ex;\n      return make<CastExpr>(\"const_cast\", Ty, Ex);\n    }\n    // cl <expression>+ E                                   # call\n    case 'l': {\n      First += 2;\n      Node *Callee = parseExpr();\n      if (Callee == nullptr)\n        return Callee;\n      size_t ExprsBegin = Names.size();\n      while (!consumeIf('E')) {\n        Node *E = parseExpr();\n        if (E == nullptr)\n          return E;\n        Names.push_back(E);\n      }\n      return make<CallExpr>(Callee, popTrailingNodeArray(ExprsBegin));\n    }\n    case 'm':\n      First += 2;\n      return parseBinaryExpr(\",\");\n    case 'o':\n      First += 2;\n      return parsePrefixExpr(\"~\");\n    case 'v':\n      return parseConversionExpr();\n    }\n    return nullptr;\n  case 'd':\n    switch (First[1]) {\n    case 'a': {\n      First += 2;\n      Node *Ex = parseExpr();\n      if (Ex == nullptr)\n        return Ex;\n      return make<DeleteExpr>(Ex, Global, /*is_array=*/true);\n    }\n    case 'c': {\n      First += 2;\n      Node *T = parseType();\n      if (T == nullptr)\n        return T;\n      Node *Ex = parseExpr();\n      if (Ex == nullptr)\n        return Ex;\n      return make<CastExpr>(\"dynamic_cast\", T, Ex);\n    }\n    case 'e':\n      First += 2;\n      return parsePrefixExpr(\"*\");\n    case 'l': {\n      First += 2;\n      Node *E = parseExpr();\n      if (E == nullptr)\n        return E;\n      return make<DeleteExpr>(E, Global, /*is_array=*/false);\n    }\n    case 'n':\n      return parseUnresolvedName();\n    case 's': {\n      First += 2;\n      Node *LHS = parseExpr();\n      if (LHS == nullptr)\n        return nullptr;\n      Node *RHS = parseExpr();\n      if (RHS == nullptr)\n        return nullptr;\n      return make<MemberExpr>(LHS, \".*\", RHS);\n    }\n    case 't': {\n      First += 2;\n      Node *LHS = parseExpr();\n      if (LHS == nullptr)\n        return LHS;\n      Node *RHS = parseExpr();\n      if (RHS == nullptr)\n        return nullptr;\n      return make<MemberExpr>(LHS, \".\", RHS);\n    }\n    case 'v':\n      First += 2;\n      return parseBinaryExpr(\"/\");\n    case 'V':\n      First += 2;\n      return parseBinaryExpr(\"/=\");\n    }\n    return nullptr;\n  case 'e':\n    switch (First[1]) {\n    case 'o':\n      First += 2;\n      return parseBinaryExpr(\"^\");\n    case 'O':\n      First += 2;\n      return parseBinaryExpr(\"^=\");\n    case 'q':\n      First += 2;\n      return parseBinaryExpr(\"==\");\n    }\n    return nullptr;\n  case 'g':\n    switch (First[1]) {\n    case 'e':\n      First += 2;\n      return parseBinaryExpr(\">=\");\n    case 't':\n      First += 2;\n      return parseBinaryExpr(\">\");\n    }\n    return nullptr;\n  case 'i':\n    switch (First[1]) {\n    case 'x': {\n      First += 2;\n      Node *Base = parseExpr();\n      if (Base == nullptr)\n        return nullptr;\n      Node *Index = parseExpr();\n      if (Index == nullptr)\n        return Index;\n      return make<ArraySubscriptExpr>(Base, Index);\n    }\n    case 'l': {\n      First += 2;\n      size_t InitsBegin = Names.size();\n      while (!consumeIf('E')) {\n        Node *E = parseBracedExpr();\n        if (E == nullptr)\n          return nullptr;\n        Names.push_back(E);\n      }\n      return make<InitListExpr>(nullptr, popTrailingNodeArray(InitsBegin));\n    }\n    }\n    return nullptr;\n  case 'l':\n    switch (First[1]) {\n    case 'e':\n      First += 2;\n      return parseBinaryExpr(\"<=\");\n    case 's':\n      First += 2;\n      return parseBinaryExpr(\"<<\");\n    case 'S':\n      First += 2;\n      return parseBinaryExpr(\"<<=\");\n    case 't':\n      First += 2;\n      return parseBinaryExpr(\"<\");\n    }\n    return nullptr;\n  case 'm':\n    switch (First[1]) {\n    case 'i':\n      First += 2;\n      return parseBinaryExpr(\"-\");\n    case 'I':\n      First += 2;\n      return parseBinaryExpr(\"-=\");\n    case 'l':\n      First += 2;\n      return parseBinaryExpr(\"*\");\n    case 'L':\n      First += 2;\n      return parseBinaryExpr(\"*=\");\n    case 'm':\n      First += 2;\n      if (consumeIf('_'))\n        return parsePrefixExpr(\"--\");\n      Node *Ex = parseExpr();\n      if (Ex == nullptr)\n        return nullptr;\n      return make<PostfixExpr>(Ex, \"--\");\n    }\n    return nullptr;\n  case 'n':\n    switch (First[1]) {\n    case 'a':\n    case 'w':\n      return parseNewExpr();\n    case 'e':\n      First += 2;\n      return parseBinaryExpr(\"!=\");\n    case 'g':\n      First += 2;\n      return parsePrefixExpr(\"-\");\n    case 't':\n      First += 2;\n      return parsePrefixExpr(\"!\");\n    case 'x':\n      First += 2;\n      Node *Ex = parseExpr();\n      if (Ex == nullptr)\n        return Ex;\n      return make<EnclosingExpr>(\"noexcept (\", Ex, \")\");\n    }\n    return nullptr;\n  case 'o':\n    switch (First[1]) {\n    case 'n':\n      return parseUnresolvedName();\n    case 'o':\n      First += 2;\n      return parseBinaryExpr(\"||\");\n    case 'r':\n      First += 2;\n      return parseBinaryExpr(\"|\");\n    case 'R':\n      First += 2;\n      return parseBinaryExpr(\"|=\");\n    }\n    return nullptr;\n  case 'p':\n    switch (First[1]) {\n    case 'm':\n      First += 2;\n      return parseBinaryExpr(\"->*\");\n    case 'l':\n      First += 2;\n      return parseBinaryExpr(\"+\");\n    case 'L':\n      First += 2;\n      return parseBinaryExpr(\"+=\");\n    case 'p': {\n      First += 2;\n      if (consumeIf('_'))\n        return parsePrefixExpr(\"++\");\n      Node *Ex = parseExpr();\n      if (Ex == nullptr)\n        return Ex;\n      return make<PostfixExpr>(Ex, \"++\");\n    }\n    case 's':\n      First += 2;\n      return parsePrefixExpr(\"+\");\n    case 't': {\n      First += 2;\n      Node *L = parseExpr();\n      if (L == nullptr)\n        return nullptr;\n      Node *R = parseExpr();\n      if (R == nullptr)\n        return nullptr;\n      return make<MemberExpr>(L, \"->\", R);\n    }\n    }\n    return nullptr;\n  case 'q':\n    if (First[1] == 'u') {\n      First += 2;\n      Node *Cond = parseExpr();\n      if (Cond == nullptr)\n        return nullptr;\n      Node *LHS = parseExpr();\n      if (LHS == nullptr)\n        return nullptr;\n      Node *RHS = parseExpr();\n      if (RHS == nullptr)\n        return nullptr;\n      return make<ConditionalExpr>(Cond, LHS, RHS);\n    }\n    return nullptr;\n  case 'r':\n    switch (First[1]) {\n    case 'c': {\n      First += 2;\n      Node *T = parseType();\n      if (T == nullptr)\n        return T;\n      Node *Ex = parseExpr();\n      if (Ex == nullptr)\n        return Ex;\n      return make<CastExpr>(\"reinterpret_cast\", T, Ex);\n    }\n    case 'm':\n      First += 2;\n      return parseBinaryExpr(\"%\");\n    case 'M':\n      First += 2;\n      return parseBinaryExpr(\"%=\");\n    case 's':\n      First += 2;\n      return parseBinaryExpr(\">>\");\n    case 'S':\n      First += 2;\n      return parseBinaryExpr(\">>=\");\n    }\n    return nullptr;\n  case 's':\n    switch (First[1]) {\n    case 'c': {\n      First += 2;\n      Node *T = parseType();\n      if (T == nullptr)\n        return T;\n      Node *Ex = parseExpr();\n      if (Ex == nullptr)\n        return Ex;\n      return make<CastExpr>(\"static_cast\", T, Ex);\n    }\n    case 'p': {\n      First += 2;\n      Node *Child = parseExpr();\n      if (Child == nullptr)\n        return nullptr;\n      return make<ParameterPackExpansion>(Child);\n    }\n    case 'r':\n      return parseUnresolvedName();\n    case 't': {\n      First += 2;\n      Node *Ty = parseType();\n      if (Ty == nullptr)\n        return Ty;\n      return make<EnclosingExpr>(\"sizeof (\", Ty, \")\");\n    }\n    case 'z': {\n      First += 2;\n      Node *Ex = parseExpr();\n      if (Ex == nullptr)\n        return Ex;\n      return make<EnclosingExpr>(\"sizeof (\", Ex, \")\");\n    }\n    case 'Z':\n      First += 2;\n      if (look() == 'T') {\n        Node *R = parseTemplateParam();\n        if (R == nullptr)\n          return nullptr;\n        return make<SizeofParamPackExpr>(R);\n      } else if (look() == 'f') {\n        Node *FP = parseFunctionParam();\n        if (FP == nullptr)\n          return nullptr;\n        return make<EnclosingExpr>(\"sizeof... (\", FP, \")\");\n      }\n      return nullptr;\n    case 'P': {\n      First += 2;\n      size_t ArgsBegin = Names.size();\n      while (!consumeIf('E')) {\n        Node *Arg = parseTemplateArg();\n        if (Arg == nullptr)\n          return nullptr;\n        Names.push_back(Arg);\n      }\n      auto *Pack = make<NodeArrayNode>(popTrailingNodeArray(ArgsBegin));\n      if (!Pack)\n        return nullptr;\n      return make<EnclosingExpr>(\"sizeof... (\", Pack, \")\");\n    }\n    }\n    return nullptr;\n  case 't':\n    switch (First[1]) {\n    case 'e': {\n      First += 2;\n      Node *Ex = parseExpr();\n      if (Ex == nullptr)\n        return Ex;\n      return make<EnclosingExpr>(\"typeid (\", Ex, \")\");\n    }\n    case 'i': {\n      First += 2;\n      Node *Ty = parseType();\n      if (Ty == nullptr)\n        return Ty;\n      return make<EnclosingExpr>(\"typeid (\", Ty, \")\");\n    }\n    case 'l': {\n      First += 2;\n      Node *Ty = parseType();\n      if (Ty == nullptr)\n        return nullptr;\n      size_t InitsBegin = Names.size();\n      while (!consumeIf('E')) {\n        Node *E = parseBracedExpr();\n        if (E == nullptr)\n          return nullptr;\n        Names.push_back(E);\n      }\n      return make<InitListExpr>(Ty, popTrailingNodeArray(InitsBegin));\n    }\n    case 'r':\n      First += 2;\n      return make<NameType>(\"throw\");\n    case 'w': {\n      First += 2;\n      Node *Ex = parseExpr();\n      if (Ex == nullptr)\n        return nullptr;\n      return make<ThrowExpr>(Ex);\n    }\n    }\n    return nullptr;\n  case '1':\n  case '2':\n  case '3':\n  case '4':\n  case '5':\n  case '6':\n  case '7':\n  case '8':\n  case '9':\n    return parseUnresolvedName();\n  }\n  return nullptr;\n}\n\n// <call-offset> ::= h <nv-offset> _\n//               ::= v <v-offset> _\n//\n// <nv-offset> ::= <offset number>\n//               # non-virtual base override\n//\n// <v-offset>  ::= <offset number> _ <virtual offset number>\n//               # virtual base override, with vcall offset\ntemplate<typename Alloc> bool Db<Alloc>::parseCallOffset() {\n  // Just scan through the call offset, we never add this information into the\n  // output.\n  if (consumeIf('h'))\n    return parseNumber(true).empty() || !consumeIf('_');\n  if (consumeIf('v'))\n    return parseNumber(true).empty() || !consumeIf('_') ||\n           parseNumber(true).empty() || !consumeIf('_');\n  return true;\n}\n\n// <special-name> ::= TV <type>    # virtual table\n//                ::= TT <type>    # VTT structure (construction vtable index)\n//                ::= TI <type>    # typeinfo structure\n//                ::= TS <type>    # typeinfo name (null-terminated byte string)\n//                ::= Tc <call-offset> <call-offset> <base encoding>\n//                    # base is the nominal target function of thunk\n//                    # first call-offset is 'this' adjustment\n//                    # second call-offset is result adjustment\n//                ::= T <call-offset> <base encoding>\n//                    # base is the nominal target function of thunk\n//                ::= GV <object name> # Guard variable for one-time initialization\n//                                     # No <type>\n//                ::= TW <object name> # Thread-local wrapper\n//                ::= TH <object name> # Thread-local initialization\n//                ::= GR <object name> _             # First temporary\n//                ::= GR <object name> <seq-id> _    # Subsequent temporaries\n//      extension ::= TC <first type> <number> _ <second type> # construction vtable for second-in-first\n//      extension ::= GR <object name> # reference temporary for object\ntemplate<typename Alloc> Node *Db<Alloc>::parseSpecialName() {\n  switch (look()) {\n  case 'T':\n    switch (look(1)) {\n    // TV <type>    # virtual table\n    case 'V': {\n      First += 2;\n      Node *Ty = parseType();\n      if (Ty == nullptr)\n        return nullptr;\n      return make<SpecialName>(\"vtable for \", Ty);\n    }\n    // TT <type>    # VTT structure (construction vtable index)\n    case 'T': {\n      First += 2;\n      Node *Ty = parseType();\n      if (Ty == nullptr)\n        return nullptr;\n      return make<SpecialName>(\"VTT for \", Ty);\n    }\n    // TI <type>    # typeinfo structure\n    case 'I': {\n      First += 2;\n      Node *Ty = parseType();\n      if (Ty == nullptr)\n        return nullptr;\n      return make<SpecialName>(\"typeinfo for \", Ty);\n    }\n    // TS <type>    # typeinfo name (null-terminated byte string)\n    case 'S': {\n      First += 2;\n      Node *Ty = parseType();\n      if (Ty == nullptr)\n        return nullptr;\n      return make<SpecialName>(\"typeinfo name for \", Ty);\n    }\n    // Tc <call-offset> <call-offset> <base encoding>\n    case 'c': {\n      First += 2;\n      if (parseCallOffset() || parseCallOffset())\n        return nullptr;\n      Node *Encoding = parseEncoding();\n      if (Encoding == nullptr)\n        return nullptr;\n      return make<SpecialName>(\"covariant return thunk to \", Encoding);\n    }\n    // extension ::= TC <first type> <number> _ <second type>\n    //               # construction vtable for second-in-first\n    case 'C': {\n      First += 2;\n      Node *FirstType = parseType();\n      if (FirstType == nullptr)\n        return nullptr;\n      if (parseNumber(true).empty() || !consumeIf('_'))\n        return nullptr;\n      Node *SecondType = parseType();\n      if (SecondType == nullptr)\n        return nullptr;\n      return make<CtorVtableSpecialName>(SecondType, FirstType);\n    }\n    // TW <object name> # Thread-local wrapper\n    case 'W': {\n      First += 2;\n      Node *Name = parseName();\n      if (Name == nullptr)\n        return nullptr;\n      return make<SpecialName>(\"thread-local wrapper routine for \", Name);\n    }\n    // TH <object name> # Thread-local initialization\n    case 'H': {\n      First += 2;\n      Node *Name = parseName();\n      if (Name == nullptr)\n        return nullptr;\n      return make<SpecialName>(\"thread-local initialization routine for \", Name);\n    }\n    // T <call-offset> <base encoding>\n    default: {\n      ++First;\n      bool IsVirt = look() == 'v';\n      if (parseCallOffset())\n        return nullptr;\n      Node *BaseEncoding = parseEncoding();\n      if (BaseEncoding == nullptr)\n        return nullptr;\n      if (IsVirt)\n        return make<SpecialName>(\"virtual thunk to \", BaseEncoding);\n      else\n        return make<SpecialName>(\"non-virtual thunk to \", BaseEncoding);\n    }\n    }\n  case 'G':\n    switch (look(1)) {\n    // GV <object name> # Guard variable for one-time initialization\n    case 'V': {\n      First += 2;\n      Node *Name = parseName();\n      if (Name == nullptr)\n        return nullptr;\n      return make<SpecialName>(\"guard variable for \", Name);\n    }\n    // GR <object name> # reference temporary for object\n    // GR <object name> _             # First temporary\n    // GR <object name> <seq-id> _    # Subsequent temporaries\n    case 'R': {\n      First += 2;\n      Node *Name = parseName();\n      if (Name == nullptr)\n        return nullptr;\n      size_t Count;\n      bool ParsedSeqId = !parseSeqId(&Count);\n      if (!consumeIf('_') && ParsedSeqId)\n        return nullptr;\n      return make<SpecialName>(\"reference temporary for \", Name);\n    }\n    }\n  }\n  return nullptr;\n}\n\n// <encoding> ::= <function name> <bare-function-type>\n//            ::= <data name>\n//            ::= <special-name>\ntemplate<typename Alloc> Node *Db<Alloc>::parseEncoding() {\n  if (look() == 'G' || look() == 'T')\n    return parseSpecialName();\n\n  auto IsEndOfEncoding = [&] {\n    // The set of chars that can potentially follow an <encoding> (none of which\n    // can start a <type>). Enumerating these allows us to avoid speculative\n    // parsing.\n    return numLeft() == 0 || look() == 'E' || look() == '.' || look() == '_';\n  };\n\n  NameState NameInfo(this);\n  Node *Name = parseName(&NameInfo);\n  if (Name == nullptr)\n    return nullptr;\n\n  if (resolveForwardTemplateRefs(NameInfo))\n    return nullptr;\n\n  if (IsEndOfEncoding())\n    return Name;\n\n  Node *Attrs = nullptr;\n  if (consumeIf(\"Ua9enable_ifI\")) {\n    size_t BeforeArgs = Names.size();\n    while (!consumeIf('E')) {\n      Node *Arg = parseTemplateArg();\n      if (Arg == nullptr)\n        return nullptr;\n      Names.push_back(Arg);\n    }\n    Attrs = make<EnableIfAttr>(popTrailingNodeArray(BeforeArgs));\n    if (!Attrs)\n      return nullptr;\n  }\n\n  Node *ReturnType = nullptr;\n  if (!NameInfo.CtorDtorConversion && NameInfo.EndsWithTemplateArgs) {\n    ReturnType = parseType();\n    if (ReturnType == nullptr)\n      return nullptr;\n  }\n\n  if (consumeIf('v'))\n    return make<FunctionEncoding>(ReturnType, Name, NodeArray(),\n                                  Attrs, NameInfo.CVQualifiers,\n                                  NameInfo.ReferenceQualifier);\n\n  size_t ParamsBegin = Names.size();\n  do {\n    Node *Ty = parseType();\n    if (Ty == nullptr)\n      return nullptr;\n    Names.push_back(Ty);\n  } while (!IsEndOfEncoding());\n\n  return make<FunctionEncoding>(ReturnType, Name,\n                                popTrailingNodeArray(ParamsBegin),\n                                Attrs, NameInfo.CVQualifiers,\n                                NameInfo.ReferenceQualifier);\n}\n\ntemplate <class Float>\nstruct FloatData;\n\ntemplate <>\nstruct FloatData<float>\n{\n    static const size_t mangled_size = 8;\n    static const size_t max_demangled_size = 24;\n    static constexpr const char* spec = \"%af\";\n};\n\ntemplate <>\nstruct FloatData<double>\n{\n    static const size_t mangled_size = 16;\n    static const size_t max_demangled_size = 32;\n    static constexpr const char* spec = \"%a\";\n};\n\ntemplate <>\nstruct FloatData<long double>\n{\n#if defined(__mips__) && defined(__mips_n64) || defined(__aarch64__) || \\\n    defined(__wasm__)\n    static const size_t mangled_size = 32;\n#elif defined(__arm__) || defined(__mips__) || defined(__hexagon__)\n    static const size_t mangled_size = 16;\n#else\n    static const size_t mangled_size = 20;  // May need to be adjusted to 16 or 24 on other platforms\n#endif\n    static const size_t max_demangled_size = 40;\n    static constexpr const char *spec = \"%LaL\";\n};\n\ntemplate<typename Alloc>\ntemplate<class Float>\nNode *Db<Alloc>::parseFloatingLiteral() {\n  const size_t N = FloatData<Float>::mangled_size;\n  if (numLeft() <= N)\n    return nullptr;\n  StringView Data(First, First + N);\n  for (char C : Data)\n    if (!std::isxdigit(C))\n      return nullptr;\n  First += N;\n  if (!consumeIf('E'))\n    return nullptr;\n  return make<FloatLiteralImpl<Float>>(Data);\n}\n\n// <seq-id> ::= <0-9A-Z>+\ntemplate<typename Alloc> bool Db<Alloc>::parseSeqId(size_t *Out) {\n  if (!(look() >= '0' && look() <= '9') &&\n      !(look() >= 'A' && look() <= 'Z'))\n    return true;\n\n  size_t Id = 0;\n  while (true) {\n    if (look() >= '0' && look() <= '9') {\n      Id *= 36;\n      Id += static_cast<size_t>(look() - '0');\n    } else if (look() >= 'A' && look() <= 'Z') {\n      Id *= 36;\n      Id += static_cast<size_t>(look() - 'A') + 10;\n    } else {\n      *Out = Id;\n      return false;\n    }\n    ++First;\n  }\n}\n\n// <substitution> ::= S <seq-id> _\n//                ::= S_\n// <substitution> ::= Sa # ::std::allocator\n// <substitution> ::= Sb # ::std::basic_string\n// <substitution> ::= Ss # ::std::basic_string < char,\n//                                               ::std::char_traits<char>,\n//                                               ::std::allocator<char> >\n// <substitution> ::= Si # ::std::basic_istream<char,  std::char_traits<char> >\n// <substitution> ::= So # ::std::basic_ostream<char,  std::char_traits<char> >\n// <substitution> ::= Sd # ::std::basic_iostream<char, std::char_traits<char> >\ntemplate<typename Alloc> Node *Db<Alloc>::parseSubstitution() {\n  if (!consumeIf('S'))\n    return nullptr;\n\n  if (std::islower(look())) {\n    Node *SpecialSub;\n    switch (look()) {\n    case 'a':\n      ++First;\n      SpecialSub = make<SpecialSubstitution>(SpecialSubKind::allocator);\n      break;\n    case 'b':\n      ++First;\n      SpecialSub = make<SpecialSubstitution>(SpecialSubKind::basic_string);\n      break;\n    case 's':\n      ++First;\n      SpecialSub = make<SpecialSubstitution>(SpecialSubKind::string);\n      break;\n    case 'i':\n      ++First;\n      SpecialSub = make<SpecialSubstitution>(SpecialSubKind::istream);\n      break;\n    case 'o':\n      ++First;\n      SpecialSub = make<SpecialSubstitution>(SpecialSubKind::ostream);\n      break;\n    case 'd':\n      ++First;\n      SpecialSub = make<SpecialSubstitution>(SpecialSubKind::iostream);\n      break;\n    default:\n      return nullptr;\n    }\n    if (!SpecialSub)\n      return nullptr;\n    // Itanium C++ ABI 5.1.2: If a name that would use a built-in <substitution>\n    // has ABI tags, the tags are appended to the substitution; the result is a\n    // substitutable component.\n    Node *WithTags = parseAbiTags(SpecialSub);\n    if (WithTags != SpecialSub) {\n      Subs.push_back(WithTags);\n      SpecialSub = WithTags;\n    }\n    return SpecialSub;\n  }\n\n  //                ::= S_\n  if (consumeIf('_')) {\n    if (Subs.empty())\n      return nullptr;\n    return Subs[0];\n  }\n\n  //                ::= S <seq-id> _\n  size_t Index = 0;\n  if (parseSeqId(&Index))\n    return nullptr;\n  ++Index;\n  if (!consumeIf('_') || Index >= Subs.size())\n    return nullptr;\n  return Subs[Index];\n}\n\n// <template-param> ::= T_    # first template parameter\n//                  ::= T <parameter-2 non-negative number> _\ntemplate<typename Alloc> Node *Db<Alloc>::parseTemplateParam() {\n  if (!consumeIf('T'))\n    return nullptr;\n\n  size_t Index = 0;\n  if (!consumeIf('_')) {\n    if (parsePositiveInteger(&Index))\n      return nullptr;\n    ++Index;\n    if (!consumeIf('_'))\n      return nullptr;\n  }\n\n  // Itanium ABI 5.1.8: In a generic lambda, uses of auto in the parameter list\n  // are mangled as the corresponding artificial template type parameter.\n  if (ParsingLambdaParams)\n    return make<NameType>(\"auto\");\n\n  // If we're in a context where this <template-param> refers to a\n  // <template-arg> further ahead in the mangled name (currently just conversion\n  // operator types), then we should only look it up in the right context.\n  if (PermitForwardTemplateReferences) {\n    Node *ForwardRef = make<ForwardTemplateReference>(Index);\n    if (!ForwardRef)\n      return nullptr;\n    assert(ForwardRef->getKind() == Node::KForwardTemplateReference);\n    ForwardTemplateRefs.push_back(\n        static_cast<ForwardTemplateReference *>(ForwardRef));\n    return ForwardRef;\n  }\n\n  if (Index >= TemplateParams.size())\n    return nullptr;\n  return TemplateParams[Index];\n}\n\n// <template-arg> ::= <type>                    # type or template\n//                ::= X <expression> E          # expression\n//                ::= <expr-primary>            # simple expressions\n//                ::= J <template-arg>* E       # argument pack\n//                ::= LZ <encoding> E           # extension\ntemplate<typename Alloc> Node *Db<Alloc>::parseTemplateArg() {\n  switch (look()) {\n  case 'X': {\n    ++First;\n    Node *Arg = parseExpr();\n    if (Arg == nullptr || !consumeIf('E'))\n      return nullptr;\n    return Arg;\n  }\n  case 'J': {\n    ++First;\n    size_t ArgsBegin = Names.size();\n    while (!consumeIf('E')) {\n      Node *Arg = parseTemplateArg();\n      if (Arg == nullptr)\n        return nullptr;\n      Names.push_back(Arg);\n    }\n    NodeArray Args = popTrailingNodeArray(ArgsBegin);\n    return make<TemplateArgumentPack>(Args);\n  }\n  case 'L': {\n    //                ::= LZ <encoding> E           # extension\n    if (look(1) == 'Z') {\n      First += 2;\n      Node *Arg = parseEncoding();\n      if (Arg == nullptr || !consumeIf('E'))\n        return nullptr;\n      return Arg;\n    }\n    //                ::= <expr-primary>            # simple expressions\n    return parseExprPrimary();\n  }\n  default:\n    return parseType();\n  }\n}\n\n// <template-args> ::= I <template-arg>* E\n//     extension, the abi says <template-arg>+\ntemplate <typename Alloc>\nNode *Db<Alloc>::parseTemplateArgs(bool TagTemplates) {\n  if (!consumeIf('I'))\n    return nullptr;\n\n  // <template-params> refer to the innermost <template-args>. Clear out any\n  // outer args that we may have inserted into TemplateParams.\n  if (TagTemplates)\n    TemplateParams.clear();\n\n  size_t ArgsBegin = Names.size();\n  while (!consumeIf('E')) {\n    if (TagTemplates) {\n      auto OldParams = std::move(TemplateParams);\n      Node *Arg = parseTemplateArg();\n      TemplateParams = std::move(OldParams);\n      if (Arg == nullptr)\n        return nullptr;\n      Names.push_back(Arg);\n      Node *TableEntry = Arg;\n      if (Arg->getKind() == Node::KTemplateArgumentPack) {\n        TableEntry = make<ParameterPack>(\n            static_cast<TemplateArgumentPack*>(TableEntry)->getElements());\n        if (!TableEntry)\n          return nullptr;\n      }\n      TemplateParams.push_back(TableEntry);\n    } else {\n      Node *Arg = parseTemplateArg();\n      if (Arg == nullptr)\n        return nullptr;\n      Names.push_back(Arg);\n    }\n  }\n  return make<TemplateArgs>(popTrailingNodeArray(ArgsBegin));\n}\n\n// <mangled-name> ::= _Z <encoding>\n//                ::= <type>\n// extension      ::= ___Z <encoding> _block_invoke\n// extension      ::= ___Z <encoding> _block_invoke<decimal-digit>+\n// extension      ::= ___Z <encoding> _block_invoke_<decimal-digit>+\ntemplate<typename Alloc> Node *Db<Alloc>::parse() {\n  if (consumeIf(\"_Z\")) {\n    Node *Encoding = parseEncoding();\n    if (Encoding == nullptr)\n      return nullptr;\n    if (look() == '.') {\n      Encoding = make<DotSuffix>(Encoding, StringView(First, Last));\n      First = Last;\n    }\n    if (numLeft() != 0)\n      return nullptr;\n    return Encoding;\n  }\n\n  if (consumeIf(\"___Z\")) {\n    Node *Encoding = parseEncoding();\n    if (Encoding == nullptr || !consumeIf(\"_block_invoke\"))\n      return nullptr;\n    bool RequireNumber = consumeIf('_');\n    if (parseNumber().empty() && RequireNumber)\n      return nullptr;\n    if (look() == '.')\n      First = Last;\n    if (numLeft() != 0)\n      return nullptr;\n    return make<SpecialName>(\"invocation function for block in \", Encoding);\n  }\n\n  Node *Ty = parseType();\n  if (numLeft() != 0)\n    return nullptr;\n  return Ty;\n}\n\n}  // namespace itanium_demangle\n}  // namespace llvm\n\n#endif // LLVM_DEMANGLE_ITANIUMDEMANGLE_H\n"
  },
  {
    "path": "third_party/llvm-demangle/include/llvm/Demangle/StringView.h",
    "content": "//===--- StringView.h -------------------------------------------*- C++ -*-===//\n//\n//                     The LLVM Compiler Infrastructure\n//\n// This file is distributed under the University of Illinois Open Source\n// License. See LICENSE.TXT for details.\n//\n//\n// This file contains a limited version of LLVM's StringView class.  It is\n// copied here so that LLVMDemangle need not take a dependency on LLVMSupport.\n//===----------------------------------------------------------------------===//\n\n#ifndef LLVM_DEMANGLE_STRINGVIEW_H\n#define LLVM_DEMANGLE_STRINGVIEW_H\n\n#include <algorithm>\n#include <cassert>\n#include <cstring>\n\nclass StringView {\n  const char *First;\n  const char *Last;\n\npublic:\n  static const size_t npos = ~size_t(0);\n\n  template <size_t N>\n  StringView(const char (&Str)[N]) : First(Str), Last(Str + N - 1) {}\n  StringView(const char *First_, const char *Last_)\n      : First(First_), Last(Last_) {}\n  StringView(const char *First_, size_t Len)\n      : First(First_), Last(First_ + Len) {}\n  StringView(const char *Str) : First(Str), Last(Str + std::strlen(Str)) {}\n  StringView() : First(nullptr), Last(nullptr) {}\n\n  StringView substr(size_t From) const {\n    return StringView(begin() + From, size() - From);\n  }\n\n  size_t find(char C, size_t From = 0) const {\n    size_t FindBegin = std::min(From, size());\n    // Avoid calling memchr with nullptr.\n    if (FindBegin < size()) {\n      // Just forward to memchr, which is faster than a hand-rolled loop.\n      if (const void *P = ::memchr(First + FindBegin, C, size() - FindBegin))\n        return static_cast<const char *>(P) - First;\n    }\n    return npos;\n  }\n\n  StringView substr(size_t From, size_t To) const {\n    if (To >= size())\n      To = size() - 1;\n    if (From >= size())\n      From = size() - 1;\n    return StringView(First + From, First + To);\n  }\n\n  StringView dropFront(size_t N = 1) const {\n    if (N >= size())\n      N = size();\n    return StringView(First + N, Last);\n  }\n\n  StringView dropBack(size_t N = 1) const {\n    if (N >= size())\n      N = size();\n    return StringView(First, Last - N);\n  }\n\n  char front() const {\n    assert(!empty());\n    return *begin();\n  }\n\n  char back() const {\n    assert(!empty());\n    return *(end() - 1);\n  }\n\n  char popFront() {\n    assert(!empty());\n    return *First++;\n  }\n\n  bool consumeFront(char C) {\n    if (!startsWith(C))\n      return false;\n    *this = dropFront(1);\n    return true;\n  }\n\n  bool consumeFront(StringView S) {\n    if (!startsWith(S))\n      return false;\n    *this = dropFront(S.size());\n    return true;\n  }\n\n  bool startsWith(char C) const { return !empty() && *begin() == C; }\n\n  bool startsWith(StringView Str) const {\n    if (Str.size() > size())\n      return false;\n    return std::equal(Str.begin(), Str.end(), begin());\n  }\n\n  const char &operator[](size_t Idx) const { return *(begin() + Idx); }\n\n  const char *begin() const { return First; }\n  const char *end() const { return Last; }\n  size_t size() const { return static_cast<size_t>(Last - First); }\n  bool empty() const { return First == Last; }\n};\n\ninline bool operator==(const StringView &LHS, const StringView &RHS) {\n  return LHS.size() == RHS.size() &&\n         std::equal(LHS.begin(), LHS.end(), RHS.begin());\n}\n\n#endif\n"
  },
  {
    "path": "third_party/llvm-demangle/include/llvm/Demangle/Utility.h",
    "content": "//===--- Utility.h ----------------------------------------------*- C++ -*-===//\n//\n//                     The LLVM Compiler Infrastructure\n//\n// This file is distributed under the University of Illinois Open Source\n// License. See LICENSE.TXT for details.\n//\n//\n// This file contains several utility classes used by the demangle library.\n//===----------------------------------------------------------------------===//\n\n#ifndef LLVM_DEMANGLE_UTILITY_H\n#define LLVM_DEMANGLE_UTILITY_H\n\n#include \"StringView.h\"\n\n#include <cstdint>\n#include <cstdlib>\n#include <cstring>\n#include <iterator>\n#include <limits>\n\n// Stream that AST nodes write their string representation into after the AST\n// has been parsed.\nclass OutputStream {\n  char *Buffer;\n  size_t CurrentPosition;\n  size_t BufferCapacity;\n\n  // Ensure there is at least n more positions in buffer.\n  void grow(size_t N) {\n    if (N + CurrentPosition >= BufferCapacity) {\n      BufferCapacity *= 2;\n      if (BufferCapacity < N + CurrentPosition)\n        BufferCapacity = N + CurrentPosition;\n      Buffer = static_cast<char *>(std::realloc(Buffer, BufferCapacity));\n      if (Buffer == nullptr)\n        std::terminate();\n    }\n  }\n\n  void writeUnsigned(uint64_t N, bool isNeg = false) {\n    // Handle special case...\n    if (N == 0) {\n      *this << '0';\n      return;\n    }\n\n    char Temp[21];\n    char *TempPtr = std::end(Temp);\n\n    while (N) {\n      *--TempPtr = '0' + char(N % 10);\n      N /= 10;\n    }\n\n    // Add negative sign...\n    if (isNeg)\n      *--TempPtr = '-';\n    this->operator<<(StringView(TempPtr, std::end(Temp)));\n  }\n\npublic:\n  OutputStream(char *StartBuf, size_t Size)\n      : Buffer(StartBuf), CurrentPosition(0), BufferCapacity(Size) {}\n  OutputStream() = default;\n  void reset(char *Buffer_, size_t BufferCapacity_) {\n    CurrentPosition = 0;\n    Buffer = Buffer_;\n    BufferCapacity = BufferCapacity_;\n  }\n\n  /// If a ParameterPackExpansion (or similar type) is encountered, the offset\n  /// into the pack that we're currently printing.\n  unsigned CurrentPackIndex = std::numeric_limits<unsigned>::max();\n  unsigned CurrentPackMax = std::numeric_limits<unsigned>::max();\n\n  OutputStream &operator+=(StringView R) {\n    size_t Size = R.size();\n    if (Size == 0)\n      return *this;\n    grow(Size);\n    std::memmove(Buffer + CurrentPosition, R.begin(), Size);\n    CurrentPosition += Size;\n    return *this;\n  }\n\n  OutputStream &operator+=(char C) {\n    grow(1);\n    Buffer[CurrentPosition++] = C;\n    return *this;\n  }\n\n  OutputStream &operator<<(StringView R) { return (*this += R); }\n\n  OutputStream &operator<<(char C) { return (*this += C); }\n\n  OutputStream &operator<<(long long N) {\n    if (N < 0)\n      writeUnsigned(static_cast<unsigned long long>(-N), true);\n    else\n      writeUnsigned(static_cast<unsigned long long>(N));\n    return *this;\n  }\n\n  OutputStream &operator<<(unsigned long long N) {\n    writeUnsigned(N, false);\n    return *this;\n  }\n\n  OutputStream &operator<<(long N) {\n    return this->operator<<(static_cast<long long>(N));\n  }\n\n  OutputStream &operator<<(unsigned long N) {\n    return this->operator<<(static_cast<unsigned long long>(N));\n  }\n\n  OutputStream &operator<<(int N) {\n    return this->operator<<(static_cast<long long>(N));\n  }\n\n  OutputStream &operator<<(unsigned int N) {\n    return this->operator<<(static_cast<unsigned long long>(N));\n  }\n\n  size_t getCurrentPosition() const { return CurrentPosition; }\n  void setCurrentPosition(size_t NewPos) { CurrentPosition = NewPos; }\n\n  char back() const {\n    return CurrentPosition ? Buffer[CurrentPosition - 1] : '\\0';\n  }\n\n  bool empty() const { return CurrentPosition == 0; }\n\n  char *getBuffer() { return Buffer; }\n  char *getBufferEnd() { return Buffer + CurrentPosition - 1; }\n  size_t getBufferCapacity() { return BufferCapacity; }\n};\n\ntemplate <class T> class SwapAndRestore {\n  T &Restore;\n  T OriginalValue;\n  bool ShouldRestore = true;\n\npublic:\n  SwapAndRestore(T &Restore_) : SwapAndRestore(Restore_, Restore_) {}\n\n  SwapAndRestore(T &Restore_, T NewVal)\n      : Restore(Restore_), OriginalValue(Restore) {\n    Restore = std::move(NewVal);\n  }\n  ~SwapAndRestore() {\n    if (ShouldRestore)\n      Restore = std::move(OriginalValue);\n  }\n\n  void shouldRestore(bool ShouldRestore_) { ShouldRestore = ShouldRestore_; }\n\n  void restoreNow(bool Force) {\n    if (!Force && !ShouldRestore)\n      return;\n\n    Restore = std::move(OriginalValue);\n    ShouldRestore = false;\n  }\n\n  SwapAndRestore(const SwapAndRestore &) = delete;\n  SwapAndRestore &operator=(const SwapAndRestore &) = delete;\n};\n\ninline bool initializeOutputStream(char *Buf, size_t *N, OutputStream &S,\n                                   size_t InitSize) {\n  size_t BufferSize;\n  if (Buf == nullptr) {\n    Buf = static_cast<char *>(std::malloc(InitSize));\n    if (Buf == nullptr)\n      return true;\n    BufferSize = InitSize;\n  } else\n    BufferSize = *N;\n\n  S.reset(Buf, BufferSize);\n  return false;\n}\n\n#endif\n"
  },
  {
    "path": "third_party/llvm-demangle/lib/Demangle/CMakeLists.txt",
    "content": "add_llvm_library(LLVMDemangle\n  ItaniumDemangle.cpp\n  MicrosoftDemangle.cpp\n  MicrosoftDemangleNodes.cpp\n\n  ADDITIONAL_HEADER_DIRS\n  \"${LLVM_MAIN_INCLUDE_DIR}/llvm/Demangle\"\n)\n"
  },
  {
    "path": "third_party/llvm-demangle/lib/Demangle/ItaniumDemangle.cpp",
    "content": "//===------------------------- ItaniumDemangle.cpp ------------------------===//\n//\n//                     The LLVM Compiler Infrastructure\n//\n// This file is dual licensed under the MIT and the University of Illinois Open\n// Source Licenses. See LICENSE.TXT for details.\n//\n//===----------------------------------------------------------------------===//\n\n// FIXME: (possibly) incomplete list of features that clang mangles that this\n// file does not yet support:\n//   - C++ modules TS\n\n#include \"llvm/Demangle/Demangle.h\"\n#include \"llvm/Demangle/ItaniumDemangle.h\"\n\n#include <cassert>\n#include <cctype>\n#include <cstdio>\n#include <cstdlib>\n#include <cstring>\n#include <functional>\n#include <numeric>\n#include <utility>\n#include <vector>\n\nusing namespace llvm;\nusing namespace llvm::itanium_demangle;\n\nconstexpr const char *itanium_demangle::FloatData<float>::spec;\nconstexpr const char *itanium_demangle::FloatData<double>::spec;\nconstexpr const char *itanium_demangle::FloatData<long double>::spec;\n\n// <discriminator> := _ <non-negative number>      # when number < 10\n//                 := __ <non-negative number> _   # when number >= 10\n//  extension      := decimal-digit+               # at the end of string\nconst char *itanium_demangle::parse_discriminator(const char *first,\n                                                  const char *last) {\n  // parse but ignore discriminator\n  if (first != last) {\n    if (*first == '_') {\n      const char *t1 = first + 1;\n      if (t1 != last) {\n        if (std::isdigit(*t1))\n          first = t1 + 1;\n        else if (*t1 == '_') {\n          for (++t1; t1 != last && std::isdigit(*t1); ++t1)\n            ;\n          if (t1 != last && *t1 == '_')\n            first = t1 + 1;\n        }\n      }\n    } else if (std::isdigit(*first)) {\n      const char *t1 = first + 1;\n      for (; t1 != last && std::isdigit(*t1); ++t1)\n        ;\n      if (t1 == last)\n        first = last;\n    }\n  }\n  return first;\n}\n\n#ifndef NDEBUG\nnamespace {\nstruct DumpVisitor {\n  unsigned Depth = 0;\n  bool PendingNewline = false;\n\n  template<typename NodeT> static constexpr bool wantsNewline(const NodeT *) {\n    return true;\n  }\n  static bool wantsNewline(NodeArray A) { return !A.empty(); }\n  static constexpr bool wantsNewline(...) { return false; }\n\n  template<typename ...Ts> static bool anyWantNewline(Ts ...Vs) {\n    for (bool B : {wantsNewline(Vs)...})\n      if (B)\n        return true;\n    return false;\n  }\n\n  void printStr(const char *S) { fprintf(stderr, \"%s\", S); }\n  void print(StringView SV) {\n    fprintf(stderr, \"\\\"%.*s\\\"\", (int)SV.size(), SV.begin());\n  }\n  void print(const Node *N) {\n    if (N)\n      N->visit(std::ref(*this));\n    else\n      printStr(\"<null>\");\n  }\n  void print(NodeOrString NS) {\n    if (NS.isNode())\n      print(NS.asNode());\n    else if (NS.isString())\n      print(NS.asString());\n    else\n      printStr(\"NodeOrString()\");\n  }\n  void print(NodeArray A) {\n    ++Depth;\n    printStr(\"{\");\n    bool First = true;\n    for (const Node *N : A) {\n      if (First)\n        print(N);\n      else\n        printWithComma(N);\n      First = false;\n    }\n    printStr(\"}\");\n    --Depth;\n  }\n  // Overload used when T is exactly 'bool', not merely convertible to 'bool'.\n  template<typename T, T * = (bool*)nullptr>\n  void print(T B) {\n    printStr(B ? \"true\" : \"false\");\n  }\n  void print(size_t N) {\n    fprintf(stderr, \"%zu\", N);\n  }\n  void print(ReferenceKind RK) {\n    switch (RK) {\n    case ReferenceKind::LValue:\n      return printStr(\"ReferenceKind::LValue\");\n    case ReferenceKind::RValue:\n      return printStr(\"ReferenceKind::RValue\");\n    }\n  }\n  void print(FunctionRefQual RQ) {\n    switch (RQ) {\n    case FunctionRefQual::FrefQualNone:\n      return printStr(\"FunctionRefQual::FrefQualNone\");\n    case FunctionRefQual::FrefQualLValue:\n      return printStr(\"FunctionRefQual::FrefQualLValue\");\n    case FunctionRefQual::FrefQualRValue:\n      return printStr(\"FunctionRefQual::FrefQualRValue\");\n    }\n  }\n  void print(Qualifiers Qs) {\n    if (!Qs) return printStr(\"QualNone\");\n    struct QualName { Qualifiers Q; const char *Name; } Names[] = {\n      {QualConst, \"QualConst\"},\n      {QualVolatile, \"QualVolatile\"},\n      {QualRestrict, \"QualRestrict\"},\n    };\n    for (QualName Name : Names) {\n      if (Qs & Name.Q) {\n        printStr(Name.Name);\n        Qs = Qualifiers(Qs & ~Name.Q);\n        if (Qs) printStr(\" | \");\n      }\n    }\n  }\n  void print(SpecialSubKind SSK) {\n    switch (SSK) {\n    case SpecialSubKind::allocator:\n      return printStr(\"SpecialSubKind::allocator\");\n    case SpecialSubKind::basic_string:\n      return printStr(\"SpecialSubKind::basic_string\");\n    case SpecialSubKind::string:\n      return printStr(\"SpecialSubKind::string\");\n    case SpecialSubKind::istream:\n      return printStr(\"SpecialSubKind::istream\");\n    case SpecialSubKind::ostream:\n      return printStr(\"SpecialSubKind::ostream\");\n    case SpecialSubKind::iostream:\n      return printStr(\"SpecialSubKind::iostream\");\n    }\n  }\n\n  void newLine() {\n    printStr(\"\\n\");\n    for (unsigned I = 0; I != Depth; ++I)\n      printStr(\" \");\n    PendingNewline = false;\n  }\n\n  template<typename T> void printWithPendingNewline(T V) {\n    print(V);\n    if (wantsNewline(V))\n      PendingNewline = true;\n  }\n\n  template<typename T> void printWithComma(T V) {\n    if (PendingNewline || wantsNewline(V)) {\n      printStr(\",\");\n      newLine();\n    } else {\n      printStr(\", \");\n    }\n\n    printWithPendingNewline(V);\n  }\n\n  struct CtorArgPrinter {\n    DumpVisitor &Visitor;\n\n    template<typename T, typename ...Rest> void operator()(T V, Rest ...Vs) {\n      if (Visitor.anyWantNewline(V, Vs...))\n        Visitor.newLine();\n      Visitor.printWithPendingNewline(V);\n      int PrintInOrder[] = { (Visitor.printWithComma(Vs), 0)..., 0 };\n      (void)PrintInOrder;\n    }\n  };\n\n  template<typename NodeT> void operator()(const NodeT *Node) {\n    Depth += 2;\n    fprintf(stderr, \"%s(\", itanium_demangle::NodeKind<NodeT>::name());\n    Node->match(CtorArgPrinter{*this});\n    fprintf(stderr, \")\");\n    Depth -= 2;\n  }\n\n  void operator()(const ForwardTemplateReference *Node) {\n    Depth += 2;\n    fprintf(stderr, \"ForwardTemplateReference(\");\n    if (Node->Ref && !Node->Printing) {\n      Node->Printing = true;\n      CtorArgPrinter{*this}(Node->Ref);\n      Node->Printing = false;\n    } else {\n      CtorArgPrinter{*this}(Node->Index);\n    }\n    fprintf(stderr, \")\");\n    Depth -= 2;\n  }\n};\n}\n\nvoid itanium_demangle::Node::dump() const {\n  DumpVisitor V;\n  visit(std::ref(V));\n  V.newLine();\n}\n#endif\n\nnamespace {\nclass BumpPointerAllocator {\n  struct BlockMeta {\n    BlockMeta* Next;\n    size_t Current;\n  };\n\n  static constexpr size_t AllocSize = 4096;\n  static constexpr size_t UsableAllocSize = AllocSize - sizeof(BlockMeta);\n\n  alignas(long double) char InitialBuffer[AllocSize];\n  BlockMeta* BlockList = nullptr;\n\n  void grow() {\n    char* NewMeta = static_cast<char *>(std::malloc(AllocSize));\n    if (NewMeta == nullptr)\n      std::terminate();\n    BlockList = new (NewMeta) BlockMeta{BlockList, 0};\n  }\n\n  void* allocateMassive(size_t NBytes) {\n    NBytes += sizeof(BlockMeta);\n    BlockMeta* NewMeta = reinterpret_cast<BlockMeta*>(std::malloc(NBytes));\n    if (NewMeta == nullptr)\n      std::terminate();\n    BlockList->Next = new (NewMeta) BlockMeta{BlockList->Next, 0};\n    return static_cast<void*>(NewMeta + 1);\n  }\n\npublic:\n  BumpPointerAllocator()\n      : BlockList(new (InitialBuffer) BlockMeta{nullptr, 0}) {}\n\n  void* allocate(size_t N) {\n    N = (N + 15u) & ~15u;\n    if (N + BlockList->Current >= UsableAllocSize) {\n      if (N > UsableAllocSize)\n        return allocateMassive(N);\n      grow();\n    }\n    BlockList->Current += N;\n    return static_cast<void*>(reinterpret_cast<char*>(BlockList + 1) +\n                              BlockList->Current - N);\n  }\n\n  void reset() {\n    while (BlockList) {\n      BlockMeta* Tmp = BlockList;\n      BlockList = BlockList->Next;\n      if (reinterpret_cast<char*>(Tmp) != InitialBuffer)\n        std::free(Tmp);\n    }\n    BlockList = new (InitialBuffer) BlockMeta{nullptr, 0};\n  }\n\n  ~BumpPointerAllocator() { reset(); }\n};\n\nclass DefaultAllocator {\n  BumpPointerAllocator Alloc;\n\npublic:\n  void reset() { Alloc.reset(); }\n\n  template<typename T, typename ...Args> T *makeNode(Args &&...args) {\n    return new (Alloc.allocate(sizeof(T)))\n        T(std::forward<Args>(args)...);\n  }\n\n  void *allocateNodeArray(size_t sz) {\n    return Alloc.allocate(sizeof(Node *) * sz);\n  }\n};\n}  // unnamed namespace\n\n//===----------------------------------------------------------------------===//\n// Code beyond this point should not be synchronized with libc++abi.\n//===----------------------------------------------------------------------===//\n\nusing Demangler = itanium_demangle::Db<DefaultAllocator>;\n\nchar *llvm::itaniumDemangle(const char *MangledName, char *Buf,\n                            size_t *N, int *Status) {\n  if (MangledName == nullptr || (Buf != nullptr && N == nullptr)) {\n    if (Status)\n      *Status = demangle_invalid_args;\n    return nullptr;\n  }\n\n  int InternalStatus = demangle_success;\n  Demangler Parser(MangledName, MangledName + std::strlen(MangledName));\n  OutputStream S;\n\n  Node *AST = Parser.parse();\n\n  if (AST == nullptr)\n    InternalStatus = demangle_invalid_mangled_name;\n  else if (initializeOutputStream(Buf, N, S, 1024))\n    InternalStatus = demangle_memory_alloc_failure;\n  else {\n    assert(Parser.ForwardTemplateRefs.empty());\n    AST->print(S);\n    S += '\\0';\n    if (N != nullptr)\n      *N = S.getCurrentPosition();\n    Buf = S.getBuffer();\n  }\n\n  if (Status)\n    *Status = InternalStatus;\n  return InternalStatus == demangle_success ? Buf : nullptr;\n}\n\nbool llvm::itaniumFindTypesInMangledName(const char *MangledName, void *Ctx,\n                                         void (*Callback)(void *,\n                                                          const char *)) {\n  Demangler Parser(MangledName, MangledName + std::strlen(MangledName));\n  Parser.TypeCallback = Callback;\n  Parser.TypeCallbackContext = Ctx;\n  return Parser.parse() == nullptr;\n}\n\nItaniumPartialDemangler::ItaniumPartialDemangler()\n    : RootNode(nullptr), Context(new Demangler{nullptr, nullptr}) {}\n\nItaniumPartialDemangler::~ItaniumPartialDemangler() {\n  delete static_cast<Demangler *>(Context);\n}\n\nItaniumPartialDemangler::ItaniumPartialDemangler(\n    ItaniumPartialDemangler &&Other)\n    : RootNode(Other.RootNode), Context(Other.Context) {\n  Other.Context = Other.RootNode = nullptr;\n}\n\nItaniumPartialDemangler &ItaniumPartialDemangler::\noperator=(ItaniumPartialDemangler &&Other) {\n  std::swap(RootNode, Other.RootNode);\n  std::swap(Context, Other.Context);\n  return *this;\n}\n\n// Demangle MangledName into an AST, storing it into this->RootNode.\nbool ItaniumPartialDemangler::partialDemangle(const char *MangledName) {\n  Demangler *Parser = static_cast<Demangler *>(Context);\n  size_t Len = std::strlen(MangledName);\n  Parser->reset(MangledName, MangledName + Len);\n  RootNode = Parser->parse();\n  return RootNode == nullptr;\n}\n\nstatic char *printNode(const Node *RootNode, char *Buf, size_t *N) {\n  OutputStream S;\n  if (initializeOutputStream(Buf, N, S, 128))\n    return nullptr;\n  RootNode->print(S);\n  S += '\\0';\n  if (N != nullptr)\n    *N = S.getCurrentPosition();\n  return S.getBuffer();\n}\n\nchar *ItaniumPartialDemangler::getFunctionBaseName(char *Buf, size_t *N) const {\n  if (!isFunction())\n    return nullptr;\n\n  const Node *Name = static_cast<const FunctionEncoding *>(RootNode)->getName();\n\n  while (true) {\n    switch (Name->getKind()) {\n    case Node::KAbiTagAttr:\n      Name = static_cast<const AbiTagAttr *>(Name)->Base;\n      continue;\n    case Node::KStdQualifiedName:\n      Name = static_cast<const StdQualifiedName *>(Name)->Child;\n      continue;\n    case Node::KNestedName:\n      Name = static_cast<const NestedName *>(Name)->Name;\n      continue;\n    case Node::KLocalName:\n      Name = static_cast<const LocalName *>(Name)->Entity;\n      continue;\n    case Node::KNameWithTemplateArgs:\n      Name = static_cast<const NameWithTemplateArgs *>(Name)->Name;\n      continue;\n    default:\n      return printNode(Name, Buf, N);\n    }\n  }\n}\n\nchar *ItaniumPartialDemangler::getFunctionDeclContextName(char *Buf,\n                                                          size_t *N) const {\n  if (!isFunction())\n    return nullptr;\n  const Node *Name = static_cast<const FunctionEncoding *>(RootNode)->getName();\n\n  OutputStream S;\n  if (initializeOutputStream(Buf, N, S, 128))\n    return nullptr;\n\n KeepGoingLocalFunction:\n  while (true) {\n    if (Name->getKind() == Node::KAbiTagAttr) {\n      Name = static_cast<const AbiTagAttr *>(Name)->Base;\n      continue;\n    }\n    if (Name->getKind() == Node::KNameWithTemplateArgs) {\n      Name = static_cast<const NameWithTemplateArgs *>(Name)->Name;\n      continue;\n    }\n    break;\n  }\n\n  switch (Name->getKind()) {\n  case Node::KStdQualifiedName:\n    S += \"std\";\n    break;\n  case Node::KNestedName:\n    static_cast<const NestedName *>(Name)->Qual->print(S);\n    break;\n  case Node::KLocalName: {\n    auto *LN = static_cast<const LocalName *>(Name);\n    LN->Encoding->print(S);\n    S += \"::\";\n    Name = LN->Entity;\n    goto KeepGoingLocalFunction;\n  }\n  default:\n    break;\n  }\n  S += '\\0';\n  if (N != nullptr)\n    *N = S.getCurrentPosition();\n  return S.getBuffer();\n}\n\nchar *ItaniumPartialDemangler::getFunctionName(char *Buf, size_t *N) const {\n  if (!isFunction())\n    return nullptr;\n  auto *Name = static_cast<FunctionEncoding *>(RootNode)->getName();\n  return printNode(Name, Buf, N);\n}\n\nchar *ItaniumPartialDemangler::getFunctionParameters(char *Buf,\n                                                     size_t *N) const {\n  if (!isFunction())\n    return nullptr;\n  NodeArray Params = static_cast<FunctionEncoding *>(RootNode)->getParams();\n\n  OutputStream S;\n  if (initializeOutputStream(Buf, N, S, 128))\n    return nullptr;\n\n  S += '(';\n  Params.printWithComma(S);\n  S += ')';\n  S += '\\0';\n  if (N != nullptr)\n    *N = S.getCurrentPosition();\n  return S.getBuffer();\n}\n\nchar *ItaniumPartialDemangler::getFunctionReturnType(\n    char *Buf, size_t *N) const {\n  if (!isFunction())\n    return nullptr;\n\n  OutputStream S;\n  if (initializeOutputStream(Buf, N, S, 128))\n    return nullptr;\n\n  if (const Node *Ret =\n          static_cast<const FunctionEncoding *>(RootNode)->getReturnType())\n    Ret->print(S);\n\n  S += '\\0';\n  if (N != nullptr)\n    *N = S.getCurrentPosition();\n  return S.getBuffer();\n}\n\nchar *ItaniumPartialDemangler::finishDemangle(char *Buf, size_t *N) const {\n  assert(RootNode != nullptr && \"must call partialDemangle()\");\n  return printNode(static_cast<Node *>(RootNode), Buf, N);\n}\n\nbool ItaniumPartialDemangler::hasFunctionQualifiers() const {\n  assert(RootNode != nullptr && \"must call partialDemangle()\");\n  if (!isFunction())\n    return false;\n  auto *E = static_cast<const FunctionEncoding *>(RootNode);\n  return E->getCVQuals() != QualNone || E->getRefQual() != FrefQualNone;\n}\n\nbool ItaniumPartialDemangler::isCtorOrDtor() const {\n  const Node *N = static_cast<const Node *>(RootNode);\n  while (N) {\n    switch (N->getKind()) {\n    default:\n      return false;\n    case Node::KCtorDtorName:\n      return true;\n\n    case Node::KAbiTagAttr:\n      N = static_cast<const AbiTagAttr *>(N)->Base;\n      break;\n    case Node::KFunctionEncoding:\n      N = static_cast<const FunctionEncoding *>(N)->getName();\n      break;\n    case Node::KLocalName:\n      N = static_cast<const LocalName *>(N)->Entity;\n      break;\n    case Node::KNameWithTemplateArgs:\n      N = static_cast<const NameWithTemplateArgs *>(N)->Name;\n      break;\n    case Node::KNestedName:\n      N = static_cast<const NestedName *>(N)->Name;\n      break;\n    case Node::KStdQualifiedName:\n      N = static_cast<const StdQualifiedName *>(N)->Child;\n      break;\n    }\n  }\n  return false;\n}\n\nbool ItaniumPartialDemangler::isFunction() const {\n  assert(RootNode != nullptr && \"must call partialDemangle()\");\n  return static_cast<const Node *>(RootNode)->getKind() ==\n         Node::KFunctionEncoding;\n}\n\nbool ItaniumPartialDemangler::isSpecialName() const {\n  assert(RootNode != nullptr && \"must call partialDemangle()\");\n  auto K = static_cast<const Node *>(RootNode)->getKind();\n  return K == Node::KSpecialName || K == Node::KCtorVtableSpecialName;\n}\n\nbool ItaniumPartialDemangler::isData() const {\n  return !isFunction() && !isSpecialName();\n}\n"
  },
  {
    "path": "third_party/llvm-demangle/lib/Demangle/LLVMBuild.txt",
    "content": ";===- ./lib/Support/LLVMBuild.txt ------------------------------*- Conf -*--===;\n;\n;                     The LLVM Compiler Infrastructure\n;\n; This file is distributed under the University of Illinois Open Source\n; License. See LICENSE.TXT for details.\n;\n;===------------------------------------------------------------------------===;\n;\n; This is an LLVMBuild description file for the components in this subdirectory.\n;\n; For more information on the LLVMBuild system, please see:\n;\n;   http://llvm.org/docs/LLVMBuild.html\n;\n;===------------------------------------------------------------------------===;\n\n[component_0]\ntype = Library\nname = Demangle\nparent = Libraries\n"
  },
  {
    "path": "third_party/llvm-demangle/lib/Demangle/MicrosoftDemangle.cpp",
    "content": "//===- MicrosoftDemangle.cpp ----------------------------------------------===//\n//\n//                     The LLVM Compiler Infrastructure\n//\n// This file is dual licensed under the MIT and the University of Illinois Open\n// Source Licenses. See LICENSE.TXT for details.\n//\n//===----------------------------------------------------------------------===//\n//\n// This file defines a demangler for MSVC-style mangled symbols.\n//\n// This file has no dependencies on the rest of LLVM so that it can be\n// easily reused in other programs such as libcxxabi.\n//\n//===----------------------------------------------------------------------===//\n\n#include \"MicrosoftDemangleNodes.h\"\n#include \"llvm/Demangle/Demangle.h\"\n\n#include \"llvm/Demangle/Compiler.h\"\n#include \"llvm/Demangle/StringView.h\"\n#include \"llvm/Demangle/Utility.h\"\n\n#include <array>\n#include <cctype>\n#include <cstdio>\n#include <tuple>\n\nusing namespace llvm;\nusing namespace ms_demangle;\n\nstatic bool startsWithDigit(StringView S) {\n  return !S.empty() && std::isdigit(S.front());\n}\n\nenum class QualifierMangleMode { Drop, Mangle, Result };\n\nstruct NodeList {\n  Node *N = nullptr;\n  NodeList *Next = nullptr;\n};\n\nenum class FunctionIdentifierCodeGroup { Basic, Under, DoubleUnder };\n\nenum NameBackrefBehavior : uint8_t {\n  NBB_None = 0,          // don't save any names as backrefs.\n  NBB_Template = 1 << 0, // save template instanations.\n  NBB_Simple = 1 << 1,   // save simple names.\n};\n\nstatic bool isMemberPointer(StringView MangledName) {\n  switch (MangledName.popFront()) {\n  case '$':\n    // This is probably an rvalue reference (e.g. $$Q), and you cannot have an\n    // rvalue reference to a member.\n    return false;\n  case 'A':\n    // 'A' indicates a reference, and you cannot have a reference to a member\n    // function or member.\n    return false;\n  case 'P':\n  case 'Q':\n  case 'R':\n  case 'S':\n    // These 4 values indicate some kind of pointer, but we still don't know\n    // what.\n    break;\n  default:\n    assert(false && \"Ty is not a pointer type!\");\n  }\n\n  // If it starts with a number, then 6 indicates a non-member function\n  // pointer, and 8 indicates a member function pointer.\n  if (startsWithDigit(MangledName)) {\n    assert(MangledName[0] == '6' || MangledName[0] == '8');\n    return (MangledName[0] == '8');\n  }\n\n  // Remove ext qualifiers since those can appear on either type and are\n  // therefore not indicative.\n  MangledName.consumeFront('E'); // 64-bit\n  MangledName.consumeFront('I'); // restrict\n  MangledName.consumeFront('F'); // unaligned\n\n  assert(!MangledName.empty());\n\n  // The next value should be either ABCD (non-member) or QRST (member).\n  switch (MangledName.front()) {\n  case 'A':\n  case 'B':\n  case 'C':\n  case 'D':\n    return false;\n  case 'Q':\n  case 'R':\n  case 'S':\n  case 'T':\n    return true;\n  default:\n    assert(false);\n  }\n  return false;\n}\n\nstatic SpecialIntrinsicKind\nconsumeSpecialIntrinsicKind(StringView &MangledName) {\n  if (MangledName.consumeFront(\"?_7\"))\n    return SpecialIntrinsicKind::Vftable;\n  if (MangledName.consumeFront(\"?_8\"))\n    return SpecialIntrinsicKind::Vbtable;\n  if (MangledName.consumeFront(\"?_9\"))\n    return SpecialIntrinsicKind::VcallThunk;\n  if (MangledName.consumeFront(\"?_A\"))\n    return SpecialIntrinsicKind::Typeof;\n  if (MangledName.consumeFront(\"?_B\"))\n    return SpecialIntrinsicKind::LocalStaticGuard;\n  if (MangledName.consumeFront(\"?_C\"))\n    return SpecialIntrinsicKind::StringLiteralSymbol;\n  if (MangledName.consumeFront(\"?_P\"))\n    return SpecialIntrinsicKind::UdtReturning;\n  if (MangledName.consumeFront(\"?_R0\"))\n    return SpecialIntrinsicKind::RttiTypeDescriptor;\n  if (MangledName.consumeFront(\"?_R1\"))\n    return SpecialIntrinsicKind::RttiBaseClassDescriptor;\n  if (MangledName.consumeFront(\"?_R2\"))\n    return SpecialIntrinsicKind::RttiBaseClassArray;\n  if (MangledName.consumeFront(\"?_R3\"))\n    return SpecialIntrinsicKind::RttiClassHierarchyDescriptor;\n  if (MangledName.consumeFront(\"?_R4\"))\n    return SpecialIntrinsicKind::RttiCompleteObjLocator;\n  if (MangledName.consumeFront(\"?_S\"))\n    return SpecialIntrinsicKind::LocalVftable;\n  if (MangledName.consumeFront(\"?__E\"))\n    return SpecialIntrinsicKind::DynamicInitializer;\n  if (MangledName.consumeFront(\"?__F\"))\n    return SpecialIntrinsicKind::DynamicAtexitDestructor;\n  if (MangledName.consumeFront(\"?__J\"))\n    return SpecialIntrinsicKind::LocalStaticThreadGuard;\n  return SpecialIntrinsicKind::None;\n}\n\nstatic bool startsWithLocalScopePattern(StringView S) {\n  if (!S.consumeFront('?'))\n    return false;\n  if (S.size() < 2)\n    return false;\n\n  size_t End = S.find('?');\n  if (End == StringView::npos)\n    return false;\n  StringView Candidate = S.substr(0, End);\n  if (Candidate.empty())\n    return false;\n\n  // \\?[0-9]\\?\n  // ?@? is the discriminator 0.\n  if (Candidate.size() == 1)\n    return Candidate[0] == '@' || (Candidate[0] >= '0' && Candidate[0] <= '9');\n\n  // If it's not 0-9, then it's an encoded number terminated with an @\n  if (Candidate.back() != '@')\n    return false;\n  Candidate = Candidate.dropBack();\n\n  // An encoded number starts with B-P and all subsequent digits are in A-P.\n  // Note that the reason the first digit cannot be A is two fold.  First, it\n  // would create an ambiguity with ?A which delimits the beginning of an\n  // anonymous namespace.  Second, A represents 0, and you don't start a multi\n  // digit number with a leading 0.  Presumably the anonymous namespace\n  // ambiguity is also why single digit encoded numbers use 0-9 rather than A-J.\n  if (Candidate[0] < 'B' || Candidate[0] > 'P')\n    return false;\n  Candidate = Candidate.dropFront();\n  while (!Candidate.empty()) {\n    if (Candidate[0] < 'A' || Candidate[0] > 'P')\n      return false;\n    Candidate = Candidate.dropFront();\n  }\n\n  return true;\n}\n\nstatic bool isTagType(StringView S) {\n  switch (S.front()) {\n  case 'T': // union\n  case 'U': // struct\n  case 'V': // class\n  case 'W': // enum\n    return true;\n  }\n  return false;\n}\n\nstatic bool isCustomType(StringView S) { return S[0] == '?'; }\n\nstatic bool isPointerType(StringView S) {\n  if (S.startsWith(\"$$Q\")) // foo &&\n    return true;\n\n  switch (S.front()) {\n  case 'A': // foo &\n  case 'P': // foo *\n  case 'Q': // foo *const\n  case 'R': // foo *volatile\n  case 'S': // foo *const volatile\n    return true;\n  }\n  return false;\n}\n\nstatic bool isArrayType(StringView S) { return S[0] == 'Y'; }\n\nstatic bool isFunctionType(StringView S) {\n  return S.startsWith(\"$$A8@@\") || S.startsWith(\"$$A6\");\n}\n\nstatic FunctionRefQualifier\ndemangleFunctionRefQualifier(StringView &MangledName) {\n  if (MangledName.consumeFront('G'))\n    return FunctionRefQualifier::Reference;\n  else if (MangledName.consumeFront('H'))\n    return FunctionRefQualifier::RValueReference;\n  return FunctionRefQualifier::None;\n}\n\nstatic std::pair<Qualifiers, PointerAffinity>\ndemanglePointerCVQualifiers(StringView &MangledName) {\n  if (MangledName.consumeFront(\"$$Q\"))\n    return std::make_pair(Q_None, PointerAffinity::RValueReference);\n\n  switch (MangledName.popFront()) {\n  case 'A':\n    return std::make_pair(Q_None, PointerAffinity::Reference);\n  case 'P':\n    return std::make_pair(Q_None, PointerAffinity::Pointer);\n  case 'Q':\n    return std::make_pair(Q_Const, PointerAffinity::Pointer);\n  case 'R':\n    return std::make_pair(Q_Volatile, PointerAffinity::Pointer);\n  case 'S':\n    return std::make_pair(Qualifiers(Q_Const | Q_Volatile),\n                          PointerAffinity::Pointer);\n  default:\n    assert(false && \"Ty is not a pointer type!\");\n  }\n  return std::make_pair(Q_None, PointerAffinity::Pointer);\n}\n\nnamespace {\n\nstruct BackrefContext {\n  static constexpr size_t Max = 10;\n\n  TypeNode *FunctionParams[Max];\n  size_t FunctionParamCount = 0;\n\n  // The first 10 BackReferences in a mangled name can be back-referenced by\n  // special name @[0-9]. This is a storage for the first 10 BackReferences.\n  NamedIdentifierNode *Names[Max];\n  size_t NamesCount = 0;\n};\n\n// Demangler class takes the main role in demangling symbols.\n// It has a set of functions to parse mangled symbols into Type instances.\n// It also has a set of functions to cnovert Type instances to strings.\nclass Demangler {\npublic:\n  Demangler() = default;\n  virtual ~Demangler() = default;\n\n  // You are supposed to call parse() first and then check if error is true.  If\n  // it is false, call output() to write the formatted name to the given stream.\n  SymbolNode *parse(StringView &MangledName);\n\n  // True if an error occurred.\n  bool Error = false;\n\n  void dumpBackReferences();\n\nprivate:\n  SymbolNode *demangleEncodedSymbol(StringView &MangledName,\n                                    QualifiedNameNode *QN);\n\n  VariableSymbolNode *demangleVariableEncoding(StringView &MangledName,\n                                               StorageClass SC);\n  FunctionSymbolNode *demangleFunctionEncoding(StringView &MangledName);\n\n  Qualifiers demanglePointerExtQualifiers(StringView &MangledName);\n\n  // Parser functions. This is a recursive-descent parser.\n  TypeNode *demangleType(StringView &MangledName, QualifierMangleMode QMM);\n  PrimitiveTypeNode *demanglePrimitiveType(StringView &MangledName);\n  CustomTypeNode *demangleCustomType(StringView &MangledName);\n  TagTypeNode *demangleClassType(StringView &MangledName);\n  PointerTypeNode *demanglePointerType(StringView &MangledName);\n  PointerTypeNode *demangleMemberPointerType(StringView &MangledName);\n  FunctionSignatureNode *demangleFunctionType(StringView &MangledName,\n                                              bool HasThisQuals);\n\n  ArrayTypeNode *demangleArrayType(StringView &MangledName);\n\n  NodeArrayNode *demangleTemplateParameterList(StringView &MangledName);\n  NodeArrayNode *demangleFunctionParameterList(StringView &MangledName);\n\n  std::pair<uint64_t, bool> demangleNumber(StringView &MangledName);\n  uint64_t demangleUnsigned(StringView &MangledName);\n  int64_t demangleSigned(StringView &MangledName);\n\n  void memorizeString(StringView s);\n  void memorizeIdentifier(IdentifierNode *Identifier);\n\n  /// Allocate a copy of \\p Borrowed into memory that we own.\n  StringView copyString(StringView Borrowed);\n\n  QualifiedNameNode *demangleFullyQualifiedTypeName(StringView &MangledName);\n  QualifiedNameNode *demangleFullyQualifiedSymbolName(StringView &MangledName);\n\n  IdentifierNode *demangleUnqualifiedTypeName(StringView &MangledName,\n                                              bool Memorize);\n  IdentifierNode *demangleUnqualifiedSymbolName(StringView &MangledName,\n                                                NameBackrefBehavior NBB);\n\n  QualifiedNameNode *demangleNameScopeChain(StringView &MangledName,\n                                            IdentifierNode *UnqualifiedName);\n  IdentifierNode *demangleNameScopePiece(StringView &MangledName);\n\n  NamedIdentifierNode *demangleBackRefName(StringView &MangledName);\n  IdentifierNode *demangleTemplateInstantiationName(StringView &MangledName,\n                                                    NameBackrefBehavior NBB);\n  IdentifierNode *demangleFunctionIdentifierCode(StringView &MangledName);\n  IdentifierNode *\n  demangleFunctionIdentifierCode(StringView &MangledName,\n                                 FunctionIdentifierCodeGroup Group);\n  StructorIdentifierNode *demangleStructorIdentifier(StringView &MangledName,\n                                                     bool IsDestructor);\n  ConversionOperatorIdentifierNode *\n  demangleConversionOperatorIdentifier(StringView &MangledName);\n  LiteralOperatorIdentifierNode *\n  demangleLiteralOperatorIdentifier(StringView &MangledName);\n\n  SymbolNode *demangleSpecialIntrinsic(StringView &MangledName);\n  SpecialTableSymbolNode *\n  demangleSpecialTableSymbolNode(StringView &MangledName,\n                                 SpecialIntrinsicKind SIK);\n  LocalStaticGuardVariableNode *\n  demangleLocalStaticGuard(StringView &MangledName);\n  VariableSymbolNode *demangleUntypedVariable(ArenaAllocator &Arena,\n                                              StringView &MangledName,\n                                              StringView VariableName);\n  VariableSymbolNode *\n  demangleRttiBaseClassDescriptorNode(ArenaAllocator &Arena,\n                                      StringView &MangledName);\n  FunctionSymbolNode *demangleInitFiniStub(StringView &MangledName,\n                                           bool IsDestructor);\n\n  NamedIdentifierNode *demangleSimpleName(StringView &MangledName,\n                                          bool Memorize);\n  NamedIdentifierNode *demangleAnonymousNamespaceName(StringView &MangledName);\n  NamedIdentifierNode *demangleLocallyScopedNamePiece(StringView &MangledName);\n  EncodedStringLiteralNode *demangleStringLiteral(StringView &MangledName);\n  FunctionSymbolNode *demangleVcallThunkNode(StringView &MangledName);\n\n  StringView demangleSimpleString(StringView &MangledName, bool Memorize);\n\n  FuncClass demangleFunctionClass(StringView &MangledName);\n  CallingConv demangleCallingConvention(StringView &MangledName);\n  StorageClass demangleVariableStorageClass(StringView &MangledName);\n  void demangleThrowSpecification(StringView &MangledName);\n  wchar_t demangleWcharLiteral(StringView &MangledName);\n  uint8_t demangleCharLiteral(StringView &MangledName);\n\n  std::pair<Qualifiers, bool> demangleQualifiers(StringView &MangledName);\n\n  // Memory allocator.\n  ArenaAllocator Arena;\n\n  // A single type uses one global back-ref table for all function params.\n  // This means back-refs can even go \"into\" other types.  Examples:\n  //\n  //  // Second int* is a back-ref to first.\n  //  void foo(int *, int*);\n  //\n  //  // Second int* is not a back-ref to first (first is not a function param).\n  //  int* foo(int*);\n  //\n  //  // Second int* is a back-ref to first (ALL function types share the same\n  //  // back-ref map.\n  //  using F = void(*)(int*);\n  //  F G(int *);\n  BackrefContext Backrefs;\n};\n} // namespace\n\nStringView Demangler::copyString(StringView Borrowed) {\n  char *Stable = Arena.allocUnalignedBuffer(Borrowed.size() + 1);\n  std::strcpy(Stable, Borrowed.begin());\n\n  return {Stable, Borrowed.size()};\n}\n\nSpecialTableSymbolNode *\nDemangler::demangleSpecialTableSymbolNode(StringView &MangledName,\n                                          SpecialIntrinsicKind K) {\n  NamedIdentifierNode *NI = Arena.alloc<NamedIdentifierNode>();\n  switch (K) {\n  case SpecialIntrinsicKind::Vftable:\n    NI->Name = \"`vftable'\";\n    break;\n  case SpecialIntrinsicKind::Vbtable:\n    NI->Name = \"`vbtable'\";\n    break;\n  case SpecialIntrinsicKind::LocalVftable:\n    NI->Name = \"`local vftable'\";\n    break;\n  case SpecialIntrinsicKind::RttiCompleteObjLocator:\n    NI->Name = \"`RTTI Complete Object Locator'\";\n    break;\n  default:\n    LLVM_BUILTIN_UNREACHABLE;\n  }\n  QualifiedNameNode *QN = demangleNameScopeChain(MangledName, NI);\n  SpecialTableSymbolNode *STSN = Arena.alloc<SpecialTableSymbolNode>();\n  STSN->Name = QN;\n  bool IsMember = false;\n  char Front = MangledName.popFront();\n  if (Front != '6' && Front != '7') {\n    Error = true;\n    return nullptr;\n  }\n\n  std::tie(STSN->Quals, IsMember) = demangleQualifiers(MangledName);\n  if (!MangledName.consumeFront('@'))\n    STSN->TargetName = demangleFullyQualifiedTypeName(MangledName);\n  return STSN;\n}\n\nLocalStaticGuardVariableNode *\nDemangler::demangleLocalStaticGuard(StringView &MangledName) {\n  LocalStaticGuardIdentifierNode *LSGI =\n      Arena.alloc<LocalStaticGuardIdentifierNode>();\n  QualifiedNameNode *QN = demangleNameScopeChain(MangledName, LSGI);\n  LocalStaticGuardVariableNode *LSGVN =\n      Arena.alloc<LocalStaticGuardVariableNode>();\n  LSGVN->Name = QN;\n\n  if (MangledName.consumeFront(\"4IA\"))\n    LSGVN->IsVisible = false;\n  else if (MangledName.consumeFront(\"5\"))\n    LSGVN->IsVisible = true;\n  else {\n    Error = true;\n    return nullptr;\n  }\n\n  if (!MangledName.empty())\n    LSGI->ScopeIndex = demangleUnsigned(MangledName);\n  return LSGVN;\n}\n\nstatic NamedIdentifierNode *synthesizeNamedIdentifier(ArenaAllocator &Arena,\n                                                      StringView Name) {\n  NamedIdentifierNode *Id = Arena.alloc<NamedIdentifierNode>();\n  Id->Name = Name;\n  return Id;\n}\n\nstatic QualifiedNameNode *synthesizeQualifiedName(ArenaAllocator &Arena,\n                                                  IdentifierNode *Identifier) {\n  QualifiedNameNode *QN = Arena.alloc<QualifiedNameNode>();\n  QN->Components = Arena.alloc<NodeArrayNode>();\n  QN->Components->Count = 1;\n  QN->Components->Nodes = Arena.allocArray<Node *>(1);\n  QN->Components->Nodes[0] = Identifier;\n  return QN;\n}\n\nstatic QualifiedNameNode *synthesizeQualifiedName(ArenaAllocator &Arena,\n                                                  StringView Name) {\n  NamedIdentifierNode *Id = synthesizeNamedIdentifier(Arena, Name);\n  return synthesizeQualifiedName(Arena, Id);\n}\n\nstatic VariableSymbolNode *synthesizeVariable(ArenaAllocator &Arena,\n                                              TypeNode *Type,\n                                              StringView VariableName) {\n  VariableSymbolNode *VSN = Arena.alloc<VariableSymbolNode>();\n  VSN->Type = Type;\n  VSN->Name = synthesizeQualifiedName(Arena, VariableName);\n  return VSN;\n}\n\nVariableSymbolNode *Demangler::demangleUntypedVariable(\n    ArenaAllocator &Arena, StringView &MangledName, StringView VariableName) {\n  NamedIdentifierNode *NI = synthesizeNamedIdentifier(Arena, VariableName);\n  QualifiedNameNode *QN = demangleNameScopeChain(MangledName, NI);\n  VariableSymbolNode *VSN = Arena.alloc<VariableSymbolNode>();\n  VSN->Name = QN;\n  if (MangledName.consumeFront(\"8\"))\n    return VSN;\n\n  Error = true;\n  return nullptr;\n}\n\nVariableSymbolNode *\nDemangler::demangleRttiBaseClassDescriptorNode(ArenaAllocator &Arena,\n                                               StringView &MangledName) {\n  RttiBaseClassDescriptorNode *RBCDN =\n      Arena.alloc<RttiBaseClassDescriptorNode>();\n  RBCDN->NVOffset = demangleUnsigned(MangledName);\n  RBCDN->VBPtrOffset = demangleSigned(MangledName);\n  RBCDN->VBTableOffset = demangleUnsigned(MangledName);\n  RBCDN->Flags = demangleUnsigned(MangledName);\n  if (Error)\n    return nullptr;\n\n  VariableSymbolNode *VSN = Arena.alloc<VariableSymbolNode>();\n  VSN->Name = demangleNameScopeChain(MangledName, RBCDN);\n  MangledName.consumeFront('8');\n  return VSN;\n}\n\nFunctionSymbolNode *Demangler::demangleInitFiniStub(StringView &MangledName,\n                                                    bool IsDestructor) {\n  DynamicStructorIdentifierNode *DSIN =\n      Arena.alloc<DynamicStructorIdentifierNode>();\n  DSIN->IsDestructor = IsDestructor;\n\n  bool IsKnownStaticDataMember = false;\n  if (MangledName.consumeFront('?'))\n    IsKnownStaticDataMember = true;\n\n  QualifiedNameNode *QN = demangleFullyQualifiedSymbolName(MangledName);\n\n  SymbolNode *Symbol = demangleEncodedSymbol(MangledName, QN);\n  FunctionSymbolNode *FSN = nullptr;\n  Symbol->Name = QN;\n\n  if (Symbol->kind() == NodeKind::VariableSymbol) {\n    DSIN->Variable = static_cast<VariableSymbolNode *>(Symbol);\n\n    // Older versions of clang mangled this type of symbol incorrectly.  They\n    // would omit the leading ? and they would only emit a single @ at the end.\n    // The correct mangling is a leading ? and 2 trailing @ signs.  Handle\n    // both cases.\n    int AtCount = IsKnownStaticDataMember ? 2 : 1;\n    for (int I = 0; I < AtCount; ++I) {\n      if (MangledName.consumeFront('@'))\n        continue;\n      Error = true;\n      return nullptr;\n    }\n\n    FSN = demangleFunctionEncoding(MangledName);\n    FSN->Name = synthesizeQualifiedName(Arena, DSIN);\n  } else {\n    if (IsKnownStaticDataMember) {\n      // This was supposed to be a static data member, but we got a function.\n      Error = true;\n      return nullptr;\n    }\n\n    FSN = static_cast<FunctionSymbolNode *>(Symbol);\n    DSIN->Name = Symbol->Name;\n    FSN->Name = synthesizeQualifiedName(Arena, DSIN);\n  }\n\n  return FSN;\n}\n\nSymbolNode *Demangler::demangleSpecialIntrinsic(StringView &MangledName) {\n  SpecialIntrinsicKind SIK = consumeSpecialIntrinsicKind(MangledName);\n  if (SIK == SpecialIntrinsicKind::None)\n    return nullptr;\n\n  switch (SIK) {\n  case SpecialIntrinsicKind::StringLiteralSymbol:\n    return demangleStringLiteral(MangledName);\n  case SpecialIntrinsicKind::Vftable:\n  case SpecialIntrinsicKind::Vbtable:\n  case SpecialIntrinsicKind::LocalVftable:\n  case SpecialIntrinsicKind::RttiCompleteObjLocator:\n    return demangleSpecialTableSymbolNode(MangledName, SIK);\n  case SpecialIntrinsicKind::VcallThunk:\n    return demangleVcallThunkNode(MangledName);\n  case SpecialIntrinsicKind::LocalStaticGuard:\n    return demangleLocalStaticGuard(MangledName);\n  case SpecialIntrinsicKind::RttiTypeDescriptor: {\n    TypeNode *T = demangleType(MangledName, QualifierMangleMode::Result);\n    if (Error)\n      break;\n    if (!MangledName.consumeFront(\"@8\"))\n      break;\n    if (!MangledName.empty())\n      break;\n    return synthesizeVariable(Arena, T, \"`RTTI Type Descriptor'\");\n  }\n  case SpecialIntrinsicKind::RttiBaseClassArray:\n    return demangleUntypedVariable(Arena, MangledName,\n                                   \"`RTTI Base Class Array'\");\n  case SpecialIntrinsicKind::RttiClassHierarchyDescriptor:\n    return demangleUntypedVariable(Arena, MangledName,\n                                   \"`RTTI Class Hierarchy Descriptor'\");\n  case SpecialIntrinsicKind::RttiBaseClassDescriptor:\n    return demangleRttiBaseClassDescriptorNode(Arena, MangledName);\n  case SpecialIntrinsicKind::DynamicInitializer:\n    return demangleInitFiniStub(MangledName, false);\n  case SpecialIntrinsicKind::DynamicAtexitDestructor:\n    return demangleInitFiniStub(MangledName, true);\n  default:\n    break;\n  }\n  Error = true;\n  return nullptr;\n}\n\nIdentifierNode *\nDemangler::demangleFunctionIdentifierCode(StringView &MangledName) {\n  assert(MangledName.startsWith('?'));\n  MangledName = MangledName.dropFront();\n\n  if (MangledName.consumeFront(\"__\"))\n    return demangleFunctionIdentifierCode(\n        MangledName, FunctionIdentifierCodeGroup::DoubleUnder);\n  else if (MangledName.consumeFront(\"_\"))\n    return demangleFunctionIdentifierCode(MangledName,\n                                          FunctionIdentifierCodeGroup::Under);\n  return demangleFunctionIdentifierCode(MangledName,\n                                        FunctionIdentifierCodeGroup::Basic);\n}\n\nStructorIdentifierNode *\nDemangler::demangleStructorIdentifier(StringView &MangledName,\n                                      bool IsDestructor) {\n  StructorIdentifierNode *N = Arena.alloc<StructorIdentifierNode>();\n  N->IsDestructor = IsDestructor;\n  return N;\n}\n\nConversionOperatorIdentifierNode *\nDemangler::demangleConversionOperatorIdentifier(StringView &MangledName) {\n  ConversionOperatorIdentifierNode *N =\n      Arena.alloc<ConversionOperatorIdentifierNode>();\n  return N;\n}\n\nLiteralOperatorIdentifierNode *\nDemangler::demangleLiteralOperatorIdentifier(StringView &MangledName) {\n  LiteralOperatorIdentifierNode *N =\n      Arena.alloc<LiteralOperatorIdentifierNode>();\n  N->Name = demangleSimpleString(MangledName, false);\n  return N;\n}\n\nIntrinsicFunctionKind\ntranslateIntrinsicFunctionCode(char CH, FunctionIdentifierCodeGroup Group) {\n  // Not all ? identifiers are intrinsics *functions*.  This function only maps\n  // operator codes for the special functions, all others are handled elsewhere,\n  // hence the IFK::None entries in the table.\n  using IFK = IntrinsicFunctionKind;\n  static IFK Basic[36] = {\n      IFK::None,             // ?0 # Foo::Foo()\n      IFK::None,             // ?1 # Foo::~Foo()\n      IFK::New,              // ?2 # operator new\n      IFK::Delete,           // ?3 # operator delete\n      IFK::Assign,           // ?4 # operator=\n      IFK::RightShift,       // ?5 # operator>>\n      IFK::LeftShift,        // ?6 # operator<<\n      IFK::LogicalNot,       // ?7 # operator!\n      IFK::Equals,           // ?8 # operator==\n      IFK::NotEquals,        // ?9 # operator!=\n      IFK::ArraySubscript,   // ?A # operator[]\n      IFK::None,             // ?B # Foo::operator <type>()\n      IFK::Pointer,          // ?C # operator->\n      IFK::Dereference,      // ?D # operator*\n      IFK::Increment,        // ?E # operator++\n      IFK::Decrement,        // ?F # operator--\n      IFK::Minus,            // ?G # operator-\n      IFK::Plus,             // ?H # operator+\n      IFK::BitwiseAnd,       // ?I # operator&\n      IFK::MemberPointer,    // ?J # operator->*\n      IFK::Divide,           // ?K # operator/\n      IFK::Modulus,          // ?L # operator%\n      IFK::LessThan,         // ?M operator<\n      IFK::LessThanEqual,    // ?N operator<=\n      IFK::GreaterThan,      // ?O operator>\n      IFK::GreaterThanEqual, // ?P operator>=\n      IFK::Comma,            // ?Q operator,\n      IFK::Parens,           // ?R operator()\n      IFK::BitwiseNot,       // ?S operator~\n      IFK::BitwiseXor,       // ?T operator^\n      IFK::BitwiseOr,        // ?U operator|\n      IFK::LogicalAnd,       // ?V operator&&\n      IFK::LogicalOr,        // ?W operator||\n      IFK::TimesEqual,       // ?X operator*=\n      IFK::PlusEqual,        // ?Y operator+=\n      IFK::MinusEqual,       // ?Z operator-=\n  };\n  static IFK Under[36] = {\n      IFK::DivEqual,           // ?_0 operator/=\n      IFK::ModEqual,           // ?_1 operator%=\n      IFK::RshEqual,           // ?_2 operator>>=\n      IFK::LshEqual,           // ?_3 operator<<=\n      IFK::BitwiseAndEqual,    // ?_4 operator&=\n      IFK::BitwiseOrEqual,     // ?_5 operator|=\n      IFK::BitwiseXorEqual,    // ?_6 operator^=\n      IFK::None,               // ?_7 # vftable\n      IFK::None,               // ?_8 # vbtable\n      IFK::None,               // ?_9 # vcall\n      IFK::None,               // ?_A # typeof\n      IFK::None,               // ?_B # local static guard\n      IFK::None,               // ?_C # string literal\n      IFK::VbaseDtor,          // ?_D # vbase destructor\n      IFK::VecDelDtor,         // ?_E # vector deleting destructor\n      IFK::DefaultCtorClosure, // ?_F # default constructor closure\n      IFK::ScalarDelDtor,      // ?_G # scalar deleting destructor\n      IFK::VecCtorIter,        // ?_H # vector constructor iterator\n      IFK::VecDtorIter,        // ?_I # vector destructor iterator\n      IFK::VecVbaseCtorIter,   // ?_J # vector vbase constructor iterator\n      IFK::VdispMap,           // ?_K # virtual displacement map\n      IFK::EHVecCtorIter,      // ?_L # eh vector constructor iterator\n      IFK::EHVecDtorIter,      // ?_M # eh vector destructor iterator\n      IFK::EHVecVbaseCtorIter, // ?_N # eh vector vbase constructor iterator\n      IFK::CopyCtorClosure,    // ?_O # copy constructor closure\n      IFK::None,               // ?_P<name> # udt returning <name>\n      IFK::None,               // ?_Q # <unknown>\n      IFK::None,               // ?_R0 - ?_R4 # RTTI Codes\n      IFK::None,               // ?_S # local vftable\n      IFK::LocalVftableCtorClosure, // ?_T # local vftable constructor closure\n      IFK::ArrayNew,                // ?_U operator new[]\n      IFK::ArrayDelete,             // ?_V operator delete[]\n      IFK::None,                    // ?_W <unused>\n      IFK::None,                    // ?_X <unused>\n      IFK::None,                    // ?_Y <unused>\n      IFK::None,                    // ?_Z <unused>\n  };\n  static IFK DoubleUnder[36] = {\n      IFK::None,                       // ?__0 <unused>\n      IFK::None,                       // ?__1 <unused>\n      IFK::None,                       // ?__2 <unused>\n      IFK::None,                       // ?__3 <unused>\n      IFK::None,                       // ?__4 <unused>\n      IFK::None,                       // ?__5 <unused>\n      IFK::None,                       // ?__6 <unused>\n      IFK::None,                       // ?__7 <unused>\n      IFK::None,                       // ?__8 <unused>\n      IFK::None,                       // ?__9 <unused>\n      IFK::ManVectorCtorIter,          // ?__A managed vector ctor iterator\n      IFK::ManVectorDtorIter,          // ?__B managed vector dtor iterator\n      IFK::EHVectorCopyCtorIter,       // ?__C EH vector copy ctor iterator\n      IFK::EHVectorVbaseCopyCtorIter,  // ?__D EH vector vbase copy ctor iter\n      IFK::None,                       // ?__E dynamic initializer for `T'\n      IFK::None,                       // ?__F dynamic atexit destructor for `T'\n      IFK::VectorCopyCtorIter,         // ?__G vector copy constructor iter\n      IFK::VectorVbaseCopyCtorIter,    // ?__H vector vbase copy ctor iter\n      IFK::ManVectorVbaseCopyCtorIter, // ?__I managed vector vbase copy ctor\n                                       // iter\n      IFK::None,                       // ?__J local static thread guard\n      IFK::None,                       // ?__K operator \"\"_name\n      IFK::CoAwait,                    // ?__L co_await\n      IFK::None,                       // ?__M <unused>\n      IFK::None,                       // ?__N <unused>\n      IFK::None,                       // ?__O <unused>\n      IFK::None,                       // ?__P <unused>\n      IFK::None,                       // ?__Q <unused>\n      IFK::None,                       // ?__R <unused>\n      IFK::None,                       // ?__S <unused>\n      IFK::None,                       // ?__T <unused>\n      IFK::None,                       // ?__U <unused>\n      IFK::None,                       // ?__V <unused>\n      IFK::None,                       // ?__W <unused>\n      IFK::None,                       // ?__X <unused>\n      IFK::None,                       // ?__Y <unused>\n      IFK::None,                       // ?__Z <unused>\n  };\n\n  int Index = (CH >= '0' && CH <= '9') ? (CH - '0') : (CH - 'A' + 10);\n  switch (Group) {\n  case FunctionIdentifierCodeGroup::Basic:\n    return Basic[Index];\n  case FunctionIdentifierCodeGroup::Under:\n    return Under[Index];\n  case FunctionIdentifierCodeGroup::DoubleUnder:\n    return DoubleUnder[Index];\n  }\n  LLVM_BUILTIN_UNREACHABLE;\n}\n\nIdentifierNode *\nDemangler::demangleFunctionIdentifierCode(StringView &MangledName,\n                                          FunctionIdentifierCodeGroup Group) {\n  switch (Group) {\n  case FunctionIdentifierCodeGroup::Basic:\n    switch (char CH = MangledName.popFront()) {\n    case '0':\n    case '1':\n      return demangleStructorIdentifier(MangledName, CH == '1');\n    case 'B':\n      return demangleConversionOperatorIdentifier(MangledName);\n    default:\n      return Arena.alloc<IntrinsicFunctionIdentifierNode>(\n          translateIntrinsicFunctionCode(CH, Group));\n    }\n    break;\n  case FunctionIdentifierCodeGroup::Under:\n    return Arena.alloc<IntrinsicFunctionIdentifierNode>(\n        translateIntrinsicFunctionCode(MangledName.popFront(), Group));\n  case FunctionIdentifierCodeGroup::DoubleUnder:\n    switch (char CH = MangledName.popFront()) {\n    case 'K':\n      return demangleLiteralOperatorIdentifier(MangledName);\n    default:\n      return Arena.alloc<IntrinsicFunctionIdentifierNode>(\n          translateIntrinsicFunctionCode(CH, Group));\n    }\n  }\n  // No Mangling Yet:      Spaceship,                    // operator<=>\n\n  return nullptr;\n}\n\nSymbolNode *Demangler::demangleEncodedSymbol(StringView &MangledName,\n                                             QualifiedNameNode *Name) {\n  // Read a variable.\n  switch (MangledName.front()) {\n  case '0':\n  case '1':\n  case '2':\n  case '3':\n  case '4': {\n    StorageClass SC = demangleVariableStorageClass(MangledName);\n    return demangleVariableEncoding(MangledName, SC);\n  }\n  case '8':\n    return nullptr;\n  }\n  FunctionSymbolNode *FSN = demangleFunctionEncoding(MangledName);\n\n  IdentifierNode *UQN = Name->getUnqualifiedIdentifier();\n  if (UQN->kind() == NodeKind::ConversionOperatorIdentifier) {\n    ConversionOperatorIdentifierNode *COIN =\n        static_cast<ConversionOperatorIdentifierNode *>(UQN);\n    COIN->TargetType = FSN->Signature->ReturnType;\n  }\n  return FSN;\n}\n\n// Parser entry point.\nSymbolNode *Demangler::parse(StringView &MangledName) {\n  // We can't demangle MD5 names, just output them as-is.\n  // Also, MSVC-style mangled symbols must start with '?'.\n  if (MangledName.startsWith(\"??@\")) {\n    // This is an MD5 mangled name.  We can't demangle it, just return the\n    // mangled name.\n    SymbolNode *S = Arena.alloc<SymbolNode>(NodeKind::Md5Symbol);\n    S->Name = synthesizeQualifiedName(Arena, MangledName);\n    return S;\n  }\n\n  if (!MangledName.startsWith('?')) {\n    Error = true;\n    return nullptr;\n  }\n\n  MangledName.consumeFront('?');\n\n  // ?$ is a template instantiation, but all other names that start with ? are\n  // operators / special names.\n  if (SymbolNode *SI = demangleSpecialIntrinsic(MangledName))\n    return SI;\n\n  // What follows is a main symbol name. This may include namespaces or class\n  // back references.\n  QualifiedNameNode *QN = demangleFullyQualifiedSymbolName(MangledName);\n  if (Error)\n    return nullptr;\n\n  SymbolNode *Symbol = demangleEncodedSymbol(MangledName, QN);\n  if (Symbol) {\n    Symbol->Name = QN;\n  }\n\n  if (Error)\n    return nullptr;\n\n  return Symbol;\n}\n\n// <type-encoding> ::= <storage-class> <variable-type>\n// <storage-class> ::= 0  # private static member\n//                 ::= 1  # protected static member\n//                 ::= 2  # public static member\n//                 ::= 3  # global\n//                 ::= 4  # static local\n\nVariableSymbolNode *Demangler::demangleVariableEncoding(StringView &MangledName,\n                                                        StorageClass SC) {\n  VariableSymbolNode *VSN = Arena.alloc<VariableSymbolNode>();\n\n  VSN->Type = demangleType(MangledName, QualifierMangleMode::Drop);\n  VSN->SC = SC;\n\n  // <variable-type> ::= <type> <cvr-qualifiers>\n  //                 ::= <type> <pointee-cvr-qualifiers> # pointers, references\n  switch (VSN->Type->kind()) {\n  case NodeKind::PointerType: {\n    PointerTypeNode *PTN = static_cast<PointerTypeNode *>(VSN->Type);\n\n    Qualifiers ExtraChildQuals = Q_None;\n    PTN->Quals = Qualifiers(VSN->Type->Quals |\n                            demanglePointerExtQualifiers(MangledName));\n\n    bool IsMember = false;\n    std::tie(ExtraChildQuals, IsMember) = demangleQualifiers(MangledName);\n\n    if (PTN->ClassParent) {\n      QualifiedNameNode *BackRefName =\n          demangleFullyQualifiedTypeName(MangledName);\n      (void)BackRefName;\n    }\n    PTN->Pointee->Quals = Qualifiers(PTN->Pointee->Quals | ExtraChildQuals);\n\n    break;\n  }\n  default:\n    VSN->Type->Quals = demangleQualifiers(MangledName).first;\n    break;\n  }\n\n  return VSN;\n}\n\n// Sometimes numbers are encoded in mangled symbols. For example,\n// \"int (*x)[20]\" is a valid C type (x is a pointer to an array of\n// length 20), so we need some way to embed numbers as part of symbols.\n// This function parses it.\n//\n// <number>               ::= [?] <non-negative integer>\n//\n// <non-negative integer> ::= <decimal digit> # when 1 <= Number <= 10\n//                        ::= <hex digit>+ @  # when Numbrer == 0 or >= 10\n//\n// <hex-digit>            ::= [A-P]           # A = 0, B = 1, ...\nstd::pair<uint64_t, bool> Demangler::demangleNumber(StringView &MangledName) {\n  bool IsNegative = MangledName.consumeFront('?');\n\n  if (startsWithDigit(MangledName)) {\n    uint64_t Ret = MangledName[0] - '0' + 1;\n    MangledName = MangledName.dropFront(1);\n    return {Ret, IsNegative};\n  }\n\n  uint64_t Ret = 0;\n  for (size_t i = 0; i < MangledName.size(); ++i) {\n    char C = MangledName[i];\n    if (C == '@') {\n      MangledName = MangledName.dropFront(i + 1);\n      return {Ret, IsNegative};\n    }\n    if ('A' <= C && C <= 'P') {\n      Ret = (Ret << 4) + (C - 'A');\n      continue;\n    }\n    break;\n  }\n\n  Error = true;\n  return {0ULL, false};\n}\n\nuint64_t Demangler::demangleUnsigned(StringView &MangledName) {\n  bool IsNegative = false;\n  uint64_t Number = 0;\n  std::tie(Number, IsNegative) = demangleNumber(MangledName);\n  if (IsNegative)\n    Error = true;\n  return Number;\n}\n\nint64_t Demangler::demangleSigned(StringView &MangledName) {\n  bool IsNegative = false;\n  uint64_t Number = 0;\n  std::tie(Number, IsNegative) = demangleNumber(MangledName);\n  if (Number > INT64_MAX)\n    Error = true;\n  int64_t I = static_cast<int64_t>(Number);\n  return IsNegative ? -I : I;\n}\n\n// First 10 strings can be referenced by special BackReferences ?0, ?1, ..., ?9.\n// Memorize it.\nvoid Demangler::memorizeString(StringView S) {\n  if (Backrefs.NamesCount >= BackrefContext::Max)\n    return;\n  for (size_t i = 0; i < Backrefs.NamesCount; ++i)\n    if (S == Backrefs.Names[i]->Name)\n      return;\n  NamedIdentifierNode *N = Arena.alloc<NamedIdentifierNode>();\n  N->Name = S;\n  Backrefs.Names[Backrefs.NamesCount++] = N;\n}\n\nNamedIdentifierNode *Demangler::demangleBackRefName(StringView &MangledName) {\n  assert(startsWithDigit(MangledName));\n\n  size_t I = MangledName[0] - '0';\n  if (I >= Backrefs.NamesCount) {\n    Error = true;\n    return nullptr;\n  }\n\n  MangledName = MangledName.dropFront();\n  return Backrefs.Names[I];\n}\n\nvoid Demangler::memorizeIdentifier(IdentifierNode *Identifier) {\n  // Render this class template name into a string buffer so that we can\n  // memorize it for the purpose of back-referencing.\n  OutputStream OS;\n  if (initializeOutputStream(nullptr, nullptr, OS, 1024))\n    // FIXME: Propagate out-of-memory as an error?\n    std::terminate();\n  Identifier->output(OS, OF_Default);\n  OS << '\\0';\n  char *Name = OS.getBuffer();\n\n  StringView Owned = copyString(Name);\n  memorizeString(Owned);\n  std::free(Name);\n}\n\nIdentifierNode *\nDemangler::demangleTemplateInstantiationName(StringView &MangledName,\n                                             NameBackrefBehavior NBB) {\n  assert(MangledName.startsWith(\"?$\"));\n  MangledName.consumeFront(\"?$\");\n\n  BackrefContext OuterContext;\n  std::swap(OuterContext, Backrefs);\n\n  IdentifierNode *Identifier =\n      demangleUnqualifiedSymbolName(MangledName, NBB_Simple);\n  if (!Error)\n    Identifier->TemplateParams = demangleTemplateParameterList(MangledName);\n\n  std::swap(OuterContext, Backrefs);\n  if (Error)\n    return nullptr;\n\n  if (NBB & NBB_Template)\n    memorizeIdentifier(Identifier);\n\n  return Identifier;\n}\n\nNamedIdentifierNode *Demangler::demangleSimpleName(StringView &MangledName,\n                                                   bool Memorize) {\n  StringView S = demangleSimpleString(MangledName, Memorize);\n  if (Error)\n    return nullptr;\n\n  NamedIdentifierNode *Name = Arena.alloc<NamedIdentifierNode>();\n  Name->Name = S;\n  return Name;\n}\n\nstatic bool isRebasedHexDigit(char C) { return (C >= 'A' && C <= 'P'); }\n\nstatic uint8_t rebasedHexDigitToNumber(char C) {\n  assert(isRebasedHexDigit(C));\n  return (C <= 'J') ? (C - 'A') : (10 + C - 'K');\n}\n\nuint8_t Demangler::demangleCharLiteral(StringView &MangledName) {\n  if (!MangledName.startsWith('?'))\n    return MangledName.popFront();\n\n  MangledName = MangledName.dropFront();\n  if (MangledName.empty())\n    goto CharLiteralError;\n\n  if (MangledName.consumeFront('$')) {\n    // Two hex digits\n    if (MangledName.size() < 2)\n      goto CharLiteralError;\n    StringView Nibbles = MangledName.substr(0, 2);\n    if (!isRebasedHexDigit(Nibbles[0]) || !isRebasedHexDigit(Nibbles[1]))\n      goto CharLiteralError;\n    // Don't append the null terminator.\n    uint8_t C1 = rebasedHexDigitToNumber(Nibbles[0]);\n    uint8_t C2 = rebasedHexDigitToNumber(Nibbles[1]);\n    MangledName = MangledName.dropFront(2);\n    return (C1 << 4) | C2;\n  }\n\n  if (startsWithDigit(MangledName)) {\n    const char *Lookup = \",/\\\\:. \\n\\t'-\";\n    char C = Lookup[MangledName[0] - '0'];\n    MangledName = MangledName.dropFront();\n    return C;\n  }\n\n  if (MangledName[0] >= 'a' && MangledName[0] <= 'z') {\n    char Lookup[26] = {'\\xE1', '\\xE2', '\\xE3', '\\xE4', '\\xE5', '\\xE6', '\\xE7',\n                       '\\xE8', '\\xE9', '\\xEA', '\\xEB', '\\xEC', '\\xED', '\\xEE',\n                       '\\xEF', '\\xF0', '\\xF1', '\\xF2', '\\xF3', '\\xF4', '\\xF5',\n                       '\\xF6', '\\xF7', '\\xF8', '\\xF9', '\\xFA'};\n    char C = Lookup[MangledName[0] - 'a'];\n    MangledName = MangledName.dropFront();\n    return C;\n  }\n\n  if (MangledName[0] >= 'A' && MangledName[0] <= 'Z') {\n    char Lookup[26] = {'\\xC1', '\\xC2', '\\xC3', '\\xC4', '\\xC5', '\\xC6', '\\xC7',\n                       '\\xC8', '\\xC9', '\\xCA', '\\xCB', '\\xCC', '\\xCD', '\\xCE',\n                       '\\xCF', '\\xD0', '\\xD1', '\\xD2', '\\xD3', '\\xD4', '\\xD5',\n                       '\\xD6', '\\xD7', '\\xD8', '\\xD9', '\\xDA'};\n    char C = Lookup[MangledName[0] - 'A'];\n    MangledName = MangledName.dropFront();\n    return C;\n  }\n\nCharLiteralError:\n  Error = true;\n  return '\\0';\n}\n\nwchar_t Demangler::demangleWcharLiteral(StringView &MangledName) {\n  uint8_t C1, C2;\n\n  C1 = demangleCharLiteral(MangledName);\n  if (Error)\n    goto WCharLiteralError;\n  C2 = demangleCharLiteral(MangledName);\n  if (Error)\n    goto WCharLiteralError;\n\n  return ((wchar_t)C1 << 8) | (wchar_t)C2;\n\nWCharLiteralError:\n  Error = true;\n  return L'\\0';\n}\n\nstatic void writeHexDigit(char *Buffer, uint8_t Digit) {\n  assert(Digit <= 15);\n  *Buffer = (Digit < 10) ? ('0' + Digit) : ('A' + Digit - 10);\n}\n\nstatic void outputHex(OutputStream &OS, unsigned C) {\n  if (C == 0) {\n    OS << \"\\\\x00\";\n    return;\n  }\n  // It's easier to do the math if we can work from right to left, but we need\n  // to print the numbers from left to right.  So render this into a temporary\n  // buffer first, then output the temporary buffer.  Each byte is of the form\n  // \\xAB, which means that each byte needs 4 characters.  Since there are at\n  // most 4 bytes, we need a 4*4+1 = 17 character temporary buffer.\n  char TempBuffer[17];\n\n  ::memset(TempBuffer, 0, sizeof(TempBuffer));\n  constexpr int MaxPos = 15;\n\n  int Pos = MaxPos - 1;\n  while (C != 0) {\n    for (int I = 0; I < 2; ++I) {\n      writeHexDigit(&TempBuffer[Pos--], C % 16);\n      C /= 16;\n    }\n    TempBuffer[Pos--] = 'x';\n    TempBuffer[Pos--] = '\\\\';\n    assert(Pos >= 0);\n  }\n  OS << StringView(&TempBuffer[Pos + 1]);\n}\n\nstatic void outputEscapedChar(OutputStream &OS, unsigned C) {\n  switch (C) {\n  case '\\'': // single quote\n    OS << \"\\\\\\'\";\n    return;\n  case '\\\"': // double quote\n    OS << \"\\\\\\\"\";\n    return;\n  case '\\\\': // backslash\n    OS << \"\\\\\\\\\";\n    return;\n  case '\\a': // bell\n    OS << \"\\\\a\";\n    return;\n  case '\\b': // backspace\n    OS << \"\\\\b\";\n    return;\n  case '\\f': // form feed\n    OS << \"\\\\f\";\n    return;\n  case '\\n': // new line\n    OS << \"\\\\n\";\n    return;\n  case '\\r': // carriage return\n    OS << \"\\\\r\";\n    return;\n  case '\\t': // tab\n    OS << \"\\\\t\";\n    return;\n  case '\\v': // vertical tab\n    OS << \"\\\\v\";\n    return;\n  default:\n    break;\n  }\n\n  if (C > 0x1F && C < 0x7F) {\n    // Standard ascii char.\n    OS << (char)C;\n    return;\n  }\n\n  outputHex(OS, C);\n}\n\nunsigned countTrailingNullBytes(const uint8_t *StringBytes, int Length) {\n  const uint8_t *End = StringBytes + Length - 1;\n  unsigned Count = 0;\n  while (Length > 0 && *End == 0) {\n    --Length;\n    --End;\n    ++Count;\n  }\n  return Count;\n}\n\nunsigned countEmbeddedNulls(const uint8_t *StringBytes, unsigned Length) {\n  unsigned Result = 0;\n  for (unsigned I = 0; I < Length; ++I) {\n    if (*StringBytes++ == 0)\n      ++Result;\n  }\n  return Result;\n}\n\nunsigned guessCharByteSize(const uint8_t *StringBytes, unsigned NumChars,\n                           unsigned NumBytes) {\n  assert(NumBytes > 0);\n\n  // If the number of bytes is odd, this is guaranteed to be a char string.\n  if (NumBytes % 2 == 1)\n    return 1;\n\n  // All strings can encode at most 32 bytes of data.  If it's less than that,\n  // then we encoded the entire string.  In this case we check for a 1-byte,\n  // 2-byte, or 4-byte null terminator.\n  if (NumBytes < 32) {\n    unsigned TrailingNulls = countTrailingNullBytes(StringBytes, NumChars);\n    if (TrailingNulls >= 4)\n      return 4;\n    if (TrailingNulls >= 2)\n      return 2;\n    return 1;\n  }\n\n  // The whole string was not able to be encoded.  Try to look at embedded null\n  // terminators to guess.  The heuristic is that we count all embedded null\n  // terminators.  If more than 2/3 are null, it's a char32.  If more than 1/3\n  // are null, it's a char16.  Otherwise it's a char8.  This obviously isn't\n  // perfect and is biased towards languages that have ascii alphabets, but this\n  // was always going to be best effort since the encoding is lossy.\n  unsigned Nulls = countEmbeddedNulls(StringBytes, NumChars);\n  if (Nulls >= 2 * NumChars / 3)\n    return 4;\n  if (Nulls >= NumChars / 3)\n    return 2;\n  return 1;\n}\n\nstatic unsigned decodeMultiByteChar(const uint8_t *StringBytes,\n                                    unsigned CharIndex, unsigned CharBytes) {\n  assert(CharBytes == 1 || CharBytes == 2 || CharBytes == 4);\n  unsigned Offset = CharIndex * CharBytes;\n  unsigned Result = 0;\n  StringBytes = StringBytes + Offset;\n  for (unsigned I = 0; I < CharBytes; ++I) {\n    unsigned C = static_cast<unsigned>(StringBytes[I]);\n    Result |= C << (8 * I);\n  }\n  return Result;\n}\n\nFunctionSymbolNode *Demangler::demangleVcallThunkNode(StringView &MangledName) {\n  FunctionSymbolNode *FSN = Arena.alloc<FunctionSymbolNode>();\n  VcallThunkIdentifierNode *VTIN = Arena.alloc<VcallThunkIdentifierNode>();\n  FSN->Signature = Arena.alloc<ThunkSignatureNode>();\n  FSN->Signature->FunctionClass = FC_NoParameterList;\n\n  FSN->Name = demangleNameScopeChain(MangledName, VTIN);\n  if (!Error)\n    Error = !MangledName.consumeFront(\"$B\");\n  if (!Error)\n    VTIN->OffsetInVTable = demangleUnsigned(MangledName);\n  if (!Error)\n    Error = !MangledName.consumeFront('A');\n  if (!Error)\n    FSN->Signature->CallConvention = demangleCallingConvention(MangledName);\n  return (Error) ? nullptr : FSN;\n}\n\nEncodedStringLiteralNode *\nDemangler::demangleStringLiteral(StringView &MangledName) {\n  // This function uses goto, so declare all variables up front.\n  OutputStream OS;\n  StringView CRC;\n  uint64_t StringByteSize;\n  bool IsWcharT = false;\n  bool IsNegative = false;\n  size_t CrcEndPos = 0;\n  char *ResultBuffer = nullptr;\n\n  EncodedStringLiteralNode *Result = Arena.alloc<EncodedStringLiteralNode>();\n\n  // Prefix indicating the beginning of a string literal\n  if (!MangledName.consumeFront(\"@_\"))\n    goto StringLiteralError;\n  if (MangledName.empty())\n    goto StringLiteralError;\n\n  // Char Type (regular or wchar_t)\n  switch (MangledName.popFront()) {\n  case '1':\n    IsWcharT = true;\n    LLVM_FALLTHROUGH;\n  case '0':\n    break;\n  default:\n    goto StringLiteralError;\n  }\n\n  // Encoded Length\n  std::tie(StringByteSize, IsNegative) = demangleNumber(MangledName);\n  if (Error || IsNegative)\n    goto StringLiteralError;\n\n  // CRC 32 (always 8 characters plus a terminator)\n  CrcEndPos = MangledName.find('@');\n  if (CrcEndPos == StringView::npos)\n    goto StringLiteralError;\n  CRC = MangledName.substr(0, CrcEndPos);\n  MangledName = MangledName.dropFront(CrcEndPos + 1);\n  if (MangledName.empty())\n    goto StringLiteralError;\n\n  if (initializeOutputStream(nullptr, nullptr, OS, 1024))\n    // FIXME: Propagate out-of-memory as an error?\n    std::terminate();\n  if (IsWcharT) {\n    Result->Char = CharKind::Wchar;\n    if (StringByteSize > 64)\n      Result->IsTruncated = true;\n\n    while (!MangledName.consumeFront('@')) {\n      assert(StringByteSize >= 2);\n      wchar_t W = demangleWcharLiteral(MangledName);\n      if (StringByteSize != 2 || Result->IsTruncated)\n        outputEscapedChar(OS, W);\n      StringByteSize -= 2;\n      if (Error)\n        goto StringLiteralError;\n    }\n  } else {\n    // The max byte length is actually 32, but some compilers mangled strings\n    // incorrectly, so we have to assume it can go higher.\n    constexpr unsigned MaxStringByteLength = 32 * 4;\n    uint8_t StringBytes[MaxStringByteLength];\n\n    unsigned BytesDecoded = 0;\n    while (!MangledName.consumeFront('@')) {\n      assert(StringByteSize >= 1);\n      StringBytes[BytesDecoded++] = demangleCharLiteral(MangledName);\n    }\n\n    if (StringByteSize > BytesDecoded)\n      Result->IsTruncated = true;\n\n    unsigned CharBytes =\n        guessCharByteSize(StringBytes, BytesDecoded, StringByteSize);\n    assert(StringByteSize % CharBytes == 0);\n    switch (CharBytes) {\n    case 1:\n      Result->Char = CharKind::Char;\n      break;\n    case 2:\n      Result->Char = CharKind::Char16;\n      break;\n    case 4:\n      Result->Char = CharKind::Char32;\n      break;\n    default:\n      LLVM_BUILTIN_UNREACHABLE;\n    }\n    const unsigned NumChars = BytesDecoded / CharBytes;\n    for (unsigned CharIndex = 0; CharIndex < NumChars; ++CharIndex) {\n      unsigned NextChar =\n          decodeMultiByteChar(StringBytes, CharIndex, CharBytes);\n      if (CharIndex + 1 < NumChars || Result->IsTruncated)\n        outputEscapedChar(OS, NextChar);\n    }\n  }\n\n  OS << '\\0';\n  ResultBuffer = OS.getBuffer();\n  Result->DecodedString = copyString(ResultBuffer);\n  std::free(ResultBuffer);\n  return Result;\n\nStringLiteralError:\n  Error = true;\n  return nullptr;\n}\n\nStringView Demangler::demangleSimpleString(StringView &MangledName,\n                                           bool Memorize) {\n  StringView S;\n  for (size_t i = 0; i < MangledName.size(); ++i) {\n    if (MangledName[i] != '@')\n      continue;\n    S = MangledName.substr(0, i);\n    MangledName = MangledName.dropFront(i + 1);\n\n    if (Memorize)\n      memorizeString(S);\n    return S;\n  }\n\n  Error = true;\n  return {};\n}\n\nNamedIdentifierNode *\nDemangler::demangleAnonymousNamespaceName(StringView &MangledName) {\n  assert(MangledName.startsWith(\"?A\"));\n  MangledName.consumeFront(\"?A\");\n\n  NamedIdentifierNode *Node = Arena.alloc<NamedIdentifierNode>();\n  Node->Name = \"`anonymous namespace'\";\n  size_t EndPos = MangledName.find('@');\n  if (EndPos == StringView::npos) {\n    Error = true;\n    return nullptr;\n  }\n  StringView NamespaceKey = MangledName.substr(0, EndPos);\n  memorizeString(NamespaceKey);\n  MangledName = MangledName.substr(EndPos + 1);\n  return Node;\n}\n\nNamedIdentifierNode *\nDemangler::demangleLocallyScopedNamePiece(StringView &MangledName) {\n  assert(startsWithLocalScopePattern(MangledName));\n\n  NamedIdentifierNode *Identifier = Arena.alloc<NamedIdentifierNode>();\n  MangledName.consumeFront('?');\n  auto Number = demangleNumber(MangledName);\n  assert(!Number.second);\n\n  // One ? to terminate the number\n  MangledName.consumeFront('?');\n\n  assert(!Error);\n  Node *Scope = parse(MangledName);\n  if (Error)\n    return nullptr;\n\n  // Render the parent symbol's name into a buffer.\n  OutputStream OS;\n  if (initializeOutputStream(nullptr, nullptr, OS, 1024))\n    // FIXME: Propagate out-of-memory as an error?\n    std::terminate();\n  OS << '`';\n  Scope->output(OS, OF_Default);\n  OS << '\\'';\n  OS << \"::`\" << Number.first << \"'\";\n  OS << '\\0';\n  char *Result = OS.getBuffer();\n  Identifier->Name = copyString(Result);\n  std::free(Result);\n  return Identifier;\n}\n\n// Parses a type name in the form of A@B@C@@ which represents C::B::A.\nQualifiedNameNode *\nDemangler::demangleFullyQualifiedTypeName(StringView &MangledName) {\n  IdentifierNode *Identifier = demangleUnqualifiedTypeName(MangledName, true);\n  if (Error)\n    return nullptr;\n  assert(Identifier);\n\n  QualifiedNameNode *QN = demangleNameScopeChain(MangledName, Identifier);\n  if (Error)\n    return nullptr;\n  assert(QN);\n  return QN;\n}\n\n// Parses a symbol name in the form of A@B@C@@ which represents C::B::A.\n// Symbol names have slightly different rules regarding what can appear\n// so we separate out the implementations for flexibility.\nQualifiedNameNode *\nDemangler::demangleFullyQualifiedSymbolName(StringView &MangledName) {\n  // This is the final component of a symbol name (i.e. the leftmost component\n  // of a mangled name.  Since the only possible template instantiation that\n  // can appear in this context is a function template, and since those are\n  // not saved for the purposes of name backreferences, only backref simple\n  // names.\n  IdentifierNode *Identifier =\n      demangleUnqualifiedSymbolName(MangledName, NBB_Simple);\n  if (Error)\n    return nullptr;\n\n  QualifiedNameNode *QN = demangleNameScopeChain(MangledName, Identifier);\n  if (Error)\n    return nullptr;\n\n  if (Identifier->kind() == NodeKind::StructorIdentifier) {\n    StructorIdentifierNode *SIN =\n        static_cast<StructorIdentifierNode *>(Identifier);\n    assert(QN->Components->Count >= 2);\n    Node *ClassNode = QN->Components->Nodes[QN->Components->Count - 2];\n    SIN->Class = static_cast<IdentifierNode *>(ClassNode);\n  }\n  assert(QN);\n  return QN;\n}\n\nIdentifierNode *Demangler::demangleUnqualifiedTypeName(StringView &MangledName,\n                                                       bool Memorize) {\n  // An inner-most name can be a back-reference, because a fully-qualified name\n  // (e.g. Scope + Inner) can contain other fully qualified names inside of\n  // them (for example template parameters), and these nested parameters can\n  // refer to previously mangled types.\n  if (startsWithDigit(MangledName))\n    return demangleBackRefName(MangledName);\n\n  if (MangledName.startsWith(\"?$\"))\n    return demangleTemplateInstantiationName(MangledName, NBB_Template);\n\n  return demangleSimpleName(MangledName, Memorize);\n}\n\nIdentifierNode *\nDemangler::demangleUnqualifiedSymbolName(StringView &MangledName,\n                                         NameBackrefBehavior NBB) {\n  if (startsWithDigit(MangledName))\n    return demangleBackRefName(MangledName);\n  if (MangledName.startsWith(\"?$\"))\n    return demangleTemplateInstantiationName(MangledName, NBB);\n  if (MangledName.startsWith('?'))\n    return demangleFunctionIdentifierCode(MangledName);\n  return demangleSimpleName(MangledName, (NBB & NBB_Simple) != 0);\n}\n\nIdentifierNode *Demangler::demangleNameScopePiece(StringView &MangledName) {\n  if (startsWithDigit(MangledName))\n    return demangleBackRefName(MangledName);\n\n  if (MangledName.startsWith(\"?$\"))\n    return demangleTemplateInstantiationName(MangledName, NBB_Template);\n\n  if (MangledName.startsWith(\"?A\"))\n    return demangleAnonymousNamespaceName(MangledName);\n\n  if (startsWithLocalScopePattern(MangledName))\n    return demangleLocallyScopedNamePiece(MangledName);\n\n  return demangleSimpleName(MangledName, true);\n}\n\nstatic NodeArrayNode *nodeListToNodeArray(ArenaAllocator &Arena, NodeList *Head,\n                                          size_t Count) {\n  NodeArrayNode *N = Arena.alloc<NodeArrayNode>();\n  N->Count = Count;\n  N->Nodes = Arena.allocArray<Node *>(Count);\n  for (size_t I = 0; I < Count; ++I) {\n    N->Nodes[I] = Head->N;\n    Head = Head->Next;\n  }\n  return N;\n}\n\nQualifiedNameNode *\nDemangler::demangleNameScopeChain(StringView &MangledName,\n                                  IdentifierNode *UnqualifiedName) {\n  NodeList *Head = Arena.alloc<NodeList>();\n\n  Head->N = UnqualifiedName;\n\n  size_t Count = 1;\n  while (!MangledName.consumeFront(\"@\")) {\n    ++Count;\n    NodeList *NewHead = Arena.alloc<NodeList>();\n    NewHead->Next = Head;\n    Head = NewHead;\n\n    if (MangledName.empty()) {\n      Error = true;\n      return nullptr;\n    }\n\n    assert(!Error);\n    IdentifierNode *Elem = demangleNameScopePiece(MangledName);\n    if (Error)\n      return nullptr;\n\n    Head->N = Elem;\n  }\n\n  QualifiedNameNode *QN = Arena.alloc<QualifiedNameNode>();\n  QN->Components = nodeListToNodeArray(Arena, Head, Count);\n  return QN;\n}\n\nFuncClass Demangler::demangleFunctionClass(StringView &MangledName) {\n  switch (MangledName.popFront()) {\n  case '9':\n    return FuncClass(FC_ExternC | FC_NoParameterList);\n  case 'A':\n    return FC_Private;\n  case 'B':\n    return FuncClass(FC_Private | FC_Far);\n  case 'C':\n    return FuncClass(FC_Private | FC_Static);\n  case 'D':\n    return FuncClass(FC_Private | FC_Static);\n  case 'E':\n    return FuncClass(FC_Private | FC_Virtual);\n  case 'F':\n    return FuncClass(FC_Private | FC_Virtual);\n  case 'G':\n    return FuncClass(FC_Private | FC_StaticThisAdjust);\n  case 'H':\n    return FuncClass(FC_Private | FC_StaticThisAdjust | FC_Far);\n  case 'I':\n    return FuncClass(FC_Protected);\n  case 'J':\n    return FuncClass(FC_Protected | FC_Far);\n  case 'K':\n    return FuncClass(FC_Protected | FC_Static);\n  case 'L':\n    return FuncClass(FC_Protected | FC_Static | FC_Far);\n  case 'M':\n    return FuncClass(FC_Protected | FC_Virtual);\n  case 'N':\n    return FuncClass(FC_Protected | FC_Virtual | FC_Far);\n  case 'O':\n    return FuncClass(FC_Protected | FC_Virtual | FC_StaticThisAdjust);\n  case 'P':\n    return FuncClass(FC_Protected | FC_Virtual | FC_StaticThisAdjust | FC_Far);\n  case 'Q':\n    return FuncClass(FC_Public);\n  case 'R':\n    return FuncClass(FC_Public | FC_Far);\n  case 'S':\n    return FuncClass(FC_Public | FC_Static);\n  case 'T':\n    return FuncClass(FC_Public | FC_Static | FC_Far);\n  case 'U':\n    return FuncClass(FC_Public | FC_Virtual);\n  case 'V':\n    return FuncClass(FC_Public | FC_Virtual | FC_Far);\n  case 'W':\n    return FuncClass(FC_Public | FC_Virtual | FC_StaticThisAdjust);\n  case 'X':\n    return FuncClass(FC_Public | FC_Virtual | FC_StaticThisAdjust | FC_Far);\n  case 'Y':\n    return FuncClass(FC_Global);\n  case 'Z':\n    return FuncClass(FC_Global | FC_Far);\n  case '$': {\n    FuncClass VFlag = FC_VirtualThisAdjust;\n    if (MangledName.consumeFront('R'))\n      VFlag = FuncClass(VFlag | FC_VirtualThisAdjustEx);\n\n    switch (MangledName.popFront()) {\n    case '0':\n      return FuncClass(FC_Private | FC_Virtual | VFlag);\n    case '1':\n      return FuncClass(FC_Private | FC_Virtual | VFlag | FC_Far);\n    case '2':\n      return FuncClass(FC_Protected | FC_Virtual | VFlag);\n    case '3':\n      return FuncClass(FC_Protected | FC_Virtual | VFlag | FC_Far);\n    case '4':\n      return FuncClass(FC_Public | FC_Virtual | VFlag);\n    case '5':\n      return FuncClass(FC_Public | FC_Virtual | VFlag | FC_Far);\n    }\n  }\n  }\n\n  Error = true;\n  return FC_Public;\n}\n\nCallingConv Demangler::demangleCallingConvention(StringView &MangledName) {\n  switch (MangledName.popFront()) {\n  case 'A':\n  case 'B':\n    return CallingConv::Cdecl;\n  case 'C':\n  case 'D':\n    return CallingConv::Pascal;\n  case 'E':\n  case 'F':\n    return CallingConv::Thiscall;\n  case 'G':\n  case 'H':\n    return CallingConv::Stdcall;\n  case 'I':\n  case 'J':\n    return CallingConv::Fastcall;\n  case 'M':\n  case 'N':\n    return CallingConv::Clrcall;\n  case 'O':\n  case 'P':\n    return CallingConv::Eabi;\n  case 'Q':\n    return CallingConv::Vectorcall;\n  }\n\n  return CallingConv::None;\n}\n\nStorageClass Demangler::demangleVariableStorageClass(StringView &MangledName) {\n  assert(std::isdigit(MangledName.front()));\n\n  switch (MangledName.popFront()) {\n  case '0':\n    return StorageClass::PrivateStatic;\n  case '1':\n    return StorageClass::ProtectedStatic;\n  case '2':\n    return StorageClass::PublicStatic;\n  case '3':\n    return StorageClass::Global;\n  case '4':\n    return StorageClass::FunctionLocalStatic;\n  }\n  Error = true;\n  return StorageClass::None;\n}\n\nstd::pair<Qualifiers, bool>\nDemangler::demangleQualifiers(StringView &MangledName) {\n\n  switch (MangledName.popFront()) {\n  // Member qualifiers\n  case 'Q':\n    return std::make_pair(Q_None, true);\n  case 'R':\n    return std::make_pair(Q_Const, true);\n  case 'S':\n    return std::make_pair(Q_Volatile, true);\n  case 'T':\n    return std::make_pair(Qualifiers(Q_Const | Q_Volatile), true);\n  // Non-Member qualifiers\n  case 'A':\n    return std::make_pair(Q_None, false);\n  case 'B':\n    return std::make_pair(Q_Const, false);\n  case 'C':\n    return std::make_pair(Q_Volatile, false);\n  case 'D':\n    return std::make_pair(Qualifiers(Q_Const | Q_Volatile), false);\n  }\n  Error = true;\n  return std::make_pair(Q_None, false);\n}\n\n// <variable-type> ::= <type> <cvr-qualifiers>\n//                 ::= <type> <pointee-cvr-qualifiers> # pointers, references\nTypeNode *Demangler::demangleType(StringView &MangledName,\n                                  QualifierMangleMode QMM) {\n  Qualifiers Quals = Q_None;\n  bool IsMember = false;\n  if (QMM == QualifierMangleMode::Mangle) {\n    std::tie(Quals, IsMember) = demangleQualifiers(MangledName);\n  } else if (QMM == QualifierMangleMode::Result) {\n    if (MangledName.consumeFront('?'))\n      std::tie(Quals, IsMember) = demangleQualifiers(MangledName);\n  }\n\n  TypeNode *Ty = nullptr;\n  if (isTagType(MangledName))\n    Ty = demangleClassType(MangledName);\n  else if (isPointerType(MangledName)) {\n    if (isMemberPointer(MangledName))\n      Ty = demangleMemberPointerType(MangledName);\n    else\n      Ty = demanglePointerType(MangledName);\n  } else if (isArrayType(MangledName))\n    Ty = demangleArrayType(MangledName);\n  else if (isFunctionType(MangledName)) {\n    if (MangledName.consumeFront(\"$$A8@@\"))\n      Ty = demangleFunctionType(MangledName, true);\n    else {\n      assert(MangledName.startsWith(\"$$A6\"));\n      MangledName.consumeFront(\"$$A6\");\n      Ty = demangleFunctionType(MangledName, false);\n    }\n  } else if (isCustomType(MangledName)) {\n    Ty = demangleCustomType(MangledName);\n  } else {\n    Ty = demanglePrimitiveType(MangledName);\n    if (!Ty || Error)\n      return Ty;\n  }\n\n  Ty->Quals = Qualifiers(Ty->Quals | Quals);\n  return Ty;\n}\n\nvoid Demangler::demangleThrowSpecification(StringView &MangledName) {\n  if (MangledName.consumeFront('Z'))\n    return;\n\n  Error = true;\n}\n\nFunctionSignatureNode *Demangler::demangleFunctionType(StringView &MangledName,\n                                                       bool HasThisQuals) {\n  FunctionSignatureNode *FTy = Arena.alloc<FunctionSignatureNode>();\n\n  if (HasThisQuals) {\n    FTy->Quals = demanglePointerExtQualifiers(MangledName);\n    FTy->RefQualifier = demangleFunctionRefQualifier(MangledName);\n    FTy->Quals = Qualifiers(FTy->Quals | demangleQualifiers(MangledName).first);\n  }\n\n  // Fields that appear on both member and non-member functions.\n  FTy->CallConvention = demangleCallingConvention(MangledName);\n\n  // <return-type> ::= <type>\n  //               ::= @ # structors (they have no declared return type)\n  bool IsStructor = MangledName.consumeFront('@');\n  if (!IsStructor)\n    FTy->ReturnType = demangleType(MangledName, QualifierMangleMode::Result);\n\n  FTy->Params = demangleFunctionParameterList(MangledName);\n\n  demangleThrowSpecification(MangledName);\n\n  return FTy;\n}\n\nFunctionSymbolNode *\nDemangler::demangleFunctionEncoding(StringView &MangledName) {\n  FuncClass ExtraFlags = FC_None;\n  if (MangledName.consumeFront(\"$$J0\"))\n    ExtraFlags = FC_ExternC;\n\n  FuncClass FC = demangleFunctionClass(MangledName);\n  FC = FuncClass(ExtraFlags | FC);\n\n  FunctionSignatureNode *FSN = nullptr;\n  ThunkSignatureNode *TTN = nullptr;\n  if (FC & FC_StaticThisAdjust) {\n    TTN = Arena.alloc<ThunkSignatureNode>();\n    TTN->ThisAdjust.StaticOffset = demangleSigned(MangledName);\n  } else if (FC & FC_VirtualThisAdjust) {\n    TTN = Arena.alloc<ThunkSignatureNode>();\n    if (FC & FC_VirtualThisAdjustEx) {\n      TTN->ThisAdjust.VBPtrOffset = demangleSigned(MangledName);\n      TTN->ThisAdjust.VBOffsetOffset = demangleSigned(MangledName);\n    }\n    TTN->ThisAdjust.VtordispOffset = demangleSigned(MangledName);\n    TTN->ThisAdjust.StaticOffset = demangleSigned(MangledName);\n  }\n\n  if (FC & FC_NoParameterList) {\n    // This is an extern \"C\" function whose full signature hasn't been mangled.\n    // This happens when we need to mangle a local symbol inside of an extern\n    // \"C\" function.\n    FSN = Arena.alloc<FunctionSignatureNode>();\n  } else {\n    bool HasThisQuals = !(FC & (FC_Global | FC_Static));\n    FSN = demangleFunctionType(MangledName, HasThisQuals);\n  }\n  if (TTN) {\n    *static_cast<FunctionSignatureNode *>(TTN) = *FSN;\n    FSN = TTN;\n  }\n  FSN->FunctionClass = FC;\n\n  FunctionSymbolNode *Symbol = Arena.alloc<FunctionSymbolNode>();\n  Symbol->Signature = FSN;\n  return Symbol;\n}\n\nCustomTypeNode *Demangler::demangleCustomType(StringView &MangledName) {\n  assert(MangledName.startsWith('?'));\n  MangledName.popFront();\n\n  CustomTypeNode *CTN = Arena.alloc<CustomTypeNode>();\n  CTN->Identifier = demangleUnqualifiedTypeName(MangledName, true);\n  if (!MangledName.consumeFront('@'))\n    Error = true;\n  if (Error)\n    return nullptr;\n  return CTN;\n}\n\n// Reads a primitive type.\nPrimitiveTypeNode *Demangler::demanglePrimitiveType(StringView &MangledName) {\n  if (MangledName.consumeFront(\"$$T\"))\n    return Arena.alloc<PrimitiveTypeNode>(PrimitiveKind::Nullptr);\n\n  switch (MangledName.popFront()) {\n  case 'X':\n    return Arena.alloc<PrimitiveTypeNode>(PrimitiveKind::Void);\n  case 'D':\n    return Arena.alloc<PrimitiveTypeNode>(PrimitiveKind::Char);\n  case 'C':\n    return Arena.alloc<PrimitiveTypeNode>(PrimitiveKind::Schar);\n  case 'E':\n    return Arena.alloc<PrimitiveTypeNode>(PrimitiveKind::Uchar);\n  case 'F':\n    return Arena.alloc<PrimitiveTypeNode>(PrimitiveKind::Short);\n  case 'G':\n    return Arena.alloc<PrimitiveTypeNode>(PrimitiveKind::Ushort);\n  case 'H':\n    return Arena.alloc<PrimitiveTypeNode>(PrimitiveKind::Int);\n  case 'I':\n    return Arena.alloc<PrimitiveTypeNode>(PrimitiveKind::Uint);\n  case 'J':\n    return Arena.alloc<PrimitiveTypeNode>(PrimitiveKind::Long);\n  case 'K':\n    return Arena.alloc<PrimitiveTypeNode>(PrimitiveKind::Ulong);\n  case 'M':\n    return Arena.alloc<PrimitiveTypeNode>(PrimitiveKind::Float);\n  case 'N':\n    return Arena.alloc<PrimitiveTypeNode>(PrimitiveKind::Double);\n  case 'O':\n    return Arena.alloc<PrimitiveTypeNode>(PrimitiveKind::Ldouble);\n  case '_': {\n    if (MangledName.empty()) {\n      Error = true;\n      return nullptr;\n    }\n    switch (MangledName.popFront()) {\n    case 'N':\n      return Arena.alloc<PrimitiveTypeNode>(PrimitiveKind::Bool);\n    case 'J':\n      return Arena.alloc<PrimitiveTypeNode>(PrimitiveKind::Int64);\n    case 'K':\n      return Arena.alloc<PrimitiveTypeNode>(PrimitiveKind::Uint64);\n    case 'W':\n      return Arena.alloc<PrimitiveTypeNode>(PrimitiveKind::Wchar);\n    case 'S':\n      return Arena.alloc<PrimitiveTypeNode>(PrimitiveKind::Char16);\n    case 'U':\n      return Arena.alloc<PrimitiveTypeNode>(PrimitiveKind::Char32);\n    }\n    break;\n  }\n  }\n  Error = true;\n  return nullptr;\n}\n\nTagTypeNode *Demangler::demangleClassType(StringView &MangledName) {\n  TagTypeNode *TT = nullptr;\n\n  switch (MangledName.popFront()) {\n  case 'T':\n    TT = Arena.alloc<TagTypeNode>(TagKind::Union);\n    break;\n  case 'U':\n    TT = Arena.alloc<TagTypeNode>(TagKind::Struct);\n    break;\n  case 'V':\n    TT = Arena.alloc<TagTypeNode>(TagKind::Class);\n    break;\n  case 'W':\n    if (MangledName.popFront() != '4') {\n      Error = true;\n      return nullptr;\n    }\n    TT = Arena.alloc<TagTypeNode>(TagKind::Enum);\n    break;\n  default:\n    assert(false);\n  }\n\n  TT->QualifiedName = demangleFullyQualifiedTypeName(MangledName);\n  return TT;\n}\n\n// <pointer-type> ::= E? <pointer-cvr-qualifiers> <ext-qualifiers> <type>\n//                       # the E is required for 64-bit non-static pointers\nPointerTypeNode *Demangler::demanglePointerType(StringView &MangledName) {\n  PointerTypeNode *Pointer = Arena.alloc<PointerTypeNode>();\n\n  std::tie(Pointer->Quals, Pointer->Affinity) =\n      demanglePointerCVQualifiers(MangledName);\n\n  if (MangledName.consumeFront(\"6\")) {\n    Pointer->Pointee = demangleFunctionType(MangledName, false);\n    return Pointer;\n  }\n\n  Qualifiers ExtQuals = demanglePointerExtQualifiers(MangledName);\n  Pointer->Quals = Qualifiers(Pointer->Quals | ExtQuals);\n\n  Pointer->Pointee = demangleType(MangledName, QualifierMangleMode::Mangle);\n  return Pointer;\n}\n\nPointerTypeNode *Demangler::demangleMemberPointerType(StringView &MangledName) {\n  PointerTypeNode *Pointer = Arena.alloc<PointerTypeNode>();\n\n  std::tie(Pointer->Quals, Pointer->Affinity) =\n      demanglePointerCVQualifiers(MangledName);\n  assert(Pointer->Affinity == PointerAffinity::Pointer);\n\n  Qualifiers ExtQuals = demanglePointerExtQualifiers(MangledName);\n  Pointer->Quals = Qualifiers(Pointer->Quals | ExtQuals);\n\n  if (MangledName.consumeFront(\"8\")) {\n    Pointer->ClassParent = demangleFullyQualifiedTypeName(MangledName);\n    Pointer->Pointee = demangleFunctionType(MangledName, true);\n  } else {\n    Qualifiers PointeeQuals = Q_None;\n    bool IsMember = false;\n    std::tie(PointeeQuals, IsMember) = demangleQualifiers(MangledName);\n    assert(IsMember);\n    Pointer->ClassParent = demangleFullyQualifiedTypeName(MangledName);\n\n    Pointer->Pointee = demangleType(MangledName, QualifierMangleMode::Drop);\n    Pointer->Pointee->Quals = PointeeQuals;\n  }\n\n  return Pointer;\n}\n\nQualifiers Demangler::demanglePointerExtQualifiers(StringView &MangledName) {\n  Qualifiers Quals = Q_None;\n  if (MangledName.consumeFront('E'))\n    Quals = Qualifiers(Quals | Q_Pointer64);\n  if (MangledName.consumeFront('I'))\n    Quals = Qualifiers(Quals | Q_Restrict);\n  if (MangledName.consumeFront('F'))\n    Quals = Qualifiers(Quals | Q_Unaligned);\n\n  return Quals;\n}\n\nArrayTypeNode *Demangler::demangleArrayType(StringView &MangledName) {\n  assert(MangledName.front() == 'Y');\n  MangledName.popFront();\n\n  uint64_t Rank = 0;\n  bool IsNegative = false;\n  std::tie(Rank, IsNegative) = demangleNumber(MangledName);\n  if (IsNegative || Rank == 0) {\n    Error = true;\n    return nullptr;\n  }\n\n  ArrayTypeNode *ATy = Arena.alloc<ArrayTypeNode>();\n  NodeList *Head = Arena.alloc<NodeList>();\n  NodeList *Tail = Head;\n\n  for (uint64_t I = 0; I < Rank; ++I) {\n    uint64_t D = 0;\n    std::tie(D, IsNegative) = demangleNumber(MangledName);\n    if (IsNegative) {\n      Error = true;\n      return nullptr;\n    }\n    Tail->N = Arena.alloc<IntegerLiteralNode>(D, IsNegative);\n    if (I + 1 < Rank) {\n      Tail->Next = Arena.alloc<NodeList>();\n      Tail = Tail->Next;\n    }\n  }\n  ATy->Dimensions = nodeListToNodeArray(Arena, Head, Rank);\n\n  if (MangledName.consumeFront(\"$$C\")) {\n    bool IsMember = false;\n    std::tie(ATy->Quals, IsMember) = demangleQualifiers(MangledName);\n    if (IsMember) {\n      Error = true;\n      return nullptr;\n    }\n  }\n\n  ATy->ElementType = demangleType(MangledName, QualifierMangleMode::Drop);\n  return ATy;\n}\n\n// Reads a function or a template parameters.\nNodeArrayNode *\nDemangler::demangleFunctionParameterList(StringView &MangledName) {\n  // Empty parameter list.\n  if (MangledName.consumeFront('X'))\n    return {};\n\n  NodeList *Head = Arena.alloc<NodeList>();\n  NodeList **Current = &Head;\n  size_t Count = 0;\n  while (!Error && !MangledName.startsWith('@') &&\n         !MangledName.startsWith('Z')) {\n    ++Count;\n\n    if (startsWithDigit(MangledName)) {\n      size_t N = MangledName[0] - '0';\n      if (N >= Backrefs.FunctionParamCount) {\n        Error = true;\n        return {};\n      }\n      MangledName = MangledName.dropFront();\n\n      *Current = Arena.alloc<NodeList>();\n      (*Current)->N = Backrefs.FunctionParams[N];\n      Current = &(*Current)->Next;\n      continue;\n    }\n\n    size_t OldSize = MangledName.size();\n\n    *Current = Arena.alloc<NodeList>();\n    TypeNode *TN = demangleType(MangledName, QualifierMangleMode::Drop);\n\n    (*Current)->N = TN;\n\n    size_t CharsConsumed = OldSize - MangledName.size();\n    assert(CharsConsumed != 0);\n\n    // Single-letter types are ignored for backreferences because memorizing\n    // them doesn't save anything.\n    if (Backrefs.FunctionParamCount <= 9 && CharsConsumed > 1)\n      Backrefs.FunctionParams[Backrefs.FunctionParamCount++] = TN;\n\n    Current = &(*Current)->Next;\n  }\n\n  if (Error)\n    return {};\n\n  NodeArrayNode *NA = nodeListToNodeArray(Arena, Head, Count);\n  // A non-empty parameter list is terminated by either 'Z' (variadic) parameter\n  // list or '@' (non variadic).  Careful not to consume \"@Z\", as in that case\n  // the following Z could be a throw specifier.\n  if (MangledName.consumeFront('@'))\n    return NA;\n\n  if (MangledName.consumeFront('Z')) {\n    // This is a variadic parameter list.  We probably need a variadic node to\n    // append to the end.\n    return NA;\n  }\n\n  Error = true;\n  return {};\n}\n\nNodeArrayNode *\nDemangler::demangleTemplateParameterList(StringView &MangledName) {\n  NodeList *Head;\n  NodeList **Current = &Head;\n  size_t Count = 0;\n\n  while (!Error && !MangledName.startsWith('@')) {\n    if (MangledName.consumeFront(\"$S\") || MangledName.consumeFront(\"$$V\") ||\n        MangledName.consumeFront(\"$$$V\") || MangledName.consumeFront(\"$$Z\")) {\n      // parameter pack separator\n      continue;\n    }\n\n    ++Count;\n\n    // Template parameter lists don't participate in back-referencing.\n    *Current = Arena.alloc<NodeList>();\n\n    NodeList &TP = **Current;\n\n    TemplateParameterReferenceNode *TPRN = nullptr;\n    if (MangledName.consumeFront(\"$$Y\")) {\n      // Template alias\n      TP.N = demangleFullyQualifiedTypeName(MangledName);\n    } else if (MangledName.consumeFront(\"$$B\")) {\n      // Array\n      TP.N = demangleType(MangledName, QualifierMangleMode::Drop);\n    } else if (MangledName.consumeFront(\"$$C\")) {\n      // Type has qualifiers.\n      TP.N = demangleType(MangledName, QualifierMangleMode::Mangle);\n    } else if (MangledName.startsWith(\"$1\") || MangledName.startsWith(\"$H\") ||\n               MangledName.startsWith(\"$I\") || MangledName.startsWith(\"$J\")) {\n      // Pointer to member\n      TP.N = TPRN = Arena.alloc<TemplateParameterReferenceNode>();\n      TPRN->IsMemberPointer = true;\n\n      MangledName = MangledName.dropFront();\n      // 1 - single inheritance       <name>\n      // H - multiple inheritance     <name> <number>\n      // I - virtual inheritance      <name> <number> <number> <number>\n      // J - unspecified inheritance  <name> <number> <number> <number>\n      char InheritanceSpecifier = MangledName.popFront();\n      SymbolNode *S = nullptr;\n      if (MangledName.startsWith('?')) {\n        S = parse(MangledName);\n        memorizeIdentifier(S->Name->getUnqualifiedIdentifier());\n      }\n\n      switch (InheritanceSpecifier) {\n      case 'J':\n        TPRN->ThunkOffsets[TPRN->ThunkOffsetCount++] =\n            demangleSigned(MangledName);\n        LLVM_FALLTHROUGH;\n      case 'I':\n        TPRN->ThunkOffsets[TPRN->ThunkOffsetCount++] =\n            demangleSigned(MangledName);\n        LLVM_FALLTHROUGH;\n      case 'H':\n        TPRN->ThunkOffsets[TPRN->ThunkOffsetCount++] =\n            demangleSigned(MangledName);\n        LLVM_FALLTHROUGH;\n      case '1':\n        break;\n      default:\n        Error = true;\n        break;\n      }\n      TPRN->Affinity = PointerAffinity::Pointer;\n      TPRN->Symbol = S;\n    } else if (MangledName.startsWith(\"$E?\")) {\n      MangledName.consumeFront(\"$E\");\n      // Reference to symbol\n      TP.N = TPRN = Arena.alloc<TemplateParameterReferenceNode>();\n      TPRN->Symbol = parse(MangledName);\n      TPRN->Affinity = PointerAffinity::Reference;\n    } else if (MangledName.startsWith(\"$F\") || MangledName.startsWith(\"$G\")) {\n      TP.N = TPRN = Arena.alloc<TemplateParameterReferenceNode>();\n\n      // Data member pointer.\n      MangledName = MangledName.dropFront();\n      char InheritanceSpecifier = MangledName.popFront();\n\n      switch (InheritanceSpecifier) {\n      case 'G':\n        TPRN->ThunkOffsets[TPRN->ThunkOffsetCount++] =\n            demangleSigned(MangledName);\n        LLVM_FALLTHROUGH;\n      case 'F':\n        TPRN->ThunkOffsets[TPRN->ThunkOffsetCount++] =\n            demangleSigned(MangledName);\n        TPRN->ThunkOffsets[TPRN->ThunkOffsetCount++] =\n            demangleSigned(MangledName);\n        LLVM_FALLTHROUGH;\n      case '0':\n        break;\n      default:\n        Error = true;\n        break;\n      }\n      TPRN->IsMemberPointer = true;\n\n    } else if (MangledName.consumeFront(\"$0\")) {\n      // Integral non-type template parameter\n      bool IsNegative = false;\n      uint64_t Value = 0;\n      std::tie(Value, IsNegative) = demangleNumber(MangledName);\n\n      TP.N = Arena.alloc<IntegerLiteralNode>(Value, IsNegative);\n    } else {\n      TP.N = demangleType(MangledName, QualifierMangleMode::Drop);\n    }\n    if (Error)\n      return nullptr;\n\n    Current = &TP.Next;\n  }\n\n  if (Error)\n    return nullptr;\n\n  // Template parameter lists cannot be variadic, so it can only be terminated\n  // by @.\n  if (MangledName.consumeFront('@'))\n    return nodeListToNodeArray(Arena, Head, Count);\n  Error = true;\n  return nullptr;\n}\n\nvoid Demangler::dumpBackReferences() {\n  std::printf(\"%d function parameter backreferences\\n\",\n              (int)Backrefs.FunctionParamCount);\n\n  // Create an output stream so we can render each type.\n  OutputStream OS;\n  if (initializeOutputStream(nullptr, nullptr, OS, 1024))\n    std::terminate();\n  for (size_t I = 0; I < Backrefs.FunctionParamCount; ++I) {\n    OS.setCurrentPosition(0);\n\n    TypeNode *T = Backrefs.FunctionParams[I];\n    T->output(OS, OF_Default);\n\n    std::printf(\"  [%d] - %.*s\\n\", (int)I, (int)OS.getCurrentPosition(),\n                OS.getBuffer());\n  }\n  std::free(OS.getBuffer());\n\n  if (Backrefs.FunctionParamCount > 0)\n    std::printf(\"\\n\");\n  std::printf(\"%d name backreferences\\n\", (int)Backrefs.NamesCount);\n  for (size_t I = 0; I < Backrefs.NamesCount; ++I) {\n    std::printf(\"  [%d] - %.*s\\n\", (int)I, (int)Backrefs.Names[I]->Name.size(),\n                Backrefs.Names[I]->Name.begin());\n  }\n  if (Backrefs.NamesCount > 0)\n    std::printf(\"\\n\");\n}\n\nchar *llvm::microsoftDemangle(const char *MangledName, char *Buf, size_t *N,\n                              int *Status, MSDemangleFlags Flags) {\n  int InternalStatus = demangle_success;\n  Demangler D;\n  OutputStream S;\n\n  StringView Name{MangledName};\n  SymbolNode *AST = D.parse(Name);\n\n  if (Flags & MSDF_DumpBackrefs)\n    D.dumpBackReferences();\n\n  if (D.Error)\n    InternalStatus = demangle_invalid_mangled_name;\n  else if (initializeOutputStream(Buf, N, S, 1024))\n    InternalStatus = demangle_memory_alloc_failure;\n  else {\n    AST->output(S, OF_Default);\n    S += '\\0';\n    if (N != nullptr)\n      *N = S.getCurrentPosition();\n    Buf = S.getBuffer();\n  }\n\n  if (Status)\n    *Status = InternalStatus;\n  return InternalStatus == demangle_success ? Buf : nullptr;\n}\n"
  },
  {
    "path": "third_party/llvm-demangle/lib/Demangle/MicrosoftDemangleNodes.cpp",
    "content": "//===- MicrosoftDemangle.cpp ----------------------------------------------===//\n//\n//                     The LLVM Compiler Infrastructure\n//\n// This file is dual licensed under the MIT and the University of Illinois Open\n// Source Licenses. See LICENSE.TXT for details.\n//\n//===----------------------------------------------------------------------===//\n//\n// This file defines a demangler for MSVC-style mangled symbols.\n//\n//===----------------------------------------------------------------------===//\n\n#include \"MicrosoftDemangleNodes.h\"\n#include \"llvm/Demangle/Compiler.h\"\n#include \"llvm/Demangle/Utility.h\"\n#include <cctype>\n\nusing namespace llvm;\nusing namespace ms_demangle;\n\n#define OUTPUT_ENUM_CLASS_VALUE(Enum, Value, Desc)                             \\\n  case Enum::Value:                                                            \\\n    OS << Desc;                                                                \\\n    break;\n\n// Writes a space if the last token does not end with a punctuation.\nstatic void outputSpaceIfNecessary(OutputStream &OS) {\n  if (OS.empty())\n    return;\n\n  char C = OS.back();\n  if (std::isalnum(C) || C == '>')\n    OS << \" \";\n}\n\nstatic bool outputSingleQualifier(OutputStream &OS, Qualifiers Q) {\n  switch (Q) {\n  case Q_Const:\n    OS << \"const\";\n    return true;\n  case Q_Volatile:\n    OS << \"volatile\";\n    return true;\n  case Q_Restrict:\n    OS << \"__restrict\";\n    return true;\n  default:\n    break;\n  }\n  return false;\n}\n\nstatic bool outputQualifierIfPresent(OutputStream &OS, Qualifiers Q,\n                                     Qualifiers Mask, bool NeedSpace) {\n  if (!(Q & Mask))\n    return NeedSpace;\n\n  if (NeedSpace)\n    OS << \" \";\n\n  outputSingleQualifier(OS, Mask);\n  return true;\n}\n\nstatic void outputQualifiers(OutputStream &OS, Qualifiers Q, bool SpaceBefore,\n                             bool SpaceAfter) {\n  if (Q == Q_None)\n    return;\n\n  size_t Pos1 = OS.getCurrentPosition();\n  SpaceBefore = outputQualifierIfPresent(OS, Q, Q_Const, SpaceBefore);\n  SpaceBefore = outputQualifierIfPresent(OS, Q, Q_Volatile, SpaceBefore);\n  SpaceBefore = outputQualifierIfPresent(OS, Q, Q_Restrict, SpaceBefore);\n  size_t Pos2 = OS.getCurrentPosition();\n  if (SpaceAfter && Pos2 > Pos1)\n    OS << \" \";\n}\n\nstatic void outputCallingConvention(OutputStream &OS, CallingConv CC) {\n  outputSpaceIfNecessary(OS);\n\n  switch (CC) {\n  case CallingConv::Cdecl:\n    OS << \"__cdecl\";\n    break;\n  case CallingConv::Fastcall:\n    OS << \"__fastcall\";\n    break;\n  case CallingConv::Pascal:\n    OS << \"__pascal\";\n    break;\n  case CallingConv::Regcall:\n    OS << \"__regcall\";\n    break;\n  case CallingConv::Stdcall:\n    OS << \"__stdcall\";\n    break;\n  case CallingConv::Thiscall:\n    OS << \"__thiscall\";\n    break;\n  case CallingConv::Eabi:\n    OS << \"__eabi\";\n    break;\n  case CallingConv::Vectorcall:\n    OS << \"__vectorcall\";\n    break;\n  case CallingConv::Clrcall:\n    OS << \"__clrcall\";\n    break;\n  default:\n    break;\n  }\n}\n\nvoid TypeNode::outputQuals(bool SpaceBefore, bool SpaceAfter) const {}\n\nvoid PrimitiveTypeNode::outputPre(OutputStream &OS, OutputFlags Flags) const {\n  switch (PrimKind) {\n    OUTPUT_ENUM_CLASS_VALUE(PrimitiveKind, Void, \"void\");\n    OUTPUT_ENUM_CLASS_VALUE(PrimitiveKind, Bool, \"bool\");\n    OUTPUT_ENUM_CLASS_VALUE(PrimitiveKind, Char, \"char\");\n    OUTPUT_ENUM_CLASS_VALUE(PrimitiveKind, Schar, \"signed char\");\n    OUTPUT_ENUM_CLASS_VALUE(PrimitiveKind, Uchar, \"unsigned char\");\n    OUTPUT_ENUM_CLASS_VALUE(PrimitiveKind, Char16, \"char16_t\");\n    OUTPUT_ENUM_CLASS_VALUE(PrimitiveKind, Char32, \"char32_t\");\n    OUTPUT_ENUM_CLASS_VALUE(PrimitiveKind, Short, \"short\");\n    OUTPUT_ENUM_CLASS_VALUE(PrimitiveKind, Ushort, \"unsigned short\");\n    OUTPUT_ENUM_CLASS_VALUE(PrimitiveKind, Int, \"int\");\n    OUTPUT_ENUM_CLASS_VALUE(PrimitiveKind, Uint, \"unsigned int\");\n    OUTPUT_ENUM_CLASS_VALUE(PrimitiveKind, Long, \"long\");\n    OUTPUT_ENUM_CLASS_VALUE(PrimitiveKind, Ulong, \"unsigned long\");\n    OUTPUT_ENUM_CLASS_VALUE(PrimitiveKind, Int64, \"__int64\");\n    OUTPUT_ENUM_CLASS_VALUE(PrimitiveKind, Uint64, \"unsigned __int64\");\n    OUTPUT_ENUM_CLASS_VALUE(PrimitiveKind, Wchar, \"wchar_t\");\n    OUTPUT_ENUM_CLASS_VALUE(PrimitiveKind, Float, \"float\");\n    OUTPUT_ENUM_CLASS_VALUE(PrimitiveKind, Double, \"double\");\n    OUTPUT_ENUM_CLASS_VALUE(PrimitiveKind, Ldouble, \"long double\");\n    OUTPUT_ENUM_CLASS_VALUE(PrimitiveKind, Nullptr, \"std::nullptr_t\");\n  }\n  outputQualifiers(OS, Quals, true, false);\n}\n\nvoid NodeArrayNode::output(OutputStream &OS, OutputFlags Flags) const {\n  output(OS, Flags, \", \");\n}\n\nvoid NodeArrayNode::output(OutputStream &OS, OutputFlags Flags,\n                           StringView Separator) const {\n  if (Count == 0)\n    return;\n  if (Nodes[0])\n    Nodes[0]->output(OS, Flags);\n  for (size_t I = 1; I < Count; ++I) {\n    OS << Separator;\n    Nodes[I]->output(OS, Flags);\n  }\n}\n\nvoid EncodedStringLiteralNode::output(OutputStream &OS,\n                                      OutputFlags Flags) const {\n  switch (Char) {\n  case CharKind::Wchar:\n    OS << \"const wchar_t * {L\\\"\";\n    break;\n  case CharKind::Char:\n    OS << \"const char * {\\\"\";\n    break;\n  case CharKind::Char16:\n    OS << \"const char16_t * {u\\\"\";\n    break;\n  case CharKind::Char32:\n    OS << \"const char32_t * {U\\\"\";\n    break;\n  }\n  OS << DecodedString << \"\\\"\";\n  if (IsTruncated)\n    OS << \"...\";\n  OS << \"}\";\n}\n\nvoid IntegerLiteralNode::output(OutputStream &OS, OutputFlags Flags) const {\n  if (IsNegative)\n    OS << '-';\n  OS << Value;\n}\n\nvoid TemplateParameterReferenceNode::output(OutputStream &OS,\n                                            OutputFlags Flags) const {\n  if (ThunkOffsetCount > 0)\n    OS << \"{\";\n  else if (Affinity == PointerAffinity::Pointer)\n    OS << \"&\";\n\n  if (Symbol) {\n    Symbol->output(OS, Flags);\n    if (ThunkOffsetCount > 0)\n      OS << \", \";\n  }\n\n  if (ThunkOffsetCount > 0)\n    OS << ThunkOffsets[0];\n  for (int I = 1; I < ThunkOffsetCount; ++I) {\n    OS << \", \" << ThunkOffsets[I];\n  }\n  if (ThunkOffsetCount > 0)\n    OS << \"}\";\n}\n\nvoid IdentifierNode::outputTemplateParameters(OutputStream &OS,\n                                              OutputFlags Flags) const {\n  if (!TemplateParams)\n    return;\n  OS << \"<\";\n  TemplateParams->output(OS, Flags);\n  OS << \">\";\n}\n\nvoid DynamicStructorIdentifierNode::output(OutputStream &OS,\n                                           OutputFlags Flags) const {\n  if (IsDestructor)\n    OS << \"`dynamic atexit destructor for \";\n  else\n    OS << \"`dynamic initializer for \";\n\n  if (Variable) {\n    OS << \"`\";\n    Variable->output(OS, Flags);\n    OS << \"''\";\n  } else {\n    OS << \"'\";\n    Name->output(OS, Flags);\n    OS << \"''\";\n  }\n}\n\nvoid NamedIdentifierNode::output(OutputStream &OS, OutputFlags Flags) const {\n  OS << Name;\n  outputTemplateParameters(OS, Flags);\n}\n\nvoid IntrinsicFunctionIdentifierNode::output(OutputStream &OS,\n                                             OutputFlags Flags) const {\n  switch (Operator) {\n    OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, New, \"operator new\");\n    OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, Delete, \"operator delete\");\n    OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, Assign, \"operator=\");\n    OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, RightShift, \"operator>>\");\n    OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, LeftShift, \"operator<<\");\n    OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, LogicalNot, \"operator!\");\n    OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, Equals, \"operator==\");\n    OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, NotEquals, \"operator!=\");\n    OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, ArraySubscript,\n                            \"operator[]\");\n    OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, Pointer, \"operator->\");\n    OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, Increment, \"operator++\");\n    OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, Decrement, \"operator--\");\n    OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, Minus, \"operator-\");\n    OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, Plus, \"operator+\");\n    OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, Dereference, \"operator*\");\n    OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, BitwiseAnd, \"operator&\");\n    OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, MemberPointer,\n                            \"operator->*\");\n    OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, Divide, \"operator/\");\n    OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, Modulus, \"operator%\");\n    OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, LessThan, \"operator<\");\n    OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, LessThanEqual, \"operator<=\");\n    OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, GreaterThan, \"operator>\");\n    OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, GreaterThanEqual,\n                            \"operator>=\");\n    OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, Comma, \"operator,\");\n    OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, Parens, \"operator()\");\n    OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, BitwiseNot, \"operator~\");\n    OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, BitwiseXor, \"operator^\");\n    OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, BitwiseOr, \"operator|\");\n    OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, LogicalAnd, \"operator&&\");\n    OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, LogicalOr, \"operator||\");\n    OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, TimesEqual, \"operator*=\");\n    OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, PlusEqual, \"operator+=\");\n    OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, MinusEqual, \"operator-=\");\n    OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, DivEqual, \"operator/=\");\n    OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, ModEqual, \"operator%=\");\n    OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, RshEqual, \"operator>>=\");\n    OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, LshEqual, \"operator<<=\");\n    OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, BitwiseAndEqual,\n                            \"operator&=\");\n    OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, BitwiseOrEqual,\n                            \"operator|=\");\n    OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, BitwiseXorEqual,\n                            \"operator^=\");\n    OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, VbaseDtor, \"`vbase dtor'\");\n    OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, VecDelDtor,\n                            \"`vector deleting dtor'\");\n    OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, DefaultCtorClosure,\n                            \"`default ctor closure'\");\n    OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, ScalarDelDtor,\n                            \"`scalar deleting dtor'\");\n    OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, VecCtorIter,\n                            \"`vector ctor iterator'\");\n    OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, VecDtorIter,\n                            \"`vector dtor iterator'\");\n    OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, VecVbaseCtorIter,\n                            \"`vector vbase ctor iterator'\");\n    OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, VdispMap,\n                            \"`virtual displacement map'\");\n    OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, EHVecCtorIter,\n                            \"`eh vector ctor iterator'\");\n    OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, EHVecDtorIter,\n                            \"`eh vector dtor iterator'\");\n    OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, EHVecVbaseCtorIter,\n                            \"`eh vector vbase ctor iterator'\");\n    OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, CopyCtorClosure,\n                            \"`copy ctor closure'\");\n    OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, LocalVftableCtorClosure,\n                            \"`local vftable ctor closure'\");\n    OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, ArrayNew, \"operator new[]\");\n    OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, ArrayDelete,\n                            \"operator delete[]\");\n    OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, ManVectorCtorIter,\n                            \"`managed vector ctor iterator'\");\n    OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, ManVectorDtorIter,\n                            \"`managed vector dtor iterator'\");\n    OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, EHVectorCopyCtorIter,\n                            \"`EH vector copy ctor iterator'\");\n    OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, EHVectorVbaseCopyCtorIter,\n                            \"`EH vector vbase copy ctor iterator'\");\n    OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, VectorCopyCtorIter,\n                            \"`vector copy ctor iterator'\");\n    OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, VectorVbaseCopyCtorIter,\n                            \"`vector vbase copy constructor iterator'\");\n    OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, ManVectorVbaseCopyCtorIter,\n                            \"`managed vector vbase copy constructor iterator'\");\n    OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, CoAwait, \"co_await\");\n    OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, Spaceship, \"operator <=>\");\n  case IntrinsicFunctionKind::MaxIntrinsic:\n  case IntrinsicFunctionKind::None:\n    break;\n  }\n  outputTemplateParameters(OS, Flags);\n}\n\nvoid LocalStaticGuardIdentifierNode::output(OutputStream &OS,\n                                            OutputFlags Flags) const {\n  OS << \"`local static guard'\";\n  if (ScopeIndex > 0)\n    OS << \"{\" << ScopeIndex << \"}\";\n}\n\nvoid ConversionOperatorIdentifierNode::output(OutputStream &OS,\n                                              OutputFlags Flags) const {\n  OS << \"operator\";\n  outputTemplateParameters(OS, Flags);\n  OS << \" \";\n  TargetType->output(OS, Flags);\n}\n\nvoid StructorIdentifierNode::output(OutputStream &OS, OutputFlags Flags) const {\n  if (IsDestructor)\n    OS << \"~\";\n  Class->output(OS, Flags);\n  outputTemplateParameters(OS, Flags);\n}\n\nvoid LiteralOperatorIdentifierNode::output(OutputStream &OS,\n                                           OutputFlags Flags) const {\n  OS << \"operator \\\"\\\"\" << Name;\n  outputTemplateParameters(OS, Flags);\n}\n\nvoid FunctionSignatureNode::outputPre(OutputStream &OS,\n                                      OutputFlags Flags) const {\n  if (!(FunctionClass & FC_Global)) {\n    if (FunctionClass & FC_Static)\n      OS << \"static \";\n  }\n  if (FunctionClass & FC_ExternC)\n    OS << \"extern \\\"C\\\" \";\n\n  if (FunctionClass & FC_Virtual)\n    OS << \"virtual \";\n\n  if (ReturnType) {\n    ReturnType->outputPre(OS, Flags);\n    OS << \" \";\n  }\n\n  if (!(Flags & OF_NoCallingConvention))\n    outputCallingConvention(OS, CallConvention);\n}\n\nvoid FunctionSignatureNode::outputPost(OutputStream &OS,\n                                       OutputFlags Flags) const {\n  if (!(FunctionClass & FC_NoParameterList)) {\n    OS << \"(\";\n    if (Params)\n      Params->output(OS, Flags);\n    else\n      OS << \"void\";\n    OS << \")\";\n  }\n\n  if (Quals & Q_Const)\n    OS << \" const\";\n  if (Quals & Q_Volatile)\n    OS << \" volatile\";\n  if (Quals & Q_Restrict)\n    OS << \" __restrict\";\n  if (Quals & Q_Unaligned)\n    OS << \" __unaligned\";\n\n  if (RefQualifier == FunctionRefQualifier::Reference)\n    OS << \" &\";\n  else if (RefQualifier == FunctionRefQualifier::RValueReference)\n    OS << \" &&\";\n\n  if (ReturnType)\n    ReturnType->outputPost(OS, Flags);\n}\n\nvoid ThunkSignatureNode::outputPre(OutputStream &OS, OutputFlags Flags) const {\n  OS << \"[thunk]: \";\n\n  FunctionSignatureNode::outputPre(OS, Flags);\n}\n\nvoid ThunkSignatureNode::outputPost(OutputStream &OS, OutputFlags Flags) const {\n  if (FunctionClass & FC_StaticThisAdjust) {\n    OS << \"`adjustor{\" << ThisAdjust.StaticOffset << \"}'\";\n  } else if (FunctionClass & FC_VirtualThisAdjust) {\n    if (FunctionClass & FC_VirtualThisAdjustEx) {\n      OS << \"`vtordispex{\" << ThisAdjust.VBPtrOffset << \", \"\n         << ThisAdjust.VBOffsetOffset << \", \" << ThisAdjust.VtordispOffset\n         << \", \" << ThisAdjust.StaticOffset << \"}'\";\n    } else {\n      OS << \"`vtordisp{\" << ThisAdjust.VtordispOffset << \", \"\n         << ThisAdjust.StaticOffset << \"}'\";\n    }\n  }\n\n  FunctionSignatureNode::outputPost(OS, Flags);\n}\n\nvoid PointerTypeNode::outputPre(OutputStream &OS, OutputFlags Flags) const {\n  if (Pointee->kind() == NodeKind::FunctionSignature) {\n    // If this is a pointer to a function, don't output the calling convention.\n    // It needs to go inside the parentheses.\n    const FunctionSignatureNode *Sig =\n        static_cast<const FunctionSignatureNode *>(Pointee);\n    Sig->outputPre(OS, OF_NoCallingConvention);\n  } else\n    Pointee->outputPre(OS, Flags);\n\n  outputSpaceIfNecessary(OS);\n\n  if (Quals & Q_Unaligned)\n    OS << \"__unaligned \";\n\n  if (Pointee->kind() == NodeKind::ArrayType) {\n    OS << \"(\";\n  } else if (Pointee->kind() == NodeKind::FunctionSignature) {\n    OS << \"(\";\n    const FunctionSignatureNode *Sig =\n        static_cast<const FunctionSignatureNode *>(Pointee);\n    outputCallingConvention(OS, Sig->CallConvention);\n    OS << \" \";\n  }\n\n  if (ClassParent) {\n    ClassParent->output(OS, Flags);\n    OS << \"::\";\n  }\n\n  switch (Affinity) {\n  case PointerAffinity::Pointer:\n    OS << \"*\";\n    break;\n  case PointerAffinity::Reference:\n    OS << \"&\";\n    break;\n  case PointerAffinity::RValueReference:\n    OS << \"&&\";\n    break;\n  default:\n    assert(false);\n  }\n  outputQualifiers(OS, Quals, false, false);\n}\n\nvoid PointerTypeNode::outputPost(OutputStream &OS, OutputFlags Flags) const {\n  if (Pointee->kind() == NodeKind::ArrayType ||\n      Pointee->kind() == NodeKind::FunctionSignature)\n    OS << \")\";\n\n  Pointee->outputPost(OS, Flags);\n}\n\nvoid TagTypeNode::outputPre(OutputStream &OS, OutputFlags Flags) const {\n  switch (Tag) {\n    OUTPUT_ENUM_CLASS_VALUE(TagKind, Class, \"class\");\n    OUTPUT_ENUM_CLASS_VALUE(TagKind, Struct, \"struct\");\n    OUTPUT_ENUM_CLASS_VALUE(TagKind, Union, \"union\");\n    OUTPUT_ENUM_CLASS_VALUE(TagKind, Enum, \"enum\");\n  }\n  OS << \" \";\n  QualifiedName->output(OS, Flags);\n  outputQualifiers(OS, Quals, true, false);\n}\n\nvoid TagTypeNode::outputPost(OutputStream &OS, OutputFlags Flags) const {}\n\nvoid ArrayTypeNode::outputPre(OutputStream &OS, OutputFlags Flags) const {\n  ElementType->outputPre(OS, Flags);\n  outputQualifiers(OS, Quals, true, false);\n}\n\nvoid ArrayTypeNode::outputOneDimension(OutputStream &OS, OutputFlags Flags,\n                                       Node *N) const {\n  assert(N->kind() == NodeKind::IntegerLiteral);\n  IntegerLiteralNode *ILN = static_cast<IntegerLiteralNode *>(N);\n  if (ILN->Value != 0)\n    ILN->output(OS, Flags);\n}\n\nvoid ArrayTypeNode::outputDimensionsImpl(OutputStream &OS,\n                                         OutputFlags Flags) const {\n  if (Dimensions->Count == 0)\n    return;\n\n  outputOneDimension(OS, Flags, Dimensions->Nodes[0]);\n  for (size_t I = 1; I < Dimensions->Count; ++I) {\n    OS << \"][\";\n    outputOneDimension(OS, Flags, Dimensions->Nodes[I]);\n  }\n}\n\nvoid ArrayTypeNode::outputPost(OutputStream &OS, OutputFlags Flags) const {\n  OS << \"[\";\n  outputDimensionsImpl(OS, Flags);\n  OS << \"]\";\n\n  ElementType->outputPost(OS, Flags);\n}\n\nvoid SymbolNode::output(OutputStream &OS, OutputFlags Flags) const {\n  Name->output(OS, Flags);\n}\n\nvoid FunctionSymbolNode::output(OutputStream &OS, OutputFlags Flags) const {\n  Signature->outputPre(OS, Flags);\n  outputSpaceIfNecessary(OS);\n  Name->output(OS, Flags);\n  Signature->outputPost(OS, Flags);\n}\n\nvoid VariableSymbolNode::output(OutputStream &OS, OutputFlags Flags) const {\n  switch (SC) {\n  case StorageClass::PrivateStatic:\n  case StorageClass::PublicStatic:\n  case StorageClass::ProtectedStatic:\n    OS << \"static \";\n  default:\n    break;\n  }\n\n  if (Type) {\n    Type->outputPre(OS, Flags);\n    outputSpaceIfNecessary(OS);\n  }\n  Name->output(OS, Flags);\n  if (Type)\n    Type->outputPost(OS, Flags);\n}\n\nvoid CustomTypeNode::outputPre(OutputStream &OS, OutputFlags Flags) const {\n  Identifier->output(OS, Flags);\n}\nvoid CustomTypeNode::outputPost(OutputStream &OS, OutputFlags Flags) const {}\n\nvoid QualifiedNameNode::output(OutputStream &OS, OutputFlags Flags) const {\n  Components->output(OS, Flags, \"::\");\n}\n\nvoid RttiBaseClassDescriptorNode::output(OutputStream &OS,\n                                         OutputFlags Flags) const {\n  OS << \"`RTTI Base Class Descriptor at (\";\n  OS << NVOffset << \", \" << VBPtrOffset << \", \" << VBTableOffset << \", \"\n     << this->Flags;\n  OS << \")'\";\n}\n\nvoid LocalStaticGuardVariableNode::output(OutputStream &OS,\n                                          OutputFlags Flags) const {\n  Name->output(OS, Flags);\n}\n\nvoid VcallThunkIdentifierNode::output(OutputStream &OS,\n                                      OutputFlags Flags) const {\n  OS << \"`vcall'{\" << OffsetInVTable << \", {flat}}\";\n}\n\nvoid SpecialTableSymbolNode::output(OutputStream &OS, OutputFlags Flags) const {\n  outputQualifiers(OS, Quals, false, true);\n  Name->output(OS, Flags);\n  if (TargetName) {\n    OS << \"{for `\";\n    TargetName->output(OS, Flags);\n    OS << \"'}\";\n  }\n  return;\n}\n"
  },
  {
    "path": "third_party/llvm-demangle/lib/Demangle/MicrosoftDemangleNodes.h",
    "content": "#ifndef LLVM_SUPPORT_MICROSOFTDEMANGLENODES_H\n#define LLVM_SUPPORT_MICROSOFTDEMANGLENODES_H\n\n#include \"llvm/Demangle/Compiler.h\"\n#include \"llvm/Demangle/StringView.h\"\n#include <array>\n\nclass OutputStream;\n\nnamespace llvm {\nnamespace ms_demangle {\n\n// This memory allocator is extremely fast, but it doesn't call dtors\n// for allocated objects. That means you can't use STL containers\n// (such as std::vector) with this allocator. But it pays off --\n// the demangler is 3x faster with this allocator compared to one with\n// STL containers.\nconstexpr size_t AllocUnit = 4096;\n\nclass ArenaAllocator {\n  struct AllocatorNode {\n    uint8_t *Buf = nullptr;\n    size_t Used = 0;\n    size_t Capacity = 0;\n    AllocatorNode *Next = nullptr;\n  };\n\n  void addNode(size_t Capacity) {\n    AllocatorNode *NewHead = new AllocatorNode;\n    NewHead->Buf = new uint8_t[Capacity];\n    NewHead->Next = Head;\n    NewHead->Capacity = Capacity;\n    Head = NewHead;\n    NewHead->Used = 0;\n  }\n\npublic:\n  ArenaAllocator() { addNode(AllocUnit); }\n\n  ~ArenaAllocator() {\n    while (Head) {\n      assert(Head->Buf);\n      delete[] Head->Buf;\n      AllocatorNode *Next = Head->Next;\n      delete Head;\n      Head = Next;\n    }\n  }\n\n  char *allocUnalignedBuffer(size_t Length) {\n    uint8_t *Buf = Head->Buf + Head->Used;\n\n    Head->Used += Length;\n    if (Head->Used > Head->Capacity) {\n      // It's possible we need a buffer which is larger than our default unit\n      // size, so we need to be careful to add a node with capacity that is at\n      // least as large as what we need.\n      addNode(std::max(AllocUnit, Length));\n      Head->Used = Length;\n      Buf = Head->Buf;\n    }\n\n    return reinterpret_cast<char *>(Buf);\n  }\n\n  template <typename T, typename... Args>\n  T *allocArray(size_t Count) {\n\n    size_t Size = Count * sizeof(T);\n    assert(Head && Head->Buf);\n\n    size_t P = (size_t)Head->Buf + Head->Used;\n    uintptr_t AlignedP =\n        (((size_t)P + alignof(T) - 1) & ~(size_t)(alignof(T) - 1));\n    uint8_t *PP = (uint8_t *)AlignedP;\n    size_t Adjustment = AlignedP - P;\n\n    Head->Used += Size + Adjustment;\n    if (Head->Used < Head->Capacity)\n      return new (PP) T[Count]();\n\n    addNode(AllocUnit);\n    Head->Used = Size;\n    return new (Head->Buf) T[Count]();\n  }\n\n  template <typename T, typename... Args> T *alloc(Args &&... ConstructorArgs) {\n\n    size_t Size = sizeof(T);\n    assert(Head && Head->Buf);\n\n    size_t P = (size_t)Head->Buf + Head->Used;\n    uintptr_t AlignedP =\n        (((size_t)P + alignof(T) - 1) & ~(size_t)(alignof(T) - 1));\n    uint8_t *PP = (uint8_t *)AlignedP;\n    size_t Adjustment = AlignedP - P;\n\n    Head->Used += Size + Adjustment;\n    if (Head->Used < Head->Capacity)\n      return new (PP) T(std::forward<Args>(ConstructorArgs)...);\n\n    addNode(AllocUnit);\n    Head->Used = Size;\n    return new (Head->Buf) T(std::forward<Args>(ConstructorArgs)...);\n  }\n\nprivate:\n  AllocatorNode *Head = nullptr;\n};\n\n// Storage classes\nenum Qualifiers : uint8_t {\n  Q_None = 0,\n  Q_Const = 1 << 0,\n  Q_Volatile = 1 << 1,\n  Q_Far = 1 << 2,\n  Q_Huge = 1 << 3,\n  Q_Unaligned = 1 << 4,\n  Q_Restrict = 1 << 5,\n  Q_Pointer64 = 1 << 6\n};\n\nenum class StorageClass : uint8_t {\n  None,\n  PrivateStatic,\n  ProtectedStatic,\n  PublicStatic,\n  Global,\n  FunctionLocalStatic,\n};\n\nenum class PointerAffinity { None, Pointer, Reference, RValueReference };\nenum class FunctionRefQualifier { None, Reference, RValueReference };\n\n// Calling conventions\nenum class CallingConv : uint8_t {\n  None,\n  Cdecl,\n  Pascal,\n  Thiscall,\n  Stdcall,\n  Fastcall,\n  Clrcall,\n  Eabi,\n  Vectorcall,\n  Regcall,\n};\n\nenum class ReferenceKind : uint8_t { None, LValueRef, RValueRef };\n\nenum OutputFlags {\n  OF_Default = 0,\n  OF_NoCallingConvention = 1,\n};\n\n// Types\nenum class PrimitiveKind {\n  Void,\n  Bool,\n  Char,\n  Schar,\n  Uchar,\n  Char16,\n  Char32,\n  Short,\n  Ushort,\n  Int,\n  Uint,\n  Long,\n  Ulong,\n  Int64,\n  Uint64,\n  Wchar,\n  Float,\n  Double,\n  Ldouble,\n  Nullptr,\n};\n\nenum class CharKind {\n  Char,\n  Char16,\n  Char32,\n  Wchar,\n};\n\nenum class IntrinsicFunctionKind : uint8_t {\n  None,\n  New,                        // ?2 # operator new\n  Delete,                     // ?3 # operator delete\n  Assign,                     // ?4 # operator=\n  RightShift,                 // ?5 # operator>>\n  LeftShift,                  // ?6 # operator<<\n  LogicalNot,                 // ?7 # operator!\n  Equals,                     // ?8 # operator==\n  NotEquals,                  // ?9 # operator!=\n  ArraySubscript,             // ?A # operator[]\n  Pointer,                    // ?C # operator->\n  Dereference,                // ?D # operator*\n  Increment,                  // ?E # operator++\n  Decrement,                  // ?F # operator--\n  Minus,                      // ?G # operator-\n  Plus,                       // ?H # operator+\n  BitwiseAnd,                 // ?I # operator&\n  MemberPointer,              // ?J # operator->*\n  Divide,                     // ?K # operator/\n  Modulus,                    // ?L # operator%\n  LessThan,                   // ?M operator<\n  LessThanEqual,              // ?N operator<=\n  GreaterThan,                // ?O operator>\n  GreaterThanEqual,           // ?P operator>=\n  Comma,                      // ?Q operator,\n  Parens,                     // ?R operator()\n  BitwiseNot,                 // ?S operator~\n  BitwiseXor,                 // ?T operator^\n  BitwiseOr,                  // ?U operator|\n  LogicalAnd,                 // ?V operator&&\n  LogicalOr,                  // ?W operator||\n  TimesEqual,                 // ?X operator*=\n  PlusEqual,                  // ?Y operator+=\n  MinusEqual,                 // ?Z operator-=\n  DivEqual,                   // ?_0 operator/=\n  ModEqual,                   // ?_1 operator%=\n  RshEqual,                   // ?_2 operator>>=\n  LshEqual,                   // ?_3 operator<<=\n  BitwiseAndEqual,            // ?_4 operator&=\n  BitwiseOrEqual,             // ?_5 operator|=\n  BitwiseXorEqual,            // ?_6 operator^=\n  VbaseDtor,                  // ?_D # vbase destructor\n  VecDelDtor,                 // ?_E # vector deleting destructor\n  DefaultCtorClosure,         // ?_F # default constructor closure\n  ScalarDelDtor,              // ?_G # scalar deleting destructor\n  VecCtorIter,                // ?_H # vector constructor iterator\n  VecDtorIter,                // ?_I # vector destructor iterator\n  VecVbaseCtorIter,           // ?_J # vector vbase constructor iterator\n  VdispMap,                   // ?_K # virtual displacement map\n  EHVecCtorIter,              // ?_L # eh vector constructor iterator\n  EHVecDtorIter,              // ?_M # eh vector destructor iterator\n  EHVecVbaseCtorIter,         // ?_N # eh vector vbase constructor iterator\n  CopyCtorClosure,            // ?_O # copy constructor closure\n  LocalVftableCtorClosure,    // ?_T # local vftable constructor closure\n  ArrayNew,                   // ?_U operator new[]\n  ArrayDelete,                // ?_V operator delete[]\n  ManVectorCtorIter,          // ?__A managed vector ctor iterator\n  ManVectorDtorIter,          // ?__B managed vector dtor iterator\n  EHVectorCopyCtorIter,       // ?__C EH vector copy ctor iterator\n  EHVectorVbaseCopyCtorIter,  // ?__D EH vector vbase copy ctor iterator\n  VectorCopyCtorIter,         // ?__G vector copy constructor iterator\n  VectorVbaseCopyCtorIter,    // ?__H vector vbase copy constructor iterator\n  ManVectorVbaseCopyCtorIter, // ?__I managed vector vbase copy constructor\n  CoAwait,                    // ?__L co_await\n  Spaceship,                  // operator<=>\n  MaxIntrinsic\n};\n\nenum class SpecialIntrinsicKind {\n  None,\n  Vftable,\n  Vbtable,\n  Typeof,\n  VcallThunk,\n  LocalStaticGuard,\n  StringLiteralSymbol,\n  UdtReturning,\n  Unknown,\n  DynamicInitializer,\n  DynamicAtexitDestructor,\n  RttiTypeDescriptor,\n  RttiBaseClassDescriptor,\n  RttiBaseClassArray,\n  RttiClassHierarchyDescriptor,\n  RttiCompleteObjLocator,\n  LocalVftable,\n  LocalStaticThreadGuard,\n};\n\n// Function classes\nenum FuncClass : uint16_t {\n  FC_None = 0,\n  FC_Public = 1 << 0,\n  FC_Protected = 1 << 1,\n  FC_Private = 1 << 2,\n  FC_Global = 1 << 3,\n  FC_Static = 1 << 4,\n  FC_Virtual = 1 << 5,\n  FC_Far = 1 << 6,\n  FC_ExternC = 1 << 7,\n  FC_NoParameterList = 1 << 8,\n  FC_VirtualThisAdjust = 1 << 9,\n  FC_VirtualThisAdjustEx = 1 << 10,\n  FC_StaticThisAdjust = 1 << 11,\n};\n\nenum class TagKind { Class, Struct, Union, Enum };\n\nenum class NodeKind {\n  Unknown,\n  Md5Symbol,\n  PrimitiveType,\n  FunctionSignature,\n  Identifier,\n  NamedIdentifier,\n  VcallThunkIdentifier,\n  LocalStaticGuardIdentifier,\n  IntrinsicFunctionIdentifier,\n  ConversionOperatorIdentifier,\n  DynamicStructorIdentifier,\n  StructorIdentifier,\n  LiteralOperatorIdentifier,\n  ThunkSignature,\n  PointerType,\n  TagType,\n  ArrayType,\n  Custom,\n  IntrinsicType,\n  NodeArray,\n  QualifiedName,\n  TemplateParameterReference,\n  EncodedStringLiteral,\n  IntegerLiteral,\n  RttiBaseClassDescriptor,\n  LocalStaticGuardVariable,\n  FunctionSymbol,\n  VariableSymbol,\n  SpecialTableSymbol\n};\n\nstruct Node {\n  explicit Node(NodeKind K) : Kind(K) {}\n  virtual ~Node() = default;\n\n  NodeKind kind() const { return Kind; }\n\n  virtual void output(OutputStream &OS, OutputFlags Flags) const = 0;\n\nprivate:\n  NodeKind Kind;\n};\n\nstruct TypeNode;\nstruct PrimitiveTypeNode;\nstruct FunctionSignatureNode;\nstruct IdentifierNode;\nstruct NamedIdentifierNode;\nstruct VcallThunkIdentifierNode;\nstruct IntrinsicFunctionIdentifierNode;\nstruct LiteralOperatorIdentifierNode;\nstruct ConversionOperatorIdentifierNode;\nstruct StructorIdentifierNode;\nstruct ThunkSignatureNode;\nstruct PointerTypeNode;\nstruct ArrayTypeNode;\nstruct CustomNode;\nstruct TagTypeNode;\nstruct IntrinsicTypeNode;\nstruct NodeArrayNode;\nstruct QualifiedNameNode;\nstruct TemplateParameterReferenceNode;\nstruct EncodedStringLiteralNode;\nstruct IntegerLiteralNode;\nstruct RttiBaseClassDescriptorNode;\nstruct LocalStaticGuardVariableNode;\nstruct SymbolNode;\nstruct FunctionSymbolNode;\nstruct VariableSymbolNode;\nstruct SpecialTableSymbolNode;\n\nstruct TypeNode : public Node {\n  explicit TypeNode(NodeKind K) : Node(K) {}\n\n  virtual void outputPre(OutputStream &OS, OutputFlags Flags) const = 0;\n  virtual void outputPost(OutputStream &OS, OutputFlags Flags) const = 0;\n\n  void output(OutputStream &OS, OutputFlags Flags) const override {\n    outputPre(OS, Flags);\n    outputPost(OS, Flags);\n  }\n\n  void outputQuals(bool SpaceBefore, bool SpaceAfter) const;\n\n  Qualifiers Quals = Q_None;\n};\n\nstruct PrimitiveTypeNode : public TypeNode {\n  explicit PrimitiveTypeNode(PrimitiveKind K)\n      : TypeNode(NodeKind::PrimitiveType), PrimKind(K) {}\n\n  void outputPre(OutputStream &OS, OutputFlags Flags) const;\n  void outputPost(OutputStream &OS, OutputFlags Flags) const {}\n\n  PrimitiveKind PrimKind;\n};\n\nstruct FunctionSignatureNode : public TypeNode {\n  explicit FunctionSignatureNode(NodeKind K) : TypeNode(K) {}\n  FunctionSignatureNode() : TypeNode(NodeKind::FunctionSignature) {}\n\n  void outputPre(OutputStream &OS, OutputFlags Flags) const override;\n  void outputPost(OutputStream &OS, OutputFlags Flags) const override;\n\n  // Valid if this FunctionTypeNode is the Pointee of a PointerType or\n  // MemberPointerType.\n  PointerAffinity Affinity = PointerAffinity::None;\n\n  // The function's calling convention.\n  CallingConv CallConvention = CallingConv::None;\n\n  // Function flags (gloabl, public, etc)\n  FuncClass FunctionClass = FC_Global;\n\n  FunctionRefQualifier RefQualifier = FunctionRefQualifier::None;\n\n  // The return type of the function.\n  TypeNode *ReturnType = nullptr;\n\n  // True if this is a C-style ... varargs function.\n  bool IsVariadic = false;\n\n  // Function parameters\n  NodeArrayNode *Params = nullptr;\n};\n\nstruct IdentifierNode : public Node {\n  explicit IdentifierNode(NodeKind K) : Node(K) {}\n\n  NodeArrayNode *TemplateParams = nullptr;\n\nprotected:\n  void outputTemplateParameters(OutputStream &OS, OutputFlags Flags) const;\n};\n\nstruct VcallThunkIdentifierNode : public IdentifierNode {\n  VcallThunkIdentifierNode() : IdentifierNode(NodeKind::VcallThunkIdentifier) {}\n\n  void output(OutputStream &OS, OutputFlags Flags) const override;\n\n  uint64_t OffsetInVTable = 0;\n};\n\nstruct DynamicStructorIdentifierNode : public IdentifierNode {\n  DynamicStructorIdentifierNode()\n      : IdentifierNode(NodeKind::DynamicStructorIdentifier) {}\n\n  void output(OutputStream &OS, OutputFlags Flags) const override;\n\n  VariableSymbolNode *Variable = nullptr;\n  QualifiedNameNode *Name = nullptr;\n  bool IsDestructor = false;\n};\n\nstruct NamedIdentifierNode : public IdentifierNode {\n  NamedIdentifierNode() : IdentifierNode(NodeKind::NamedIdentifier) {}\n\n  void output(OutputStream &OS, OutputFlags Flags) const override;\n\n  StringView Name;\n};\n\nstruct IntrinsicFunctionIdentifierNode : public IdentifierNode {\n  explicit IntrinsicFunctionIdentifierNode(IntrinsicFunctionKind Operator)\n      : IdentifierNode(NodeKind::IntrinsicFunctionIdentifier),\n        Operator(Operator) {}\n\n  void output(OutputStream &OS, OutputFlags Flags) const override;\n\n  IntrinsicFunctionKind Operator;\n};\n\nstruct LiteralOperatorIdentifierNode : public IdentifierNode {\n  LiteralOperatorIdentifierNode()\n      : IdentifierNode(NodeKind::LiteralOperatorIdentifier) {}\n\n  void output(OutputStream &OS, OutputFlags Flags) const override;\n\n  StringView Name;\n};\n\nstruct LocalStaticGuardIdentifierNode : public IdentifierNode {\n  LocalStaticGuardIdentifierNode()\n      : IdentifierNode(NodeKind::LocalStaticGuardIdentifier) {}\n\n  void output(OutputStream &OS, OutputFlags Flags) const override;\n\n  uint32_t ScopeIndex = 0;\n};\n\nstruct ConversionOperatorIdentifierNode : public IdentifierNode {\n  ConversionOperatorIdentifierNode()\n      : IdentifierNode(NodeKind::ConversionOperatorIdentifier) {}\n\n  void output(OutputStream &OS, OutputFlags Flags) const override;\n\n  // The type that this operator converts too.\n  TypeNode *TargetType = nullptr;\n};\n\nstruct StructorIdentifierNode : public IdentifierNode {\n  StructorIdentifierNode() : IdentifierNode(NodeKind::StructorIdentifier) {}\n  explicit StructorIdentifierNode(bool IsDestructor)\n      : IdentifierNode(NodeKind::StructorIdentifier),\n        IsDestructor(IsDestructor) {}\n\n  void output(OutputStream &OS, OutputFlags Flags) const override;\n\n  // The name of the class that this is a structor of.\n  IdentifierNode *Class = nullptr;\n  bool IsDestructor = false;\n};\n\nstruct ThunkSignatureNode : public FunctionSignatureNode {\n  ThunkSignatureNode() : FunctionSignatureNode(NodeKind::ThunkSignature) {}\n\n  void outputPre(OutputStream &OS, OutputFlags Flags) const override;\n  void outputPost(OutputStream &OS, OutputFlags Flags) const override;\n\n  struct ThisAdjustor {\n    uint32_t StaticOffset = 0;\n    int32_t VBPtrOffset = 0;\n    int32_t VBOffsetOffset = 0;\n    int32_t VtordispOffset = 0;\n  };\n\n  ThisAdjustor ThisAdjust;\n};\n\nstruct PointerTypeNode : public TypeNode {\n  PointerTypeNode() : TypeNode(NodeKind::PointerType) {}\n  void outputPre(OutputStream &OS, OutputFlags Flags) const override;\n  void outputPost(OutputStream &OS, OutputFlags Flags) const override;\n\n  // Is this a pointer, reference, or rvalue-reference?\n  PointerAffinity Affinity = PointerAffinity::None;\n\n  // If this is a member pointer, this is the class that the member is in.\n  QualifiedNameNode *ClassParent = nullptr;\n\n  // Represents a type X in \"a pointer to X\", \"a reference to X\", or\n  // \"rvalue-reference to X\"\n  TypeNode *Pointee = nullptr;\n};\n\nstruct TagTypeNode : public TypeNode {\n  explicit TagTypeNode(TagKind Tag) : TypeNode(NodeKind::TagType), Tag(Tag) {}\n\n  void outputPre(OutputStream &OS, OutputFlags Flags) const;\n  void outputPost(OutputStream &OS, OutputFlags Flags) const;\n\n  QualifiedNameNode *QualifiedName = nullptr;\n  TagKind Tag;\n};\n\nstruct ArrayTypeNode : public TypeNode {\n  ArrayTypeNode() : TypeNode(NodeKind::ArrayType) {}\n\n  void outputPre(OutputStream &OS, OutputFlags Flags) const;\n  void outputPost(OutputStream &OS, OutputFlags Flags) const;\n\n  void outputDimensionsImpl(OutputStream &OS, OutputFlags Flags) const;\n  void outputOneDimension(OutputStream &OS, OutputFlags Flags, Node *N) const;\n\n  // A list of array dimensions.  e.g. [3,4,5] in `int Foo[3][4][5]`\n  NodeArrayNode *Dimensions = nullptr;\n\n  // The type of array element.\n  TypeNode *ElementType = nullptr;\n};\n\nstruct IntrinsicNode : public TypeNode {\n  IntrinsicNode() : TypeNode(NodeKind::IntrinsicType) {}\n  void output(OutputStream &OS, OutputFlags Flags) const override {}\n};\n\nstruct CustomTypeNode : public TypeNode {\n  CustomTypeNode() : TypeNode(NodeKind::Custom) {}\n\n  void outputPre(OutputStream &OS, OutputFlags Flags) const override;\n  void outputPost(OutputStream &OS, OutputFlags Flags) const override;\n\n  IdentifierNode *Identifier;\n};\n\nstruct NodeArrayNode : public Node {\n  NodeArrayNode() : Node(NodeKind::NodeArray) {}\n\n  void output(OutputStream &OS, OutputFlags Flags) const override;\n\n  void output(OutputStream &OS, OutputFlags Flags, StringView Separator) const;\n\n  Node **Nodes = 0;\n  size_t Count = 0;\n};\n\nstruct QualifiedNameNode : public Node {\n  QualifiedNameNode() : Node(NodeKind::QualifiedName) {}\n\n  void output(OutputStream &OS, OutputFlags Flags) const override;\n\n  NodeArrayNode *Components = nullptr;\n\n  IdentifierNode *getUnqualifiedIdentifier() {\n    Node *LastComponent = Components->Nodes[Components->Count - 1];\n    return static_cast<IdentifierNode *>(LastComponent);\n  }\n};\n\nstruct TemplateParameterReferenceNode : public Node {\n  TemplateParameterReferenceNode()\n      : Node(NodeKind::TemplateParameterReference) {}\n\n  void output(OutputStream &OS, OutputFlags Flags) const override;\n\n  SymbolNode *Symbol = nullptr;\n\n  int ThunkOffsetCount = 0;\n  std::array<int64_t, 3> ThunkOffsets;\n  PointerAffinity Affinity = PointerAffinity::None;\n  bool IsMemberPointer = false;\n};\n\nstruct IntegerLiteralNode : public Node {\n  IntegerLiteralNode() : Node(NodeKind::IntegerLiteral) {}\n  IntegerLiteralNode(uint64_t Value, bool IsNegative)\n      : Node(NodeKind::IntegerLiteral), Value(Value), IsNegative(IsNegative) {}\n\n  void output(OutputStream &OS, OutputFlags Flags) const override;\n\n  uint64_t Value = 0;\n  bool IsNegative = false;\n};\n\nstruct RttiBaseClassDescriptorNode : public IdentifierNode {\n  RttiBaseClassDescriptorNode()\n      : IdentifierNode(NodeKind::RttiBaseClassDescriptor) {}\n\n  void output(OutputStream &OS, OutputFlags Flags) const override;\n\n  uint32_t NVOffset = 0;\n  int32_t VBPtrOffset = 0;\n  uint32_t VBTableOffset = 0;\n  uint32_t Flags = 0;\n};\n\nstruct SymbolNode : public Node {\n  explicit SymbolNode(NodeKind K) : Node(K) {}\n  void output(OutputStream &OS, OutputFlags Flags) const override;\n  QualifiedNameNode *Name = nullptr;\n};\n\nstruct SpecialTableSymbolNode : public SymbolNode {\n  explicit SpecialTableSymbolNode()\n      : SymbolNode(NodeKind::SpecialTableSymbol) {}\n\n  void output(OutputStream &OS, OutputFlags Flags) const override;\n  QualifiedNameNode *TargetName = nullptr;\n  Qualifiers Quals;\n};\n\nstruct LocalStaticGuardVariableNode : public SymbolNode {\n  LocalStaticGuardVariableNode()\n      : SymbolNode(NodeKind::LocalStaticGuardVariable) {}\n\n  void output(OutputStream &OS, OutputFlags Flags) const override;\n\n  bool IsVisible = false;\n};\n\nstruct EncodedStringLiteralNode : public SymbolNode {\n  EncodedStringLiteralNode() : SymbolNode(NodeKind::EncodedStringLiteral) {}\n\n  void output(OutputStream &OS, OutputFlags Flags) const override;\n\n  StringView DecodedString;\n  bool IsTruncated = false;\n  CharKind Char = CharKind::Char;\n};\n\nstruct VariableSymbolNode : public SymbolNode {\n  VariableSymbolNode() : SymbolNode(NodeKind::VariableSymbol) {}\n\n  void output(OutputStream &OS, OutputFlags Flags) const override;\n\n  StorageClass SC = StorageClass::None;\n  TypeNode *Type = nullptr;\n};\n\nstruct FunctionSymbolNode : public SymbolNode {\n  FunctionSymbolNode() : SymbolNode(NodeKind::FunctionSymbol) {}\n\n  void output(OutputStream &OS, OutputFlags Flags) const override;\n\n  FunctionSignatureNode *Signature = nullptr;\n};\n\n} // namespace ms_demangle\n} // namespace llvm\n\n#endif"
  },
  {
    "path": "third_party/llvm-demangle/llvm-demangle.vcxproj",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<Project DefaultTargets=\"Build\" ToolsVersion=\"15.0\" xmlns=\"http://schemas.microsoft.com/developer/msbuild/2003\">\n  <ItemGroup Label=\"ProjectConfigurations\">\n    <ProjectConfiguration Include=\"Appx|Win32\">\n      <Configuration>Appx</Configuration>\n      <Platform>Win32</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"Appx|x64\">\n      <Configuration>Appx</Configuration>\n      <Platform>x64</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"Debug|Win32\">\n      <Configuration>Debug</Configuration>\n      <Platform>Win32</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"Release|Win32\">\n      <Configuration>Release</Configuration>\n      <Platform>Win32</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"Debug|x64\">\n      <Configuration>Debug</Configuration>\n      <Platform>x64</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"Release|x64\">\n      <Configuration>Release</Configuration>\n      <Platform>x64</Platform>\n    </ProjectConfiguration>\n  </ItemGroup>\n  <ItemGroup>\n    <ClInclude Include=\"include\\llvm\\Demangle\\Compiler.h\" />\n    <ClInclude Include=\"include\\llvm\\Demangle\\Demangle.h\" />\n    <ClInclude Include=\"include\\llvm\\Demangle\\ItaniumDemangle.h\" />\n    <ClInclude Include=\"include\\llvm\\Demangle\\StringView.h\" />\n    <ClInclude Include=\"include\\llvm\\Demangle\\Utility.h\" />\n    <ClInclude Include=\"lib\\Demangle\\Compiler.h\" />\n    <ClInclude Include=\"lib\\Demangle\\MicrosoftDemangleNodes.h\" />\n    <ClInclude Include=\"lib\\Demangle\\StringView.h\" />\n    <ClInclude Include=\"lib\\Demangle\\Utility.h\" />\n  </ItemGroup>\n  <ItemGroup>\n    <ClCompile Include=\"lib\\Demangle\\ItaniumDemangle.cpp\" />\n    <ClCompile Include=\"lib\\Demangle\\MicrosoftDemangle.cpp\" />\n    <ClCompile Include=\"lib\\Demangle\\MicrosoftDemangleNodes.cpp\" />\n  </ItemGroup>\n  <PropertyGroup Label=\"Globals\">\n    <VCProjectVersion>15.0</VCProjectVersion>\n    <ProjectGuid>{FC532FFF-EBB1-4601-B903-C09EFB79ECED}</ProjectGuid>\n    <Keyword>Win32Proj</Keyword>\n    <RootNamespace>llvmdemangle</RootNamespace>\n    <WindowsTargetPlatformVersion>10.0</WindowsTargetPlatformVersion>\n  </PropertyGroup>\n  <Import Project=\"$(VCTargetsPath)\\Microsoft.Cpp.Default.props\" />\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Debug|Win32'\" Label=\"Configuration\">\n    <ConfigurationType>StaticLibrary</ConfigurationType>\n    <UseDebugLibraries>true</UseDebugLibraries>\n    <PlatformToolset>v142</PlatformToolset>\n    <CharacterSet>Unicode</CharacterSet>\n    <SpectreMitigation>false</SpectreMitigation>\n  </PropertyGroup>\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Release|Win32'\" Label=\"Configuration\">\n    <ConfigurationType>StaticLibrary</ConfigurationType>\n    <UseDebugLibraries>false</UseDebugLibraries>\n    <PlatformToolset>v142</PlatformToolset>\n    <WholeProgramOptimization>true</WholeProgramOptimization>\n    <CharacterSet>Unicode</CharacterSet>\n    <SpectreMitigation>false</SpectreMitigation>\n  </PropertyGroup>\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\" Label=\"Configuration\">\n    <ConfigurationType>StaticLibrary</ConfigurationType>\n    <UseDebugLibraries>true</UseDebugLibraries>\n    <PlatformToolset>v142</PlatformToolset>\n    <CharacterSet>Unicode</CharacterSet>\n    <SpectreMitigation>false</SpectreMitigation>\n  </PropertyGroup>\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\" Label=\"Configuration\">\n    <ConfigurationType>StaticLibrary</ConfigurationType>\n    <UseDebugLibraries>false</UseDebugLibraries>\n    <PlatformToolset>v142</PlatformToolset>\n    <WholeProgramOptimization>true</WholeProgramOptimization>\n    <CharacterSet>Unicode</CharacterSet>\n    <SpectreMitigation>false</SpectreMitigation>\n  </PropertyGroup>\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Appx|Win32'\" Label=\"Configuration\">\n    <ConfigurationType>StaticLibrary</ConfigurationType>\n    <UseDebugLibraries>false</UseDebugLibraries>\n    <PlatformToolset>v142</PlatformToolset>\n    <WholeProgramOptimization>true</WholeProgramOptimization>\n    <CharacterSet>Unicode</CharacterSet>\n    <SpectreMitigation>false</SpectreMitigation>\n  </PropertyGroup>\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Appx|x64'\" Label=\"Configuration\">\n    <ConfigurationType>StaticLibrary</ConfigurationType>\n    <UseDebugLibraries>true</UseDebugLibraries>\n    <PlatformToolset>v142</PlatformToolset>\n    <CharacterSet>Unicode</CharacterSet>\n    <SpectreMitigation>false</SpectreMitigation>\n  </PropertyGroup>\n  <Import Project=\"$(VCTargetsPath)\\Microsoft.Cpp.props\" />\n  <ImportGroup Label=\"ExtensionSettings\">\n  </ImportGroup>\n  <ImportGroup Label=\"Shared\">\n  </ImportGroup>\n  <ImportGroup Label=\"PropertySheets\" Condition=\"'$(Configuration)|$(Platform)'=='Debug|Win32'\">\n    <Import Project=\"$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props\" Condition=\"exists('$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props')\" Label=\"LocalAppDataPlatform\" />\n  </ImportGroup>\n  <ImportGroup Label=\"PropertySheets\" Condition=\"'$(Configuration)|$(Platform)'=='Release|Win32'\">\n    <Import Project=\"$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props\" Condition=\"exists('$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props')\" Label=\"LocalAppDataPlatform\" />\n  </ImportGroup>\n  <ImportGroup Label=\"PropertySheets\" Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">\n    <Import Project=\"$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props\" Condition=\"exists('$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props')\" Label=\"LocalAppDataPlatform\" />\n  </ImportGroup>\n  <ImportGroup Label=\"PropertySheets\" Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\">\n    <Import Project=\"$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props\" Condition=\"exists('$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props')\" Label=\"LocalAppDataPlatform\" />\n  </ImportGroup>\n  <PropertyGroup Label=\"UserMacros\" />\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">\n    <LinkIncremental>true</LinkIncremental>\n    <OutDir>$(SolutionDir)bin\\$(Configuration)$(PlatformArchitecture)\\</OutDir>\n    <IntDir>$(SolutionDir)obj\\$(ProjectName)\\$(Configuration)$(PlatformArchitecture)\\</IntDir>\n  </PropertyGroup>\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Debug|Win32'\">\n    <LinkIncremental>true</LinkIncremental>\n    <OutDir>$(SolutionDir)bin\\$(Configuration)$(PlatformArchitecture)\\</OutDir>\n    <IntDir>$(SolutionDir)obj\\$(ProjectName)\\$(Configuration)$(PlatformArchitecture)\\</IntDir>\n  </PropertyGroup>\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Release|Win32'\">\n    <LinkIncremental>false</LinkIncremental>\n    <OutDir>$(SolutionDir)bin\\$(Configuration)$(PlatformArchitecture)\\</OutDir>\n    <IntDir>$(SolutionDir)obj\\$(ProjectName)\\$(Configuration)$(PlatformArchitecture)\\</IntDir>\n  </PropertyGroup>\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\">\n    <LinkIncremental>false</LinkIncremental>\n    <OutDir>$(SolutionDir)bin\\$(Configuration)$(PlatformArchitecture)\\</OutDir>\n    <IntDir>$(SolutionDir)obj\\$(ProjectName)\\$(Configuration)$(PlatformArchitecture)\\</IntDir>\n  </PropertyGroup>\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Appx|Win32'\">\n    <IntDir>$(SolutionDir)obj\\$(ProjectName)\\$(Configuration)$(PlatformArchitecture)\\</IntDir>\n    <OutDir>$(SolutionDir)bin\\$(Configuration)$(PlatformArchitecture)\\</OutDir>\n  </PropertyGroup>\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Appx|x64'\">\n    <IntDir>$(SolutionDir)obj\\$(ProjectName)\\$(Configuration)$(PlatformArchitecture)\\</IntDir>\n    <OutDir>$(SolutionDir)bin\\$(Configuration)$(PlatformArchitecture)\\</OutDir>\n  </PropertyGroup>\n  <ItemDefinitionGroup Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">\n    <ClCompile>\n      <PrecompiledHeader>NotUsing</PrecompiledHeader>\n      <WarningLevel>Level3</WarningLevel>\n      <Optimization>Disabled</Optimization>\n      <SDLCheck>true</SDLCheck>\n      <PreprocessorDefinitions>_DEBUG;_LIB;%(PreprocessorDefinitions);_SCL_SECURE_NO_WARNINGS;_CRT_SECURE_NO_WARNINGS;NDEBUG;</PreprocessorDefinitions>\n      <ConformanceMode>true</ConformanceMode>\n      <AdditionalIncludeDirectories>$(ProjectDir)\\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>\n      <RuntimeLibrary>MultiThreadedDebugDLL</RuntimeLibrary>\n    </ClCompile>\n    <Link>\n      <SubSystem>Windows</SubSystem>\n      <GenerateDebugInformation>true</GenerateDebugInformation>\n    </Link>\n  </ItemDefinitionGroup>\n  <ItemDefinitionGroup Condition=\"'$(Configuration)|$(Platform)'=='Debug|Win32'\">\n    <ClCompile>\n      <PrecompiledHeader>NotUsing</PrecompiledHeader>\n      <WarningLevel>Level3</WarningLevel>\n      <Optimization>Disabled</Optimization>\n      <SDLCheck>true</SDLCheck>\n      <PreprocessorDefinitions>WIN32;_DEBUG;_LIB;%(PreprocessorDefinitions);_SCL_SECURE_NO_WARNINGS;_CRT_SECURE_NO_WARNINGS;NDEBUG;</PreprocessorDefinitions>\n      <ConformanceMode>true</ConformanceMode>\n      <AdditionalIncludeDirectories>$(ProjectDir)\\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>\n      <RuntimeLibrary>MultiThreadedDebugDLL</RuntimeLibrary>\n    </ClCompile>\n    <Link>\n      <SubSystem>Windows</SubSystem>\n      <GenerateDebugInformation>true</GenerateDebugInformation>\n    </Link>\n  </ItemDefinitionGroup>\n  <ItemDefinitionGroup Condition=\"'$(Configuration)|$(Platform)'=='Release|Win32'\">\n    <ClCompile>\n      <PrecompiledHeader>NotUsing</PrecompiledHeader>\n      <WarningLevel>Level3</WarningLevel>\n      <Optimization>MaxSpeed</Optimization>\n      <FunctionLevelLinking>true</FunctionLevelLinking>\n      <IntrinsicFunctions>true</IntrinsicFunctions>\n      <SDLCheck>true</SDLCheck>\n      <PreprocessorDefinitions>WIN32;NDEBUG;_LIB;%(PreprocessorDefinitions);_SCL_SECURE_NO_WARNINGS;_CRT_SECURE_NO_WARNINGS;NDEBUG;</PreprocessorDefinitions>\n      <ConformanceMode>true</ConformanceMode>\n      <AdditionalIncludeDirectories>$(ProjectDir)\\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>\n      <RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary>\n    </ClCompile>\n    <Link>\n      <SubSystem>Windows</SubSystem>\n      <EnableCOMDATFolding>true</EnableCOMDATFolding>\n      <OptimizeReferences>true</OptimizeReferences>\n      <GenerateDebugInformation>true</GenerateDebugInformation>\n    </Link>\n  </ItemDefinitionGroup>\n  <ItemDefinitionGroup Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\">\n    <ClCompile>\n      <PrecompiledHeader>NotUsing</PrecompiledHeader>\n      <WarningLevel>Level3</WarningLevel>\n      <Optimization>MaxSpeed</Optimization>\n      <FunctionLevelLinking>true</FunctionLevelLinking>\n      <IntrinsicFunctions>true</IntrinsicFunctions>\n      <SDLCheck>true</SDLCheck>\n      <PreprocessorDefinitions>NDEBUG;_LIB;%(PreprocessorDefinitions);_SCL_SECURE_NO_WARNINGS;_CRT_SECURE_NO_WARNINGS;NDEBUG;</PreprocessorDefinitions>\n      <ConformanceMode>true</ConformanceMode>\n      <AdditionalIncludeDirectories>$(ProjectDir)\\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>\n      <RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary>\n    </ClCompile>\n    <Link>\n      <SubSystem>Windows</SubSystem>\n      <EnableCOMDATFolding>true</EnableCOMDATFolding>\n      <OptimizeReferences>true</OptimizeReferences>\n      <GenerateDebugInformation>true</GenerateDebugInformation>\n    </Link>\n  </ItemDefinitionGroup>\n  <ItemDefinitionGroup Condition=\"'$(Configuration)|$(Platform)'=='Appx|Win32'\">\n    <ClCompile>\n      <PrecompiledHeader>NotUsing</PrecompiledHeader>\n      <WarningLevel>Level3</WarningLevel>\n      <Optimization>MaxSpeed</Optimization>\n      <FunctionLevelLinking>true</FunctionLevelLinking>\n      <IntrinsicFunctions>true</IntrinsicFunctions>\n      <SDLCheck>true</SDLCheck>\n      <PreprocessorDefinitions>WIN32;NDEBUG;_LIB;%(PreprocessorDefinitions);_SCL_SECURE_NO_WARNINGS;_CRT_SECURE_NO_WARNINGS;NDEBUG;</PreprocessorDefinitions>\n      <ConformanceMode>true</ConformanceMode>\n      <AdditionalIncludeDirectories>$(ProjectDir)\\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>\n      <RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary>\n    </ClCompile>\n    <Link>\n      <SubSystem>Windows</SubSystem>\n      <EnableCOMDATFolding>true</EnableCOMDATFolding>\n      <OptimizeReferences>true</OptimizeReferences>\n      <GenerateDebugInformation>true</GenerateDebugInformation>\n    </Link>\n  </ItemDefinitionGroup>\n  <ItemDefinitionGroup Condition=\"'$(Configuration)|$(Platform)'=='Appx|x64'\">\n    <ClCompile>\n      <PrecompiledHeader>NotUsing</PrecompiledHeader>\n      <WarningLevel>Level3</WarningLevel>\n      <Optimization>MaxSpeed</Optimization>\n      <FunctionLevelLinking>true</FunctionLevelLinking>\n      <IntrinsicFunctions>true</IntrinsicFunctions>\n      <SDLCheck>true</SDLCheck>\n      <PreprocessorDefinitions>NDEBUG;_LIB;%(PreprocessorDefinitions);_SCL_SECURE_NO_WARNINGS;_CRT_SECURE_NO_WARNINGS;NDEBUG;</PreprocessorDefinitions>\n      <ConformanceMode>true</ConformanceMode>\n      <AdditionalIncludeDirectories>$(ProjectDir)\\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>\n      <RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary>\n      <BasicRuntimeChecks>Default</BasicRuntimeChecks>\n    </ClCompile>\n    <Link>\n      <SubSystem>Windows</SubSystem>\n      <EnableCOMDATFolding>true</EnableCOMDATFolding>\n      <OptimizeReferences>true</OptimizeReferences>\n      <GenerateDebugInformation>true</GenerateDebugInformation>\n    </Link>\n  </ItemDefinitionGroup>\n  <Import Project=\"$(VCTargetsPath)\\Microsoft.Cpp.targets\" />\n  <ImportGroup Label=\"ExtensionTargets\">\n  </ImportGroup>\n</Project>"
  },
  {
    "path": "third_party/llvm-demangle/llvm-demangle.vcxproj.filters",
    "content": "﻿<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<Project ToolsVersion=\"4.0\" xmlns=\"http://schemas.microsoft.com/developer/msbuild/2003\">\n  <ItemGroup>\n    <Filter Include=\"Fichiers sources\">\n      <UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier>\n      <Extensions>cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx</Extensions>\n    </Filter>\n    <Filter Include=\"Fichiers d%27en-tête\">\n      <UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier>\n      <Extensions>h;hh;hpp;hxx;hm;inl;inc;ipp;xsd</Extensions>\n    </Filter>\n    <Filter Include=\"Fichiers de ressources\">\n      <UniqueIdentifier>{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}</UniqueIdentifier>\n      <Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms</Extensions>\n    </Filter>\n  </ItemGroup>\n  <ItemGroup>\n    <ClInclude Include=\"include\\llvm\\Demangle\\Demangle.h\">\n      <Filter>Fichiers d%27en-tête</Filter>\n    </ClInclude>\n    <ClInclude Include=\"lib\\Demangle\\Compiler.h\">\n      <Filter>Fichiers sources</Filter>\n    </ClInclude>\n    <ClInclude Include=\"lib\\Demangle\\StringView.h\">\n      <Filter>Fichiers sources</Filter>\n    </ClInclude>\n    <ClInclude Include=\"lib\\Demangle\\Utility.h\">\n      <Filter>Fichiers sources</Filter>\n    </ClInclude>\n    <ClInclude Include=\"include\\llvm\\Demangle\\Compiler.h\">\n      <Filter>Fichiers d%27en-tête</Filter>\n    </ClInclude>\n    <ClInclude Include=\"include\\llvm\\Demangle\\ItaniumDemangle.h\">\n      <Filter>Fichiers d%27en-tête</Filter>\n    </ClInclude>\n    <ClInclude Include=\"include\\llvm\\Demangle\\StringView.h\">\n      <Filter>Fichiers d%27en-tête</Filter>\n    </ClInclude>\n    <ClInclude Include=\"include\\llvm\\Demangle\\Utility.h\">\n      <Filter>Fichiers d%27en-tête</Filter>\n    </ClInclude>\n    <ClInclude Include=\"lib\\Demangle\\MicrosoftDemangleNodes.h\">\n      <Filter>Fichiers sources</Filter>\n    </ClInclude>\n  </ItemGroup>\n  <ItemGroup>\n    <ClCompile Include=\"lib\\Demangle\\ItaniumDemangle.cpp\">\n      <Filter>Fichiers sources</Filter>\n    </ClCompile>\n    <ClCompile Include=\"lib\\Demangle\\MicrosoftDemangle.cpp\">\n      <Filter>Fichiers sources</Filter>\n    </ClCompile>\n    <ClCompile Include=\"lib\\Demangle\\MicrosoftDemangleNodes.cpp\">\n      <Filter>Fichiers sources</Filter>\n    </ClCompile>\n  </ItemGroup>\n</Project>"
  },
  {
    "path": "third_party/phlib/apiimport.c",
    "content": "/*\n * Process Hacker -\n *   procedure import module\n *\n * Copyright (C) 2015 wj32\n *\n * This file is part of Process Hacker.\n *\n * Process Hacker is free software; you can redistribute it and/or modify\n * it under the terms of the GNU General Public License as published by\n * the Free Software Foundation, either version 3 of the License, or\n * (at your option) any later version.\n *\n * Process Hacker is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n * GNU General Public License for more details.\n *\n * You should have received a copy of the GNU General Public License\n * along with Process Hacker.  If not, see <http://www.gnu.org/licenses/>.\n */\n\n#include <ph.h>\n#include <apiimport.h>\n\nPVOID PhpImportProcedure(\n    _Inout_ PVOID *Cache,\n    _Inout_ PBOOLEAN CacheValid,\n    _In_ PWSTR ModuleName,\n    _In_ PSTR ProcedureName\n    )\n{\n    PVOID module;\n    PVOID procedure;\n\n    if (*CacheValid)\n        return *Cache;\n\n    module = PhGetDllHandle(ModuleName);\n\n    if (!module)\n        return NULL;\n\n    procedure = PhGetProcedureAddress(module, ProcedureName, 0);\n    *Cache = procedure;\n    MemoryBarrier();\n    *CacheValid = TRUE;\n\n    return procedure;\n}\n\n#define PH_DEFINE_IMPORT(Module, Name) \\\n_##Name Name##_Import(VOID) \\\n{ \\\n    static PVOID cache = NULL; \\\n    static BOOLEAN cacheValid = FALSE; \\\n\\\n    return (_##Name)PhpImportProcedure(&cache, &cacheValid, Module, #Name); \\\n}\n\nPH_DEFINE_IMPORT(L\"ntdll.dll\", NtQueryInformationEnlistment);\nPH_DEFINE_IMPORT(L\"ntdll.dll\", NtQueryInformationResourceManager);\nPH_DEFINE_IMPORT(L\"ntdll.dll\", NtQueryInformationTransaction);\nPH_DEFINE_IMPORT(L\"ntdll.dll\", NtQueryInformationTransactionManager);\nPH_DEFINE_IMPORT(L\"shell32.dll\", SHCreateShellItem);\nPH_DEFINE_IMPORT(L\"shell32.dll\", SHOpenFolderAndSelectItems);\nPH_DEFINE_IMPORT(L\"shell32.dll\", SHParseDisplayName);\n"
  },
  {
    "path": "third_party/phlib/appresolver.c",
    "content": "/*\n * Process Hacker -\n *   Appmodel support functions\n *\n * Copyright (C) 2017-2018 dmex\n *\n * This file is part of Process Hacker.\n *\n * Process Hacker is free software; you can redistribute it and/or modify\n * it under the terms of the GNU General Public License as published by\n * the Free Software Foundation, either version 3 of the License, or\n * (at your option) any later version.\n *\n * Process Hacker is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n * GNU General Public License for more details.\n *\n * You should have received a copy of the GNU General Public License\n * along with Process Hacker.  If not, see <http://www.gnu.org/licenses/>.\n */\n\n#define COBJMACROS\n#define CINTERFACE\n#include <phbase.h>\n\n#include <combaseapi.h>\n#include <propsys.h>\n#include <shobjidl.h>\n\n#include <appresolverp.h>\n#include <appresolver.h>\n\nstatic PVOID PhpQueryAppResolverInterface(\n    VOID\n    )\n{\n    static PH_INITONCE initOnce = PH_INITONCE_INIT;\n    static PVOID resolverInterface = NULL;\n\n    if (PhBeginInitOnce(&initOnce))\n    {\n        if (WindowsVersion < WINDOWS_8)\n            CoCreateInstance(&CLSID_StartMenuCacheAndAppResolver_I, NULL, CLSCTX_INPROC_SERVER, &IID_IApplicationResolver61_I, &resolverInterface);\n        else\n            CoCreateInstance(&CLSID_StartMenuCacheAndAppResolver_I, NULL, CLSCTX_INPROC_SERVER, &IID_IApplicationResolver62_I, &resolverInterface);\n\n        PhEndInitOnce(&initOnce);\n    }\n\n    return resolverInterface;\n}\n\nstatic PVOID PhpQueryStartMenuCacheInterface(\n    VOID\n    )\n{\n    static PH_INITONCE initOnce = PH_INITONCE_INIT;\n    static PVOID startMenuInterface = NULL;\n\n    if (PhBeginInitOnce(&initOnce))\n    {\n        if (WindowsVersion < WINDOWS_8)\n            CoCreateInstance(&CLSID_StartMenuCacheAndAppResolver_I, NULL, CLSCTX_INPROC_SERVER, &IID_IStartMenuAppItems61_I, &startMenuInterface);\n        else\n            CoCreateInstance(&CLSID_StartMenuCacheAndAppResolver_I, NULL, CLSCTX_INPROC_SERVER, &IID_IStartMenuAppItems62_I, &startMenuInterface);\n\n        PhEndInitOnce(&initOnce);\n    }\n\n    return startMenuInterface;\n}\n\nBOOLEAN PhAppResolverGetAppIdForProcess(\n    _In_ HANDLE ProcessId,\n    _Out_ PPH_STRING *ApplicationUserModelId\n    )\n{\n    PVOID resolverInterface;\n    PWSTR appIdText = NULL;\n\n    if (!(resolverInterface = PhpQueryAppResolverInterface()))\n        return FALSE;\n\n    if (WindowsVersion < WINDOWS_8)\n    {\n        IApplicationResolver_GetAppIDForProcess(\n            (IApplicationResolver61*)resolverInterface, \n            HandleToUlong(ProcessId), \n            &appIdText, \n            NULL, \n            NULL, \n            NULL\n            );\n    }\n    else\n    {\n        IApplicationResolver2_GetAppIDForProcess(\n            (IApplicationResolver62*)resolverInterface, \n            HandleToUlong(ProcessId), \n            &appIdText, \n            NULL, \n            NULL, \n            NULL\n            );\n    }\n\n    if (appIdText)\n    {\n        *ApplicationUserModelId = PhCreateString(appIdText);\n        return TRUE;\n    }\n\n    return FALSE;\n}\n\nPPH_LIST PhGetPackageAssetsFromResourceFile(\n    _In_ PWSTR FilePath\n    )\n{\n    IMrtResourceManager* resourceManager = NULL;\n    IResourceMap* resourceMap = NULL;\n    PPH_LIST resourceList = NULL;\n    ULONG resourceCount = 0;\n\n    if (FAILED(CoCreateInstance(\n        &CLSID_MrtResourceManager_I,\n        NULL,\n        CLSCTX_INPROC_SERVER,\n        &IID_IMrtResourceManager_I,\n        &resourceManager\n        )))\n    {\n        return FALSE;\n    }\n\n    if (FAILED(IMrtResourceManager_InitializeForFile(resourceManager, FilePath)))\n        goto CleanupExit;\n\n    if (FAILED(IMrtResourceManager_GetMainResourceMap(resourceManager, &IID_IResourceMap_I, &resourceMap)))\n        goto CleanupExit;\n\n    if (FAILED(IResourceMap_GetNamedResourceCount(resourceMap, &resourceCount)))\n        goto CleanupExit;\n\n    resourceList = PhCreateList(10);\n\n    for (ULONG i = 0; i < resourceCount; i++)\n    {\n        PWSTR resourceName;\n\n        if (SUCCEEDED(IResourceMap_GetNamedResourceUri(resourceMap, i, &resourceName)))\n        {\n            PhAddItemList(resourceList, PhCreateString(resourceName));\n        }\n    }\n\nCleanupExit:\n\n    if (resourceMap)\n        IResourceMap_Release(resourceMap);\n\n    if (resourceManager)\n        IMrtResourceManager_Release(resourceManager);\n\n    return resourceList;\n}\n\n// TODO: FIXME\n//HICON PhAppResolverGetPackageIcon(\n//    _In_ HANDLE ProcessId,\n//    _In_ PPH_STRING PackageFullName\n//    )\n//{\n//    PVOID startMenuInterface;\n//    PPH_STRING applicationUserModelId;\n//    IPropertyStore* propStoreInterface;\n//    HICON packageIcon = NULL;\n//\n//    if (!(startMenuInterface = PhpQueryStartMenuCacheInterface()))\n//        return NULL;\n//\n//    if (!PhAppResolverGetAppIdForProcess(ProcessId, &applicationUserModelId))\n//        return NULL;\n//\n//    if (WindowsVersion < WINDOWS_8)\n//    {\n//        IStartMenuAppItems_GetItem(\n//            (IStartMenuAppItems61*)startMenuInterface,\n//            SMAIF_DEFAULT,\n//            applicationUserModelId->Buffer,\n//            &IID_IPropertyStore,\n//            &propStoreInterface\n//            );\n//    }\n//    else\n//    {\n//        IStartMenuAppItems2_GetItem(\n//            (IStartMenuAppItems62*)startMenuInterface,\n//            SMAIF_DEFAULT,\n//            applicationUserModelId->Buffer,\n//            &IID_IPropertyStore,\n//            &propStoreInterface\n//            );\n//    }\n//\n//    if (propStoreInterface)\n//    {\n//        IMrtResourceManager* mrtResourceManager;\n//        IResourceMap* resourceMap;\n//        PROPVARIANT propVar;\n//        PWSTR filePath;\n//\n//        IPropertyStore_GetValue(propStoreInterface, &PKEY_Tile_Background, &propVar);\n//        IPropertyStore_GetValue(propStoreInterface, &PKEY_Tile_SmallLogoPath, &propVar);\n//\n//        CoCreateInstance(\n//            &CLSID_MrtResourceManager_I,\n//            NULL,\n//            CLSCTX_INPROC_SERVER,\n//            &IID_IMrtResourceManager_I,\n//            &mrtResourceManager\n//            );\n//\n//        IMrtResourceManager_InitializeForPackage(mrtResourceManager, PackageFullName->Buffer);\n//        IMrtResourceManager_GetMainResourceMap(mrtResourceManager, &IID_IResourceMap_I, &resourceMap);\n//        IResourceMap_GetFilePath(resourceMap, propVar.pwszVal, &filePath);\n//\n//        //HBITMAP bitmap = PhLoadImageFromFile(filePath, 32, 32);\n//        //packageIcon = PhBitmapToIcon(bitmap, 32, 32);\n//\n//        IResourceMap_Release(resourceMap);\n//        IMrtResourceManager_Release(mrtResourceManager);\n//        PropVariantClear(&propVar);\n//\n//        IPropertyStore_Release(propStoreInterface);\n//    }\n//\n//    PhDereferenceObject(applicationUserModelId);\n//\n//    return packageIcon;\n//}\n"
  },
  {
    "path": "third_party/phlib/avltree.c",
    "content": "/*\n * Process Hacker -\n *   AVL tree\n *\n * Copyright (C) 2010-2016 wj32\n *\n * This file is part of Process Hacker.\n *\n * Process Hacker is free software; you can redistribute it and/or modify\n * it under the terms of the GNU General Public License as published by\n * the Free Software Foundation, either version 3 of the License, or\n * (at your option) any later version.\n *\n * Process Hacker is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n * GNU General Public License for more details.\n *\n * You should have received a copy of the GNU General Public License\n * along with Process Hacker.  If not, see <http://www.gnu.org/licenses/>.\n */\n\n#include <phbase.h>\n\n/**\n * Initializes an AVL tree.\n *\n * \\param Tree The tree.\n * \\param CompareFunction A function used to compare tree elements.\n */\nVOID PhInitializeAvlTree(\n    _Out_ PPH_AVL_TREE Tree,\n    _In_ PPH_AVL_TREE_COMPARE_FUNCTION CompareFunction\n    )\n{\n    Tree->Root.Parent = NULL;\n    Tree->Root.Left = NULL;\n    Tree->Root.Right = NULL;\n    Tree->Root.Balance = 0;\n    Tree->Count = 0;\n\n    Tree->CompareFunction = CompareFunction;\n}\n\n/**\n * Finds an element in an AVL tree.\n *\n * \\param Tree The tree.\n * \\param Element The element to find.\n * \\param Result The result of the search.\n */\nFORCEINLINE PPH_AVL_LINKS PhpFindElementAvlTree(\n    _In_ PPH_AVL_TREE Tree,\n    _In_ PPH_AVL_LINKS Element,\n    _Out_ PLONG Result\n    )\n{\n    PPH_AVL_LINKS links;\n    LONG result;\n\n    links = PhRootElementAvlTree(Tree);\n\n    if (!links)\n    {\n        *Result = 1;\n        return &Tree->Root;\n    }\n\n    while (TRUE)\n    {\n        result = Tree->CompareFunction(Element, links);\n\n        if (result == 0)\n        {\n            *Result = 0;\n            return links;\n        }\n        else if (result < 0)\n        {\n            if (links->Left)\n            {\n                links = links->Left;\n            }\n            else\n            {\n                *Result = -1;\n                return links;\n            }\n        }\n        else\n        {\n            if (links->Right)\n            {\n                links = links->Right;\n            }\n            else\n            {\n                *Result = 1;\n                return links;\n            }\n        }\n    }\n}\n\nFORCEINLINE VOID PhpRotateLeftAvlLinks(\n    _Inout_ PPH_AVL_LINKS *Root\n    )\n{\n    PPH_AVL_LINKS P;\n    PPH_AVL_LINKS Q;\n\n    //    P\n    //  |   |\n    //  A   Q\n    //     | |\n    //     B C\n    //\n    // becomes\n    //\n    //    Q\n    //  |   |\n    //  P   C\n    // | |\n    // A B\n    //\n    // P and Q must exist.\n    // B may not exist.\n    // A and C are not affected.\n\n    P = *Root;\n    Q = P->Right;\n\n    // The new root is Q\n\n    *Root = Q;\n    Q->Parent = P->Parent;\n\n    // P.Right = Q.Left (transfer B)\n\n    P->Right = Q->Left;\n\n    if (P->Right)\n        P->Right->Parent = P;\n\n    // Q.Left = P\n\n    Q->Left = P;\n    P->Parent = Q;\n}\n\nFORCEINLINE VOID PhpRotateLeftTwiceAvlLinks(\n    _Inout_ PPH_AVL_LINKS *Root\n    )\n{\n    PPH_AVL_LINKS P;\n    PPH_AVL_LINKS Q;\n    PPH_AVL_LINKS R;\n\n    //     P\n    //  |     |\n    //  A     Q\n    //      |   |\n    //      R   D\n    //     | |\n    //     B C\n    //\n    // becomes\n    //\n    //     R\n    //  |     |\n    //  P     Q\n    // | |   | |\n    // A B   C D\n    //\n    // P, Q, and R must exist.\n    // B and C may not exist.\n    // A and D are not affected.\n\n    // PhpRotateRightAvlLinks(&(*Root)->Right);\n    // PhpRotateLeftAvlLinks(Root);\n\n    // P is the current root\n    // Q is P.Right\n    // R is Q.Left (P.Right.Left)\n\n    P = *Root;\n    Q = P->Right;\n    R = Q->Left;\n\n    // The new root is R\n\n    *Root = R;\n    R->Parent = P->Parent;\n\n    // Q.Left = R.Right (transfer C)\n\n    Q->Left = R->Right;\n\n    if (Q->Left)\n        Q->Left->Parent = Q;\n\n    // R.Right = Q\n\n    R->Right = Q;\n    Q->Parent = R;\n\n    // P.Right = R.Left (transfer B)\n\n    P->Right = R->Left;\n\n    if (P->Right)\n        P->Right->Parent = P;\n\n    // R.Left = P\n\n    R->Left = P;\n    P->Parent = R;\n}\n\nFORCEINLINE VOID PhpRotateRightAvlLinks(\n    _Inout_ PPH_AVL_LINKS *Root\n    )\n{\n    PPH_AVL_LINKS Q;\n    PPH_AVL_LINKS P;\n\n    //    Q\n    //  |   |\n    //  P   C\n    // | |\n    // A B\n    //\n    // becomes\n    //\n    //    P\n    //  |   |\n    //  A   Q\n    //     | |\n    //     B C\n    //\n    // Q and P must exist.\n    // B may not exist.\n    // A and C are not affected.\n\n    Q = *Root;\n    P = Q->Left;\n\n    // The new root is P\n\n    *Root = P;\n    P->Parent = Q->Parent;\n\n    // Q.Left = P.Right (transfer B)\n\n    Q->Left = P->Right;\n\n    if (Q->Left)\n        Q->Left->Parent = Q;\n\n    // P.Right = Q\n\n    P->Right = Q;\n    Q->Parent = P;\n}\n\nFORCEINLINE VOID PhpRotateRightTwiceAvlLinks(\n    _Inout_ PPH_AVL_LINKS *Root\n    )\n{\n    PPH_AVL_LINKS P;\n    PPH_AVL_LINKS Q;\n    PPH_AVL_LINKS R;\n\n    //       P\n    //    |     |\n    //    Q     D\n    //  |   |\n    //  A   R\n    //     | |\n    //     B C\n    //\n    // becomes\n    //\n    //     R\n    //  |     |\n    //  Q     P\n    // | |   | |\n    // A B   C D\n    //\n    // P, Q, and R must exist.\n    // B and C may not exist.\n    // A and D are not affected.\n\n    // PhpRotateLeftAvlLinks(&(*Root)->Left);\n    // PhpRotateRightAvlLinks(Root);\n\n    // P is the current root\n    // Q is P.Left\n    // R is Q.Right (P.Left.Right)\n\n    P = *Root;\n    Q = P->Left;\n    R = Q->Right;\n\n    // The new root is R\n\n    *Root = R;\n    R->Parent = P->Parent;\n\n    // Q.Right = R.Left (transfer B)\n\n    Q->Right = R->Left;\n\n    if (Q->Right)\n        Q->Right->Parent = Q;\n\n    // R.Left = Q\n\n    R->Left = Q;\n    Q->Parent = R;\n\n    // P.Left = R.Right (transfer C)\n\n    P->Left = R->Right;\n\n    if (P->Left)\n        P->Left->Parent = P;\n\n    // R.Right = P\n\n    R->Right = P;\n    P->Parent = R;\n}\n\nULONG PhpRebalanceAvlLinks(\n    _Inout_ PPH_AVL_LINKS *Root\n    )\n{\n    PPH_AVL_LINKS P;\n    PPH_AVL_LINKS Q;\n    PPH_AVL_LINKS R;\n\n    P = *Root;\n\n    if (P->Balance == -1)\n    {\n        Q = P->Left;\n\n        if (Q->Balance == -1)\n        {\n            // Left-left\n\n            PhpRotateRightAvlLinks(Root);\n\n            P->Balance = 0;\n            Q->Balance = 0;\n\n            return 1;\n        }\n        else if (Q->Balance == 1)\n        {\n            // Left-right\n\n            R = Q->Right;\n\n            PhpRotateRightTwiceAvlLinks(Root);\n\n            if (R->Balance == -1)\n            {\n                P->Balance = 1;\n                Q->Balance = 0;\n            }\n            else if (R->Balance == 1)\n            {\n                P->Balance = 0;\n                Q->Balance = -1;\n            }\n            else\n            {\n                P->Balance = 0;\n                Q->Balance = 0;\n            }\n\n            R->Balance = 0;\n\n            return 2;\n        }\n        else\n        {\n            // Special (only occurs when removing)\n\n            //    D\n            //  |   |\n            //  B   E\n            // | |\n            // A C\n            //\n            // Removing E results in:\n            //\n            //    D\n            //  |\n            //  B\n            // | |\n            // A C\n            //\n            // which is unbalanced. Rotating right at B results in:\n            //\n            //   B\n            // |   |\n            // A   D\n            //    |\n            //    C\n            //\n            // The same applies for the mirror case.\n\n            PhpRotateRightAvlLinks(Root);\n\n            Q->Balance = 1;\n\n            return 3;\n        }\n    }\n    else\n    {\n        Q = P->Right;\n\n        if (Q->Balance == 1)\n        {\n            // Right-right\n\n            PhpRotateLeftAvlLinks(Root);\n\n            P->Balance = 0;\n            Q->Balance = 0;\n\n            return 1;\n        }\n        else if (Q->Balance == -1)\n        {\n            // Right-left\n\n            R = Q->Left;\n\n            PhpRotateLeftTwiceAvlLinks(Root);\n\n            if (R->Balance == -1)\n            {\n                P->Balance = 0;\n                Q->Balance = 1;\n            }\n            else if (R->Balance == 1)\n            {\n                P->Balance = -1;\n                Q->Balance = 0;\n            }\n            else\n            {\n                P->Balance = 0;\n                Q->Balance = 0;\n            }\n\n            R->Balance = 0;\n\n            return 2;\n        }\n        else\n        {\n            // Special (only occurs when removing)\n\n            PhpRotateLeftAvlLinks(Root);\n\n            Q->Balance = -1;\n\n            return 3;\n        }\n    }\n}\n\n/**\n * Adds an element to an AVL tree.\n *\n * \\param Tree The tree.\n * \\param Element The element to add.\n *\n * \\return NULL if the element was added, or an existing element.\n */\nPPH_AVL_LINKS PhAddElementAvlTree(\n    _Inout_ PPH_AVL_TREE Tree,\n    _Out_ PPH_AVL_LINKS Element\n    )\n{\n    LONG result;\n    PPH_AVL_LINKS P;\n    PPH_AVL_LINKS root;\n    LONG balance;\n\n    P = PhpFindElementAvlTree(Tree, Element, &result);\n\n    if (result < 0)\n        P->Left = Element;\n    else if (result > 0)\n        P->Right = Element;\n    else\n        return P;\n\n    Element->Parent = P;\n    Element->Left = NULL;\n    Element->Right = NULL;\n    Element->Balance = 0;\n\n    // Balance the tree.\n\n    P = Element;\n    root = PhRootElementAvlTree(Tree);\n\n    while (P != root)\n    {\n        // In this implementation, the balance factor is the right height minus left height.\n\n        if (P->Parent->Left == P)\n            balance = -1;\n        else\n            balance = 1;\n\n        P = P->Parent;\n\n        if (P->Balance == 0)\n        {\n            // The balance becomes -1 or 1. Rotations are not needed\n            // yet, but we should keep tracing upwards.\n\n            P->Balance = balance;\n        }\n        else if (P->Balance != balance)\n        {\n            // The balance is opposite the new balance, so it now\n            // becomes 0.\n\n            P->Balance = 0;\n\n            break;\n        }\n        else\n        {\n            PPH_AVL_LINKS *ref;\n\n            // The balance is the same as the new balance, meaning\n            // it now becomes -2 or 2. Rotations are needed.\n\n            if (P->Parent->Left == P)\n                ref = &P->Parent->Left;\n            else\n                ref = &P->Parent->Right;\n\n            PhpRebalanceAvlLinks(ref);\n\n            break;\n        }\n    }\n\n    Tree->Count++;\n\n    return NULL;\n}\n\n/**\n * Removes an element from an AVL tree.\n *\n * \\param Tree The tree.\n * \\param Element An element already present in the tree.\n */\nVOID PhRemoveElementAvlTree(\n    _Inout_ PPH_AVL_TREE Tree,\n    _Inout_ PPH_AVL_LINKS Element\n    )\n{\n    PPH_AVL_LINKS newElement;\n    PPH_AVL_LINKS *replace;\n    PPH_AVL_LINKS P;\n    PPH_AVL_LINKS root;\n    LONG balance;\n\n    if (!Element->Left || !Element->Right)\n    {\n        newElement = Element;\n    }\n    else if (Element->Balance >= 0) // Pick the side depending on the balance to minimize rebalances\n    {\n        newElement = Element->Right;\n\n        while (newElement->Left)\n            newElement = newElement->Left;\n    }\n    else\n    {\n        newElement = Element->Left;\n\n        while (newElement->Right)\n            newElement = newElement->Right;\n    }\n\n    if (newElement->Parent->Left == newElement)\n    {\n        replace = &newElement->Parent->Left;\n        balance = -1;\n    }\n    else\n    {\n        replace = &newElement->Parent->Right;\n        balance = 1;\n    }\n\n    if (!newElement->Right)\n    {\n        *replace = newElement->Left;\n\n        if (newElement->Left)\n            newElement->Left->Parent = newElement->Parent;\n    }\n    else\n    {\n        *replace = newElement->Right;\n        newElement->Right->Parent = newElement->Parent; // we know Right exists\n    }\n\n    P = newElement->Parent;\n    root = &Tree->Root;\n\n    while (P != root)\n    {\n        if (P->Balance == balance)\n        {\n            // The balance is cancelled by the remove operation and becomes 0.\n            // Rotations are not needed yet, but we should keep tracing upwards.\n\n            P->Balance = 0;\n        }\n        else if (P->Balance == 0)\n        {\n            // The balance is 0, so it now becomes -1 or 1.\n\n            P->Balance = -balance;\n\n            break;\n        }\n        else\n        {\n            PPH_AVL_LINKS *ref;\n\n            // The balance is the same as the new balance, meaning\n            // it now becomes -2 or 2. Rotations are needed.\n\n            if (P->Parent->Left == P)\n                ref = &P->Parent->Left;\n            else\n                ref = &P->Parent->Right;\n\n            // We can stop tracing if we have a special case rotation.\n            if (PhpRebalanceAvlLinks(ref) == 3)\n                break;\n\n            P = P->Parent;\n        }\n\n        if (P->Parent->Left == P)\n            balance = -1;\n        else\n            balance = 1;\n\n        P = P->Parent;\n    }\n\n    if (newElement != Element)\n    {\n        // Replace the subject with the new subject.\n\n        *newElement = *Element;\n\n        if (Element->Parent->Left == Element)\n            newElement->Parent->Left = newElement;\n        else\n            newElement->Parent->Right = newElement;\n\n        if (newElement->Left)\n            newElement->Left->Parent = newElement;\n        if (newElement->Right)\n            newElement->Right->Parent = newElement;\n    }\n\n    Tree->Count--;\n}\n\n/**\n * Finds an element in an AVL tree.\n *\n * \\param Tree The tree.\n * \\param Element An element to find.\n *\n * \\return The element, or NULL if it could not be found.\n */\nPPH_AVL_LINKS PhFindElementAvlTree(\n    _In_ PPH_AVL_TREE Tree,\n    _In_ PPH_AVL_LINKS Element\n    )\n{\n    PPH_AVL_LINKS links;\n    LONG result;\n\n    links = PhpFindElementAvlTree(Tree, Element, &result);\n\n    if (result == 0)\n        return links;\n    else\n        return NULL;\n}\n\n/**\n * Finds the first element in an AVL tree that is greater than or equal to the specified element.\n *\n * \\param Tree The tree.\n * \\param Element The element to find.\n *\n * \\return The bound element, or NULL if the tree is empty.\n */\nPPH_AVL_LINKS PhLowerBoundElementAvlTree(\n    _In_ PPH_AVL_TREE Tree,\n    _In_ PPH_AVL_LINKS Element\n    )\n{\n    PPH_AVL_LINKS links;\n    PPH_AVL_LINKS closest;\n    LONG result;\n\n    links = PhRootElementAvlTree(Tree);\n    closest = NULL;\n\n    while (links)\n    {\n        result = Tree->CompareFunction(Element, links);\n\n        if (result > 0)\n        {\n            links = links->Right;\n        }\n        else\n        {\n            closest = links;\n            links = links->Left;\n        }\n    }\n\n    return closest;\n}\n\n/**\n * Finds the first element in an AVL tree that is greater than the specified element.\n *\n * \\param Tree The tree.\n * \\param Element The element to find.\n *\n * \\return The bound element, or NULL if the tree is empty.\n */\nPPH_AVL_LINKS PhUpperBoundElementAvlTree(\n    _In_ PPH_AVL_TREE Tree,\n    _In_ PPH_AVL_LINKS Element\n    )\n{\n    PPH_AVL_LINKS links;\n    PPH_AVL_LINKS closest;\n    LONG result;\n\n    links = PhRootElementAvlTree(Tree);\n    closest = NULL;\n\n    while (links)\n    {\n        result = Tree->CompareFunction(Element, links);\n\n        if (result >= 0)\n        {\n            links = links->Right;\n        }\n        else\n        {\n            closest = links;\n            links = links->Left;\n        }\n    }\n\n    return closest;\n}\n\n/**\n * Finds the last element in an AVL tree that is less than the specified element.\n *\n * \\param Tree The tree.\n * \\param Element The element to find.\n *\n * \\return The bound element, or NULL if the tree is empty.\n */\nPPH_AVL_LINKS PhLowerDualBoundElementAvlTree(\n    _In_ PPH_AVL_TREE Tree,\n    _In_ PPH_AVL_LINKS Element\n    )\n{\n    PPH_AVL_LINKS links;\n    PPH_AVL_LINKS closest;\n    LONG result;\n\n    links = PhRootElementAvlTree(Tree);\n    closest = NULL;\n\n    while (links)\n    {\n        result = Tree->CompareFunction(Element, links);\n\n        if (result > 0)\n        {\n            closest = links;\n            links = links->Right;\n        }\n        else\n        {\n            links = links->Left;\n        }\n    }\n\n    return closest;\n}\n\n/**\n * Finds the last element in an AVL tree that is less than or equal to the specified element.\n *\n * \\param Tree The tree.\n * \\param Element The element to find.\n *\n * \\return The bound element, or NULL if the tree is empty.\n */\nPPH_AVL_LINKS PhUpperDualBoundElementAvlTree(\n    _In_ PPH_AVL_TREE Tree,\n    _In_ PPH_AVL_LINKS Element\n    )\n{\n    PPH_AVL_LINKS links;\n    PPH_AVL_LINKS closest;\n    LONG result;\n\n    links = PhRootElementAvlTree(Tree);\n    closest = NULL;\n\n    while (links)\n    {\n        result = Tree->CompareFunction(Element, links);\n\n        if (result >= 0)\n        {\n            closest = links;\n            links = links->Right;\n        }\n        else\n        {\n            links = links->Left;\n        }\n    }\n\n    return closest;\n}\n\n/**\n * Finds the smallest element in an AVL tree.\n *\n * \\param Tree The tree.\n *\n * \\return An element, or NULL if the tree is empty.\n */\nPPH_AVL_LINKS PhMinimumElementAvlTree(\n    _In_ PPH_AVL_TREE Tree\n    )\n{\n    PPH_AVL_LINKS links;\n\n    links = PhRootElementAvlTree(Tree);\n\n    if (!links)\n        return NULL;\n\n    while (links->Left)\n        links = links->Left;\n\n    return links;\n}\n\n/**\n * Finds the biggest element in an AVL tree.\n *\n * \\param Tree The tree.\n *\n * \\return An element, or NULL if the tree is empty.\n */\nPPH_AVL_LINKS PhMaximumElementAvlTree(\n    _In_ PPH_AVL_TREE Tree\n    )\n{\n    PPH_AVL_LINKS links;\n\n    links = PhRootElementAvlTree(Tree);\n\n    if (!links)\n        return NULL;\n\n    while (links->Right)\n        links = links->Right;\n\n    return links;\n}\n\n/**\n * Finds the next element in an AVL tree.\n *\n * \\param Element The element.\n *\n * \\return The next element, or NULL if there are no more elements.\n */\nPPH_AVL_LINKS PhSuccessorElementAvlTree(\n    _In_ PPH_AVL_LINKS Element\n    )\n{\n    PPH_AVL_LINKS links;\n\n    if (Element->Right)\n    {\n        Element = Element->Right;\n\n        while (Element->Left)\n            Element = Element->Left;\n\n        return Element;\n    }\n    else\n    {\n        // Trace back to the next vertical level. Note\n        // that this code does in fact return NULL when there\n        // are no more elements because of the way the root\n        // element is constructed.\n\n        links = Element->Parent;\n\n        while (links && links->Right == Element)\n        {\n            Element = links;\n            links = links->Parent;\n        }\n\n        return links;\n    }\n}\n\n/**\n * Finds the previous element in an AVL tree.\n *\n * \\param Element The element.\n *\n * \\return The previous element, or NULL if there are no more elements.\n */\nPPH_AVL_LINKS PhPredecessorElementAvlTree(\n    _In_ PPH_AVL_LINKS Element\n    )\n{\n    PPH_AVL_LINKS links;\n\n    if (Element->Left)\n    {\n        Element = Element->Left;\n\n        while (Element->Right)\n            Element = Element->Right;\n\n        return Element;\n    }\n    else\n    {\n        links = Element->Parent;\n\n        while (links && links->Left == Element)\n        {\n            Element = links;\n            links = links->Parent;\n        }\n\n        if (links)\n        {\n            // We need an additional check because the tree root is\n            // stored in Root.Right, not Left.\n            if (!links->Parent)\n                return NULL; // reached Root, so no more elements\n        }\n\n        return links;\n    }\n}\n\n/**\n * Enumerates the elements in an AVL tree.\n *\n * \\param Tree The tree.\n * \\param Order The enumeration order.\n * \\param Callback The callback function.\n * \\param Context A user-defined value to pass to the callback function.\n */\nVOID PhEnumAvlTree(\n    _In_ PPH_AVL_TREE Tree,\n    _In_ PH_TREE_ENUMERATION_ORDER Order,\n    _In_ PPH_ENUM_AVL_TREE_CALLBACK Callback,\n    _In_opt_ PVOID Context\n    )\n{\n    // The maximum height of an AVL tree is around 1.44 * log2(n).\n    // The maximum number of elements in this implementation is 2^32, so the maximum height is\n    // around 46.08.\n    PPH_AVL_LINKS stackBase[47];\n    PPH_AVL_LINKS *stack;\n    PPH_AVL_LINKS links;\n\n    stack = stackBase;\n\n    switch (Order)\n    {\n    case TreeEnumerateInOrder:\n        links = PhRootElementAvlTree(Tree);\n\n        while (links)\n        {\n            *stack++ = links;\n            links = links->Left;\n        }\n\n        while (stack != stackBase)\n        {\n            links = *--stack;\n\n            if (!Callback(Tree, links, Context))\n                break;\n\n            links = links->Right;\n\n            while (links)\n            {\n                *stack++ = links;\n                links = links->Left;\n            }\n        }\n\n        break;\n    case TreeEnumerateInReverseOrder:\n        links = PhRootElementAvlTree(Tree);\n\n        while (links)\n        {\n            *stack++ = links;\n            links = links->Right;\n        }\n\n        while (stack != stackBase)\n        {\n            links = *--stack;\n\n            if (!Callback(Tree, links, Context))\n                break;\n\n            links = links->Left;\n\n            while (links)\n            {\n                *stack++ = links;\n                links = links->Right;\n            }\n        }\n\n        break;\n    }\n}\n"
  },
  {
    "path": "third_party/phlib/basesup.c",
    "content": "/*\n * Process Hacker -\n *   base support functions\n *\n * Copyright (C) 2009-2016 wj32\n *\n * This file is part of Process Hacker.\n *\n * Process Hacker is free software; you can redistribute it and/or modify\n * it under the terms of the GNU General Public License as published by\n * the Free Software Foundation, either version 3 of the License, or\n * (at your option) any later version.\n *\n * Process Hacker is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n * GNU General Public License for more details.\n *\n * You should have received a copy of the GNU General Public License\n * along with Process Hacker.  If not, see <http://www.gnu.org/licenses/>.\n */\n\n/*\n * This file contains basic low-level code as well as general algorithms and data structures.\n *\n * Memory allocation. PhAllocate is a wrapper around RtlAllocateHeap, and always allocates from the\n * phlib heap. PhAllocatePage is a wrapper around NtAllocateVirtualMemory and allocates pages.\n *\n * Null-terminated strings. The Ph*StringZ functions manipulate null-terminated strings. The copying\n * functions provide a simple way to copy strings which may not be null-terminated, but have a\n * specified limit.\n *\n * String. The design of the string object was chosen for maximum compatibility. As such each string\n * buffer must be null-terminated, and each object contains an embedded PH_STRINGREF structure. Note\n * that efficient sub-string creation (no copying, only references the parent string object) could\n * not be implemented due to the mandatory null-termination. String objects must be regarded as\n * immutable (for thread-safety reasons) unless the object has just been created and no references\n * have been shared.\n *\n * String builder. This is a set of functions which allow for efficient modification of strings. For\n * performance reasons, these functions modify string objects directly, even though they are\n * normally immutable.\n *\n * List. A simple PVOID list that resizes itself when needed.\n *\n * Pointer list. Similar to the normal list object, but uses a free list in order to support\n * constant time insertion and deletion. In order for the free list to work, normal entries have\n * their lowest bit clear while free entries have their lowest bit set, with the index of the next\n * free entry in the upper bits.\n *\n * Hashtable. A hashtable with power-of-two bucket sizes and with all entries stored in a single\n * array. This improves locality but may be inefficient when resizing the hashtable. It is a good\n * idea to store pointers to objects as entries, as opposed to the objects themselves.\n *\n * Simple hashtable. A wrapper around the normal hashtable, with PVOID keys and PVOID values.\n *\n * Free list. A thread-safe memory allocation method where freed blocks are stored in a S-list, and\n * allocations are made from this list whenever possible.\n *\n * Callback. A thread-safe notification mechanism where clients can register callback functions\n * which are then invoked by other code.\n */\n\n#include <phbase.h>\n\n#include <math.h>\n#include <objbase.h>\n\n#include <phintrnl.h>\n\n#define PH_VECTOR_LEVEL_NONE 0\n#define PH_VECTOR_LEVEL_SSE2 1\n#define PH_VECTOR_LEVEL_AVX 2\n\ntypedef struct _PHP_BASE_THREAD_CONTEXT\n{\n    PUSER_THREAD_START_ROUTINE StartAddress;\n    PVOID Parameter;\n} PHP_BASE_THREAD_CONTEXT, *PPHP_BASE_THREAD_CONTEXT;\n\nVOID NTAPI PhpListDeleteProcedure(\n    _In_ PVOID Object,\n    _In_ ULONG Flags\n    );\n\nVOID NTAPI PhpPointerListDeleteProcedure(\n    _In_ PVOID Object,\n    _In_ ULONG Flags\n    );\n\nVOID NTAPI PhpHashtableDeleteProcedure(\n    _In_ PVOID Object,\n    _In_ ULONG Flags\n    );\n\n// Types\n\nPPH_OBJECT_TYPE PhStringType;\nPPH_OBJECT_TYPE PhBytesType;\nPPH_OBJECT_TYPE PhListType;\nPPH_OBJECT_TYPE PhPointerListType;\nPPH_OBJECT_TYPE PhHashtableType;\n\n// Misc.\n\nstatic BOOLEAN PhpVectorLevel = PH_VECTOR_LEVEL_NONE;\nstatic PPH_STRING PhSharedEmptyString = NULL;\n\n// Threads\n\nstatic PH_FREE_LIST PhpBaseThreadContextFreeList;\n#ifdef DEBUG\nULONG PhDbgThreadDbgTlsIndex;\nLIST_ENTRY PhDbgThreadListHead;\nPH_QUEUED_LOCK PhDbgThreadListLock = PH_QUEUED_LOCK_INIT;\n#endif\n\n// Data\n\nstatic ULONG PhpPrimeNumbers[] =\n{\n    0x3, 0x7, 0xb, 0x11, 0x17, 0x1d, 0x25, 0x2f, 0x3b, 0x47, 0x59, 0x6b, 0x83,\n    0xa3, 0xc5, 0xef, 0x125, 0x161, 0x1af, 0x209, 0x277, 0x2f9, 0x397, 0x44f,\n    0x52f, 0x63d, 0x78b, 0x91d, 0xaf1, 0xd2b, 0xfd1, 0x12fd, 0x16cf, 0x1b65,\n    0x20e3, 0x2777, 0x2f6f, 0x38ff, 0x446f, 0x521f, 0x628d, 0x7655, 0x8e01,\n    0xaa6b, 0xcc89, 0xf583, 0x126a7, 0x1619b, 0x1a857, 0x1fd3b, 0x26315, 0x2dd67,\n    0x3701b, 0x42023, 0x4f361, 0x5f0ed, 0x72125, 0x88e31, 0xa443b, 0xc51eb,\n    0xec8c1, 0x11bdbf, 0x154a3f, 0x198c4f, 0x1ea867, 0x24ca19, 0x2c25c1, 0x34fa1b,\n    0x3f928f, 0x4c4987, 0x5b8b6f, 0x6dda89\n};\n\n/**\n * Initializes the base support module.\n */\nBOOLEAN PhBaseInitialization(\n    VOID\n    )\n{\n    PH_OBJECT_TYPE_PARAMETERS parameters;\n\n    // The following relies on the (technically undefined) value of XState being zero before Windows 7 SP1.\n    // NOTE: This is unused for now.\n    /*if (USER_SHARED_DATA->XState.EnabledFeatures & XSTATE_MASK_AVX)\n        PhpVectorLevel = PH_VECTOR_LEVEL_AVX;\n    else*/ if (USER_SHARED_DATA->ProcessorFeatures[PF_XMMI64_INSTRUCTIONS_AVAILABLE])\n        PhpVectorLevel = PH_VECTOR_LEVEL_SSE2;\n\n    PhStringType = PhCreateObjectType(L\"String\", 0, NULL);\n    PhBytesType = PhCreateObjectType(L\"Bytes\", 0, NULL);\n\n    parameters.FreeListSize = sizeof(PH_LIST);\n    parameters.FreeListCount = 128;\n\n    PhListType = PhCreateObjectTypeEx(L\"List\", PH_OBJECT_TYPE_USE_FREE_LIST, PhpListDeleteProcedure, &parameters);\n    PhPointerListType = PhCreateObjectType(L\"PointerList\", 0, PhpPointerListDeleteProcedure);\n\n    parameters.FreeListSize = sizeof(PH_HASHTABLE);\n    parameters.FreeListCount = 64;\n\n    PhHashtableType = PhCreateObjectTypeEx(L\"Hashtable\", PH_OBJECT_TYPE_USE_FREE_LIST, PhpHashtableDeleteProcedure, &parameters);\n\n    PhInitializeFreeList(&PhpBaseThreadContextFreeList, sizeof(PHP_BASE_THREAD_CONTEXT), 16);\n\n#ifdef DEBUG\n    PhDbgThreadDbgTlsIndex = TlsAlloc();\n    InitializeListHead(&PhDbgThreadListHead);\n#endif\n\n    return TRUE;\n}\n\nNTSTATUS PhpBaseThreadStart(\n    _In_ PVOID Parameter\n    )\n{\n    NTSTATUS status;\n    HRESULT result;\n    PHP_BASE_THREAD_CONTEXT context;\n#ifdef DEBUG\n    PHP_BASE_THREAD_DBG dbg;\n#endif\n\n    context = *(PPHP_BASE_THREAD_CONTEXT)Parameter;\n    PhFreeToFreeList(&PhpBaseThreadContextFreeList, Parameter);\n\n#ifdef DEBUG\n    dbg.ClientId = NtCurrentTeb()->ClientId;\n\n    dbg.StartAddress = context.StartAddress;\n    dbg.Parameter = context.Parameter;\n    dbg.CurrentAutoPool = NULL;\n\n    PhAcquireQueuedLockExclusive(&PhDbgThreadListLock);\n    InsertTailList(&PhDbgThreadListHead, &dbg.ListEntry);\n    PhReleaseQueuedLockExclusive(&PhDbgThreadListLock);\n\n    TlsSetValue(PhDbgThreadDbgTlsIndex, &dbg);\n#endif\n\n    // Initialization code\n\n    result = CoInitializeEx(NULL, COINIT_APARTMENTTHREADED | COINIT_DISABLE_OLE1DDE);\n\n    // Call the user-supplied function.\n    status = context.StartAddress(context.Parameter);\n\n    // De-initialization code\n\n    if (result == S_OK || result == S_FALSE)\n        CoUninitialize();\n\n#ifdef DEBUG\n    PhAcquireQueuedLockExclusive(&PhDbgThreadListLock);\n    RemoveEntryList(&dbg.ListEntry);\n    PhReleaseQueuedLockExclusive(&PhDbgThreadListLock);\n#endif\n\n    return status;\n}\n\n/**\n * Creates a thread.\n *\n * \\param StackSize The initial stack size of the thread.\n * \\param StartAddress The function to execute in the thread.\n * \\param Parameter A user-defined value to pass to the function.\n */\nHANDLE PhCreateThread(\n    _In_opt_ SIZE_T StackSize,\n    _In_ PUSER_THREAD_START_ROUTINE StartAddress,\n    _In_opt_ PVOID Parameter\n    )\n{\n    HANDLE threadHandle;\n    PPHP_BASE_THREAD_CONTEXT context;\n\n    context = PhAllocateFromFreeList(&PhpBaseThreadContextFreeList);\n    context->StartAddress = StartAddress;\n    context->Parameter = Parameter;\n\n    if (NT_SUCCESS(RtlCreateUserThread(\n        NtCurrentProcess(),\n        NULL,\n        FALSE,\n        0,\n        0,\n        StackSize,\n        PhpBaseThreadStart,\n        context,\n        &threadHandle,\n        NULL\n        )))\n    {\n        PHLIB_INC_STATISTIC(BaseThreadsCreated);\n        return threadHandle;\n    }\n    else\n    {\n        PHLIB_INC_STATISTIC(BaseThreadsCreateFailed);\n        PhFreeToFreeList(&PhpBaseThreadContextFreeList, context);\n        return NULL;\n    }\n}\n\nNTSTATUS PhCreateThread2(\n    _In_ PUSER_THREAD_START_ROUTINE StartAddress,\n    _In_opt_ PVOID Parameter\n    )\n{\n    NTSTATUS status;\n    HANDLE threadHandle;\n    PPHP_BASE_THREAD_CONTEXT context;\n\n    context = PhAllocateFromFreeList(&PhpBaseThreadContextFreeList);\n    context->StartAddress = StartAddress;\n    context->Parameter = Parameter;\n\n    status = RtlCreateUserThread(\n        NtCurrentProcess(),\n        NULL,\n        FALSE,\n        0,\n        0,\n        0,\n        PhpBaseThreadStart,\n        context,\n        &threadHandle,\n        NULL\n        );\n\n    if (NT_SUCCESS(status))\n    {\n        PHLIB_INC_STATISTIC(BaseThreadsCreated);\n        NtClose(threadHandle);\n    }\n    else\n    {\n        PHLIB_INC_STATISTIC(BaseThreadsCreateFailed);\n        PhFreeToFreeList(&PhpBaseThreadContextFreeList, context);\n    }\n\n    return status;\n}\n\n/**\n * Gets the current system time (UTC).\n *\n * \\remarks Use this function instead of NtQuerySystemTime() because no system calls are involved.\n */\nVOID PhQuerySystemTime(\n    _Out_ PLARGE_INTEGER SystemTime\n    )\n{\n    do\n    {\n        SystemTime->HighPart = USER_SHARED_DATA->SystemTime.High1Time;\n        SystemTime->LowPart = USER_SHARED_DATA->SystemTime.LowPart;\n    } while (SystemTime->HighPart != USER_SHARED_DATA->SystemTime.High2Time);\n}\n\n/**\n * Gets the offset of the current time zone from UTC.\n */\nVOID PhQueryTimeZoneBias(\n    _Out_ PLARGE_INTEGER TimeZoneBias\n    )\n{\n    do\n    {\n        TimeZoneBias->HighPart = USER_SHARED_DATA->TimeZoneBias.High1Time;\n        TimeZoneBias->LowPart = USER_SHARED_DATA->TimeZoneBias.LowPart;\n    } while (TimeZoneBias->HighPart != USER_SHARED_DATA->TimeZoneBias.High2Time);\n}\n\n/**\n * Converts system time to local time.\n *\n * \\param SystemTime A UTC time value.\n * \\param LocalTime A variable which receives the local time value. This may be the same variable as\n * \\a SystemTime.\n *\n * \\remarks Use this function instead of RtlSystemTimeToLocalTime() because no system calls are\n * involved.\n */\nVOID PhSystemTimeToLocalTime(\n    _In_ PLARGE_INTEGER SystemTime,\n    _Out_ PLARGE_INTEGER LocalTime\n    )\n{\n    LARGE_INTEGER timeZoneBias;\n\n    PhQueryTimeZoneBias(&timeZoneBias);\n    LocalTime->QuadPart = SystemTime->QuadPart - timeZoneBias.QuadPart;\n}\n\n/**\n * Converts local time to system time.\n *\n * \\param LocalTime A local time value.\n * \\param SystemTime A variable which receives the UTC time value. This may be the same variable as\n * \\a LocalTime.\n *\n * \\remarks Use this function instead of RtlLocalTimeToSystemTime() because no system calls are\n * involved.\n */\nVOID PhLocalTimeToSystemTime(\n    _In_ PLARGE_INTEGER LocalTime,\n    _Out_ PLARGE_INTEGER SystemTime\n    )\n{\n    LARGE_INTEGER timeZoneBias;\n\n    PhQueryTimeZoneBias(&timeZoneBias);\n    SystemTime->QuadPart = LocalTime->QuadPart + timeZoneBias.QuadPart;\n}\n\n/**\n * Allocates a block of memory.\n *\n * \\param Size The number of bytes to allocate.\n *\n * \\return A pointer to the allocated block of memory.\n *\n * \\remarks If the function fails to allocate the block of memory, it raises an exception. The block\n * is guaranteed to be aligned at MEMORY_ALLOCATION_ALIGNMENT bytes.\n */\n_May_raise_\n_Check_return_\n_Ret_notnull_\n_Post_writable_byte_size_(Size)\nPVOID PhAllocate(\n    _In_ SIZE_T Size\n    )\n{\n    return RtlAllocateHeap(PhHeapHandle, HEAP_GENERATE_EXCEPTIONS, Size);\n}\n\n/**\n * Allocates a block of memory.\n *\n * \\param Size The number of bytes to allocate.\n *\n * \\return A pointer to the allocated block of memory, or NULL if the block could not be allocated.\n */\nPVOID PhAllocateSafe(\n    _In_ SIZE_T Size\n    )\n{\n    return RtlAllocateHeap(PhHeapHandle, 0, Size);\n}\n\n/**\n * Allocates a block of memory.\n *\n * \\param Size The number of bytes to allocate.\n * \\param Flags Flags controlling the allocation.\n *\n * \\return A pointer to the allocated block of memory, or NULL if the block could not be allocated.\n */\nPVOID PhAllocateExSafe(\n    _In_ SIZE_T Size,\n    _In_ ULONG Flags\n    )\n{\n    return RtlAllocateHeap(PhHeapHandle, Flags, Size);\n}\n\n/**\n * Frees a block of memory allocated with PhAllocate().\n *\n * \\param Memory A pointer to a block of memory.\n */\nVOID PhFree(\n    _Frees_ptr_opt_ PVOID Memory\n    )\n{\n    RtlFreeHeap(PhHeapHandle, 0, Memory);\n}\n\n/**\n * Re-allocates a block of memory originally allocated with PhAllocate().\n *\n * \\param Memory A pointer to a block of memory.\n * \\param Size The new size of the memory block, in bytes.\n *\n * \\return A pointer to the new block of memory. The existing contents of the memory block are\n * copied to the new block.\n *\n * \\remarks If the function fails to allocate the block of memory, it raises an exception.\n */\n_May_raise_\n_Post_writable_byte_size_(Size)\nPVOID PhReAllocate(\n    _Frees_ptr_opt_ PVOID Memory,\n    _In_ SIZE_T Size\n    )\n{\n    return RtlReAllocateHeap(PhHeapHandle, HEAP_GENERATE_EXCEPTIONS, Memory, Size);\n}\n\n/**\n * Re-allocates a block of memory originally allocated with PhAllocate().\n *\n * \\param Memory A pointer to a block of memory.\n * \\param Size The new size of the memory block, in bytes.\n *\n * \\return A pointer to the new block of memory, or NULL if the block could not be allocated. The\n * existing contents of the memory block are copied to the new block.\n */\nPVOID PhReAllocateSafe(\n    _In_ PVOID Memory,\n    _In_ SIZE_T Size\n    )\n{\n    return RtlReAllocateHeap(PhHeapHandle, 0, Memory, Size);\n}\n\n/**\n * Allocates pages of memory.\n *\n * \\param Size The number of bytes to allocate. The number of pages allocated will be large enough\n * to contain \\a Size bytes.\n * \\param NewSize The number of bytes actually allocated. This is \\a Size rounded up to the next\n * multiple of PAGE_SIZE.\n *\n * \\return A pointer to the allocated block of memory, or NULL if the block could not be allocated.\n */\n_Check_return_\n_Ret_maybenull_\nPVOID PhAllocatePage(\n    _In_ SIZE_T Size,\n    _Out_opt_ PSIZE_T NewSize\n    )\n{\n    PVOID baseAddress;\n\n    baseAddress = NULL;\n\n    if (NT_SUCCESS(NtAllocateVirtualMemory(\n        NtCurrentProcess(),\n        &baseAddress,\n        0,\n        &Size,\n        MEM_COMMIT,\n        PAGE_READWRITE\n        )))\n    {\n        if (NewSize)\n            *NewSize = Size;\n\n        return baseAddress;\n    }\n    else\n    {\n        return NULL;\n    }\n}\n\n/**\n * Frees pages of memory allocated with PhAllocatePage().\n *\n * \\param Memory A pointer to a block of memory.\n */\nVOID PhFreePage(\n    _Frees_ptr_opt_ PVOID Memory\n    )\n{\n    SIZE_T size;\n\n    size = 0;\n\n    NtFreeVirtualMemory(\n        NtCurrentProcess(),\n        &Memory,\n        &size,\n        MEM_RELEASE\n        );\n}\n\n/**\n * Determines the length of the specified string, in characters.\n *\n * \\param String The string.\n */\nSIZE_T PhCountStringZ(\n    _In_ PWSTR String\n    )\n{\n    if (PhpVectorLevel >= PH_VECTOR_LEVEL_SSE2)\n    {\n        PWSTR p;\n        ULONG unaligned;\n        __m128i b;\n        __m128i z;\n        ULONG mask;\n        ULONG index;\n\n        p = (PWSTR)((ULONG_PTR)String & ~0xe); // String should be 2 byte aligned\n        unaligned = PtrToUlong(String) & 0xf;\n        z = _mm_setzero_si128();\n\n        if (unaligned != 0)\n        {\n            b = _mm_load_si128((__m128i *)p);\n            b = _mm_cmpeq_epi16(b, z);\n            mask = _mm_movemask_epi8(b) >> unaligned;\n\n            if (_BitScanForward(&index, mask))\n                return index / sizeof(WCHAR);\n\n            p += 16 / sizeof(WCHAR);\n        }\n\n        while (TRUE)\n        {\n            b = _mm_load_si128((__m128i *)p);\n            b = _mm_cmpeq_epi16(b, z);\n            mask = _mm_movemask_epi8(b);\n\n            if (_BitScanForward(&index, mask))\n                return (SIZE_T)(p - String) + index / sizeof(WCHAR);\n\n            p += 16 / sizeof(WCHAR);\n        }\n    }\n    else\n    {\n        return wcslen(String);\n    }\n}\n\n/**\n * Allocates space for and copies a byte string.\n *\n * \\param String The string to duplicate.\n *\n * \\return The new string, which can be freed using PhFree().\n */\nPSTR PhDuplicateBytesZ(\n    _In_ PSTR String\n    )\n{\n    PSTR newString;\n    SIZE_T length;\n\n    length = strlen(String) + 1; // include the null terminator\n\n    newString = PhAllocate(length);\n    memcpy(newString, String, length);\n\n    return newString;\n}\n\n/**\n * Allocates space for and copies a byte string.\n *\n * \\param String The string to duplicate.\n *\n * \\return The new string, which can be freed using PhFree(), or NULL if storage could not be\n * allocated.\n */\nPSTR PhDuplicateBytesZSafe(\n    _In_ PSTR String\n    )\n{\n    PSTR newString;\n    SIZE_T length;\n\n    length = strlen(String) + 1; // include the null terminator\n\n    newString = PhAllocateSafe(length);\n\n    if (!newString)\n        return NULL;\n\n    memcpy(newString, String, length);\n\n    return newString;\n}\n\n/**\n * Allocates space for and copies a 16-bit string.\n *\n * \\param String The string to duplicate.\n *\n * \\return The new string, which can be freed using PhFree().\n */\nPWSTR PhDuplicateStringZ(\n    _In_ PWSTR String\n    )\n{\n    PWSTR newString;\n    SIZE_T length;\n\n    length = (PhCountStringZ(String) + 1) * sizeof(WCHAR); // include the null terminator\n\n    newString = PhAllocate(length);\n    memcpy(newString, String, length);\n\n    return newString;\n}\n\n/**\n * Copies a string with optional null termination and a maximum number of characters.\n *\n * \\param InputBuffer A pointer to the input string.\n * \\param InputCount The maximum number of characters to copy, not including the null terminator.\n * Specify -1 for no limit.\n * \\param OutputBuffer A pointer to the output buffer.\n * \\param OutputCount The number of characters in the output buffer, including the null terminator.\n * \\param ReturnCount A variable which receives the number of characters required to contain the\n * input string, including the null terminator. If the function returns TRUE, this variable contains\n * the number of characters written to the output buffer.\n *\n * \\return TRUE if the input string was copied to the output string, otherwise FALSE.\n *\n * \\remarks The function stops copying when it encounters the first null character in the input\n * string. It will also stop copying when it reaches the character count specified in \\a InputCount,\n * if \\a InputCount is not -1.\n */\nBOOLEAN PhCopyBytesZ(\n    _In_ PSTR InputBuffer,\n    _In_ SIZE_T InputCount,\n    _Out_writes_opt_z_(OutputCount) PSTR OutputBuffer,\n    _In_ SIZE_T OutputCount,\n    _Out_opt_ PSIZE_T ReturnCount\n    )\n{\n    SIZE_T i;\n    BOOLEAN copied;\n\n    // Determine the length of the input string.\n\n    if (InputCount != -1)\n    {\n        i = 0;\n\n        while (i < InputCount && InputBuffer[i])\n            i++;\n    }\n    else\n    {\n        i = strlen(InputBuffer);\n    }\n\n    // Copy the string if there is enough room.\n\n    if (OutputBuffer && OutputCount >= i + 1) // need one character for null terminator\n    {\n        memcpy(OutputBuffer, InputBuffer, i);\n        OutputBuffer[i] = 0;\n        copied = TRUE;\n    }\n    else\n    {\n        copied = FALSE;\n    }\n\n    if (ReturnCount)\n        *ReturnCount = i + 1;\n\n    return copied;\n}\n\n/**\n * Copies a string with optional null termination and a maximum number of characters.\n *\n * \\param InputBuffer A pointer to the input string.\n * \\param InputCount The maximum number of characters to copy, not including the null terminator.\n * Specify -1 for no limit.\n * \\param OutputBuffer A pointer to the output buffer.\n * \\param OutputCount The number of characters in the output buffer, including the null terminator.\n * \\param ReturnCount A variable which receives the number of characters required to contain the\n * input string, including the null terminator. If the function returns TRUE, this variable contains\n * the number of characters written to the output buffer.\n *\n * \\return TRUE if the input string was copied to the output string, otherwise FALSE.\n *\n * \\remarks The function stops copying when it encounters the first null character in the input\n * string. It will also stop copying when it reaches the character count specified in \\a InputCount,\n * if \\a InputCount is not -1.\n */\nBOOLEAN PhCopyStringZ(\n    _In_ PWSTR InputBuffer,\n    _In_ SIZE_T InputCount,\n    _Out_writes_opt_z_(OutputCount) PWSTR OutputBuffer,\n    _In_ SIZE_T OutputCount,\n    _Out_opt_ PSIZE_T ReturnCount\n    )\n{\n    SIZE_T i;\n    BOOLEAN copied;\n\n    // Determine the length of the input string.\n\n    if (InputCount != -1)\n    {\n        i = 0;\n\n        while (i < InputCount && InputBuffer[i])\n            i++;\n    }\n    else\n    {\n        i = PhCountStringZ(InputBuffer);\n    }\n\n    // Copy the string if there is enough room.\n\n    if (OutputBuffer && OutputCount >= i + 1) // need one character for null terminator\n    {\n        memcpy(OutputBuffer, InputBuffer, i * sizeof(WCHAR));\n        OutputBuffer[i] = 0;\n        copied = TRUE;\n    }\n    else\n    {\n        copied = FALSE;\n    }\n\n    if (ReturnCount)\n        *ReturnCount = i + 1;\n\n    return copied;\n}\n\n/**\n * Copies a string with optional null termination and a maximum number of characters.\n *\n * \\param InputBuffer A pointer to the input string.\n * \\param InputCount The maximum number of characters to copy, not including the null terminator.\n * Specify -1 for no limit.\n * \\param OutputBuffer A pointer to the output buffer.\n * \\param OutputCount The number of characters in the output buffer, including the null terminator.\n * \\param ReturnCount A variable which receives the number of characters required to contain the\n * input string, including the null terminator. If the function returns TRUE, this variable contains\n * the number of characters written to the output buffer.\n *\n * \\return TRUE if the input string was copied to the output string, otherwise FALSE.\n *\n * \\remarks The function stops copying when it encounters the first null character in the input\n * string. It will also stop copying when it reaches the character count specified in \\a InputCount,\n * if \\a InputCount is not -1.\n */\nBOOLEAN PhCopyStringZFromBytes(\n    _In_ PSTR InputBuffer,\n    _In_ SIZE_T InputCount,\n    _Out_writes_opt_z_(OutputCount) PWSTR OutputBuffer,\n    _In_ SIZE_T OutputCount,\n    _Out_opt_ PSIZE_T ReturnCount\n    )\n{\n    SIZE_T i;\n    BOOLEAN copied;\n\n    // Determine the length of the input string.\n\n    if (InputCount != -1)\n    {\n        i = 0;\n\n        while (i < InputCount && InputBuffer[i])\n            i++;\n    }\n    else\n    {\n        i = strlen(InputBuffer);\n    }\n\n    // Copy the string if there is enough room.\n\n    if (OutputBuffer && OutputCount >= i + 1) // need one character for null terminator\n    {\n        PhZeroExtendToUtf16Buffer(InputBuffer, i, OutputBuffer);\n        OutputBuffer[i] = 0;\n        copied = TRUE;\n    }\n    else\n    {\n        copied = FALSE;\n    }\n\n    if (ReturnCount)\n        *ReturnCount = i + 1;\n\n    return copied;\n}\n\n/**\n * Copies a string with optional null termination and a maximum number of characters.\n *\n * \\param InputBuffer A pointer to the input string.\n * \\param InputCount The maximum number of characters to copy, not including the null terminator.\n * Specify -1 for no limit.\n * \\param OutputBuffer A pointer to the output buffer.\n * \\param OutputCount The number of characters in the output buffer, including the null terminator.\n * \\param ReturnCount A variable which receives the number of characters required to contain the\n * input string, including the null terminator. If the function returns TRUE, this variable contains\n * the number of characters written to the output buffer.\n *\n * \\return TRUE if the input string was copied to the output string, otherwise FALSE.\n *\n * \\remarks The function stops copying when it encounters the first null character in the input\n * string. It will also stop copying when it reaches the character count specified in \\a InputCount,\n * if \\a InputCount is not -1.\n */\nBOOLEAN PhCopyStringZFromMultiByte(\n    _In_ PSTR InputBuffer,\n    _In_ SIZE_T InputCount,\n    _Out_writes_opt_z_(OutputCount) PWSTR OutputBuffer,\n    _In_ SIZE_T OutputCount,\n    _Out_opt_ PSIZE_T ReturnCount\n    )\n{\n    NTSTATUS status;\n    SIZE_T i;\n    ULONG unicodeBytes;\n    BOOLEAN copied;\n\n    // Determine the length of the input string.\n\n    if (InputCount != -1)\n    {\n        i = 0;\n\n        while (i < InputCount && InputBuffer[i])\n            i++;\n    }\n    else\n    {\n        i = strlen(InputBuffer);\n    }\n\n    // Determine the length of the output string.\n\n    status = RtlMultiByteToUnicodeSize(\n        &unicodeBytes,\n        InputBuffer,\n        (ULONG)i\n        );\n\n    if (!NT_SUCCESS(status))\n    {\n        if (ReturnCount)\n            *ReturnCount = -1;\n\n        return FALSE;\n    }\n\n    // Convert the string to Unicode if there is enough room.\n\n    if (OutputBuffer && OutputCount >= unicodeBytes / sizeof(WCHAR) + 1)\n    {\n        status = RtlMultiByteToUnicodeN(\n            OutputBuffer,\n            unicodeBytes,\n            NULL,\n            InputBuffer,\n            (ULONG)i\n            );\n\n        if (NT_SUCCESS(status))\n        {\n            // RtlMultiByteToUnicodeN doesn't null terminate the string.\n            *(PWCHAR)PTR_ADD_OFFSET(OutputBuffer, unicodeBytes) = 0;\n            copied = TRUE;\n        }\n        else\n        {\n            copied = FALSE;\n        }\n    }\n    else\n    {\n        copied = FALSE;\n    }\n\n    if (ReturnCount)\n        *ReturnCount = unicodeBytes / sizeof(WCHAR) + 1;\n\n    return copied;\n}\n\nFORCEINLINE LONG PhpCompareRightNatural(\n    _In_ PWSTR A,\n    _In_ PWSTR B\n    )\n{\n    LONG bias = 0;\n\n    for (; ; A++, B++)\n    {\n        if (!PhIsDigitCharacter(*A) && !PhIsDigitCharacter(*B))\n        {\n            return bias;\n        }\n        else if (!PhIsDigitCharacter(*A))\n        {\n            return -1;\n        }\n        else if (!PhIsDigitCharacter(*B))\n        {\n            return 1;\n        }\n        else if (*A < *B)\n        {\n            if (bias == 0)\n                bias = -1;\n        }\n        else if (*A > *B)\n        {\n            if (bias == 0)\n                bias = 1;\n        }\n        else if (!*A && !*B)\n        {\n            return bias;\n        }\n    }\n\n    return 0;\n}\n\nFORCEINLINE LONG PhpCompareLeftNatural(\n    _In_ PWSTR A,\n    _In_ PWSTR B\n    )\n{\n    for (; ; A++, B++)\n    {\n        if (!PhIsDigitCharacter(*A) && !PhIsDigitCharacter(*B))\n        {\n            return 0;\n        }\n        else if (!PhIsDigitCharacter(*A))\n        {\n            return -1;\n        }\n        else if (!PhIsDigitCharacter(*B))\n        {\n            return 1;\n        }\n        else if (*A < *B)\n        {\n            return -1;\n        }\n        else if (*A > *B)\n        {\n            return 1;\n        }\n    }\n\n    return 0;\n}\n\nFORCEINLINE LONG PhpCompareStringZNatural(\n    _In_ PWSTR A,\n    _In_ PWSTR B,\n    _In_ BOOLEAN IgnoreCase\n    )\n{\n    /*  strnatcmp.c -- Perform 'natural order' comparisons of strings in C.\n        Copyright (C) 2000, 2004 by Martin Pool <mbp sourcefrog net>\n\n        This software is provided 'as-is', without any express or implied\n        warranty.  In no event will the authors be held liable for any damages\n        arising from the use of this software.\n\n        Permission is granted to anyone to use this software for any purpose,\n        including commercial applications, and to alter it and redistribute it\n        freely, subject to the following restrictions:\n\n        1. The origin of this software must not be misrepresented; you must not\n         claim that you wrote the original software. If you use this software\n         in a product, an acknowledgment in the product documentation would be\n         appreciated but is not required.\n        2. Altered source versions must be plainly marked as such, and must not be\n         misrepresented as being the original software.\n        3. This notice may not be removed or altered from any source distribution.\n\n        This code has been modified for Process Hacker.\n     */\n\n    ULONG ai, bi;\n    WCHAR ca, cb;\n    LONG result;\n    BOOLEAN fractional;\n\n    ai = 0;\n    bi = 0;\n\n    while (TRUE)\n    {\n        ca = A[ai];\n        cb = B[bi];\n\n        /* Skip over leading spaces or zeros. */\n\n        while (ca == ' ')\n            ca = A[++ai];\n\n        while (cb == ' ')\n            cb = B[++bi];\n\n        /* Process run of digits. */\n        if (PhIsDigitCharacter(ca) && PhIsDigitCharacter(cb))\n        {\n            fractional = (ca == '0' || cb == '0');\n\n            if (fractional)\n            {\n                if ((result = PhpCompareLeftNatural(A + ai, B + bi)) != 0)\n                    return result;\n            }\n            else\n            {\n                if ((result = PhpCompareRightNatural(A + ai, B + bi)) != 0)\n                    return result;\n            }\n        }\n\n        if (!ca && !cb)\n        {\n            /* Strings are considered the same. */\n            return 0;\n        }\n\n        if (IgnoreCase)\n        {\n            ca = towupper(ca);\n            cb = towupper(cb);\n        }\n\n        if (ca < cb)\n            return -1;\n        else if (ca > cb)\n            return 1;\n\n        ai++;\n        bi++;\n    }\n}\n\n/**\n * Compares two strings in natural sort order.\n *\n * \\param A The first string.\n * \\param B The second string.\n * \\param IgnoreCase Whether to ignore character cases.\n */\nLONG PhCompareStringZNatural(\n    _In_ PWSTR A,\n    _In_ PWSTR B,\n    _In_ BOOLEAN IgnoreCase\n    )\n{\n    if (!IgnoreCase)\n        return PhpCompareStringZNatural(A, B, FALSE);\n    else\n        return PhpCompareStringZNatural(A, B, TRUE);\n}\n\n/**\n * Compares two strings.\n *\n * \\param String1 The first string.\n * \\param String2 The second string.\n * \\param IgnoreCase TRUE to perform a case-insensitive comparison, otherwise FALSE.\n */\nLONG PhCompareStringRef(\n    _In_ PPH_STRINGREF String1,\n    _In_ PPH_STRINGREF String2,\n    _In_ BOOLEAN IgnoreCase\n    )\n{\n    SIZE_T l1;\n    SIZE_T l2;\n    PWCHAR s1;\n    PWCHAR s2;\n    WCHAR c1;\n    WCHAR c2;\n    PWCHAR end;\n\n    // Note: this function assumes that the difference between the lengths of the two strings can\n    // fit inside a LONG.\n\n    l1 = String1->Length;\n    l2 = String2->Length;\n    assert(!(l1 & 1));\n    assert(!(l2 & 1));\n    s1 = String1->Buffer;\n    s2 = String2->Buffer;\n\n    end = (PWCHAR)PTR_ADD_OFFSET(s1, l1 <= l2 ? l1 : l2);\n\n    if (!IgnoreCase)\n    {\n        while (s1 != end)\n        {\n            c1 = *s1;\n            c2 = *s2;\n\n            if (c1 != c2)\n                return (LONG)c1 - (LONG)c2;\n\n            s1++;\n            s2++;\n        }\n    }\n    else\n    {\n        while (s1 != end)\n        {\n            c1 = *s1;\n            c2 = *s2;\n\n            if (c1 != c2)\n            {\n                c1 = RtlUpcaseUnicodeChar(c1);\n                c2 = RtlUpcaseUnicodeChar(c2);\n\n                if (c1 != c2)\n                    return (LONG)c1 - (LONG)c2;\n            }\n\n            s1++;\n            s2++;\n        }\n    }\n\n    return (LONG)(l1 - l2);\n}\n\n/**\n * Determines if two strings are equal.\n *\n * \\param String1 The first string.\n * \\param String2 The second string.\n * \\param IgnoreCase TRUE to perform a case-insensitive comparison, otherwise FALSE.\n */\nBOOLEAN PhEqualStringRef(\n    _In_ PPH_STRINGREF String1,\n    _In_ PPH_STRINGREF String2,\n    _In_ BOOLEAN IgnoreCase\n    )\n{\n    SIZE_T l1;\n    SIZE_T l2;\n    PWSTR s1;\n    PWSTR s2;\n    WCHAR c1;\n    WCHAR c2;\n    SIZE_T length;\n\n    l1 = String1->Length;\n    l2 = String2->Length;\n    assert(!(l1 & 1));\n    assert(!(l2 & 1));\n\n    if (l1 != l2)\n        return FALSE;\n\n    s1 = String1->Buffer;\n    s2 = String2->Buffer;\n\n    if (PhpVectorLevel >= PH_VECTOR_LEVEL_SSE2)\n    {\n        length = l1 / 16;\n\n        if (length != 0)\n        {\n            __m128i b1;\n            __m128i b2;\n\n            do\n            {\n                b1 = _mm_loadu_si128((__m128i *)s1);\n                b2 = _mm_loadu_si128((__m128i *)s2);\n                b1 = _mm_cmpeq_epi32(b1, b2);\n\n                if (_mm_movemask_epi8(b1) != 0xffff)\n                {\n                    if (!IgnoreCase)\n                    {\n                        return FALSE;\n                    }\n                    else\n                    {\n                        // Compare character-by-character to ignore case.\n                        l1 = length * 16 + (l1 & 15);\n                        l1 /= sizeof(WCHAR);\n                        goto CompareCharacters;\n                    }\n                }\n\n                s1 += 16 / sizeof(WCHAR);\n                s2 += 16 / sizeof(WCHAR);\n            } while (--length != 0);\n        }\n\n        // Compare character-by-character because we have no more 16-byte blocks to compare.\n        l1 = (l1 & 15) / sizeof(WCHAR);\n    }\n    else\n    {\n        length = l1 / sizeof(ULONG_PTR);\n\n        if (length != 0)\n        {\n            do\n            {\n                if (*(PULONG_PTR)s1 != *(PULONG_PTR)s2)\n                {\n                    if (!IgnoreCase)\n                    {\n                        return FALSE;\n                    }\n                    else\n                    {\n                        // Compare character-by-character to ignore case.\n                        l1 = length * sizeof(ULONG_PTR) + (l1 & (sizeof(ULONG_PTR) - 1));\n                        l1 /= sizeof(WCHAR);\n                        goto CompareCharacters;\n                    }\n                }\n\n                s1 += sizeof(ULONG_PTR) / sizeof(WCHAR);\n                s2 += sizeof(ULONG_PTR) / sizeof(WCHAR);\n            } while (--length != 0);\n        }\n\n        // Compare character-by-character because we have no more ULONG_PTR blocks to compare.\n        l1 = (l1 & (sizeof(ULONG_PTR) - 1)) / sizeof(WCHAR);\n    }\n\nCompareCharacters:\n    if (l1 != 0)\n    {\n        if (!IgnoreCase)\n        {\n            do\n            {\n                c1 = *s1;\n                c2 = *s2;\n\n                if (c1 != c2)\n                    return FALSE;\n\n                s1++;\n                s2++;\n            } while (--l1 != 0);\n        }\n        else\n        {\n            do\n            {\n                c1 = *s1;\n                c2 = *s2;\n\n                if (c1 != c2)\n                {\n                    c1 = RtlUpcaseUnicodeChar(c1);\n                    c2 = RtlUpcaseUnicodeChar(c2);\n\n                    if (c1 != c2)\n                        return FALSE;\n                }\n\n                s1++;\n                s2++;\n            } while (--l1 != 0);\n        }\n    }\n\n    return TRUE;\n}\n\n/**\n * Locates a character in a string.\n *\n * \\param String The string to search.\n * \\param Character The character to search for.\n * \\param IgnoreCase TRUE to perform a case-insensitive search, otherwise FALSE.\n *\n * \\return The index, in characters, of the first occurrence of \\a Character in \\a String1. If\n * \\a Character was not found, -1 is returned.\n */\nULONG_PTR PhFindCharInStringRef(\n    _In_ PPH_STRINGREF String,\n    _In_ WCHAR Character,\n    _In_ BOOLEAN IgnoreCase\n    )\n{\n    PWSTR buffer;\n    SIZE_T length;\n\n    buffer = String->Buffer;\n    length = String->Length / sizeof(WCHAR);\n\n    if (!IgnoreCase)\n    {\n        if (PhpVectorLevel >= PH_VECTOR_LEVEL_SSE2)\n        {\n            SIZE_T length16;\n\n            length16 = String->Length / 16;\n            length &= 7;\n\n            if (length16 != 0)\n            {\n                __m128i pattern;\n                __m128i block;\n                ULONG mask;\n                ULONG index;\n\n                pattern = _mm_set1_epi16(Character);\n\n                do\n                {\n                    block = _mm_loadu_si128((__m128i *)buffer);\n                    block = _mm_cmpeq_epi16(block, pattern);\n                    mask = _mm_movemask_epi8(block);\n\n                    if (_BitScanForward(&index, mask))\n                        return (String->Length - length16 * 16) / sizeof(WCHAR) - length + index / 2;\n\n                    buffer += 16 / sizeof(WCHAR);\n                } while (--length16 != 0);\n            }\n        }\n\n        if (length != 0)\n        {\n            do\n            {\n                if (*buffer == Character)\n                    return String->Length / sizeof(WCHAR) - length;\n\n                buffer++;\n            } while (--length != 0);\n        }\n    }\n    else\n    {\n        if (length != 0)\n        {\n            WCHAR c;\n\n            c = RtlUpcaseUnicodeChar(Character);\n\n            do\n            {\n                if (RtlUpcaseUnicodeChar(*buffer) == c)\n                    return String->Length / sizeof(WCHAR) - length;\n\n                buffer++;\n            } while (--length != 0);\n        }\n    }\n\n    return -1;\n}\n\n/**\n * Locates a character in a string, searching backwards.\n *\n * \\param String The string to search.\n * \\param Character The character to search for.\n * \\param IgnoreCase TRUE to perform a case-insensitive search, otherwise FALSE.\n *\n * \\return The index, in characters, of the last occurrence of \\a Character in \\a String1. If\n * \\a Character was not found, -1 is returned.\n */\nULONG_PTR PhFindLastCharInStringRef(\n    _In_ PPH_STRINGREF String,\n    _In_ WCHAR Character,\n    _In_ BOOLEAN IgnoreCase\n    )\n{\n    PWCHAR buffer;\n    SIZE_T length;\n\n    buffer = (PWCHAR)PTR_ADD_OFFSET(String->Buffer, String->Length);\n    length = String->Length / sizeof(WCHAR);\n\n    if (!IgnoreCase)\n    {\n        if (PhpVectorLevel >= PH_VECTOR_LEVEL_SSE2)\n        {\n            SIZE_T length16;\n\n            length16 = String->Length / 16;\n            length &= 7;\n\n            if (length16 != 0)\n            {\n                __m128i pattern;\n                __m128i block;\n                ULONG mask;\n                ULONG index;\n\n                pattern = _mm_set1_epi16(Character);\n                buffer -= 16 / sizeof(WCHAR);\n\n                do\n                {\n                    block = _mm_loadu_si128((__m128i *)buffer);\n                    block = _mm_cmpeq_epi16(block, pattern);\n                    mask = _mm_movemask_epi8(block);\n\n                    if (_BitScanReverse(&index, mask))\n                        return (length16 - 1) * 16 / sizeof(WCHAR) + length + index / 2;\n\n                    buffer -= 16 / sizeof(WCHAR);\n                } while (--length16 != 0);\n\n                buffer += 16 / sizeof(WCHAR);\n            }\n        }\n\n        if (length != 0)\n        {\n            buffer--;\n\n            do\n            {\n                if (*buffer == Character)\n                    return length - 1;\n\n                buffer--;\n            } while (--length != 0);\n        }\n    }\n    else\n    {\n        if (length != 0)\n        {\n            WCHAR c;\n\n            c = RtlUpcaseUnicodeChar(Character);\n            buffer--;\n\n            do\n            {\n                if (RtlUpcaseUnicodeChar(*buffer) == c)\n                    return length - 1;\n\n                buffer--;\n            } while (--length != 0);\n        }\n    }\n\n    return -1;\n}\n\n/**\n * Locates a string in a string.\n *\n * \\param String The string to search.\n * \\param SubString The string to search for.\n * \\param IgnoreCase TRUE to perform a case-insensitive search, otherwise FALSE.\n *\n * \\return The index, in characters, of the first occurrence of \\a SubString in \\a String. If\n * \\a SubString was not found, -1 is returned.\n */\nULONG_PTR PhFindStringInStringRef(\n    _In_ PPH_STRINGREF String,\n    _In_ PPH_STRINGREF SubString,\n    _In_ BOOLEAN IgnoreCase\n    )\n{\n    SIZE_T length1;\n    SIZE_T length2;\n    PH_STRINGREF sr1;\n    PH_STRINGREF sr2;\n    WCHAR c;\n    SIZE_T i;\n\n    length1 = String->Length / sizeof(WCHAR);\n    length2 = SubString->Length / sizeof(WCHAR);\n\n    // Can't be a substring if it's bigger than the first string.\n    if (length2 > length1)\n        return -1;\n    // We always get a match if the substring is zero-length.\n    if (length2 == 0)\n        return 0;\n\n    sr1.Buffer = String->Buffer;\n    sr1.Length = SubString->Length - sizeof(WCHAR);\n    sr2.Buffer = SubString->Buffer;\n    sr2.Length = SubString->Length - sizeof(WCHAR);\n\n    if (!IgnoreCase)\n    {\n        c = *sr2.Buffer++;\n\n        for (i = length1 - length2 + 1; i != 0; i--)\n        {\n            if (*sr1.Buffer++ == c && PhEqualStringRef(&sr1, &sr2, FALSE))\n            {\n                goto FoundUString;\n            }\n        }\n    }\n    else\n    {\n        c = RtlUpcaseUnicodeChar(*sr2.Buffer++);\n\n        for (i = length1 - length2 + 1; i != 0; i--)\n        {\n            if (RtlUpcaseUnicodeChar(*sr1.Buffer++) == c && PhEqualStringRef(&sr1, &sr2, TRUE))\n            {\n                goto FoundUString;\n            }\n        }\n    }\n\n    return -1;\nFoundUString:\n    return (ULONG_PTR)(sr1.Buffer - String->Buffer - 1);\n}\n\n/**\n * Splits a string.\n *\n * \\param Input The input string.\n * \\param Separator The character to split at.\n * \\param FirstPart A variable which receives the part of \\a Input before the separator. This may be\n * the same variable as \\a Input. If the separator is not found in \\a Input, this variable is set to\n * \\a Input.\n * \\param SecondPart A variable which recieves the part of \\a Input after the separator. This may be\n * the same variable as \\a Input. If the separator is not found in \\a Input, this variable is set to\n * an empty string.\n *\n * \\return TRUE if \\a Separator was found in \\a Input, otherwise FALSE.\n */\nBOOLEAN PhSplitStringRefAtChar(\n    _In_ PPH_STRINGREF Input,\n    _In_ WCHAR Separator,\n    _Out_ PPH_STRINGREF FirstPart,\n    _Out_ PPH_STRINGREF SecondPart\n    )\n{\n    PH_STRINGREF input;\n    ULONG_PTR index;\n\n    input = *Input; // get a copy of the input because FirstPart/SecondPart may alias Input\n    index = PhFindCharInStringRef(Input, Separator, FALSE);\n\n    if (index == -1)\n    {\n        // The separator was not found.\n\n        FirstPart->Buffer = Input->Buffer;\n        FirstPart->Length = Input->Length;\n        SecondPart->Buffer = NULL;\n        SecondPart->Length = 0;\n\n        return FALSE;\n    }\n\n    FirstPart->Buffer = input.Buffer;\n    FirstPart->Length = index * sizeof(WCHAR);\n    SecondPart->Buffer = (PWCHAR)PTR_ADD_OFFSET(input.Buffer, index * sizeof(WCHAR) + sizeof(WCHAR));\n    SecondPart->Length = input.Length - index * sizeof(WCHAR) - sizeof(WCHAR);\n\n    return TRUE;\n}\n\n/**\n * Splits a string at the last occurrence of a character.\n *\n * \\param Input The input string.\n * \\param Separator The character to split at.\n * \\param FirstPart A variable which receives the part of \\a Input before the separator. This may be\n * the same variable as \\a Input. If the separator is not found in \\a Input, this variable is set to\n * \\a Input.\n * \\param SecondPart A variable which recieves the part of \\a Input after the separator. This may be\n * the same variable as \\a Input. If the separator is not found in \\a Input, this variable is set to\n * an empty string.\n *\n * \\return TRUE if \\a Separator was found in \\a Input, otherwise FALSE.\n */\nBOOLEAN PhSplitStringRefAtLastChar(\n    _In_ PPH_STRINGREF Input,\n    _In_ WCHAR Separator,\n    _Out_ PPH_STRINGREF FirstPart,\n    _Out_ PPH_STRINGREF SecondPart\n    )\n{\n    PH_STRINGREF input;\n    ULONG_PTR index;\n\n    input = *Input; // get a copy of the input because FirstPart/SecondPart may alias Input\n    index = PhFindLastCharInStringRef(Input, Separator, FALSE);\n\n    if (index == -1)\n    {\n        // The separator was not found.\n\n        FirstPart->Buffer = Input->Buffer;\n        FirstPart->Length = Input->Length;\n        SecondPart->Buffer = NULL;\n        SecondPart->Length = 0;\n\n        return FALSE;\n    }\n\n    FirstPart->Buffer = input.Buffer;\n    FirstPart->Length = index * sizeof(WCHAR);\n    SecondPart->Buffer = (PWCHAR)PTR_ADD_OFFSET(input.Buffer, index * sizeof(WCHAR) + sizeof(WCHAR));\n    SecondPart->Length = input.Length - index * sizeof(WCHAR) - sizeof(WCHAR);\n\n    return TRUE;\n}\n\n/**\n * Splits a string.\n *\n * \\param Input The input string.\n * \\param Separator The string to split at.\n * \\param IgnoreCase TRUE to perform a case-insensitive search, otherwise FALSE.\n * \\param FirstPart A variable which receives the part of \\a Input before the separator. This may be\n * the same variable as \\a Input. If the separator is not found in \\a Input, this variable is set to\n * \\a Input.\n * \\param SecondPart A variable which recieves the part of \\a Input after the separator. This may be\n * the same variable as \\a Input. If the separator is not found in \\a Input, this variable is set to\n * an empty string.\n *\n * \\return TRUE if \\a Separator was found in \\a Input, otherwise FALSE.\n */\nBOOLEAN PhSplitStringRefAtString(\n    _In_ PPH_STRINGREF Input,\n    _In_ PPH_STRINGREF Separator,\n    _In_ BOOLEAN IgnoreCase,\n    _Out_ PPH_STRINGREF FirstPart,\n    _Out_ PPH_STRINGREF SecondPart\n    )\n{\n    PH_STRINGREF input;\n    ULONG_PTR index;\n\n    input = *Input; // get a copy of the input because FirstPart/SecondPart may alias Input\n    index = PhFindStringInStringRef(Input, Separator, IgnoreCase);\n\n    if (index == -1)\n    {\n        // The separator was not found.\n\n        FirstPart->Buffer = Input->Buffer;\n        FirstPart->Length = Input->Length;\n        SecondPart->Buffer = NULL;\n        SecondPart->Length = 0;\n\n        return FALSE;\n    }\n\n    FirstPart->Buffer = input.Buffer;\n    FirstPart->Length = index * sizeof(WCHAR);\n    SecondPart->Buffer = (PWCHAR)PTR_ADD_OFFSET(input.Buffer, index * sizeof(WCHAR) + Separator->Length);\n    SecondPart->Length = input.Length - index * sizeof(WCHAR) - Separator->Length;\n\n    return TRUE;\n}\n\n/**\n * Splits a string.\n *\n * \\param Input The input string.\n * \\param Separator The character set, string or range to split at.\n * \\param Flags A combination of flags.\n * \\li \\c PH_SPLIT_AT_CHAR_SET \\a Separator specifies a character set. \\a Input will be split at a\n * character which is contained in \\a Separator.\n * \\li \\c PH_SPLIT_AT_STRING \\a Separator specifies a string. \\a Input will be split an occurrence\n * of \\a Separator.\n * \\li \\c PH_SPLIT_AT_RANGE \\a Separator specifies a range. The \\a Buffer field contains a character\n * index cast to \\c PWSTR and the \\a Length field contains the length of the range, in bytes.\n * \\li \\c PH_SPLIT_CASE_INSENSITIVE Specifies a case-insensitive search.\n * \\li \\c PH_SPLIT_COMPLEMENT_CHAR_SET If used with \\c PH_SPLIT_AT_CHAR_SET, the separator is a\n * character which is not contained in \\a Separator.\n * \\li \\c PH_SPLIT_START_AT_END If used with \\c PH_SPLIT_AT_CHAR_SET, the search is performed\n * starting from the end of the string.\n * \\li \\c PH_SPLIT_CHAR_SET_IS_UPPERCASE If used with \\c PH_SPLIT_CASE_INSENSITIVE, specifies that\n * the character set in \\a Separator contains only uppercase characters.\n * \\param FirstPart A variable which receives the part of \\a Input before the separator. This may be\n * the same variable as \\a Input. If the separator is not found in \\a Input, this variable is set to\n * \\a Input.\n * \\param SecondPart A variable which recieves the part of \\a Input after the separator. This may be\n * the same variable as \\a Input. If the separator is not found in \\a Input, this variable is set to\n * an empty string.\n * \\param SeparatorPart A variable which receives the part of \\a Input that is the separator. If the\n * separator is not found in \\a Input, this variable is set to an empty string.\n *\n * \\return TRUE if a separator was found in \\a Input, otherwise FALSE.\n */\nBOOLEAN PhSplitStringRefEx(\n    _In_ PPH_STRINGREF Input,\n    _In_ PPH_STRINGREF Separator,\n    _In_ ULONG Flags,\n    _Out_ PPH_STRINGREF FirstPart,\n    _Out_ PPH_STRINGREF SecondPart,\n    _Out_opt_ PPH_STRINGREF SeparatorPart\n    )\n{\n    PH_STRINGREF input;\n    SIZE_T separatorIndex;\n    SIZE_T separatorLength;\n    PWCHAR charSet;\n    SIZE_T charSetCount;\n    BOOLEAN charSetTable[256];\n    BOOLEAN charSetTableComplete;\n    SIZE_T i;\n    SIZE_T j;\n    USHORT c;\n    PWCHAR s;\n    LONG_PTR direction;\n\n    input = *Input; // Get a copy of the input because FirstPart/SecondPart/SeparatorPart may alias Input\n\n    if (Flags & PH_SPLIT_AT_RANGE)\n    {\n        separatorIndex = (SIZE_T)Separator->Buffer;\n        separatorLength = Separator->Length;\n\n        if (separatorIndex == -1)\n            goto SeparatorNotFound;\n\n        goto SeparatorFound;\n    }\n    else if (Flags & PH_SPLIT_AT_STRING)\n    {\n        if (Flags & PH_SPLIT_START_AT_END)\n        {\n            // not implemented\n            goto SeparatorNotFound;\n        }\n\n        separatorIndex = PhFindStringInStringRef(Input, Separator, !!(Flags & PH_SPLIT_CASE_INSENSITIVE));\n\n        if (separatorIndex == -1)\n            goto SeparatorNotFound;\n\n        separatorLength = Separator->Length;\n        goto SeparatorFound;\n    }\n\n    // Special case for character sets with only one character.\n    if (!(Flags & PH_SPLIT_COMPLEMENT_CHAR_SET) && Separator->Length == sizeof(WCHAR))\n    {\n        if (!(Flags & PH_SPLIT_START_AT_END))\n            separatorIndex = PhFindCharInStringRef(Input, Separator->Buffer[0], !!(Flags & PH_SPLIT_CASE_INSENSITIVE));\n        else\n            separatorIndex = PhFindLastCharInStringRef(Input, Separator->Buffer[0], !!(Flags & PH_SPLIT_CASE_INSENSITIVE));\n\n        if (separatorIndex == -1)\n            goto SeparatorNotFound;\n\n        separatorLength = sizeof(WCHAR);\n        goto SeparatorFound;\n    }\n\n    if (input.Length == 0)\n        goto SeparatorNotFound;\n\n    // Build the character set lookup table.\n\n    charSet = Separator->Buffer;\n    charSetCount = Separator->Length / sizeof(WCHAR);\n    memset(charSetTable, 0, sizeof(charSetTable));\n    charSetTableComplete = TRUE;\n\n    for (i = 0; i < charSetCount; i++)\n    {\n        c = charSet[i];\n\n        if (Flags & PH_SPLIT_CASE_INSENSITIVE)\n            c = RtlUpcaseUnicodeChar(c);\n\n        charSetTable[c & 0xff] = TRUE;\n\n        if (c >= 256)\n            charSetTableComplete = FALSE;\n    }\n\n    // Perform the search.\n\n    i = input.Length / sizeof(WCHAR);\n    separatorLength = sizeof(WCHAR);\n\n    if (!(Flags & PH_SPLIT_START_AT_END))\n    {\n        s = input.Buffer;\n        direction = 1;\n    }\n    else\n    {\n        s = (PWCHAR)PTR_ADD_OFFSET(input.Buffer, input.Length - sizeof(WCHAR));\n        direction = -1;\n    }\n\n    do\n    {\n        c = *s;\n\n        if (Flags & PH_SPLIT_CASE_INSENSITIVE)\n            c = RtlUpcaseUnicodeChar(c);\n\n        if (c < 256 && charSetTableComplete)\n        {\n            if (!(Flags & PH_SPLIT_COMPLEMENT_CHAR_SET))\n            {\n                if (charSetTable[c])\n                    goto CharFound;\n            }\n            else\n            {\n                if (!charSetTable[c])\n                    goto CharFound;\n            }\n        }\n        else\n        {\n            if (!(Flags & PH_SPLIT_COMPLEMENT_CHAR_SET))\n            {\n                if (charSetTable[c & 0xff])\n                {\n                    if (!(Flags & PH_SPLIT_CASE_INSENSITIVE) || (Flags & PH_SPLIT_CHAR_SET_IS_UPPERCASE))\n                    {\n                        for (j = 0; j < charSetCount; j++)\n                        {\n                            if (charSet[j] == c)\n                                goto CharFound;\n                        }\n                    }\n                    else\n                    {\n                        for (j = 0; j < charSetCount; j++)\n                        {\n                            if (RtlUpcaseUnicodeChar(charSet[j]) == c)\n                                goto CharFound;\n                        }\n                    }\n                }\n            }\n            else\n            {\n                if (charSetTable[c & 0xff])\n                {\n                    if (!(Flags & PH_SPLIT_CASE_INSENSITIVE) || (Flags & PH_SPLIT_CHAR_SET_IS_UPPERCASE))\n                    {\n                        for (j = 0; j < charSetCount; j++)\n                        {\n                            if (charSet[j] == c)\n                                break;\n                        }\n                    }\n                    else\n                    {\n                        for (j = 0; j < charSetCount; j++)\n                        {\n                            if (RtlUpcaseUnicodeChar(charSet[j]) == c)\n                                break;\n                        }\n                    }\n\n                    if (j == charSetCount)\n                        goto CharFound;\n                }\n                else\n                {\n                    goto CharFound;\n                }\n            }\n        }\n\n        s += direction;\n    } while (--i != 0);\n\n    goto SeparatorNotFound;\n\nCharFound:\n    separatorIndex = s - input.Buffer;\n\nSeparatorFound:\n    FirstPart->Buffer = input.Buffer;\n    FirstPart->Length = separatorIndex * sizeof(WCHAR);\n    SecondPart->Buffer = (PWCHAR)PTR_ADD_OFFSET(input.Buffer, separatorIndex * sizeof(WCHAR) + separatorLength);\n    SecondPart->Length = input.Length - separatorIndex * sizeof(WCHAR) - separatorLength;\n\n    if (SeparatorPart)\n    {\n        SeparatorPart->Buffer = input.Buffer + separatorIndex;\n        SeparatorPart->Length = separatorLength;\n    }\n\n    return TRUE;\n\nSeparatorNotFound:\n    FirstPart->Buffer = input.Buffer;\n    FirstPart->Length = input.Length;\n    SecondPart->Buffer = NULL;\n    SecondPart->Length = 0;\n\n    if (SeparatorPart)\n    {\n        SeparatorPart->Buffer = NULL;\n        SeparatorPart->Length = 0;\n    }\n\n    return FALSE;\n}\n\nVOID PhTrimStringRef(\n    _Inout_ PPH_STRINGREF String,\n    _In_ PPH_STRINGREF CharSet,\n    _In_ ULONG Flags\n    )\n{\n    PWCHAR charSet;\n    SIZE_T charSetCount;\n    BOOLEAN charSetTable[256];\n    BOOLEAN charSetTableComplete;\n    SIZE_T i;\n    SIZE_T j;\n    USHORT c;\n    SIZE_T trimCount;\n    SIZE_T count;\n    PWCHAR s;\n\n    if (String->Length == 0 || CharSet->Length == 0)\n        return;\n\n    if (CharSet->Length == sizeof(WCHAR))\n    {\n        c = CharSet->Buffer[0];\n\n        if (!(Flags & PH_TRIM_END_ONLY))\n        {\n            trimCount = 0;\n            count = String->Length / sizeof(WCHAR);\n            s = String->Buffer;\n\n            while (count-- != 0)\n            {\n                if (*s++ != c)\n                    break;\n\n                trimCount++;\n            }\n\n            PhSkipStringRef(String, trimCount * sizeof(WCHAR));\n        }\n\n        if (!(Flags & PH_TRIM_START_ONLY))\n        {\n            trimCount = 0;\n            count = String->Length / sizeof(WCHAR);\n            s = (PWCHAR)PTR_ADD_OFFSET(String->Buffer, String->Length - sizeof(WCHAR));\n\n            while (count-- != 0)\n            {\n                if (*s-- != c)\n                    break;\n\n                trimCount++;\n            }\n\n            String->Length -= trimCount * sizeof(WCHAR);\n        }\n\n        return;\n    }\n\n    // Build the character set lookup table.\n\n    charSet = CharSet->Buffer;\n    charSetCount = CharSet->Length / sizeof(WCHAR);\n    memset(charSetTable, 0, sizeof(charSetTable));\n    charSetTableComplete = TRUE;\n\n    for (i = 0; i < charSetCount; i++)\n    {\n        c = charSet[i];\n        charSetTable[c & 0xff] = TRUE;\n\n        if (c >= 256)\n            charSetTableComplete = FALSE;\n    }\n\n    // Trim the string.\n\n    if (!(Flags & PH_TRIM_END_ONLY))\n    {\n        trimCount = 0;\n        count = String->Length / sizeof(WCHAR);\n        s = String->Buffer;\n\n        while (count-- != 0)\n        {\n            c = *s++;\n\n            if (!charSetTable[c & 0xff])\n                break;\n\n            if (!charSetTableComplete)\n            {\n                for (j = 0; j < charSetCount; j++)\n                {\n                    if (charSet[j] == c)\n                        goto CharFound;\n                }\n\n                break;\n            }\n\nCharFound:\n            trimCount++;\n        }\n\n        PhSkipStringRef(String, trimCount * sizeof(WCHAR));\n    }\n\n    if (!(Flags & PH_TRIM_START_ONLY))\n    {\n        trimCount = 0;\n        count = String->Length / sizeof(WCHAR);\n        s = (PWCHAR)PTR_ADD_OFFSET(String->Buffer, String->Length - sizeof(WCHAR));\n\n        while (count-- != 0)\n        {\n            c = *s--;\n\n            if (!charSetTable[c & 0xff])\n                break;\n\n            if (!charSetTableComplete)\n            {\n                for (j = 0; j < charSetCount; j++)\n                {\n                    if (charSet[j] == c)\n                        goto CharFound2;\n                }\n\n                break;\n            }\n\nCharFound2:\n            trimCount++;\n        }\n\n        String->Length -= trimCount * sizeof(WCHAR);\n    }\n}\n\n/**\n * Creates a string object from an existing null-terminated string.\n *\n * \\param Buffer A null-terminated Unicode string.\n */\nPPH_STRING PhCreateString(\n    _In_ PWSTR Buffer\n    )\n{\n    return PhCreateStringEx(Buffer, wcslen(Buffer) * sizeof(WCHAR));\n}\n\n/**\n * Creates a string object using a specified length.\n *\n * \\param Buffer A null-terminated Unicode string.\n * \\param Length The length, in bytes, of the string.\n */\nPPH_STRING PhCreateStringEx(\n    _In_opt_ PWCHAR Buffer,\n    _In_ SIZE_T Length\n    )\n{\n    PPH_STRING string;\n\n    string = PhCreateObject(\n        FIELD_OFFSET(PH_STRING, Data) + Length + sizeof(WCHAR), // Null terminator\n        PhStringType\n        );\n\n    assert(!(Length & 1));\n    string->Length = Length;\n    string->Buffer = string->Data;\n    *(PWCHAR)PTR_ADD_OFFSET(string->Buffer, Length) = 0;\n\n    if (Buffer)\n    {\n        memcpy(string->Buffer, Buffer, Length);\n    }\n\n    return string;\n}\n\n/**\n * Obtains a reference to a zero-length string.\n */\nPPH_STRING PhReferenceEmptyString(\n    VOID\n    )\n{\n    PPH_STRING string;\n    PPH_STRING newString;\n\n    string = PhSharedEmptyString;\n\n    if (!string)\n    {\n        newString = PhCreateStringEx(NULL, 0);\n\n        string = _InterlockedCompareExchangePointer(\n            &PhSharedEmptyString,\n            newString,\n            NULL\n            );\n\n        if (!string)\n        {\n            string = newString; // success\n        }\n        else\n        {\n            PhDereferenceObject(newString);\n        }\n    }\n\n    return PhReferenceObject(string);\n}\n\n/**\n * Concatenates multiple strings.\n *\n * \\param Count The number of strings to concatenate.\n */\nPPH_STRING PhConcatStrings(\n    _In_ ULONG Count,\n    ...\n    )\n{\n    va_list argptr;\n\n    va_start(argptr, Count);\n\n    return PhConcatStrings_V(Count, argptr);\n}\n\n/**\n * Concatenates multiple strings.\n *\n * \\param Count The number of strings to concatenate.\n * \\param ArgPtr A pointer to an array of strings.\n */\nPPH_STRING PhConcatStrings_V(\n    _In_ ULONG Count,\n    _In_ va_list ArgPtr\n    )\n{\n    va_list argptr;\n    ULONG i;\n    SIZE_T totalLength = 0;\n    SIZE_T stringLength;\n    SIZE_T cachedLengths[PH_CONCAT_STRINGS_LENGTH_CACHE_SIZE];\n    PWSTR arg;\n    PPH_STRING string;\n\n    // Compute the total length, in bytes, of the strings.\n\n    argptr = ArgPtr;\n\n    for (i = 0; i < Count; i++)\n    {\n        arg = va_arg(argptr, PWSTR);\n        stringLength = PhCountStringZ(arg) * sizeof(WCHAR);\n        totalLength += stringLength;\n\n        if (i < PH_CONCAT_STRINGS_LENGTH_CACHE_SIZE)\n            cachedLengths[i] = stringLength;\n    }\n\n    // Create the string.\n\n    string = PhCreateStringEx(NULL, totalLength);\n    totalLength = 0;\n\n    // Append the strings one by one.\n\n    argptr = ArgPtr;\n\n    for (i = 0; i < Count; i++)\n    {\n        arg = va_arg(argptr, PWSTR);\n\n        if (i < PH_CONCAT_STRINGS_LENGTH_CACHE_SIZE)\n            stringLength = cachedLengths[i];\n        else\n            stringLength = PhCountStringZ(arg) * sizeof(WCHAR);\n\n        memcpy(\n            PTR_ADD_OFFSET(string->Buffer, totalLength),\n            arg,\n            stringLength\n            );\n        totalLength += stringLength;\n    }\n\n    return string;\n}\n\n/**\n * Concatenates two strings.\n *\n * \\param String1 The first string.\n * \\param String2 The second string.\n */\nPPH_STRING PhConcatStrings2(\n    _In_ PWSTR String1,\n    _In_ PWSTR String2\n    )\n{\n    PPH_STRING string;\n    SIZE_T length1;\n    SIZE_T length2;\n\n    length1 = PhCountStringZ(String1) * sizeof(WCHAR);\n    length2 = PhCountStringZ(String2) * sizeof(WCHAR);\n    string = PhCreateStringEx(NULL, length1 + length2);\n    memcpy(\n        string->Buffer,\n        String1,\n        length1\n        );\n    memcpy(\n        PTR_ADD_OFFSET(string->Buffer, length1),\n        String2,\n        length2\n        );\n\n    return string;\n}\n\n/**\n * Concatenates two strings.\n *\n * \\param String1 The first string.\n * \\param String2 The second string.\n */\nPPH_STRING PhConcatStringRef2(\n    _In_ PPH_STRINGREF String1,\n    _In_ PPH_STRINGREF String2\n    )\n{\n    PPH_STRING string;\n\n    assert(!(String1->Length & 1));\n    assert(!(String2->Length & 1));\n\n    string = PhCreateStringEx(NULL, String1->Length + String2->Length);\n    memcpy(string->Buffer, String1->Buffer, String1->Length);\n    memcpy(PTR_ADD_OFFSET(string->Buffer, String1->Length), String2->Buffer, String2->Length);\n\n    return string;\n}\n\n/**\n * Concatenates three strings.\n *\n * \\param String1 The first string.\n * \\param String2 The second string.\n * \\param String3 The third string.\n */\nPPH_STRING PhConcatStringRef3(\n    _In_ PPH_STRINGREF String1,\n    _In_ PPH_STRINGREF String2,\n    _In_ PPH_STRINGREF String3\n    )\n{\n    PPH_STRING string;\n    PCHAR buffer;\n\n    assert(!(String1->Length & 1));\n    assert(!(String2->Length & 1));\n    assert(!(String3->Length & 1));\n\n    string = PhCreateStringEx(NULL, String1->Length + String2->Length + String3->Length);\n\n    buffer = (PCHAR)string->Buffer;\n    memcpy(buffer, String1->Buffer, String1->Length);\n\n    buffer += String1->Length;\n    memcpy(buffer, String2->Buffer, String2->Length);\n\n    buffer += String2->Length;\n    memcpy(buffer, String3->Buffer, String3->Length);\n\n    return string;\n}\n\n/**\n * Creates a string using format specifiers.\n *\n * \\param Format The format-control string.\n */\nPPH_STRING PhFormatString(\n    _In_ _Printf_format_string_ PWSTR Format,\n    ...\n    )\n{\n    va_list argptr;\n\n    va_start(argptr, Format);\n\n    return PhFormatString_V(Format, argptr);\n}\n\n/**\n * Creates a string using format specifiers.\n *\n * \\param Format The format-control string.\n * \\param ArgPtr A pointer to the list of arguments.\n */\nPPH_STRING PhFormatString_V(\n    _In_ _Printf_format_string_ PWSTR Format,\n    _In_ va_list ArgPtr\n    )\n{\n    PPH_STRING string;\n    int length;\n\n    length = _vscwprintf(Format, ArgPtr);\n\n    if (length == -1)\n        return NULL;\n\n    string = PhCreateStringEx(NULL, length * sizeof(WCHAR));\n    _vsnwprintf(string->Buffer, length, Format, ArgPtr);\n\n    return string;\n}\n\n/**\n * Creates a bytes object from an existing null-terminated string of bytes.\n *\n * \\param Buffer A null-terminated byte string.\n */\nPPH_BYTES PhCreateBytes(\n    _In_ PSTR Buffer\n    )\n{\n    return PhCreateBytesEx(Buffer, strlen(Buffer) * sizeof(CHAR));\n}\n\n/**\n * Creates a bytes object.\n *\n * \\param Buffer An array of bytes.\n * \\param Length The length of \\a Buffer, in bytes.\n */\nPPH_BYTES PhCreateBytesEx(\n    _In_opt_ PCHAR Buffer,\n    _In_ SIZE_T Length\n    )\n{\n    PPH_BYTES bytes;\n\n    bytes = PhCreateObject(\n        FIELD_OFFSET(PH_BYTES, Data) + Length + sizeof(CHAR), // Null terminator for compatibility\n        PhBytesType\n        );\n\n    bytes->Length = Length;\n    bytes->Buffer = bytes->Data;\n    bytes->Buffer[Length] = 0;\n\n    if (Buffer)\n    {\n        memcpy(bytes->Buffer, Buffer, Length);\n    }\n\n    return bytes;\n}\n\nBOOLEAN PhWriteUnicodeDecoder(\n    _Inout_ PPH_UNICODE_DECODER Decoder,\n    _In_ ULONG CodeUnit\n    )\n{\n    switch (Decoder->Encoding)\n    {\n    case PH_UNICODE_UTF8:\n        if (Decoder->InputCount >= 4)\n            return FALSE;\n        Decoder->u.Utf8.Input[Decoder->InputCount] = (UCHAR)CodeUnit;\n        Decoder->InputCount++;\n        return TRUE;\n    case PH_UNICODE_UTF16:\n        if (Decoder->InputCount >= 2)\n            return FALSE;\n        Decoder->u.Utf16.Input[Decoder->InputCount] = (USHORT)CodeUnit;\n        Decoder->InputCount++;\n        return TRUE;\n    case PH_UNICODE_UTF32:\n        if (Decoder->InputCount >= 1)\n            return FALSE;\n        Decoder->u.Utf32.Input = CodeUnit;\n        Decoder->InputCount = 1;\n        return TRUE;\n    default:\n        PhRaiseStatus(STATUS_UNSUCCESSFUL);\n    }\n}\n\nBOOLEAN PhpReadUnicodeDecoder(\n    _Inout_ PPH_UNICODE_DECODER Decoder,\n    _Out_ PULONG CodeUnit\n    )\n{\n    switch (Decoder->Encoding)\n    {\n    case PH_UNICODE_UTF8:\n        if (Decoder->InputCount == 0)\n            return FALSE;\n        *CodeUnit = Decoder->u.Utf8.Input[0];\n        Decoder->u.Utf8.Input[0] = Decoder->u.Utf8.Input[1];\n        Decoder->u.Utf8.Input[1] = Decoder->u.Utf8.Input[2];\n        Decoder->u.Utf8.Input[2] = Decoder->u.Utf8.Input[3];\n        Decoder->InputCount--;\n        return TRUE;\n    case PH_UNICODE_UTF16:\n        if (Decoder->InputCount == 0)\n            return FALSE;\n        *CodeUnit = Decoder->u.Utf16.Input[0];\n        Decoder->u.Utf16.Input[0] = Decoder->u.Utf16.Input[1];\n        Decoder->InputCount--;\n        return TRUE;\n    case PH_UNICODE_UTF32:\n        if (Decoder->InputCount == 0)\n            return FALSE;\n        *CodeUnit = Decoder->u.Utf32.Input;\n        Decoder->InputCount--;\n        return TRUE;\n    default:\n        PhRaiseStatus(STATUS_UNSUCCESSFUL);\n    }\n}\n\nVOID PhpUnreadUnicodeDecoder(\n    _Inout_ PPH_UNICODE_DECODER Decoder,\n    _In_ ULONG CodeUnit\n    )\n{\n    switch (Decoder->Encoding)\n    {\n    case PH_UNICODE_UTF8:\n        if (Decoder->InputCount >= 4)\n            PhRaiseStatus(STATUS_UNSUCCESSFUL);\n        Decoder->u.Utf8.Input[3] = Decoder->u.Utf8.Input[2];\n        Decoder->u.Utf8.Input[2] = Decoder->u.Utf8.Input[1];\n        Decoder->u.Utf8.Input[1] = Decoder->u.Utf8.Input[0];\n        Decoder->u.Utf8.Input[0] = (UCHAR)CodeUnit;\n        Decoder->InputCount++;\n        break;\n    case PH_UNICODE_UTF16:\n        if (Decoder->InputCount >= 2)\n            PhRaiseStatus(STATUS_UNSUCCESSFUL);\n        Decoder->u.Utf16.Input[1] = Decoder->u.Utf16.Input[0];\n        Decoder->u.Utf16.Input[0] = (USHORT)CodeUnit;\n        Decoder->InputCount++;\n        break;\n    case PH_UNICODE_UTF32:\n        if (Decoder->InputCount >= 1)\n            PhRaiseStatus(STATUS_UNSUCCESSFUL);\n        Decoder->u.Utf32.Input = CodeUnit;\n        Decoder->InputCount = 1;\n        break;\n    default:\n        PhRaiseStatus(STATUS_UNSUCCESSFUL);\n    }\n}\n\nBOOLEAN PhpDecodeUtf8Error(\n    _Inout_ PPH_UNICODE_DECODER Decoder,\n    _Out_ PULONG CodePoint,\n    _In_ ULONG Which\n    )\n{\n    if (Which >= 4)\n        PhpUnreadUnicodeDecoder(Decoder, Decoder->u.Utf8.CodeUnit4);\n    if (Which >= 3)\n        PhpUnreadUnicodeDecoder(Decoder, Decoder->u.Utf8.CodeUnit3);\n    if (Which >= 2)\n        PhpUnreadUnicodeDecoder(Decoder, Decoder->u.Utf8.CodeUnit2);\n\n    *CodePoint = (ULONG)Decoder->u.Utf8.CodeUnit1 + 0xdc00;\n    Decoder->State = 0;\n\n    return TRUE;\n}\n\nBOOLEAN PhDecodeUnicodeDecoder(\n    _Inout_ PPH_UNICODE_DECODER Decoder,\n    _Out_ PULONG CodePoint\n    )\n{\n    ULONG codeUnit;\n\n    while (TRUE)\n    {\n        switch (Decoder->Encoding)\n        {\n        case PH_UNICODE_UTF8:\n            if (!PhpReadUnicodeDecoder(Decoder, &codeUnit))\n                return FALSE;\n\n            switch (Decoder->State)\n            {\n            case 0:\n                Decoder->u.Utf8.CodeUnit1 = (UCHAR)codeUnit;\n\n                if (codeUnit < 0x80)\n                {\n                    *CodePoint = codeUnit;\n                    return TRUE;\n                }\n                else if (codeUnit < 0xc2)\n                {\n                    return PhpDecodeUtf8Error(Decoder, CodePoint, 1);\n                }\n                else if (codeUnit < 0xe0)\n                {\n                    Decoder->State = 1; // 2 byte sequence\n                    continue;\n                }\n                else if (codeUnit < 0xf0)\n                {\n                    Decoder->State = 2; // 3 byte sequence\n                    continue;\n                }\n                else if (codeUnit < 0xf5)\n                {\n                    Decoder->State = 3; // 4 byte sequence\n                    continue;\n                }\n                else\n                {\n                    return PhpDecodeUtf8Error(Decoder, CodePoint, 1);\n                }\n\n                break;\n            case 1: // 2 byte sequence\n                Decoder->u.Utf8.CodeUnit2 = (UCHAR)codeUnit;\n\n                if ((codeUnit & 0xc0) == 0x80)\n                {\n                    *CodePoint = ((ULONG)Decoder->u.Utf8.CodeUnit1 << 6) + codeUnit - 0x3080;\n                    Decoder->State = 0;\n                    return TRUE;\n                }\n                else\n                {\n                    return PhpDecodeUtf8Error(Decoder, CodePoint, 2);\n                }\n\n                break;\n            case 2: // 3 byte sequence (1)\n                Decoder->u.Utf8.CodeUnit2 = (UCHAR)codeUnit;\n\n                if (((codeUnit & 0xc0) == 0x80) &&\n                    (Decoder->u.Utf8.CodeUnit1 != 0xe0 || codeUnit >= 0xa0))\n                {\n                    Decoder->State = 4; // 3 byte sequence (2)\n                    continue;\n                }\n                else\n                {\n                    return PhpDecodeUtf8Error(Decoder, CodePoint, 2);\n                }\n\n                break;\n            case 3: // 4 byte sequence (1)\n                Decoder->u.Utf8.CodeUnit2 = (UCHAR)codeUnit;\n\n                if (((codeUnit & 0xc0) == 0x80) &&\n                    (Decoder->u.Utf8.CodeUnit1 != 0xf0 || codeUnit >= 0x90) &&\n                    (Decoder->u.Utf8.CodeUnit1 != 0xf4 || codeUnit < 0x90))\n                {\n                    Decoder->State = 5; // 4 byte sequence (2)\n                    continue;\n                }\n                else\n                {\n                    return PhpDecodeUtf8Error(Decoder, CodePoint, 2);\n                }\n\n                break;\n            case 4: // 3 byte sequence (2)\n                Decoder->u.Utf8.CodeUnit3 = (UCHAR)codeUnit;\n\n                if ((codeUnit & 0xc0) == 0x80)\n                {\n                    *CodePoint =\n                        ((ULONG)Decoder->u.Utf8.CodeUnit1 << 12) +\n                        ((ULONG)Decoder->u.Utf8.CodeUnit2 << 6) +\n                        codeUnit - 0xe2080;\n                    Decoder->State = 0;\n                    return TRUE;\n                }\n                else\n                {\n                    return PhpDecodeUtf8Error(Decoder, CodePoint, 3);\n                }\n\n                break;\n            case 5: // 4 byte sequence (2)\n                Decoder->u.Utf8.CodeUnit3 = (UCHAR)codeUnit;\n\n                if ((codeUnit & 0xc0) == 0x80)\n                {\n                    Decoder->State = 6; // 4 byte sequence (3)\n                    continue;\n                }\n                else\n                {\n                    return PhpDecodeUtf8Error(Decoder, CodePoint, 3);\n                }\n\n                break;\n            case 6: // 4 byte sequence (3)\n                Decoder->u.Utf8.CodeUnit4 = (UCHAR)codeUnit;\n\n                if ((codeUnit & 0xc0) == 0x80)\n                {\n                    *CodePoint =\n                        ((ULONG)Decoder->u.Utf8.CodeUnit1 << 18) +\n                        ((ULONG)Decoder->u.Utf8.CodeUnit2 << 12) +\n                        ((ULONG)Decoder->u.Utf8.CodeUnit3 << 6) +\n                        codeUnit - 0x3c82080;\n                    Decoder->State = 0;\n                    return TRUE;\n                }\n                else\n                {\n                    return PhpDecodeUtf8Error(Decoder, CodePoint, 4);\n                }\n\n                break;\n            }\n\n            return FALSE;\n        case PH_UNICODE_UTF16:\n            if (!PhpReadUnicodeDecoder(Decoder, &codeUnit))\n                return FALSE;\n\n            switch (Decoder->State)\n            {\n            case 0:\n                if (PH_UNICODE_UTF16_IS_HIGH_SURROGATE(codeUnit))\n                {\n                    Decoder->u.Utf16.CodeUnit = (USHORT)codeUnit;\n                    Decoder->State = 1;\n                    continue;\n                }\n                else\n                {\n                    *CodePoint = codeUnit;\n                    return TRUE;\n                }\n                break;\n            case 1:\n                if (PH_UNICODE_UTF16_IS_LOW_SURROGATE(codeUnit))\n                {\n                    *CodePoint = PH_UNICODE_UTF16_TO_CODE_POINT(Decoder->u.Utf16.CodeUnit, codeUnit);\n                    Decoder->State = 0;\n                    return TRUE;\n                }\n                else\n                {\n                    *CodePoint = Decoder->u.Utf16.CodeUnit;\n                    PhpUnreadUnicodeDecoder(Decoder, codeUnit);\n                    Decoder->State = 0;\n                    return TRUE;\n                }\n                break;\n            }\n\n            return FALSE;\n        case PH_UNICODE_UTF32:\n            if (PhpReadUnicodeDecoder(Decoder, CodePoint))\n                return TRUE;\n            return FALSE;\n        default:\n            return FALSE;\n        }\n    }\n}\n\nBOOLEAN PhEncodeUnicode(\n    _In_ UCHAR Encoding,\n    _In_ ULONG CodePoint,\n    _Out_opt_ PVOID CodeUnits,\n    _Out_ PULONG NumberOfCodeUnits\n    )\n{\n    switch (Encoding)\n    {\n    case PH_UNICODE_UTF8:\n        {\n            PUCHAR codeUnits = CodeUnits;\n\n            if (CodePoint < 0x80)\n            {\n                *NumberOfCodeUnits = 1;\n\n                if (codeUnits)\n                    codeUnits[0] = (UCHAR)CodePoint;\n            }\n            else if (CodePoint <= 0x7ff)\n            {\n                *NumberOfCodeUnits = 2;\n\n                if (codeUnits)\n                {\n                    codeUnits[0] = (UCHAR)(CodePoint >> 6) + 0xc0;\n                    codeUnits[1] = (UCHAR)(CodePoint & 0x3f) + 0x80;\n                }\n            }\n            else if (CodePoint <= 0xffff)\n            {\n                *NumberOfCodeUnits = 3;\n\n                if (codeUnits)\n                {\n                    codeUnits[0] = (UCHAR)(CodePoint >> 12) + 0xe0;\n                    codeUnits[1] = (UCHAR)((CodePoint >> 6) & 0x3f) + 0x80;\n                    codeUnits[2] = (UCHAR)(CodePoint & 0x3f) + 0x80;\n                }\n            }\n            else if (CodePoint <= PH_UNICODE_MAX_CODE_POINT)\n            {\n                *NumberOfCodeUnits = 4;\n\n                if (codeUnits)\n                {\n                    codeUnits[0] = (UCHAR)(CodePoint >> 18) + 0xf0;\n                    codeUnits[1] = (UCHAR)((CodePoint >> 12) & 0x3f) + 0x80;\n                    codeUnits[2] = (UCHAR)((CodePoint >> 6) & 0x3f) + 0x80;\n                    codeUnits[3] = (UCHAR)(CodePoint & 0x3f) + 0x80;\n                }\n            }\n            else\n            {\n                return FALSE;\n            }\n        }\n        return TRUE;\n    case PH_UNICODE_UTF16:\n        {\n            PUSHORT codeUnits = CodeUnits;\n\n            if (CodePoint < 0x10000)\n            {\n                *NumberOfCodeUnits = 1;\n\n                if (codeUnits)\n                    codeUnits[0] = (USHORT)CodePoint;\n            }\n            else if (CodePoint <= PH_UNICODE_MAX_CODE_POINT)\n            {\n                *NumberOfCodeUnits = 2;\n\n                if (codeUnits)\n                {\n                    codeUnits[0] = PH_UNICODE_UTF16_TO_HIGH_SURROGATE(CodePoint);\n                    codeUnits[1] = PH_UNICODE_UTF16_TO_LOW_SURROGATE(CodePoint);\n                }\n            }\n            else\n            {\n                return FALSE;\n            }\n        }\n        return TRUE;\n    case PH_UNICODE_UTF32:\n        *NumberOfCodeUnits = 1;\n        if (CodeUnits)\n            *(PULONG)CodeUnits = CodePoint;\n        return TRUE;\n    default:\n        return FALSE;\n    }\n}\n\n/**\n * Converts an ASCII string to a UTF-16 string by zero-extending each byte.\n *\n * \\param Input The original ASCII string.\n * \\param InputLength The length of \\a Input.\n * \\param Output A buffer which will contain the converted string.\n */\nVOID PhZeroExtendToUtf16Buffer(\n    _In_reads_bytes_(InputLength) PCH Input,\n    _In_ SIZE_T InputLength,\n    _Out_writes_bytes_(InputLength * sizeof(WCHAR)) PWCH Output\n    )\n{\n    SIZE_T inputLength;\n\n    inputLength = InputLength & -4;\n\n    if (inputLength)\n    {\n        do\n        {\n            Output[0] = C_1uTo2(Input[0]);\n            Output[1] = C_1uTo2(Input[1]);\n            Output[2] = C_1uTo2(Input[2]);\n            Output[3] = C_1uTo2(Input[3]);\n            Input += 4;\n            Output += 4;\n            inputLength -= 4;\n        } while (inputLength != 0);\n    }\n\n    switch (InputLength & 3)\n    {\n    case 3:\n        *Output++ = C_1uTo2(*Input++);\n    case 2:\n        *Output++ = C_1uTo2(*Input++);\n    case 1:\n        *Output++ = C_1uTo2(*Input++);\n    }\n}\n\nPPH_STRING PhZeroExtendToUtf16Ex(\n    _In_reads_bytes_(InputLength) PCH Input,\n    _In_ SIZE_T InputLength\n    )\n{\n    PPH_STRING string;\n\n    string = PhCreateStringEx(NULL, InputLength * sizeof(WCHAR));\n    PhZeroExtendToUtf16Buffer(Input, InputLength, string->Buffer);\n\n    return string;\n}\n\nPPH_BYTES PhConvertUtf16ToAsciiEx(\n    _In_ PWCH Buffer,\n    _In_ SIZE_T Length,\n    _In_opt_ CHAR Replacement\n    )\n{\n    PPH_BYTES bytes;\n    PH_UNICODE_DECODER decoder;\n    PWCH in;\n    SIZE_T inRemaining;\n    PCH out;\n    SIZE_T outLength;\n    ULONG codePoint;\n\n    bytes = PhCreateBytesEx(NULL, Length / sizeof(WCHAR));\n    PhInitializeUnicodeDecoder(&decoder, PH_UNICODE_UTF16);\n    in = Buffer;\n    inRemaining = Length / sizeof(WCHAR);\n    out = bytes->Buffer;\n    outLength = 0;\n\n    while (inRemaining != 0)\n    {\n        PhWriteUnicodeDecoder(&decoder, (USHORT)*in);\n        in++;\n        inRemaining--;\n\n        while (PhDecodeUnicodeDecoder(&decoder, &codePoint))\n        {\n            if (codePoint < 0x80)\n            {\n                *out++ = (CHAR)codePoint;\n                outLength++;\n            }\n            else if (Replacement)\n            {\n                *out++ = Replacement;\n                outLength++;\n            }\n        }\n    }\n\n    bytes->Length = outLength;\n    bytes->Buffer[outLength] = 0;\n\n    return bytes;\n}\n\n/**\n * Creates a string object from an existing null-terminated multi-byte string.\n *\n * \\param Buffer A null-terminated multi-byte string.\n */\nPPH_STRING PhConvertMultiByteToUtf16(\n    _In_ PSTR Buffer\n    )\n{\n    return PhConvertMultiByteToUtf16Ex(\n        Buffer,\n        strlen(Buffer)\n        );\n}\n\n/**\n * Creates a string object from an existing null-terminated multi-byte string.\n *\n * \\param Buffer A null-terminated multi-byte string.\n * \\param Length The number of bytes to use.\n */\nPPH_STRING PhConvertMultiByteToUtf16Ex(\n    _In_ PCHAR Buffer,\n    _In_ SIZE_T Length\n    )\n{\n    NTSTATUS status;\n    PPH_STRING string;\n    ULONG unicodeBytes;\n\n    status = RtlMultiByteToUnicodeSize(\n        &unicodeBytes,\n        Buffer,\n        (ULONG)Length\n        );\n\n    if (!NT_SUCCESS(status))\n        return NULL;\n\n    string = PhCreateStringEx(NULL, unicodeBytes);\n    status = RtlMultiByteToUnicodeN(\n        string->Buffer,\n        (ULONG)string->Length,\n        NULL,\n        Buffer,\n        (ULONG)Length\n        );\n\n    if (!NT_SUCCESS(status))\n    {\n        PhDereferenceObject(string);\n        return NULL;\n    }\n\n    return string;\n}\n\n/**\n * Creates a multi-byte string from an existing null-terminated UTF-16 string.\n *\n * \\param Buffer A null-terminated UTF-16 string.\n */\nPPH_BYTES PhConvertUtf16ToMultiByte(\n    _In_ PWSTR Buffer\n    )\n{\n    return PhConvertUtf16ToMultiByteEx(\n        Buffer,\n        PhCountStringZ(Buffer) * sizeof(WCHAR)\n        );\n}\n\n/**\n * Creates a multi-byte string from an existing null-terminated UTF-16 string.\n *\n * \\param Buffer A null-terminated UTF-16 string.\n * \\param Length The number of bytes to use.\n */\nPPH_BYTES PhConvertUtf16ToMultiByteEx(\n    _In_ PWCHAR Buffer,\n    _In_ SIZE_T Length\n    )\n{\n    NTSTATUS status;\n    PPH_BYTES bytes;\n    ULONG multiByteLength;\n\n    status = RtlUnicodeToMultiByteSize(\n        &multiByteLength,\n        Buffer,\n        (ULONG)Length\n        );\n\n    if (!NT_SUCCESS(status))\n        return NULL;\n\n    bytes = PhCreateBytesEx(NULL, multiByteLength);\n    status = RtlUnicodeToMultiByteN(\n        bytes->Buffer,\n        (ULONG)bytes->Length,\n        NULL,\n        Buffer,\n        (ULONG)Length\n        );\n\n    if (!NT_SUCCESS(status))\n    {\n        PhDereferenceObject(bytes);\n        return NULL;\n    }\n\n    return bytes;\n}\n\nBOOLEAN PhConvertUtf8ToUtf16Size(\n    _Out_ PSIZE_T BytesInUtf16String,\n    _In_reads_bytes_(BytesInUtf8String) PCH Utf8String,\n    _In_ SIZE_T BytesInUtf8String\n    )\n{\n    BOOLEAN result;\n    PH_UNICODE_DECODER decoder;\n    PCH in;\n    SIZE_T inRemaining;\n    SIZE_T bytesInUtf16String;\n    ULONG codePoint;\n    ULONG numberOfCodeUnits;\n\n    result = TRUE;\n    PhInitializeUnicodeDecoder(&decoder, PH_UNICODE_UTF8);\n    in = Utf8String;\n    inRemaining = BytesInUtf8String;\n    bytesInUtf16String = 0;\n\n    while (inRemaining != 0)\n    {\n        PhWriteUnicodeDecoder(&decoder, (UCHAR)*in);\n        in++;\n        inRemaining--;\n\n        while (PhDecodeUnicodeDecoder(&decoder, &codePoint))\n        {\n            if (PhEncodeUnicode(PH_UNICODE_UTF16, codePoint, NULL, &numberOfCodeUnits))\n                bytesInUtf16String += numberOfCodeUnits * sizeof(WCHAR);\n            else\n                result = FALSE;\n        }\n    }\n\n    *BytesInUtf16String = bytesInUtf16String;\n\n    return result;\n}\n\nBOOLEAN PhConvertUtf8ToUtf16Buffer(\n    _Out_writes_bytes_to_(MaxBytesInUtf16String, *BytesInUtf16String) PWCH Utf16String,\n    _In_ SIZE_T MaxBytesInUtf16String,\n    _Out_opt_ PSIZE_T BytesInUtf16String,\n    _In_reads_bytes_(BytesInUtf8String) PCH Utf8String,\n    _In_ SIZE_T BytesInUtf8String\n    )\n{\n    BOOLEAN result;\n    PH_UNICODE_DECODER decoder;\n    PCH in;\n    SIZE_T inRemaining;\n    PWCH out;\n    SIZE_T outRemaining;\n    SIZE_T bytesInUtf16String;\n    ULONG codePoint;\n    USHORT codeUnits[2];\n    ULONG numberOfCodeUnits;\n\n    result = TRUE;\n    PhInitializeUnicodeDecoder(&decoder, PH_UNICODE_UTF8);\n    in = Utf8String;\n    inRemaining = BytesInUtf8String;\n    out = Utf16String;\n    outRemaining = MaxBytesInUtf16String / sizeof(WCHAR);\n    bytesInUtf16String = 0;\n\n    while (inRemaining != 0)\n    {\n        PhWriteUnicodeDecoder(&decoder, (UCHAR)*in);\n        in++;\n        inRemaining--;\n\n        while (PhDecodeUnicodeDecoder(&decoder, &codePoint))\n        {\n            if (PhEncodeUnicode(PH_UNICODE_UTF16, codePoint, codeUnits, &numberOfCodeUnits))\n            {\n                bytesInUtf16String += numberOfCodeUnits * sizeof(WCHAR);\n\n                if (outRemaining >= numberOfCodeUnits)\n                {\n                    *out++ = codeUnits[0];\n\n                    if (numberOfCodeUnits >= 2)\n                        *out++ = codeUnits[1];\n\n                    outRemaining -= numberOfCodeUnits;\n                }\n                else\n                {\n                    result = FALSE;\n                }\n            }\n            else\n            {\n                result = FALSE;\n            }\n        }\n    }\n\n    if (BytesInUtf16String)\n        *BytesInUtf16String = bytesInUtf16String;\n\n    return result;\n}\n\nPPH_STRING PhConvertUtf8ToUtf16(\n    _In_ PSTR Buffer\n    )\n{\n    return PhConvertUtf8ToUtf16Ex(\n        Buffer,\n        strlen(Buffer)\n        );\n}\n\nPPH_STRING PhConvertUtf8ToUtf16Ex(\n    _In_ PCHAR Buffer,\n    _In_ SIZE_T Length\n    )\n{\n    PPH_STRING string;\n    SIZE_T utf16Bytes;\n\n    if (!PhConvertUtf8ToUtf16Size(\n        &utf16Bytes,\n        Buffer,\n        Length\n        ))\n    {\n        return NULL;\n    }\n\n    string = PhCreateStringEx(NULL, utf16Bytes);\n\n    if (!PhConvertUtf8ToUtf16Buffer(\n        string->Buffer,\n        string->Length,\n        NULL,\n        Buffer,\n        Length\n        ))\n    {\n        PhDereferenceObject(string);\n        return NULL;\n    }\n\n    return string;\n}\n\nBOOLEAN PhConvertUtf16ToUtf8Size(\n    _Out_ PSIZE_T BytesInUtf8String,\n    _In_reads_bytes_(BytesInUtf16String) PWCH Utf16String,\n    _In_ SIZE_T BytesInUtf16String\n    )\n{\n    BOOLEAN result;\n    PH_UNICODE_DECODER decoder;\n    PWCH in;\n    SIZE_T inRemaining;\n    SIZE_T bytesInUtf8String;\n    ULONG codePoint;\n    ULONG numberOfCodeUnits;\n\n    result = TRUE;\n    PhInitializeUnicodeDecoder(&decoder, PH_UNICODE_UTF16);\n    in = Utf16String;\n    inRemaining = BytesInUtf16String / sizeof(WCHAR);\n    bytesInUtf8String = 0;\n\n    while (inRemaining != 0)\n    {\n        PhWriteUnicodeDecoder(&decoder, (USHORT)*in);\n        in++;\n        inRemaining--;\n\n        while (PhDecodeUnicodeDecoder(&decoder, &codePoint))\n        {\n            if (PhEncodeUnicode(PH_UNICODE_UTF8, codePoint, NULL, &numberOfCodeUnits))\n                bytesInUtf8String += numberOfCodeUnits;\n            else\n                result = FALSE;\n        }\n    }\n\n    *BytesInUtf8String = bytesInUtf8String;\n\n    return result;\n}\n\nBOOLEAN PhConvertUtf16ToUtf8Buffer(\n    _Out_writes_bytes_to_(MaxBytesInUtf8String, *BytesInUtf8String) PCH Utf8String,\n    _In_ SIZE_T MaxBytesInUtf8String,\n    _Out_opt_ PSIZE_T BytesInUtf8String,\n    _In_reads_bytes_(BytesInUtf16String) PWCH Utf16String,\n    _In_ SIZE_T BytesInUtf16String\n    )\n{\n    BOOLEAN result;\n    PH_UNICODE_DECODER decoder;\n    PWCH in;\n    SIZE_T inRemaining;\n    PCH out;\n    SIZE_T outRemaining;\n    SIZE_T bytesInUtf8String;\n    ULONG codePoint;\n    UCHAR codeUnits[4];\n    ULONG numberOfCodeUnits;\n\n    result = TRUE;\n    PhInitializeUnicodeDecoder(&decoder, PH_UNICODE_UTF16);\n    in = Utf16String;\n    inRemaining = BytesInUtf16String / sizeof(WCHAR);\n    out = Utf8String;\n    outRemaining = MaxBytesInUtf8String;\n    bytesInUtf8String = 0;\n\n    while (inRemaining != 0)\n    {\n        PhWriteUnicodeDecoder(&decoder, (USHORT)*in);\n        in++;\n        inRemaining--;\n\n        while (PhDecodeUnicodeDecoder(&decoder, &codePoint))\n        {\n            if (PhEncodeUnicode(PH_UNICODE_UTF8, codePoint, codeUnits, &numberOfCodeUnits))\n            {\n                bytesInUtf8String += numberOfCodeUnits;\n\n                if (outRemaining >= numberOfCodeUnits)\n                {\n                    *out++ = codeUnits[0];\n\n                    if (numberOfCodeUnits >= 2)\n                        *out++ = codeUnits[1];\n                    if (numberOfCodeUnits >= 3)\n                        *out++ = codeUnits[2];\n                    if (numberOfCodeUnits >= 4)\n                        *out++ = codeUnits[3];\n\n                    outRemaining -= numberOfCodeUnits;\n                }\n                else\n                {\n                    result = FALSE;\n                }\n            }\n            else\n            {\n                result = FALSE;\n            }\n        }\n    }\n\n    if (BytesInUtf8String)\n        *BytesInUtf8String = bytesInUtf8String;\n\n    return result;\n}\n\nPPH_BYTES PhConvertUtf16ToUtf8(\n    _In_ PWSTR Buffer\n    )\n{\n    return PhConvertUtf16ToUtf8Ex(\n        Buffer,\n        PhCountStringZ(Buffer) * sizeof(WCHAR)\n        );\n}\n\nPPH_BYTES PhConvertUtf16ToUtf8Ex(\n    _In_ PWCHAR Buffer,\n    _In_ SIZE_T Length\n    )\n{\n    PPH_BYTES bytes;\n    SIZE_T utf8Bytes;\n\n    if (!PhConvertUtf16ToUtf8Size(\n        &utf8Bytes,\n        Buffer,\n        Length\n        ))\n    {\n        return NULL;\n    }\n\n    bytes = PhCreateBytesEx(NULL, utf8Bytes);\n\n    if (!PhConvertUtf16ToUtf8Buffer(\n        bytes->Buffer,\n        bytes->Length,\n        NULL,\n        Buffer,\n        Length\n        ))\n    {\n        PhDereferenceObject(bytes);\n        return NULL;\n    }\n\n    return bytes;\n}\n\n/**\n * Initializes a string builder object.\n *\n * \\param StringBuilder A string builder object.\n * \\param InitialCapacity The number of bytes to allocate initially.\n */\nVOID PhInitializeStringBuilder(\n    _Out_ PPH_STRING_BUILDER StringBuilder,\n    _In_ SIZE_T InitialCapacity\n    )\n{\n    // Make sure the initial capacity is even, as required for all string objects.\n    if (InitialCapacity & 1)\n        InitialCapacity++;\n\n    StringBuilder->AllocatedLength = InitialCapacity;\n\n    // Allocate a PH_STRING for the string builder.\n    // We will dereference it and allocate a new one when we need to resize the string.\n\n    StringBuilder->String = PhCreateStringEx(NULL, StringBuilder->AllocatedLength);\n\n    // We will keep modifying the Length field of the string so that:\n    // 1. We know how much of the string is used, and\n    // 2. The user can simply get a reference to the string and use it as-is.\n\n    StringBuilder->String->Length = 0;\n\n    // Write the null terminator.\n    StringBuilder->String->Buffer[0] = 0;\n\n    PHLIB_INC_STATISTIC(BaseStringBuildersCreated);\n}\n\n/**\n * Frees resources used by a string builder object.\n *\n * \\param StringBuilder A string builder object.\n */\nVOID PhDeleteStringBuilder(\n    _Inout_ PPH_STRING_BUILDER StringBuilder\n    )\n{\n    PhDereferenceObject(StringBuilder->String);\n}\n\n/**\n * Obtains a reference to the string constructed by a string builder object and frees resources used\n * by the object.\n *\n * \\param StringBuilder A string builder object.\n *\n * \\return A pointer to a string. You must free the string using PhDereferenceObject() when you no\n * longer need it.\n */\nPPH_STRING PhFinalStringBuilderString(\n    _Inout_ PPH_STRING_BUILDER StringBuilder\n    )\n{\n    return StringBuilder->String;\n}\n\nVOID PhpResizeStringBuilder(\n    _In_ PPH_STRING_BUILDER StringBuilder,\n    _In_ SIZE_T NewCapacity\n    )\n{\n    PPH_STRING newString;\n\n    // Double the string size. If that still isn't enough room, just use the new length.\n\n    StringBuilder->AllocatedLength *= 2;\n\n    if (StringBuilder->AllocatedLength < NewCapacity)\n        StringBuilder->AllocatedLength = NewCapacity;\n\n    // Allocate a new string.\n    newString = PhCreateStringEx(NULL, StringBuilder->AllocatedLength);\n\n    // Copy the old string to the new string.\n    memcpy(\n        newString->Buffer,\n        StringBuilder->String->Buffer,\n        StringBuilder->String->Length + sizeof(WCHAR) // Include null terminator\n        );\n\n    // Copy the old string length.\n    newString->Length = StringBuilder->String->Length;\n\n    // Dereference the old string and replace it with the new string.\n    PhMoveReference(&StringBuilder->String, newString);\n\n    PHLIB_INC_STATISTIC(BaseStringBuildersResized);\n}\n\nFORCEINLINE VOID PhpWriteNullTerminatorStringBuilder(\n    _In_ PPH_STRING_BUILDER StringBuilder\n    )\n{\n    assert(!(StringBuilder->String->Length & 1));\n    *(PWCHAR)PTR_ADD_OFFSET(StringBuilder->String->Buffer, StringBuilder->String->Length) = 0;\n}\n\n/**\n * Appends a string to the end of a string builder string.\n *\n * \\param StringBuilder A string builder object.\n * \\param String The string to append.\n */\nVOID PhAppendStringBuilder(\n    _Inout_ PPH_STRING_BUILDER StringBuilder,\n    _In_ PPH_STRINGREF String\n    )\n{\n    PhAppendStringBuilderEx(\n        StringBuilder,\n        String->Buffer,\n        String->Length\n        );\n}\n\n/**\n * Appends a string to the end of a string builder string.\n *\n * \\param StringBuilder A string builder object.\n * \\param String The string to append.\n */\nVOID PhAppendStringBuilder2(\n    _Inout_ PPH_STRING_BUILDER StringBuilder,\n    _In_ PWSTR String\n    )\n{\n    PhAppendStringBuilderEx(\n        StringBuilder,\n        String,\n        PhCountStringZ(String) * sizeof(WCHAR)\n        );\n}\n\n/**\n * Appends a string to the end of a string builder string.\n *\n * \\param StringBuilder A string builder object.\n * \\param String The string to append. Specify NULL to simply reserve \\a Length bytes.\n * \\param Length The number of bytes to append.\n */\nVOID PhAppendStringBuilderEx(\n    _Inout_ PPH_STRING_BUILDER StringBuilder,\n    _In_opt_ PWCHAR String,\n    _In_ SIZE_T Length\n    )\n{\n    if (Length == 0)\n        return;\n\n    // See if we need to re-allocate the string.\n    if (StringBuilder->AllocatedLength < StringBuilder->String->Length + Length)\n    {\n        PhpResizeStringBuilder(StringBuilder, StringBuilder->String->Length + Length);\n    }\n\n    // Copy the string, add the length, then write the null terminator.\n\n    if (String)\n    {\n        memcpy(\n            PTR_ADD_OFFSET(StringBuilder->String->Buffer, StringBuilder->String->Length),\n            String,\n            Length\n            );\n    }\n\n    StringBuilder->String->Length += Length;\n    PhpWriteNullTerminatorStringBuilder(StringBuilder);\n}\n\n/**\n * Appends a character to the end of a string builder string.\n *\n * \\param StringBuilder A string builder object.\n * \\param Character The character to append.\n */\nVOID PhAppendCharStringBuilder(\n    _Inout_ PPH_STRING_BUILDER StringBuilder,\n    _In_ WCHAR Character\n    )\n{\n    if (StringBuilder->AllocatedLength < StringBuilder->String->Length + sizeof(WCHAR))\n    {\n        PhpResizeStringBuilder(StringBuilder, StringBuilder->String->Length + sizeof(WCHAR));\n    }\n\n    *(PWCHAR)PTR_ADD_OFFSET(StringBuilder->String->Buffer, StringBuilder->String->Length) = Character;\n    StringBuilder->String->Length += sizeof(WCHAR);\n    PhpWriteNullTerminatorStringBuilder(StringBuilder);\n}\n\n/**\n * Appends a number of characters to the end of a string builder string.\n *\n * \\param StringBuilder A string builder object.\n * \\param Character The character to append.\n * \\param Count The number of times to append the character.\n */\nVOID PhAppendCharStringBuilder2(\n    _Inout_ PPH_STRING_BUILDER StringBuilder,\n    _In_ WCHAR Character,\n    _In_ SIZE_T Count\n    )\n{\n    if (Count == 0)\n        return;\n\n    // See if we need to re-allocate the string.\n    if (StringBuilder->AllocatedLength < StringBuilder->String->Length + Count * sizeof(WCHAR))\n    {\n        PhpResizeStringBuilder(StringBuilder, StringBuilder->String->Length + Count * sizeof(WCHAR));\n    }\n\n    wmemset(\n        PTR_ADD_OFFSET(StringBuilder->String->Buffer, StringBuilder->String->Length),\n        Character,\n        Count\n        );\n\n    StringBuilder->String->Length += Count * sizeof(WCHAR);\n    PhpWriteNullTerminatorStringBuilder(StringBuilder);\n}\n\n/**\n * Appends a formatted string to the end of a string builder string.\n *\n * \\param StringBuilder A string builder object.\n * \\param Format The format-control string.\n */\nVOID PhAppendFormatStringBuilder(\n    _Inout_ PPH_STRING_BUILDER StringBuilder,\n    _In_ _Printf_format_string_ PWSTR Format,\n    ...\n    )\n{\n    va_list argptr;\n\n    va_start(argptr, Format);\n    PhAppendFormatStringBuilder_V(StringBuilder, Format, argptr);\n    va_end(argptr);\n}\n\nVOID PhAppendFormatStringBuilder_V(\n    _Inout_ PPH_STRING_BUILDER StringBuilder,\n    _In_ _Printf_format_string_ PWSTR Format,\n    _In_ va_list ArgPtr\n    )\n{\n    int length;\n    SIZE_T lengthInBytes;\n\n    length = _vscwprintf(Format, ArgPtr);\n\n    if (length == -1 || length == 0)\n        return;\n\n    lengthInBytes = length * sizeof(WCHAR);\n\n    if (StringBuilder->AllocatedLength < StringBuilder->String->Length + lengthInBytes)\n        PhpResizeStringBuilder(StringBuilder, StringBuilder->String->Length + lengthInBytes);\n\n    _vsnwprintf(\n        PTR_ADD_OFFSET(StringBuilder->String->Buffer, StringBuilder->String->Length),\n        length,\n        Format,\n        ArgPtr\n        );\n\n    StringBuilder->String->Length += lengthInBytes;\n    PhpWriteNullTerminatorStringBuilder(StringBuilder);\n}\n\n/**\n * Inserts a string into a string builder string.\n *\n * \\param StringBuilder A string builder object.\n * \\param Index The index, in characters, at which to insert the string.\n * \\param String The string to insert.\n */\nVOID PhInsertStringBuilder(\n    _Inout_ PPH_STRING_BUILDER StringBuilder,\n    _In_ SIZE_T Index,\n    _In_ PPH_STRINGREF String\n    )\n{\n    PhInsertStringBuilderEx(\n        StringBuilder,\n        Index,\n        String->Buffer,\n        String->Length\n        );\n}\n\n/**\n * Inserts a string into a string builder string.\n *\n * \\param StringBuilder A string builder object.\n * \\param Index The index, in characters, at which to insert the string.\n * \\param String The string to insert.\n */\nVOID PhInsertStringBuilder2(\n    _Inout_ PPH_STRING_BUILDER StringBuilder,\n    _In_ SIZE_T Index,\n    _In_ PWSTR String\n    )\n{\n    PhInsertStringBuilderEx(\n        StringBuilder,\n        Index,\n        String,\n        PhCountStringZ(String) * sizeof(WCHAR)\n        );\n}\n\n/**\n * Inserts a string into a string builder string.\n *\n * \\param StringBuilder A string builder object.\n * \\param Index The index, in characters, at which to insert the string.\n * \\param String The string to insert. Specify NULL to simply reserve \\a Length bytes at \\a Index.\n * \\param Length The number of bytes to insert.\n */\nVOID PhInsertStringBuilderEx(\n    _Inout_ PPH_STRING_BUILDER StringBuilder,\n    _In_ SIZE_T Index,\n    _In_opt_ PWCHAR String,\n    _In_ SIZE_T Length\n    )\n{\n    if (Length == 0)\n        return;\n\n    // See if we need to re-allocate the string.\n    if (StringBuilder->AllocatedLength < StringBuilder->String->Length + Length)\n    {\n        PhpResizeStringBuilder(StringBuilder, StringBuilder->String->Length + Length);\n    }\n\n    if (Index * sizeof(WCHAR) < StringBuilder->String->Length)\n    {\n        // Create some space for the string.\n        memmove(\n            &StringBuilder->String->Buffer[Index + Length / sizeof(WCHAR)],\n            &StringBuilder->String->Buffer[Index],\n            StringBuilder->String->Length - Index * sizeof(WCHAR)\n            );\n    }\n\n    if (String)\n    {\n        // Copy the new string.\n        memcpy(\n            &StringBuilder->String->Buffer[Index],\n            String,\n            Length\n            );\n    }\n\n    StringBuilder->String->Length += Length;\n    PhpWriteNullTerminatorStringBuilder(StringBuilder);\n}\n\n/**\n * Removes characters from a string builder string.\n *\n * \\param StringBuilder A string builder object.\n * \\param StartIndex The index, in characters, at which to begin removing characters.\n * \\param Count The number of characters to remove.\n */\nVOID PhRemoveStringBuilder(\n    _Inout_ PPH_STRING_BUILDER StringBuilder,\n    _In_ SIZE_T StartIndex,\n    _In_ SIZE_T Count\n    )\n{\n    // Overwrite the removed part with the part\n    // behind it.\n\n    memmove(\n        &StringBuilder->String->Buffer[StartIndex],\n        &StringBuilder->String->Buffer[StartIndex + Count],\n        StringBuilder->String->Length - (Count + StartIndex) * sizeof(WCHAR)\n        );\n    StringBuilder->String->Length -= Count * sizeof(WCHAR);\n    PhpWriteNullTerminatorStringBuilder(StringBuilder);\n}\n\n/**\n * Initializes a byte string builder object.\n *\n * \\param BytesBuilder A byte string builder object.\n * \\param InitialCapacity The number of bytes to allocate initially.\n */\nVOID PhInitializeBytesBuilder(\n    _Out_ PPH_BYTES_BUILDER BytesBuilder,\n    _In_ SIZE_T InitialCapacity\n    )\n{\n    BytesBuilder->AllocatedLength = InitialCapacity;\n    BytesBuilder->Bytes = PhCreateBytesEx(NULL, BytesBuilder->AllocatedLength);\n    BytesBuilder->Bytes->Length = 0;\n    BytesBuilder->Bytes->Buffer[0] = 0;\n}\n\n/**\n * Frees resources used by a byte string builder object.\n *\n * \\param BytesBuilder A byte string builder object.\n */\nVOID PhDeleteBytesBuilder(\n    _Inout_ PPH_BYTES_BUILDER BytesBuilder\n    )\n{\n    PhDereferenceObject(BytesBuilder->Bytes);\n}\n\n/**\n * Obtains a reference to the byte string constructed by a byte string builder object and frees\n * resources used by the object.\n *\n * \\param BytesBuilder A byte string builder object.\n *\n * \\return A pointer to a byte string. You must free the byte string using PhDereferenceObject()\n * when you no longer need it.\n */\nPPH_BYTES PhFinalBytesBuilderBytes(\n    _Inout_ PPH_BYTES_BUILDER BytesBuilder\n    )\n{\n    return BytesBuilder->Bytes;\n}\n\nVOID PhpResizeBytesBuilder(\n    _In_ PPH_BYTES_BUILDER BytesBuilder,\n    _In_ SIZE_T NewCapacity\n    )\n{\n    PPH_BYTES newBytes;\n\n    // Double the byte string size. If that still isn't enough room, just use the new length.\n\n    BytesBuilder->AllocatedLength *= 2;\n\n    if (BytesBuilder->AllocatedLength < NewCapacity)\n        BytesBuilder->AllocatedLength = NewCapacity;\n\n    // Allocate a new byte string.\n    newBytes = PhCreateBytesEx(NULL, BytesBuilder->AllocatedLength);\n\n    // Copy the old byte string to the new byte string.\n    memcpy(\n        newBytes->Buffer,\n        BytesBuilder->Bytes->Buffer,\n        BytesBuilder->Bytes->Length + sizeof(CHAR) // Include null terminator\n        );\n\n    // Copy the old byte string length.\n    newBytes->Length = BytesBuilder->Bytes->Length;\n\n    // Dereference the old byte string and replace it with the new byte string.\n    PhMoveReference(&BytesBuilder->Bytes, newBytes);\n}\n\nFORCEINLINE VOID PhpWriteNullTerminatorBytesBuilder(\n    _In_ PPH_BYTES_BUILDER BytesBuilder\n    )\n{\n    BytesBuilder->Bytes->Buffer[BytesBuilder->Bytes->Length] = 0;\n}\n\n/**\n * Appends a byte string to the end of a byte string builder string.\n *\n * \\param BytesBuilder A byte string builder object.\n * \\param Bytes The byte string to append.\n */\nVOID PhAppendBytesBuilder(\n    _Inout_ PPH_BYTES_BUILDER BytesBuilder,\n    _In_ PPH_BYTESREF Bytes\n    )\n{\n    PhAppendBytesBuilderEx(\n        BytesBuilder,\n        Bytes->Buffer,\n        Bytes->Length,\n        0,\n        NULL\n        );\n}\n\n/**\n * Appends a byte string to the end of a byte string builder string.\n *\n * \\param BytesBuilder A byte string builder object.\n * \\param Bytes The byte string to append.\n */\nVOID PhAppendBytesBuilder2(\n    _Inout_ PPH_BYTES_BUILDER BytesBuilder,\n    _In_ PCHAR Bytes\n    )\n{\n    PhAppendBytesBuilderEx(\n        BytesBuilder,\n        Bytes,\n        strlen(Bytes),\n        0,\n        NULL\n        );\n}\n\n/**\n * Appends a byte string to the end of a byte string builder string.\n *\n * \\param BytesBuilder A byte string builder object.\n * \\param Buffer The byte string to append. Specify NULL to simply reserve \\a Length bytes.\n * \\param Length The number of bytes to append.\n * \\param Alignment The required alignment. This should not be greater than 8.\n * \\param Offset A variable which receives the byte offset of the appended or reserved bytes in the\n * byte string builder string.\n *\n * \\return A pointer to the appended or reserved bytes.\n */\nPVOID PhAppendBytesBuilderEx(\n    _Inout_ PPH_BYTES_BUILDER BytesBuilder,\n    _In_opt_ PVOID Buffer,\n    _In_ SIZE_T Length,\n    _In_opt_ SIZE_T Alignment,\n    _Out_opt_ PSIZE_T Offset\n    )\n{\n    SIZE_T currentLength;\n\n    currentLength = BytesBuilder->Bytes->Length;\n\n    if (Length == 0)\n        goto Done;\n\n    if (Alignment)\n        currentLength = ALIGN_UP_BY(currentLength, Alignment);\n\n    // See if we need to re-allocate the byte string.\n    if (BytesBuilder->AllocatedLength < currentLength + Length)\n        PhpResizeBytesBuilder(BytesBuilder, currentLength + Length);\n\n    // Copy the byte string, add the length, then write the null terminator.\n\n    if (Buffer)\n        memcpy(BytesBuilder->Bytes->Buffer + currentLength, Buffer, Length);\n\n    BytesBuilder->Bytes->Length = currentLength + Length;\n    PhpWriteNullTerminatorBytesBuilder(BytesBuilder);\n\nDone:\n    if (Offset)\n        *Offset = currentLength;\n\n    return BytesBuilder->Bytes->Buffer + currentLength;\n}\n\n/**\n * Creates an array object.\n *\n * \\param Array An array object.\n * \\param ItemSize The size of each item, in bytes.\n * \\param InitialCapacity The number of elements to allocate storage for, initially.\n */\nVOID PhInitializeArray(\n    _Out_ PPH_ARRAY Array,\n    _In_ SIZE_T ItemSize,\n    _In_ SIZE_T InitialCapacity\n    )\n{\n    // Initial capacity of 0 is not allowed.\n    if (InitialCapacity == 0)\n        InitialCapacity = 1;\n\n    Array->Count = 0;\n    Array->AllocatedCount = InitialCapacity;\n    Array->ItemSize = ItemSize;\n    Array->Items = PhAllocate(Array->AllocatedCount * ItemSize);\n}\n\n/**\n * Frees resources used by an array object.\n *\n * \\param Array An array object.\n */\nVOID PhDeleteArray(\n    _Inout_ PPH_ARRAY Array\n    )\n{\n    PhFree(Array->Items);\n}\n\n/**\n * Obtains a copy of the array constructed by an array object and frees resources used by the\n * object.\n *\n * \\param Array An array object.\n *\n * \\return The array buffer.\n */\nPVOID PhFinalArrayItems(\n    _Inout_ PPH_ARRAY Array\n    )\n{\n    return Array->Items;\n}\n\n/**\n * Resizes an array.\n *\n * \\param Array An array object.\n * \\param NewCapacity The new required number of elements for which storage has been reserved. This\n * must not be smaller than the current number of items in the array.\n */\nVOID PhResizeArray(\n    _Inout_ PPH_ARRAY Array,\n    _In_ SIZE_T NewCapacity\n    )\n{\n    if (Array->Count > NewCapacity)\n        PhRaiseStatus(STATUS_INVALID_PARAMETER_2);\n\n    Array->AllocatedCount = NewCapacity;\n    Array->Items = PhReAllocate(Array->Items, Array->AllocatedCount * Array->ItemSize);\n}\n\n/**\n * Adds an item to an array.\n *\n * \\param Array An array object.\n * \\param Item The item to add.\n */\nVOID PhAddItemArray(\n    _Inout_ PPH_ARRAY Array,\n    _In_ PVOID Item\n    )\n{\n    // See if we need to resize the list.\n    if (Array->Count == Array->AllocatedCount)\n    {\n        Array->AllocatedCount *= 2;\n        Array->Items = PhReAllocate(Array->Items, Array->AllocatedCount * Array->ItemSize);\n    }\n\n    memcpy(PhItemArray(Array, Array->Count), Item, Array->ItemSize);\n    Array->Count++;\n}\n\n/**\n * Adds items to an array.\n *\n * \\param Array An array object.\n * \\param Items An array containing the items to add.\n * \\param Count The number of items to add.\n */\nVOID PhAddItemsArray(\n    _Inout_ PPH_ARRAY Array,\n    _In_ PVOID Items,\n    _In_ SIZE_T Count\n    )\n{\n    // See if we need to resize the list.\n    if (Array->AllocatedCount < Array->Count + Count)\n    {\n        Array->AllocatedCount *= 2;\n\n        if (Array->AllocatedCount < Array->Count + Count)\n            Array->AllocatedCount = Array->Count + Count;\n\n        Array->Items = PhReAllocate(Array->Items, Array->AllocatedCount * Array->ItemSize);\n    }\n\n    memcpy(\n        PhItemArray(Array, Array->Count),\n        Items,\n        Count * Array->ItemSize\n        );\n    Array->Count += Count;\n}\n\n/**\n * Clears an array.\n *\n * \\param Array An array object.\n */\nVOID PhClearArray(\n    _Inout_ PPH_ARRAY Array\n    )\n{\n    Array->Count = 0;\n}\n\n/**\n * Removes an item from an array.\n *\n * \\param Array An array object.\n * \\param Index The index of the item.\n */\nVOID PhRemoveItemArray(\n    _Inout_ PPH_ARRAY Array,\n    _In_ SIZE_T Index\n    )\n{\n    PhRemoveItemsArray(Array, Index, 1);\n}\n\n/**\n * Removes items from an array.\n *\n * \\param Array An array object.\n * \\param StartIndex The index at which to begin removing items.\n * \\param Count The number of items to remove.\n */\nVOID PhRemoveItemsArray(\n    _Inout_ PPH_ARRAY Array,\n    _In_ SIZE_T StartIndex,\n    _In_ SIZE_T Count\n    )\n{\n    // Shift the items after the items forward.\n    memmove(\n        PhItemArray(Array, StartIndex),\n        PhItemArray(Array, StartIndex + Count),\n        (Array->Count - StartIndex - Count) * Array->ItemSize\n        );\n    Array->Count -= Count;\n}\n\n/**\n * Creates a list object.\n *\n * \\param InitialCapacity The number of elements to allocate storage for, initially.\n */\nPPH_LIST PhCreateList(\n    _In_ ULONG InitialCapacity\n    )\n{\n    PPH_LIST list;\n\n    list = PhCreateObject(sizeof(PH_LIST), PhListType);\n\n    // Initial capacity of 0 is not allowed.\n    if (InitialCapacity == 0)\n        InitialCapacity = 1;\n\n    list->Count = 0;\n    list->AllocatedCount = InitialCapacity;\n    list->Items = PhAllocate(list->AllocatedCount * sizeof(PVOID));\n\n    return list;\n}\n\nVOID PhpListDeleteProcedure(\n    _In_ PVOID Object,\n    _In_ ULONG Flags\n    )\n{\n    PPH_LIST list = (PPH_LIST)Object;\n\n    PhFree(list->Items);\n}\n\n/**\n * Resizes a list.\n *\n * \\param List A list object.\n * \\param NewCapacity The new required number of elements for which storage has been reserved. This\n * must not be smaller than the current number of items in the list.\n */\nVOID PhResizeList(\n    _Inout_ PPH_LIST List,\n    _In_ ULONG NewCapacity\n    )\n{\n    if (List->Count > NewCapacity)\n        PhRaiseStatus(STATUS_INVALID_PARAMETER_2);\n\n    List->AllocatedCount = NewCapacity;\n    List->Items = PhReAllocate(List->Items, List->AllocatedCount * sizeof(PVOID));\n}\n\n/**\n * Adds an item to a list.\n *\n * \\param List A list object.\n * \\param Item The item to add.\n */\nVOID PhAddItemList(\n    _Inout_ PPH_LIST List,\n    _In_ PVOID Item\n    )\n{\n    // See if we need to resize the list.\n    if (List->Count == List->AllocatedCount)\n    {\n        List->AllocatedCount *= 2;\n        List->Items = PhReAllocate(List->Items, List->AllocatedCount * sizeof(PVOID));\n    }\n\n    List->Items[List->Count++] = Item;\n}\n\n/**\n * Adds items to a list.\n *\n * \\param List A list object.\n * \\param Items An array containing the items to add.\n * \\param Count The number of items to add.\n */\nVOID PhAddItemsList(\n    _Inout_ PPH_LIST List,\n    _In_ PVOID *Items,\n    _In_ ULONG Count\n    )\n{\n    // See if we need to resize the list.\n    if (List->AllocatedCount < List->Count + Count)\n    {\n        List->AllocatedCount *= 2;\n\n        if (List->AllocatedCount < List->Count + Count)\n            List->AllocatedCount = List->Count + Count;\n\n        List->Items = PhReAllocate(List->Items, List->AllocatedCount * sizeof(PVOID));\n    }\n\n    memcpy(\n        &List->Items[List->Count],\n        Items,\n        Count * sizeof(PVOID)\n        );\n    List->Count += Count;\n}\n\n/**\n * Clears a list.\n *\n * \\param List A list object.\n */\nVOID PhClearList(\n    _Inout_ PPH_LIST List\n    )\n{\n    List->Count = 0;\n}\n\n_Success_(return != -1)\n/**\n * Locates an item in a list.\n *\n * \\param List A list object.\n * \\param Item The item to search for.\n *\n * \\return The index of the item. If the\n * item was not found, -1 is returned.\n */\nULONG PhFindItemList(\n    _In_ PPH_LIST List,\n    _In_ PVOID Item\n    )\n{\n    ULONG i;\n\n    for (i = 0; i < List->Count; i++)\n    {\n        if (List->Items[i] == Item)\n            return i;\n    }\n\n    return -1;\n}\n\n/**\n * Inserts an item into a list.\n *\n * \\param List A list object.\n * \\param Index The index at which to insert the item.\n * \\param Item The item to add.\n */\nVOID PhInsertItemList(\n    _Inout_ PPH_LIST List,\n    _In_ ULONG Index,\n    _In_ PVOID Item\n    )\n{\n    PhInsertItemsList(List, Index, &Item, 1);\n}\n\n/**\n * Inserts items into a list.\n *\n * \\param List A list object.\n * \\param Index The index at which to insert the items.\n * \\param Items An array containing the items to add.\n * \\param Count The number of items to add.\n */\nVOID PhInsertItemsList(\n    _Inout_ PPH_LIST List,\n    _In_ ULONG Index,\n    _In_ PVOID *Items,\n    _In_ ULONG Count\n    )\n{\n    // See if we need to resize the list.\n    if (List->AllocatedCount < List->Count + Count)\n    {\n        List->AllocatedCount *= 2;\n\n        if (List->AllocatedCount < List->Count + Count)\n            List->AllocatedCount = List->Count + Count;\n\n        List->Items = PhReAllocate(List->Items, List->AllocatedCount * sizeof(PVOID));\n    }\n\n    if (Index < List->Count)\n    {\n        // Shift the existing items backward.\n        memmove(\n            &List->Items[Index + Count],\n            &List->Items[Index],\n            (List->Count - Index) * sizeof(PVOID)\n            );\n    }\n\n    // Copy the new items into the list.\n    memcpy(\n        &List->Items[Index],\n        Items,\n        Count * sizeof(PVOID)\n        );\n\n    List->Count += Count;\n}\n\n/**\n * Removes an item from a list.\n *\n * \\param List A list object.\n * \\param Index The index of the item.\n */\nVOID PhRemoveItemList(\n    _Inout_ PPH_LIST List,\n    _In_ ULONG Index\n    )\n{\n    PhRemoveItemsList(List, Index, 1);\n}\n\n/**\n * Removes items from a list.\n *\n * \\param List A list object.\n * \\param StartIndex The index at which to begin removing items.\n * \\param Count The number of items to remove.\n */\nVOID PhRemoveItemsList(\n    _Inout_ PPH_LIST List,\n    _In_ ULONG StartIndex,\n    _In_ ULONG Count\n    )\n{\n    // Shift the items after the items forward.\n    memmove(\n        &List->Items[StartIndex],\n        &List->Items[StartIndex + Count],\n        (List->Count - StartIndex - Count) * sizeof(PVOID)\n        );\n    List->Count -= Count;\n}\n\n/**\n * Creates a pointer list object.\n *\n * \\param InitialCapacity The number of elements to allocate storage for initially.\n */\nPPH_POINTER_LIST PhCreatePointerList(\n    _In_ ULONG InitialCapacity\n    )\n{\n    PPH_POINTER_LIST pointerList;\n\n    pointerList = PhCreateObject(sizeof(PH_POINTER_LIST), PhPointerListType);\n\n    // Initial capacity of 0 is not allowed.\n    if (InitialCapacity == 0)\n        InitialCapacity = 1;\n\n    pointerList->Count = 0;\n    pointerList->AllocatedCount = InitialCapacity;\n    pointerList->FreeEntry = -1;\n    pointerList->NextEntry = 0;\n    pointerList->Items = PhAllocate(pointerList->AllocatedCount * sizeof(PVOID));\n\n    return pointerList;\n}\n\nVOID NTAPI PhpPointerListDeleteProcedure(\n    _In_ PVOID Object,\n    _In_ ULONG Flags\n    )\n{\n    PPH_POINTER_LIST pointerList = (PPH_POINTER_LIST)Object;\n\n    PhFree(pointerList->Items);\n}\n\n/**\n * Decodes an index stored in a free entry.\n */\nFORCEINLINE ULONG PhpDecodePointerListIndex(\n    _In_ PVOID Index\n    )\n{\n    // At least with Microsoft's compiler, shift right on a signed value preserves the sign. This is\n    // important because we want decode(encode(-1)) = ((-1 << 1) | 1) >> 1 = -1.\n    return (ULONG)((LONG_PTR)Index >> 1);\n}\n\n/**\n * Encodes an index for storage in a free entry.\n */\nFORCEINLINE PVOID PhpEncodePointerListIndex(\n    _In_ ULONG Index\n    )\n{\n    return (PVOID)(((ULONG_PTR)Index << 1) | 0x1);\n}\n\nFORCEINLINE HANDLE PhpPointerListIndexToHandle(\n    _In_ ULONG Index\n    )\n{\n    // Add one to allow NULL handles to indicate failure/an invalid index.\n    return UlongToHandle(Index + 1);\n}\n\nFORCEINLINE ULONG PhpPointerListHandleToIndex(\n    _In_ HANDLE Handle\n    )\n{\n    return HandleToUlong(Handle) - 1;\n}\n\n/**\n * Adds a pointer to a pointer list.\n *\n * \\param PointerList A pointer list object.\n * \\param Pointer The pointer to add. The pointer must be at least 2 byte aligned.\n *\n * \\return A handle to the pointer, valid until the pointer is removed from the pointer list.\n */\nHANDLE PhAddItemPointerList(\n    _Inout_ PPH_POINTER_LIST PointerList,\n    _In_ PVOID Pointer\n    )\n{\n    ULONG index;\n\n    assert(PH_IS_LIST_POINTER_VALID(Pointer));\n\n    // Use a free entry if possible.\n    if (PointerList->FreeEntry != -1)\n    {\n        PVOID oldPointer;\n\n        index = PointerList->FreeEntry;\n        oldPointer = PointerList->Items[index];\n        PointerList->Items[index] = Pointer;\n        PointerList->FreeEntry = PhpDecodePointerListIndex(oldPointer);\n    }\n    else\n    {\n        // Use the next entry.\n        if (PointerList->NextEntry == PointerList->AllocatedCount)\n        {\n            PointerList->AllocatedCount *= 2;\n            PointerList->Items = PhReAllocate(PointerList->Items, PointerList->AllocatedCount * sizeof(PVOID));\n        }\n\n        index = PointerList->NextEntry++;\n        PointerList->Items[index] = Pointer;\n    }\n\n    PointerList->Count++;\n\n    return PhpPointerListIndexToHandle(index);\n}\n\nBOOLEAN PhEnumPointerListEx(\n    _In_ PPH_POINTER_LIST PointerList,\n    _Inout_ PULONG EnumerationKey,\n    _Out_ PVOID *Pointer,\n    _Out_ PHANDLE PointerHandle\n    )\n{\n    ULONG index;\n\n    while ((index = *EnumerationKey) < PointerList->NextEntry)\n    {\n        PVOID pointer = PointerList->Items[index];\n\n        (*EnumerationKey)++;\n\n        if (PH_IS_LIST_POINTER_VALID(pointer))\n        {\n            *Pointer = pointer;\n            *PointerHandle = PhpPointerListIndexToHandle(index);\n\n            return TRUE;\n        }\n    }\n\n    return FALSE;\n}\n\n/**\n * Locates a pointer in a pointer list.\n *\n * \\param PointerList A pointer list object.\n * \\param Pointer The pointer to find. The pointer must be at least 2 byte aligned.\n *\n * \\return A handle to the pointer, valid until the pointer is removed from the pointer list. If the\n * pointer is not contained in the pointer list, NULL is returned.\n */\nHANDLE PhFindItemPointerList(\n    _In_ PPH_POINTER_LIST PointerList,\n    _In_ PVOID Pointer\n    )\n{\n    ULONG i;\n\n    assert(PH_IS_LIST_POINTER_VALID(Pointer));\n\n    for (i = 0; i < PointerList->NextEntry; i++)\n    {\n        if (PointerList->Items[i] == Pointer)\n            return PhpPointerListIndexToHandle(i);\n    }\n\n    return NULL;\n}\n\n/**\n * Removes a pointer from a pointer list.\n *\n * \\param PointerList A pointer list object.\n * \\param PointerHandle A handle to the pointer to remove.\n *\n * \\remarks No checking is performed on the pointer handle. Make sure the handle is valid before\n * calling the function.\n */\nVOID PhRemoveItemPointerList(\n    _Inout_ PPH_POINTER_LIST PointerList,\n    _In_ HANDLE PointerHandle\n    )\n{\n    ULONG index;\n\n    assert(PointerHandle);\n\n    index = PhpPointerListHandleToIndex(PointerHandle);\n\n    PointerList->Items[index] = PhpEncodePointerListIndex(PointerList->FreeEntry);\n    PointerList->FreeEntry = index;\n\n    PointerList->Count--;\n}\n\nFORCEINLINE ULONG PhpValidateHash(\n    _In_ ULONG Hash\n    )\n{\n    // No point in using a full hash when we're going to AND with size minus one anyway.\n#if defined(PH_HASHTABLE_FULL_HASH) && !defined(PH_HASHTABLE_POWER_OF_TWO_SIZE)\n    if (Hash != -1)\n        return Hash;\n    else\n        return 0;\n#else\n    return Hash & MAXLONG;\n#endif\n}\n\nFORCEINLINE ULONG PhpIndexFromHash(\n    _In_ PPH_HASHTABLE Hashtable,\n    _In_ ULONG Hash\n    )\n{\n#ifdef PH_HASHTABLE_POWER_OF_TWO_SIZE\n    return Hash & (Hashtable->AllocatedBuckets - 1);\n#else\n    return Hash % Hashtable->AllocatedBuckets;\n#endif\n}\n\nFORCEINLINE ULONG PhpGetNumberOfBuckets(\n    _In_ ULONG Capacity\n    )\n{\n#ifdef PH_HASHTABLE_POWER_OF_TWO_SIZE\n    return PhRoundUpToPowerOfTwo(Capacity);\n#else\n    return PhGetPrimeNumber(Capacity);\n#endif\n}\n\n/**\n * Creates a hashtable object.\n *\n * \\param EntrySize The size of each hashtable entry, in bytes.\n * \\param EqualFunction A comparison function that is executed to compare two hashtable entries.\n * \\param HashFunction A hash function that is executed to generate a hash code for a hashtable\n * entry.\n * \\param InitialCapacity The number of entries to allocate storage for initially.\n */\nPPH_HASHTABLE PhCreateHashtable(\n    _In_ ULONG EntrySize,\n    _In_ PPH_HASHTABLE_EQUAL_FUNCTION EqualFunction,\n    _In_ PPH_HASHTABLE_HASH_FUNCTION HashFunction,\n    _In_ ULONG InitialCapacity\n    )\n{\n    PPH_HASHTABLE hashtable;\n\n    hashtable = PhCreateObject(sizeof(PH_HASHTABLE), PhHashtableType);\n\n    // Initial capacity of 0 is not allowed.\n    if (InitialCapacity == 0)\n        InitialCapacity = 1;\n\n    hashtable->EntrySize = EntrySize;\n    hashtable->EqualFunction = EqualFunction;\n    hashtable->HashFunction = HashFunction;\n\n    // Allocate the buckets.\n    hashtable->AllocatedBuckets = PhpGetNumberOfBuckets(InitialCapacity);\n    hashtable->Buckets = PhAllocate(sizeof(ULONG) * hashtable->AllocatedBuckets);\n    // Set all bucket values to -1.\n    memset(hashtable->Buckets, 0xff, sizeof(ULONG) * hashtable->AllocatedBuckets);\n\n    // Allocate the entries.\n    hashtable->AllocatedEntries = hashtable->AllocatedBuckets;\n    hashtable->Entries = PhAllocate(PH_HASHTABLE_ENTRY_SIZE(EntrySize) * hashtable->AllocatedEntries);\n\n    hashtable->Count = 0;\n    hashtable->FreeEntry = -1;\n    hashtable->NextEntry = 0;\n\n    return hashtable;\n}\n\nVOID PhpHashtableDeleteProcedure(\n    _In_ PVOID Object,\n    _In_ ULONG Flags\n    )\n{\n    PPH_HASHTABLE hashtable = (PPH_HASHTABLE)Object;\n\n    PhFree(hashtable->Buckets);\n    PhFree(hashtable->Entries);\n}\n\nVOID PhpResizeHashtable(\n    _Inout_ PPH_HASHTABLE Hashtable,\n    _In_ ULONG NewCapacity\n    )\n{\n    PPH_HASHTABLE_ENTRY entry;\n    ULONG i;\n\n    // Re-allocate the buckets. Note that we don't need to keep the contents.\n    Hashtable->AllocatedBuckets = PhpGetNumberOfBuckets(NewCapacity);\n    PhFree(Hashtable->Buckets);\n    Hashtable->Buckets = PhAllocate(sizeof(ULONG) * Hashtable->AllocatedBuckets);\n    // Set all bucket values to -1.\n    memset(Hashtable->Buckets, 0xff, sizeof(ULONG) * Hashtable->AllocatedBuckets);\n\n    // Re-allocate the entries.\n    Hashtable->AllocatedEntries = Hashtable->AllocatedBuckets;\n    Hashtable->Entries = PhReAllocate(\n        Hashtable->Entries,\n        PH_HASHTABLE_ENTRY_SIZE(Hashtable->EntrySize) * Hashtable->AllocatedEntries\n        );\n\n    // Re-distribute the entries among the buckets.\n\n    // PH_HASHTABLE_GET_ENTRY is quite slow (it involves a multiply), so we use a pointer here.\n    entry = Hashtable->Entries;\n\n    for (i = 0; i < Hashtable->NextEntry; i++)\n    {\n        if (entry->HashCode != -1)\n        {\n            ULONG index = PhpIndexFromHash(Hashtable, entry->HashCode);\n\n            entry->Next = Hashtable->Buckets[index];\n            Hashtable->Buckets[index] = i;\n        }\n\n        entry = (PPH_HASHTABLE_ENTRY)((ULONG_PTR)entry + PH_HASHTABLE_ENTRY_SIZE(Hashtable->EntrySize));\n    }\n}\n\nFORCEINLINE PVOID PhpAddEntryHashtable(\n    _Inout_ PPH_HASHTABLE Hashtable,\n    _In_ PVOID Entry,\n    _In_ BOOLEAN CheckForDuplicate,\n    _Out_opt_ PBOOLEAN Added\n    )\n{\n    ULONG hashCode; // hash code of the new entry\n    ULONG index; // bucket index of the new entry\n    ULONG freeEntry; // index of new entry in entry array\n    PPH_HASHTABLE_ENTRY entry; // pointer to new entry in entry array\n\n    hashCode = PhpValidateHash(Hashtable->HashFunction(Entry));\n    index = PhpIndexFromHash(Hashtable, hashCode);\n\n    if (CheckForDuplicate)\n    {\n        ULONG i;\n\n        for (i = Hashtable->Buckets[index]; i != -1; i = entry->Next)\n        {\n            entry = PH_HASHTABLE_GET_ENTRY(Hashtable, i);\n\n            if (entry->HashCode == hashCode && Hashtable->EqualFunction(&entry->Body, Entry))\n            {\n                if (Added)\n                    *Added = FALSE;\n\n                return &entry->Body;\n            }\n        }\n    }\n\n    // Use a free entry if possible.\n    if (Hashtable->FreeEntry != -1)\n    {\n        freeEntry = Hashtable->FreeEntry;\n        entry = PH_HASHTABLE_GET_ENTRY(Hashtable, freeEntry);\n        Hashtable->FreeEntry = entry->Next;\n    }\n    else\n    {\n        // Use the next entry in the entry array.\n\n        if (Hashtable->NextEntry == Hashtable->AllocatedEntries)\n        {\n            // Resize the hashtable.\n            PhpResizeHashtable(Hashtable, Hashtable->AllocatedBuckets * 2);\n            index = PhpIndexFromHash(Hashtable, hashCode);\n        }\n\n        freeEntry = Hashtable->NextEntry++;\n        entry = PH_HASHTABLE_GET_ENTRY(Hashtable, freeEntry);\n    }\n\n    // Initialize the entry.\n    entry->HashCode = hashCode;\n    entry->Next = Hashtable->Buckets[index];\n    Hashtable->Buckets[index] = freeEntry;\n    // Copy the user-supplied data to the entry.\n    memcpy(&entry->Body, Entry, Hashtable->EntrySize);\n\n    Hashtable->Count++;\n\n    if (Added)\n        *Added = TRUE;\n\n    return &entry->Body;\n}\n\n/**\n * Adds an entry to a hashtable.\n *\n * \\param Hashtable A hashtable object.\n * \\param Entry The entry to add.\n *\n * \\return A pointer to the entry as stored in the hashtable. This pointer is valid until the\n * hashtable is modified. If the hashtable already contained an equal entry, NULL is returned.\n *\n * \\remarks Entries are only guaranteed to be 8 byte aligned, even on 64-bit systems.\n */\nPVOID PhAddEntryHashtable(\n    _Inout_ PPH_HASHTABLE Hashtable,\n    _In_ PVOID Entry\n    )\n{\n    PVOID entry;\n    BOOLEAN added;\n\n    entry = PhpAddEntryHashtable(Hashtable, Entry, TRUE, &added);\n\n    if (added)\n        return entry;\n    else\n        return NULL;\n}\n\n/**\n * Adds an entry to a hashtable or returns an existing one.\n *\n * \\param Hashtable A hashtable object.\n * \\param Entry The entry to add.\n * \\param Added A variable which receives TRUE if a new entry was created, and FALSE if an existing\n * entry was returned.\n *\n * \\return A pointer to the entry as stored in the hashtable. This pointer is valid until the\n * hashtable is modified. If the hashtable already contained an equal entry, the existing entry is\n * returned. Check the value of \\a Added to determine whether the returned entry is new or existing.\n *\n * \\remarks Entries are only guaranteed to be 8 byte aligned, even on 64-bit systems.\n */\nPVOID PhAddEntryHashtableEx(\n    _Inout_ PPH_HASHTABLE Hashtable,\n    _In_ PVOID Entry,\n    _Out_opt_ PBOOLEAN Added\n    )\n{\n    return PhpAddEntryHashtable(Hashtable, Entry, TRUE, Added);\n}\n\n/**\n * Clears a hashtable.\n *\n * \\param Hashtable A hashtable object.\n */\nVOID PhClearHashtable(\n    _Inout_ PPH_HASHTABLE Hashtable\n    )\n{\n    if (Hashtable->Count > 0)\n    {\n        memset(Hashtable->Buckets, 0xff, sizeof(ULONG) * Hashtable->AllocatedBuckets);\n        Hashtable->Count = 0;\n        Hashtable->FreeEntry = -1;\n        Hashtable->NextEntry = 0;\n    }\n}\n\n/**\n * Enumerates the entries in a hashtable.\n *\n * \\param Hashtable A hashtable object.\n * \\param Entry A variable which receives a pointer to the hashtable entry. The pointer is valid\n * until the hashtable is modified.\n * \\param EnumerationKey A variable which is initialized to 0 before first calling this function.\n *\n * \\return TRUE if an entry pointer was stored in \\a Entry, FALSE if there are no more entries.\n *\n * \\remarks Do not modify the hashtable while the hashtable is being enumerated (between calls to\n * this function). Otherwise, the function may behave unexpectedly. You may reset the\n * \\a EnumerationKey variable to 0 if you wish to restart the enumeration.\n */\nBOOLEAN PhEnumHashtable(\n    _In_ PPH_HASHTABLE Hashtable,\n    _Out_ PVOID *Entry,\n    _Inout_ PULONG EnumerationKey\n    )\n{\n    while (*EnumerationKey < Hashtable->NextEntry)\n    {\n        PPH_HASHTABLE_ENTRY entry = PH_HASHTABLE_GET_ENTRY(Hashtable, *EnumerationKey);\n\n        (*EnumerationKey)++;\n\n        if (entry->HashCode != -1)\n        {\n            *Entry = &entry->Body;\n            return TRUE;\n        }\n    }\n\n    return FALSE;\n}\n\n/**\n * Locates an entry in a hashtable.\n *\n * \\param Hashtable A hashtable object.\n * \\param Entry An entry representing the entry to find.\n *\n * \\return A pointer to the entry as stored in the hashtable. This pointer is valid until the\n * hashtable is modified. If the entry could not be found, NULL is returned.\n *\n * \\remarks The entry specified in \\a Entry can be a partial entry that is filled in enough so that\n * the comparison and hash functions can work with them.\n */\nPVOID PhFindEntryHashtable(\n    _In_ PPH_HASHTABLE Hashtable,\n    _In_ PVOID Entry\n    )\n{\n    ULONG hashCode;\n    ULONG index;\n    ULONG i;\n    PPH_HASHTABLE_ENTRY entry;\n\n    hashCode = PhpValidateHash(Hashtable->HashFunction(Entry));\n    index = PhpIndexFromHash(Hashtable, hashCode);\n\n    for (i = Hashtable->Buckets[index]; i != -1; i = entry->Next)\n    {\n        entry = PH_HASHTABLE_GET_ENTRY(Hashtable, i);\n\n        if (entry->HashCode == hashCode && Hashtable->EqualFunction(&entry->Body, Entry))\n        {\n            return &entry->Body;\n        }\n    }\n\n    return NULL;\n}\n\n/**\n * Removes an entry from a hashtable.\n *\n * \\param Hashtable A hashtable object.\n * \\param Entry The entry to remove.\n *\n * \\return TRUE if the entry was removed, FALSE if the entry could not be found.\n *\n * \\remarks The entry specified in \\a Entry can be an actual entry pointer returned by\n * PhFindEntryHashtable, or a partial entry.\n */\nBOOLEAN PhRemoveEntryHashtable(\n    _Inout_ PPH_HASHTABLE Hashtable,\n    _In_ PVOID Entry\n    )\n{\n    ULONG hashCode;\n    ULONG index;\n    ULONG i;\n    ULONG previousIndex;\n    PPH_HASHTABLE_ENTRY entry;\n\n    hashCode = PhpValidateHash(Hashtable->HashFunction(Entry));\n    index = PhpIndexFromHash(Hashtable, hashCode);\n    previousIndex = -1;\n\n    for (i = Hashtable->Buckets[index]; i != -1; i = entry->Next)\n    {\n        entry = PH_HASHTABLE_GET_ENTRY(Hashtable, i);\n\n        if (entry->HashCode == hashCode && Hashtable->EqualFunction(&entry->Body, Entry))\n        {\n            // Unlink the entry from the bucket.\n            if (previousIndex == -1)\n            {\n                Hashtable->Buckets[index] = entry->Next;\n            }\n            else\n            {\n                PH_HASHTABLE_GET_ENTRY(Hashtable, previousIndex)->Next = entry->Next;\n            }\n\n            entry->HashCode = -1; // indicates the entry is not being used\n            entry->Next = Hashtable->FreeEntry;\n            Hashtable->FreeEntry = i;\n\n            Hashtable->Count--;\n\n            return TRUE;\n        }\n\n        previousIndex = i;\n    }\n\n    return FALSE;\n}\n\n/**\n * Generates a hash code for a sequence of bytes.\n *\n * \\param Bytes A pointer to a byte array.\n * \\param Length The number of bytes to hash.\n */\nULONG PhHashBytes(\n    _In_reads_(Length) PUCHAR Bytes,\n    _In_ SIZE_T Length\n    )\n{\n    ULONG hash = 0;\n\n    if (Length == 0)\n        return hash;\n\n    // FNV-1a algorithm: http://www.isthe.com/chongo/src/fnv/hash_32a.c\n\n    do\n    {\n        hash ^= *Bytes++;\n        hash *= 0x01000193;\n    } while (--Length != 0);\n\n    return hash;\n}\n\n/**\n * Generates a hash code for a string.\n *\n * \\param String The string to hash.\n * \\param IgnoreCase TRUE for a case-insensitive hash function, otherwise FALSE.\n */\nULONG PhHashStringRef(\n    _In_ PPH_STRINGREF String,\n    _In_ BOOLEAN IgnoreCase\n    )\n{\n    ULONG hash = 0;\n    SIZE_T count;\n    PWCHAR p;\n\n    if (String->Length == 0)\n        return 0;\n\n    count = String->Length / sizeof(WCHAR);\n    p = String->Buffer;\n\n    if (!IgnoreCase)\n    {\n        return PhHashBytes((PUCHAR)String->Buffer, String->Length);\n    }\n    else\n    {\n        do\n        {\n            hash ^= (USHORT)RtlUpcaseUnicodeChar(*p++);\n            hash *= 0x01000193;\n        } while (--count != 0);\n    }\n\n    return hash;\n}\n\nBOOLEAN NTAPI PhpSimpleHashtableEqualFunction(\n    _In_ PVOID Entry1,\n    _In_ PVOID Entry2\n    )\n{\n    PPH_KEY_VALUE_PAIR entry1 = Entry1;\n    PPH_KEY_VALUE_PAIR entry2 = Entry2;\n\n    return entry1->Key == entry2->Key;\n}\n\nULONG NTAPI PhpSimpleHashtableHashFunction(\n    _In_ PVOID Entry\n    )\n{\n    PPH_KEY_VALUE_PAIR entry = Entry;\n\n    return PhHashIntPtr((ULONG_PTR)entry->Key);\n}\n\nPPH_HASHTABLE PhCreateSimpleHashtable(\n    _In_ ULONG InitialCapacity\n    )\n{\n    return PhCreateHashtable(\n        sizeof(PH_KEY_VALUE_PAIR),\n        PhpSimpleHashtableEqualFunction,\n        PhpSimpleHashtableHashFunction,\n        InitialCapacity\n        );\n}\n\nPVOID PhAddItemSimpleHashtable(\n    _Inout_ PPH_HASHTABLE SimpleHashtable,\n    _In_opt_ PVOID Key,\n    _In_opt_ PVOID Value\n    )\n{\n    PH_KEY_VALUE_PAIR entry;\n\n    entry.Key = Key;\n    entry.Value = Value;\n\n    if (PhAddEntryHashtable(SimpleHashtable, &entry))\n        return Value;\n    else\n        return NULL;\n}\n\nPVOID *PhFindItemSimpleHashtable(\n    _In_ PPH_HASHTABLE SimpleHashtable,\n    _In_opt_ PVOID Key\n    )\n{\n    PH_KEY_VALUE_PAIR lookupEntry;\n    PPH_KEY_VALUE_PAIR entry;\n\n    lookupEntry.Key = Key;\n    entry = PhFindEntryHashtable(SimpleHashtable, &lookupEntry);\n\n    if (entry)\n        return &entry->Value;\n    else\n        return NULL;\n}\n\nBOOLEAN PhRemoveItemSimpleHashtable(\n    _Inout_ PPH_HASHTABLE SimpleHashtable,\n    _In_opt_ PVOID Key\n    )\n{\n    PH_KEY_VALUE_PAIR lookupEntry;\n\n    lookupEntry.Key = Key;\n\n    return PhRemoveEntryHashtable(SimpleHashtable, &lookupEntry);\n}\n\n/**\n * Initializes a free list object.\n *\n * \\param FreeList A pointer to the free list object.\n * \\param Size The number of bytes in each allocation.\n * \\param MaximumCount The number of unused allocations to store.\n */\nVOID PhInitializeFreeList(\n    _Out_ PPH_FREE_LIST FreeList,\n    _In_ SIZE_T Size,\n    _In_ ULONG MaximumCount\n    )\n{\n    RtlInitializeSListHead(&FreeList->ListHead);\n    FreeList->Count = 0;\n    FreeList->MaximumCount = MaximumCount;\n    FreeList->Size = Size;\n}\n\n/**\n * Frees resources used by a free list object.\n *\n * \\param FreeList A pointer to the free list object.\n */\nVOID PhDeleteFreeList(\n    _Inout_ PPH_FREE_LIST FreeList\n    )\n{\n    PPH_FREE_LIST_ENTRY entry;\n    PSLIST_ENTRY listEntry;\n\n    listEntry = RtlInterlockedFlushSList(&FreeList->ListHead);\n\n    while (listEntry)\n    {\n        entry = CONTAINING_RECORD(listEntry, PH_FREE_LIST_ENTRY, ListEntry);\n        listEntry = listEntry->Next;\n        PhFree(entry);\n    }\n}\n\n/**\n * Allocates a block of memory from a free list.\n *\n * \\param FreeList A pointer to a free list object.\n *\n * \\return A pointer to the allocated block of memory. The memory must be freed using\n * PhFreeToFreeList(). The block is guaranteed to be aligned at MEMORY_ALLOCATION_ALIGNMENT bytes.\n */\nPVOID PhAllocateFromFreeList(\n    _Inout_ PPH_FREE_LIST FreeList\n    )\n{\n    PPH_FREE_LIST_ENTRY entry;\n    PSLIST_ENTRY listEntry;\n\n    listEntry = RtlInterlockedPopEntrySList(&FreeList->ListHead);\n\n    if (listEntry)\n    {\n        _InterlockedDecrement((PLONG)&FreeList->Count);\n        entry = CONTAINING_RECORD(listEntry, PH_FREE_LIST_ENTRY, ListEntry);\n    }\n    else\n    {\n        entry = PhAllocate(FIELD_OFFSET(PH_FREE_LIST_ENTRY, Body) + FreeList->Size);\n    }\n\n    return &entry->Body;\n}\n\n/**\n * Frees a block of memory to a free list.\n *\n * \\param FreeList A pointer to a free list object.\n * \\param Memory A pointer to a block of memory.\n */\nVOID PhFreeToFreeList(\n    _Inout_ PPH_FREE_LIST FreeList,\n    _In_ PVOID Memory\n    )\n{\n    PPH_FREE_LIST_ENTRY entry;\n\n    entry = CONTAINING_RECORD(Memory, PH_FREE_LIST_ENTRY, Body);\n\n    // We don't enforce Count <= MaximumCount (that would require locking),\n    // but we do check it.\n    if (FreeList->Count < FreeList->MaximumCount)\n    {\n        RtlInterlockedPushEntrySList(&FreeList->ListHead, &entry->ListEntry);\n        _InterlockedIncrement((PLONG)&FreeList->Count);\n    }\n    else\n    {\n        PhFree(entry);\n    }\n}\n\n/**\n * Initializes a callback object.\n *\n * \\param Callback A pointer to a callback object.\n */\nVOID PhInitializeCallback(\n    _Out_ PPH_CALLBACK Callback\n    )\n{\n    InitializeListHead(&Callback->ListHead);\n    PhInitializeQueuedLock(&Callback->ListLock);\n    PhInitializeCondition(&Callback->BusyCondition);\n}\n\n/**\n * Frees resources used by a callback object.\n *\n * \\param Callback A pointer to a callback object.\n */\nVOID PhDeleteCallback(\n    _Inout_ PPH_CALLBACK Callback\n    )\n{\n    // Nothing for now\n}\n\n/**\n * Registers a callback function to be notified.\n *\n * \\param Callback A pointer to a callback object.\n * \\param Function The callback function.\n * \\param Context A user-defined value to pass to the callback function.\n * \\param Registration A variable which receives registration information for the callback. Do not\n * modify the contents of this structure and do not free the storage for this structure until you\n * have unregistered the callback.\n */\nVOID PhRegisterCallback(\n    _Inout_ PPH_CALLBACK Callback,\n    _In_ PPH_CALLBACK_FUNCTION Function,\n    _In_opt_ PVOID Context,\n    _Out_ PPH_CALLBACK_REGISTRATION Registration\n    )\n{\n    PhRegisterCallbackEx(\n        Callback,\n        Function,\n        Context,\n        0,\n        Registration\n        );\n}\n\n/**\n * Registers a callback function to be notified.\n *\n * \\param Callback A pointer to a callback object.\n * \\param Function The callback function.\n * \\param Context A user-defined value to pass to the callback function.\n * \\param Flags A combination of flags controlling the callback. Set this parameter to 0.\n * \\param Registration A variable which receives registration information for the callback. Do not\n * modify the contents of this structure and do not free the storage for this structure until you\n * have unregistered the callback.\n */\nVOID PhRegisterCallbackEx(\n    _Inout_ PPH_CALLBACK Callback,\n    _In_ PPH_CALLBACK_FUNCTION Function,\n    _In_opt_ PVOID Context,\n    _In_ USHORT Flags,\n    _Out_ PPH_CALLBACK_REGISTRATION Registration\n    )\n{\n    Registration->Function = Function;\n    Registration->Context = Context;\n    Registration->Busy = 0;\n    Registration->Unregistering = FALSE;\n    Registration->Flags = Flags;\n\n    PhAcquireQueuedLockExclusive(&Callback->ListLock);\n    InsertTailList(&Callback->ListHead, &Registration->ListEntry);\n    PhReleaseQueuedLockExclusive(&Callback->ListLock);\n}\n\n/**\n * Unregisters a callback function.\n *\n * \\param Callback A pointer to a callback object.\n * \\param Registration The structure returned by PhRegisterCallback().\n *\n * \\remarks It is guaranteed that the callback function will not be in execution once this function\n * returns. Attempting to unregister a callback function from within the same function will result\n * in a deadlock.\n */\nVOID PhUnregisterCallback(\n    _Inout_ PPH_CALLBACK Callback,\n    _Inout_ PPH_CALLBACK_REGISTRATION Registration\n    )\n{\n    Registration->Unregistering = TRUE;\n\n    PhAcquireQueuedLockExclusive(&Callback->ListLock);\n\n    // Wait for the callback to be unbusy.\n    while (Registration->Busy)\n        PhWaitForCondition(&Callback->BusyCondition, &Callback->ListLock, NULL);\n\n    RemoveEntryList(&Registration->ListEntry);\n\n    PhReleaseQueuedLockExclusive(&Callback->ListLock);\n}\n\n/**\n * Notifies all registered callback functions.\n *\n * \\param Callback A pointer to a callback object.\n * \\param Parameter A value to pass to all callback functions.\n */\nVOID PhInvokeCallback(\n    _In_ PPH_CALLBACK Callback,\n    _In_opt_ PVOID Parameter\n    )\n{\n    PLIST_ENTRY listEntry;\n\n    PhAcquireQueuedLockShared(&Callback->ListLock);\n\n    listEntry = Callback->ListHead.Flink;\n\n    while (listEntry != &Callback->ListHead)\n    {\n        PPH_CALLBACK_REGISTRATION registration;\n        LONG busy;\n\n        registration = CONTAINING_RECORD(listEntry, PH_CALLBACK_REGISTRATION, ListEntry);\n\n        // Don't bother executing the callback function if it is being unregistered.\n        if (registration->Unregistering)\n            continue;\n\n        _InterlockedIncrement(&registration->Busy);\n\n        // Execute the callback function.\n\n        PhReleaseQueuedLockShared(&Callback->ListLock);\n        registration->Function(\n            Parameter,\n            registration->Context\n            );\n        PhAcquireQueuedLockShared(&Callback->ListLock);\n\n        busy = _InterlockedDecrement(&registration->Busy);\n\n        if (registration->Unregistering && busy == 0)\n        {\n            // Someone started unregistering while the callback function was executing, and we must\n            // wake them.\n            PhPulseAllCondition(&Callback->BusyCondition);\n        }\n\n        listEntry = listEntry->Flink;\n    }\n\n    PhReleaseQueuedLockShared(&Callback->ListLock);\n}\n\n/**\n * Retrieves a prime number bigger than or equal to the specified number.\n */\nULONG PhGetPrimeNumber(\n    _In_ ULONG Minimum\n    )\n{\n    ULONG i, j;\n\n    for (i = 0; i < sizeof(PhpPrimeNumbers) / sizeof(ULONG); i++)\n    {\n        if (PhpPrimeNumbers[i] >= Minimum)\n            return PhpPrimeNumbers[i];\n    }\n\n    for (i = Minimum | 1; i < MAXLONG; i += 2)\n    {\n        ULONG sqrtI = (ULONG)sqrt(i);\n\n        for (j = 3; j <= sqrtI; j += 2)\n        {\n            if (i % j == 0)\n            {\n                // Not a prime.\n                goto NextPrime;\n            }\n        }\n\n        // Success.\n        return i;\nNextPrime:\n        NOTHING;\n    }\n\n    return Minimum;\n}\n\n/**\n * Rounds up a number to the next power of two.\n */\nULONG PhRoundUpToPowerOfTwo(\n    _In_ ULONG Number\n    )\n{\n    Number--;\n    Number |= Number >> 1;\n    Number |= Number >> 2;\n    Number |= Number >> 4;\n    Number |= Number >> 8;\n    Number |= Number >> 16;\n    Number++;\n\n    return Number;\n}\n\n/**\n * Performs exponentiation.\n */\nULONG PhExponentiate(\n    _In_ ULONG Base,\n    _In_ ULONG Exponent\n    )\n{\n    ULONG result = 1;\n\n    while (Exponent)\n    {\n        if (Exponent & 1)\n            result *= Base;\n\n        Exponent >>= 1;\n        Base *= Base;\n    }\n\n    return result;\n}\n\n/**\n * Performs 64-bit exponentiation.\n */\nULONG64 PhExponentiate64(\n    _In_ ULONG64 Base,\n    _In_ ULONG Exponent\n    )\n{\n    ULONG64 result = 1;\n\n    while (Exponent)\n    {\n        if (Exponent & 1)\n            result *= Base;\n\n        Exponent >>= 1;\n        Base *= Base;\n    }\n\n    return result;\n}\n\n/**\n * Converts a sequence of hexadecimal digits into a byte array.\n *\n * \\param String A string containing hexadecimal digits to convert. The string must have an even\n * number of digits, because each pair of hexadecimal digits represents one byte. Example:\n * \"129a2eff5c0b\".\n * \\param Buffer The output buffer.\n *\n * \\return TRUE if the string was successfully converted, otherwise FALSE.\n */\nBOOLEAN PhHexStringToBuffer(\n    _In_ PPH_STRINGREF String,\n    _Out_writes_bytes_(String->Length / sizeof(WCHAR) / 2) PUCHAR Buffer\n    )\n{\n    SIZE_T i;\n    SIZE_T length;\n\n    // The string must have an even length.\n    if ((String->Length / sizeof(WCHAR)) & 1)\n        return FALSE;\n\n    length = String->Length / sizeof(WCHAR) / 2;\n\n    for (i = 0; i < length; i++)\n    {\n        Buffer[i] =\n            (UCHAR)(PhCharToInteger[(UCHAR)String->Buffer[i * 2]] << 4) +\n            (UCHAR)PhCharToInteger[(UCHAR)String->Buffer[i * 2 + 1]];\n    }\n\n    return TRUE;\n}\n\n/**\n * Converts a byte array into a sequence of hexadecimal digits.\n *\n * \\param Buffer The input buffer.\n * \\param Length The number of bytes to convert.\n *\n * \\return A string containing a sequence of hexadecimal digits.\n */\nPPH_STRING PhBufferToHexString(\n    _In_reads_bytes_(Length) PUCHAR Buffer,\n    _In_ ULONG Length\n    )\n{\n    return PhBufferToHexStringEx(Buffer, Length, FALSE);\n}\n\n/**\n * Converts a byte array into a sequence of hexadecimal digits.\n *\n * \\param Buffer The input buffer.\n * \\param Length The number of bytes to convert.\n * \\param UpperCase TRUE to use uppercase characters, otherwise FALSE.\n *\n * \\return A string containing a sequence of hexadecimal digits.\n */\nPPH_STRING PhBufferToHexStringEx(\n    _In_reads_bytes_(Length) PUCHAR Buffer,\n    _In_ ULONG Length,\n    _In_ BOOLEAN UpperCase\n    )\n{\n    PCHAR table;\n    PPH_STRING string;\n    ULONG i;\n\n    if (UpperCase)\n        table = PhIntegerToCharUpper;\n    else\n        table = PhIntegerToChar;\n\n    string = PhCreateStringEx(NULL, Length * 2 * sizeof(WCHAR));\n\n    for (i = 0; i < Length; i++)\n    {\n        string->Buffer[i * 2] = table[Buffer[i] >> 4];\n        string->Buffer[i * 2 + 1] = table[Buffer[i] & 0xf];\n    }\n\n    return string;\n}\n\n/**\n * Converts a string to an integer.\n *\n * \\param String The string to process.\n * \\param Base The base which the string uses to represent the integer. The maximum value is 69.\n * \\param Integer The resulting integer.\n */\nBOOLEAN PhpStringToInteger64(\n    _In_ PPH_STRINGREF String,\n    _In_ ULONG Base,\n    _Out_ PULONG64 Integer\n    )\n{\n    BOOLEAN valid = TRUE;\n    ULONG64 result;\n    SIZE_T length;\n    SIZE_T i;\n\n    length = String->Length / sizeof(WCHAR);\n    result = 0;\n\n    for (i = 0; i < length; i++)\n    {\n        ULONG value;\n\n        value = PhCharToInteger[(UCHAR)String->Buffer[i]];\n\n        if (value < Base)\n            result = result * Base + value;\n        else\n            valid = FALSE;\n    }\n\n    *Integer = result;\n\n    return valid;\n}\n\n/**\n * Converts a string to an integer.\n *\n * \\param String The string to process.\n * \\param Base The base which the string uses to represent the integer. The maximum value is 69. If\n * the parameter is 0, the base is inferred from the string.\n * \\param Integer The resulting integer.\n *\n * \\remarks If \\a Base is 0, the following prefixes may be used to indicate bases:\n *\n * \\li \\c 0x Base 16.\n * \\li \\c 0o Base 8.\n * \\li \\c 0b Base 2.\n * \\li \\c 0t Base 3.\n * \\li \\c 0q Base 4.\n * \\li \\c 0w Base 12.\n * \\li \\c 0r Base 32.\n *\n * If there is no recognized prefix, base 10 is used.\n */\nBOOLEAN PhStringToInteger64(\n    _In_ PPH_STRINGREF String,\n    _In_opt_ ULONG Base,\n    _Out_opt_ PLONG64 Integer\n    )\n{\n    BOOLEAN valid;\n    ULONG64 result;\n    PH_STRINGREF string;\n    BOOLEAN negative;\n    ULONG base;\n\n    if (Base > 69)\n        return FALSE;\n\n    string = *String;\n    negative = FALSE;\n\n    if (string.Length != 0 && (string.Buffer[0] == '-' || string.Buffer[0] == '+'))\n    {\n        if (string.Buffer[0] == '-')\n            negative = TRUE;\n\n        PhSkipStringRef(&string, sizeof(WCHAR));\n    }\n\n    // If the caller specified a base, don't perform any additional processing.\n\n    if (Base)\n    {\n        base = Base;\n    }\n    else\n    {\n        base = 10;\n\n        if (string.Length >= 2 * sizeof(WCHAR) && string.Buffer[0] == '0')\n        {\n            switch (string.Buffer[1])\n            {\n            case 'x':\n            case 'X':\n                base = 16;\n                break;\n            case 'o':\n            case 'O':\n                base = 8;\n                break;\n            case 'b':\n            case 'B':\n                base = 2;\n                break;\n            case 't': // ternary\n            case 'T':\n                base = 3;\n                break;\n            case 'q': // quaternary\n            case 'Q':\n                base = 4;\n                break;\n            case 'w': // base 12\n            case 'W':\n                base = 12;\n                break;\n            case 'r': // base 32\n            case 'R':\n                base = 32;\n                break;\n            }\n\n            if (base != 10)\n                PhSkipStringRef(&string, 2 * sizeof(WCHAR));\n        }\n    }\n\n    valid = PhpStringToInteger64(&string, base, &result);\n\n    if (Integer)\n        *Integer = negative ? -(LONG64)result : result;\n\n    return valid;\n}\n\nBOOLEAN PhpStringToDouble(\n    _In_ PPH_STRINGREF String,\n    _In_ ULONG Base,\n    _Out_ DOUBLE *Double\n    )\n{\n    BOOLEAN valid = TRUE;\n    BOOLEAN dotSeen = FALSE;\n    DOUBLE result;\n    DOUBLE fraction;\n    SIZE_T length;\n    SIZE_T i;\n\n    length = String->Length / sizeof(WCHAR);\n    result = 0;\n    fraction = 1;\n\n    for (i = 0; i < length; i++)\n    {\n        if (String->Buffer[i] == '.')\n        {\n            if (!dotSeen)\n                dotSeen = TRUE;\n            else\n                valid = FALSE;\n        }\n        else\n        {\n            ULONG value;\n\n            value = PhCharToInteger[(UCHAR)String->Buffer[i]];\n\n            if (value < Base)\n            {\n                if (!dotSeen)\n                {\n                    result = result * Base + value;\n                }\n                else\n                {\n                    fraction /= Base;\n                    result = result + value * fraction;\n                }\n            }\n            else\n            {\n                valid = FALSE;\n            }\n        }\n    }\n\n    *Double = result;\n\n    return valid;\n}\n\n/**\n * Converts a string to a double-precision floating point value.\n *\n * \\param String The string to process.\n * \\param Base Reserved.\n * \\param Double The resulting double value.\n */\nBOOLEAN PhStringToDouble(\n    _In_ PPH_STRINGREF String,\n    _Reserved_ ULONG Base,\n    _Out_opt_ DOUBLE *Double\n    )\n{\n    BOOLEAN valid;\n    DOUBLE result;\n    PH_STRINGREF string;\n    BOOLEAN negative;\n\n    string = *String;\n    negative = FALSE;\n\n    if (string.Length != 0 && (string.Buffer[0] == '-' || string.Buffer[0] == '+'))\n    {\n        if (string.Buffer[0] == '-')\n            negative = TRUE;\n\n        PhSkipStringRef(&string, sizeof(WCHAR));\n    }\n\n    valid = PhpStringToDouble(&string, 10, &result);\n\n    if (Double)\n        *Double = negative ? -result : result;\n\n    return valid;\n}\n\n/**\n * Converts an integer to a string.\n *\n * \\param Integer The integer to process.\n * \\param Base The base which the integer is represented with. The maximum value is 69. The base\n * cannot be 1. If the parameter is 0, the base used is 10.\n * \\param Signed TRUE if \\a Integer is a signed value, otherwise FALSE.\n *\n * \\return The resulting string, or NULL if an error occurred.\n */\nPPH_STRING PhIntegerToString64(\n    _In_ LONG64 Integer,\n    _In_opt_ ULONG Base,\n    _In_ BOOLEAN Signed\n    )\n{\n    PH_FORMAT format;\n\n    if (Base == 1 || Base > 69)\n        return NULL;\n\n    if (Signed)\n        PhInitFormatI64D(&format, Integer);\n    else\n        PhInitFormatI64U(&format, Integer);\n\n    if (Base != 0)\n    {\n        format.Type |= FormatUseRadix;\n        format.Radix = (UCHAR)Base;\n    }\n\n    return PhFormat(&format, 1, 0);\n}\n\nVOID PhPrintTimeSpan(\n    _Out_writes_(PH_TIMESPAN_STR_LEN_1) PWSTR Destination,\n    _In_ ULONG64 Ticks,\n    _In_opt_ ULONG Mode\n    )\n{\n    switch (Mode)\n    {\n    case PH_TIMESPAN_HMSM:\n        _snwprintf(\n            Destination,\n            PH_TIMESPAN_STR_LEN,\n            L\"%02I64u:%02I64u:%02I64u.%03I64u\",\n            PH_TICKS_PARTIAL_HOURS(Ticks),\n            PH_TICKS_PARTIAL_MIN(Ticks),\n            PH_TICKS_PARTIAL_SEC(Ticks),\n            PH_TICKS_PARTIAL_MS(Ticks)\n            );\n        break;\n    case PH_TIMESPAN_DHMS:\n        _snwprintf(\n            Destination,\n            PH_TIMESPAN_STR_LEN,\n            L\"%I64u:%02I64u:%02I64u:%02I64u\",\n            PH_TICKS_PARTIAL_DAYS(Ticks),\n            PH_TICKS_PARTIAL_HOURS(Ticks),\n            PH_TICKS_PARTIAL_MIN(Ticks),\n            PH_TICKS_PARTIAL_SEC(Ticks)\n            );\n        break;\n    default:\n        _snwprintf(\n            Destination,\n            PH_TIMESPAN_STR_LEN,\n            L\"%02I64u:%02I64u:%02I64u\",\n            PH_TICKS_PARTIAL_HOURS(Ticks),\n            PH_TICKS_PARTIAL_MIN(Ticks),\n            PH_TICKS_PARTIAL_SEC(Ticks)\n            );\n        break;\n    }\n}\n\n/**\n * Fills a memory block with a ULONG pattern.\n *\n * \\param Memory The memory block. The block must be 4 byte aligned.\n * \\param Value The ULONG pattern.\n * \\param Count The number of elements.\n */\nVOID PhFillMemoryUlong(\n    _Inout_updates_(Count) _Needs_align_(4) PULONG Memory,\n    _In_ ULONG Value,\n    _In_ SIZE_T Count\n    )\n{\n    __m128i pattern;\n    SIZE_T count;\n\n    if (PhpVectorLevel < PH_VECTOR_LEVEL_SSE2)\n    {\n        if (Count != 0)\n        {\n            do\n            {\n                *Memory++ = Value;\n            } while (--Count != 0);\n        }\n\n        return;\n    }\n\n    if ((ULONG_PTR)Memory & 0xf)\n    {\n        switch ((ULONG_PTR)Memory & 0xf)\n        {\n        case 0x4:\n            if (Count >= 1)\n            {\n                *Memory++ = Value;\n                Count--;\n            }\n            __fallthrough;\n        case 0x8:\n            if (Count >= 1)\n            {\n                *Memory++ = Value;\n                Count--;\n            }\n            __fallthrough;\n        case 0xc:\n            if (Count >= 1)\n            {\n                *Memory++ = Value;\n                Count--;\n            }\n            break;\n        }\n    }\n\n    pattern = _mm_set1_epi32(Value);\n    count = Count / 4;\n\n    if (count != 0)\n    {\n        do\n        {\n            _mm_store_si128((__m128i *)Memory, pattern);\n            Memory += 4;\n        } while (--count != 0);\n    }\n\n    switch (Count & 0x3)\n    {\n    case 0x3:\n        *Memory++ = Value;\n        __fallthrough;\n    case 0x2:\n        *Memory++ = Value;\n        __fallthrough;\n    case 0x1:\n        *Memory++ = Value;\n        break;\n    }\n}\n\n/**\n * Divides an array of numbers by a number.\n *\n * \\param A The destination array, divided by \\a B.\n * \\param B The number.\n * \\param Count The number of elements.\n */\nVOID PhDivideSinglesBySingle(\n    _Inout_updates_(Count) PFLOAT A,\n    _In_ FLOAT B,\n    _In_ SIZE_T Count\n    )\n{\n    PFLOAT endA;\n    __m128 b;\n\n    if (PhpVectorLevel < PH_VECTOR_LEVEL_SSE2)\n    {\n        while (Count--)\n            *A++ /= B;\n\n        return;\n    }\n\n    if ((ULONG_PTR)A & 0xf)\n    {\n        switch ((ULONG_PTR)A & 0xf)\n        {\n        case 0x4:\n            if (Count >= 1)\n            {\n                *A++ /= B;\n                Count--;\n            }\n            __fallthrough;\n        case 0x8:\n            if (Count >= 1)\n            {\n                *A++ /= B;\n                Count--;\n            }\n            __fallthrough;\n        case 0xc:\n            if (Count >= 1)\n            {\n                *A++ /= B;\n                Count--;\n            }\n            else\n            {\n                return; // essential; A may not be aligned properly\n            }\n            break;\n        }\n    }\n\n    endA = (PFLOAT)((ULONG_PTR)(A + Count) & ~0xf);\n    b = _mm_load1_ps(&B);\n\n    while (A != endA)\n    {\n        __m128 a;\n\n        a = _mm_load_ps(A);\n        a = _mm_div_ps(a, b);\n        _mm_store_ps(A, a);\n\n        A += 4;\n    }\n\n    switch (Count & 0x3)\n    {\n    case 0x3:\n        *A++ /= B;\n        __fallthrough;\n    case 0x2:\n        *A++ /= B;\n        __fallthrough;\n    case 0x1:\n        *A++ /= B;\n        break;\n    }\n}\n"
  },
  {
    "path": "third_party/phlib/circbuf.c",
    "content": "#include <phbase.h>\n#include <circbuf.h>\n\n#undef T\n#define T ULONG\n#include \"circbuf_i.h\"\n\n#undef T\n#define T ULONG64\n#include \"circbuf_i.h\"\n\n#undef T\n#define T PVOID\n#include \"circbuf_i.h\"\n\n#undef T\n#define T SIZE_T\n#include \"circbuf_i.h\"\n\n#undef T\n#define T FLOAT\n#include \"circbuf_i.h\"\n"
  },
  {
    "path": "third_party/phlib/circbuf_i.h",
    "content": "#ifdef T\n\n#include <templ.h>\n\nVOID T___(PhInitializeCircularBuffer, T)(\n    _Out_ T___(PPH_CIRCULAR_BUFFER, T) Buffer,\n    _In_ ULONG Size\n    )\n{\n#ifdef PH_CIRCULAR_BUFFER_POWER_OF_TWO_SIZE\n    Buffer->Size = PhRoundUpToPowerOfTwo(Size);\n    Buffer->SizeMinusOne = Buffer->Size - 1;\n#else\n    Buffer->Size = Size;\n#endif\n\n    Buffer->Count = 0;\n    Buffer->Index = 0;\n    Buffer->Data = PhAllocate(sizeof(T) * Buffer->Size);\n}\n\nVOID T___(PhDeleteCircularBuffer, T)(\n    _Inout_ T___(PPH_CIRCULAR_BUFFER, T) Buffer\n    )\n{\n    PhFree(Buffer->Data);\n}\n\nVOID T___(PhResizeCircularBuffer, T)(\n    _Inout_ T___(PPH_CIRCULAR_BUFFER, T) Buffer,\n    _In_ ULONG NewSize\n    )\n{\n    T *newData;\n    ULONG tailSize;\n    ULONG headSize;\n\n#ifdef PH_CIRCULAR_BUFFER_POWER_OF_TWO_SIZE\n    NewSize = PhRoundUpToPowerOfTwo(NewSize);\n#endif\n\n    // If we're not actually resizing it, return.\n    if (NewSize == Buffer->Size)\n        return;\n\n    newData = PhAllocate(sizeof(T) * NewSize);\n    tailSize = (ULONG)(Buffer->Size - Buffer->Index);\n    headSize = Buffer->Count - tailSize;\n\n    if (NewSize > Buffer->Size)\n    {\n        // Copy the tail, then the head.\n        memcpy(newData, &Buffer->Data[Buffer->Index], sizeof(T) * tailSize);\n        memcpy(&newData[tailSize], Buffer->Data, sizeof(T) * headSize);\n        Buffer->Index = 0;\n    }\n    else\n    {\n        if (tailSize >= NewSize)\n        {\n            // Copy only a part of the tail.\n            memcpy(newData, &Buffer->Data[Buffer->Index], sizeof(T) * NewSize);\n            Buffer->Index = 0;\n        }\n        else\n        {\n            // Copy the tail, then only part of the head.\n            memcpy(newData, &Buffer->Data[Buffer->Index], sizeof(T) * tailSize);\n            memcpy(&newData[tailSize], Buffer->Data, sizeof(T) * (NewSize - tailSize));\n            Buffer->Index = 0;\n        }\n\n        // Since we're making the circular buffer smaller, limit the count.\n        if (Buffer->Count > NewSize)\n            Buffer->Count = NewSize;\n    }\n\n    Buffer->Data = newData;\n    Buffer->Size = NewSize;\n#ifdef PH_CIRCULAR_BUFFER_POWER_OF_TWO_SIZE\n    Buffer->SizeMinusOne = NewSize - 1;\n#endif\n}\n\nVOID T___(PhClearCircularBuffer, T)(\n    _Inout_ T___(PPH_CIRCULAR_BUFFER, T) Buffer\n    )\n{\n    Buffer->Count = 0;\n    Buffer->Index = 0;\n}\n\nVOID T___(PhCopyCircularBuffer, T)(\n    _Inout_ T___(PPH_CIRCULAR_BUFFER, T) Buffer,\n    _Out_writes_(Count) T *Destination,\n    _In_ ULONG Count\n    )\n{\n    ULONG tailSize;\n    ULONG headSize;\n\n    tailSize = (ULONG)(Buffer->Size - Buffer->Index);\n    headSize = Buffer->Count - tailSize;\n\n    if (Count > Buffer->Count)\n        Count = Buffer->Count;\n\n    if (tailSize >= Count)\n    {\n        // Copy only a part of the tail.\n        memcpy(Destination, &Buffer->Data[Buffer->Index], sizeof(T) * Count);\n    }\n    else\n    {\n        // Copy the tail, then only part of the head.\n        memcpy(Destination, &Buffer->Data[Buffer->Index], sizeof(T) * tailSize);\n        memcpy(&Destination[tailSize], Buffer->Data, sizeof(T) * (Count - tailSize));\n    }\n}\n\n#endif\n"
  },
  {
    "path": "third_party/phlib/colorbox.c",
    "content": "/*\n * Process Hacker -\n *   color picker\n *\n * Copyright (C) 2010 wj32\n *\n * This file is part of Process Hacker.\n *\n * Process Hacker is free software; you can redistribute it and/or modify\n * it under the terms of the GNU General Public License as published by\n * the Free Software Foundation, either version 3 of the License, or\n * (at your option) any later version.\n *\n * Process Hacker is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n * GNU General Public License for more details.\n *\n * You should have received a copy of the GNU General Public License\n * along with Process Hacker.  If not, see <http://www.gnu.org/licenses/>.\n */\n\n#include <ph.h>\n#include <colorbox.h>\n\n#include <commdlg.h>\n\n#include <guisup.h>\n\ntypedef struct _PHP_COLORBOX_CONTEXT\n{\n    COLORREF SelectedColor;\n    BOOLEAN Hot;\n    BOOLEAN HasFocus;\n} PHP_COLORBOX_CONTEXT, *PPHP_COLORBOX_CONTEXT;\n\nLRESULT CALLBACK PhpColorBoxWndProc(\n    _In_ HWND hwnd,\n    _In_ UINT uMsg,\n    _In_ WPARAM wParam,\n    _In_ LPARAM lParam\n    );\n\nBOOLEAN PhColorBoxInitialization(\n    VOID\n    )\n{\n    WNDCLASSEX c = { sizeof(c) };\n\n    c.style = CS_GLOBALCLASS;\n    c.lpfnWndProc = PhpColorBoxWndProc;\n    c.cbClsExtra = 0;\n    c.cbWndExtra = sizeof(PVOID);\n    c.hInstance = PhInstanceHandle;\n    c.hIcon = NULL;\n    c.hCursor = LoadCursor(NULL, IDC_ARROW);\n    c.hbrBackground = NULL;\n    c.lpszMenuName = NULL;\n    c.lpszClassName = PH_COLORBOX_CLASSNAME;\n    c.hIconSm = NULL;\n\n    if (!RegisterClassEx(&c))\n        return FALSE;\n\n    return TRUE;\n}\n\nVOID PhpCreateColorBoxContext(\n    _Out_ PPHP_COLORBOX_CONTEXT *Context\n    )\n{\n    PPHP_COLORBOX_CONTEXT context;\n\n    context = PhAllocate(sizeof(PHP_COLORBOX_CONTEXT));\n    memset(context, 0, sizeof(PHP_COLORBOX_CONTEXT));\n    *Context = context;\n}\n\nVOID PhpFreeColorBoxContext(\n    _In_ _Post_invalid_ PPHP_COLORBOX_CONTEXT Context\n    )\n{\n    PhFree(Context);\n}\n\nVOID PhpChooseColor(\n    _In_ HWND hwnd,\n    _In_ PPHP_COLORBOX_CONTEXT Context\n    )\n{\n    CHOOSECOLOR chooseColor = { sizeof(chooseColor) };\n    COLORREF customColors[16] = { 0 };\n\n    chooseColor.hwndOwner = hwnd;\n    chooseColor.rgbResult = Context->SelectedColor;\n    chooseColor.lpCustColors = customColors;\n    chooseColor.Flags = CC_ANYCOLOR | CC_FULLOPEN | CC_RGBINIT;\n\n    if (ChooseColor(&chooseColor))\n    {\n        Context->SelectedColor = chooseColor.rgbResult;\n        InvalidateRect(hwnd, NULL, TRUE);\n    }\n}\n\nLRESULT CALLBACK PhpColorBoxWndProc(\n    _In_ HWND hwnd,\n    _In_ UINT uMsg,\n    _In_ WPARAM wParam,\n    _In_ LPARAM lParam\n    )\n{\n    PPHP_COLORBOX_CONTEXT context;\n\n    context = (PPHP_COLORBOX_CONTEXT)GetWindowLongPtr(hwnd, 0);\n\n    if (uMsg == WM_CREATE)\n    {\n        PhpCreateColorBoxContext(&context);\n        SetWindowLongPtr(hwnd, 0, (LONG_PTR)context);\n    }\n\n    if (!context)\n        return DefWindowProc(hwnd, uMsg, wParam, lParam);\n\n    switch (uMsg)\n    {\n    case WM_CREATE:\n        {\n            // Nothing\n        }\n        break;\n    case WM_DESTROY:\n        {\n            SetWindowLongPtr(hwnd, 0, (LONG_PTR)NULL);\n            PhpFreeColorBoxContext(context);\n        }\n        break;\n    case WM_PAINT:\n        {\n            PAINTSTRUCT paintStruct;\n            RECT clientRect;\n            HDC hdc;\n\n            if (hdc = BeginPaint(hwnd, &paintStruct))\n            {\n                GetClientRect(hwnd, &clientRect);\n\n                // Border color\n                SetDCPenColor(hdc, RGB(0x44, 0x44, 0x44));\n\n                // Fill color\n                if (!context->Hot && !context->HasFocus)\n                    SetDCBrushColor(hdc, context->SelectedColor);\n                else\n                    SetDCBrushColor(hdc, PhMakeColorBrighter(context->SelectedColor, 64));\n\n                // Draw the rectangle.\n                SelectObject(hdc, GetStockObject(DC_PEN));\n                SelectObject(hdc, GetStockObject(DC_BRUSH));\n                Rectangle(hdc, clientRect.left, clientRect.top, clientRect.right, clientRect.bottom);\n\n                EndPaint(hwnd, &paintStruct);\n            }\n        }\n        return 0;\n    case WM_ERASEBKGND:\n        return 1;\n    case WM_MOUSEMOVE:\n        {\n            if (!context->Hot)\n            {\n                TRACKMOUSEEVENT trackMouseEvent = { sizeof(trackMouseEvent) };\n\n                context->Hot = TRUE;\n                InvalidateRect(hwnd, NULL, TRUE);\n\n                trackMouseEvent.dwFlags = TME_LEAVE;\n                trackMouseEvent.hwndTrack = hwnd;\n                TrackMouseEvent(&trackMouseEvent);\n            }\n        }\n        break;\n    case WM_MOUSELEAVE:\n        {\n            context->Hot = FALSE;\n            InvalidateRect(hwnd, NULL, TRUE);\n        }\n        break;\n    case WM_LBUTTONDOWN:\n        {\n            PhpChooseColor(hwnd, context);\n        }\n        break;\n    case WM_SETFOCUS:\n        {\n            context->HasFocus = TRUE;\n            InvalidateRect(hwnd, NULL, TRUE);\n        }\n        return 0;\n    case WM_KILLFOCUS:\n        {\n            context->HasFocus = FALSE;\n            InvalidateRect(hwnd, NULL, TRUE);\n        }\n        return 0;\n    case WM_GETDLGCODE:\n        if (wParam == VK_RETURN)\n            return DLGC_WANTMESSAGE;\n        return 0;\n    case WM_KEYDOWN:\n        {\n            switch (wParam)\n            {\n            case VK_SPACE:\n            case VK_RETURN:\n                PhpChooseColor(hwnd, context);\n                break;\n            }\n        }\n        break;\n    case CBCM_SETCOLOR:\n        context->SelectedColor = (COLORREF)wParam;\n        return TRUE;\n    case CBCM_GETCOLOR:\n        return (LRESULT)context->SelectedColor;\n    }\n\n    return DefWindowProc(hwnd, uMsg, wParam, lParam);\n}\n"
  },
  {
    "path": "third_party/phlib/cpysave.c",
    "content": "/*\n * Process Hacker -\n *   copy/save code for listviews and treelists\n *\n * Copyright (C) 2010-2012 wj32\n *\n * This file is part of Process Hacker.\n *\n * Process Hacker is free software; you can redistribute it and/or modify\n * it under the terms of the GNU General Public License as published by\n * the Free Software Foundation, either version 3 of the License, or\n * (at your option) any later version.\n *\n * Process Hacker is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n * GNU General Public License for more details.\n *\n * You should have received a copy of the GNU General Public License\n * along with Process Hacker.  If not, see <http://www.gnu.org/licenses/>.\n */\n\n#include <ph.h>\n#include <cpysave.h>\n\n#include <guisup.h>\n#include <treenew.h>\n\n#define TAB_SIZE 8\n\nVOID PhpEscapeStringForCsv(\n    _Inout_ PPH_STRING_BUILDER StringBuilder,\n    _In_ PPH_STRING String\n    )\n{\n    SIZE_T i;\n    SIZE_T length;\n    PWCHAR runStart;\n    SIZE_T runLength;\n\n    length = String->Length / sizeof(WCHAR);\n    runStart = NULL;\n\n    for (i = 0; i < length; i++)\n    {\n        switch (String->Buffer[i])\n        {\n        case '\\\"':\n            if (runStart)\n            {\n                PhAppendStringBuilderEx(StringBuilder, runStart, runLength * sizeof(WCHAR));\n                runStart = NULL;\n            }\n\n            PhAppendStringBuilder2(StringBuilder, L\"\\\"\\\"\");\n\n            break;\n        default:\n            if (runStart)\n            {\n                runLength++;\n            }\n            else\n            {\n                runStart = &String->Buffer[i];\n                runLength = 1;\n            }\n\n            break;\n        }\n    }\n\n    if (runStart)\n        PhAppendStringBuilderEx(StringBuilder, runStart, runLength * sizeof(WCHAR));\n}\n\n/**\n * Allocates a text table.\n *\n * \\param Table A variable which receives a pointer to the text table.\n * \\param Rows The number of rows in the table.\n * \\param Columns The number of columns in the table.\n */\nVOID PhaCreateTextTable(\n    _Out_ PPH_STRING ***Table,\n    _In_ ULONG Rows,\n    _In_ ULONG Columns\n    )\n{\n    PPH_STRING **table;\n    ULONG i;\n\n    table = PH_AUTO(PhCreateAlloc(sizeof(PPH_STRING *) * Rows));\n\n    for (i = 0; i < Rows; i++)\n    {\n        table[i] = PH_AUTO(PhCreateAlloc(sizeof(PPH_STRING) * Columns));\n        memset(table[i], 0, sizeof(PPH_STRING) * Columns);\n    }\n\n    *Table = table;\n}\n\n/**\n * Formats a text table to a list of lines.\n *\n * \\param Table A pointer to the text table.\n * \\param Rows The number of rows in the table.\n * \\param Columns The number of columns in the table.\n * \\param Mode The export formatting mode.\n *\n * \\return A list of strings for each line in the output. The list object and\n * string objects are not auto-dereferenced.\n */\nPPH_LIST PhaFormatTextTable(\n    _In_ PPH_STRING **Table,\n    _In_ ULONG Rows,\n    _In_ ULONG Columns,\n    _In_ ULONG Mode\n    )\n{\n    PPH_LIST lines;\n    // The tab count array contains the number of tabs need to fill the biggest\n    // row cell in each column.\n    PULONG tabCount;\n    ULONG i;\n    ULONG j;\n\n    if (Mode == PH_EXPORT_MODE_TABS || Mode == PH_EXPORT_MODE_SPACES)\n    {\n        // Create the tab count array.\n\n        tabCount = PH_AUTO(PhCreateAlloc(sizeof(ULONG) * Columns));\n        memset(tabCount, 0, sizeof(ULONG) * Columns); // zero all values\n\n        for (i = 0; i < Rows; i++)\n        {\n            for (j = 0; j < Columns; j++)\n            {\n                ULONG newCount;\n\n                if (Table[i][j])\n                    newCount = (ULONG)(Table[i][j]->Length / sizeof(WCHAR) / TAB_SIZE);\n                else\n                    newCount = 0;\n\n                // Replace the existing count if this tab count is bigger.\n                if (tabCount[j] < newCount)\n                    tabCount[j] = newCount;\n            }\n        }\n    }\n\n    // Create the final list of lines by going through each cell and appending\n    // the proper tab count (if we are using tabs). This will make sure each column\n    // is properly aligned.\n\n    lines = PhCreateList(Rows);\n\n    for (i = 0; i < Rows; i++)\n    {\n        PH_STRING_BUILDER stringBuilder;\n\n        PhInitializeStringBuilder(&stringBuilder, 100);\n\n        switch (Mode)\n        {\n        case PH_EXPORT_MODE_TABS:\n            {\n                for (j = 0; j < Columns; j++)\n                {\n                    ULONG k;\n\n                    if (Table[i][j])\n                    {\n                        // Calculate the number of tabs needed.\n                        k = (ULONG)(tabCount[j] + 1 - Table[i][j]->Length / sizeof(WCHAR) / TAB_SIZE);\n\n                        PhAppendStringBuilder(&stringBuilder, &Table[i][j]->sr);\n                    }\n                    else\n                    {\n                        k = tabCount[j] + 1;\n                    }\n\n                    PhAppendCharStringBuilder2(&stringBuilder, '\\t', k);\n                }\n            }\n            break;\n        case PH_EXPORT_MODE_SPACES:\n            {\n                for (j = 0; j < Columns; j++)\n                {\n                    ULONG k;\n\n                    if (Table[i][j])\n                    {\n                        // Calculate the number of spaces needed.\n                        k = (ULONG)((tabCount[j] + 1) * TAB_SIZE - Table[i][j]->Length / sizeof(WCHAR));\n\n                        PhAppendStringBuilder(&stringBuilder, &Table[i][j]->sr);\n                    }\n                    else\n                    {\n                        k = (tabCount[j] + 1) * TAB_SIZE;\n                    }\n\n                    PhAppendCharStringBuilder2(&stringBuilder, ' ', k);\n                }\n            }\n            break;\n        case PH_EXPORT_MODE_CSV:\n            {\n                for (j = 0; j < Columns; j++)\n                {\n                    PhAppendCharStringBuilder(&stringBuilder, '\\\"');\n\n                    if (Table[i][j])\n                    {\n                        PhpEscapeStringForCsv(&stringBuilder, Table[i][j]);\n                    }\n\n                    PhAppendCharStringBuilder(&stringBuilder, '\\\"');\n\n                    if (j != Columns - 1)\n                        PhAppendCharStringBuilder(&stringBuilder, ',');\n                }\n            }\n            break;\n        }\n\n        PhAddItemList(lines, PhFinalStringBuilderString(&stringBuilder));\n    }\n\n    return lines;\n}\n\nVOID PhMapDisplayIndexTreeNew(\n    _In_ HWND TreeNewHandle,\n    _Out_opt_ PULONG *DisplayToId,\n    _Out_opt_ PWSTR **DisplayToText,\n    _Out_ PULONG NumberOfColumns\n    )\n{\n    PPH_TREENEW_COLUMN fixedColumn;\n    ULONG numberOfColumns;\n    PULONG displayToId;\n    PWSTR *displayToText;\n    ULONG i;\n    PH_TREENEW_COLUMN column;\n\n    fixedColumn = TreeNew_GetFixedColumn(TreeNewHandle);\n    numberOfColumns = TreeNew_GetVisibleColumnCount(TreeNewHandle);\n\n    displayToId = PhAllocate(numberOfColumns * sizeof(ULONG));\n\n    if (fixedColumn)\n    {\n        TreeNew_GetColumnOrderArray(TreeNewHandle, numberOfColumns - 1, displayToId + 1);\n        displayToId[0] = fixedColumn->Id;\n    }\n    else\n    {\n        TreeNew_GetColumnOrderArray(TreeNewHandle, numberOfColumns, displayToId);\n    }\n\n    if (DisplayToText)\n    {\n        displayToText = PhAllocate(numberOfColumns * sizeof(PWSTR));\n\n        for (i = 0; i < numberOfColumns; i++)\n        {\n            if (TreeNew_GetColumn(TreeNewHandle, displayToId[i], &column))\n            {\n                displayToText[i] = column.Text;\n            }\n        }\n\n        *DisplayToText = displayToText;\n    }\n\n    if (DisplayToId)\n        *DisplayToId = displayToId;\n    else\n        PhFree(displayToId);\n\n    *NumberOfColumns = numberOfColumns;\n}\n\nPPH_STRING PhGetTreeNewText(\n    _In_ HWND TreeNewHandle,\n    _Reserved_ ULONG Reserved\n    )\n{\n    PH_STRING_BUILDER stringBuilder;\n    PULONG displayToId;\n    ULONG rows;\n    ULONG columns;\n    ULONG i;\n    ULONG j;\n\n    PhMapDisplayIndexTreeNew(TreeNewHandle, &displayToId, NULL, &columns);\n    rows = TreeNew_GetFlatNodeCount(TreeNewHandle);\n\n    PhInitializeStringBuilder(&stringBuilder, 0x100);\n\n    for (i = 0; i < rows; i++)\n    {\n        PH_TREENEW_GET_CELL_TEXT getCellText;\n\n        getCellText.Node = TreeNew_GetFlatNode(TreeNewHandle, i);\n        assert(getCellText.Node);\n\n        if (!getCellText.Node->Selected)\n            continue;\n\n        for (j = 0; j < columns; j++)\n        {\n            getCellText.Id = displayToId[j];\n            PhInitializeEmptyStringRef(&getCellText.Text);\n            TreeNew_GetCellText(TreeNewHandle, &getCellText);\n\n            PhAppendStringBuilder(&stringBuilder, &getCellText.Text);\n            PhAppendStringBuilder2(&stringBuilder, L\", \");\n        }\n\n        // Remove the trailing comma and space.\n        if (stringBuilder.String->Length != 0)\n            PhRemoveEndStringBuilder(&stringBuilder, 2);\n\n        PhAppendStringBuilder2(&stringBuilder, L\"\\r\\n\");\n    }\n\n    PhFree(displayToId);\n\n    return PhFinalStringBuilderString(&stringBuilder);\n}\n\nPPH_LIST PhGetGenericTreeNewLines(\n    _In_ HWND TreeNewHandle,\n    _In_ ULONG Mode\n    )\n{\n    PH_AUTO_POOL autoPool;\n    PPH_LIST lines;\n    ULONG rows;\n    ULONG columns;\n    ULONG numberOfNodes;\n    PULONG displayToId;\n    PWSTR *displayToText;\n    PPH_STRING **table;\n    ULONG i;\n    ULONG j;\n\n    PhInitializeAutoPool(&autoPool);\n\n    numberOfNodes = TreeNew_GetFlatNodeCount(TreeNewHandle);\n\n    rows = numberOfNodes + 1;\n    PhMapDisplayIndexTreeNew(TreeNewHandle, &displayToId, &displayToText, &columns);\n\n    PhaCreateTextTable(&table, rows, columns);\n\n    for (i = 0; i < columns; i++)\n        table[0][i] = PhaCreateString(displayToText[i]);\n\n    for (i = 0; i < numberOfNodes; i++)\n    {\n        PPH_TREENEW_NODE node;\n\n        node = TreeNew_GetFlatNode(TreeNewHandle, i);\n\n        if (node)\n        {\n            for (j = 0; j < columns; j++)\n            {\n                PH_TREENEW_GET_CELL_TEXT getCellText;\n\n                getCellText.Node = node;\n                getCellText.Id = displayToId[j];\n                PhInitializeEmptyStringRef(&getCellText.Text);\n                TreeNew_GetCellText(TreeNewHandle, &getCellText);\n\n                table[i + 1][j] = PhaCreateStringEx(getCellText.Text.Buffer, getCellText.Text.Length);\n            }\n        }\n        else\n        {\n            for (j = 0; j < columns; j++)\n            {\n                table[i + 1][j] = PH_AUTO(PhReferenceEmptyString());\n            }\n        }\n    }\n\n    PhFree(displayToText);\n    PhFree(displayToId);\n\n    lines = PhaFormatTextTable(table, rows, columns, Mode);\n\n    PhDeleteAutoPool(&autoPool);\n\n    return lines;\n}\n\nVOID PhaMapDisplayIndexListView(\n    _In_ HWND ListViewHandle,\n    _Out_writes_(Count) PULONG DisplayToId,\n    _Out_writes_opt_(Count) PPH_STRING *DisplayToText,\n    _In_ ULONG Count,\n    _Out_ PULONG NumberOfColumns\n    )\n{\n    LVCOLUMN lvColumn;\n    ULONG i;\n    ULONG count;\n    WCHAR buffer[128];\n\n    count = 0;\n    lvColumn.mask = LVCF_ORDER | LVCF_TEXT;\n    lvColumn.pszText = buffer;\n    lvColumn.cchTextMax = sizeof(buffer) / sizeof(WCHAR);\n\n    for (i = 0; i < Count; i++)\n    {\n        if (ListView_GetColumn(ListViewHandle, i, &lvColumn))\n        {\n            ULONG displayIndex;\n\n            displayIndex = (ULONG)lvColumn.iOrder;\n            assert(displayIndex < Count);\n            DisplayToId[displayIndex] = i;\n\n            if (DisplayToText)\n                DisplayToText[displayIndex] = PhaCreateString(buffer);\n\n            count++;\n        }\n        else\n        {\n            break;\n        }\n    }\n\n    *NumberOfColumns = count;\n}\n\nPPH_STRING PhaGetListViewItemText(\n    _In_ HWND ListViewHandle,\n    _In_ INT Index,\n    _In_ INT SubItemIndex\n    )\n{\n    PPH_STRING buffer;\n    SIZE_T allocatedCount;\n    SIZE_T count;\n    LVITEM lvItem;\n\n    // Unfortunately LVM_GETITEMTEXT doesn't want to return the actual length of the text.\n    // Keep doubling the buffer size until we get a return count that is strictly less than\n    // the amount we allocated.\n\n    buffer = NULL;\n    allocatedCount = 256;\n    count = allocatedCount;\n\n    while (count >= allocatedCount)\n    {\n        if (buffer)\n            PhDereferenceObject(buffer);\n\n        allocatedCount *= 2;\n        buffer = PhCreateStringEx(NULL, allocatedCount * sizeof(WCHAR));\n        buffer->Buffer[0] = 0;\n\n        lvItem.iSubItem = SubItemIndex;\n        lvItem.cchTextMax = (INT)allocatedCount + 1;\n        lvItem.pszText = buffer->Buffer;\n        count = SendMessage(ListViewHandle, LVM_GETITEMTEXT, Index, (LPARAM)&lvItem);\n    }\n\n    PhTrimToNullTerminatorString(buffer);\n    PH_AUTO(buffer);\n\n    return buffer;\n}\n\nPPH_STRING PhGetListViewText(\n    _In_ HWND ListViewHandle\n    )\n{\n    PH_AUTO_POOL autoPool;\n    PH_STRING_BUILDER stringBuilder;\n    ULONG displayToId[100];\n    ULONG rows;\n    ULONG columns;\n    ULONG i;\n    ULONG j;\n\n    PhInitializeAutoPool(&autoPool);\n\n    PhaMapDisplayIndexListView(ListViewHandle, displayToId, NULL, 100, &columns);\n    rows = ListView_GetItemCount(ListViewHandle);\n\n    PhInitializeStringBuilder(&stringBuilder, 0x100);\n\n    for (i = 0; i < rows; i++)\n    {\n        if (!(ListView_GetItemState(ListViewHandle, i, LVIS_SELECTED) & LVIS_SELECTED))\n            continue;\n\n        for (j = 0; j < columns; j++)\n        {\n            PhAppendStringBuilder(&stringBuilder, &PhaGetListViewItemText(ListViewHandle, i, j)->sr);\n            PhAppendStringBuilder2(&stringBuilder, L\", \");\n        }\n\n        // Remove the trailing comma and space.\n        if (stringBuilder.String->Length != 0)\n            PhRemoveEndStringBuilder(&stringBuilder, 2);\n\n        PhAppendStringBuilder2(&stringBuilder, L\"\\r\\n\");\n    }\n\n    PhDeleteAutoPool(&autoPool);\n\n    return PhFinalStringBuilderString(&stringBuilder);\n}\n\nPPH_LIST PhGetListViewLines(\n    _In_ HWND ListViewHandle,\n    _In_ ULONG Mode\n    )\n{\n    PH_AUTO_POOL autoPool;\n    PPH_LIST lines;\n    ULONG rows;\n    ULONG columns;\n    ULONG displayToId[100];\n    PPH_STRING displayToText[100];\n    PPH_STRING **table;\n    ULONG i;\n    ULONG j;\n\n    PhInitializeAutoPool(&autoPool);\n\n    rows = ListView_GetItemCount(ListViewHandle) + 1; // +1 for column headers\n\n    // Create the display index/text to ID map.\n    PhaMapDisplayIndexListView(ListViewHandle, displayToId, displayToText, 100, &columns);\n\n    PhaCreateTextTable(&table, rows, columns);\n\n    // Populate the first row with the column headers.\n    for (i = 0; i < columns; i++)\n        table[0][i] = displayToText[i];\n\n    // Populate the other rows with text.\n    for (i = 1; i < rows; i++)\n    {\n        for (j = 0; j < columns; j++)\n        {\n            // Important: use this to bypass extlv's hooking.\n            // extlv only hooks LVM_GETITEM, not LVM_GETITEMTEXT.\n            table[i][j] = PhaGetListViewItemText(ListViewHandle, i - 1, j);\n        }\n    }\n\n    lines = PhaFormatTextTable(table, rows, columns, Mode);\n\n    PhDeleteAutoPool(&autoPool);\n\n    return lines;\n}\n"
  },
  {
    "path": "third_party/phlib/data.c",
    "content": "#include <ph.h>\n#include <phdata.h>\n\n// SIDs\n\nSID PhSeNobodySid = { SID_REVISION, 1, SECURITY_NULL_SID_AUTHORITY, { SECURITY_NULL_RID } };\n\nSID PhSeEveryoneSid = { SID_REVISION, 1, SECURITY_WORLD_SID_AUTHORITY, { SECURITY_WORLD_RID } };\n\nSID PhSeLocalSid = { SID_REVISION, 1, SECURITY_LOCAL_SID_AUTHORITY, { SECURITY_LOCAL_RID } };\n\nSID PhSeCreatorOwnerSid = { SID_REVISION, 1, SECURITY_CREATOR_SID_AUTHORITY, { SECURITY_CREATOR_OWNER_RID } };\nSID PhSeCreatorGroupSid = { SID_REVISION, 1, SECURITY_CREATOR_SID_AUTHORITY, { SECURITY_CREATOR_GROUP_RID } };\n\nSID PhSeDialupSid = { SID_REVISION, 1, SECURITY_NT_AUTHORITY, { SECURITY_DIALUP_RID } };\nSID PhSeNetworkSid = { SID_REVISION, 1, SECURITY_NT_AUTHORITY, { SECURITY_NETWORK_RID } };\nSID PhSeBatchSid = { SID_REVISION, 1, SECURITY_NT_AUTHORITY, { SECURITY_BATCH_RID } };\nSID PhSeInteractiveSid = { SID_REVISION, 1, SECURITY_NT_AUTHORITY, { SECURITY_INTERACTIVE_RID } };\nSID PhSeServiceSid = { SID_REVISION, 1, SECURITY_NT_AUTHORITY, { SECURITY_SERVICE_RID } };\nSID PhSeAnonymousLogonSid = { SID_REVISION, 1, SECURITY_NT_AUTHORITY, { SECURITY_ANONYMOUS_LOGON_RID } };\nSID PhSeProxySid = { SID_REVISION, 1, SECURITY_NT_AUTHORITY, { SECURITY_PROXY_RID } };\nSID PhSeAuthenticatedUserSid = { SID_REVISION, 1, SECURITY_NT_AUTHORITY, { SECURITY_AUTHENTICATED_USER_RID } };\nSID PhSeRestrictedCodeSid = { SID_REVISION, 1, SECURITY_NT_AUTHORITY, { SECURITY_RESTRICTED_CODE_RID } };\nSID PhSeTerminalServerUserSid = { SID_REVISION, 1, SECURITY_NT_AUTHORITY, { SECURITY_TERMINAL_SERVER_RID } };\nSID PhSeRemoteInteractiveLogonSid = { SID_REVISION, 1, SECURITY_NT_AUTHORITY, { SECURITY_REMOTE_LOGON_RID } };\nSID PhSeLocalSystemSid = { SID_REVISION, 1, SECURITY_NT_AUTHORITY, { SECURITY_LOCAL_SYSTEM_RID } };\nSID PhSeLocalServiceSid = { SID_REVISION, 1, SECURITY_NT_AUTHORITY, { SECURITY_LOCAL_SERVICE_RID } };\nSID PhSeNetworkServiceSid = { SID_REVISION, 1, SECURITY_NT_AUTHORITY, { SECURITY_NETWORK_SERVICE_RID } };\n\n// Unicode\n\nPH_STRINGREF PhUnicodeByteOrderMark = PH_STRINGREF_INIT(L\"\\ufeff\");\n\n// Characters\n\nDECLSPEC_SELECTANY\nBOOLEAN PhCharIsPrintable[256] =\n{\n    0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 1, 0, 0, /* 0 - 15 */ // TAB, LF and CR are printable\n    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 16 - 31 */\n    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* ' ' - '/' */\n    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* '0' - '9' */\n    1, 1, 1, 1, 1, 1, 1, /* ':' - '@' */\n    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 'A' - 'Z' */\n    1, 1, 1, 1, 1, 1, /* '[' - '`' */\n    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 'a' - 'z' */\n    1, 1, 1, 1, 0, /* '{' - 127 */ // DEL is not printable\n    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 128 - 143 */\n    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 144 - 159 */\n    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 160 - 175 */\n    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 176 - 191 */\n    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 192 - 207 */\n    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 208 - 223 */\n    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 224 - 239 */\n    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 /* 240 - 255 */\n};\n\nDECLSPEC_SELECTANY\nULONG PhCharToInteger[256] =\n{\n    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 0 - 15 */\n    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 16 - 31 */\n    36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, /* ' ' - '/' */\n    0, 1, 2, 3, 4, 5, 6, 7, 8, 9, /* '0' - '9' */\n    52, 53, 54, 55, 56, 57, 58, /* ':' - '@' */\n    10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, /* 'A' - 'Z' */\n    59, 60, 61, 62, 63, 64, /* '[' - '`' */\n    10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, /* 'a' - 'z' */\n    65, 66, 67, 68, -1, /* '{' - 127 */\n    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 128 - 143 */\n    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 144 - 159 */\n    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 160 - 175 */\n    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 176 - 191 */\n    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 192 - 207 */\n    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 208 - 223 */\n    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 224 - 239 */\n    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 /* 240 - 255 */\n};\n\nDECLSPEC_SELECTANY\nCHAR PhIntegerToChar[69] =\n    \"0123456789\" /* 0 - 9 */\n    \"abcdefghijklmnopqrstuvwxyz\" /* 10 - 35 */\n    \" !\\\"#$%&'()*+,-./\" /* 36 - 51 */\n    \":;<=>?@\" /* 52 - 58 */\n    \"[\\\\]^_`\" /* 59 - 64 */\n    \"{|}~\" /* 65 - 68 */\n    ;\n\nDECLSPEC_SELECTANY\nCHAR PhIntegerToCharUpper[69] =\n    \"0123456789\" /* 0 - 9 */\n    \"ABCDEFGHIJKLMNOPQRSTUVWXYZ\" /* 10 - 35 */\n    \" !\\\"#$%&'()*+,-./\" /* 36 - 51 */\n    \":;<=>?@\" /* 52 - 58 */\n    \"[\\\\]^_`\" /* 59 - 64 */\n    \"{|}~\" /* 65 - 68 */\n    ;\n\n// CRC32 (IEEE 802.3)\n\nDECLSPEC_SELECTANY\nULONG PhCrc32Table[256] =\n{\n    0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419, 0x706af48f, 0xe963a535, 0x9e6495a3,\n    0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988, 0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91,\n    0x1db71064, 0x6ab020f2, 0xf3b97148, 0x84be41de, 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7,\n    0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec, 0x14015c4f, 0x63066cd9, 0xfa0f3d63, 0x8d080df5,\n    0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172, 0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b,\n    0x35b5a8fa, 0x42b2986c, 0xdbbbc9d6, 0xacbcf940, 0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59,\n    0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116, 0x21b4f4b5, 0x56b3c423, 0xcfba9599, 0xb8bda50f,\n    0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924, 0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d,\n    0x76dc4190, 0x01db7106, 0x98d220bc, 0xefd5102a, 0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433,\n    0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818, 0x7f6a0dbb, 0x086d3d2d, 0x91646c97, 0xe6635c01,\n    0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e, 0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457,\n    0x65b0d9c6, 0x12b7e950, 0x8bbeb8ea, 0xfcb9887c, 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65,\n    0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2, 0x4adfa541, 0x3dd895d7, 0xa4d1c46d, 0xd3d6f4fb,\n    0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0, 0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9,\n    0x5005713c, 0x270241aa, 0xbe0b1010, 0xc90c2086, 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f,\n    0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, 0x59b33d17, 0x2eb40d81, 0xb7bd5c3b, 0xc0ba6cad,\n    0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a, 0xead54739, 0x9dd277af, 0x04db2615, 0x73dc1683,\n    0xe3630b12, 0x94643b84, 0x0d6d6a3e, 0x7a6a5aa8, 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1,\n    0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe, 0xf762575d, 0x806567cb, 0x196c3671, 0x6e6b06e7,\n    0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc, 0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5,\n    0xd6d6a3e8, 0xa1d1937e, 0x38d8c2c4, 0x4fdff252, 0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b,\n    0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60, 0xdf60efc3, 0xa867df55, 0x316e8eef, 0x4669be79,\n    0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236, 0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f,\n    0xc5ba3bbe, 0xb2bd0b28, 0x2bb45a92, 0x5cb36a04, 0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d,\n    0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a, 0x9c0906a9, 0xeb0e363f, 0x72076785, 0x05005713,\n    0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38, 0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21,\n    0x86d3d2d4, 0xf1d4e242, 0x68ddb3f8, 0x1fda836e, 0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777,\n    0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c, 0x8f659eff, 0xf862ae69, 0x616bffd3, 0x166ccf45,\n    0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2, 0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db,\n    0xaed16a4a, 0xd9d65adc, 0x40df0b66, 0x37d83bf0, 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9,\n    0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, 0xbad03605, 0xcdd70693, 0x54de5729, 0x23d967bf,\n    0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94, 0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d\n};\n\n// Enums\n\nDECLSPEC_SELECTANY\nWCHAR *PhIoPriorityHintNames[MaxIoPriorityTypes] =\n{\n    L\"Very low\",\n    L\"Low\",\n    L\"Normal\",\n    L\"High\",\n    L\"Critical\"\n};\n\nDECLSPEC_SELECTANY\nWCHAR *PhPagePriorityNames[MEMORY_PRIORITY_NORMAL + 1] =\n{\n    L\"Lowest\",\n    L\"Very low\",\n    L\"Low\",\n    L\"Medium\",\n    L\"Below normal\",\n    L\"Normal\"\n};\n\nDECLSPEC_SELECTANY\nWCHAR *PhKThreadStateNames[MaximumThreadState] =\n{\n    L\"Initialized\",\n    L\"Ready\",\n    L\"Running\",\n    L\"Standby\",\n    L\"Terminated\",\n    L\"Waiting\",\n    L\"Transition\",\n    L\"DeferredReady\",\n    L\"GateWait\",\n    L\"WaitingForProcessInSwap\"\n};\n\nDECLSPEC_SELECTANY\nWCHAR *PhKWaitReasonNames[MaximumWaitReason] =\n{\n    L\"Executive\",\n    L\"FreePage\",\n    L\"PageIn\",\n    L\"PoolAllocation\",\n    L\"DelayExecution\",\n    L\"Suspended\",\n    L\"UserRequest\",\n    L\"WrExecutive\",\n    L\"WrFreePage\",\n    L\"WrPageIn\",\n    L\"WrPoolAllocation\",\n    L\"WrDelayExecution\",\n    L\"WrSuspended\",\n    L\"WrUserRequest\",\n    L\"WrEventPair\",\n    L\"WrQueue\",\n    L\"WrLpcReceive\",\n    L\"WrLpcReply\",\n    L\"WrVirtualMemory\",\n    L\"WrPageOut\",\n    L\"WrRendezvous\",\n    L\"WrKeyedEvent\",\n    L\"WrTerminated\",\n    L\"WrProcessInSwap\",\n    L\"WrCpuRateControl\",\n    L\"WrCalloutStack\",\n    L\"WrKernel\",\n    L\"WrResource\",\n    L\"WrPushLock\",\n    L\"WrMutex\",\n    L\"WrQuantumEnd\",\n    L\"WrDispatchInt\",\n    L\"WrPreempted\",\n    L\"WrYieldExecution\",\n    L\"WrFastMutex\",\n    L\"WrGuardedMutex\",\n    L\"WrRundown\",\n    L\"WrAlertByThreadId\",\n    L\"WrDeferredPreempt\"\n};\n"
  },
  {
    "path": "third_party/phlib/dspick.c",
    "content": "/*\n * Process Hacker -\n *   DS object picker wrapper\n *\n * Copyright (C) 2010 wj32\n *\n * This file is part of Process Hacker.\n *\n * Process Hacker is free software; you can redistribute it and/or modify\n * it under the terms of the GNU General Public License as published by\n * the Free Software Foundation, either version 3 of the License, or\n * (at your option) any later version.\n *\n * Process Hacker is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n * GNU General Public License for more details.\n *\n * You should have received a copy of the GNU General Public License\n * along with Process Hacker.  If not, see <http://www.gnu.org/licenses/>.\n */\n\n#include <ph.h>\n#include <dspick.h>\n\n#include <ole2.h>\n#define CINTERFACE\n#define COBJMACROS\n#include <objsel.h>\n\n#include <guisup.h>\n#include <lsasup.h>\n\n#define IDataObject_AddRef(This) ((This)->lpVtbl->AddRef(This))\n#define IDataObject_Release(This) ((This)->lpVtbl->Release(This))\n#define IDataObject_GetData(This, pformatetcIn, pmedium) ((This)->lpVtbl->GetData(This, pformatetcIn, pmedium))\n\n#define IDsObjectPicker_QueryInterface(This, riid, ppvObject) ((This)->lpVtbl->QueryInterface(This, riid, ppvObject))\n#define IDsObjectPicker_AddRef(This) ((This)->lpVtbl->AddRef(This))\n#define IDsObjectPicker_Release(This) ((This)->lpVtbl->Release(This))\n#define IDsObjectPicker_Initialize(This, pInitInfo) ((This)->lpVtbl->Initialize(This, pInitInfo))\n#define IDsObjectPicker_InvokeDialog(This, hwndParent, ppdoSelections) ((This)->lpVtbl->InvokeDialog(This, hwndParent, ppdoSelections))\n\nIDsObjectPicker *PhpCreateDsObjectPicker(\n    VOID\n    )\n{\n    static CLSID CLSID_DsObjectPicker_I = { 0x17d6ccd8, 0x3b7b, 0x11d2, { 0xb9, 0xe0, 0x00, 0xc0, 0x4f, 0xd8, 0xdb, 0xf7 } };\n    static IID IID_IDsObjectPicker_I = { 0x0c87e64e, 0x3b7a, 0x11d2, { 0xb9, 0xe0, 0x00, 0xc0, 0x4f, 0xd8, 0xdb, 0xf7 } };\n\n    IDsObjectPicker *picker;\n\n    if (SUCCEEDED(CoCreateInstance(\n        &CLSID_DsObjectPicker_I,\n        NULL,\n        CLSCTX_INPROC_SERVER,\n        &IID_IDsObjectPicker_I,\n        &picker\n        )))\n    {\n        return picker;\n    }\n    else\n    {\n        return NULL;\n    }\n}\n\nVOID PhFreeDsObjectPickerDialog(\n    _In_ PVOID PickerDialog\n    )\n{\n    IDsObjectPicker_Release((IDsObjectPicker *)PickerDialog);\n}\n\nPVOID PhCreateDsObjectPickerDialog(\n    _In_ ULONG Flags\n    )\n{\n    IDsObjectPicker *picker;\n    DSOP_INIT_INFO initInfo;\n    DSOP_SCOPE_INIT_INFO scopeInit[1];\n\n    picker = PhpCreateDsObjectPicker();\n\n    if (!picker)\n        return NULL;\n\n    memset(scopeInit, 0, sizeof(scopeInit));\n\n    scopeInit[0].cbSize = sizeof(DSOP_SCOPE_INIT_INFO);\n    scopeInit[0].flType = DSOP_SCOPE_TYPE_TARGET_COMPUTER;\n    scopeInit[0].flScope =\n        DSOP_SCOPE_FLAG_WANT_PROVIDER_WINNT |\n        DSOP_SCOPE_FLAG_WANT_SID_PATH |\n        DSOP_SCOPE_FLAG_DEFAULT_FILTER_USERS |\n        DSOP_SCOPE_FLAG_DEFAULT_FILTER_GROUPS;\n    scopeInit[0].FilterFlags.Uplevel.flBothModes =\n        DSOP_FILTER_INCLUDE_ADVANCED_VIEW |\n        DSOP_FILTER_USERS |\n        DSOP_FILTER_BUILTIN_GROUPS |\n        DSOP_FILTER_WELL_KNOWN_PRINCIPALS;\n    scopeInit[0].FilterFlags.flDownlevel =\n        DSOP_DOWNLEVEL_FILTER_USERS |\n        DSOP_DOWNLEVEL_FILTER_LOCAL_GROUPS |\n        DSOP_DOWNLEVEL_FILTER_GLOBAL_GROUPS |\n        DSOP_DOWNLEVEL_FILTER_ALL_WELLKNOWN_SIDS;\n\n    memset(&initInfo, 0, sizeof(DSOP_INIT_INFO));\n    initInfo.cbSize = sizeof(DSOP_INIT_INFO);\n    initInfo.pwzTargetComputer = NULL;\n    initInfo.cDsScopeInfos = 1;\n    initInfo.aDsScopeInfos = scopeInit;\n    initInfo.flOptions = DSOP_FLAG_SKIP_TARGET_COMPUTER_DC_CHECK;\n\n    if (Flags & PH_DSPICK_MULTISELECT)\n        initInfo.flOptions |= DSOP_FLAG_MULTISELECT;\n\n    if (!SUCCEEDED(IDsObjectPicker_Initialize(picker, &initInfo)))\n    {\n        IDsObjectPicker_Release(picker);\n        return NULL;\n    }\n\n    return picker;\n}\n\nPDS_SELECTION_LIST PhpGetDsSelectionList(\n    _In_ IDataObject *Selections\n    )\n{\n    FORMATETC format;\n    STGMEDIUM medium;\n\n    format.cfFormat = (CLIPFORMAT)RegisterClipboardFormat(L\"CFSTR_DSOP_DS_SELECTION_LIST\");\n    format.ptd = NULL;\n    format.dwAspect = -1;\n    format.lindex = -1;\n    format.tymed = TYMED_HGLOBAL;\n\n    if (SUCCEEDED(IDataObject_GetData(Selections, &format, &medium)))\n    {\n        if (medium.tymed != TYMED_HGLOBAL)\n            return NULL;\n\n        return (PDS_SELECTION_LIST)GlobalLock(medium.hGlobal);\n    }\n    else\n    {\n        return NULL;\n    }\n}\n\nBOOLEAN PhShowDsObjectPickerDialog(\n    _In_ HWND hWnd,\n    _In_ PVOID PickerDialog,\n    _Out_ PPH_DSPICK_OBJECTS *Objects\n    )\n{\n    IDsObjectPicker *picker;\n    IDataObject *dataObject;\n    PDS_SELECTION_LIST selections;\n    PPH_DSPICK_OBJECTS objects;\n    ULONG i;\n\n    picker = (IDsObjectPicker *)PickerDialog;\n\n    if (!SUCCEEDED(IDsObjectPicker_InvokeDialog(picker, hWnd, &dataObject)))\n        return FALSE;\n\n    if (!dataObject)\n        return FALSE;\n\n    selections = PhpGetDsSelectionList(dataObject);\n    IDataObject_Release(dataObject);\n\n    if (!selections)\n        return FALSE;\n\n    objects = PhAllocate(\n        FIELD_OFFSET(PH_DSPICK_OBJECTS, Objects) +\n        selections->cItems * sizeof(PH_DSPICK_OBJECT)\n        );\n\n    objects->NumberOfObjects = selections->cItems;\n\n    for (i = 0; i < selections->cItems; i++)\n    {\n        PDS_SELECTION selection;\n        PSID sid;\n        PH_STRINGREF path;\n        PH_STRINGREF prefix;\n\n        selection = &selections->aDsSelection[i];\n\n        objects->Objects[i].Name = PhCreateString(selection->pwzName);\n        objects->Objects[i].Sid = NULL;\n\n        if (selection->pwzADsPath && selection->pwzADsPath[0] != 0)\n        {\n            PhInitializeStringRef(&path, selection->pwzADsPath);\n            PhInitializeStringRef(&prefix, L\"LDAP://<SID=\");\n\n            if (PhStartsWithStringRef(&path, &prefix, TRUE))\n            {\n                PhSkipStringRef(&path, prefix.Length);\n                path.Length -= sizeof(WCHAR); // Ignore \">\" at end\n\n                sid = PhAllocate(path.Length / sizeof(WCHAR) / 2);\n\n                if (PhHexStringToBuffer(&path, (PUCHAR)sid))\n                {\n                    if (RtlValidSid(sid))\n                        objects->Objects[i].Sid = sid;\n                    else\n                        PhFree(sid);\n                }\n                else\n                {\n                    PhFree(sid);\n                }\n            }\n        }\n        else\n        {\n            // Try to get the SID.\n            PhLookupName(&objects->Objects[i].Name->sr, &objects->Objects[i].Sid, NULL, NULL);\n        }\n    }\n\n    *Objects = objects;\n\n    return TRUE;\n}\n\nVOID PhFreeDsObjectPickerObjects(\n    _In_ PPH_DSPICK_OBJECTS Objects\n    )\n{\n    ULONG i;\n\n    for (i = 0; i < Objects->NumberOfObjects; i++)\n    {\n        PhDereferenceObject(Objects->Objects[i].Name);\n\n        if (Objects->Objects[i].Sid)\n            PhFree(Objects->Objects[i].Sid);\n    }\n\n    PhFree(Objects);\n}\n"
  },
  {
    "path": "third_party/phlib/emenu.c",
    "content": "/*\n * Process Hacker -\n *   extended menus\n *\n * Copyright (C) 2010-2011 wj32\n *\n * This file is part of Process Hacker.\n *\n * Process Hacker is free software; you can redistribute it and/or modify\n * it under the terms of the GNU General Public License as published by\n * the Free Software Foundation, either version 3 of the License, or\n * (at your option) any later version.\n *\n * Process Hacker is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n * GNU General Public License for more details.\n *\n * You should have received a copy of the GNU General Public License\n * along with Process Hacker.  If not, see <http://www.gnu.org/licenses/>.\n */\n\n#include <ph.h>\n#include <emenu.h>\n\n#include <guisup.h>\n\nstatic const PH_FLAG_MAPPING EMenuTypeMappings[] =\n{\n    { PH_EMENU_MENUBARBREAK, MFT_MENUBARBREAK },\n    { PH_EMENU_MENUBREAK, MFT_MENUBREAK },\n    { PH_EMENU_RADIOCHECK, MFT_RADIOCHECK }\n};\n\nstatic const PH_FLAG_MAPPING EMenuStateMappings[] =\n{\n    { PH_EMENU_CHECKED, MFS_CHECKED },\n    { PH_EMENU_DEFAULT, MFS_DEFAULT },\n    { PH_EMENU_DISABLED, MFS_DISABLED },\n    { PH_EMENU_HIGHLIGHT, MFS_HILITE }\n};\n\nPPH_EMENU_ITEM PhAllocateEMenuItem(\n    VOID\n    )\n{\n    PPH_EMENU_ITEM item;\n\n    item = PhAllocate(sizeof(PH_EMENU_ITEM));\n    memset(item, 0, sizeof(PH_EMENU_ITEM));\n\n    return item;\n}\n\n/**\n * Creates a menu item.\n *\n * \\param Flags A combination of the following:\n * \\li \\c PH_EMENU_DISABLED The menu item is greyed and cannot be selected.\n * \\li \\c PH_EMENU_CHECKED A check mark is displayed.\n * \\li \\c PH_EMENU_HIGHLIGHT The menu item is highlighted.\n * \\li \\c PH_EMENU_MENUBARBREAK Places the menu item in a new column, separated by a vertical line.\n * \\li \\c PH_EMENU_MENUBREAK Places the menu item in a new column, with no vertical line.\n * \\li \\c PH_EMENU_DEFAULT The menu item is displayed as the default item. This causes the text to\n * be bolded.\n * \\li \\c PH_EMENU_RADIOCHECK Uses a radio-button mark instead of a check mark.\n * \\param Id A unique identifier for the menu item.\n * \\param Text The text displayed for the menu item.\n * \\param Bitmap A bitmap image for the menu item.\n * \\param Context A user-defined value.\n */\nPPH_EMENU_ITEM PhCreateEMenuItem(\n    _In_ ULONG Flags,\n    _In_ ULONG Id,\n    _In_ PWSTR Text,\n    _In_opt_ HBITMAP Bitmap,\n    _In_opt_ PVOID Context\n    )\n{\n    PPH_EMENU_ITEM item;\n\n    item = PhAllocateEMenuItem();\n\n    item->Flags = Flags;\n    item->Id = Id;\n    item->Text = Text;\n    item->Bitmap = Bitmap;\n\n    item->Context = Context;\n\n    return item;\n}\n\n/**\n * Frees resources used by a menu item and its children.\n *\n * \\param Item The menu item.\n *\n * \\remarks The menu item is NOT automatically removed from its parent. It is safe to call this\n * function while enumerating menu items.\n */\nVOID PhpDestroyEMenuItem(\n    _In_ PPH_EMENU_ITEM Item\n    )\n{\n    if (Item->DeleteFunction)\n        Item->DeleteFunction(Item);\n\n    if ((Item->Flags & PH_EMENU_TEXT_OWNED) && Item->Text)\n        PhFree(Item->Text);\n    if ((Item->Flags & PH_EMENU_BITMAP_OWNED) && Item->Bitmap)\n        DeleteObject(Item->Bitmap);\n\n    if (Item->Items)\n    {\n        ULONG i;\n\n        for (i = 0; i < Item->Items->Count; i++)\n        {\n            PhpDestroyEMenuItem(Item->Items->Items[i]);\n        }\n\n        PhDereferenceObject(Item->Items);\n    }\n\n    PhFree(Item);\n}\n\n/**\n * Frees resources used by a menu item and its children.\n *\n * \\param Item The menu item.\n *\n * \\remarks The menu item is automatically removed from its parent.\n */\nVOID PhDestroyEMenuItem(\n    _In_ PPH_EMENU_ITEM Item\n    )\n{\n    // Remove the item from its parent, if it has one.\n    if (Item->Parent)\n        PhRemoveEMenuItem(NULL, Item, -1);\n\n    PhpDestroyEMenuItem(Item);\n}\n\n/**\n * Finds a child menu item.\n *\n * \\param Item The parent menu item.\n * \\param Flags A combination of the following:\n * \\li \\c PH_EMENU_FIND_DESCEND Searches recursively within child menu items.\n * \\li \\c PH_EMENU_FIND_STARTSWITH Performs a partial text search instead of an exact search.\n * \\li \\c PH_EMENU_FIND_LITERAL Performs a literal search instead of ignoring prefix characters\n * (ampersands).\n * \\param Text The text of the menu item to find. If NULL, the text is ignored.\n * \\param Id The identifier of the menu item to find. If 0, the identifier is ignored.\n *\n * \\return The found menu item, or NULL if the menu item could not be found.\n */\nPPH_EMENU_ITEM PhFindEMenuItem(\n    _In_ PPH_EMENU_ITEM Item,\n    _In_ ULONG Flags,\n    _In_opt_ PWSTR Text,\n    _In_opt_ ULONG Id\n    )\n{\n    return PhFindEMenuItemEx(Item, Flags, Text, Id, NULL, NULL);\n}\n\n/**\n * Finds a child menu item.\n *\n * \\param Item The parent menu item.\n * \\param Flags A combination of the following:\n * \\li \\c PH_EMENU_FIND_DESCEND Searches recursively within child menu items.\n * \\li \\c PH_EMENU_FIND_STARTSWITH Performs a partial text search instead of an exact search.\n * \\li \\c PH_EMENU_FIND_LITERAL Performs a literal search instead of ignoring prefix characters\n * (ampersands).\n * \\param Text The text of the menu item to find. If NULL, the text is ignored.\n * \\param Id The identifier of the menu item to find. If 0, the identifier is ignored.\n * \\param FoundParent A variable which receives the parent of the found menu item.\n * \\param FoundIndex A variable which receives the index of the found menu item.\n *\n * \\return The found menu item, or NULL if the menu item could not be found.\n */\nPPH_EMENU_ITEM PhFindEMenuItemEx(\n    _In_ PPH_EMENU_ITEM Item,\n    _In_ ULONG Flags,\n    _In_opt_ PWSTR Text,\n    _In_opt_ ULONG Id,\n    _Out_opt_ PPH_EMENU_ITEM *FoundParent,\n    _Out_opt_ PULONG FoundIndex\n    )\n{\n    PH_STRINGREF searchText;\n    ULONG i;\n    PPH_EMENU_ITEM item;\n\n    if (!Item->Items)\n        return NULL;\n\n    if (Text && (Flags & PH_EMENU_FIND_LITERAL))\n        PhInitializeStringRef(&searchText, Text);\n\n    for (i = 0; i < Item->Items->Count; i++)\n    {\n        item = Item->Items->Items[i];\n\n        if (Text)\n        {\n            if (Flags & PH_EMENU_FIND_LITERAL)\n            {\n                PH_STRINGREF text;\n\n                PhInitializeStringRef(&text, item->Text);\n\n                if (Flags & PH_EMENU_FIND_STARTSWITH)\n                {\n                    if (PhStartsWithStringRef(&text, &searchText, TRUE))\n                        goto FoundItemHere;\n                }\n                else\n                {\n                    if (PhEqualStringRef(&text, &searchText, TRUE))\n                        goto FoundItemHere;\n                }\n            }\n            else\n            {\n                if (PhCompareUnicodeStringZIgnoreMenuPrefix(Text, item->Text,\n                    TRUE, !!(Flags & PH_EMENU_FIND_STARTSWITH)) == 0)\n                    goto FoundItemHere;\n            }\n        }\n\n        if (Id && item->Id == Id)\n            goto FoundItemHere;\n\n        if (Flags & PH_EMENU_FIND_DESCEND)\n        {\n            PPH_EMENU_ITEM foundItem;\n            PPH_EMENU_ITEM foundParent;\n            ULONG foundIndex;\n\n            foundItem = PhFindEMenuItemEx(item, Flags, Text, Id, &foundParent, &foundIndex);\n\n            if (foundItem)\n            {\n                if (FoundParent)\n                    *FoundParent = foundParent;\n                if (FoundIndex)\n                    *FoundIndex = foundIndex;\n\n                return foundItem;\n            }\n        }\n    }\n\n    return NULL;\n\nFoundItemHere:\n    if (FoundParent)\n        *FoundParent = Item;\n    if (FoundIndex)\n        *FoundIndex = i;\n\n    return item;\n}\n\n/**\n * Determines the index of a menu item.\n *\n * \\param Parent The parent menu item.\n * \\param Item The child menu item.\n *\n * \\return The index of the menu item, or -1 if the menu item was not found in the parent menu item.\n */\nULONG PhIndexOfEMenuItem(\n    _In_ PPH_EMENU_ITEM Parent,\n    _In_ PPH_EMENU_ITEM Item\n    )\n{\n    if (!Parent->Items)\n        return -1;\n\n    return PhFindItemList(Parent->Items, Item);\n}\n\n/**\n * Inserts a menu item into a parent menu item.\n *\n * \\param Parent The parent menu item.\n * \\param Item The menu item to insert.\n * \\param Index The index at which to insert the menu item. If the index is too large, the menu item\n * is inserted at the last position.\n */\nVOID PhInsertEMenuItem(\n    _Inout_ PPH_EMENU_ITEM Parent,\n    _Inout_ PPH_EMENU_ITEM Item,\n    _In_ ULONG Index\n    )\n{\n    // Remove the item from its old parent if it has one.\n    if (Item->Parent)\n        PhRemoveEMenuItem(Item->Parent, Item, 0);\n\n    if (!Parent->Items)\n        Parent->Items = PhCreateList(16);\n\n    if (Index > Parent->Items->Count)\n        Index = Parent->Items->Count;\n\n    if (Index == -1)\n        PhAddItemList(Parent->Items, Item);\n    else\n        PhInsertItemList(Parent->Items, Index, Item);\n\n    Item->Parent = Parent;\n}\n\n/**\n * Removes a menu item from its parent.\n *\n * \\param Parent The parent menu item. If \\a Item is NULL, this parameter must be specified.\n * \\param Item The child menu item. This may be NULL if \\a Index is specified.\n * \\param Index The index of the menu item to remove. If \\a Item is specified, this parameter is\n * ignored.\n */\nBOOLEAN PhRemoveEMenuItem(\n    _Inout_opt_ PPH_EMENU_ITEM Parent,\n    _In_opt_ PPH_EMENU_ITEM Item,\n    _In_opt_ ULONG Index\n    )\n{\n    if (Item)\n    {\n        if (!Parent)\n            Parent = Item->Parent;\n        if (!Parent->Items)\n            return FALSE;\n\n        Index = PhFindItemList(Parent->Items, Item);\n\n        if (Index == -1)\n            return FALSE;\n    }\n    else\n    {\n        if (!Parent)\n            return FALSE;\n        if (!Parent->Items)\n            return FALSE;\n    }\n\n    Item = Parent->Items->Items[Index];\n    PhRemoveItemList(Parent->Items, Index);\n    Item->Parent = NULL;\n\n    return TRUE;\n}\n\n/**\n * Removes all children from a menu item.\n *\n * \\param Parent The parent menu item.\n */\nVOID PhRemoveAllEMenuItems(\n    _Inout_ PPH_EMENU_ITEM Parent\n    )\n{\n    ULONG i;\n\n    if (!Parent->Items)\n        return;\n\n    for (i = 0; i < Parent->Items->Count; i++)\n    {\n        PhpDestroyEMenuItem(Parent->Items->Items[i]);\n    }\n\n    PhClearList(Parent->Items);\n}\n\n/**\n * Creates a root menu.\n */\nPPH_EMENU PhCreateEMenu(\n    VOID\n    )\n{\n    PPH_EMENU menu;\n\n    menu = PhAllocate(sizeof(PH_EMENU));\n    memset(menu, 0, sizeof(PH_EMENU));\n    menu->Items = PhCreateList(16);\n\n    return menu;\n}\n\n/**\n * Frees resources used by a root menu and its children.\n *\n * \\param Menu A root menu.\n */\nVOID PhDestroyEMenu(\n    _In_ PPH_EMENU Menu\n    )\n{\n    ULONG i;\n\n    for (i = 0; i < Menu->Items->Count; i++)\n    {\n        PhpDestroyEMenuItem(Menu->Items->Items[i]);\n    }\n\n    PhDereferenceObject(Menu->Items);\n    PhFree(Menu);\n}\n\n/**\n * Initializes a data structure containing additional information resulting from a call to\n * PhEMenuToHMenu().\n */\nVOID PhInitializeEMenuData(\n    _Out_ PPH_EMENU_DATA Data\n    )\n{\n    Data->IdToItem = PhCreateList(16);\n}\n\n/**\n * Frees resources used by a data structure initialized by PhInitializeEMenuData().\n */\nVOID PhDeleteEMenuData(\n    _Inout_ PPH_EMENU_DATA Data\n    )\n{\n    PhDereferenceObject(Data->IdToItem);\n}\n\n/**\n * Converts an EMENU to a Windows menu object.\n *\n * \\param Menu The menu item to convert.\n * \\param Flags A combination of the following:\n * \\li \\c PH_EMENU_CONVERT_ID Automatically assigns a unique identifier to each converted menu item.\n * The resulting mappings are placed in \\a Data.\n * \\param Data Additional data resulting from the conversion. The data structure must be initialized\n * by PhInitializeEMenuData() prior to calling this function.\n *\n * \\return A menu handle. The menu object must be destroyed using DestroyMenu() when it is no longer\n * needed.\n */\nHMENU PhEMenuToHMenu(\n    _In_ PPH_EMENU_ITEM Menu,\n    _In_ ULONG Flags,\n    _Inout_opt_ PPH_EMENU_DATA Data\n    )\n{\n    HMENU menuHandle;\n\n    menuHandle = CreatePopupMenu();\n\n    if (!menuHandle)\n        return NULL;\n\n    PhEMenuToHMenu2(menuHandle, Menu, Flags, Data);\n\n    if (!(Menu->Flags & PH_EMENU_SEPARATECHECKSPACE))\n    {\n        MENUINFO menuInfo;\n\n        memset(&menuInfo, 0, sizeof(MENUINFO));\n        menuInfo.cbSize = sizeof(MENUINFO);\n        menuInfo.fMask = MIM_STYLE;\n        menuInfo.dwStyle = MNS_CHECKORBMP;\n        SetMenuInfo(menuHandle, &menuInfo);\n    }\n\n    return menuHandle;\n}\n\n/**\n * Converts an EMENU to a Windows menu object.\n *\n * \\param MenuHandle A handle to a Windows menu object.\n * \\param Menu The menu item to convert. The items are appended to \\a MenuHandle.\n * \\param Flags A combination of the following:\n * \\li \\c PH_EMENU_CONVERT_ID Automatically assigns a unique identifier to each converted menu item.\n * The resulting mappings are placed in \\a Data.\n * \\param Data Additional data resulting from the conversion. The data structure must be initialized\n * by PhInitializeEMenuData() prior to calling this function.\n */\nVOID PhEMenuToHMenu2(\n    _In_ HMENU MenuHandle,\n    _In_ PPH_EMENU_ITEM Menu,\n    _In_ ULONG Flags,\n    _Inout_opt_ PPH_EMENU_DATA Data\n    )\n{\n    ULONG i;\n    PPH_EMENU_ITEM item;\n    MENUITEMINFO menuItemInfo;\n\n    for (i = 0; i < Menu->Items->Count; i++)\n    {\n        item = Menu->Items->Items[i];\n\n        memset(&menuItemInfo, 0, sizeof(MENUITEMINFO));\n        menuItemInfo.cbSize = sizeof(MENUITEMINFO);\n\n        // Type\n\n        menuItemInfo.fMask = MIIM_FTYPE | MIIM_STATE;\n\n        if (item->Flags & PH_EMENU_SEPARATOR)\n        {\n            menuItemInfo.fType = MFT_SEPARATOR;\n        }\n        else\n        {\n            menuItemInfo.fType = MFT_STRING;\n            menuItemInfo.fMask |= MIIM_STRING;\n            menuItemInfo.dwTypeData = item->Text;\n        }\n\n        PhMapFlags1(\n            &menuItemInfo.fType,\n            item->Flags,\n            EMenuTypeMappings,\n            sizeof(EMenuTypeMappings) / sizeof(PH_FLAG_MAPPING)\n            );\n\n        // Bitmap\n\n        if (item->Bitmap)\n        {\n            menuItemInfo.fMask |= MIIM_BITMAP;\n            menuItemInfo.hbmpItem = item->Bitmap;\n        }\n\n        // Id\n\n        if (Flags & PH_EMENU_CONVERT_ID)\n        {\n            ULONG id;\n\n            if (Data)\n            {\n                PhAddItemList(Data->IdToItem, item);\n                id = Data->IdToItem->Count;\n\n                menuItemInfo.fMask |= MIIM_ID;\n                menuItemInfo.wID = id;\n            }\n        }\n        else\n        {\n            if (item->Id)\n            {\n                menuItemInfo.fMask |= MIIM_ID;\n                menuItemInfo.wID = item->Id;\n            }\n        }\n\n        // State\n\n        PhMapFlags1(\n            &menuItemInfo.fState,\n            item->Flags,\n            EMenuStateMappings,\n            sizeof(EMenuStateMappings) / sizeof(PH_FLAG_MAPPING)\n            );\n\n        // Context\n\n        menuItemInfo.fMask |= MIIM_DATA;\n        menuItemInfo.dwItemData = (ULONG_PTR)item;\n\n        // Submenu\n\n        if (item->Items && item->Items->Count != 0)\n        {\n            menuItemInfo.fMask |= MIIM_SUBMENU;\n            menuItemInfo.hSubMenu = PhEMenuToHMenu(item, Flags, Data);\n        }\n\n        InsertMenuItem(MenuHandle, MAXINT, TRUE, &menuItemInfo);\n    }\n}\n\n/**\n * Converts a Windows menu object to an EMENU.\n *\n * \\param MenuItem The menu item in which the converted menu items will be placed.\n * \\param MenuHandle A menu handle.\n */\nVOID PhHMenuToEMenuItem(\n    _Inout_ PPH_EMENU_ITEM MenuItem,\n    _In_ HMENU MenuHandle\n    )\n{\n    ULONG i;\n    ULONG count;\n\n    count = GetMenuItemCount(MenuHandle);\n\n    if (count != -1)\n    {\n        for (i = 0; i < count; i++)\n        {\n            MENUITEMINFO menuItemInfo;\n            WCHAR buffer[256];\n            PPH_EMENU_ITEM menuItem;\n\n            menuItemInfo.cbSize = sizeof(menuItemInfo);\n            menuItemInfo.fMask = MIIM_FTYPE | MIIM_ID | MIIM_STATE | MIIM_STRING | MIIM_SUBMENU;\n            menuItemInfo.cch = sizeof(buffer) / sizeof(WCHAR);\n            menuItemInfo.dwTypeData = buffer;\n\n            if (!GetMenuItemInfo(MenuHandle, i, TRUE, &menuItemInfo))\n                continue;\n\n            menuItem = PhCreateEMenuItem(\n                PH_EMENU_TEXT_OWNED,\n                menuItemInfo.wID,\n                PhDuplicateStringZ(buffer),\n                NULL,\n                NULL\n                );\n\n            if (menuItemInfo.fType & MFT_SEPARATOR)\n                menuItem->Flags |= PH_EMENU_SEPARATOR;\n\n            PhMapFlags2(\n                &menuItem->Flags,\n                menuItemInfo.fType,\n                EMenuTypeMappings,\n                sizeof(EMenuTypeMappings) / sizeof(PH_FLAG_MAPPING)\n                );\n            PhMapFlags2(\n                &menuItem->Flags,\n                menuItemInfo.fState,\n                EMenuStateMappings,\n                sizeof(EMenuStateMappings) / sizeof(PH_FLAG_MAPPING)\n                );\n\n            if (menuItemInfo.hSubMenu)\n                PhHMenuToEMenuItem(menuItem, menuItemInfo.hSubMenu);\n\n            PhInsertEMenuItem(MenuItem, menuItem, -1);\n        }\n    }\n}\n\n/**\n * Loads a menu resource and converts it to an EMENU.\n *\n * \\param MenuItem The menu item in which the converted menu items will be placed.\n * \\param InstanceHandle The module containing the menu resource.\n * \\param Resource The resource identifier.\n * \\param SubMenuIndex The index of the sub menu to use, or -1 to use the root menu.\n */\nVOID PhLoadResourceEMenuItem(\n    _Inout_ PPH_EMENU_ITEM MenuItem,\n    _In_ HINSTANCE InstanceHandle,\n    _In_ PWSTR Resource,\n    _In_ ULONG SubMenuIndex\n    )\n{\n    HMENU menu;\n    HMENU realMenu;\n\n    menu = LoadMenu(InstanceHandle, Resource);\n\n    if (SubMenuIndex != -1)\n        realMenu = GetSubMenu(menu, SubMenuIndex);\n    else\n        realMenu = menu;\n\n    PhHMenuToEMenuItem(MenuItem, realMenu);\n\n    DestroyMenu(menu);\n}\n\n/**\n * Displays a menu.\n *\n * \\param Menu A menu.\n * \\param WindowHandle The window that owns the popup menu.\n * \\param Flags A combination of the following:\n * \\li \\c PH_EMENU_SHOW_SEND_COMMAND A WM_COMMAND message is sent to the window when the user clicks\n * on a menu item.\n * \\li \\c PH_EMENU_SHOW_LEFTRIGHT The user can select menu items with both the left and right mouse\n * buttons.\n * \\param Align The alignment of the menu.\n * \\param X The horizontal location of the menu.\n * \\param Y The vertical location of the menu.\n *\n * \\return The selected menu item, or NULL if the menu was cancelled.\n */\nPPH_EMENU_ITEM PhShowEMenu(\n    _In_ PPH_EMENU Menu,\n    _In_ HWND WindowHandle,\n    _In_ ULONG Flags,\n    _In_ ULONG Align,\n    _In_ ULONG X,\n    _In_ ULONG Y\n    )\n{\n    PPH_EMENU_ITEM selectedItem;\n    ULONG result;\n    ULONG flags;\n    PH_EMENU_DATA data;\n    HMENU popupMenu;\n\n    selectedItem = NULL;\n    flags = TPM_RETURNCMD | TPM_NONOTIFY;\n\n    // Flags\n\n    if (Flags & PH_EMENU_SHOW_LEFTRIGHT)\n        flags |= TPM_RIGHTBUTTON;\n    else\n        flags |= TPM_LEFTBUTTON;\n\n    // Align\n\n    if (Align & PH_ALIGN_LEFT)\n        flags |= TPM_LEFTALIGN;\n    else if (Align & PH_ALIGN_RIGHT)\n        flags |= TPM_RIGHTALIGN;\n    else\n        flags |= TPM_CENTERALIGN;\n\n    if (Align & PH_ALIGN_TOP)\n        flags |= TPM_TOPALIGN;\n    else if (Align & PH_ALIGN_BOTTOM)\n        flags |= TPM_BOTTOMALIGN;\n    else\n        flags |= TPM_VCENTERALIGN;\n\n    PhInitializeEMenuData(&data);\n\n    if (popupMenu = PhEMenuToHMenu(Menu, PH_EMENU_CONVERT_ID, &data))\n    {\n        result = TrackPopupMenu(\n            popupMenu,\n            flags,\n            X,\n            Y,\n            0,\n            WindowHandle,\n            NULL\n            );\n\n        if (result != 0)\n        {\n            selectedItem = data.IdToItem->Items[result - 1];\n        }\n\n        DestroyMenu(popupMenu);\n    }\n\n    PhDeleteEMenuData(&data);\n\n    if ((Flags & PH_EMENU_SHOW_SEND_COMMAND) && selectedItem && selectedItem->Id != 0)\n        SendMessage(WindowHandle, WM_COMMAND, MAKEWPARAM(selectedItem->Id, 0), 0);\n\n    return selectedItem;\n}\n\n/**\n * Sets the flags of a menu item.\n *\n * \\param Item The parent menu item.\n * \\param Id The identifier of the child menu item.\n * \\param Mask The flags to modify.\n * \\param Value The new value of the flags.\n */\nBOOLEAN PhSetFlagsEMenuItem(\n    _Inout_ PPH_EMENU_ITEM Item,\n    _In_ ULONG Id,\n    _In_ ULONG Mask,\n    _In_ ULONG Value\n    )\n{\n    PPH_EMENU_ITEM item;\n\n    item = PhFindEMenuItem(Item, PH_EMENU_FIND_DESCEND, NULL, Id);\n\n    if (item)\n    {\n        item->Flags &= ~Mask;\n        item->Flags |= Value;\n\n        return TRUE;\n    }\n    else\n    {\n        return FALSE;\n    }\n}\n\n/**\n * Sets flags for all children of a menu item.\n *\n * \\param Item The parent menu item.\n * \\param Mask The flags to modify.\n * \\param Value The new value of the flags.\n */\nVOID PhSetFlagsAllEMenuItems(\n    _In_ PPH_EMENU_ITEM Item,\n    _In_ ULONG Mask,\n    _In_ ULONG Value\n    )\n{\n    ULONG i;\n\n    for (i = 0; i < Item->Items->Count; i++)\n    {\n        PPH_EMENU_ITEM item = Item->Items->Items[i];\n\n        item->Flags &= ~Mask;\n        item->Flags |= Value;\n    }\n}\n\nVOID PhModifyEMenuItem(\n    _Inout_ PPH_EMENU_ITEM Item,\n    _In_ ULONG ModifyFlags,\n    _In_ ULONG OwnedFlags,\n    _In_opt_ PWSTR Text,\n    _In_opt_ HBITMAP Bitmap\n    )\n{\n    if (ModifyFlags & PH_EMENU_MODIFY_TEXT)\n    {\n        if ((Item->Flags & PH_EMENU_TEXT_OWNED) && Item->Text)\n            PhFree(Item->Text);\n\n        Item->Text = Text;\n        Item->Flags &= ~PH_EMENU_TEXT_OWNED;\n        Item->Flags |= OwnedFlags & PH_EMENU_TEXT_OWNED;\n    }\n\n    if (ModifyFlags & PH_EMENU_MODIFY_BITMAP)\n    {\n        if ((Item->Flags & PH_EMENU_BITMAP_OWNED) && Item->Bitmap)\n            DeleteObject(Item->Bitmap);\n\n        Item->Bitmap = Bitmap;\n        Item->Flags &= ~PH_EMENU_BITMAP_OWNED;\n        Item->Flags |= OwnedFlags & PH_EMENU_BITMAP_OWNED;\n    }\n}\n"
  },
  {
    "path": "third_party/phlib/error.c",
    "content": "/*\n * Process Hacker -\n *   error codes\n *\n * Copyright (C) 2010-2011 wj32\n *\n * This file is part of Process Hacker.\n *\n * Process Hacker is free software; you can redistribute it and/or modify\n * it under the terms of the GNU General Public License as published by\n * the Free Software Foundation, either version 3 of the License, or\n * (at your option) any later version.\n *\n * Process Hacker is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n * GNU General Public License for more details.\n *\n * You should have received a copy of the GNU General Public License\n * along with Process Hacker.  If not, see <http://www.gnu.org/licenses/>.\n */\n\n#include <phbase.h>\n\n/**\n * Converts a NTSTATUS value to a Win32 error code.\n *\n * \\remarks This function handles FACILITY_NTWIN32 status values properly, unlike\n * RtlNtStatusToDosError.\n */\nULONG PhNtStatusToDosError(\n    _In_ NTSTATUS Status\n    )\n{\n    if (NT_NTWIN32(Status)) // RtlNtStatusToDosError doesn't seem to handle these cases correctly\n        return WIN32_FROM_NTSTATUS(Status);\n    else\n        return RtlNtStatusToDosError(Status);\n}\n\n/**\n * Converts a Win32 error code to a NTSTATUS value.\n *\n * \\remarks Only a small number of cases are currently supported. Other status values are wrapped\n * using FACILITY_NTWIN32.\n */\nNTSTATUS PhDosErrorToNtStatus(\n    _In_ ULONG DosError\n    )\n{\n    switch (DosError)\n    {\n    case ERROR_INVALID_FUNCTION: return STATUS_ILLEGAL_FUNCTION;\n    case ERROR_FILE_NOT_FOUND: return STATUS_NO_SUCH_FILE;\n    case ERROR_ACCESS_DENIED: return STATUS_ACCESS_DENIED;\n    case ERROR_INVALID_HANDLE: return STATUS_INVALID_HANDLE;\n    case ERROR_HANDLE_EOF: return STATUS_END_OF_FILE;\n    case ERROR_NOT_SUPPORTED: return STATUS_NOT_SUPPORTED;\n    case ERROR_INVALID_PARAMETER: return STATUS_INVALID_PARAMETER;\n    case ERROR_NOT_LOCKED: return STATUS_NOT_LOCKED;\n    case ERROR_MORE_DATA: return STATUS_MORE_ENTRIES;\n    case ERROR_NOACCESS: return STATUS_ACCESS_VIOLATION;\n    case ERROR_STACK_OVERFLOW: return STATUS_STACK_OVERFLOW;\n    case ERROR_INTERNAL_ERROR: return STATUS_INTERNAL_ERROR;\n    default: return NTSTATUS_FROM_WIN32(DosError);\n    }\n}\n\n/**\n * Determines whether a NTSTATUS value indicates that a file cannot be not found.\n */\nBOOLEAN PhNtStatusFileNotFound(\n    _In_ NTSTATUS Status\n    )\n{\n    switch (Status)\n    {\n    case STATUS_NO_SUCH_FILE:\n        return TRUE;\n    case STATUS_OBJECT_NAME_INVALID:\n        return TRUE;\n    case STATUS_OBJECT_NAME_NOT_FOUND:\n        return TRUE;\n    case STATUS_OBJECT_NO_LONGER_EXISTS:\n        return TRUE;\n    case STATUS_OBJECT_PATH_INVALID:\n        return TRUE;\n    case STATUS_OBJECT_PATH_NOT_FOUND:\n        return TRUE;\n    default: return FALSE;\n    }\n}\n"
  },
  {
    "path": "third_party/phlib/extlv.c",
    "content": "/*\n * Process Hacker -\n *   extended list view\n *\n * Copyright (C) 2010-2012 wj32\n * Copyright (C) 2017 dmex\n *\n * This file is part of Process Hacker.\n *\n * Process Hacker is free software; you can redistribute it and/or modify\n * it under the terms of the GNU General Public License as published by\n * the Free Software Foundation, either version 3 of the License, or\n * (at your option) any later version.\n *\n * Process Hacker is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n * GNU General Public License for more details.\n *\n * You should have received a copy of the GNU General Public License\n * along with Process Hacker.  If not, see <http://www.gnu.org/licenses/>.\n */\n\n/*\n * The extended list view adds some functionality to the default list view control, such as sorting,\n * item colors and fonts, better redraw disabling, and the ability to change the cursor. This is\n * currently implemented by hooking the window procedure.\n */\n\n#include <ph.h>\n\n#include <windowsx.h>\n\n#include <guisup.h>\n\n#define PH_MAX_COMPARE_FUNCTIONS 16\n\ntypedef struct _PH_EXTLV_CONTEXT\n{\n    HWND Handle;\n    PVOID Context;\n\n    // Sorting\n\n    BOOLEAN TriState;\n    ULONG SortColumn;\n    PH_SORT_ORDER SortOrder;\n    BOOLEAN SortFast;\n\n    PPH_COMPARE_FUNCTION TriStateCompareFunction;\n    PPH_COMPARE_FUNCTION CompareFunctions[PH_MAX_COMPARE_FUNCTIONS];\n    ULONG FallbackColumns[PH_MAX_COMPARE_FUNCTIONS];\n    ULONG NumberOfFallbackColumns;\n\n    // Color and Font\n    PPH_EXTLV_GET_ITEM_COLOR ItemColorFunction;\n    PPH_EXTLV_GET_ITEM_FONT ItemFontFunction;\n\n    // Misc.\n\n    LONG EnableRedraw;\n    HCURSOR Cursor;\n} PH_EXTLV_CONTEXT, *PPH_EXTLV_CONTEXT;\n\nLRESULT CALLBACK PhpExtendedListViewWndProc(\n    _In_ HWND hwnd,\n    _In_ UINT uMsg,\n    _In_ WPARAM wParam,\n    _In_ LPARAM lParam,\n    _In_ UINT_PTR uIdSubclass,\n    _In_ ULONG_PTR dwRefData\n    );\n\nINT PhpExtendedListViewCompareFunc(\n    _In_ LPARAM lParam1,\n    _In_ LPARAM lParam2,\n    _In_ LPARAM lParamSort\n    );\n\nINT PhpExtendedListViewCompareFastFunc(\n    _In_ LPARAM lParam1,\n    _In_ LPARAM lParam2,\n    _In_ LPARAM lParamSort\n    );\n\nINT PhpCompareListViewItems(\n    _In_ PPH_EXTLV_CONTEXT Context,\n    _In_ INT X,\n    _In_ INT Y,\n    _In_ PVOID XParam,\n    _In_ PVOID YParam,\n    _In_ ULONG Column,\n    _In_ BOOLEAN EnableDefault\n    );\n\nINT PhpDefaultCompareListViewItems(\n    _In_ PPH_EXTLV_CONTEXT Context,\n    _In_ INT X,\n    _In_ INT Y,\n    _In_ ULONG Column\n    );\n\n/**\n * Enables extended list view support for a list view control.\n *\n * \\param hWnd A handle to the list view control.\n */\nVOID PhSetExtendedListView(\n    _In_ HWND hWnd\n    )\n{\n    PPH_EXTLV_CONTEXT context;\n\n    context = PhAllocate(sizeof(PH_EXTLV_CONTEXT));\n\n    context->Handle = hWnd;\n    context->Context = NULL;\n    context->TriState = FALSE;\n    context->SortColumn = 0;\n    context->SortOrder = AscendingSortOrder;\n    context->SortFast = FALSE;\n    context->TriStateCompareFunction = NULL;\n    memset(context->CompareFunctions, 0, sizeof(context->CompareFunctions));\n    context->NumberOfFallbackColumns = 0;\n\n    context->ItemColorFunction = NULL;\n    context->ItemFontFunction = NULL;\n\n    context->EnableRedraw = 1;\n    context->Cursor = NULL;\n\n    SetWindowSubclass(hWnd, PhpExtendedListViewWndProc, 0, (ULONG_PTR)context);\n\n    ExtendedListView_Init(hWnd);\n}\n\nLRESULT CALLBACK PhpExtendedListViewWndProc(\n    _In_ HWND hwnd,\n    _In_ UINT uMsg,\n    _In_ WPARAM wParam,\n    _In_ LPARAM lParam,\n    _In_ UINT_PTR uIdSubclass,\n    _In_ ULONG_PTR dwRefData\n    )\n{\n    PPH_EXTLV_CONTEXT context = (PPH_EXTLV_CONTEXT)dwRefData;\n\n    switch (uMsg)\n    {\n    case WM_DESTROY:\n        {\n            RemoveWindowSubclass(hwnd, PhpExtendedListViewWndProc, uIdSubclass);\n\n            PhFree(context);\n        }\n        break;\n    case WM_NOTIFY:\n        {\n            LPNMHDR header = (LPNMHDR)lParam;\n\n            switch (header->code)\n            {\n            case HDN_ITEMCLICK:\n                {\n                    HWND headerHandle;\n\n                    headerHandle = (HWND)SendMessage(hwnd, LVM_GETHEADER, 0, 0);\n\n                    if (header->hwndFrom == headerHandle)\n                    {\n                        LPNMHEADER header2 = (LPNMHEADER)header;\n\n                        if (header2->iItem == context->SortColumn)\n                        {\n                            if (context->TriState)\n                            {\n                                if (context->SortOrder == AscendingSortOrder)\n                                    context->SortOrder = DescendingSortOrder;\n                                else if (context->SortOrder == DescendingSortOrder)\n                                    context->SortOrder = NoSortOrder;\n                                else\n                                    context->SortOrder = AscendingSortOrder;\n                            }\n                            else\n                            {\n                                if (context->SortOrder == AscendingSortOrder)\n                                    context->SortOrder = DescendingSortOrder;\n                                else\n                                    context->SortOrder = AscendingSortOrder;\n                            }\n                        }\n                        else\n                        {\n                            context->SortColumn = header2->iItem;\n                            context->SortOrder = AscendingSortOrder;\n                        }\n\n                        PhSetHeaderSortIcon(headerHandle, context->SortColumn, context->SortOrder);\n                        ExtendedListView_SortItems(hwnd);\n                    }\n                }\n                break;\n            }\n        }\n        break;\n    case WM_REFLECT + WM_NOTIFY:\n        {\n            LPNMHDR header = (LPNMHDR)lParam;\n\n            switch (header->code)\n            {\n            case NM_CUSTOMDRAW:\n                {\n                    if (header->hwndFrom == hwnd)\n                    {\n                        LPNMLVCUSTOMDRAW customDraw = (LPNMLVCUSTOMDRAW)header;\n\n                        switch (customDraw->nmcd.dwDrawStage)\n                        {\n                        case CDDS_PREPAINT:\n                            return CDRF_NOTIFYITEMDRAW;\n                        case CDDS_ITEMPREPAINT:\n                            {\n                                BOOLEAN colorChanged = FALSE;\n                                HFONT newFont = NULL;\n\n                                if (context->ItemColorFunction)\n                                {\n                                    customDraw->clrTextBk = context->ItemColorFunction(\n                                        (INT)customDraw->nmcd.dwItemSpec,\n                                        (PVOID)customDraw->nmcd.lItemlParam,\n                                        context->Context\n                                        );\n                                    colorChanged = TRUE;\n                                }\n\n                                if (context->ItemFontFunction)\n                                {\n                                    newFont = context->ItemFontFunction(\n                                        (INT)customDraw->nmcd.dwItemSpec,\n                                        (PVOID)customDraw->nmcd.lItemlParam,\n                                        context->Context\n                                        );\n                                }\n\n                                if (newFont)\n                                    SelectObject(customDraw->nmcd.hdc, newFont);\n\n                                if (colorChanged)\n                                {\n                                    if (PhGetColorBrightness(customDraw->clrTextBk) > 100) // slightly less than half\n                                        customDraw->clrText = RGB(0x00, 0x00, 0x00);\n                                    else\n                                        customDraw->clrText = RGB(0xff, 0xff, 0xff);\n                                }\n\n                                if (!newFont)\n                                    return CDRF_DODEFAULT;\n                                else\n                                    return CDRF_NEWFONT;\n                            }\n                            break;\n                        }\n                    }\n                }\n                break;\n            }\n        }\n        break;\n    case WM_SETCURSOR:\n        {\n            if (context->Cursor)\n            {\n                SetCursor(context->Cursor);\n                return TRUE;\n            }\n        }\n        break;\n    case WM_UPDATEUISTATE:\n        {\n            // Disable focus rectangles by setting or masking out the flag where appropriate.\n            switch (LOWORD(wParam))\n            {\n            case UIS_SET:\n                wParam |= UISF_HIDEFOCUS << 16;\n                break;\n            case UIS_CLEAR:\n            case UIS_INITIALIZE:\n                wParam &= ~(UISF_HIDEFOCUS << 16);\n                break;\n            }\n        }\n        break;\n    case ELVM_ADDFALLBACKCOLUMN:\n        {\n            if (context->NumberOfFallbackColumns < PH_MAX_COMPARE_FUNCTIONS)\n                context->FallbackColumns[context->NumberOfFallbackColumns++] = (ULONG)wParam;\n            else\n                return FALSE;\n        }\n        return TRUE;\n    case ELVM_ADDFALLBACKCOLUMNS:\n        {\n            ULONG numberOfColumns = (ULONG)wParam;\n            PULONG columns = (PULONG)lParam;\n\n            if (context->NumberOfFallbackColumns + numberOfColumns <= PH_MAX_COMPARE_FUNCTIONS)\n            {\n                memcpy(\n                    &context->FallbackColumns[context->NumberOfFallbackColumns],\n                    columns,\n                    numberOfColumns * sizeof(ULONG)\n                    );\n                context->NumberOfFallbackColumns += numberOfColumns;\n            }\n            else\n            {\n                return FALSE;\n            }\n        }\n        return TRUE;\n    case ELVM_INIT:\n        {\n            PhSetHeaderSortIcon(ListView_GetHeader(hwnd), context->SortColumn, context->SortOrder);\n\n            // HACK to fix tooltips showing behind Always On Top windows.\n            SetWindowPos(ListView_GetToolTips(hwnd), HWND_TOPMOST, 0, 0, 0, 0,\n                SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOSIZE);\n\n            // Make sure focus rectangles are disabled.\n            SendMessage(hwnd, WM_CHANGEUISTATE, MAKELONG(UIS_SET, UISF_HIDEFOCUS), 0);\n        }\n        return TRUE;\n    case ELVM_SETCOLUMNWIDTH:\n        {\n            ULONG column = (ULONG)wParam;\n            LONG width = (LONG)lParam;\n\n            if (width == ELVSCW_AUTOSIZE_REMAININGSPACE)\n            {\n                RECT clientRect;\n                LONG availableWidth;\n                ULONG i;\n                LVCOLUMN lvColumn;\n\n                GetClientRect(hwnd, &clientRect);\n                availableWidth = clientRect.right;\n                i = 0;\n                lvColumn.mask = LVCF_WIDTH;\n\n                while (TRUE)\n                {\n                    if (i != column)\n                    {\n                        if (SendMessage(hwnd, LVM_GETCOLUMN, i, (LPARAM)&lvColumn))\n                        {\n                            availableWidth -= lvColumn.cx;\n                        }\n                        else\n                        {\n                            break;\n                        }\n                    }\n\n                    i++;\n                }\n\n                if (availableWidth >= 40)\n                    return SendMessage(hwnd, LVM_SETCOLUMNWIDTH, column, availableWidth);\n            }\n\n            return SendMessage(hwnd, LVM_SETCOLUMNWIDTH, column, width);\n        }\n        break;\n    case ELVM_SETCOMPAREFUNCTION:\n        {\n            ULONG column = (ULONG)wParam;\n            PPH_COMPARE_FUNCTION compareFunction = (PPH_COMPARE_FUNCTION)lParam;\n\n            if (column >= PH_MAX_COMPARE_FUNCTIONS)\n                return FALSE;\n\n            context->CompareFunctions[column] = compareFunction;\n        }\n        return TRUE;\n    case ELVM_SETCONTEXT:\n        {\n            context->Context = (PVOID)lParam;\n        }\n        return TRUE;\n    case ELVM_SETCURSOR:\n        {\n            context->Cursor = (HCURSOR)lParam;\n        }\n        return TRUE;\n    case ELVM_SETITEMCOLORFUNCTION:\n        {\n            context->ItemColorFunction = (PPH_EXTLV_GET_ITEM_COLOR)lParam;\n        }\n        return TRUE;\n    case ELVM_SETITEMFONTFUNCTION:\n        {\n            context->ItemFontFunction = (PPH_EXTLV_GET_ITEM_FONT)lParam;\n        }\n        return TRUE;\n    case ELVM_SETREDRAW:\n        {\n            if (wParam)\n                context->EnableRedraw++;\n            else\n                context->EnableRedraw--;\n\n            if (context->EnableRedraw == 1)\n            {\n                SendMessage(hwnd, WM_SETREDRAW, TRUE, 0);\n                InvalidateRect(hwnd, NULL, FALSE);\n            }\n            else if (context->EnableRedraw == 0)\n            {\n                SendMessage(hwnd, WM_SETREDRAW, FALSE, 0);\n            }\n        }\n        return TRUE;\n    case ELVM_SETSORT:\n        {\n            context->SortColumn = (ULONG)wParam;\n            context->SortOrder = (PH_SORT_ORDER)lParam;\n\n            PhSetHeaderSortIcon(ListView_GetHeader(hwnd), context->SortColumn, context->SortOrder);\n        }\n        return TRUE;\n    case ELVM_SETSORTFAST:\n        {\n            context->SortFast = !!wParam;\n        }\n        return TRUE;\n    case ELVM_SETTRISTATE:\n        {\n            context->TriState = !!wParam;\n        }\n        return TRUE;\n    case ELVM_SETTRISTATECOMPAREFUNCTION:\n        {\n            context->TriStateCompareFunction = (PPH_COMPARE_FUNCTION)lParam;\n        }\n        return TRUE;\n    case ELVM_SORTITEMS:\n        {\n            if (context->SortFast)\n            {\n                // This sort method is faster than the normal sort because our comparison function\n                // doesn't have to call the list view window procedure to get the item lParam\n                // values. The disadvantage of this method is that default sorting is not available\n                // - if a column doesn't have a comparison function, it doesn't get sorted at all.\n\n                ListView_SortItems(\n                    hwnd,\n                    PhpExtendedListViewCompareFastFunc,\n                    (LPARAM)context\n                    );\n            }\n            else\n            {\n                ListView_SortItemsEx(\n                    hwnd,\n                    PhpExtendedListViewCompareFunc,\n                    (LPARAM)context\n                    );\n            }\n        }\n        return TRUE;\n    }\n\n    return DefSubclassProc(hwnd, uMsg, wParam, lParam);\n}\n\n/**\n * Visually indicates the sort order of a header control item.\n *\n * \\param hwnd A handle to the header control.\n * \\param Index The index of the item.\n * \\param Order The sort order of the item.\n */\nVOID PhSetHeaderSortIcon(\n    _In_ HWND hwnd,\n    _In_ INT Index,\n    _In_ PH_SORT_ORDER Order\n    )\n{\n    ULONG count;\n    ULONG i;\n\n    count = Header_GetItemCount(hwnd);\n\n    if (count == -1)\n        return;\n\n    for (i = 0; i < count; i++)\n    {\n        HDITEM item;\n\n        item.mask = HDI_FORMAT;\n        Header_GetItem(hwnd, i, &item);\n\n        if (Order != NoSortOrder && i == Index)\n        {\n            if (Order == AscendingSortOrder)\n            {\n                item.fmt &= ~HDF_SORTDOWN;\n                item.fmt |= HDF_SORTUP;\n            }\n            else if (Order == DescendingSortOrder)\n            {\n                item.fmt &= ~HDF_SORTUP;\n                item.fmt |= HDF_SORTDOWN;\n            }\n        }\n        else\n        {\n            item.fmt &= ~(HDF_SORTDOWN | HDF_SORTUP);\n        }\n\n        Header_SetItem(hwnd, i, &item);\n    }\n}\n\nstatic INT PhpExtendedListViewCompareFunc(\n    _In_ LPARAM lParam1,\n    _In_ LPARAM lParam2,\n    _In_ LPARAM lParamSort\n    )\n{\n    PPH_EXTLV_CONTEXT context = (PPH_EXTLV_CONTEXT)lParamSort;\n    INT result;\n    INT x = (INT)lParam1;\n    INT y = (INT)lParam2;\n    ULONG i;\n    PULONG fallbackColumns;\n    LVITEM xItem;\n    LVITEM yItem;\n\n    // Get the param values.\n\n    xItem.mask = LVIF_PARAM | LVIF_STATE;\n    xItem.iItem = x;\n    xItem.iSubItem = 0;\n\n    yItem.mask = LVIF_PARAM | LVIF_STATE;\n    yItem.iItem = y;\n    yItem.iSubItem = 0;\n\n    if (!SendMessage(context->Handle, LVM_GETITEM, 0, (LPARAM)&xItem))\n        return 0;\n    if (!SendMessage(context->Handle, LVM_GETITEM, 0, (LPARAM)&yItem))\n        return 0;\n\n    // First, do tri-state sorting.\n\n    if (\n        context->TriState &&\n        context->SortOrder == NoSortOrder &&\n        context->TriStateCompareFunction\n        )\n    {\n        result = context->TriStateCompareFunction(\n            (PVOID)xItem.lParam,\n            (PVOID)yItem.lParam,\n            context->Context\n            );\n\n        if (result != 0)\n            return result;\n    }\n\n    // Compare using the user-selected column and move on to the fallback columns if necessary.\n\n    result = PhpCompareListViewItems(context, x, y, (PVOID)xItem.lParam, (PVOID)yItem.lParam, context->SortColumn, TRUE);\n\n    if (result != 0)\n        return result;\n\n    fallbackColumns = context->FallbackColumns;\n\n    for (i = context->NumberOfFallbackColumns; i != 0; i--)\n    {\n        ULONG fallbackColumn = *fallbackColumns++;\n\n        if (fallbackColumn == context->SortColumn)\n            continue;\n\n        result = PhpCompareListViewItems(context, x, y, (PVOID)xItem.lParam, (PVOID)yItem.lParam, fallbackColumn, TRUE);\n\n        if (result != 0)\n            return result;\n    }\n\n    return 0;\n}\n\nstatic INT PhpExtendedListViewCompareFastFunc(\n    _In_ LPARAM lParam1,\n    _In_ LPARAM lParam2,\n    _In_ LPARAM lParamSort\n    )\n{\n    PPH_EXTLV_CONTEXT context = (PPH_EXTLV_CONTEXT)lParamSort;\n    INT result;\n    ULONG i;\n    PULONG fallbackColumns;\n\n    if (!lParam1 || !lParam2)\n        return 0;\n\n    // First, do tri-state sorting.\n\n    if (\n        context->TriState &&\n        context->SortOrder == NoSortOrder &&\n        context->TriStateCompareFunction\n        )\n    {\n        result = context->TriStateCompareFunction(\n            (PVOID)lParam1,\n            (PVOID)lParam2,\n            context->Context\n            );\n\n        if (result != 0)\n            return result;\n    }\n\n    // Compare using the user-selected column and move on to the fallback columns if necessary.\n\n    result = PhpCompareListViewItems(context, 0, 0, (PVOID)lParam1, (PVOID)lParam2, context->SortColumn, FALSE);\n\n    if (result != 0)\n        return result;\n\n    fallbackColumns = context->FallbackColumns;\n\n    for (i = context->NumberOfFallbackColumns; i != 0; i--)\n    {\n        ULONG fallbackColumn = *fallbackColumns++;\n\n        if (fallbackColumn == context->SortColumn)\n            continue;\n\n        result = PhpCompareListViewItems(context, 0, 0, (PVOID)lParam1, (PVOID)lParam2, fallbackColumn, FALSE);\n\n        if (result != 0)\n            return result;\n    }\n\n    return 0;\n}\n\nstatic FORCEINLINE INT PhpCompareListViewItems(\n    _In_ PPH_EXTLV_CONTEXT Context,\n    _In_ INT X,\n    _In_ INT Y,\n    _In_ PVOID XParam,\n    _In_ PVOID YParam,\n    _In_ ULONG Column,\n    _In_ BOOLEAN EnableDefault\n    )\n{\n    INT result = 0;\n\n    if (\n        Column < PH_MAX_COMPARE_FUNCTIONS &&\n        Context->CompareFunctions[Column]\n        )\n    {\n        result = PhModifySort(\n            Context->CompareFunctions[Column](XParam, YParam, Context->Context),\n            Context->SortOrder\n            );\n\n        if (result != 0)\n            return result;\n    }\n\n    if (EnableDefault)\n    {\n        return PhModifySort(\n            PhpDefaultCompareListViewItems(Context, X, Y, Column),\n            Context->SortOrder\n            );\n    }\n    else\n    {\n        return 0;\n    }\n}\n\nstatic INT PhpDefaultCompareListViewItems(\n    _In_ PPH_EXTLV_CONTEXT Context,\n    _In_ INT X,\n    _In_ INT Y,\n    _In_ ULONG Column\n    )\n{\n    WCHAR xText[261];\n    WCHAR yText[261];\n    LVITEM item;\n\n    // Get the X item text.\n\n    item.mask = LVIF_TEXT;\n    item.iItem = X;\n    item.iSubItem = Column;\n    item.pszText = xText;\n    item.cchTextMax = 260;\n\n    xText[0] = 0;\n    SendMessage(Context->Handle, LVM_GETITEM, 0, (LPARAM)&item);\n\n    // Get the Y item text.\n\n    item.iItem = Y;\n    item.pszText = yText;\n    item.cchTextMax = 260;\n\n    yText[0] = 0;\n    SendMessage(Context->Handle, LVM_GETITEM, 0, (LPARAM)&item);\n\n    // Compare them.\n\n#if 1\n    return PhCompareStringZNatural(xText, yText, TRUE);\n#else\n    return _wcsicmp(xText, yText);\n#endif\n}\n"
  },
  {
    "path": "third_party/phlib/fastlock.c",
    "content": "/*\n * Process Hacker -\n *   fast resource lock\n *\n * Copyright (C) 2009-2010 wj32\n *\n * This file is part of Process Hacker.\n *\n * Process Hacker is free software; you can redistribute it and/or modify\n * it under the terms of the GNU General Public License as published by\n * the Free Software Foundation, either version 3 of the License, or\n * (at your option) any later version.\n *\n * Process Hacker is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n * GNU General Public License for more details.\n *\n * You should have received a copy of the GNU General Public License\n * along with Process Hacker.  If not, see <http://www.gnu.org/licenses/>.\n */\n\n#include <phbase.h>\n#include <fastlock.h>\n\n// FastLock is a port of FastResourceLock from PH 1.x.\n//\n// The code contains no comments because it is a direct port. Please see FastResourceLock.cs in PH\n// 1.x for details.\n\n// The fast lock is around 7% faster than the critical section when there is no contention, when\n// used solely for mutual exclusion. It is also much smaller than the critical section.\n\n#define PH_LOCK_OWNED 0x1\n#define PH_LOCK_EXCLUSIVE_WAKING 0x2\n\n#define PH_LOCK_SHARED_OWNERS_SHIFT 2\n#define PH_LOCK_SHARED_OWNERS_MASK 0x3ff\n#define PH_LOCK_SHARED_OWNERS_INC 0x4\n\n#define PH_LOCK_SHARED_WAITERS_SHIFT 12\n#define PH_LOCK_SHARED_WAITERS_MASK 0x3ff\n#define PH_LOCK_SHARED_WAITERS_INC 0x1000\n\n#define PH_LOCK_EXCLUSIVE_WAITERS_SHIFT 22\n#define PH_LOCK_EXCLUSIVE_WAITERS_MASK 0x3ff\n#define PH_LOCK_EXCLUSIVE_WAITERS_INC 0x400000\n\n#define PH_LOCK_EXCLUSIVE_MASK \\\n    (PH_LOCK_EXCLUSIVE_WAKING | \\\n    (PH_LOCK_EXCLUSIVE_WAITERS_MASK << PH_LOCK_EXCLUSIVE_WAITERS_SHIFT))\n\nVOID PhInitializeFastLock(\n    _Out_ PPH_FAST_LOCK FastLock\n    )\n{\n    FastLock->Value = 0;\n    FastLock->ExclusiveWakeEvent = NULL;\n    FastLock->SharedWakeEvent = NULL;\n}\n\nVOID PhDeleteFastLock(\n    _Inout_ PPH_FAST_LOCK FastLock\n    )\n{\n    if (FastLock->ExclusiveWakeEvent)\n    {\n        NtClose(FastLock->ExclusiveWakeEvent);\n        FastLock->ExclusiveWakeEvent = NULL;\n    }\n\n    if (FastLock->SharedWakeEvent)\n    {\n        NtClose(FastLock->SharedWakeEvent);\n        FastLock->SharedWakeEvent = NULL;\n    }\n}\n\nFORCEINLINE VOID PhpEnsureEventCreated(\n    _Inout_ PHANDLE Handle\n    )\n{\n    HANDLE handle;\n\n    if (*Handle != NULL)\n        return;\n\n    NtCreateSemaphore(&handle, SEMAPHORE_ALL_ACCESS, NULL, 0, MAXLONG);\n\n    if (_InterlockedCompareExchangePointer(\n        Handle,\n        handle,\n        NULL\n        ) != NULL)\n    {\n        NtClose(handle);\n    }\n}\n\nFORCEINLINE ULONG PhpGetSpinCount(\n    VOID\n    )\n{\n    if ((ULONG)PhSystemBasicInformation.NumberOfProcessors > 1)\n        return 4000;\n    else\n        return 0;\n}\n\n_May_raise_\n_Acquires_exclusive_lock_(*FastLock)\nVOID FASTCALL PhfAcquireFastLockExclusive(\n    _Inout_ PPH_FAST_LOCK FastLock\n    )\n{\n    ULONG value;\n    ULONG i = 0;\n    ULONG spinCount;\n\n    spinCount = PhpGetSpinCount();\n\n    while (TRUE)\n    {\n        value = FastLock->Value;\n\n        if (!(value & (PH_LOCK_OWNED | PH_LOCK_EXCLUSIVE_WAKING)))\n        {\n            if (_InterlockedCompareExchange(\n                &FastLock->Value,\n                value + PH_LOCK_OWNED,\n                value\n                ) == value)\n                break;\n        }\n        else if (i >= spinCount)\n        {\n            PhpEnsureEventCreated(&FastLock->ExclusiveWakeEvent);\n\n            if (_InterlockedCompareExchange(\n                &FastLock->Value,\n                value + PH_LOCK_EXCLUSIVE_WAITERS_INC,\n                value\n                ) == value)\n            {\n                if (NtWaitForSingleObject(\n                    FastLock->ExclusiveWakeEvent,\n                    FALSE,\n                    NULL\n                    ) != STATUS_WAIT_0)\n                    PhRaiseStatus(STATUS_UNSUCCESSFUL);\n\n                do\n                {\n                    value = FastLock->Value;\n                } while (_InterlockedCompareExchange(\n                    &FastLock->Value,\n                    value + PH_LOCK_OWNED - PH_LOCK_EXCLUSIVE_WAKING,\n                    value\n                    ) != value);\n\n                break;\n            }\n        }\n\n        i++;\n        YieldProcessor();\n    }\n}\n\n_May_raise_\n_Acquires_shared_lock_(*FastLock)\nVOID FASTCALL PhfAcquireFastLockShared(\n    _Inout_ PPH_FAST_LOCK FastLock\n    )\n{\n    ULONG value;\n    ULONG i = 0;\n    ULONG spinCount;\n\n    spinCount = PhpGetSpinCount();\n\n    while (TRUE)\n    {\n        value = FastLock->Value;\n\n        if (!(value & (\n            PH_LOCK_OWNED |\n            (PH_LOCK_SHARED_OWNERS_MASK << PH_LOCK_SHARED_OWNERS_SHIFT) |\n            PH_LOCK_EXCLUSIVE_MASK\n            )))\n        {\n            if (_InterlockedCompareExchange(\n                &FastLock->Value,\n                value + PH_LOCK_OWNED + PH_LOCK_SHARED_OWNERS_INC,\n                value\n                ) == value)\n                break;\n        }\n        else if (\n            (value & PH_LOCK_OWNED) &&\n            ((value >> PH_LOCK_SHARED_OWNERS_SHIFT) & PH_LOCK_SHARED_OWNERS_MASK) > 0 &&\n            !(value & PH_LOCK_EXCLUSIVE_MASK)\n            )\n        {\n            if (_InterlockedCompareExchange(\n                &FastLock->Value,\n                value + PH_LOCK_SHARED_OWNERS_INC,\n                value\n                ) == value)\n                break;\n        }\n        else if (i >= spinCount)\n        {\n            PhpEnsureEventCreated(&FastLock->SharedWakeEvent);\n\n            if (_InterlockedCompareExchange(\n                &FastLock->Value,\n                value + PH_LOCK_SHARED_WAITERS_INC,\n                value\n                ) == value)\n            {\n                if (NtWaitForSingleObject(\n                    FastLock->SharedWakeEvent,\n                    FALSE,\n                    NULL\n                    ) != STATUS_WAIT_0)\n                    PhRaiseStatus(STATUS_UNSUCCESSFUL);\n\n                continue;\n            }\n        }\n\n        i++;\n        YieldProcessor();\n    }\n}\n\n_Releases_exclusive_lock_(*FastLock)\nVOID FASTCALL PhfReleaseFastLockExclusive(\n    _Inout_ PPH_FAST_LOCK FastLock\n    )\n{\n    ULONG value;\n\n    while (TRUE)\n    {\n        value = FastLock->Value;\n\n        if ((value >> PH_LOCK_EXCLUSIVE_WAITERS_SHIFT) & PH_LOCK_EXCLUSIVE_WAITERS_MASK)\n        {\n            if (_InterlockedCompareExchange(\n                &FastLock->Value,\n                value - PH_LOCK_OWNED + PH_LOCK_EXCLUSIVE_WAKING - PH_LOCK_EXCLUSIVE_WAITERS_INC,\n                value\n                ) == value)\n            {\n                NtReleaseSemaphore(FastLock->ExclusiveWakeEvent, 1, NULL);\n\n                break;\n            }\n        }\n        else\n        {\n            ULONG sharedWaiters;\n\n            sharedWaiters = (value >> PH_LOCK_SHARED_WAITERS_SHIFT) & PH_LOCK_SHARED_WAITERS_MASK;\n\n            if (_InterlockedCompareExchange(\n                &FastLock->Value,\n                value & ~(PH_LOCK_OWNED | (PH_LOCK_SHARED_WAITERS_MASK << PH_LOCK_SHARED_WAITERS_SHIFT)),\n                value\n                ) == value)\n            {\n                if (sharedWaiters)\n                    NtReleaseSemaphore(FastLock->SharedWakeEvent, sharedWaiters, 0);\n\n                break;\n            }\n        }\n\n        YieldProcessor();\n    }\n}\n\n_Releases_shared_lock_(*FastLock)\nVOID FASTCALL PhfReleaseFastLockShared(\n    _Inout_ PPH_FAST_LOCK FastLock\n    )\n{\n    ULONG value;\n\n    while (TRUE)\n    {\n        value = FastLock->Value;\n\n        if (((value >> PH_LOCK_SHARED_OWNERS_SHIFT) & PH_LOCK_SHARED_OWNERS_MASK) > 1)\n        {\n            if (_InterlockedCompareExchange(\n                &FastLock->Value,\n                value - PH_LOCK_SHARED_OWNERS_INC,\n                value\n                ) == value)\n                break;\n        }\n        else if ((value >> PH_LOCK_EXCLUSIVE_WAITERS_SHIFT) & PH_LOCK_EXCLUSIVE_WAITERS_MASK)\n        {\n            if (_InterlockedCompareExchange(\n                &FastLock->Value,\n                value - PH_LOCK_OWNED + PH_LOCK_EXCLUSIVE_WAKING -\n                PH_LOCK_SHARED_OWNERS_INC - PH_LOCK_EXCLUSIVE_WAITERS_INC,\n                value\n                ) == value)\n            {\n                NtReleaseSemaphore(FastLock->ExclusiveWakeEvent, 1, NULL);\n\n                break;\n            }\n        }\n        else\n        {\n            if (_InterlockedCompareExchange(\n                &FastLock->Value,\n                value - PH_LOCK_OWNED - PH_LOCK_SHARED_OWNERS_INC,\n                value\n                ) == value)\n                break;\n        }\n\n        YieldProcessor();\n    }\n}\n\n_When_(return != 0, _Acquires_exclusive_lock_(*FastLock))\nBOOLEAN FASTCALL PhfTryAcquireFastLockExclusive(\n    _Inout_ PPH_FAST_LOCK FastLock\n    )\n{\n    ULONG value;\n\n    value = FastLock->Value;\n\n    if (value & (PH_LOCK_OWNED | PH_LOCK_EXCLUSIVE_WAKING))\n        return FALSE;\n\n    return _InterlockedCompareExchange(\n        &FastLock->Value,\n        value + PH_LOCK_OWNED,\n        value\n        ) == value;\n}\n\n_When_(return != 0, _Acquires_shared_lock_(*FastLock))\nBOOLEAN FASTCALL PhfTryAcquireFastLockShared(\n    _Inout_ PPH_FAST_LOCK FastLock\n    )\n{\n    ULONG value;\n\n    value = FastLock->Value;\n\n    if (value & PH_LOCK_EXCLUSIVE_MASK)\n        return FALSE;\n\n    if (!(value & PH_LOCK_OWNED))\n    {\n        return _InterlockedCompareExchange(\n            &FastLock->Value,\n            value + PH_LOCK_OWNED + PH_LOCK_SHARED_OWNERS_INC,\n            value\n            ) == value;\n    }\n    else if ((value >> PH_LOCK_SHARED_OWNERS_SHIFT) & PH_LOCK_SHARED_OWNERS_MASK)\n    {\n        return _InterlockedCompareExchange(\n            &FastLock->Value,\n            value + PH_LOCK_SHARED_OWNERS_INC,\n            value\n            ) == value;\n    }\n    else\n    {\n        return FALSE;\n    }\n}\n"
  },
  {
    "path": "third_party/phlib/filepool.c",
    "content": "/*\n * Process Hacker -\n *   file-based allocator\n *\n * Copyright (C) 2011 wj32\n *\n * This file is part of Process Hacker.\n *\n * Process Hacker is free software; you can redistribute it and/or modify\n * it under the terms of the GNU General Public License as published by\n * the Free Software Foundation, either version 3 of the License, or\n * (at your option) any later version.\n *\n * Process Hacker is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n * GNU General Public License for more details.\n *\n * You should have received a copy of the GNU General Public License\n * along with Process Hacker.  If not, see <http://www.gnu.org/licenses/>.\n */\n\n/*\n * File pool allows blocks of storage to be allocated from a file. Each file looks like this:\n *\n * Segment 0 __________________________________________________________\n * |              |                |              |                |\n * | Block Header |  File Header   | Block Header | Segment Header |\n * |______________|________________|______________|________________|\n * |              |                |              |                |\n * | Block Header |    User Data   | Block Header |    User Data   |\n * |______________|________________|______________|________________|\n * |              |                |              |                |\n * |      ...     |       ...      |     ...      |      ...       |\n * |______________|________________|______________|________________|\n * Segment 1 __________________________________________________________\n * |              |                |              |                |\n * | Block Header | Segment Header | Block Header |    User Data   |\n * |______________|________________|______________|________________|\n * |              |                |              |                |\n * |      ...     |       ...      |     ...      |      ...       |\n * |______________|________________|______________|________________|\n * Segment 2 __________________________________________________________\n * |              |                |              |                |\n * |      ...     |       ...      |     ...      |      ...       |\n * |______________|________________|______________|________________|\n *\n */\n\n/*\n * A file consists of a variable number of segments, with the segment size specified as a power of\n * two. Each segment contains a fixed number of blocks, leading to a variable block size. Every\n * allocation made by the user is an allocation of a certain number of blocks, with enough space for\n * the block header. This is placed at the beginning of each allocation and contains the number of\n * blocks in the allocation (a better name for it would be the allocation header).\n *\n * Block management in each segment is handled by a bitmap which is stored in the segment header at\n * the beginning of each segment. The first segment (segment 0) is special with the file header\n * being placed immediately after an initial block header. This is because the segment size is\n * stored in the file header, and without it we cannot calculate the block size, which is used to\n * locate everything else in the file.\n *\n * To speed up allocations a number of free lists are maintained which categorize each segment based\n * on how many free blocks they have. This means we can avoid trying to allocate from every existing\n * segment before finding out we have to allocate a new segment, or trying to allocate from segments\n * without the required number of free blocks. The downside of this technique is that it doesn't\n * account for fragmentation within the allocation bitmap.\n *\n * Each segment is mapped in separately, and each view is cached. Even after a view becomes inactive\n * (has a reference count of 0) it remains mapped in until the maximum number of inactive views is\n * reached.\n */\n\n#include <ph.h>\n#include <filepool.h>\n\n#include <filepoolp.h>\n\n/**\n * Creates or opens a file pool.\n *\n * \\param Pool A variable which receives the file pool instance.\n * \\param FileHandle A handle to the file.\n * \\param ReadOnly TRUE to disallow writes to the file.\n * \\param Parameters Parameters for on-disk and runtime structures.\n */\nNTSTATUS PhCreateFilePool(\n    _Out_ PPH_FILE_POOL *Pool,\n    _In_ HANDLE FileHandle,\n    _In_ BOOLEAN ReadOnly,\n    _In_opt_ PPH_FILE_POOL_PARAMETERS Parameters\n    )\n{\n    NTSTATUS status;\n    PPH_FILE_POOL pool;\n    LARGE_INTEGER fileSize;\n    PH_FILE_POOL_PARAMETERS localParameters;\n    BOOLEAN creating;\n    HANDLE sectionHandle;\n    PPH_FP_BLOCK_HEADER initialBlock;\n    PPH_FP_FILE_HEADER header;\n    ULONG i;\n\n    if (Parameters)\n    {\n        PhpValidateFilePoolParameters(Parameters);\n    }\n    else\n    {\n        PhpSetDefaultFilePoolParameters(&localParameters);\n        Parameters = &localParameters;\n    }\n\n    pool = PhAllocate(sizeof(PH_FILE_POOL));\n    memset(pool, 0, sizeof(PH_FILE_POOL));\n\n    pool->FileHandle = FileHandle;\n    pool->ReadOnly = ReadOnly;\n\n    if (!NT_SUCCESS(status = PhGetFileSize(FileHandle, &fileSize)))\n        goto CleanupExit;\n\n    creating = FALSE;\n\n    // If the file is smaller than the page size, assume we're creating a new file.\n    if (fileSize.QuadPart < PAGE_SIZE)\n    {\n        if (ReadOnly)\n        {\n            status = STATUS_BAD_FILE_TYPE;\n            goto CleanupExit;\n        }\n\n        fileSize.QuadPart = PAGE_SIZE;\n\n        if (!NT_SUCCESS(status = PhSetFileSize(FileHandle, &fileSize)))\n            goto CleanupExit;\n\n        creating = TRUE;\n    }\n\n    // Create a section.\n    status = NtCreateSection(\n        &sectionHandle,\n        SECTION_ALL_ACCESS,\n        NULL,\n        &fileSize,\n        !ReadOnly ? PAGE_READWRITE : PAGE_READONLY,\n        SEC_COMMIT,\n        FileHandle\n        );\n\n    if (!NT_SUCCESS(status))\n        goto CleanupExit;\n\n    pool->SectionHandle = sectionHandle;\n\n    // Map in the first segment, set up initial parameters, then remap the first segment.\n\n    if (!NT_SUCCESS(status = PhFppMapRange(pool, 0, PAGE_SIZE, &initialBlock)))\n        goto CleanupExit;\n\n    header = (PPH_FP_FILE_HEADER)&initialBlock->Body;\n\n    if (creating)\n    {\n        header->Magic = PH_FP_MAGIC;\n        header->SegmentShift = Parameters->SegmentShift;\n        header->SegmentCount = 1;\n\n        for (i = 0; i < PH_FP_FREE_LIST_COUNT; i++)\n            header->FreeLists[i] = -1;\n    }\n    else\n    {\n        if (header->Magic != PH_FP_MAGIC)\n        {\n            PhFppUnmapRange(pool, initialBlock);\n            status = STATUS_BAD_FILE_TYPE;\n            goto CleanupExit;\n        }\n    }\n\n    pool->SegmentShift = header->SegmentShift;\n    pool->SegmentSize = 1 << pool->SegmentShift;\n\n    pool->BlockShift = pool->SegmentShift - PH_FP_BLOCK_COUNT_SHIFT;\n    pool->BlockSize = 1 << pool->BlockShift;\n    pool->FileHeaderBlockSpan = (sizeof(PH_FP_FILE_HEADER) + pool->BlockSize - 1) >> pool->BlockShift;\n    pool->SegmentHeaderBlockSpan = (sizeof(PH_FP_SEGMENT_HEADER) + pool->BlockSize - 1) >> pool->BlockShift;\n\n    // Unmap the first segment and remap with the new segment size.\n\n    PhFppUnmapRange(pool, initialBlock);\n\n    if (creating)\n    {\n        // Extend the section so it fits the entire first segment.\n        if (!NT_SUCCESS(status = PhFppExtendRange(pool, pool->SegmentSize)))\n            goto CleanupExit;\n    }\n\n    // Runtime structure initialization\n\n    PhInitializeFreeList(&pool->ViewFreeList, sizeof(PH_FILE_POOL_VIEW), 32);\n    pool->ByIndexSize = 32;\n    pool->ByIndexBuckets = PhAllocate(sizeof(PPH_FILE_POOL_VIEW) * pool->ByIndexSize);\n    memset(pool->ByIndexBuckets, 0, sizeof(PPH_FILE_POOL_VIEW) * pool->ByIndexSize);\n    PhInitializeAvlTree(&pool->ByBaseSet, PhpFilePoolViewByBaseCompareFunction);\n\n    pool->MaximumInactiveViews = Parameters->MaximumInactiveViews;\n    InitializeListHead(&pool->InactiveViewsListHead);\n\n    // File structure initialization\n\n    pool->FirstBlockOfFirstSegment = PhFppReferenceSegment(pool, 0);\n    pool->Header = (PPH_FP_FILE_HEADER)&pool->FirstBlockOfFirstSegment->Body;\n\n    if (creating)\n    {\n        PPH_FP_BLOCK_HEADER segmentHeaderBlock;\n\n        // Set up the first segment properly.\n\n        pool->FirstBlockOfFirstSegment->Span = pool->FileHeaderBlockSpan;\n        segmentHeaderBlock = (PPH_FP_BLOCK_HEADER)PTR_ADD_OFFSET(pool->FirstBlockOfFirstSegment, (pool->FileHeaderBlockSpan << pool->BlockShift));\n        PhFppInitializeSegment(pool, segmentHeaderBlock, pool->FileHeaderBlockSpan);\n\n        pool->Header->FreeLists[1] = 0;\n    }\n\nCleanupExit:\n    if (NT_SUCCESS(status))\n    {\n        *Pool = pool;\n    }\n    else\n    {\n        // Don't close the file handle the user passed in.\n        pool->FileHandle = NULL;\n        PhDestroyFilePool(pool);\n    }\n\n    return status;\n}\n\n/**\n * Creates or opens a file pool.\n *\n * \\param Pool A variable which receives the file pool instance.\n * \\param FileName The file name of the file pool.\n * \\param ReadOnly TRUE to disallow writes to the file.\n * \\param ShareAccess The file access granted to other threads.\n * \\param CreateDisposition The action to perform if the file does or does not exist. See\n * PhCreateFileWin32() for more information.\n * \\param Parameters Parameters for on-disk and runtime structures.\n */\nNTSTATUS PhCreateFilePool2(\n    _Out_ PPH_FILE_POOL *Pool,\n    _In_ PWSTR FileName,\n    _In_ BOOLEAN ReadOnly,\n    _In_ ULONG ShareAccess,\n    _In_ ULONG CreateDisposition,\n    _In_opt_ PPH_FILE_POOL_PARAMETERS Parameters\n    )\n{\n    NTSTATUS status;\n    PPH_FILE_POOL pool;\n    HANDLE fileHandle;\n    ULONG createStatus;\n\n    if (!NT_SUCCESS(status = PhCreateFileWin32Ex(\n        &fileHandle,\n        FileName,\n        !ReadOnly ? (FILE_GENERIC_READ | FILE_GENERIC_WRITE | DELETE) : FILE_GENERIC_READ,\n        FILE_ATTRIBUTE_NORMAL,\n        ShareAccess,\n        CreateDisposition,\n        FILE_NON_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT,\n        &createStatus\n        )))\n    {\n        return status;\n    }\n\n    status = PhCreateFilePool(&pool, fileHandle, ReadOnly, Parameters);\n\n    if (NT_SUCCESS(status))\n    {\n        *Pool = pool;\n    }\n    else\n    {\n        if (!ReadOnly && createStatus == FILE_CREATED)\n        {\n            FILE_DISPOSITION_INFORMATION dispositionInfo;\n            IO_STATUS_BLOCK isb;\n\n            dispositionInfo.DeleteFile = TRUE;\n            NtSetInformationFile(fileHandle, &isb, &dispositionInfo, sizeof(FILE_DISPOSITION_INFORMATION), FileDispositionInformation);\n        }\n\n        NtClose(fileHandle);\n    }\n\n    return status;\n}\n\n/**\n * Frees resources used by a file pool instance.\n *\n * \\param Pool The file pool.\n */\nVOID PhDestroyFilePool(\n    _In_ _Post_invalid_ PPH_FILE_POOL Pool\n    )\n{\n    ULONG i;\n    PLIST_ENTRY head;\n    PLIST_ENTRY entry;\n    PPH_FILE_POOL_VIEW view;\n\n    // Unmap all views.\n    for (i = 0; i < Pool->ByIndexSize; i++)\n    {\n        if (head = Pool->ByIndexBuckets[i])\n        {\n            entry = head;\n\n            do\n            {\n                view = CONTAINING_RECORD(entry, PH_FILE_POOL_VIEW, ByIndexListEntry);\n                entry = entry->Flink;\n                PhFppUnmapRange(Pool, view->Base);\n                PhFreeToFreeList(&Pool->ViewFreeList, view);\n            } while (entry != head);\n        }\n    }\n\n    if (Pool->ByIndexBuckets)\n        PhFree(Pool->ByIndexBuckets);\n\n    PhDeleteFreeList(&Pool->ViewFreeList);\n\n    if (Pool->SectionHandle)\n        NtClose(Pool->SectionHandle);\n    if (Pool->FileHandle)\n        NtClose(Pool->FileHandle);\n\n    PhFree(Pool);\n}\n\n/**\n * Validates and corrects file pool parameters.\n *\n * \\param Parameters The parameters structure which is validated and modified if necessary.\n */\nNTSTATUS PhpValidateFilePoolParameters(\n    _Inout_ PPH_FILE_POOL_PARAMETERS Parameters\n    )\n{\n    NTSTATUS status = STATUS_SUCCESS;\n\n    // 16 <= SegmentShift <= 28\n\n    if (Parameters->SegmentShift < 16)\n    {\n        Parameters->SegmentShift = 16;\n        status = STATUS_SOME_NOT_MAPPED;\n    }\n\n    if (Parameters->SegmentShift > 28)\n    {\n        Parameters->SegmentShift = 28;\n        status = STATUS_SOME_NOT_MAPPED;\n    }\n\n    return status;\n}\n\n/**\n * Creates default file pool parameters.\n *\n * \\param Parameters The parameters structure which receives the default parameter values.\n */\nVOID PhpSetDefaultFilePoolParameters(\n    _Out_ PPH_FILE_POOL_PARAMETERS Parameters\n    )\n{\n    Parameters->SegmentShift = 18; // 256kB\n    Parameters->MaximumInactiveViews = 128;\n}\n\n/**\n * Allocates a block from a file pool.\n *\n * \\param Pool The file pool.\n * \\param Size The number of bytes to allocate.\n * \\param Rva A variable which receives the relative virtual address of the allocated block.\n *\n * \\return A pointer to the allocated block. You must call PhDereferenceFilePool() or\n * PhDereferenceFilePoolByRva() when you no longer need a reference to the block.\n *\n * \\remarks The returned pointer is not valid beyond the lifetime of the file pool instance. Use the\n * relative virtual address if you need a permanent reference to the allocated block.\n */\nPVOID PhAllocateFilePool(\n    _Inout_ PPH_FILE_POOL Pool,\n    _In_ ULONG Size,\n    _Out_opt_ PULONG Rva\n    )\n{\n    PPH_FP_BLOCK_HEADER blockHeader;\n    ULONG numberOfBlocks;\n    PPH_FP_BLOCK_HEADER firstBlock;\n    PPH_FP_SEGMENT_HEADER segmentHeader;\n    ULONG freeListIndex;\n    ULONG freeListLimit;\n    ULONG segmentIndex;\n    ULONG nextSegmentIndex;\n    ULONG newFreeListIndex;\n\n    // Calculate the number of blocks needed for the allocation.\n    numberOfBlocks = (FIELD_OFFSET(PH_FP_BLOCK_HEADER, Body) + Size + Pool->BlockSize - 1) >> Pool->BlockShift;\n\n    if (numberOfBlocks > PH_FP_BLOCK_COUNT - Pool->SegmentHeaderBlockSpan)\n    {\n        // TODO: Perform a large allocation.\n        return NULL;\n    }\n\n    // Scan each applicable free list and try to allocate from those segments.\n\n    freeListLimit = PhFppComputeFreeListIndex(Pool, numberOfBlocks);\n\n    for (freeListIndex = 0; freeListIndex <= freeListLimit; freeListIndex++)\n    {\n        segmentIndex = Pool->Header->FreeLists[freeListIndex];\n\n        while (segmentIndex != -1)\n        {\n            firstBlock = PhFppReferenceSegment(Pool, segmentIndex);\n\n            if (!firstBlock)\n                return NULL;\n\n            segmentHeader = PhFppGetHeaderSegment(Pool, firstBlock);\n            nextSegmentIndex = segmentHeader->FreeFlink;\n\n            blockHeader = PhFppAllocateBlocks(Pool, firstBlock, segmentHeader, numberOfBlocks);\n\n            if (blockHeader)\n                goto BlockAllocated;\n\n            PhFppDereferenceSegment(Pool, segmentIndex);\n            segmentIndex = nextSegmentIndex;\n        }\n    }\n\n    // No segments have the required number of contiguous free blocks. Allocate a new one.\n\n    firstBlock = PhFppAllocateSegment(Pool, &segmentIndex);\n\n    if (!firstBlock)\n        return NULL;\n\n    freeListIndex = 0;\n    segmentHeader = PhFppGetHeaderSegment(Pool, firstBlock);\n    blockHeader = PhFppAllocateBlocks(Pool, firstBlock, segmentHeader, numberOfBlocks);\n\n    if (!blockHeader)\n    {\n        PhFppDereferenceSegment(Pool, segmentIndex);\n        return NULL;\n    }\n\nBlockAllocated:\n\n    // Compute the new free list index of the segment and move it to another free list if necessary.\n\n    newFreeListIndex = PhFppComputeFreeListIndex(Pool, segmentHeader->FreeBlocks);\n\n    if (newFreeListIndex != freeListIndex)\n    {\n        PhFppRemoveFreeList(Pool, freeListIndex, segmentIndex, segmentHeader);\n        PhFppInsertFreeList(Pool, newFreeListIndex, segmentIndex, segmentHeader);\n    }\n\n    if (Rva)\n    {\n        *Rva = PhFppEncodeRva(Pool, segmentIndex, firstBlock, &blockHeader->Body);\n    }\n\n    return &blockHeader->Body;\n}\n\n/**\n * Frees a block.\n *\n * \\param Pool The file pool.\n * \\param SegmentIndex The index of the segment containing the block.\n * \\param FirstBlock The first block of the segment containing the block.\n * \\param Block A pointer to the block.\n */\nVOID PhpFreeFilePool(\n    _Inout_ PPH_FILE_POOL Pool,\n    _In_ ULONG SegmentIndex,\n    _In_ PPH_FP_BLOCK_HEADER FirstBlock,\n    _In_ PVOID Block\n    )\n{\n    PPH_FP_SEGMENT_HEADER segmentHeader;\n    ULONG oldFreeListIndex;\n    ULONG newFreeListIndex;\n\n    segmentHeader = PhFppGetHeaderSegment(Pool, FirstBlock);\n    oldFreeListIndex = PhFppComputeFreeListIndex(Pool, segmentHeader->FreeBlocks);\n    PhFppFreeBlocks(Pool, FirstBlock, segmentHeader, PhFppGetHeaderBlock(Pool, Block));\n    newFreeListIndex = PhFppComputeFreeListIndex(Pool, segmentHeader->FreeBlocks);\n\n    // Move the segment into another free list if needed.\n    if (newFreeListIndex != oldFreeListIndex)\n    {\n        PhFppRemoveFreeList(Pool, oldFreeListIndex, SegmentIndex, segmentHeader);\n        PhFppInsertFreeList(Pool, newFreeListIndex, SegmentIndex, segmentHeader);\n    }\n}\n\n/**\n * Frees a block allocated by PhAllocateFilePool().\n *\n * \\param Pool The file pool.\n * \\param Block A pointer to the block. The pointer is no longer valid after you call this function.\n * Do not use PhDereferenceFilePool() or PhDereferenceFilePoolByRva().\n */\nVOID PhFreeFilePool(\n    _Inout_ PPH_FILE_POOL Pool,\n    _In_ PVOID Block\n    )\n{\n    PPH_FILE_POOL_VIEW view;\n    PPH_FP_BLOCK_HEADER firstBlock;\n\n    view = PhFppFindViewByBase(Pool, Block);\n\n    if (!view)\n        PhRaiseStatus(STATUS_INVALID_PARAMETER_2);\n\n    firstBlock = view->Base;\n    PhpFreeFilePool(Pool, view->SegmentIndex, firstBlock, Block);\n    PhFppDereferenceView(Pool, view);\n}\n\n/**\n * Frees a block allocated by PhAllocateFilePool().\n *\n * \\param Pool The file pool.\n * \\param Rva The relative virtual address of the block.\n */\nBOOLEAN PhFreeFilePoolByRva(\n    _Inout_ PPH_FILE_POOL Pool,\n    _In_ ULONG Rva\n    )\n{\n    ULONG segmentIndex;\n    ULONG offset;\n    PPH_FP_BLOCK_HEADER firstBlock;\n\n    offset = PhFppDecodeRva(Pool, Rva, &segmentIndex);\n\n    if (offset == -1)\n        return FALSE;\n\n    firstBlock = PhFppReferenceSegment(Pool, segmentIndex);\n\n    if (!firstBlock)\n        return FALSE;\n\n    PhpFreeFilePool(Pool, segmentIndex, firstBlock, PTR_ADD_OFFSET(firstBlock, offset));\n    PhFppDereferenceSegment(Pool, segmentIndex);\n\n    return TRUE;\n}\n\n/**\n * Increments the reference count for the specified address.\n *\n * \\param Pool The file pool.\n * \\param Address An address.\n */\nVOID PhReferenceFilePool(\n    _Inout_ PPH_FILE_POOL Pool,\n    _In_ PVOID Address\n    )\n{\n    PhFppReferenceSegmentByBase(Pool, Address);\n}\n\n/**\n * Decrements the reference count for the specified address.\n *\n * \\param Pool The file pool.\n * \\param Address An address.\n */\nVOID PhDereferenceFilePool(\n    _Inout_ PPH_FILE_POOL Pool,\n    _In_ PVOID Address\n    )\n{\n    PhFppDereferenceSegmentByBase(Pool, Address);\n}\n\n/**\n * Obtains a pointer for a relative virtual address, incrementing the reference count of the\n * address.\n *\n * \\param Pool The file pool.\n * \\param Rva A relative virtual address.\n */\nPVOID PhReferenceFilePoolByRva(\n    _Inout_ PPH_FILE_POOL Pool,\n    _In_ ULONG Rva\n    )\n{\n    ULONG segmentIndex;\n    ULONG offset;\n    PPH_FP_BLOCK_HEADER firstBlock;\n\n    if (Rva == 0)\n        return NULL;\n\n    offset = PhFppDecodeRva(Pool, Rva, &segmentIndex);\n\n    if (offset == -1)\n        return NULL;\n\n    firstBlock = PhFppReferenceSegment(Pool, segmentIndex);\n\n    if (!firstBlock)\n        return NULL;\n\n    return PTR_ADD_OFFSET(firstBlock, offset);\n}\n\n/**\n * Decrements the reference count for the specified relative virtual address.\n *\n * \\param Pool The file pool.\n * \\param Rva A relative virtual address.\n */\nBOOLEAN PhDereferenceFilePoolByRva(\n    _Inout_ PPH_FILE_POOL Pool,\n    _In_ ULONG Rva\n    )\n{\n    ULONG segmentIndex;\n    ULONG offset;\n\n    offset = PhFppDecodeRva(Pool, Rva, &segmentIndex);\n\n    if (offset == -1)\n        return FALSE;\n\n    PhFppDereferenceSegment(Pool, segmentIndex);\n\n    return TRUE;\n}\n\n/**\n * Obtains a relative virtual address for a pointer.\n *\n * \\param Pool The file pool.\n * \\param Address A pointer.\n *\n * \\return The relative virtual address.\n *\n * \\remarks No reference counts are changed.\n */\nULONG PhEncodeRvaFilePool(\n    _In_ PPH_FILE_POOL Pool,\n    _In_ PVOID Address\n    )\n{\n    PPH_FILE_POOL_VIEW view;\n\n    if (!Address)\n        return 0;\n\n    view = PhFppFindViewByBase(Pool, Address);\n\n    if (!view)\n        PhRaiseStatus(STATUS_INVALID_PARAMETER_2);\n\n    return PhFppEncodeRva(Pool, view->SegmentIndex, view->Base, Address);\n}\n\n/**\n * Retrieves user data.\n *\n * \\param Pool The file pool.\n * \\param Context A variable which receives the user data.\n */\nVOID PhGetUserContextFilePool(\n    _In_ PPH_FILE_POOL Pool,\n    _Out_ PULONGLONG Context\n    )\n{\n    *Context = Pool->Header->UserContext;\n}\n\n/**\n * Stores user data.\n *\n * \\param Pool The file pool.\n * \\param Context A variable which contains the user data.\n */\nVOID PhSetUserContextFilePool(\n    _Inout_ PPH_FILE_POOL Pool,\n    _In_ PULONGLONG Context\n    )\n{\n    Pool->Header->UserContext = *Context;\n}\n\n/**\n * Extends a file pool.\n *\n * \\param Pool The file pool.\n * \\param NewSize The new size of the file, in bytes.\n */\nNTSTATUS PhFppExtendRange(\n    _Inout_ PPH_FILE_POOL Pool,\n    _In_ ULONG NewSize\n    )\n{\n    LARGE_INTEGER newSectionSize;\n\n    newSectionSize.QuadPart = NewSize;\n\n    return NtExtendSection(Pool->SectionHandle, &newSectionSize);\n}\n\n/**\n * Maps in a view of a file pool.\n *\n * \\param Pool The file pool.\n * \\param Offset The offset of the view, in bytes.\n * \\param Size The size of the view, in bytes.\n * \\param Base A variable which receives the base address of the view.\n */\nNTSTATUS PhFppMapRange(\n    _Inout_ PPH_FILE_POOL Pool,\n    _In_ ULONG Offset,\n    _In_ ULONG Size,\n    _Out_ PVOID *Base\n    )\n{\n    NTSTATUS status;\n    PVOID baseAddress;\n    LARGE_INTEGER sectionOffset;\n    SIZE_T viewSize;\n\n    baseAddress = NULL;\n    sectionOffset.QuadPart = Offset;\n    viewSize = Size;\n\n    status = NtMapViewOfSection(\n        Pool->SectionHandle,\n        NtCurrentProcess(),\n        &baseAddress,\n        0,\n        viewSize,\n        &sectionOffset,\n        &viewSize,\n        ViewShare,\n        0,\n        !Pool->ReadOnly ? PAGE_READWRITE : PAGE_READONLY\n        );\n\n    if (NT_SUCCESS(status))\n        *Base = baseAddress;\n\n    return status;\n}\n\n/**\n * Unmaps a view of a file pool.\n *\n * \\param Pool The file pool.\n * \\param Base The base address of the view.\n */\nNTSTATUS PhFppUnmapRange(\n    _Inout_ PPH_FILE_POOL Pool,\n    _In_ PVOID Base\n    )\n{\n    return NtUnmapViewOfSection(NtCurrentProcess(), Base);\n}\n\n/**\n * Initializes a segment.\n *\n * \\param Pool The file pool.\n * \\param BlockOfSegmentHeader The block header of the span containing the segment header.\n * \\param AdditionalBlocksUsed The number of blocks already allocated from the segment, excluding\n * the blocks comprising the segment header.\n */\nVOID PhFppInitializeSegment(\n    _Inout_ PPH_FILE_POOL Pool,\n    _Out_ PPH_FP_BLOCK_HEADER BlockOfSegmentHeader,\n    _In_ ULONG AdditionalBlocksUsed\n    )\n{\n    PPH_FP_SEGMENT_HEADER segmentHeader;\n    RTL_BITMAP bitmap;\n\n    BlockOfSegmentHeader->Span = Pool->SegmentHeaderBlockSpan;\n    segmentHeader = (PPH_FP_SEGMENT_HEADER)&BlockOfSegmentHeader->Body;\n\n    RtlInitializeBitMap(&bitmap, segmentHeader->Bitmap, PH_FP_BLOCK_COUNT);\n    RtlSetBits(&bitmap, 0, Pool->SegmentHeaderBlockSpan + AdditionalBlocksUsed);\n    segmentHeader->FreeBlocks = PH_FP_BLOCK_COUNT - (Pool->SegmentHeaderBlockSpan + AdditionalBlocksUsed);\n    segmentHeader->FreeFlink = -1;\n    segmentHeader->FreeBlink = -1;\n}\n\n/**\n * Allocates a segment.\n *\n * \\param Pool The file pool.\n * \\param NewSegmentIndex A variable which receives the index of the new segment.\n *\n * \\return A pointer to the first block of the segment.\n */\nPPH_FP_BLOCK_HEADER PhFppAllocateSegment(\n    _Inout_ PPH_FILE_POOL Pool,\n    _Out_ PULONG NewSegmentIndex\n    )\n{\n    ULONG newSize;\n    ULONG segmentIndex;\n    PPH_FP_BLOCK_HEADER firstBlock;\n    PPH_FP_SEGMENT_HEADER segmentHeader;\n\n    newSize = (Pool->Header->SegmentCount + 1) << Pool->SegmentShift;\n\n    if (!NT_SUCCESS(PhFppExtendRange(Pool, newSize)))\n        return NULL;\n\n    segmentIndex = Pool->Header->SegmentCount++;\n    firstBlock = PhFppReferenceSegment(Pool, segmentIndex);\n    PhFppInitializeSegment(Pool, firstBlock, 0);\n    segmentHeader = (PPH_FP_SEGMENT_HEADER)&firstBlock->Body;\n\n    PhFppInsertFreeList(Pool, 0, segmentIndex, segmentHeader);\n\n    *NewSegmentIndex = segmentIndex;\n\n    return firstBlock;\n}\n\n/**\n * Retrieves the header of a segment.\n *\n * \\param Pool The file pool.\n * \\param FirstBlock The first block of the segment.\n */\nPPH_FP_SEGMENT_HEADER PhFppGetHeaderSegment(\n    _Inout_ PPH_FILE_POOL Pool,\n    _In_ PPH_FP_BLOCK_HEADER FirstBlock\n    )\n{\n    if (FirstBlock != Pool->FirstBlockOfFirstSegment)\n    {\n        return (PPH_FP_SEGMENT_HEADER)&FirstBlock->Body;\n    }\n    else\n    {\n        // In the first segment, the segment header is after the file header.\n        return (PPH_FP_SEGMENT_HEADER)&((PPH_FP_BLOCK_HEADER)PTR_ADD_OFFSET(FirstBlock, (Pool->FileHeaderBlockSpan << Pool->BlockShift)))->Body;\n    }\n}\n\nVOID PhFppAddViewByIndex(\n    _Inout_ PPH_FILE_POOL Pool,\n    _Inout_ PPH_FILE_POOL_VIEW View\n    )\n{\n    ULONG index;\n    PLIST_ENTRY head;\n\n    index = View->SegmentIndex & (Pool->ByIndexSize - 1);\n    head = Pool->ByIndexBuckets[index];\n\n    if (head)\n    {\n        InsertHeadList(head, &View->ByIndexListEntry);\n    }\n    else\n    {\n        InitializeListHead(&View->ByIndexListEntry);\n        Pool->ByIndexBuckets[index] = &View->ByIndexListEntry;\n    }\n}\n\nVOID PhFppRemoveViewByIndex(\n    _Inout_ PPH_FILE_POOL Pool,\n    _Inout_ PPH_FILE_POOL_VIEW View\n    )\n{\n    ULONG index;\n    PLIST_ENTRY head;\n\n    index = View->SegmentIndex & (Pool->ByIndexSize - 1);\n    head = Pool->ByIndexBuckets[index];\n    assert(head);\n\n    // Unlink the entry from the chain.\n    RemoveEntryList(&View->ByIndexListEntry);\n\n    if (&View->ByIndexListEntry == head)\n    {\n        // This entry is currently the chain head.\n\n        // If this was the last entry in the chain, then indicate that the chain is empty.\n        // Otherwise, choose a new head.\n\n        if (IsListEmpty(head))\n            Pool->ByIndexBuckets[index] = NULL;\n        else\n            Pool->ByIndexBuckets[index] = head->Flink;\n    }\n}\n\n/**\n * Finds a view for the specified segment.\n *\n * \\param Pool The file pool.\n * \\param SegmentIndex The index of the segment.\n *\n * \\return The view for the segment, or NULL if no view is present for the segment.\n */\nPPH_FILE_POOL_VIEW PhFppFindViewByIndex(\n    _Inout_ PPH_FILE_POOL Pool,\n    _In_ ULONG SegmentIndex\n    )\n{\n    ULONG index;\n    PLIST_ENTRY head;\n    PLIST_ENTRY entry;\n    PPH_FILE_POOL_VIEW view;\n\n    index = SegmentIndex & (Pool->ByIndexSize - 1);\n    head = Pool->ByIndexBuckets[index];\n\n    if (!head)\n        return NULL;\n\n    entry = head;\n\n    do\n    {\n        view = CONTAINING_RECORD(entry, PH_FILE_POOL_VIEW, ByIndexListEntry);\n\n        if (view->SegmentIndex == SegmentIndex)\n            return view;\n\n        entry = entry->Flink;\n    } while (entry != head);\n\n    return NULL;\n}\n\nLONG NTAPI PhpFilePoolViewByBaseCompareFunction(\n    _In_ PPH_AVL_LINKS Links1,\n    _In_ PPH_AVL_LINKS Links2\n    )\n{\n    PPH_FILE_POOL_VIEW view1 = CONTAINING_RECORD(Links1, PH_FILE_POOL_VIEW, ByBaseLinks);\n    PPH_FILE_POOL_VIEW view2 = CONTAINING_RECORD(Links2, PH_FILE_POOL_VIEW, ByBaseLinks);\n\n    return uintptrcmp((ULONG_PTR)view1->Base, (ULONG_PTR)view2->Base);\n}\n\nVOID PhFppAddViewByBase(\n    _Inout_ PPH_FILE_POOL Pool,\n    _Inout_ PPH_FILE_POOL_VIEW View\n    )\n{\n    PhAddElementAvlTree(&Pool->ByBaseSet, &View->ByBaseLinks);\n}\n\nVOID PhFppRemoveViewByBase(\n    _Inout_ PPH_FILE_POOL Pool,\n    _Inout_ PPH_FILE_POOL_VIEW View\n    )\n{\n    PhRemoveElementAvlTree(&Pool->ByBaseSet, &View->ByBaseLinks);\n}\n\n/**\n * Finds a view containing the specified address.\n *\n * \\param Pool The file pool.\n * \\param Base The address.\n *\n * \\return The view containing the address, or NULL if no view is present for the address.\n */\nPPH_FILE_POOL_VIEW PhFppFindViewByBase(\n    _Inout_ PPH_FILE_POOL Pool,\n    _In_ PVOID Base\n    )\n{\n    PPH_FILE_POOL_VIEW view;\n    PPH_AVL_LINKS links;\n    PH_FILE_POOL_VIEW lookupView;\n\n    // This is an approximate search to find the target view in which the specified address lies.\n\n    lookupView.Base = Base;\n    links = PhUpperDualBoundElementAvlTree(&Pool->ByBaseSet, &lookupView.ByBaseLinks);\n\n    if (!links)\n        return NULL;\n\n    view = CONTAINING_RECORD(links, PH_FILE_POOL_VIEW, ByBaseLinks);\n\n    if ((ULONG_PTR)Base < (ULONG_PTR)view->Base + Pool->SegmentSize)\n        return view;\n\n    return NULL;\n}\n\nPPH_FILE_POOL_VIEW PhFppCreateView(\n    _Inout_ PPH_FILE_POOL Pool,\n    _In_ ULONG SegmentIndex\n    )\n{\n    PPH_FILE_POOL_VIEW view;\n    PVOID base;\n\n    // Map in the segment.\n    if (!NT_SUCCESS(PhFppMapRange(Pool, SegmentIndex << Pool->SegmentShift, Pool->SegmentSize, &base)))\n        return NULL;\n\n    // Create and add the view entry.\n\n    view = PhAllocateFromFreeList(&Pool->ViewFreeList);\n    memset(view, 0, sizeof(PH_FILE_POOL_VIEW));\n\n    view->RefCount = 1;\n    view->SegmentIndex = SegmentIndex;\n    view->Base = base;\n\n    PhFppAddViewByIndex(Pool, view);\n    PhFppAddViewByBase(Pool, view);\n\n    return view;\n}\n\nVOID PhFppDestroyView(\n    _Inout_ PPH_FILE_POOL Pool,\n    _Inout_ PPH_FILE_POOL_VIEW View\n    )\n{\n    PhFppUnmapRange(Pool, View->Base);\n    PhFppRemoveViewByIndex(Pool, View);\n    PhFppRemoveViewByBase(Pool, View);\n\n    PhFreeToFreeList(&Pool->ViewFreeList, View);\n}\n\nVOID PhFppActivateView(\n    _Inout_ PPH_FILE_POOL Pool,\n    _Inout_ PPH_FILE_POOL_VIEW View\n    )\n{\n    RemoveEntryList(&View->InactiveViewsListEntry);\n    Pool->NumberOfInactiveViews--;\n}\n\nVOID PhFppDeactivateView(\n    _Inout_ PPH_FILE_POOL Pool,\n    _Inout_ PPH_FILE_POOL_VIEW View\n    )\n{\n    InsertHeadList(&Pool->InactiveViewsListHead, &View->InactiveViewsListEntry);\n    Pool->NumberOfInactiveViews++;\n\n    // If we have too many inactive views, destroy the least recent ones.\n    while (Pool->NumberOfInactiveViews > Pool->MaximumInactiveViews)\n    {\n        PLIST_ENTRY lruEntry;\n        PPH_FILE_POOL_VIEW lruView;\n\n        lruEntry = RemoveTailList(&Pool->InactiveViewsListHead);\n        Pool->NumberOfInactiveViews--;\n\n        assert(lruEntry != &Pool->InactiveViewsListHead);\n        lruView = CONTAINING_RECORD(lruEntry, PH_FILE_POOL_VIEW, InactiveViewsListEntry);\n        PhFppDestroyView(Pool, lruView);\n    }\n}\n\nVOID PhFppReferenceView(\n    _Inout_ PPH_FILE_POOL Pool,\n    _Inout_ PPH_FILE_POOL_VIEW View\n    )\n{\n    if (View->RefCount == 0)\n    {\n        // The view is inactive, so make it active.\n        PhFppActivateView(Pool, View);\n    }\n\n    View->RefCount++;\n}\n\nVOID PhFppDereferenceView(\n    _Inout_ PPH_FILE_POOL Pool,\n    _Inout_ PPH_FILE_POOL_VIEW View\n    )\n{\n    if (--View->RefCount == 0)\n    {\n        if (View->SegmentIndex == 0)\n            PhRaiseStatus(STATUS_INTERNAL_ERROR);\n\n        PhFppDeactivateView(Pool, View);\n    }\n}\n\nPPH_FP_BLOCK_HEADER PhFppReferenceSegment(\n    _Inout_ PPH_FILE_POOL Pool,\n    _In_ ULONG SegmentIndex\n    )\n{\n    PPH_FILE_POOL_VIEW view;\n\n    // Validate parameters.\n    if (SegmentIndex != 0 && SegmentIndex >= Pool->Header->SegmentCount)\n        return NULL;\n\n    // Try to get a cached view.\n\n    view = PhFppFindViewByIndex(Pool, SegmentIndex);\n\n    if (view)\n    {\n        PhFppReferenceView(Pool, view);\n\n        return (PPH_FP_BLOCK_HEADER)view->Base;\n    }\n\n    // No cached view, so create one.\n\n    view = PhFppCreateView(Pool, SegmentIndex);\n\n    if (!view)\n        return NULL;\n\n    return (PPH_FP_BLOCK_HEADER)view->Base;\n}\n\nVOID PhFppDereferenceSegment(\n    _Inout_ PPH_FILE_POOL Pool,\n    _In_ ULONG SegmentIndex\n    )\n{\n    PPH_FILE_POOL_VIEW view;\n\n    view = PhFppFindViewByIndex(Pool, SegmentIndex);\n\n    if (!view)\n        PhRaiseStatus(STATUS_INTERNAL_ERROR);\n\n    PhFppDereferenceView(Pool, view);\n}\n\nVOID PhFppReferenceSegmentByBase(\n    _Inout_ PPH_FILE_POOL Pool,\n    _In_ PVOID Base\n    )\n{\n    PPH_FILE_POOL_VIEW view;\n\n    view = PhFppFindViewByBase(Pool, Base);\n\n    if (!view)\n        PhRaiseStatus(STATUS_INTERNAL_ERROR);\n\n    PhFppReferenceView(Pool, view);\n}\n\nVOID PhFppDereferenceSegmentByBase(\n    _Inout_ PPH_FILE_POOL Pool,\n    _In_ PVOID Base\n    )\n{\n    PPH_FILE_POOL_VIEW view;\n\n    view = PhFppFindViewByBase(Pool, Base);\n\n    if (!view)\n        PhRaiseStatus(STATUS_INTERNAL_ERROR);\n\n    PhFppDereferenceView(Pool, view);\n}\n\n/**\n * Allocates blocks from a segment.\n *\n * \\param Pool The file pool.\n * \\param FirstBlock The first block of the segment.\n * \\param SegmentHeader The header of the segment.\n * \\param NumberOfBlocks The number of blocks to allocate.\n *\n * \\return The header of the allocated span, or NULL if there is an insufficient number of\n * contiguous free blocks for the allocation.\n */\nPPH_FP_BLOCK_HEADER PhFppAllocateBlocks(\n    _Inout_ PPH_FILE_POOL Pool,\n    _In_ PPH_FP_BLOCK_HEADER FirstBlock,\n    _Inout_ PPH_FP_SEGMENT_HEADER SegmentHeader,\n    _In_ ULONG NumberOfBlocks\n    )\n{\n    RTL_BITMAP bitmap;\n    ULONG hintIndex;\n    ULONG foundIndex;\n    PPH_FP_BLOCK_HEADER blockHeader;\n\n    if (FirstBlock != Pool->FirstBlockOfFirstSegment)\n        hintIndex = Pool->SegmentHeaderBlockSpan;\n    else\n        hintIndex = Pool->SegmentHeaderBlockSpan + Pool->FileHeaderBlockSpan;\n\n    RtlInitializeBitMap(&bitmap, SegmentHeader->Bitmap, PH_FP_BLOCK_COUNT);\n\n    // Find a range of free blocks and mark them as in-use.\n    foundIndex = RtlFindClearBitsAndSet(&bitmap, NumberOfBlocks, hintIndex);\n\n    if (foundIndex == -1)\n    {\n        // No more space.\n        return NULL;\n    }\n\n    SegmentHeader->FreeBlocks -= NumberOfBlocks;\n\n    blockHeader = (PPH_FP_BLOCK_HEADER)PTR_ADD_OFFSET(FirstBlock, (foundIndex << Pool->BlockShift));\n    blockHeader->Flags = 0;\n    blockHeader->Span = NumberOfBlocks;\n\n    return blockHeader;\n}\n\n/**\n * Frees blocks in a segment.\n *\n * \\param Pool The file pool.\n * \\param FirstBlock The first block of the segment.\n * \\param SegmentHeader The header of the segment.\n * \\param BlockHeader The header of the allocated span.\n */\nVOID PhFppFreeBlocks(\n    _Inout_ PPH_FILE_POOL Pool,\n    _In_ PPH_FP_BLOCK_HEADER FirstBlock,\n    _Inout_ PPH_FP_SEGMENT_HEADER SegmentHeader,\n    _In_ PPH_FP_BLOCK_HEADER BlockHeader\n    )\n{\n    RTL_BITMAP bitmap;\n    ULONG startIndex;\n    ULONG blockSpan;\n\n    RtlInitializeBitMap(&bitmap, SegmentHeader->Bitmap, PH_FP_BLOCK_COUNT);\n\n    // Mark the blocks as free.\n    startIndex = (ULONG)((PCHAR)BlockHeader - (PCHAR)FirstBlock) >> Pool->BlockShift;\n    blockSpan = BlockHeader->Span;\n    RtlClearBits(&bitmap, startIndex, blockSpan);\n    SegmentHeader->FreeBlocks += blockSpan;\n}\n\n/**\n * Computes the free list index (category) for a specified number of blocks.\n *\n * \\param Pool The file pool.\n * \\param NumberOfBlocks The number of free or required blocks.\n */\nULONG PhFppComputeFreeListIndex(\n    _In_ PPH_FILE_POOL Pool,\n    _In_ ULONG NumberOfBlocks\n    )\n{\n    // Use a binary tree to speed up comparison.\n\n    if (NumberOfBlocks >= PH_FP_BLOCK_COUNT / 64)\n    {\n        if (NumberOfBlocks >= PH_FP_BLOCK_COUNT / 2)\n        {\n            if (NumberOfBlocks >= PH_FP_BLOCK_COUNT - Pool->SegmentHeaderBlockSpan)\n                return 0;\n            else\n                return 1;\n        }\n        else\n        {\n            if (NumberOfBlocks >= PH_FP_BLOCK_COUNT / 16)\n                return 2;\n            else\n                return 3;\n        }\n    }\n    else\n    {\n        if (NumberOfBlocks >= 4)\n        {\n            if (NumberOfBlocks >= PH_FP_BLOCK_COUNT / 256)\n                return 4;\n            else\n                return 5;\n        }\n        else\n        {\n            if (NumberOfBlocks >= 1)\n                return 6;\n            else\n                return 7;\n        }\n    }\n}\n\n/**\n * Inserts a segment into a free list.\n *\n * \\param Pool The file pool.\n * \\param FreeListIndex The index of a free list.\n * \\param SegmentIndex The index of the segment.\n * \\param SegmentHeader The header of the segment.\n */\nBOOLEAN PhFppInsertFreeList(\n    _Inout_ PPH_FILE_POOL Pool,\n    _In_ ULONG FreeListIndex,\n    _In_ ULONG SegmentIndex,\n    _In_ PPH_FP_SEGMENT_HEADER SegmentHeader\n    )\n{\n    ULONG oldSegmentIndex;\n    PPH_FP_BLOCK_HEADER oldSegmentFirstBlock;\n    PPH_FP_SEGMENT_HEADER oldSegmentHeader;\n\n    oldSegmentIndex = Pool->Header->FreeLists[FreeListIndex];\n\n    // Try to reference the segment before we commit any changes.\n\n    if (oldSegmentIndex != -1)\n    {\n        oldSegmentFirstBlock = PhFppReferenceSegment(Pool, oldSegmentIndex);\n\n        if (!oldSegmentFirstBlock)\n            return FALSE;\n    }\n\n    // Insert the segment into the list.\n\n    SegmentHeader->FreeBlink = -1;\n    SegmentHeader->FreeFlink = oldSegmentIndex;\n    Pool->Header->FreeLists[FreeListIndex] = SegmentIndex;\n\n    if (oldSegmentIndex != -1)\n    {\n        oldSegmentHeader = PhFppGetHeaderSegment(Pool, oldSegmentFirstBlock);\n        oldSegmentHeader->FreeBlink = SegmentIndex;\n        PhFppDereferenceSegment(Pool, oldSegmentIndex);\n    }\n\n    return TRUE;\n}\n\n/**\n * Removes a segment from a free list.\n *\n * \\param Pool The file pool.\n * \\param FreeListIndex The index of a free list.\n * \\param SegmentIndex The index of the segment.\n * \\param SegmentHeader The header of the segment.\n */\nBOOLEAN PhFppRemoveFreeList(\n    _Inout_ PPH_FILE_POOL Pool,\n    _In_ ULONG FreeListIndex,\n    _In_ ULONG SegmentIndex,\n    _In_ PPH_FP_SEGMENT_HEADER SegmentHeader\n    )\n{\n    ULONG flinkSegmentIndex;\n    PPH_FP_BLOCK_HEADER flinkSegmentFirstBlock;\n    PPH_FP_SEGMENT_HEADER flinkSegmentHeader;\n    ULONG blinkSegmentIndex;\n    PPH_FP_BLOCK_HEADER blinkSegmentFirstBlock;\n    PPH_FP_SEGMENT_HEADER blinkSegmentHeader;\n\n    flinkSegmentIndex = SegmentHeader->FreeFlink;\n    blinkSegmentIndex = SegmentHeader->FreeBlink;\n\n    // Try to reference the segments before we commit any changes.\n\n    if (flinkSegmentIndex != -1)\n    {\n        flinkSegmentFirstBlock = PhFppReferenceSegment(Pool, flinkSegmentIndex);\n\n        if (!flinkSegmentFirstBlock)\n            return FALSE;\n    }\n\n    if (blinkSegmentIndex != -1)\n    {\n        blinkSegmentFirstBlock = PhFppReferenceSegment(Pool, blinkSegmentIndex);\n\n        if (!blinkSegmentFirstBlock)\n        {\n            if (flinkSegmentIndex != -1)\n                PhFppDereferenceSegment(Pool, flinkSegmentIndex);\n\n            return FALSE;\n        }\n    }\n\n    // Unlink the segment from the list.\n\n    if (flinkSegmentIndex != -1)\n    {\n        flinkSegmentHeader = PhFppGetHeaderSegment(Pool, flinkSegmentFirstBlock);\n        flinkSegmentHeader->FreeBlink = blinkSegmentIndex;\n        PhFppDereferenceSegment(Pool, flinkSegmentIndex);\n    }\n\n    if (blinkSegmentIndex != -1)\n    {\n        blinkSegmentHeader = PhFppGetHeaderSegment(Pool, blinkSegmentFirstBlock);\n        blinkSegmentHeader->FreeFlink = flinkSegmentIndex;\n        PhFppDereferenceSegment(Pool, blinkSegmentIndex);\n    }\n    else\n    {\n        // The segment was the list head; select a new one.\n        Pool->Header->FreeLists[FreeListIndex] = flinkSegmentIndex;\n    }\n\n    return TRUE;\n}\n\n/**\n * Retrieves the header of a block.\n *\n * \\param Pool The file pool.\n * \\param Block A pointer to the body of the block.\n */\nPPH_FP_BLOCK_HEADER PhFppGetHeaderBlock(\n    _In_ PPH_FILE_POOL Pool,\n    _In_ PVOID Block\n    )\n{\n    return CONTAINING_RECORD(Block, PH_FP_BLOCK_HEADER, Body);\n}\n\n/**\n * Creates a relative virtual address.\n *\n * \\param Pool The file pool.\n * \\param SegmentIndex The index of the segment containing \\a Address.\n * \\param FirstBlock The first block of the segment containing \\a Address.\n * \\param Address An address.\n */\nULONG PhFppEncodeRva(\n    _In_ PPH_FILE_POOL Pool,\n    _In_ ULONG SegmentIndex,\n    _In_ PPH_FP_BLOCK_HEADER FirstBlock,\n    _In_ PVOID Address\n    )\n{\n    return (SegmentIndex << Pool->SegmentShift) + (ULONG)((PCHAR)Address - (PCHAR)FirstBlock);\n}\n\n/**\n * Decodes a relative virtual address.\n *\n * \\param Pool The file pool.\n * \\param Rva The relative virtual address.\n * \\param SegmentIndex A variable which receives the segment index.\n *\n * \\return An offset into the segment specified by \\a SegmentIndex, or -1 if \\a Rva is invalid.\n */\nULONG PhFppDecodeRva(\n    _In_ PPH_FILE_POOL Pool,\n    _In_ ULONG Rva,\n    _Out_ PULONG SegmentIndex\n    )\n{\n    ULONG segmentIndex;\n\n    segmentIndex = Rva >> Pool->SegmentShift;\n\n    if (segmentIndex >= Pool->Header->SegmentCount)\n        return -1;\n\n    *SegmentIndex = segmentIndex;\n\n    return Rva & (Pool->SegmentSize - 1);\n}\n"
  },
  {
    "path": "third_party/phlib/filestream.c",
    "content": "/*\n * Process Hacker -\n *   file stream object\n *\n * Copyright (C) 2010-2011 wj32\n *\n * This file is part of Process Hacker.\n *\n * Process Hacker is free software; you can redistribute it and/or modify\n * it under the terms of the GNU General Public License as published by\n * the Free Software Foundation, either version 3 of the License, or\n * (at your option) any later version.\n *\n * Process Hacker is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n * GNU General Public License for more details.\n *\n * You should have received a copy of the GNU General Public License\n * along with Process Hacker.  If not, see <http://www.gnu.org/licenses/>.\n */\n\n#include <ph.h>\n#include <filestream.h>\n#include <filestreamp.h>\n\nPPH_OBJECT_TYPE PhFileStreamType;\n\nBOOLEAN PhFileStreamInitialization(\n    VOID\n    )\n{\n    PH_OBJECT_TYPE_PARAMETERS parameters;\n\n    parameters.FreeListSize = sizeof(PH_FILE_STREAM);\n    parameters.FreeListCount = 16;\n\n    PhFileStreamType = PhCreateObjectTypeEx(L\"FileStream\", PH_OBJECT_TYPE_USE_FREE_LIST, PhpFileStreamDeleteProcedure, &parameters);\n\n    return TRUE;\n}\n\nNTSTATUS PhCreateFileStream(\n    _Out_ PPH_FILE_STREAM *FileStream,\n    _In_ PWSTR FileName,\n    _In_ ACCESS_MASK DesiredAccess,\n    _In_ ULONG ShareAccess,\n    _In_ ULONG CreateDisposition,\n    _In_ ULONG Flags\n    )\n{\n    NTSTATUS status;\n    PPH_FILE_STREAM fileStream;\n    HANDLE fileHandle;\n    ULONG createOptions;\n\n    if (Flags & PH_FILE_STREAM_ASYNCHRONOUS)\n        createOptions = FILE_NON_DIRECTORY_FILE;\n    else\n        createOptions = FILE_NON_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT;\n\n    if (!NT_SUCCESS(status = PhCreateFileWin32(\n        &fileHandle,\n        FileName,\n        DesiredAccess,\n        0,\n        ShareAccess,\n        CreateDisposition,\n        createOptions\n        )))\n        return status;\n\n    if (!NT_SUCCESS(status = PhCreateFileStream2(\n        &fileStream,\n        fileHandle,\n        Flags,\n        PAGE_SIZE\n        )))\n    {\n        NtClose(fileHandle);\n        return status;\n    }\n\n    if (Flags & PH_FILE_STREAM_APPEND)\n    {\n        LARGE_INTEGER zero;\n\n        zero.QuadPart = 0;\n\n        if (!NT_SUCCESS(PhSeekFileStream(\n            fileStream,\n            &zero,\n            SeekEnd\n            )))\n        {\n            PhDereferenceObject(fileStream);\n            return status;\n        }\n    }\n\n    *FileStream = fileStream;\n\n    return status;\n}\n\nNTSTATUS PhCreateFileStream2(\n    _Out_ PPH_FILE_STREAM *FileStream,\n    _In_ HANDLE FileHandle,\n    _In_ ULONG Flags,\n    _In_ ULONG BufferLength\n    )\n{\n    PPH_FILE_STREAM fileStream;\n\n    fileStream = PhCreateObject(sizeof(PH_FILE_STREAM), PhFileStreamType);\n    fileStream->FileHandle = FileHandle;\n    fileStream->Flags = Flags;\n    fileStream->Position.QuadPart = 0;\n\n    if (!(Flags & PH_FILE_STREAM_UNBUFFERED))\n    {\n        fileStream->Buffer = NULL;\n        fileStream->BufferLength = BufferLength;\n    }\n    else\n    {\n        fileStream->Buffer = NULL;\n        fileStream->BufferLength = 0;\n    }\n\n    fileStream->ReadPosition = 0;\n    fileStream->ReadLength = 0;\n    fileStream->WritePosition = 0;\n\n    *FileStream = fileStream;\n\n    return STATUS_SUCCESS;\n}\n\nVOID NTAPI PhpFileStreamDeleteProcedure(\n    _In_ PVOID Object,\n    _In_ ULONG Flags\n    )\n{\n    PPH_FILE_STREAM fileStream = (PPH_FILE_STREAM)Object;\n\n    PhFlushFileStream(fileStream, FALSE);\n\n    if (!(fileStream->Flags & PH_FILE_STREAM_HANDLE_UNOWNED))\n        NtClose(fileStream->FileHandle);\n\n    if (fileStream->Buffer)\n        PhFreePage(fileStream->Buffer);\n}\n\n/**\n * Verifies that a file stream's position matches the position held by the file object.\n */\nVOID PhVerifyFileStream(\n    _In_ PPH_FILE_STREAM FileStream\n    )\n{\n    NTSTATUS status;\n\n    // If the file object is asynchronous, the file object doesn't maintain its position.\n    if (!(FileStream->Flags & (\n        PH_FILE_STREAM_OWN_POSITION |\n        PH_FILE_STREAM_ASYNCHRONOUS\n        )))\n    {\n        FILE_POSITION_INFORMATION positionInfo;\n        IO_STATUS_BLOCK isb;\n\n        if (!NT_SUCCESS(status = NtQueryInformationFile(\n            FileStream->FileHandle,\n            &isb,\n            &positionInfo,\n            sizeof(FILE_POSITION_INFORMATION),\n            FilePositionInformation\n            )))\n            PhRaiseStatus(status);\n\n        if (FileStream->Position.QuadPart != positionInfo.CurrentByteOffset.QuadPart)\n            PhRaiseStatus(STATUS_INTERNAL_ERROR);\n    }\n}\n\nNTSTATUS PhpAllocateBufferFileStream(\n    _Inout_ PPH_FILE_STREAM FileStream\n    )\n{\n    FileStream->Buffer = PhAllocatePage(FileStream->BufferLength, NULL);\n\n    if (FileStream->Buffer)\n        return STATUS_SUCCESS;\n    else\n        return STATUS_NO_MEMORY;\n}\n\nNTSTATUS PhpReadFileStream(\n    _Inout_ PPH_FILE_STREAM FileStream,\n    _Out_writes_bytes_(Length) PVOID Buffer,\n    _In_ ULONG Length,\n    _Out_opt_ PULONG ReadLength\n    )\n{\n    NTSTATUS status;\n    IO_STATUS_BLOCK isb;\n    PLARGE_INTEGER position;\n\n    position = NULL;\n\n    if (FileStream->Flags & PH_FILE_STREAM_OWN_POSITION)\n        position = &FileStream->Position;\n\n    status = NtReadFile(\n        FileStream->FileHandle,\n        NULL,\n        NULL,\n        NULL,\n        &isb,\n        Buffer,\n        Length,\n        position,\n        NULL\n        );\n\n    if (status == STATUS_PENDING)\n    {\n        // Wait for the operation to finish. This probably means we got called on an asynchronous\n        // file object.\n        status = NtWaitForSingleObject(FileStream->FileHandle, FALSE, NULL);\n\n        if (NT_SUCCESS(status))\n            status = isb.Status;\n    }\n\n    if (NT_SUCCESS(status))\n    {\n        FileStream->Position.QuadPart += isb.Information;\n\n        if (ReadLength)\n            *ReadLength = (ULONG)isb.Information;\n    }\n\n    return status;\n}\n\nNTSTATUS PhReadFileStream(\n    _Inout_ PPH_FILE_STREAM FileStream,\n    _Out_writes_bytes_(Length) PVOID Buffer,\n    _In_ ULONG Length,\n    _Out_opt_ PULONG ReadLength\n    )\n{\n    NTSTATUS status = STATUS_SUCCESS;\n    ULONG availableLength;\n    ULONG readLength;\n\n    if (FileStream->Flags & PH_FILE_STREAM_UNBUFFERED)\n    {\n        return PhpReadFileStream(\n            FileStream,\n            Buffer,\n            Length,\n            ReadLength\n            );\n    }\n\n    // How much do we have available to copy out of the buffer?\n    availableLength = FileStream->ReadLength - FileStream->ReadPosition;\n\n    if (availableLength == 0)\n    {\n        // Make sure buffered writes are flushed.\n        if (FileStream->WritePosition != 0)\n        {\n            if (!NT_SUCCESS(status = PhpFlushWriteFileStream(FileStream)))\n                return status;\n        }\n\n        // If this read is too big, pass it through.\n        if (Length >= FileStream->BufferLength)\n        {\n            // These are now invalid.\n            FileStream->ReadPosition = 0;\n            FileStream->ReadLength = 0;\n\n            return PhpReadFileStream(\n                FileStream,\n                Buffer,\n                Length,\n                ReadLength\n                );\n        }\n\n        if (!FileStream->Buffer)\n        {\n            if (!NT_SUCCESS(status = PhpAllocateBufferFileStream(FileStream)))\n                return status;\n        }\n\n        // Read as much as we can into our buffer.\n        if (!NT_SUCCESS(status = PhpReadFileStream(\n            FileStream,\n            FileStream->Buffer,\n            FileStream->BufferLength,\n            &readLength\n            )))\n            return status;\n\n        if (readLength == 0)\n        {\n            // No data read.\n            if (ReadLength)\n                *ReadLength = readLength;\n\n            return status;\n        }\n\n        FileStream->ReadPosition = 0;\n        FileStream->ReadLength = readLength;\n    }\n    else\n    {\n        readLength = availableLength;\n    }\n\n    if (readLength > Length)\n        readLength = Length;\n\n    // Try to satisfy the request from the buffer.\n    memcpy(\n        Buffer,\n        PTR_ADD_OFFSET(FileStream->Buffer, FileStream->ReadPosition),\n        readLength\n        );\n    FileStream->ReadPosition += readLength;\n\n    // If we didn't completely satisfy the request, read some more.\n    if (\n        readLength < Length &&\n        // Don't try to read more if the buffer wasn't even filled up last time. (No more to read.)\n        FileStream->ReadLength == FileStream->BufferLength\n        )\n    {\n        ULONG readLength2;\n\n        if (NT_SUCCESS(status = PhpReadFileStream(\n            FileStream,\n            PTR_ADD_OFFSET(Buffer, readLength),\n            Length - readLength,\n            &readLength2\n            )))\n        {\n            readLength += readLength2;\n            // These are now invalid.\n            FileStream->ReadPosition = 0;\n            FileStream->ReadLength = 0;\n        }\n    }\n\n    if (NT_SUCCESS(status))\n    {\n        if (ReadLength)\n            *ReadLength = readLength;\n    }\n\n    return status;\n}\n\nNTSTATUS PhpWriteFileStream(\n    _Inout_ PPH_FILE_STREAM FileStream,\n    _In_reads_bytes_(Length) PVOID Buffer,\n    _In_ ULONG Length\n    )\n{\n    NTSTATUS status;\n    IO_STATUS_BLOCK isb;\n    PLARGE_INTEGER position;\n\n    position = NULL;\n\n    if (FileStream->Flags & PH_FILE_STREAM_OWN_POSITION)\n        position = &FileStream->Position;\n\n    status = NtWriteFile(\n        FileStream->FileHandle,\n        NULL,\n        NULL,\n        NULL,\n        &isb,\n        Buffer,\n        Length,\n        position,\n        NULL\n        );\n\n    if (status == STATUS_PENDING)\n    {\n        // Wait for the operation to finish. This probably means we got called on an asynchronous\n        // file object.\n        status = NtWaitForSingleObject(FileStream->FileHandle, FALSE, NULL);\n\n        if (NT_SUCCESS(status))\n            status = isb.Status;\n    }\n\n    if (NT_SUCCESS(status))\n    {\n        FileStream->Position.QuadPart += isb.Information;\n        FileStream->Flags |= PH_FILE_STREAM_WRITTEN;\n    }\n\n    return status;\n}\n\nNTSTATUS PhWriteFileStream(\n    _Inout_ PPH_FILE_STREAM FileStream,\n    _In_reads_bytes_(Length) PVOID Buffer,\n    _In_ ULONG Length\n    )\n{\n    NTSTATUS status = STATUS_SUCCESS;\n    ULONG availableLength;\n    ULONG writtenLength;\n\n    if (FileStream->Flags & PH_FILE_STREAM_UNBUFFERED)\n    {\n        return PhpWriteFileStream(\n            FileStream,\n            Buffer,\n            Length\n            );\n    }\n\n    if (FileStream->WritePosition == 0)\n    {\n        // Make sure buffered reads are flushed.\n        if (!NT_SUCCESS(status = PhpFlushReadFileStream(FileStream)))\n            return status;\n    }\n\n    if (FileStream->WritePosition != 0)\n    {\n        availableLength = FileStream->BufferLength - FileStream->WritePosition;\n\n        // Try to satisfy the request by copying the data to the buffer.\n        if (availableLength != 0)\n        {\n            writtenLength = availableLength;\n\n            if (writtenLength > Length)\n                writtenLength = Length;\n\n            memcpy(\n                PTR_ADD_OFFSET(FileStream->Buffer, FileStream->WritePosition),\n                Buffer,\n                writtenLength\n                );\n            FileStream->WritePosition += writtenLength;\n\n            if (writtenLength == Length)\n            {\n                // The request has been completely satisfied.\n                return status;\n            }\n\n            Buffer = PTR_ADD_OFFSET(Buffer, writtenLength);\n            Length -= writtenLength;\n        }\n\n        // If we didn't completely satisfy the request, it's because the buffer is full. Flush it.\n        if (!NT_SUCCESS(status = PhpWriteFileStream(\n            FileStream,\n            FileStream->Buffer,\n            FileStream->WritePosition\n            )))\n            return status;\n\n        FileStream->WritePosition = 0;\n    }\n\n    // If the write is too big, pass it through.\n    if (Length >= FileStream->BufferLength)\n    {\n        if (!NT_SUCCESS(status = PhpWriteFileStream(\n            FileStream,\n            Buffer,\n            Length\n            )))\n            return status;\n    }\n    else if (Length != 0)\n    {\n        if (!FileStream->Buffer)\n        {\n            if (!NT_SUCCESS(status = PhpAllocateBufferFileStream(FileStream)))\n                return status;\n        }\n\n        // Completely satisfy the request by copying the data to the buffer.\n        memcpy(\n            FileStream->Buffer,\n            Buffer,\n            Length\n            );\n        FileStream->WritePosition = Length;\n    }\n\n    return status;\n}\n\nNTSTATUS PhpFlushReadFileStream(\n    _Inout_ PPH_FILE_STREAM FileStream\n    )\n{\n    NTSTATUS status = STATUS_SUCCESS;\n\n    if (FileStream->ReadLength - FileStream->ReadPosition != 0)\n    {\n        LARGE_INTEGER offset;\n\n        // We have some buffered read data, so our position is too far ahead. We need to move it\n        // back to the first unused byte.\n        offset.QuadPart = -(LONG)(FileStream->ReadLength - FileStream->ReadPosition);\n\n        if (!NT_SUCCESS(status = PhpSeekFileStream(\n            FileStream,\n            &offset,\n            SeekCurrent\n            )))\n            return status;\n    }\n\n    FileStream->ReadPosition = 0;\n    FileStream->ReadLength = 0;\n\n    return status;\n}\n\nNTSTATUS PhpFlushWriteFileStream(\n    _Inout_ PPH_FILE_STREAM FileStream\n    )\n{\n    NTSTATUS status = STATUS_SUCCESS;\n\n    if (!NT_SUCCESS(status = PhpWriteFileStream(\n        FileStream,\n        FileStream->Buffer,\n        FileStream->WritePosition\n        )))\n        return status;\n\n    FileStream->WritePosition = 0;\n\n    return status;\n}\n\n/**\n * Flushes the file stream.\n *\n * \\param FileStream A file stream object.\n * \\param Full TRUE to flush the file object through the operating system, otherwise FALSE to only\n * ensure the buffer is flushed to the operating system.\n */\nNTSTATUS PhFlushFileStream(\n    _Inout_ PPH_FILE_STREAM FileStream,\n    _In_ BOOLEAN Full\n    )\n{\n    NTSTATUS status = STATUS_SUCCESS;\n\n    if (FileStream->WritePosition != 0)\n    {\n        if (!NT_SUCCESS(status = PhpFlushWriteFileStream(FileStream)))\n            return status;\n    }\n\n    if (FileStream->ReadPosition != 0)\n    {\n        if (!NT_SUCCESS(status = PhpFlushReadFileStream(FileStream)))\n            return status;\n    }\n\n    if (Full && (FileStream->Flags & PH_FILE_STREAM_WRITTEN))\n    {\n        IO_STATUS_BLOCK isb;\n\n        if (!NT_SUCCESS(status = NtFlushBuffersFile(\n            FileStream->FileHandle,\n            &isb\n            )))\n            return status;\n    }\n\n    return status;\n}\n\nVOID PhGetPositionFileStream(\n    _In_ PPH_FILE_STREAM FileStream,\n    _Out_ PLARGE_INTEGER Position\n    )\n{\n    Position->QuadPart =\n        FileStream->Position.QuadPart +\n        (FileStream->ReadPosition - FileStream->ReadLength) +\n        FileStream->WritePosition;\n}\n\nNTSTATUS PhpSeekFileStream(\n    _Inout_ PPH_FILE_STREAM FileStream,\n    _In_ PLARGE_INTEGER Offset,\n    _In_ PH_SEEK_ORIGIN Origin\n    )\n{\n    NTSTATUS status = STATUS_SUCCESS;\n\n    switch (Origin)\n    {\n    case SeekStart:\n        {\n            FileStream->Position = *Offset;\n        }\n        break;\n    case SeekCurrent:\n        {\n            FileStream->Position.QuadPart += Offset->QuadPart;\n        }\n        break;\n    case SeekEnd:\n        {\n            if (!NT_SUCCESS(status = PhGetFileSize(\n                FileStream->FileHandle,\n                &FileStream->Position\n                )))\n                return status;\n\n            FileStream->Position.QuadPart += Offset->QuadPart;\n        }\n        break;\n    }\n\n    if (!(FileStream->Flags & PH_FILE_STREAM_OWN_POSITION))\n    {\n        FILE_POSITION_INFORMATION positionInfo;\n        IO_STATUS_BLOCK isb;\n\n        positionInfo.CurrentByteOffset = FileStream->Position;\n\n        if (!NT_SUCCESS(status = NtSetInformationFile(\n            FileStream->FileHandle,\n            &isb,\n            &positionInfo,\n            sizeof(FILE_POSITION_INFORMATION),\n            FilePositionInformation\n            )))\n            return status;\n    }\n\n    return status;\n}\n\nNTSTATUS PhSeekFileStream(\n    _Inout_ PPH_FILE_STREAM FileStream,\n    _In_ PLARGE_INTEGER Offset,\n    _In_ PH_SEEK_ORIGIN Origin\n    )\n{\n    NTSTATUS status = STATUS_SUCCESS;\n    LARGE_INTEGER offset;\n\n    offset = *Offset;\n\n    if (FileStream->WritePosition != 0)\n    {\n        if (!NT_SUCCESS(status = PhpFlushWriteFileStream(FileStream)))\n            return status;\n    }\n    else if (FileStream->ReadPosition != 0)\n    {\n        if (Origin == SeekCurrent)\n        {\n            // We have buffered read data, which means our position is too far ahead. Subtract this\n            // difference from the offset (which will affect the position accordingly).\n            offset.QuadPart -= FileStream->ReadLength - FileStream->ReadPosition;\n        }\n\n        // TODO: Try to keep some of the read buffer.\n        FileStream->ReadPosition = 0;\n        FileStream->ReadLength = 0;\n    }\n\n    if (!NT_SUCCESS(status = PhpSeekFileStream(\n        FileStream,\n        &offset,\n        Origin\n        )))\n        return status;\n\n    return status;\n}\n\nNTSTATUS PhLockFileStream(\n    _Inout_ PPH_FILE_STREAM FileStream,\n    _In_ PLARGE_INTEGER Position,\n    _In_ PLARGE_INTEGER Length,\n    _In_ BOOLEAN Wait,\n    _In_ BOOLEAN Shared\n    )\n{\n    NTSTATUS status;\n    IO_STATUS_BLOCK isb;\n\n    status = NtLockFile(\n        FileStream->FileHandle,\n        NULL,\n        NULL,\n        NULL,\n        &isb,\n        Position,\n        Length,\n        0,\n        !Wait,\n        !Shared\n        );\n\n    if (status == STATUS_PENDING)\n    {\n        // Wait for the operation to finish. This probably means we got called on an asynchronous\n        // file object.\n        NtWaitForSingleObject(FileStream->FileHandle, FALSE, NULL);\n        status = isb.Status;\n    }\n\n    return status;\n}\n\nNTSTATUS PhUnlockFileStream(\n    _Inout_ PPH_FILE_STREAM FileStream,\n    _In_ PLARGE_INTEGER Position,\n    _In_ PLARGE_INTEGER Length\n    )\n{\n    IO_STATUS_BLOCK isb;\n\n    return NtUnlockFile(\n        FileStream->FileHandle,\n        &isb,\n        Position,\n        Length,\n        0\n        );\n}\n\nNTSTATUS PhWriteStringAsUtf8FileStream(\n    _Inout_ PPH_FILE_STREAM FileStream,\n    _In_ PPH_STRINGREF String\n    )\n{\n    return PhWriteStringAsUtf8FileStreamEx(FileStream, String->Buffer, String->Length);\n}\n\nNTSTATUS PhWriteStringAsUtf8FileStream2(\n    _Inout_ PPH_FILE_STREAM FileStream,\n    _In_ PWSTR String\n    )\n{\n    PH_STRINGREF string;\n\n    PhInitializeStringRef(&string, String);\n\n    return PhWriteStringAsUtf8FileStream(FileStream, &string);\n}\n\nNTSTATUS PhWriteStringAsUtf8FileStreamEx(\n    _Inout_ PPH_FILE_STREAM FileStream,\n    _In_ PWSTR Buffer,\n    _In_ SIZE_T Length\n    )\n{\n    NTSTATUS status = STATUS_SUCCESS;\n    PH_STRINGREF block;\n    SIZE_T inPlaceUtf8Size;\n    PCHAR inPlaceUtf8 = NULL;\n    PPH_BYTES utf8 = NULL;\n\n    if (Length > PAGE_SIZE)\n    {\n        // In UTF-8, the maximum number of bytes per code point is 4.\n        inPlaceUtf8Size = PAGE_SIZE / sizeof(WCHAR) * 4;\n        inPlaceUtf8 = PhAllocatePage(inPlaceUtf8Size, NULL);\n    }\n\n    while (Length != 0)\n    {\n        block.Buffer = Buffer;\n        block.Length = PAGE_SIZE;\n\n        if (block.Length > Length)\n            block.Length = Length;\n\n        if (inPlaceUtf8)\n        {\n            SIZE_T bytesInUtf8String;\n\n            if (!PhConvertUtf16ToUtf8Buffer(\n                inPlaceUtf8,\n                inPlaceUtf8Size,\n                &bytesInUtf8String,\n                block.Buffer,\n                block.Length\n                ))\n            {\n                status = STATUS_INVALID_PARAMETER;\n                goto CleanupExit;\n            }\n\n            status = PhWriteFileStream(FileStream, inPlaceUtf8, (ULONG)bytesInUtf8String);\n        }\n        else\n        {\n            utf8 = PhConvertUtf16ToUtf8Ex(block.Buffer, block.Length);\n\n            if (!utf8)\n            {\n                status = STATUS_INVALID_PARAMETER;\n                goto CleanupExit;\n            }\n\n            status = PhWriteFileStream(FileStream, utf8->Buffer, (ULONG)utf8->Length);\n            PhDereferenceObject(utf8);\n        }\n\n        if (!NT_SUCCESS(status))\n            goto CleanupExit;\n\n        Buffer += block.Length / sizeof(WCHAR);\n        Length -= block.Length;\n    }\n\nCleanupExit:\n    if (inPlaceUtf8)\n        PhFreePage(inPlaceUtf8);\n\n    return status;\n}\n\nNTSTATUS PhWriteStringFormatAsUtf8FileStream_V(\n    _Inout_ PPH_FILE_STREAM FileStream,\n    _In_ _Printf_format_string_ PWSTR Format,\n    _In_ va_list ArgPtr\n    )\n{\n    NTSTATUS status;\n    PPH_STRING string;\n\n    string = PhFormatString_V(Format, ArgPtr);\n    status = PhWriteStringAsUtf8FileStream(FileStream, &string->sr);\n    PhDereferenceObject(string);\n\n    return status;\n}\n\nNTSTATUS PhWriteStringFormatAsUtf8FileStream(\n    _Inout_ PPH_FILE_STREAM FileStream,\n    _In_ _Printf_format_string_ PWSTR Format,\n    ...\n    )\n{\n    va_list argptr;\n\n    va_start(argptr, Format);\n\n    return PhWriteStringFormatAsUtf8FileStream_V(FileStream, Format, argptr);\n}\n"
  },
  {
    "path": "third_party/phlib/format.c",
    "content": "/*\n * Process Hacker -\n *   string formatting\n *\n * Copyright (C) 2010-2015 wj32\n *\n * This file is part of Process Hacker.\n *\n * Process Hacker is free software; you can redistribute it and/or modify\n * it under the terms of the GNU General Public License as published by\n * the Free Software Foundation, either version 3 of the License, or\n * (at your option) any later version.\n *\n * Process Hacker is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n * GNU General Public License for more details.\n *\n * You should have received a copy of the GNU General Public License\n * along with Process Hacker.  If not, see <http://www.gnu.org/licenses/>.\n */\n\n/*\n * This module provides a high-performance string formatting mechanism. Instead of using format\n * strings, the user supplies an array of structures. This system is 2-5 times faster than\n * printf-based functions.\n *\n * This file contains the public interfaces, while including the real formatting code from\n * elsewhere. There are currently two functions: PhFormat, which returns a string object containing\n * the formatted string, and PhFormatToBuffer, which writes the formatted string to a buffer. The\n * latter is a bit faster due to the lack of resizing logic.\n */\n\n#include <phbase.h>\n\n#include <locale.h>\n\nextern ULONG PhMaxSizeUnit;\n\n#define SMALL_BUFFER_LENGTH (PH_OBJECT_SMALL_OBJECT_SIZE - FIELD_OFFSET(PH_STRING, Data) - sizeof(WCHAR))\n#define BUFFER_SIZE 512\n\n#define PHP_FORMAT_NEGATIVE 0x1\n#define PHP_FORMAT_POSITIVE 0x2\n#define PHP_FORMAT_PAD 0x4\n\n// Internal CRT routine needed for floating-point conversion\n#if 0\nerrno_t __cdecl _cfltcvt_l(double *arg, char *buffer, size_t sizeInBytes,\n    int format, int precision, int caps, _locale_t plocinfo);\n#endif\n\n// Keep in sync with PhSizeUnitNames\nstatic PH_STRINGREF PhpSizeUnitNamesCounted[7] =\n{\n    PH_STRINGREF_INIT(L\"B\"),\n    PH_STRINGREF_INIT(L\"kB\"),\n    PH_STRINGREF_INIT(L\"MB\"),\n    PH_STRINGREF_INIT(L\"GB\"),\n    PH_STRINGREF_INIT(L\"TB\"),\n    PH_STRINGREF_INIT(L\"PB\"),\n    PH_STRINGREF_INIT(L\"EB\")\n};\n\nstatic PH_INITONCE PhpFormatInitOnce = PH_INITONCE_INIT;\nstatic WCHAR PhpFormatDecimalSeparator = '.';\nstatic WCHAR PhpFormatThousandSeparator = ',';\nstatic _locale_t PhpFormatUserLocale = NULL;\n\n#if 0\n#if (_MSC_VER >= 1900)\n\n// See Source\\10.0.10150.0\\ucrt\\convert\\cvt.cpp in SDK v10.\nerrno_t __cdecl __acrt_fp_format(\n    double const* const value,\n    char*         const result_buffer,\n    size_t        const result_buffer_count,\n    char*         const scratch_buffer,\n    size_t        const scratch_buffer_count,\n    int           const format,\n    int           const precision,\n    UINT64        const options,\n    _locale_t     const locale\n    );\n\nstatic errno_t __cdecl _cfltcvt_l(double *arg, char *buffer, size_t sizeInBytes,\n    int format, int precision, int caps, _locale_t plocinfo)\n{\n    char scratch_buffer[_CVTBUFSIZE + 1];\n\n    if (caps & 1)\n        format -= 32; // Make uppercase\n\n    return __acrt_fp_format(arg, buffer, sizeInBytes, scratch_buffer, sizeof(scratch_buffer),\n        format, precision, 0, plocinfo);\n}\n\n#endif\n#endif\n\n// From Source\\10.0.10150.0\\ucrt\\inc\\corecrt_internal_stdio_output.h in SDK v10.\nVOID PhpCropZeros(\n    _Inout_ PCHAR Buffer,\n    _In_ _locale_t Locale\n    )\n{\n    CHAR decimalSeparator = (CHAR)PhpFormatDecimalSeparator;\n\n    while (*Buffer && *Buffer != decimalSeparator)\n        ++Buffer;\n\n    if (*Buffer++)\n    {\n        while (*Buffer && *Buffer != 'e' && *Buffer != 'E')\n            ++Buffer;\n\n        PCHAR stop = Buffer--;\n\n        while (*Buffer == '0')\n            --Buffer;\n\n        if (*Buffer == decimalSeparator)\n            --Buffer;\n\n        while ((*++Buffer = *stop++) != '\\0')\n            NOTHING;\n    }\n}\n\nPPH_STRING PhpResizeFormatBuffer(\n    _In_ PPH_STRING String,\n    _Inout_ PSIZE_T AllocatedLength,\n    _In_ SIZE_T UsedLength,\n    _In_ SIZE_T NeededLength\n    )\n{\n    PPH_STRING newString;\n    SIZE_T allocatedLength;\n\n    allocatedLength = *AllocatedLength;\n    allocatedLength *= 2;\n\n    if (allocatedLength < UsedLength + NeededLength)\n        allocatedLength = UsedLength + NeededLength;\n\n    newString = PhCreateStringEx(NULL, allocatedLength);\n    memcpy(newString->Buffer, String->Buffer, UsedLength);\n    PhDereferenceObject(String);\n\n    *AllocatedLength = allocatedLength;\n\n    return newString;\n}\n\n/**\n * Creates a formatted string.\n *\n * \\param Format An array of format structures.\n * \\param Count The number of structures supplied in \\a Format.\n * \\param InitialCapacity The number of bytes to reserve initially for the string. If 0 is\n * specified, a default value is used.\n */\nPPH_STRING PhFormat(\n    _In_reads_(Count) PPH_FORMAT Format,\n    _In_ ULONG Count,\n    _In_opt_ SIZE_T InitialCapacity\n    )\n{\n    PPH_STRING string;\n    SIZE_T allocatedLength;\n    PWSTR buffer;\n    SIZE_T usedLength;\n\n    // Set up the buffer.\n\n    // If the specified initial capacity is too small (or zero), use the largest buffer size which\n    // will still be eligible for allocation from the small object free list.\n    if (InitialCapacity < SMALL_BUFFER_LENGTH)\n        InitialCapacity = SMALL_BUFFER_LENGTH;\n\n    string = PhCreateStringEx(NULL, InitialCapacity);\n    allocatedLength = InitialCapacity;\n    buffer = string->Buffer;\n    usedLength = 0;\n\n#undef ENSURE_BUFFER\n#undef OK_BUFFER\n#undef ADVANCE_BUFFER\n\n#define ENSURE_BUFFER(NeededLength) \\\n    do { \\\n        if (allocatedLength < usedLength + (NeededLength)) \\\n        { \\\n            string = PhpResizeFormatBuffer(string, &allocatedLength, usedLength, (NeededLength)); \\\n            buffer = string->Buffer + usedLength / sizeof(WCHAR); \\\n        } \\\n    } while (0)\n\n#define OK_BUFFER (TRUE)\n\n#define ADVANCE_BUFFER(Length) \\\n    do { buffer += (Length) / sizeof(WCHAR); usedLength += (Length); } while (0)\n\n#include \"format_i.h\"\n\n    string->Length = usedLength;\n    // Null-terminate the string.\n    string->Buffer[usedLength / sizeof(WCHAR)] = 0;\n\n    return string;\n}\n\n/**\n * Writes a formatted string to a buffer.\n *\n * \\param Format An array of format structures.\n * \\param Count The number of structures supplied in \\a Format.\n * \\param Buffer A buffer. If NULL, no data is written.\n * \\param BufferLength The number of bytes available in \\a Buffer, including space for the null\n * terminator.\n * \\param ReturnLength The number of bytes required to hold the string, including the null\n * terminator.\n *\n * \\return TRUE if the buffer was large enough and the string was written (i.e. \\a BufferLength >=\n * \\a ReturnLength), otherwise FALSE. In either case, the required number of bytes is stored in\n * \\a ReturnLength.\n *\n * \\remarks If the function fails but \\a BufferLength != 0, a single null byte is written to the\n * start of \\a Buffer.\n */\nBOOLEAN PhFormatToBuffer(\n    _In_reads_(Count) PPH_FORMAT Format,\n    _In_ ULONG Count,\n    _Out_writes_bytes_opt_(BufferLength) PWSTR Buffer,\n    _In_opt_ SIZE_T BufferLength,\n    _Out_opt_ PSIZE_T ReturnLength\n    )\n{\n    PWSTR buffer;\n    SIZE_T usedLength;\n    BOOLEAN overrun;\n\n    buffer = Buffer;\n    usedLength = 0;\n    overrun = FALSE;\n\n    // Make sure we don't try to write anything if we don't have a buffer.\n    if (!Buffer)\n        overrun = TRUE;\n\n#undef ENSURE_BUFFER\n#undef OK_BUFFER\n#undef ADVANCE_BUFFER\n\n#define ENSURE_BUFFER(NeededLength) \\\n    do { \\\n        if (!overrun && (BufferLength < usedLength + (NeededLength))) \\\n            overrun = TRUE; \\\n    } while (0)\n\n#define OK_BUFFER (!overrun)\n\n#define ADVANCE_BUFFER(Length) \\\n    do { buffer += (Length) / sizeof(WCHAR); usedLength += (Length); } while (0)\n\n#include \"format_i.h\"\n\n    // Write the null-terminator.\n    ENSURE_BUFFER(sizeof(WCHAR));\n    if (OK_BUFFER)\n        *buffer = 0;\n    else if (Buffer && BufferLength != 0) // try to null-terminate even if this function fails\n        *Buffer = 0;\n    ADVANCE_BUFFER(sizeof(WCHAR));\n\n    if (ReturnLength)\n        *ReturnLength = usedLength;\n\n    return OK_BUFFER;\n}\n"
  },
  {
    "path": "third_party/phlib/format_i.h",
    "content": "/*\n * This file contains the actual formatting code used by various public interface functions.\n *\n * There are three macros defined by the parent function which control how this code writes the\n * formatted string:\n * * ENSURE_BUFFER - This macro is passed the number of bytes required whenever characters need to\n *   be written to the buffer. The macro can resize the buffer if needed.\n * * OK_BUFFER - This macro returns TRUE if it is OK to write to the buffer, otherwise FALSE when\n *   the buffer is too large, is not specified, or some other error has occurred.\n * * ADVANCE_BUFFER - This macro is passed the number of bytes written to the buffer and should\n *   increment the \"buffer\" pointer and \"usedLength\" counter.\n * In addition to these macros, the \"buffer\" and \"usedLength\" variables are assumed to be present.\n *\n * The below code defines many macros; this is so that composite formatting types can be constructed\n * (e.g. the \"size\" type).\n */\n\n{\n    if (PhBeginInitOnce(&PhpFormatInitOnce))\n    {\n        WCHAR localeBuffer[4];\n\n        if (GetLocaleInfo(LOCALE_USER_DEFAULT, LOCALE_SDECIMAL, localeBuffer, 4) &&\n            (localeBuffer[0] != 0 && localeBuffer[1] == 0))\n        {\n            PhpFormatDecimalSeparator = localeBuffer[0];\n        }\n\n        if (GetLocaleInfo(LOCALE_USER_DEFAULT, LOCALE_STHOUSAND, localeBuffer, 4) &&\n            (localeBuffer[0] != 0 && localeBuffer[1] == 0))\n        {\n            PhpFormatThousandSeparator = localeBuffer[0];\n        }\n\n        if (PhpFormatDecimalSeparator != '.')\n            PhpFormatUserLocale = _create_locale(LC_ALL, \"\");\n\n        PhEndInitOnce(&PhpFormatInitOnce);\n    }\n\n    while (Count--)\n    {\n        PPH_FORMAT format;\n        SIZE_T partLength;\n        WCHAR tempBuffer[BUFFER_SIZE];\n        ULONG flags;\n        ULONG int32;\n        ULONG64 int64;\n\n        format = Format++;\n\n        // Save the currently used length so we can compute the part length later.\n        partLength = usedLength;\n\n        flags = 0;\n\n        switch (format->Type & FormatTypeMask)\n        {\n\n        // Characters and Strings\n\n        case CharFormatType:\n            ENSURE_BUFFER(sizeof(WCHAR));\n            if (OK_BUFFER)\n                *buffer = format->u.Char;\n            ADVANCE_BUFFER(sizeof(WCHAR));\n            break;\n        case StringFormatType:\n            ENSURE_BUFFER(format->u.String.Length);\n            if (OK_BUFFER)\n                memcpy(buffer, format->u.String.Buffer, format->u.String.Length);\n            ADVANCE_BUFFER(format->u.String.Length);\n            break;\n        case StringZFormatType:\n            {\n                SIZE_T count;\n\n                count = PhCountStringZ(format->u.StringZ);\n                ENSURE_BUFFER(count * sizeof(WCHAR));\n                if (OK_BUFFER)\n                    memcpy(buffer, format->u.StringZ, count * sizeof(WCHAR));\n                ADVANCE_BUFFER(count * sizeof(WCHAR));\n            }\n            break;\n        case MultiByteStringFormatType:\n        case MultiByteStringZFormatType:\n            {\n                ULONG bytesInUnicodeString;\n                PSTR multiByteBuffer;\n                SIZE_T multiByteLength;\n\n                if (format->Type == MultiByteStringFormatType)\n                {\n                    multiByteBuffer = format->u.MultiByteString.Buffer;\n                    multiByteLength = format->u.MultiByteString.Length;\n                }\n                else\n                {\n                    multiByteBuffer = format->u.MultiByteStringZ;\n                    multiByteLength = strlen(multiByteBuffer);\n                }\n\n                if (NT_SUCCESS(RtlMultiByteToUnicodeSize(\n                    &bytesInUnicodeString,\n                    multiByteBuffer,\n                    (ULONG)multiByteLength\n                    )))\n                {\n                    ENSURE_BUFFER(bytesInUnicodeString);\n\n                    if (!OK_BUFFER || NT_SUCCESS(RtlMultiByteToUnicodeN(\n                        buffer,\n                        bytesInUnicodeString,\n                        NULL,\n                        multiByteBuffer,\n                        (ULONG)multiByteLength\n                        )))\n                    {\n                        ADVANCE_BUFFER(bytesInUnicodeString);\n                    }\n                }\n            }\n            break;\n\n        // Integers\n\n#define PROCESS_DIGIT(Input) \\\n    do { \\\n        r = (ULONG)(Input % radix); \\\n        Input /= radix; \\\n        *temp-- = integerToChar[r]; \\\n        tempCount++; \\\n    } while (0)\n\n#define COMMON_INTEGER_FORMAT(Input, Format) \\\n    do { \\\n        ULONG radix; \\\n        PCHAR integerToChar; \\\n        PWSTR temp; \\\n        ULONG tempCount; \\\n        ULONG r; \\\n        ULONG preCount; \\\n        ULONG padCount; \\\n        \\\n        radix = 10; \\\n        if (((Format)->Type & FormatUseRadix) && (Format)->Radix >= 2 && (Format)->Radix <= 69) \\\n            radix = (Format)->Radix; \\\n        integerToChar = PhIntegerToChar; \\\n        if ((Format)->Type & FormatUpperCase) \\\n            integerToChar = PhIntegerToCharUpper; \\\n        temp = tempBuffer + BUFFER_SIZE - 1; \\\n        tempCount = 0; \\\n        \\\n        if (Input != 0) \\\n        { \\\n            if ((Format)->Type & FormatGroupDigits) \\\n            { \\\n                ULONG needsSep = 0; \\\n                \\\n                do \\\n                { \\\n                    PROCESS_DIGIT(Input); \\\n                    \\\n                    if (++needsSep == 3 && Input != 0) /* get rid of trailing separator */ \\\n                    { \\\n                        *temp-- = PhpFormatThousandSeparator; \\\n                        tempCount++; \\\n                        needsSep = 0; \\\n                    } \\\n                } while (Input != 0); \\\n            } \\\n            else \\\n            { \\\n                do \\\n                { \\\n                    PROCESS_DIGIT(Input); \\\n                } while (Input != 0); \\\n            } \\\n        } \\\n        else \\\n        { \\\n            *temp-- = '0'; \\\n            tempCount++; \\\n        } \\\n        \\\n        preCount = 0; \\\n        \\\n        if (flags & PHP_FORMAT_NEGATIVE) \\\n            preCount++; \\\n        else if ((Format)->Type & FormatPrefixSign) \\\n            preCount++; \\\n        \\\n        if (((Format)->Type & FormatPadZeros) && !((Format)->Type & FormatGroupDigits)) \\\n        { \\\n            if (preCount + tempCount < (Format)->Width) \\\n            { \\\n                flags |= PHP_FORMAT_PAD; \\\n                padCount = (Format)->Width - (preCount + tempCount); \\\n                preCount += padCount; \\\n            } \\\n        } \\\n        \\\n        temp++; \\\n        ENSURE_BUFFER((preCount + tempCount) * sizeof(WCHAR)); \\\n        if (OK_BUFFER) \\\n        { \\\n            if (flags & PHP_FORMAT_NEGATIVE) \\\n                *buffer++ = '-'; \\\n            else if ((Format)->Type & FormatPrefixSign) \\\n                *buffer++ = '+'; \\\n            \\\n            if (flags & PHP_FORMAT_PAD) \\\n            { \\\n                wmemset(buffer, '0', padCount); \\\n                buffer += padCount; \\\n            } \\\n            \\\n            memcpy(buffer, temp, tempCount * sizeof(WCHAR)); \\\n            buffer += tempCount; \\\n        } \\\n        usedLength += (preCount + tempCount) * sizeof(WCHAR); \\\n    } while (0)\n\n#ifndef _WIN64\n        case IntPtrFormatType:\n            int32 = format->u.IntPtr;\n            goto CommonMaybeNegativeInt32Format;\n#endif\n        case Int32FormatType:\n            int32 = format->u.Int32;\n\n#ifndef _WIN64\nCommonMaybeNegativeInt32Format:\n#endif\n            if ((LONG)int32 < 0)\n            {\n                int32 = -(LONG)int32;\n                flags |= PHP_FORMAT_NEGATIVE;\n            }\n\n            goto CommonInt32Format;\n#ifndef _WIN64\n        case UIntPtrFormatType:\n            int32 = format->u.UIntPtr;\n            goto CommonInt32Format;\n#endif\n        case UInt32FormatType:\n            int32 = format->u.UInt32;\nCommonInt32Format:\n            COMMON_INTEGER_FORMAT(int32, format);\n            break;\n#ifdef _WIN64\n        case IntPtrFormatType:\n            int64 = format->u.IntPtr;\n            goto CommonMaybeNegativeInt64Format;\n#endif\n        case Int64FormatType:\n            int64 = format->u.Int64;\n\n#ifdef _WIN64\nCommonMaybeNegativeInt64Format:\n#endif\n            if ((LONG64)int64 < 0)\n            {\n                int64 = -(LONG64)int64;\n                flags |= PHP_FORMAT_NEGATIVE;\n            }\n\n            goto CommonInt64Format;\n#ifdef _WIN64\n        case UIntPtrFormatType:\n            int64 = format->u.UIntPtr;\n            goto CommonInt64Format;\n#endif\n        case UInt64FormatType:\n            int64 = format->u.UInt64;\nCommonInt64Format:\n            COMMON_INTEGER_FORMAT(int64, format);\n            break;\n\n        // Floating point numbers\n\n#define COMMON_DOUBLE_FORMAT(Format) \\\n    do { \\\n        ULONG precision; \\\n        DOUBLE value; \\\n        CHAR c; \\\n        PSTR temp; \\\n        ULONG length; \\\n        \\\n        if ((Format)->Type & FormatUsePrecision) \\\n        { \\\n            precision = (Format)->Precision; \\\n            \\\n            if (precision > BUFFER_SIZE - 1 - _CVTBUFSIZE) \\\n                precision = BUFFER_SIZE - 1 - _CVTBUFSIZE; \\\n        } \\\n        else \\\n        { \\\n            precision = 6; \\\n        } \\\n        \\\n        c = 'f'; \\\n        \\\n        if ((Format)->Type & FormatStandardForm) \\\n            c = 'e'; \\\n        else if ((Format)->Type & FormatHexadecimalForm) \\\n            c = 'a'; \\\n        \\\n        /* Use MS CRT routines to do the work. */ \\\n        \\\n        value = (Format)->u.Double; \\\n        temp = (PSTR)tempBuffer + 1; /* leave one character so we can insert a prefix if needed */ \\\n        \\\n        /* if (((Format)->Type & FormatForceDecimalPoint) && precision == 0) */ \\\n             /* _forcdecpt_l(tempBufferAnsi, PhpFormatUserLocale); */ \\\n        if ((Format)->Type & FormatCropZeros) \\\n            PhpCropZeros(temp, PhpFormatUserLocale); \\\n        \\\n        length = (ULONG)strlen(temp); \\\n        \\\n        if (temp[0] == '-') \\\n        { \\\n            flags |= PHP_FORMAT_NEGATIVE; \\\n            temp++; \\\n            length--; \\\n        } \\\n        else if ((Format)->Type & FormatPrefixSign) \\\n        { \\\n            flags |= PHP_FORMAT_POSITIVE; \\\n        } \\\n        \\\n        if (((Format)->Type & FormatGroupDigits) && !((Format)->Type & (FormatStandardForm | FormatHexadecimalForm))) \\\n        { \\\n            PSTR whole; \\\n            PSTR decimalPoint; \\\n            ULONG wholeCount; \\\n            ULONG sepsCount; \\\n            ULONG ensureLength; \\\n            ULONG copyCount; \\\n            ULONG needsSep; \\\n            \\\n            /* Find the first non-digit character and assume that is the */ \\\n            /* decimal point (or the end of the string). */ \\\n            \\\n            whole = temp; \\\n            decimalPoint = temp; \\\n            \\\n            while ((UCHAR)(*decimalPoint - '0') < 10) \\\n                decimalPoint++; \\\n            \\\n            /* Copy the characters to the output buffer, and at the same time */ \\\n            /* insert the separators. */ \\\n            \\\n            wholeCount = (ULONG)(decimalPoint - temp); \\\n            \\\n            if (wholeCount != 0) \\\n                sepsCount = (wholeCount + 2) / 3 - 1; \\\n            else \\\n                sepsCount = 0; \\\n            \\\n            ensureLength = (length + sepsCount) * sizeof(WCHAR); \\\n            if (flags & (PHP_FORMAT_NEGATIVE | PHP_FORMAT_POSITIVE)) \\\n                ensureLength += sizeof(WCHAR); \\\n            ENSURE_BUFFER(ensureLength); \\\n            \\\n            copyCount = wholeCount; \\\n            needsSep = (wholeCount + 2) % 3; \\\n            \\\n            if (OK_BUFFER) \\\n            { \\\n                if (flags & PHP_FORMAT_NEGATIVE) \\\n                    *buffer++ = '-'; \\\n                else if (flags & PHP_FORMAT_POSITIVE) \\\n                    *buffer++ = '+'; \\\n                \\\n                while (copyCount--) \\\n                { \\\n                    *buffer++ = *whole++; \\\n                    \\\n                    if (needsSep-- == 0 && copyCount != 0) /* get rid of trailing separator */ \\\n                    { \\\n                        *buffer++ = PhpFormatThousandSeparator; \\\n                        needsSep = 2; \\\n                    } \\\n                } \\\n            } \\\n            \\\n            if (flags & (PHP_FORMAT_NEGATIVE | PHP_FORMAT_POSITIVE)) \\\n                usedLength += sizeof(WCHAR); \\\n            usedLength += (wholeCount + sepsCount) * sizeof(WCHAR); \\\n            \\\n            /* Copy the rest. */ \\\n            \\\n            copyCount = length - wholeCount; \\\n            \\\n            if (OK_BUFFER) \\\n            { \\\n                PhZeroExtendToUtf16Buffer(decimalPoint, copyCount, buffer); \\\n                ADVANCE_BUFFER(copyCount * sizeof(WCHAR)); \\\n            } \\\n        } \\\n        else \\\n        { \\\n            SIZE_T preLength; \\\n            SIZE_T padLength; \\\n            \\\n            /* Take care of the sign and zero padding. */ \\\n            preLength = 0; \\\n            \\\n            if (flags & (PHP_FORMAT_NEGATIVE | PHP_FORMAT_POSITIVE)) \\\n                preLength++; \\\n            \\\n            if ((Format)->Type & FormatPadZeros) \\\n            { \\\n                if (preLength + length < (Format)->Width) \\\n                { \\\n                    flags |= PHP_FORMAT_PAD; \\\n                    padLength = (Format)->Width - (preLength + length); \\\n                    preLength += padLength; \\\n                } \\\n            } \\\n            /* We don't need to group digits, so directly copy the characters */ \\\n            /* to the output buffer. */ \\\n            \\\n            ENSURE_BUFFER((preLength + length) * sizeof(WCHAR)); \\\n            \\\n            if (OK_BUFFER) \\\n            { \\\n                if (flags & PHP_FORMAT_NEGATIVE) \\\n                    *buffer++ = '-'; \\\n                else if (flags & PHP_FORMAT_POSITIVE) \\\n                    *buffer++ = '+'; \\\n                \\\n                if (flags & PHP_FORMAT_PAD) \\\n                { \\\n                    wmemset(buffer, '0', padLength); \\\n                    buffer += padLength; \\\n                } \\\n            } \\\n            \\\n            usedLength += preLength * sizeof(WCHAR); \\\n            \\\n            if (OK_BUFFER) \\\n            { \\\n                PhZeroExtendToUtf16Buffer((PSTR)temp, length, buffer); \\\n                ADVANCE_BUFFER(length * sizeof(WCHAR)); \\\n            } \\\n        } \\\n    } while (0)\n\n        case DoubleFormatType:\n            flags = 0;\n            COMMON_DOUBLE_FORMAT(format);\n            break;\n\n        // Additional types\n\n        case SizeFormatType:\n            {\n                ULONG i = 0;\n                ULONG maxSizeUnit;\n                DOUBLE s;\n                PH_FORMAT doubleFormat;\n\n                s = (DOUBLE)format->u.Size;\n\n                if (format->u.Size == 0)\n                {\n                    ENSURE_BUFFER(sizeof(WCHAR));\n                    if (OK_BUFFER)\n                        *buffer = '0';\n                    ADVANCE_BUFFER(sizeof(WCHAR));\n                    goto ContinueLoop;\n                }\n\n                if (format->Type & FormatUseRadix)\n                    maxSizeUnit = format->Radix;\n                else\n                    maxSizeUnit = PhMaxSizeUnit;\n\n                while (\n                    s >= 1000 &&\n                    i < sizeof(PhpSizeUnitNamesCounted) / sizeof(PH_STRINGREF) &&\n                    i < maxSizeUnit\n                    )\n                {\n                    s /= 1024;\n                    i++;\n                }\n\n                // Format the number, then append the unit name.\n\n                doubleFormat.Type = DoubleFormatType | FormatUsePrecision | FormatCropZeros | FormatGroupDigits;\n                doubleFormat.Precision = (format->Type & FormatUsePrecision) ? format->Precision : 2;\n                doubleFormat.Width = 0; // stupid compiler\n                doubleFormat.u.Double = s;\n                flags = 0;\n                COMMON_DOUBLE_FORMAT(&doubleFormat);\n\n                ENSURE_BUFFER(sizeof(WCHAR) + PhpSizeUnitNamesCounted[i].Length);\n                if (OK_BUFFER)\n                {\n                    *buffer = ' ';\n                    memcpy(buffer + 1, PhpSizeUnitNamesCounted[i].Buffer, PhpSizeUnitNamesCounted[i].Length);\n                }\n                ADVANCE_BUFFER(sizeof(WCHAR) + PhpSizeUnitNamesCounted[i].Length);\n            }\n            break;\n        }\n\nContinueLoop:\n        partLength = usedLength - partLength;\n\n        if (format->Type & (FormatLeftAlign | FormatRightAlign))\n        {\n            SIZE_T newLength;\n            SIZE_T addLength;\n\n            newLength = format->Width * sizeof(WCHAR);\n\n            // We only pad and never truncate.\n            if (partLength < newLength)\n            {\n                addLength = newLength - partLength;\n                ENSURE_BUFFER(addLength);\n\n                if (OK_BUFFER)\n                {\n                    WCHAR pad;\n\n                    if (format->Type & FormatUsePad)\n                        pad = format->Pad;\n                    else\n                        pad = ' ';\n\n                    if (format->Type & FormatLeftAlign)\n                    {\n                        // Left alignment is easy; we just fill the remaining space with the pad\n                        // character.\n                        wmemset(buffer, pad, addLength / sizeof(WCHAR));\n                    }\n                    else\n                    {\n                        PWSTR start;\n\n                        // Right alignment is much slower and involves moving the text forward, then\n                        // filling in the space before it.\n                        start = buffer - partLength / sizeof(WCHAR);\n                        memmove(start + addLength / sizeof(WCHAR), start, partLength);\n                        wmemset(start, pad, addLength / sizeof(WCHAR));\n                    }\n                }\n\n                ADVANCE_BUFFER(addLength);\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "third_party/phlib/global.c",
    "content": "/*\n * Process Hacker -\n *   global variables and initialization functions\n *\n * Copyright (C) 2010-2013 wj32\n *\n * This file is part of Process Hacker.\n *\n * Process Hacker is free software; you can redistribute it and/or modify\n * it under the terms of the GNU General Public License as published by\n * the Free Software Foundation, either version 3 of the License, or\n * (at your option) any later version.\n *\n * Process Hacker is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n * GNU General Public License for more details.\n *\n * You should have received a copy of the GNU General Public License\n * along with Process Hacker.  If not, see <http://www.gnu.org/licenses/>.\n */\n\n#include <ph.h>\n\n#include <filestream.h>\n#include <phintrnl.h>\n#include <symprv.h>\n\nBOOLEAN PhInitializeSystem(\n    _In_ ULONG Flags\n    );\n\nVOID PhInitializeSystemInformation(\n    VOID\n    );\n\nVOID PhInitializeWindowsVersion(\n    VOID\n    );\n\nPHLIBAPI PVOID PhInstanceHandle;\nPHLIBAPI PWSTR PhApplicationName = L\"Application\";\nPHLIBAPI ULONG PhGlobalDpi = 96;\nPHLIBAPI PVOID PhHeapHandle;\nPHLIBAPI RTL_OSVERSIONINFOEXW PhOsVersion;\nPHLIBAPI SYSTEM_BASIC_INFORMATION PhSystemBasicInformation;\nPHLIBAPI ULONG WindowsVersion;\n\nPHLIBAPI ACCESS_MASK ProcessQueryAccess;\nPHLIBAPI ACCESS_MASK ProcessAllAccess;\nPHLIBAPI ACCESS_MASK ThreadQueryAccess;\nPHLIBAPI ACCESS_MASK ThreadSetAccess;\nPHLIBAPI ACCESS_MASK ThreadAllAccess;\n\n// Internal data\n#ifdef DEBUG\nPHLIB_STATISTICS_BLOCK PhLibStatisticsBlock;\n#endif\n\nNTSTATUS PhInitializePhLib(\n    VOID\n    )\n{\n    return PhInitializePhLibEx(\n        0xffffffff, // all possible features\n        NtCurrentPeb()->ImageBaseAddress,\n        0,\n        0\n        );\n}\n\nNTSTATUS PhInitializePhLibEx(\n    _In_ ULONG Flags,\n    _In_ PVOID ImageBaseAddress,\n    _In_opt_ SIZE_T HeapReserveSize,\n    _In_opt_ SIZE_T HeapCommitSize\n    )\n{\n    PhInstanceHandle = ImageBaseAddress;\n    PhHeapHandle = RtlCreateHeap(\n        HEAP_GROWABLE | HEAP_CLASS_1,\n        NULL,\n        HeapReserveSize ? HeapReserveSize : 2 * 1024 * 1024, // 2 MB\n        HeapCommitSize ? HeapCommitSize : 1024 * 1024, // 1 MB\n        NULL,\n        NULL\n        );\n\n    if (!PhHeapHandle)\n        return STATUS_INSUFFICIENT_RESOURCES;\n\n    PhInitializeWindowsVersion();\n    PhInitializeSystemInformation();\n\n    if (!PhQueuedLockInitialization())\n        return STATUS_UNSUCCESSFUL;\n\n    if (!NT_SUCCESS(PhRefInitialization()))\n        return STATUS_UNSUCCESSFUL;\n    if (!PhBaseInitialization())\n        return STATUS_UNSUCCESSFUL;\n\n    if (!PhInitializeSystem(Flags))\n        return STATUS_UNSUCCESSFUL;\n\n    return STATUS_SUCCESS;\n}\n\n#ifndef _WIN64\nBOOLEAN PhIsExecutingInWow64(\n    VOID\n    )\n{\n    static BOOLEAN valid = FALSE;\n    static BOOLEAN isWow64;\n\n    if (!valid)\n    {\n        PhGetProcessIsWow64(NtCurrentProcess(), &isWow64);\n        MemoryBarrier();\n        valid = TRUE;\n    }\n\n    return isWow64;\n}\n#endif\n\nstatic BOOLEAN PhInitializeSystem(\n    _In_ ULONG Flags\n    )\n{\n    if (Flags & PHLIB_INIT_MODULE_FILE_STREAM)\n    {\n        if (!PhFileStreamInitialization())\n            return FALSE;\n    }\n\n    if (Flags & PHLIB_INIT_MODULE_SYMBOL_PROVIDER)\n    {\n        if (!PhSymbolProviderInitialization())\n            return FALSE;\n    }\n\n    return TRUE;\n}\n\nstatic VOID PhInitializeSystemInformation(\n    VOID\n    )\n{\n    NtQuerySystemInformation(\n        SystemBasicInformation,\n        &PhSystemBasicInformation,\n        sizeof(SYSTEM_BASIC_INFORMATION),\n        NULL\n        );\n}\n\nstatic VOID PhInitializeWindowsVersion(\n    VOID\n    )\n{\n    RTL_OSVERSIONINFOEXW versionInfo;\n    ULONG majorVersion;\n    ULONG minorVersion;\n    ULONG buildVersion;\n\n    versionInfo.dwOSVersionInfoSize = sizeof(RTL_OSVERSIONINFOEXW);\n\n    if (!NT_SUCCESS(RtlGetVersion((PRTL_OSVERSIONINFOW)&versionInfo)))\n    {\n        WindowsVersion = WINDOWS_NEW;\n        return;\n    }\n\n    memcpy(&PhOsVersion, &versionInfo, sizeof(RTL_OSVERSIONINFOEXW));\n    majorVersion = versionInfo.dwMajorVersion;\n    minorVersion = versionInfo.dwMinorVersion;\n    buildVersion = versionInfo.dwBuildNumber;\n\n    if (majorVersion == 6 && minorVersion < 1 || majorVersion < 6)\n    {\n        WindowsVersion = WINDOWS_ANCIENT;\n    }\n    /* Windows 7, Windows Server 2008 R2 */\n    else if (majorVersion == 6 && minorVersion == 1)\n    {\n        WindowsVersion = WINDOWS_7;\n    }\n    /* Windows 8 */\n    else if (majorVersion == 6 && minorVersion == 2)\n    {\n        WindowsVersion = WINDOWS_8;\n    }\n    /* Windows 8.1 */\n    else if (majorVersion == 6 && minorVersion == 3)\n    {\n        WindowsVersion = WINDOWS_8_1;\n    }\n    /* Windows 10 */\n    else if (majorVersion == 10 && minorVersion == 0)\n    {\n        switch (buildVersion)\n        {\n        case 10240:\n            WindowsVersion = WINDOWS_10;\n            break;\n        case 10586:\n            WindowsVersion = WINDOWS_10_TH2;\n            break;\n        case 14393:\n            WindowsVersion = WINDOWS_10_RS1;\n            break;\n        case 15063:\n            WindowsVersion = WINDOWS_10_RS2;\n            break;\n        case 16299:\n            WindowsVersion = WINDOWS_10_RS3;\n            break;\n        default:\n            WindowsVersion = WINDOWS_NEW;\n            break;\n        }\n    }\n    else if (majorVersion == 10 && minorVersion > 0 || majorVersion > 10)\n    {\n        WindowsVersion = WINDOWS_NEW;\n    }\n\n    ProcessQueryAccess = PROCESS_QUERY_LIMITED_INFORMATION;\n    ProcessAllAccess = STANDARD_RIGHTS_REQUIRED | SYNCHRONIZE | 0x1fff;\n    ThreadQueryAccess = THREAD_QUERY_LIMITED_INFORMATION;\n    ThreadSetAccess = THREAD_SET_LIMITED_INFORMATION;\n    ThreadAllAccess = STANDARD_RIGHTS_REQUIRED | SYNCHRONIZE | 0xfff;\n}\n"
  },
  {
    "path": "third_party/phlib/graph.c",
    "content": "/*\n * Process Hacker -\n *   graph control\n *\n * Copyright (C) 2010-2016 wj32\n * Copyright (C) 2017-2018 dmex\n *\n * This file is part of Process Hacker.\n *\n * Process Hacker is free software; you can redistribute it and/or modify\n * it under the terms of the GNU General Public License as published by\n * the Free Software Foundation, either version 3 of the License, or\n * (at your option) any later version.\n *\n * Process Hacker is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n * GNU General Public License for more details.\n *\n * You should have received a copy of the GNU General Public License\n * along with Process Hacker.  If not, see <http://www.gnu.org/licenses/>.\n */\n\n#include <ph.h>\n\n#include <windowsx.h>\n#include <math.h>\n\n#include <graph.h>\n#include <guisup.h>\n\n#define COLORREF_TO_BITS(Color) (_byteswap_ulong(Color) >> 8)\n\ntypedef struct _PHP_GRAPH_CONTEXT\n{\n    HWND Handle;\n    ULONG Style;\n    ULONG_PTR Id;\n    PH_GRAPH_DRAW_INFO DrawInfo;\n    PH_GRAPH_OPTIONS Options;\n    BOOLEAN NeedsUpdate;\n    BOOLEAN NeedsDraw;\n\n    HDC BufferedContext;\n    HBITMAP BufferedOldBitmap;\n    HBITMAP BufferedBitmap;\n    PVOID BufferedBits;\n    RECT BufferedContextRect;\n\n    HDC FadeOutContext;\n    HBITMAP FadeOutOldBitmap;\n    HBITMAP FadeOutBitmap;\n    PVOID FadeOutBits;\n    RECT FadeOutContextRect;\n\n    HWND TooltipHandle;\n    WNDPROC TooltipOldWndProc;\n    POINT LastCursorLocation;\n} PHP_GRAPH_CONTEXT, *PPHP_GRAPH_CONTEXT;\n\nLRESULT CALLBACK PhpGraphWndProc(\n    _In_ HWND hwnd,\n    _In_ UINT uMsg,\n    _In_ WPARAM wParam,\n    _In_ LPARAM lParam\n    );\n\nRECT PhNormalGraphTextMargin = { 5, 5, 5, 5 };\nRECT PhNormalGraphTextPadding = { 3, 3, 3, 3 };\n\nBOOLEAN PhGraphControlInitialization(\n    VOID\n    )\n{\n    WNDCLASSEX c = { sizeof(c) };\n\n    c.style = CS_GLOBALCLASS | CS_DBLCLKS;\n    c.lpfnWndProc = PhpGraphWndProc;\n    c.cbClsExtra = 0;\n    c.cbWndExtra = sizeof(PVOID);\n    c.hInstance = PhInstanceHandle;\n    c.hIcon = NULL;\n    c.hCursor = LoadCursor(NULL, IDC_ARROW);\n    c.hbrBackground = NULL;\n    c.lpszMenuName = NULL;\n    c.lpszClassName = PH_GRAPH_CLASSNAME;\n    c.hIconSm = NULL;\n\n    if (!RegisterClassEx(&c))\n        return FALSE;\n\n    return TRUE;\n}\n\nFORCEINLINE VOID PhpGetGraphPoint(\n    _In_ PPH_GRAPH_DRAW_INFO DrawInfo,\n    _In_ ULONG Index,\n    _Out_ PULONG H1,\n    _Out_ PULONG H2\n    )\n{\n    if (Index < DrawInfo->LineDataCount)\n    {\n        FLOAT f1;\n        FLOAT f2;\n\n        f1 = DrawInfo->LineData1[Index];\n\n        if (f1 < 0)\n            f1 = 0;\n        if (f1 > 1)\n            f1 = 1;\n\n        *H1 = (ULONG)(f1 * (DrawInfo->Height - 1));\n\n        if (DrawInfo->Flags & PH_GRAPH_USE_LINE_2)\n        {\n            f2 = f1 + DrawInfo->LineData2[Index];\n\n            if (f2 < 0)\n                f2 = 0;\n            if (f2 > 1)\n                f2 = 1;\n\n            *H2 = (ULONG)(f2 * (DrawInfo->Height - 1));\n        }\n        else\n        {\n            *H2 = *H1;\n        }\n    }\n    else\n    {\n        *H1 = 0;\n        *H2 = 0;\n    }\n}\n\n/**\n * Draws a graph directly to memory.\n *\n * \\param hdc The DC to draw to. This is only used when drawing text.\n * \\param Bits The bits in a bitmap.\n * \\param DrawInfo A structure which contains graphing information.\n *\n * \\remarks The following information is fixed:\n * \\li The graph is fixed to the origin (0, 0).\n * \\li The total size of the bitmap is assumed to be \\a Width and \\a Height in \\a DrawInfo.\n * \\li \\a Step is fixed at 2.\n * \\li If \\ref PH_GRAPH_USE_LINE_2 is specified in \\a Flags, \\ref PH_GRAPH_OVERLAY_LINE_2 is never\n * used.\n */\nVOID PhDrawGraphDirect(\n    _In_ HDC hdc,\n    _In_ PVOID Bits,\n    _In_ PPH_GRAPH_DRAW_INFO DrawInfo\n    )\n{\n    PULONG bits = Bits;\n    LONG width = DrawInfo->Width;\n    LONG height = DrawInfo->Height;\n    LONG numberOfPixels = width * height;\n    ULONG flags = DrawInfo->Flags;\n    LONG i;\n    LONG x;\n\n    BOOLEAN intermediate = FALSE; // whether we are currently between two data positions\n    ULONG dataIndex = 0; // the data index of the current position\n    ULONG h1_i; // the line 1 height value to the left of the current position\n    ULONG h1_o; // the line 1 height value at the current position\n    ULONG h2_i; // the line 1 + line 2 height value to the left of the current position\n    ULONG h2_o; // the line 1 + line 2 height value at the current position\n    ULONG h1; // current pixel\n    ULONG h1_left; // current pixel\n    ULONG h2; // current pixel\n    ULONG h2_left; // current pixel\n\n    LONG mid;\n    LONG h1_low1;\n    LONG h1_high1;\n    LONG h1_low2;\n    LONG h1_high2;\n    LONG h2_low1;\n    LONG h2_high1;\n    LONG h2_low2;\n    LONG h2_high2;\n    LONG old_low2;\n    LONG old_high2;\n\n    ULONG lineColor1;\n    ULONG lineBackColor1;\n    ULONG lineColor2;\n    ULONG lineBackColor2;\n    FLOAT gridHeight;\n    LONG gridYThreshold;\n    ULONG gridYCounter;\n    ULONG gridColor;\n    FLOAT gridBase;\n    FLOAT gridLevel;\n\n    ULONG yLabelMax;\n    ULONG yLabelDataIndex;\n\n    lineColor1 = COLORREF_TO_BITS(DrawInfo->LineColor1);\n    lineBackColor1 = COLORREF_TO_BITS(DrawInfo->LineBackColor1);\n    lineColor2 = COLORREF_TO_BITS(DrawInfo->LineColor2);\n    lineBackColor2 = COLORREF_TO_BITS(DrawInfo->LineBackColor2);\n\n    if (DrawInfo->BackColor == 0)\n    {\n        memset(bits, 0, numberOfPixels * 4);\n    }\n    else\n    {\n        PhFillMemoryUlong(bits, COLORREF_TO_BITS(DrawInfo->BackColor), numberOfPixels);\n    }\n\n    x = width - 1;\n    h1_low2 = MAXLONG;\n    h1_high2 = 0;\n    h2_low2 = MAXLONG;\n    h2_high2 = 0;\n\n    PhpGetGraphPoint(DrawInfo, 0, &h1_i, &h2_i);\n\n    if (flags & (PH_GRAPH_USE_GRID_X | PH_GRAPH_USE_GRID_Y))\n    {\n        gridHeight = max(DrawInfo->GridHeight, 0);\n        gridLevel = gridHeight;\n        gridYThreshold = DrawInfo->GridYThreshold;\n        gridYCounter = DrawInfo->GridWidth - (DrawInfo->GridXOffset * DrawInfo->Step) % DrawInfo->GridWidth - 1;\n        gridColor = COLORREF_TO_BITS(DrawInfo->GridColor);\n    }\n\n    if ((flags & (PH_GRAPH_USE_GRID_Y | PH_GRAPH_LOGARITHMIC_GRID_Y)) == (PH_GRAPH_USE_GRID_Y | PH_GRAPH_LOGARITHMIC_GRID_Y))\n    {\n        // Pre-process to find the largest integer n such that GridHeight*GridBase^n < 1.\n\n        gridBase = DrawInfo->GridBase;\n\n        if (gridBase > 1)\n        {\n            DOUBLE logBase;\n            DOUBLE exponent;\n            DOUBLE high;\n\n            logBase = log(gridBase);\n            exponent = ceil(-log(gridHeight) / logBase) - 1; // Works for both GridHeight > 1 and GridHeight < 1\n            high = exp(exponent * logBase);\n            gridLevel = (FLOAT)(gridHeight * high);\n\n            if (gridLevel < 0 || !isfinite(gridLevel))\n                gridLevel = 0;\n            if (gridLevel > 1)\n                gridLevel = 1;\n        }\n        else\n        {\n            // This is an error.\n            gridLevel = 0;\n        }\n    }\n\n    if (flags & PH_GRAPH_LABEL_MAX_Y)\n    {\n        yLabelMax = h2_i;\n        yLabelDataIndex = 0;\n    }\n\n    while (x >= 0)\n    {\n        // Calculate the height of the graph at this point.\n\n        if (!intermediate)\n        {\n            h1_o = h1_i;\n            h2_o = h2_i;\n\n            // Pull in new data.\n            dataIndex++;\n            PhpGetGraphPoint(DrawInfo, dataIndex, &h1_i, &h2_i);\n\n            h1 = h1_o;\n            h1_left = (h1_i + h1_o) / 2;\n            h2 = h2_o;\n            h2_left = (h2_i + h2_o) / 2;\n\n            if ((flags & PH_GRAPH_LABEL_MAX_Y) && dataIndex < DrawInfo->LabelMaxYIndexLimit)\n            {\n                if (yLabelMax <= h2_i)\n                {\n                    yLabelMax = h2_i;\n                    yLabelDataIndex = dataIndex;\n                }\n            }\n        }\n        else\n        {\n            h1 = h1_left;\n            h1_left = h1_i;\n            h2 = h2_left;\n            h2_left = h2_i;\n        }\n\n        // The graph is drawn right-to-left. There is one iteration of the loop per horizontal pixel.\n        // There is a fixed step value of 2, so every other iteration is a mid-point (intermediate)\n        // iteration with a height value of (left + right) / 2. In order to rasterize the outline,\n        // effectively in each iteration half of the line is drawn at the current column and the other\n        // half is drawn in the column to the left.\n\n        // Rasterize the data outline.\n        // h?_low2 to h?_high2 is the vertical line to the left of the current pixel.\n        // h?_low1 to h?_high1 is the vertical line at the current pixel.\n        // We merge (union) the old h?_low2 to h?_high2 line with the current line in each iteration.\n        //\n        // For example:\n        //\n        // X represents a data point. M represents the mid-point between two data points (\"intermediate\").\n        // X, M and x are all part of the outline. # represents the background filled in during\n        // the current loop iteration.\n        //\n        // slope > 0:                                     slope < 0:\n        //\n        //     X  < high1                                   X    < high2 (of next loop iteration)\n        //     x                                            x\n        //     x  < low1                                    x    < low2 (of next loop iteration)\n        //    x#  < high2                                    x   < high1 (of next loop iteration)\n        //    M#  < low2                                     M   < low1 (of next loop iteration)\n        //    x#  < high1 (of next loop iteration)           x   < high2\n        //    x#  < low1 (of next loop iteration)            x   < low2\n        //   x #  < high2 (of next loop iteration)            x  < high1\n        //   x #                                              x\n        //   X #  < low2 (of next loop iteration)             X  < low1\n        //     #                                              #\n        //     ^                                              ^\n        //    ^| current pixel                               ^| current pixel\n        //    |                                              |\n        //    | left of current pixel                        | left of current pixel\n        //\n        // In both examples above, the line low2-high2 will be merged with the line low1-high1 of\n        // the next iteration.\n\n        mid = ((h1_left + h1) / 2) * width;\n        old_low2 = h1_low2;\n        old_high2 = h1_high2;\n\n        if (h1_left < h1) // slope > 0\n        {\n            h1_low2 = h1_left * width;\n            h1_high2 = mid;\n            h1_low1 = mid + width;\n            h1_high1 = h1 * width;\n        }\n        else // slope < 0\n        {\n            h1_high2 = h1_left * width;\n            h1_low2 = mid + width;\n            h1_high1 = mid;\n            h1_low1 = h1 * width;\n        }\n\n        // Merge the lines.\n        if (h1_low1 > old_low2)\n            h1_low1 = old_low2;\n        if (h1_high1 < old_high2)\n            h1_high1 = old_high2;\n\n        // Fix up values for the current horizontal offset.\n        h1_low1 += x;\n        h1_high1 += x;\n\n        if (flags & PH_GRAPH_USE_LINE_2)\n        {\n            mid = ((h2_left + h2) / 2) * width;\n            old_low2 = h2_low2;\n            old_high2 = h2_high2;\n\n            if (h2_left < h2) // slope > 0\n            {\n                h2_low2 = h2_left * width;\n                h2_high2 = mid;\n                h2_low1 = mid + width;\n                h2_high1 = h2 * width;\n            }\n            else // slope < 0\n            {\n                h2_high2 = h2_left * width;\n                h2_low2 = mid + width;\n                h2_high1 = mid;\n                h2_low1 = h2 * width;\n            }\n\n            // Merge the lines.\n            if (h2_low1 > old_low2)\n                h2_low1 = old_low2;\n            if (h2_high1 < old_high2)\n                h2_high1 = old_high2;\n\n            // Fix up values for the current horizontal offset.\n            h2_low1 += x;\n            h2_high1 += x;\n        }\n\n        // Fill in the background.\n\n        if (flags & PH_GRAPH_USE_LINE_2)\n        {\n            for (i = h1_high1 + width; i < h2_low1; i += width)\n            {\n                bits[i] = lineBackColor2;\n            }\n        }\n\n        for (i = x; i < h1_low1; i += width)\n        {\n            bits[i] = lineBackColor1;\n        }\n\n        // Draw the grid.\n\n        if (flags & PH_GRAPH_USE_GRID_X)\n        {\n            // Draw the vertical grid line.\n            if (gridYCounter == 0)\n            {\n                for (i = x; i < numberOfPixels; i += width)\n                {\n                    bits[i] = gridColor;\n                }\n            }\n\n            gridYCounter++;\n\n            if (gridYCounter == DrawInfo->GridWidth)\n                gridYCounter = 0;\n        }\n\n        if (flags & PH_GRAPH_USE_GRID_Y)\n        {\n            FLOAT level;\n            LONG h;\n            LONG h_last;\n\n            // Draw the horizontal grid line.\n            if (flags & PH_GRAPH_LOGARITHMIC_GRID_Y)\n            {\n                level = gridLevel;\n                h = (LONG)(level * (height - 1));\n                h_last = height + gridYThreshold - 1;\n\n                while (TRUE)\n                {\n                    if (h <= h_last - gridYThreshold)\n                    {\n                        bits[x + h * width] = gridColor;\n                        h_last = h;\n                    }\n                    else\n                    {\n                        break;\n                    }\n\n                    level /= gridBase;\n                    h = (LONG)(level * (height - 1));\n                }\n            }\n            else\n            {\n                level = gridHeight;\n                h = (LONG)(level * (height - 1));\n                h_last = 0;\n\n                while (h < height - 1)\n                {\n                    if (h >= h_last + gridYThreshold)\n                    {\n                        bits[x + h * width] = gridColor;\n                        h_last = h;\n                    }\n\n                    level += gridHeight;\n                    h = (LONG)(level * (height - 1));\n                }\n            }\n        }\n\n        // Draw the outline (line 1 is allowed to paint over line 2).\n\n        if (flags & PH_GRAPH_USE_LINE_2)\n        {\n            for (i = h2_low1; i <= h2_high1; i += width) // exclude pixel in the middle\n            {\n                bits[i] = lineColor2;\n            }\n        }\n\n        for (i = h1_low1; i <= h1_high1; i += width)\n        {\n            bits[i] = lineColor1;\n        }\n\n        intermediate = !intermediate;\n        x--;\n    }\n\n    if ((flags & PH_GRAPH_LABEL_MAX_Y) && yLabelDataIndex < DrawInfo->LineDataCount)\n    {\n        FLOAT value;\n        PPH_STRING label;\n\n        value = DrawInfo->LineData1[yLabelDataIndex];\n\n        if (flags & PH_GRAPH_USE_LINE_2)\n            value += DrawInfo->LineData2[yLabelDataIndex];\n\n        if (label = DrawInfo->LabelYFunction(DrawInfo, yLabelDataIndex, value, DrawInfo->LabelYFunctionParameter))\n        {\n            HFONT oldFont = NULL;\n            SIZE textSize;\n            RECT rect;\n\n            if (DrawInfo->LabelYFont)\n                oldFont = SelectObject(hdc, DrawInfo->LabelYFont);\n\n            SetTextColor(hdc, DrawInfo->LabelYColor);\n            SetBkMode(hdc, TRANSPARENT);\n\n            GetTextExtentPoint32(hdc, label->Buffer, (ULONG)label->Length / 2, &textSize);\n\n            rect.bottom = height - yLabelMax - PhNormalGraphTextPadding.top;\n            rect.top = rect.bottom - textSize.cy;\n\n            if (rect.top < PhNormalGraphTextPadding.top)\n            {\n                rect.top = PhNormalGraphTextPadding.top;\n                rect.bottom = rect.top + textSize.cy;\n            }\n\n            rect.left = 0;\n            rect.right = width - min((LONG)yLabelDataIndex * 2, width) - PhNormalGraphTextPadding.right;\n            DrawText(hdc, label->Buffer, (ULONG)label->Length / 2, &rect, DT_NOCLIP | DT_RIGHT);\n\n            if (oldFont)\n                SelectObject(hdc, oldFont);\n\n            PhDereferenceObject(label);\n        }\n    }\n\n    if (DrawInfo->Text.Buffer)\n    {\n        HFONT oldFont = NULL;\n\n        if (DrawInfo->TextFont)\n            oldFont = SelectObject(hdc, DrawInfo->TextFont);\n\n        // Fill in the text box.\n        SetDCBrushColor(hdc, DrawInfo->TextBoxColor);\n        FillRect(hdc, &DrawInfo->TextBoxRect, GetStockObject(DC_BRUSH));\n\n        // Draw the text.\n        SetTextColor(hdc, DrawInfo->TextColor);\n        SetBkMode(hdc, TRANSPARENT);\n        DrawText(hdc, DrawInfo->Text.Buffer, (ULONG)DrawInfo->Text.Length / 2, &DrawInfo->TextRect, DT_NOCLIP);\n\n        if (oldFont)\n            SelectObject(hdc, oldFont);\n    }\n}\n\n/**\n * Sets the text in a graphing information structure.\n *\n * \\param hdc The DC to perform calculations from.\n * \\param DrawInfo A structure which contains graphing information. The structure is modified to\n * contain the new text information.\n * \\param Text The text.\n * \\param Margin The margins of the text box from the edges of the graph.\n * \\param Padding The padding within the text box.\n * \\param Align The alignment of the text box.\n */\nVOID PhSetGraphText(\n    _In_ HDC hdc,\n    _Inout_ PPH_GRAPH_DRAW_INFO DrawInfo,\n    _In_ PPH_STRINGREF Text,\n    _In_ PRECT Margin,\n    _In_ PRECT Padding,\n    _In_ ULONG Align\n    )\n{\n    HFONT oldFont = NULL;\n    SIZE textSize;\n    PH_RECTANGLE boxRectangle;\n    PH_RECTANGLE textRectangle;\n\n    if (DrawInfo->TextFont)\n        oldFont = SelectObject(hdc, DrawInfo->TextFont);\n\n    DrawInfo->Text = *Text;\n    GetTextExtentPoint32(hdc, Text->Buffer, (ULONG)Text->Length / 2, &textSize);\n\n    if (oldFont)\n        SelectObject(hdc, oldFont);\n\n    // Calculate the box rectangle.\n\n    boxRectangle.Width = textSize.cx + Padding->left + Padding->right;\n    boxRectangle.Height = textSize.cy + Padding->top + Padding->bottom;\n\n    if (Align & PH_ALIGN_LEFT)\n        boxRectangle.Left = Margin->left;\n    else if (Align & PH_ALIGN_RIGHT)\n        boxRectangle.Left = DrawInfo->Width - boxRectangle.Width - Margin->right;\n    else\n        boxRectangle.Left = (DrawInfo->Width - boxRectangle.Width) / 2;\n\n    if (Align & PH_ALIGN_TOP)\n        boxRectangle.Top = Margin->top;\n    else if (Align & PH_ALIGN_BOTTOM)\n        boxRectangle.Top = DrawInfo->Height - boxRectangle.Height - Margin->bottom;\n    else\n        boxRectangle.Top = (DrawInfo->Height - boxRectangle.Height) / 2;\n\n    // Calculate the text rectangle.\n\n    textRectangle.Left = boxRectangle.Left + Padding->left;\n    textRectangle.Top = boxRectangle.Top + Padding->top;\n    textRectangle.Width = textSize.cx;\n    textRectangle.Height = textSize.cy;\n\n    // Save the rectangles.\n    DrawInfo->TextRect = PhRectangleToRect(textRectangle);\n    DrawInfo->TextBoxRect = PhRectangleToRect(boxRectangle);\n}\n\n\nstatic HFONT PhpTrayIconFont(\n    VOID\n    )\n{\n    static HFONT iconTextFont = NULL;\n\n    if (!iconTextFont)\n    {\n        iconTextFont = CreateFont(\n            PhMultiplyDivideSigned(-11, PhGlobalDpi, 96),\n            0,\n            0,\n            0,\n            FW_NORMAL,\n            FALSE,\n            FALSE,\n            FALSE,\n            ANSI_CHARSET,\n            OUT_DEFAULT_PRECIS,\n            CLIP_DEFAULT_PRECIS,\n            ANTIALIASED_QUALITY,\n            DEFAULT_PITCH,\n            L\"Tahoma\"\n            );\n    }\n\n    return iconTextFont;\n}\n\nVOID PhDrawTrayIconText(\n    _In_ HDC hdc,\n    _In_ PVOID Bits,\n    _Inout_ PPH_GRAPH_DRAW_INFO DrawInfo,\n    _In_ PPH_STRINGREF Text\n    )\n{\n    PULONG bits = Bits;\n    LONG width = DrawInfo->Width;\n    LONG height = DrawInfo->Height;\n    LONG numberOfPixels = width * height;\n    ULONG flags = DrawInfo->Flags;\n    HFONT oldFont = NULL;\n    SIZE textSize;\n    PH_RECTANGLE boxRectangle;\n    PH_RECTANGLE textRectangle;\n\n    if (DrawInfo->BackColor == 0)\n    {\n        memset(bits, 0, numberOfPixels * 4);\n    }\n    else\n    {\n        PhFillMemoryUlong(bits, COLORREF_TO_BITS(DrawInfo->BackColor), numberOfPixels);\n    }\n\n    if (!DrawInfo->TextFont) // HACK: default font for plugins.\n        DrawInfo->TextFont = PhpTrayIconFont();\n\n    if (DrawInfo->TextFont)\n        oldFont = SelectObject(hdc, DrawInfo->TextFont);\n\n    DrawInfo->Text = *Text;\n    GetTextExtentPoint32(hdc, Text->Buffer, (ULONG)Text->Length / 2, &textSize);\n\n    // Calculate the box rectangle.\n\n    boxRectangle.Width = textSize.cx;\n    boxRectangle.Height = textSize.cy;\n    boxRectangle.Left = (DrawInfo->Width - boxRectangle.Width) / 2;\n    boxRectangle.Top = (DrawInfo->Height - boxRectangle.Height) / 2;\n\n    // Calculate the text rectangle.\n\n    textRectangle.Left = boxRectangle.Left;\n    textRectangle.Top = boxRectangle.Top;\n    textRectangle.Width = textSize.cx;\n    textRectangle.Height = textSize.cy;\n\n    // Save the rectangles.\n    DrawInfo->TextRect = PhRectangleToRect(textRectangle);\n    DrawInfo->TextBoxRect = PhRectangleToRect(boxRectangle);\n\n    // Fill in the text box.\n    //SetDCBrushColor(hdc, DrawInfo->TextBoxColor);\n    //FillRect(hdc, &DrawInfo->TextBoxRect, GetStockObject(DC_BRUSH));\n\n    // Draw the text.\n    SetTextColor(hdc, DrawInfo->TextColor);\n    SetBkMode(hdc, TRANSPARENT);\n\n    DrawText(hdc, DrawInfo->Text.Buffer, (ULONG)DrawInfo->Text.Length / 2, &DrawInfo->TextRect, DT_NOCLIP | DT_SINGLELINE);\n\n    if (oldFont)\n        SelectObject(hdc, oldFont);\n}\n\nVOID PhpCreateGraphContext(\n    _Out_ PPHP_GRAPH_CONTEXT *Context\n    )\n{\n    PPHP_GRAPH_CONTEXT context;\n\n    context = PhAllocate(sizeof(PHP_GRAPH_CONTEXT));\n    memset(context, 0, sizeof(PHP_GRAPH_CONTEXT));\n\n    context->DrawInfo.Width = 3;\n    context->DrawInfo.Height = 3;\n    context->DrawInfo.Flags = PH_GRAPH_USE_GRID_X;\n    context->DrawInfo.Step = 2;\n    context->DrawInfo.BackColor = RGB(0xef, 0xef, 0xef);\n    context->DrawInfo.LineDataCount = 0;\n    context->DrawInfo.LineData1 = NULL;\n    context->DrawInfo.LineData2 = NULL;\n    context->DrawInfo.LineColor1 = RGB(0x00, 0xff, 0x00);\n    context->DrawInfo.LineColor2 = RGB(0xff, 0x00, 0x00);\n    context->DrawInfo.LineBackColor1 = RGB(0x00, 0x77, 0x00);\n    context->DrawInfo.LineBackColor2 = RGB(0x77, 0x00, 0x00);\n    context->DrawInfo.GridColor = RGB(0xc7, 0xc7, 0xc7);\n    context->DrawInfo.GridWidth = 20;\n    context->DrawInfo.GridHeight = 0.25f;\n    context->DrawInfo.GridXOffset = 0;\n    context->DrawInfo.GridYThreshold = 10;\n    context->DrawInfo.GridBase = 2.0f;\n    context->DrawInfo.LabelYColor = RGB(0x77, 0x77, 0x77);\n    context->DrawInfo.LabelMaxYIndexLimit = -1;\n    context->DrawInfo.TextColor = RGB(0x00, 0xff, 0x00);\n    context->DrawInfo.TextBoxColor = RGB(0x00, 0x22, 0x00);\n\n    context->Options.FadeOutBackColor = RGB(0xef, 0xef, 0xef);\n    context->Options.FadeOutWidth = 100;\n\n    *Context = context;\n}\n\nVOID PhpFreeGraphContext(\n    _Inout_ _Post_invalid_ PPHP_GRAPH_CONTEXT Context\n    )\n{\n    PhFree(Context);\n}\n\nstatic PWSTR PhpMakeGraphTooltipContextAtom(\n    VOID\n    )\n{\n    PH_DEFINE_MAKE_ATOM(L\"PhLib_GraphTooltipContext\");\n}\n\nstatic VOID PhpDeleteBufferedContext(\n    _In_ PPHP_GRAPH_CONTEXT Context\n    )\n{\n    if (Context->BufferedContext)\n    {\n        // The original bitmap must be selected back into the context, otherwise the bitmap can't be\n        // deleted.\n        SelectObject(Context->BufferedContext, Context->BufferedOldBitmap);\n        DeleteObject(Context->BufferedBitmap);\n        DeleteDC(Context->BufferedContext);\n\n        Context->BufferedContext = NULL;\n        Context->BufferedBitmap = NULL;\n        Context->BufferedBits = NULL;\n    }\n}\n\nstatic VOID PhpCreateBufferedContext(\n    _In_ PPHP_GRAPH_CONTEXT Context\n    )\n{\n    HDC hdc;\n    BITMAPINFOHEADER header;\n\n    PhpDeleteBufferedContext(Context);\n\n    GetClientRect(Context->Handle, &Context->BufferedContextRect);\n\n    hdc = GetDC(Context->Handle);\n    Context->BufferedContext = CreateCompatibleDC(hdc);\n\n    memset(&header, 0, sizeof(BITMAPINFOHEADER));\n    header.biSize = sizeof(BITMAPINFOHEADER);\n    header.biWidth = Context->BufferedContextRect.right;\n    header.biHeight = Context->BufferedContextRect.bottom;\n    header.biPlanes = 1;\n    header.biBitCount = 32;\n\n    Context->BufferedBitmap = CreateDIBSection(hdc, (BITMAPINFO *)&header, DIB_RGB_COLORS, &Context->BufferedBits, NULL, 0);\n\n    ReleaseDC(Context->Handle, hdc);\n    Context->BufferedOldBitmap = SelectObject(Context->BufferedContext, Context->BufferedBitmap);\n}\n\nstatic VOID PhpDeleteFadeOutContext(\n    _In_ PPHP_GRAPH_CONTEXT Context\n    )\n{\n    if (Context->FadeOutContext)\n    {\n        SelectObject(Context->FadeOutContext, Context->FadeOutOldBitmap);\n        DeleteObject(Context->FadeOutBitmap);\n        DeleteDC(Context->FadeOutContext);\n\n        Context->FadeOutContext = NULL;\n        Context->FadeOutBitmap = NULL;\n        Context->FadeOutBits = NULL;\n    }\n}\n\nstatic VOID PhpCreateFadeOutContext(\n    _In_ PPHP_GRAPH_CONTEXT Context\n    )\n{\n    HDC hdc;\n    BITMAPINFOHEADER header;\n    ULONG i;\n    ULONG j;\n    ULONG height;\n    COLORREF backColor;\n    ULONG fadeOutWidth;\n    FLOAT fadeOutWidthSquared;\n    ULONG currentAlpha;\n    ULONG currentColor;\n\n    PhpDeleteFadeOutContext(Context);\n\n    GetClientRect(Context->Handle, &Context->FadeOutContextRect);\n    Context->FadeOutContextRect.right = Context->Options.FadeOutWidth;\n\n    hdc = GetDC(Context->Handle);\n    Context->FadeOutContext = CreateCompatibleDC(hdc);\n\n    memset(&header, 0, sizeof(BITMAPINFOHEADER));\n    header.biSize = sizeof(BITMAPINFOHEADER);\n    header.biWidth = Context->FadeOutContextRect.right;\n    header.biHeight = Context->FadeOutContextRect.bottom;\n    header.biPlanes = 1;\n    header.biBitCount = 32;\n\n    Context->FadeOutBitmap = CreateDIBSection(hdc, (BITMAPINFO *)&header, DIB_RGB_COLORS, &Context->FadeOutBits, NULL, 0);\n\n    ReleaseDC(Context->Handle, hdc);\n    Context->FadeOutOldBitmap = SelectObject(Context->FadeOutContext, Context->FadeOutBitmap);\n\n    if (!Context->FadeOutBits)\n        return;\n\n    height = Context->FadeOutContextRect.bottom;\n    backColor = Context->Options.FadeOutBackColor;\n    fadeOutWidth = Context->Options.FadeOutWidth;\n    fadeOutWidthSquared = (FLOAT)fadeOutWidth * fadeOutWidth;\n\n    for (i = 0; i < fadeOutWidth; i++)\n    {\n        currentAlpha = 255 - (ULONG)((FLOAT)(i * i) / fadeOutWidthSquared * 255);\n        currentColor =\n            ((backColor & 0xff) * currentAlpha / 255) +\n            ((((backColor >> 8) & 0xff) * currentAlpha / 255) << 8) +\n            ((((backColor >> 16) & 0xff) * currentAlpha / 255) << 16) +\n            (currentAlpha << 24);\n\n        for (j = i; j < height * fadeOutWidth; j += fadeOutWidth)\n        {\n            ((PULONG)Context->FadeOutBits)[j] = currentColor;\n        }\n    }\n}\n\nVOID PhpUpdateDrawInfo(\n    _In_ HWND hwnd,\n    _In_ PPHP_GRAPH_CONTEXT Context\n    )\n{\n    PH_GRAPH_GETDRAWINFO getDrawInfo;\n\n    Context->DrawInfo.Width = Context->BufferedContextRect.right;\n    Context->DrawInfo.Height = Context->BufferedContextRect.bottom;\n\n    getDrawInfo.Header.hwndFrom = hwnd;\n    getDrawInfo.Header.idFrom = Context->Id;\n    getDrawInfo.Header.code = GCN_GETDRAWINFO;\n    getDrawInfo.DrawInfo = &Context->DrawInfo;\n\n    SendMessage(GetParent(hwnd), WM_NOTIFY, 0, (LPARAM)&getDrawInfo);\n}\n\nVOID PhpDrawGraphControl(\n    _In_ HWND hwnd,\n    _In_ PPHP_GRAPH_CONTEXT Context\n    )\n{\n    if (Context->BufferedBits)\n        PhDrawGraphDirect(Context->BufferedContext, Context->BufferedBits, &Context->DrawInfo);\n\n    if (Context->Style & GC_STYLE_FADEOUT)\n    {\n        BLENDFUNCTION blendFunction;\n\n        if (!Context->FadeOutContext)\n            PhpCreateFadeOutContext(Context);\n\n        blendFunction.BlendOp = AC_SRC_OVER;\n        blendFunction.BlendFlags = 0;\n        blendFunction.SourceConstantAlpha = 255;\n        blendFunction.AlphaFormat = AC_SRC_ALPHA;\n        GdiAlphaBlend(\n            Context->BufferedContext,\n            0,\n            0,\n            Context->Options.FadeOutWidth,\n            Context->FadeOutContextRect.bottom,\n            Context->FadeOutContext,\n            0,\n            0,\n            Context->Options.FadeOutWidth,\n            Context->FadeOutContextRect.bottom,\n            blendFunction\n            );\n    }\n\n    if (Context->Style & GC_STYLE_DRAW_PANEL)\n    {\n        PH_GRAPH_DRAWPANEL drawPanel;\n\n        drawPanel.Header.hwndFrom = hwnd;\n        drawPanel.Header.idFrom = Context->Id;\n        drawPanel.Header.code = GCN_DRAWPANEL;\n        drawPanel.hdc = Context->BufferedContext;\n        drawPanel.Rect = Context->BufferedContextRect;\n\n        SendMessage(GetParent(hwnd), WM_NOTIFY, 0, (LPARAM)&drawPanel);\n    }\n}\n\nLRESULT CALLBACK PhpGraphWndProc(\n    _In_ HWND hwnd,\n    _In_ UINT uMsg,\n    _In_ WPARAM wParam,\n    _In_ LPARAM lParam\n    )\n{\n    PPHP_GRAPH_CONTEXT context;\n\n    context = (PPHP_GRAPH_CONTEXT)GetWindowLongPtr(hwnd, 0);\n\n    if (uMsg == WM_CREATE)\n    {\n        PhpCreateGraphContext(&context);\n        SetWindowLongPtr(hwnd, 0, (LONG_PTR)context);\n    }\n\n    if (!context)\n        return DefWindowProc(hwnd, uMsg, wParam, lParam);\n\n    switch (uMsg)\n    {\n    case WM_MOUSEMOVE:\n    case WM_LBUTTONDOWN:\n    case WM_LBUTTONUP:\n    case WM_RBUTTONDOWN:\n    case WM_RBUTTONUP:\n    case WM_MBUTTONDOWN:\n    case WM_MBUTTONUP:\n        {\n            if (context->TooltipHandle)\n            {\n                MSG message;\n\n                message.hwnd = hwnd;\n                message.message = uMsg;\n                message.wParam = wParam;\n                message.lParam = lParam;\n                SendMessage(context->TooltipHandle, TTM_RELAYEVENT, 0, (LPARAM)&message);\n            }\n        }\n        break;\n    }\n\n    switch (uMsg)\n    {\n    case WM_CREATE:\n        {\n            CREATESTRUCT *createStruct = (CREATESTRUCT *)lParam;\n\n            context->Handle = hwnd;\n            context->Style = createStruct->style;\n            context->Id = (ULONG_PTR)createStruct->hMenu;\n        }\n        break;\n    case WM_DESTROY:\n        {\n            SetWindowLongPtr(hwnd, 0, (LONG_PTR)NULL);\n\n            if (context->TooltipHandle)\n                DestroyWindow(context->TooltipHandle);\n\n            PhpDeleteFadeOutContext(context);\n            PhpDeleteBufferedContext(context);\n            PhpFreeGraphContext(context);\n        }\n        break;\n    case WM_STYLECHANGED:\n        {\n            STYLESTRUCT *styleStruct = (STYLESTRUCT *)lParam;\n\n            if (wParam == GWL_STYLE)\n            {\n                context->Style = styleStruct->styleNew;\n                context->NeedsDraw = TRUE;\n            }\n        }\n        break;\n    case WM_SIZE:\n        {\n            // Force a re-create of the buffered context.\n            PhpCreateBufferedContext(context);\n            PhpDeleteFadeOutContext(context);\n\n            PhpUpdateDrawInfo(hwnd, context);\n            context->NeedsDraw = TRUE;\n            InvalidateRect(hwnd, NULL, FALSE);\n\n            if (context->TooltipHandle)\n            {\n                TOOLINFO toolInfo;\n\n                memset(&toolInfo, 0, sizeof(TOOLINFO));\n                toolInfo.cbSize = sizeof(TOOLINFO);\n                toolInfo.hwnd = hwnd;\n                toolInfo.uId = 1;\n                GetClientRect(hwnd, &toolInfo.rect);\n                SendMessage(context->TooltipHandle, TTM_NEWTOOLRECT, 0, (LPARAM)&toolInfo);\n            }\n        }\n        break;\n    case WM_PAINT:\n        {\n            PAINTSTRUCT paintStruct;\n            HDC hdc;\n\n            if (hdc = BeginPaint(hwnd, &paintStruct))\n            {\n                if (!context->BufferedContext)\n                    PhpCreateBufferedContext(context);\n\n                if (context->NeedsUpdate)\n                {\n                    PhpUpdateDrawInfo(hwnd, context);\n                    context->NeedsUpdate = FALSE;\n                }\n\n                if (context->NeedsDraw)\n                {\n                    PhpDrawGraphControl(hwnd, context);\n                    context->NeedsDraw = FALSE;\n                }\n\n                BitBlt(\n                    hdc,\n                    paintStruct.rcPaint.left,\n                    paintStruct.rcPaint.top,\n                    paintStruct.rcPaint.right - paintStruct.rcPaint.left,\n                    paintStruct.rcPaint.bottom - paintStruct.rcPaint.top,\n                    context->BufferedContext,\n                    paintStruct.rcPaint.left,\n                    paintStruct.rcPaint.top,\n                    SRCCOPY\n                    );\n\n                EndPaint(hwnd, &paintStruct);\n            }\n        }\n        return 0;\n    case WM_ERASEBKGND:\n        return 1;\n    case WM_NCPAINT:\n        {\n            HRGN updateRegion;\n\n            updateRegion = (HRGN)wParam;\n\n            if (updateRegion == (HRGN)1) // HRGN_FULL\n                updateRegion = NULL;\n\n            // Themed border\n            if (context->Style & WS_BORDER)\n            {\n                HDC hdc;\n                ULONG flags;\n                RECT rect;\n\n                // Note the use of undocumented flags below. GetDCEx doesn't work without these.\n\n                flags = DCX_WINDOW | DCX_LOCKWINDOWUPDATE | 0x10000;\n\n                if (updateRegion)\n                    flags |= DCX_INTERSECTRGN | 0x40000;\n\n                if (hdc = GetDCEx(hwnd, updateRegion, flags))\n                {\n                    GetClientRect(hwnd, &rect);\n                    rect.right += 2;\n                    rect.bottom += 2;\n                    SetDCBrushColor(hdc, RGB(0x8f, 0x8f, 0x8f));\n                    FrameRect(hdc, &rect, GetStockObject(DC_BRUSH));\n\n                    ReleaseDC(hwnd, hdc);\n                    return 0;\n                }\n            }\n        }\n        break;\n    case WM_NOTIFY:\n        {\n            LPNMHDR header = (LPNMHDR)lParam;\n\n            if (header->hwndFrom == context->TooltipHandle)\n            {\n                switch (header->code)\n                {\n                case TTN_GETDISPINFO:\n                    {\n                        LPNMTTDISPINFO dispInfo = (LPNMTTDISPINFO)header;\n                        POINT point;\n                        RECT clientRect;\n                        PH_GRAPH_GETTOOLTIPTEXT getTooltipText;\n\n                        GetCursorPos(&point);\n                        ScreenToClient(hwnd, &point);\n                        GetClientRect(hwnd, &clientRect);\n\n                        getTooltipText.Header.hwndFrom = hwnd;\n                        getTooltipText.Header.idFrom = context->Id;\n                        getTooltipText.Header.code = GCN_GETTOOLTIPTEXT;\n                        getTooltipText.Index = (clientRect.right - point.x - 1) / context->DrawInfo.Step;\n                        getTooltipText.TotalCount = context->DrawInfo.LineDataCount;\n                        getTooltipText.Text.Buffer = NULL;\n                        getTooltipText.Text.Length = 0;\n\n                        SendMessage(GetParent(hwnd), WM_NOTIFY, 0, (LPARAM)&getTooltipText);\n\n                        if (getTooltipText.Text.Buffer)\n                        {\n                            dispInfo->lpszText = getTooltipText.Text.Buffer;\n                        }\n                    }\n                    break;\n                }\n            }\n        }\n        break;\n    case WM_SETCURSOR:\n        {\n            if (context->Options.DefaultCursor)\n            {\n                SetCursor(context->Options.DefaultCursor);\n                return TRUE;\n            }\n        }\n        break;\n    case WM_MOUSEMOVE:\n        {\n            if (context->TooltipHandle)\n            {\n                POINT point;\n\n                GetCursorPos(&point);\n                ScreenToClient(hwnd, &point);\n\n                if (context->LastCursorLocation.x != point.x || context->LastCursorLocation.y != point.y)\n                {\n                    SendMessage(context->TooltipHandle, TTM_UPDATE, 0, 0);\n                    context->LastCursorLocation = point;\n                }\n            }\n        }\n        break;\n    case WM_LBUTTONDOWN:\n    case WM_LBUTTONUP:\n    case WM_LBUTTONDBLCLK:\n    case WM_RBUTTONDOWN:\n    case WM_RBUTTONUP:\n    case WM_RBUTTONDBLCLK:\n        {\n            PH_GRAPH_MOUSEEVENT mouseEvent;\n            RECT clientRect;\n\n            GetClientRect(hwnd, &clientRect);\n\n            mouseEvent.Header.hwndFrom = hwnd;\n            mouseEvent.Header.idFrom = context->Id;\n            mouseEvent.Header.code = GCN_MOUSEEVENT;\n            mouseEvent.Message = uMsg;\n            mouseEvent.Keys = (ULONG)wParam;\n            mouseEvent.Point.x = GET_X_LPARAM(lParam);\n            mouseEvent.Point.y = GET_Y_LPARAM(lParam);\n\n            mouseEvent.Index = (clientRect.right - mouseEvent.Point.x - 1) / context->DrawInfo.Step;\n            mouseEvent.TotalCount = context->DrawInfo.LineDataCount;\n\n            SendMessage(GetParent(hwnd), WM_NOTIFY, 0, (LPARAM)&mouseEvent);\n        }\n        break;\n    case GCM_GETDRAWINFO:\n        {\n            PPH_GRAPH_DRAW_INFO drawInfo = (PPH_GRAPH_DRAW_INFO)lParam;\n\n            memcpy(drawInfo, &context->DrawInfo, sizeof(PH_GRAPH_DRAW_INFO));\n        }\n        return TRUE;\n    case GCM_SETDRAWINFO:\n        {\n            PPH_GRAPH_DRAW_INFO drawInfo = (PPH_GRAPH_DRAW_INFO)lParam;\n            ULONG width;\n            ULONG height;\n\n            width = context->DrawInfo.Width;\n            height = context->DrawInfo.Height;\n            memcpy(&context->DrawInfo, drawInfo, sizeof(PH_GRAPH_DRAW_INFO));\n            context->DrawInfo.Width = width;\n            context->DrawInfo.Height = height;\n        }\n        return TRUE;\n    case GCM_DRAW:\n        {\n            PhpUpdateDrawInfo(hwnd, context);\n            context->NeedsDraw = TRUE;\n        }\n        return TRUE;\n    case GCM_MOVEGRID:\n        {\n            LONG increment = (LONG)wParam;\n\n            context->DrawInfo.GridXOffset += increment;\n        }\n        return TRUE;\n    case GCM_GETBUFFEREDCONTEXT:\n        return (LRESULT)context->BufferedContext;\n    case GCM_SETTOOLTIP:\n        {\n            if (wParam)\n            {\n                TOOLINFO toolInfo = { sizeof(toolInfo) };\n\n                context->TooltipHandle = CreateWindow(\n                    TOOLTIPS_CLASS,\n                    NULL,\n                    WS_POPUP | WS_EX_TRANSPARENT | TTS_NOPREFIX | TTS_ALWAYSTIP,\n                    CW_USEDEFAULT,\n                    CW_USEDEFAULT,\n                    CW_USEDEFAULT,\n                    CW_USEDEFAULT,\n                    NULL,\n                    NULL,\n                    PhInstanceHandle,\n                    NULL\n                    );\n\n                SetWindowPos(context->TooltipHandle, HWND_TOPMOST, 0, 0, 0, 0,\n                    SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE);\n\n                toolInfo.uFlags = 0;\n                toolInfo.hwnd = hwnd;\n                toolInfo.uId = 1;\n                toolInfo.lpszText = LPSTR_TEXTCALLBACK;\n                GetClientRect(hwnd, &toolInfo.rect);\n                SendMessage(context->TooltipHandle, TTM_ADDTOOL, 0, (LPARAM)&toolInfo);\n\n                SendMessage(context->TooltipHandle, TTM_SETDELAYTIME, TTDT_INITIAL, 0);\n                SendMessage(context->TooltipHandle, TTM_SETDELAYTIME, TTDT_AUTOPOP, MAXSHORT);\n                // Allow newlines (-1 doesn't work)\n                SendMessage(context->TooltipHandle, TTM_SETMAXTIPWIDTH, 0, MAXSHORT);\n            }\n            else\n            {\n                DestroyWindow(context->TooltipHandle);\n                context->TooltipHandle = NULL;\n            }\n        }\n        return TRUE;\n    case GCM_UPDATETOOLTIP:\n        {\n            if (!context->TooltipHandle)\n                return FALSE;\n\n            SendMessage(context->TooltipHandle, TTM_UPDATE, 0, 0);\n        }\n        return TRUE;\n    case GCM_GETOPTIONS:\n        memcpy((PPH_GRAPH_OPTIONS)lParam, &context->Options, sizeof(PH_GRAPH_OPTIONS));\n        return TRUE;\n    case GCM_SETOPTIONS:\n        memcpy(&context->Options, (PPH_GRAPH_OPTIONS)lParam, sizeof(PH_GRAPH_OPTIONS));\n        PhpDeleteFadeOutContext(context);\n        return TRUE;\n    }\n\n    return DefWindowProc(hwnd, uMsg, wParam, lParam);\n}\n\n/**\n * Initializes a graph buffer management structure.\n *\n * \\param Buffers The buffer management structure.\n */\nVOID PhInitializeGraphBuffers(\n    _Out_ PPH_GRAPH_BUFFERS Buffers\n    )\n{\n    Buffers->AllocatedCount = 0;\n    Buffers->Data1 = NULL;\n    Buffers->Data2 = NULL;\n    Buffers->Valid = FALSE;\n}\n\n/**\n * Frees resources used by a graph buffer management structure.\n *\n * \\param Buffers The buffer management structure.\n */\nVOID PhDeleteGraphBuffers(\n    _Inout_ PPH_GRAPH_BUFFERS Buffers\n    )\n{\n    if (Buffers->Data1) PhFree(Buffers->Data1);\n    if (Buffers->Data2) PhFree(Buffers->Data2);\n}\n\n/**\n * Sets up a graphing information structure with information from a graph buffer management\n * structure.\n *\n * \\param Buffers The buffer management structure.\n * \\param DrawInfo The graphing information structure.\n * \\param DataCount The number of data points currently required. The buffers are resized if needed.\n */\nVOID PhGetDrawInfoGraphBuffers(\n    _Inout_ PPH_GRAPH_BUFFERS Buffers,\n    _Inout_ PPH_GRAPH_DRAW_INFO DrawInfo,\n    _In_ ULONG DataCount\n    )\n{\n    DrawInfo->LineDataCount = min(DataCount, PH_GRAPH_DATA_COUNT(DrawInfo->Width, DrawInfo->Step));\n\n    // Do we need to allocate or re-allocate the data buffers?\n    if (Buffers->AllocatedCount < DrawInfo->LineDataCount)\n    {\n        if (Buffers->Data1)\n            PhFree(Buffers->Data1);\n        if ((DrawInfo->Flags & PH_GRAPH_USE_LINE_2) && Buffers->Data2)\n            PhFree(Buffers->Data2);\n\n        Buffers->AllocatedCount *= 2;\n\n        if (Buffers->AllocatedCount < DrawInfo->LineDataCount)\n            Buffers->AllocatedCount = DrawInfo->LineDataCount;\n\n        Buffers->Data1 = PhAllocate(Buffers->AllocatedCount * sizeof(FLOAT));\n\n        if (DrawInfo->Flags & PH_GRAPH_USE_LINE_2)\n        {\n            Buffers->Data2 = PhAllocate(Buffers->AllocatedCount * sizeof(FLOAT));\n        }\n\n        Buffers->Valid = FALSE;\n    }\n\n    DrawInfo->LineData1 = Buffers->Data1;\n    DrawInfo->LineData2 = Buffers->Data2;\n}\n\nVOID PhInitializeGraphState(\n    _Out_ PPH_GRAPH_STATE State\n    )\n{\n    PhInitializeGraphBuffers(&State->Buffers);\n    State->Text = NULL;\n    State->TooltipText = NULL;\n    State->TooltipIndex = -1;\n}\n\nVOID PhDeleteGraphState(\n    _Inout_ PPH_GRAPH_STATE State\n    )\n{\n    PhDeleteGraphBuffers(&State->Buffers);\n    if (State->Text) PhDereferenceObject(State->Text);\n    if (State->TooltipText) PhDereferenceObject(State->TooltipText);\n}\n\nVOID PhGraphStateGetDrawInfo(\n    _Inout_ PPH_GRAPH_STATE State,\n    _In_ PPH_GRAPH_GETDRAWINFO GetDrawInfo,\n    _In_ ULONG DataCount\n    )\n{\n    PhGetDrawInfoGraphBuffers(&State->Buffers, GetDrawInfo->DrawInfo, DataCount);\n}\n"
  },
  {
    "path": "third_party/phlib/guisup.c",
    "content": "/*\n * Process Hacker -\n *   GUI support functions\n *\n * Copyright (C) 2009-2016 wj32\n *\n * This file is part of Process Hacker.\n *\n * Process Hacker is free software; you can redistribute it and/or modify\n * it under the terms of the GNU General Public License as published by\n * the Free Software Foundation, either version 3 of the License, or\n * (at your option) any later version.\n *\n * Process Hacker is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n * GNU General Public License for more details.\n *\n * You should have received a copy of the GNU General Public License\n * along with Process Hacker.  If not, see <http://www.gnu.org/licenses/>.\n */\n\n#include <ph.h>\n#include <guisup.h>\n\n#include <shellapi.h>\n#include <uxtheme.h>\n#include <windowsx.h>\n\n#include <guisupp.h>\n\n#define SCALE_DPI(Value) PhMultiplyDivide(Value, PhGlobalDpi, 96)\n\n_IsImmersiveProcess IsImmersiveProcess_I;\n_RunFileDlg RunFileDlg;\n_SHAutoComplete SHAutoComplete_I;\n\nstatic PH_INITONCE SharedIconCacheInitOnce = PH_INITONCE_INIT;\nstatic PPH_HASHTABLE SharedIconCacheHashtable;\nstatic PH_QUEUED_LOCK SharedIconCacheLock = PH_QUEUED_LOCK_INIT;\n\nVOID PhGuiSupportInitialization(\n    VOID\n    )\n{\n    HDC hdc;\n    PVOID shell32Handle;\n    PVOID shlwapiHandle;\n\n    if (hdc = GetDC(NULL))\n    {\n        PhGlobalDpi = GetDeviceCaps(hdc, LOGPIXELSY);\n        ReleaseDC(NULL, hdc);\n    }\n\n    shell32Handle = LoadLibrary(L\"shell32.dll\");\n    shlwapiHandle = LoadLibrary(L\"shlwapi.dll\");\n\n    if (WINDOWS_HAS_IMMERSIVE)\n        IsImmersiveProcess_I = PhGetModuleProcAddress(L\"user32.dll\", \"IsImmersiveProcess\");\n    RunFileDlg = PhGetProcedureAddress(shell32Handle, NULL, 61);\n    SHAutoComplete_I = PhGetProcedureAddress(shlwapiHandle, \"SHAutoComplete\", 0);\n}\n\nVOID PhSetControlTheme(\n    _In_ HWND Handle,\n    _In_ PWSTR Theme\n    )\n{\n    SetWindowTheme(Handle, Theme, NULL);\n}\n\nINT PhAddListViewColumn(\n    _In_ HWND ListViewHandle,\n    _In_ INT Index,\n    _In_ INT DisplayIndex,\n    _In_ INT SubItemIndex,\n    _In_ INT Format,\n    _In_ INT Width,\n    _In_ PWSTR Text\n    )\n{\n    LVCOLUMN column;\n\n    column.mask = LVCF_FMT | LVCF_WIDTH | LVCF_TEXT | LVCF_SUBITEM | LVCF_ORDER;\n    column.fmt = Format;\n    column.cx = Width < 0 ? -Width : SCALE_DPI(Width);\n    column.pszText = Text;\n    column.iSubItem = SubItemIndex;\n    column.iOrder = DisplayIndex;\n\n    return ListView_InsertColumn(ListViewHandle, Index, &column);\n}\n\nINT PhAddListViewItem(\n    _In_ HWND ListViewHandle,\n    _In_ INT Index,\n    _In_ PWSTR Text,\n    _In_opt_ PVOID Param\n    )\n{\n    LVITEM item;\n\n    item.mask = LVIF_TEXT | LVIF_PARAM;\n    item.iItem = Index;\n    item.iSubItem = 0;\n    item.pszText = Text;\n    item.lParam = (LPARAM)Param;\n\n    return ListView_InsertItem(ListViewHandle, &item);\n}\n\nINT PhFindListViewItemByFlags(\n    _In_ HWND ListViewHandle,\n    _In_ INT StartIndex,\n    _In_ ULONG Flags\n    )\n{\n    return ListView_GetNextItem(ListViewHandle, StartIndex, Flags);\n}\n\nINT PhFindListViewItemByParam(\n    _In_ HWND ListViewHandle,\n    _In_ INT StartIndex,\n    _In_opt_ PVOID Param\n    )\n{\n    LVFINDINFO findInfo;\n\n    findInfo.flags = LVFI_PARAM;\n    findInfo.lParam = (LPARAM)Param;\n\n    return ListView_FindItem(ListViewHandle, StartIndex, &findInfo);\n}\n\nLOGICAL PhGetListViewItemImageIndex(\n    _In_ HWND ListViewHandle,\n    _In_ INT Index,\n    _Out_ PINT ImageIndex\n    )\n{\n    LOGICAL result;\n    LVITEM item;\n\n    item.mask = LVIF_IMAGE;\n    item.iItem = Index;\n    item.iSubItem = 0;\n\n    result = ListView_GetItem(ListViewHandle, &item);\n\n    if (!result)\n        return result;\n\n    *ImageIndex = item.iImage;\n\n    return result;\n}\n\nLOGICAL PhGetListViewItemParam(\n    _In_ HWND ListViewHandle,\n    _In_ INT Index,\n    _Out_ PVOID *Param\n    )\n{\n    LOGICAL result;\n    LVITEM item;\n\n    item.mask = LVIF_PARAM;\n    item.iItem = Index;\n    item.iSubItem = 0;\n\n    result = ListView_GetItem(ListViewHandle, &item);\n\n    if (!result)\n        return result;\n\n    *Param = (PVOID)item.lParam;\n\n    return result;\n}\n\nVOID PhRemoveListViewItem(\n    _In_ HWND ListViewHandle,\n    _In_ INT Index\n    )\n{\n    ListView_DeleteItem(ListViewHandle, Index);\n}\n\nVOID PhSetListViewItemImageIndex(\n    _In_ HWND ListViewHandle,\n    _In_ INT Index,\n    _In_ INT ImageIndex\n    )\n{\n    LVITEM item;\n\n    item.mask = LVIF_IMAGE;\n    item.iItem = Index;\n    item.iSubItem = 0;\n    item.iImage = ImageIndex;\n\n    ListView_SetItem(ListViewHandle, &item);\n}\n\nVOID PhSetListViewSubItem(\n    _In_ HWND ListViewHandle,\n    _In_ INT Index,\n    _In_ INT SubItemIndex,\n    _In_ PWSTR Text\n    )\n{\n    LVITEM item;\n\n    item.mask = LVIF_TEXT;\n    item.iItem = Index;\n    item.iSubItem = SubItemIndex;\n    item.pszText = Text;\n\n    ListView_SetItem(ListViewHandle, &item);\n}\n\nINT PhAddTabControlTab(\n    _In_ HWND TabControlHandle,\n    _In_ INT Index,\n    _In_ PWSTR Text\n    )\n{\n    TCITEM item;\n\n    item.mask = TCIF_TEXT;\n    item.pszText = Text;\n\n    return TabCtrl_InsertItem(TabControlHandle, Index, &item);\n}\n\nPPH_STRING PhGetWindowText(\n    _In_ HWND hwnd\n    )\n{\n    PPH_STRING text;\n\n    PhGetWindowTextEx(hwnd, 0, &text);\n    return text;\n}\n\nULONG PhGetWindowTextEx(\n    _In_ HWND hwnd,\n    _In_ ULONG Flags,\n    _Out_opt_ PPH_STRING *Text\n    )\n{\n    PPH_STRING string;\n    ULONG length;\n\n    if (Flags & PH_GET_WINDOW_TEXT_INTERNAL)\n    {\n        if (Flags & PH_GET_WINDOW_TEXT_LENGTH_ONLY)\n        {\n            WCHAR buffer[32];\n            length = InternalGetWindowText(hwnd, buffer, sizeof(buffer) / sizeof(WCHAR));\n        }\n        else\n        {\n            // TODO: Resize the buffer until we get the entire thing.\n            string = PhCreateStringEx(NULL, 256 * sizeof(WCHAR));\n            length = InternalGetWindowText(hwnd, string->Buffer, (ULONG)string->Length / sizeof(WCHAR) + 1);\n            string->Length = length * sizeof(WCHAR);\n\n            if (Text)\n                *Text = string;\n            else\n                PhDereferenceObject(string);\n        }\n\n        return length;\n    }\n    else\n    {\n        length = GetWindowTextLength(hwnd);\n\n        if (length == 0 || (Flags & PH_GET_WINDOW_TEXT_LENGTH_ONLY))\n        {\n            if (Text)\n                *Text = PhReferenceEmptyString();\n\n            return length;\n        }\n\n        string = PhCreateStringEx(NULL, length * sizeof(WCHAR));\n\n        if (GetWindowText(hwnd, string->Buffer, (ULONG)string->Length / sizeof(WCHAR) + 1))\n        {\n            if (Text)\n                *Text = string;\n            else\n                PhDereferenceObject(string);\n\n            return length;\n        }\n        else\n        {\n            if (Text)\n                *Text = PhReferenceEmptyString();\n\n            PhDereferenceObject(string);\n\n            return 0;\n        }\n    }\n}\n\nVOID PhAddComboBoxStrings(\n    _In_ HWND hWnd,\n    _In_ PWSTR *Strings,\n    _In_ ULONG NumberOfStrings\n    )\n{\n    ULONG i;\n\n    for (i = 0; i < NumberOfStrings; i++)\n        ComboBox_AddString(hWnd, Strings[i]);\n}\n\nPPH_STRING PhGetComboBoxString(\n    _In_ HWND hwnd,\n    _In_ INT Index\n    )\n{\n    PPH_STRING string;\n    ULONG length;\n\n    if (Index == -1)\n    {\n        Index = ComboBox_GetCurSel(hwnd);\n\n        if (Index == -1)\n            return NULL;\n    }\n\n    length = ComboBox_GetLBTextLen(hwnd, Index);\n\n    if (length == CB_ERR)\n        return NULL;\n    if (length == 0)\n        return PhReferenceEmptyString();\n\n    string = PhCreateStringEx(NULL, length * 2);\n\n    if (ComboBox_GetLBText(hwnd, Index, string->Buffer) != CB_ERR)\n    {\n        return string;\n    }\n    else\n    {\n        PhDereferenceObject(string);\n        return NULL;\n    }\n}\n\nINT PhSelectComboBoxString(\n    _In_ HWND hwnd,\n    _In_ PWSTR String,\n    _In_ BOOLEAN Partial\n    )\n{\n    if (Partial)\n    {\n        return ComboBox_SelectString(hwnd, -1, String);\n    }\n    else\n    {\n        INT index;\n\n        index = ComboBox_FindStringExact(hwnd, -1, String);\n\n        if (index == CB_ERR)\n            return CB_ERR;\n\n        ComboBox_SetCurSel(hwnd, index);\n\n        return index;\n    }\n}\n\nPPH_STRING PhGetListBoxString(\n    _In_ HWND hwnd,\n    _In_ INT Index\n    )\n{\n    PPH_STRING string;\n    ULONG length;\n\n    if (Index == -1)\n    {\n        Index = ListBox_GetCurSel(hwnd);\n\n        if (Index == -1)\n            return NULL;\n    }\n\n    length = ListBox_GetTextLen(hwnd, Index);\n\n    if (length == LB_ERR)\n        return NULL;\n    if (length == 0)\n        return PhReferenceEmptyString();\n\n    string = PhCreateStringEx(NULL, length * 2);\n\n    if (ListBox_GetText(hwnd, Index, string->Buffer) != LB_ERR)\n    {\n        return string;\n    }\n    else\n    {\n        PhDereferenceObject(string);\n        return NULL;\n    }\n}\n\nVOID PhSetStateAllListViewItems(\n    _In_ HWND hWnd,\n    _In_ ULONG State,\n    _In_ ULONG Mask\n    )\n{\n    ULONG i;\n    ULONG count;\n\n    count = ListView_GetItemCount(hWnd);\n\n    if (count == -1)\n        return;\n\n    for (i = 0; i < count; i++)\n    {\n        ListView_SetItemState(hWnd, i, State, Mask);\n    }\n}\n\nPVOID PhGetSelectedListViewItemParam(\n    _In_ HWND hWnd\n    )\n{\n    INT index;\n    PVOID param;\n\n    index = PhFindListViewItemByFlags(\n        hWnd,\n        -1,\n        LVNI_SELECTED\n        );\n\n    if (index != -1)\n    {\n        if (PhGetListViewItemParam(\n            hWnd,\n            index,\n            &param\n            ))\n        {\n            return param;\n        }\n    }\n\n    return NULL;\n}\n\nVOID PhGetSelectedListViewItemParams(\n    _In_ HWND hWnd,\n    _Out_ PVOID **Items,\n    _Out_ PULONG NumberOfItems\n    )\n{\n    PH_ARRAY array;\n    ULONG index;\n    PVOID param;\n\n    PhInitializeArray(&array, sizeof(PVOID), 2);\n    index = -1;\n\n    while ((index = PhFindListViewItemByFlags(\n        hWnd,\n        index,\n        LVNI_SELECTED\n        )) != -1)\n    {\n        if (PhGetListViewItemParam(hWnd, index, &param))\n            PhAddItemArray(&array, &param);\n    }\n\n    *NumberOfItems = (ULONG)array.Count;\n    *Items = PhFinalArrayItems(&array);\n}\n\nVOID PhSetImageListBitmap(\n    _In_ HIMAGELIST ImageList,\n    _In_ INT Index,\n    _In_ HINSTANCE InstanceHandle,\n    _In_ LPCWSTR BitmapName\n    )\n{\n    HBITMAP bitmap;\n\n    bitmap = LoadImage(InstanceHandle, BitmapName, IMAGE_BITMAP, 0, 0, 0);\n\n    if (bitmap)\n    {\n        ImageList_Replace(ImageList, Index, bitmap, NULL);\n        DeleteObject(bitmap);\n    }\n}\n\nstatic BOOLEAN SharedIconCacheHashtableEqualFunction(\n    _In_ PVOID Entry1,\n    _In_ PVOID Entry2\n    )\n{\n    PPHP_ICON_ENTRY entry1 = Entry1;\n    PPHP_ICON_ENTRY entry2 = Entry2;\n\n    if (entry1->InstanceHandle != entry2->InstanceHandle ||\n        entry1->Width != entry2->Width ||\n        entry1->Height != entry2->Height)\n    {\n        return FALSE;\n    }\n\n    if (IS_INTRESOURCE(entry1->Name))\n    {\n        if (IS_INTRESOURCE(entry2->Name))\n            return entry1->Name == entry2->Name;\n        else\n            return FALSE;\n    }\n    else\n    {\n        if (!IS_INTRESOURCE(entry2->Name))\n            return PhEqualStringZ(entry1->Name, entry2->Name, FALSE);\n        else\n            return FALSE;\n    }\n}\n\nstatic ULONG SharedIconCacheHashtableHashFunction(\n    _In_ PVOID Entry\n    )\n{\n    PPHP_ICON_ENTRY entry = Entry;\n    ULONG nameHash;\n\n    if (IS_INTRESOURCE(entry->Name))\n        nameHash = PtrToUlong(entry->Name);\n    else\n        nameHash = PhHashBytes((PUCHAR)entry->Name, PhCountStringZ(entry->Name));\n\n    return nameHash ^ (PtrToUlong(entry->InstanceHandle) >> 5) ^ (entry->Width << 3) ^ entry->Height;\n}\n\nHICON PhLoadIcon(\n    _In_opt_ HINSTANCE InstanceHandle,\n    _In_ PWSTR Name,\n    _In_ ULONG Flags,\n    _In_opt_ ULONG Width,\n    _In_opt_ ULONG Height\n    )\n{\n    PHP_ICON_ENTRY entry;\n    PPHP_ICON_ENTRY actualEntry;\n    HICON icon = NULL;\n\n    if (PhBeginInitOnce(&SharedIconCacheInitOnce))\n    {\n        SharedIconCacheHashtable = PhCreateHashtable(sizeof(PHP_ICON_ENTRY),\n            SharedIconCacheHashtableEqualFunction, SharedIconCacheHashtableHashFunction, 10);\n        PhEndInitOnce(&SharedIconCacheInitOnce);\n    }\n\n    if (Flags & PH_LOAD_ICON_SHARED)\n    {\n        PhAcquireQueuedLockExclusive(&SharedIconCacheLock);\n\n        entry.InstanceHandle = InstanceHandle;\n        entry.Name = Name;\n        entry.Width = PhpGetIconEntrySize(Width, Flags);\n        entry.Height = PhpGetIconEntrySize(Height, Flags);\n        actualEntry = PhFindEntryHashtable(SharedIconCacheHashtable, &entry);\n\n        if (actualEntry)\n        {\n            icon = actualEntry->Icon;\n            PhReleaseQueuedLockExclusive(&SharedIconCacheLock);\n            return icon;\n        }\n    }\n\n    if (Flags & (PH_LOAD_ICON_SIZE_SMALL | PH_LOAD_ICON_SIZE_LARGE))\n    {\n        LoadIconMetric(InstanceHandle, Name, (Flags & PH_LOAD_ICON_SIZE_SMALL) ? LIM_SMALL : LIM_LARGE, &icon);\n    }\n    else\n    {\n        LoadIconWithScaleDown(InstanceHandle, Name, Width, Height, &icon);\n    }\n\n    if (!icon && !(Flags & PH_LOAD_ICON_STRICT))\n    {\n        if (Flags & PH_LOAD_ICON_SIZE_SMALL)\n        {\n            static ULONG smallWidth = 0;\n            static ULONG smallHeight = 0;\n\n            if (!smallWidth)\n                smallWidth = GetSystemMetrics(SM_CXSMICON);\n            if (!smallHeight)\n                smallHeight = GetSystemMetrics(SM_CYSMICON);\n\n            Width = smallWidth;\n            Height = smallHeight;\n        }\n        else if (Flags & PH_LOAD_ICON_SIZE_LARGE)\n        {\n            static ULONG largeWidth = 0;\n            static ULONG largeHeight = 0;\n\n            if (!largeWidth)\n                largeWidth = GetSystemMetrics(SM_CXICON);\n            if (!largeHeight)\n                largeHeight = GetSystemMetrics(SM_CYICON);\n\n            Width = largeWidth;\n            Height = largeHeight;\n        }\n\n        icon = LoadImage(InstanceHandle, Name, IMAGE_ICON, Width, Height, 0);\n    }\n\n    if (Flags & PH_LOAD_ICON_SHARED)\n    {\n        if (icon)\n        {\n            if (!IS_INTRESOURCE(Name))\n                entry.Name = PhDuplicateStringZ(Name);\n            entry.Icon = icon;\n            PhAddEntryHashtable(SharedIconCacheHashtable, &entry);\n        }\n\n        PhReleaseQueuedLockExclusive(&SharedIconCacheLock);\n    }\n\n    return icon;\n}\n\n/**\n * Gets the default icon used for executable files.\n *\n * \\param SmallIcon A variable which receives the small default executable icon. Do not destroy the\n * icon using DestroyIcon(); it is shared between callers.\n * \\param LargeIcon A variable which receives the large default executable icon. Do not destroy the\n * icon using DestroyIcon(); it is shared between callers.\n */\nVOID PhGetStockApplicationIcon(\n    _Out_opt_ HICON *SmallIcon,\n    _Out_opt_ HICON *LargeIcon\n    )\n{\n    static PH_INITONCE initOnce = PH_INITONCE_INIT;\n    static HICON smallIcon = NULL;\n    static HICON largeIcon = NULL;\n\n    // This no longer uses SHGetFileInfo because it is *very* slow and causes many other DLLs to be\n    // loaded, increasing memory usage. The worst thing about it, however, is that it is horribly\n    // incompatible with multi-threading. The first time it is called, it tries to perform some\n    // one-time initialization. It guards this with a lock, but when multiple threads try to call\n    // the function at the same time, instead of waiting for initialization to finish it simply\n    // fails the other threads.\n\n    if (PhBeginInitOnce(&initOnce))\n    {\n        if (WindowsVersion < WINDOWS_10)\n        {\n            PPH_STRING systemDirectory;\n            PPH_STRING dllFileName;\n\n            // imageres,11 (Windows 10 and above), user32,0 (Vista and above) or shell32,2 (XP) contains\n            // the default application icon.\n\n            if (systemDirectory = PhGetSystemDirectory())\n            {\n                PH_STRINGREF dllBaseName;\n\n                PhInitializeStringRef(&dllBaseName, L\"\\\\user32.dll\");\n                dllFileName = PhConcatStringRef2(&systemDirectory->sr, &dllBaseName);\n\n                PhExtractIcon(dllFileName->Buffer, &largeIcon, &smallIcon);\n\n                PhDereferenceObject(dllFileName);\n                PhDereferenceObject(systemDirectory);\n            }\n        }\n\n        // Fallback icons\n        if (!smallIcon)\n            smallIcon = PhLoadIcon(NULL, IDI_APPLICATION, PH_LOAD_ICON_SIZE_SMALL, 0, 0);\n        if (!largeIcon)\n            largeIcon = PhLoadIcon(NULL, IDI_APPLICATION, PH_LOAD_ICON_SIZE_LARGE, 0, 0);\n\n        PhEndInitOnce(&initOnce);\n    }\n\n    if (SmallIcon)\n        *SmallIcon = smallIcon;\n    if (LargeIcon)\n        *LargeIcon = largeIcon;\n}\n\nHICON PhGetFileShellIcon(\n    _In_opt_ PWSTR FileName,\n    _In_opt_ PWSTR DefaultExtension,\n    _In_ BOOLEAN LargeIcon\n    )\n{\n    SHFILEINFO fileInfo;\n    ULONG iconFlag;\n    HICON icon;\n\n    if (DefaultExtension && PhEqualStringZ(DefaultExtension, L\".exe\", TRUE))\n    {\n        // Special case for executable files (see above for reasoning).\n\n        icon = NULL;\n\n        if (FileName)\n        {\n            PhExtractIcon(\n                FileName,\n                LargeIcon ? &icon : NULL,\n                !LargeIcon ? &icon : NULL\n                );\n        }\n\n        if (!icon)\n        {\n            PhGetStockApplicationIcon(\n                !LargeIcon ? &icon : NULL,\n                LargeIcon ? &icon : NULL\n                );\n\n            if (icon)\n                icon = CopyIcon(icon);\n        }\n\n        return icon;\n    }\n\n    iconFlag = LargeIcon ? SHGFI_LARGEICON : SHGFI_SMALLICON;\n    icon = NULL;\n\n    if (FileName && SHGetFileInfo(\n        FileName,\n        0,\n        &fileInfo,\n        sizeof(SHFILEINFO),\n        SHGFI_ICON | iconFlag\n        ))\n    {\n        icon = fileInfo.hIcon;\n    }\n\n    if (!icon && DefaultExtension)\n    {\n        if (SHGetFileInfo(\n            DefaultExtension,\n            FILE_ATTRIBUTE_NORMAL,\n            &fileInfo,\n            sizeof(SHFILEINFO),\n            SHGFI_ICON | iconFlag | SHGFI_USEFILEATTRIBUTES\n            ))\n            icon = fileInfo.hIcon;\n    }\n\n    return icon;\n}\n\nVOID PhpSetClipboardData(\n    _In_ HWND hWnd,\n    _In_ ULONG Format,\n    _In_ HANDLE Data\n    )\n{\n    if (OpenClipboard(hWnd))\n    {\n        if (!EmptyClipboard())\n            goto Fail;\n\n        if (!SetClipboardData(Format, Data))\n            goto Fail;\n\n        CloseClipboard();\n\n        return;\n    }\n\nFail:\n    GlobalFree(Data);\n}\n\nVOID PhSetClipboardString(\n    _In_ HWND hWnd,\n    _In_ PPH_STRINGREF String\n    )\n{\n    HANDLE data;\n    PVOID memory;\n\n    data = GlobalAlloc(GMEM_MOVEABLE, String->Length + sizeof(WCHAR));\n    memory = GlobalLock(data);\n\n    memcpy(memory, String->Buffer, String->Length);\n    *(PWCHAR)PTR_ADD_OFFSET(memory, String->Length) = 0;\n\n    GlobalUnlock(memory);\n\n    PhpSetClipboardData(hWnd, CF_UNICODETEXT, data);\n}\n\nHWND PhCreateDialogFromTemplate(\n    _In_ HWND Parent,\n    _In_ ULONG Style,\n    _In_ PVOID Instance,\n    _In_ PWSTR Template,\n    _In_ DLGPROC DialogProc,\n    _In_ PVOID Parameter\n    )\n{\n    PDLGTEMPLATEEX dialogTemplate;\n    HWND dialogHandle;\n\n    if (!PhLoadResource(Instance, Template, RT_DIALOG, NULL, &dialogTemplate))\n        return NULL;\n\n    if (dialogTemplate->signature == USHRT_MAX)\n    {\n        dialogTemplate->style = Style;\n    }\n    else\n    {\n        ((DLGTEMPLATE *)dialogTemplate)->style = Style;\n    }\n\n    dialogHandle = CreateDialogIndirectParam(\n        Instance, \n        (DLGTEMPLATE *)dialogTemplate, \n        Parent, \n        DialogProc, \n        (LPARAM)Parameter\n        );\n\n    PhFree(dialogTemplate);\n\n    return dialogHandle;\n}\n\nBOOLEAN PhModalPropertySheet(\n    _Inout_ PROPSHEETHEADER *Header\n    )\n{\n    // PropertySheet incorrectly discards WM_QUIT messages in certain cases, so we will use our own\n    // message loop. An example of this is when GetMessage (called by PropertySheet's message loop)\n    // dispatches a message directly from kernel-mode that causes the property sheet to close. In\n    // that case PropertySheet will retrieve the WM_QUIT message but will ignore it because of its\n    // buggy logic.\n\n    // This is also a good opportunity to introduce an auto-pool.\n\n    PH_AUTO_POOL autoPool;\n    HWND oldFocus;\n    HWND topLevelOwner;\n    HWND hwnd;\n    BOOL result;\n    MSG message;\n\n    PhInitializeAutoPool(&autoPool);\n\n    oldFocus = GetFocus();\n    topLevelOwner = Header->hwndParent;\n\n    while (topLevelOwner && (GetWindowLongPtr(topLevelOwner, GWL_STYLE) & WS_CHILD))\n        topLevelOwner = GetParent(topLevelOwner);\n\n    if (topLevelOwner && (topLevelOwner == GetDesktopWindow() || EnableWindow(topLevelOwner, FALSE)))\n        topLevelOwner = NULL;\n\n    Header->dwFlags |= PSH_MODELESS;\n    hwnd = (HWND)PropertySheet(Header);\n\n    if (!hwnd)\n    {\n        if (topLevelOwner)\n            EnableWindow(topLevelOwner, TRUE);\n\n        return FALSE;\n    }\n\n    while (result = GetMessage(&message, NULL, 0, 0))\n    {\n        if (result == -1)\n            break;\n\n        if (!PropSheet_IsDialogMessage(hwnd, &message))\n        {\n            TranslateMessage(&message);\n            DispatchMessage(&message);\n        }\n\n        PhDrainAutoPool(&autoPool);\n\n        // Destroy the window when necessary.\n        if (!PropSheet_GetCurrentPageHwnd(hwnd))\n            break;\n    }\n\n    if (result == 0)\n        PostQuitMessage((INT)message.wParam);\n    if (Header->hwndParent && GetActiveWindow() == hwnd)\n        SetActiveWindow(Header->hwndParent);\n    if (topLevelOwner)\n        EnableWindow(topLevelOwner, TRUE);\n    if (oldFocus && IsWindow(oldFocus))\n        SetFocus(oldFocus);\n\n    DestroyWindow(hwnd);\n    PhDeleteAutoPool(&autoPool);\n\n    return TRUE;\n}\n\nVOID PhInitializeLayoutManager(\n    _Out_ PPH_LAYOUT_MANAGER Manager,\n    _In_ HWND RootWindowHandle\n    )\n{\n    Manager->List = PhCreateList(4);\n    Manager->LayoutNumber = 0;\n\n    Manager->RootItem.Handle = RootWindowHandle;\n    GetClientRect(Manager->RootItem.Handle, &Manager->RootItem.Rect);\n    Manager->RootItem.OrigRect = Manager->RootItem.Rect;\n    Manager->RootItem.ParentItem = NULL;\n    Manager->RootItem.LayoutParentItem = NULL;\n    Manager->RootItem.LayoutNumber = 0;\n    Manager->RootItem.NumberOfChildren = 0;\n    Manager->RootItem.DeferHandle = NULL;\n}\n\nVOID PhDeleteLayoutManager(\n    _Inout_ PPH_LAYOUT_MANAGER Manager\n    )\n{\n    ULONG i;\n\n    for (i = 0; i < Manager->List->Count; i++)\n        PhFree(Manager->List->Items[i]);\n\n    PhDereferenceObject(Manager->List);\n}\n\n// HACK: The math below is all horribly broken, especially the HACK for multiline tab controls.\n\nPPH_LAYOUT_ITEM PhAddLayoutItem(\n    _Inout_ PPH_LAYOUT_MANAGER Manager,\n    _In_ HWND Handle,\n    _In_opt_ PPH_LAYOUT_ITEM ParentItem,\n    _In_ ULONG Anchor\n    )\n{\n    PPH_LAYOUT_ITEM layoutItem;\n    RECT dummy = { 0 };\n\n    layoutItem = PhAddLayoutItemEx(\n        Manager,\n        Handle,\n        ParentItem,\n        Anchor,\n        dummy\n        );\n\n    layoutItem->Margin = layoutItem->Rect;\n    PhConvertRect(&layoutItem->Margin, &layoutItem->ParentItem->Rect);\n\n    if (layoutItem->ParentItem != layoutItem->LayoutParentItem)\n    {\n        // Fix the margin because the item has a dummy parent. They share the same layout parent\n        // item.\n        layoutItem->Margin.top -= layoutItem->ParentItem->Rect.top;\n        layoutItem->Margin.left -= layoutItem->ParentItem->Rect.left;\n        layoutItem->Margin.right = layoutItem->ParentItem->Margin.right;\n        layoutItem->Margin.bottom = layoutItem->ParentItem->Margin.bottom;\n    }\n\n    return layoutItem;\n}\n\nPPH_LAYOUT_ITEM PhAddLayoutItemEx(\n    _Inout_ PPH_LAYOUT_MANAGER Manager,\n    _In_ HWND Handle,\n    _In_opt_ PPH_LAYOUT_ITEM ParentItem,\n    _In_ ULONG Anchor,\n    _In_ RECT Margin\n    )\n{\n    PPH_LAYOUT_ITEM item;\n\n    if (!ParentItem)\n        ParentItem = &Manager->RootItem;\n\n    item = PhAllocate(sizeof(PH_LAYOUT_ITEM));\n    item->Handle = Handle;\n    item->ParentItem = ParentItem;\n    item->LayoutNumber = Manager->LayoutNumber;\n    item->NumberOfChildren = 0;\n    item->DeferHandle = NULL;\n    item->Anchor = Anchor;\n\n    item->LayoutParentItem = item->ParentItem;\n\n    while ((item->LayoutParentItem->Anchor & PH_LAYOUT_DUMMY_MASK) &&\n        item->LayoutParentItem->LayoutParentItem)\n    {\n        item->LayoutParentItem = item->LayoutParentItem->LayoutParentItem;\n    }\n\n    item->LayoutParentItem->NumberOfChildren++;\n\n    GetWindowRect(Handle, &item->Rect);\n    MapWindowPoints(NULL, item->LayoutParentItem->Handle, (POINT *)&item->Rect, 2);\n\n    if (item->Anchor & PH_LAYOUT_TAB_CONTROL)\n    {\n        // We want to convert the tab control rectangle to the tab page display rectangle.\n        TabCtrl_AdjustRect(Handle, FALSE, &item->Rect);\n    }\n\n    item->Margin = Margin;\n\n    item->OrigRect = item->Rect;\n\n    PhAddItemList(Manager->List, item);\n\n    return item;\n}\n\nVOID PhpLayoutItemLayout(\n    _Inout_ PPH_LAYOUT_MANAGER Manager,\n    _Inout_ PPH_LAYOUT_ITEM Item\n    )\n{\n    RECT rect;\n    BOOLEAN hasDummyParent;\n\n    if (Item->NumberOfChildren > 0 && !Item->DeferHandle)\n        Item->DeferHandle = BeginDeferWindowPos(Item->NumberOfChildren);\n\n    if (Item->LayoutNumber == Manager->LayoutNumber)\n        return;\n\n    // If this is the root item we must stop here.\n    if (!Item->ParentItem)\n        return;\n\n    PhpLayoutItemLayout(Manager, Item->ParentItem);\n\n    if (Item->ParentItem != Item->LayoutParentItem)\n    {\n        PhpLayoutItemLayout(Manager, Item->LayoutParentItem);\n        hasDummyParent = TRUE;\n    }\n    else\n    {\n        hasDummyParent = FALSE;\n    }\n\n    GetWindowRect(Item->Handle, &Item->Rect);\n    MapWindowPoints(NULL, Item->LayoutParentItem->Handle, (POINT *)&Item->Rect, 2);\n\n    if (Item->Anchor & PH_LAYOUT_TAB_CONTROL)\n    {\n        // We want to convert the tab control rectangle to the tab page display rectangle.\n        TabCtrl_AdjustRect(Item->Handle, FALSE, &Item->Rect);\n    }\n\n    if (!(Item->Anchor & PH_LAYOUT_DUMMY_MASK))\n    {\n        // Convert right/bottom into margins to make the calculations\n        // easier.\n        rect = Item->Rect;\n        PhConvertRect(&rect, &Item->LayoutParentItem->Rect);\n\n        if (!(Item->Anchor & (PH_ANCHOR_LEFT | PH_ANCHOR_RIGHT)))\n        {\n            // TODO\n            PhRaiseStatus(STATUS_NOT_IMPLEMENTED);\n        }\n        else if (Item->Anchor & PH_ANCHOR_RIGHT)\n        {\n            if (Item->Anchor & PH_ANCHOR_LEFT)\n            {\n                rect.left = (hasDummyParent ? Item->ParentItem->Rect.left : 0) + Item->Margin.left;\n                rect.right = Item->Margin.right;\n            }\n            else\n            {\n                ULONG diff = Item->Margin.right - rect.right;\n\n                rect.left -= diff;\n                rect.right += diff;\n            }\n        }\n\n        if (!(Item->Anchor & (PH_ANCHOR_TOP | PH_ANCHOR_BOTTOM)))\n        {\n            // TODO\n            PhRaiseStatus(STATUS_NOT_IMPLEMENTED);\n        }\n        else if (Item->Anchor & PH_ANCHOR_BOTTOM)\n        {\n            if (Item->Anchor & PH_ANCHOR_TOP)\n            {\n                // tab control hack\n                rect.top = (hasDummyParent ? Item->ParentItem->Rect.top : 0) + Item->Margin.top;\n                rect.bottom = Item->Margin.bottom;\n            }\n            else\n            {\n                ULONG diff = Item->Margin.bottom - rect.bottom;\n\n                rect.top -= diff;\n                rect.bottom += diff;\n            }\n        }\n\n        // Convert the right/bottom back into co-ordinates.\n        PhConvertRect(&rect, &Item->LayoutParentItem->Rect);\n        Item->Rect = rect;\n\n        if (!(Item->Anchor & PH_LAYOUT_IMMEDIATE_RESIZE))\n        {\n            Item->LayoutParentItem->DeferHandle = DeferWindowPos(\n                Item->LayoutParentItem->DeferHandle, Item->Handle,\n                NULL, rect.left, rect.top,\n                rect.right - rect.left, rect.bottom - rect.top,\n                SWP_NOACTIVATE | SWP_NOZORDER\n                );\n        }\n        else\n        {\n            // This is needed for tab controls, so that TabCtrl_AdjustRect will give us an\n            // up-to-date result.\n            SetWindowPos(\n                Item->Handle,\n                NULL, rect.left, rect.top,\n                rect.right - rect.left, rect.bottom - rect.top,\n                SWP_NOACTIVATE | SWP_NOZORDER\n                );\n        }\n    }\n\n    Item->LayoutNumber = Manager->LayoutNumber;\n}\n\nVOID PhLayoutManagerLayout(\n    _Inout_ PPH_LAYOUT_MANAGER Manager\n    )\n{\n    ULONG i;\n\n    Manager->LayoutNumber++;\n\n    GetClientRect(Manager->RootItem.Handle, &Manager->RootItem.Rect);\n\n    for (i = 0; i < Manager->List->Count; i++)\n    {\n        PPH_LAYOUT_ITEM item = (PPH_LAYOUT_ITEM)Manager->List->Items[i];\n\n        PhpLayoutItemLayout(Manager, item);\n    }\n\n    for (i = 0; i < Manager->List->Count; i++)\n    {\n        PPH_LAYOUT_ITEM item = (PPH_LAYOUT_ITEM)Manager->List->Items[i];\n\n        if (item->DeferHandle)\n        {\n            EndDeferWindowPos(item->DeferHandle);\n            item->DeferHandle = NULL;\n        }\n\n        if (item->Anchor & PH_LAYOUT_FORCE_INVALIDATE)\n        {\n            InvalidateRect(item->Handle, NULL, FALSE);\n        }\n    }\n\n    if (Manager->RootItem.DeferHandle)\n    {\n        EndDeferWindowPos(Manager->RootItem.DeferHandle);\n        Manager->RootItem.DeferHandle = NULL;\n    }\n}\n"
  },
  {
    "path": "third_party/phlib/handle.c",
    "content": "/*\n * Process Hacker -\n *   handle table\n *\n * Copyright (C) 2010-2011 wj32\n *\n * This file is part of Process Hacker.\n *\n * Process Hacker is free software; you can redistribute it and/or modify\n * it under the terms of the GNU General Public License as published by\n * the Free Software Foundation, either version 3 of the License, or\n * (at your option) any later version.\n *\n * Process Hacker is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n * GNU General Public License for more details.\n *\n * You should have received a copy of the GNU General Public License\n * along with Process Hacker.  If not, see <http://www.gnu.org/licenses/>.\n */\n\n#include <phbase.h>\n#include <handle.h>\n#include <handlep.h>\n\nstatic PH_INITONCE PhHandleTableInitOnce = PH_INITONCE_INIT;\nstatic PH_FREE_LIST PhHandleTableLevel0FreeList;\nstatic PH_FREE_LIST PhHandleTableLevel1FreeList;\n\nPPH_HANDLE_TABLE PhCreateHandleTable(\n    VOID\n    )\n{\n    PPH_HANDLE_TABLE handleTable;\n    ULONG i;\n\n    if (PhBeginInitOnce(&PhHandleTableInitOnce))\n    {\n        PhInitializeFreeList(\n            &PhHandleTableLevel0FreeList,\n            sizeof(PH_HANDLE_TABLE_ENTRY) * PH_HANDLE_TABLE_LEVEL_ENTRIES,\n            64\n            );\n        PhInitializeFreeList(\n            &PhHandleTableLevel1FreeList,\n            sizeof(PPH_HANDLE_TABLE_ENTRY) * PH_HANDLE_TABLE_LEVEL_ENTRIES,\n            64\n            );\n        PhEndInitOnce(&PhHandleTableInitOnce);\n    }\n\n#ifdef PH_HANDLE_TABLE_SAFE\n    handleTable = PhAllocateSafe(sizeof(PH_HANDLE_TABLE));\n\n    if (!handleTable)\n        return NULL;\n#else\n    handleTable = PhAllocate(sizeof(PH_HANDLE_TABLE));\n#endif\n\n    PhInitializeQueuedLock(&handleTable->Lock);\n    PhInitializeWakeEvent(&handleTable->HandleWakeEvent);\n\n    handleTable->NextValue = 0;\n\n    handleTable->Count = 0;\n    handleTable->TableValue = (ULONG_PTR)PhpCreateHandleTableLevel0(handleTable, TRUE);\n\n#ifdef PH_HANDLE_TABLE_SAFE\n    if (!handleTable->TableValue)\n    {\n        PhFree(handleTable);\n        return NULL;\n    }\n#endif\n\n    // We have now created the level 0 table. The free list can now be set up to point to handle 0,\n    // which points to the rest of the free list (1 -> 2 -> 3 -> ...). The next batch of handles\n    // that need to be created start at PH_HANDLE_TABLE_LEVEL_ENTRIES.\n\n    handleTable->FreeValue = 0;\n    handleTable->NextValue = PH_HANDLE_TABLE_LEVEL_ENTRIES;\n\n    handleTable->FreeValueAlt = PH_HANDLE_VALUE_INVALID; // no entries in alt. free list\n\n    handleTable->Flags = 0;\n\n    for (i = 0; i < PH_HANDLE_TABLE_LOCKS; i++)\n        PhInitializeQueuedLock(&handleTable->Locks[i]);\n\n    return handleTable;\n}\n\nVOID PhDestroyHandleTable(\n    _In_ _Post_invalid_ PPH_HANDLE_TABLE HandleTable\n    )\n{\n    ULONG_PTR tableValue;\n    ULONG tableLevel;\n    PPH_HANDLE_TABLE_ENTRY table0;\n    PPH_HANDLE_TABLE_ENTRY *table1;\n    PPH_HANDLE_TABLE_ENTRY **table2;\n    ULONG i;\n    ULONG j;\n\n    tableValue = HandleTable->TableValue;\n    tableLevel = tableValue & PH_HANDLE_TABLE_LEVEL_MASK;\n    tableValue -= tableLevel;\n\n    switch (tableLevel)\n    {\n    case 0:\n        {\n            table0 = (PPH_HANDLE_TABLE_ENTRY)tableValue;\n\n            PhpFreeHandleTableLevel0(table0);\n        }\n        break;\n    case 1:\n        {\n            table1 = (PPH_HANDLE_TABLE_ENTRY *)tableValue;\n\n            for (i = 0; i < PH_HANDLE_TABLE_LEVEL_ENTRIES; i++)\n            {\n                if (!table1[i])\n                    break;\n\n                PhpFreeHandleTableLevel0(table1[i]);\n            }\n\n            PhpFreeHandleTableLevel1(table1);\n        }\n        break;\n    case 2:\n        {\n            table2 = (PPH_HANDLE_TABLE_ENTRY **)tableValue;\n\n            for (i = 0; i < PH_HANDLE_TABLE_LEVEL_ENTRIES; i++)\n            {\n                if (!table2[i])\n                    break;\n\n                for (j = 0; j < PH_HANDLE_TABLE_LEVEL_ENTRIES; j++)\n                {\n                    if (!table2[i][j])\n                        break;\n\n                    PhpFreeHandleTableLevel0(table2[i][j]);\n                }\n\n                PhpFreeHandleTableLevel1(table2[i]);\n            }\n\n            PhpFreeHandleTableLevel2(table2);\n        }\n        break;\n    default:\n        ASSUME_NO_DEFAULT;\n    }\n\n    PhFree(HandleTable);\n}\n\nVOID PhpBlockOnLockedHandleTableEntry(\n    _Inout_ PPH_HANDLE_TABLE HandleTable,\n    _In_ PPH_HANDLE_TABLE_ENTRY HandleTableEntry\n    )\n{\n    PH_QUEUED_WAIT_BLOCK waitBlock;\n    ULONG_PTR value;\n\n    PhQueueWakeEvent(&HandleTable->HandleWakeEvent, &waitBlock);\n\n    value = HandleTableEntry->Value;\n\n    if (\n        (value & PH_HANDLE_TABLE_ENTRY_TYPE) != PH_HANDLE_TABLE_ENTRY_IN_USE ||\n        (value & PH_HANDLE_TABLE_ENTRY_LOCKED)\n        )\n    {\n        // Entry is not in use or has been unlocked; cancel the wait.\n        PhSetWakeEvent(&HandleTable->HandleWakeEvent, &waitBlock);\n    }\n    else\n    {\n        PhWaitForWakeEvent(&HandleTable->HandleWakeEvent, &waitBlock, TRUE, NULL);\n    }\n}\n\nBOOLEAN PhLockHandleTableEntry(\n    _Inout_ PPH_HANDLE_TABLE HandleTable,\n    _Inout_ PPH_HANDLE_TABLE_ENTRY HandleTableEntry\n    )\n{\n    ULONG_PTR value;\n\n    while (TRUE)\n    {\n        value = HandleTableEntry->Value;\n\n        if ((value & PH_HANDLE_TABLE_ENTRY_TYPE) != PH_HANDLE_TABLE_ENTRY_IN_USE)\n            return FALSE;\n\n        if (value & PH_HANDLE_TABLE_ENTRY_LOCKED)\n        {\n            if ((ULONG_PTR)_InterlockedCompareExchangePointer(\n                (PVOID *)&HandleTableEntry->Value,\n                (PVOID)(value - PH_HANDLE_TABLE_ENTRY_LOCKED),\n                (PVOID)value\n                ) == value)\n            {\n                return TRUE;\n            }\n        }\n\n        PhpBlockOnLockedHandleTableEntry(HandleTable, HandleTableEntry);\n    }\n}\n\nVOID PhUnlockHandleTableEntry(\n    _Inout_ PPH_HANDLE_TABLE HandleTable,\n    _Inout_ PPH_HANDLE_TABLE_ENTRY HandleTableEntry\n    )\n{\n    _interlockedbittestandset(\n        (PLONG)&HandleTableEntry->Value,\n        PH_HANDLE_TABLE_ENTRY_LOCKED_SHIFT\n        );\n    PhSetWakeEvent(&HandleTable->HandleWakeEvent, NULL);\n}\n\nHANDLE PhCreateHandle(\n    _Inout_ PPH_HANDLE_TABLE HandleTable,\n    _In_ PPH_HANDLE_TABLE_ENTRY HandleTableEntry\n    )\n{\n    PPH_HANDLE_TABLE_ENTRY entry;\n    ULONG handleValue;\n\n    entry = PhpAllocateHandleTableEntry(HandleTable, &handleValue);\n\n    if (!entry)\n        return NULL;\n\n    // Copy the given handle table entry to the allocated entry.\n\n    // All free entries have the Free type and have the (not) locked bit clear. There is no problem\n    // with setting the Type now; the entry is still locked, so they will block.\n    entry->TypeAndValue.Type = PH_HANDLE_TABLE_ENTRY_IN_USE;\n    entry->TypeAndValue.Value = HandleTableEntry->TypeAndValue.Value;\n    entry->Value2 = HandleTableEntry->Value2;\n\n    // Now we unlock this entry, waking anyone who was caught back there before we had finished\n    // setting up the entry.\n    PhUnlockHandleTableEntry(HandleTable, entry);\n\n    return PhpEncodeHandle(handleValue);\n}\n\nBOOLEAN PhDestroyHandle(\n    _Inout_ PPH_HANDLE_TABLE HandleTable,\n    _In_ HANDLE Handle,\n    _In_opt_ PPH_HANDLE_TABLE_ENTRY HandleTableEntry\n    )\n{\n    ULONG handleValue;\n\n    handleValue = PhpDecodeHandle(Handle);\n\n    if (!HandleTableEntry)\n    {\n        HandleTableEntry = PhpLookupHandleTableEntry(HandleTable, handleValue);\n\n        if (!HandleTableEntry)\n            return FALSE;\n\n        if (!PhLockHandleTableEntry(HandleTable, HandleTableEntry))\n            return FALSE;\n    }\n\n    _InterlockedExchangePointer(\n        (PVOID *)&HandleTableEntry->Value,\n        (PVOID)PH_HANDLE_TABLE_ENTRY_FREE\n        );\n\n    // The handle table entry is now free; wake any waiters because they can't lock the entry now.\n    // Any future lock attempts will fail because the entry is marked as being free.\n    PhSetWakeEvent(&HandleTable->HandleWakeEvent, NULL);\n\n    PhpFreeHandleTableEntry(HandleTable, handleValue, HandleTableEntry);\n\n    return TRUE;\n}\n\nPPH_HANDLE_TABLE_ENTRY PhLookupHandleTableEntry(\n    _In_ PPH_HANDLE_TABLE HandleTable,\n    _In_ HANDLE Handle\n    )\n{\n    PPH_HANDLE_TABLE_ENTRY entry;\n\n    entry = PhpLookupHandleTableEntry(HandleTable, PhpDecodeHandle(Handle));\n\n    if (!entry)\n        return NULL;\n\n    if (!PhLockHandleTableEntry(HandleTable, entry))\n        return NULL;\n\n    return entry;\n}\n\nVOID PhEnumHandleTable(\n    _In_ PPH_HANDLE_TABLE HandleTable,\n    _In_ PPH_ENUM_HANDLE_TABLE_CALLBACK Callback,\n    _In_opt_ PVOID Context\n    )\n{\n    ULONG handleValue;\n    PPH_HANDLE_TABLE_ENTRY entry;\n    BOOLEAN cont;\n\n    handleValue = 0;\n\n    while (entry = PhpLookupHandleTableEntry(HandleTable, handleValue))\n    {\n        if (PhLockHandleTableEntry(HandleTable, entry))\n        {\n            cont = Callback(\n                HandleTable,\n                PhpEncodeHandle(handleValue),\n                entry,\n                Context\n                );\n            PhUnlockHandleTableEntry(HandleTable, entry);\n\n            if (!cont)\n                break;\n        }\n\n        handleValue++;\n    }\n}\n\nVOID PhSweepHandleTable(\n    _In_ PPH_HANDLE_TABLE HandleTable,\n    _In_ PPH_ENUM_HANDLE_TABLE_CALLBACK Callback,\n    _In_opt_ PVOID Context\n    )\n{\n    ULONG handleValue;\n    PPH_HANDLE_TABLE_ENTRY entry;\n    BOOLEAN cont;\n\n    handleValue = 0;\n\n    while (entry = PhpLookupHandleTableEntry(HandleTable, handleValue))\n    {\n        if (entry->TypeAndValue.Type == PH_HANDLE_TABLE_ENTRY_IN_USE)\n        {\n            cont = Callback(\n                HandleTable,\n                PhpEncodeHandle(handleValue),\n                entry,\n                Context\n                );\n\n            if (!cont)\n                break;\n        }\n\n        handleValue++;\n    }\n}\n\nNTSTATUS PhQueryInformationHandleTable(\n    _In_ PPH_HANDLE_TABLE HandleTable,\n    _In_ PH_HANDLE_TABLE_INFORMATION_CLASS InformationClass,\n    _Out_writes_bytes_opt_(BufferLength) PVOID Buffer,\n    _In_ ULONG BufferLength,\n    _Out_opt_ PULONG ReturnLength\n    )\n{\n    NTSTATUS status = STATUS_SUCCESS;\n    ULONG returnLength;\n\n    switch (InformationClass)\n    {\n    case HandleTableBasicInformation:\n        {\n            PPH_HANDLE_TABLE_BASIC_INFORMATION basicInfo = Buffer;\n\n            if (BufferLength == sizeof(PH_HANDLE_TABLE_BASIC_INFORMATION))\n            {\n                basicInfo->Count = HandleTable->Count;\n                basicInfo->Flags = HandleTable->Flags;\n                basicInfo->TableLevel = HandleTable->TableValue & PH_HANDLE_TABLE_LEVEL_MASK;\n            }\n            else\n            {\n                status = STATUS_INFO_LENGTH_MISMATCH;\n            }\n\n            returnLength = sizeof(PH_HANDLE_TABLE_BASIC_INFORMATION);\n        }\n        break;\n    case HandleTableFlagsInformation:\n        {\n            PPH_HANDLE_TABLE_FLAGS_INFORMATION flagsInfo = Buffer;\n\n            if (BufferLength == sizeof(PH_HANDLE_TABLE_FLAGS_INFORMATION))\n            {\n                flagsInfo->Flags = HandleTable->Flags;\n            }\n            else\n            {\n                status = STATUS_INFO_LENGTH_MISMATCH;\n            }\n\n            returnLength = sizeof(PH_HANDLE_TABLE_FLAGS_INFORMATION);\n        }\n        break;\n    default:\n        status = STATUS_INVALID_INFO_CLASS;\n        returnLength = 0;\n        break;\n    }\n\n    if (ReturnLength)\n        *ReturnLength = returnLength;\n\n    return status;\n}\n\nNTSTATUS PhSetInformationHandleTable(\n    _Inout_ PPH_HANDLE_TABLE HandleTable,\n    _In_ PH_HANDLE_TABLE_INFORMATION_CLASS InformationClass,\n    _In_reads_bytes_(BufferLength) PVOID Buffer,\n    _In_ ULONG BufferLength\n    )\n{\n    NTSTATUS status = STATUS_SUCCESS;\n\n    switch (InformationClass)\n    {\n    case HandleTableFlagsInformation:\n        {\n            PPH_HANDLE_TABLE_FLAGS_INFORMATION flagsInfo = Buffer;\n            ULONG flags;\n\n            if (BufferLength == sizeof(PH_HANDLE_TABLE_FLAGS_INFORMATION))\n            {\n                flags = flagsInfo->Flags;\n\n                if ((flags & PH_HANDLE_TABLE_VALID_FLAGS) == flags)\n                    HandleTable->Flags = flags;\n                else\n                    status = STATUS_INVALID_PARAMETER;\n            }\n            else\n            {\n                status = STATUS_INFO_LENGTH_MISMATCH;\n            }\n        }\n        break;\n    default:\n        status = STATUS_INVALID_INFO_CLASS;\n    }\n\n    return status;\n}\n\nPPH_HANDLE_TABLE_ENTRY PhpAllocateHandleTableEntry(\n    _Inout_ PPH_HANDLE_TABLE HandleTable,\n    _Out_ PULONG HandleValue\n    )\n{\n    PPH_HANDLE_TABLE_ENTRY entry;\n    ULONG freeValue;\n    ULONG lockIndex;\n    ULONG nextFreeValue;\n    ULONG oldFreeValue;\n    BOOLEAN result;\n\n    while (TRUE)\n    {\n        freeValue = HandleTable->FreeValue;\n\n        while (freeValue == PH_HANDLE_VALUE_INVALID)\n        {\n            PhAcquireQueuedLockExclusive(&HandleTable->Lock);\n\n            // Check again to see if we have free handles.\n\n            freeValue = HandleTable->FreeValue;\n\n            if (freeValue != PH_HANDLE_VALUE_INVALID)\n            {\n                PhReleaseQueuedLockExclusive(&HandleTable->Lock);\n                break;\n            }\n\n            // Move handles from the alt. free list to the main free list, and check again.\n\n            freeValue = PhpMoveFreeHandleTableEntries(HandleTable);\n\n            if (freeValue != PH_HANDLE_VALUE_INVALID)\n            {\n                PhReleaseQueuedLockExclusive(&HandleTable->Lock);\n                break;\n            }\n\n            result = PhpAllocateMoreHandleTableEntries(HandleTable, TRUE);\n\n            PhReleaseQueuedLockExclusive(&HandleTable->Lock);\n\n            freeValue = HandleTable->FreeValue;\n\n            // Note that PhpAllocateMoreHandleTableEntries only returns FALSE if it failed to\n            // allocate memory. Success does not guarantee a free handle to be allocated, as they\n            // may have been all used up (however unlikely) when we reach this point. Success simply\n            // means to retry the allocation using the fast path.\n\n            if (!result && freeValue == PH_HANDLE_VALUE_INVALID)\n                return NULL;\n        }\n\n        entry = PhpLookupHandleTableEntry(HandleTable, freeValue);\n        lockIndex = PH_HANDLE_TABLE_LOCK_INDEX(freeValue);\n\n        // To avoid the ABA problem, we would ideally have one queued lock per handle table entry.\n        // That would make the overhead too large, so instead there is a fixed number of locks,\n        // indexed by the handle value (mod no. locks).\n\n        // Possibilities at this point:\n        // 1. freeValue != A (our copy), but the other thread has freed A, so FreeValue = A. No ABA\n        // problem since freeValue != A.\n        // 2. freeValue != A, and FreeValue != A. No ABA problem.\n        // 3. freeValue = A, and the other thread has freed A, so FreeValue = A. No ABA problem\n        // since we haven't read NextFreeValue yet.\n        // 4. freeValue = A, and FreeValue != A. No problem if this stays the same later, as the CAS\n        // will take care of it.\n\n        PhpLockHandleTableShared(HandleTable, lockIndex);\n\n        if (HandleTable->FreeValue != freeValue)\n        {\n            PhpUnlockHandleTableShared(HandleTable, lockIndex);\n            continue;\n        }\n\n        MemoryBarrier();\n\n        nextFreeValue = entry->NextFreeValue;\n\n        // Possibilities/non-possibilities at this point:\n        // 1. freeValue != A (our copy), but the other thread has freed A, so FreeValue = A. This is\n        // actually impossible since we have acquired the lock on A and the free code checks that\n        // and uses the alt. free list instead.\n        // 2. freeValue != A, and FreeValue != A. No ABA problem.\n        // 3. freeValue = A, and the other thread has freed A, so FreeValue = A. Impossible like\n        // above. This is *the* ABA problem which we have now prevented.\n        // 4. freeValue = A, and FreeValue != A. CAS will take care of it.\n\n        oldFreeValue = _InterlockedCompareExchange(\n            &HandleTable->FreeValue,\n            nextFreeValue,\n            freeValue\n            );\n\n        PhpUnlockHandleTableShared(HandleTable, lockIndex);\n\n        if (oldFreeValue == freeValue)\n            break;\n    }\n\n    _InterlockedIncrement((PLONG)&HandleTable->Count);\n\n    *HandleValue = freeValue;\n\n    return entry;\n}\n\nVOID PhpFreeHandleTableEntry(\n    _Inout_ PPH_HANDLE_TABLE HandleTable,\n    _In_ ULONG HandleValue,\n    _Inout_ PPH_HANDLE_TABLE_ENTRY HandleTableEntry\n    )\n{\n    PULONG freeList;\n    ULONG flags;\n    ULONG oldValue;\n\n    _InterlockedDecrement((PLONG)&HandleTable->Count);\n\n    flags = HandleTable->Flags;\n\n    // Choose the free list to use depending on whether someone is popping from the main free list\n    // (see PhpAllocateHandleTableEntry for details). We always use the alt. free list if strict\n    // FIFO is enabled.\n    if (!(flags & PH_HANDLE_TABLE_STRICT_FIFO) &&\n        PhTryAcquireReleaseQueuedLockExclusive(\n        &HandleTable->Locks[PH_HANDLE_TABLE_LOCK_INDEX(HandleValue)]))\n    {\n        freeList = &HandleTable->FreeValue;\n    }\n    else\n    {\n        freeList = &HandleTable->FreeValueAlt;\n    }\n\n    while (TRUE)\n    {\n        oldValue = *freeList;\n        HandleTableEntry->NextFreeValue = oldValue;\n\n        if (_InterlockedCompareExchange(\n            freeList,\n            HandleValue,\n            oldValue\n            ) == oldValue)\n        {\n            break;\n        }\n    }\n}\n\nBOOLEAN PhpAllocateMoreHandleTableEntries(\n    _In_ PPH_HANDLE_TABLE HandleTable,\n    _In_ BOOLEAN Initialize\n    )\n{\n    ULONG_PTR tableValue;\n    ULONG tableLevel;\n    PPH_HANDLE_TABLE_ENTRY table0;\n    PPH_HANDLE_TABLE_ENTRY *table1;\n    PPH_HANDLE_TABLE_ENTRY **table2;\n    ULONG i;\n    ULONG j;\n    ULONG oldNextValue;\n    ULONG freeValue;\n\n    // Get a pointer to the table, and its level.\n\n    tableValue = HandleTable->TableValue;\n    tableLevel = tableValue & PH_HANDLE_TABLE_LEVEL_MASK;\n    tableValue -= tableLevel;\n\n    switch (tableLevel)\n    {\n    case 0:\n        {\n            // Create a level 1 table.\n\n            table1 = PhpCreateHandleTableLevel1(HandleTable);\n\n#ifdef PH_HANDLE_TABLE_SAFE\n            if (!table1)\n                return FALSE;\n#endif\n\n            // Create a new level 0 table and move the existing level into the new level 1 table.\n\n            table0 = PhpCreateHandleTableLevel0(HandleTable, Initialize);\n\n#ifdef PH_HANDLE_TABLE_SAFE\n            if (!table0)\n            {\n                PhpFreeHandleTableLevel1(table1);\n                return FALSE;\n            }\n#endif\n\n            table1[0] = (PPH_HANDLE_TABLE_ENTRY)tableValue;\n            table1[1] = table0;\n\n            tableValue = (ULONG_PTR)table1 | 1;\n            //_InterlockedExchangePointer((PVOID *)&HandleTable->TableValue, (PVOID)tableValue);\n            HandleTable->TableValue = tableValue;\n        }\n        break;\n    case 1:\n        {\n            table1 = (PPH_HANDLE_TABLE_ENTRY *)tableValue;\n\n            // Determine whether we need to create a new level 0 table or create a level 2 table.\n\n            i = HandleTable->NextValue / PH_HANDLE_TABLE_LEVEL_ENTRIES;\n\n            if (i < PH_HANDLE_TABLE_LEVEL_ENTRIES)\n            {\n                table0 = PhpCreateHandleTableLevel0(HandleTable, TRUE);\n\n#ifdef PH_HANDLE_TABLE_SAFE\n                if (!table0)\n                    return FALSE;\n#endif\n\n                //_InterlockedExchangePointer((PVOID *)&table1[i], table0);\n                table1[i] = table0;\n            }\n            else\n            {\n                // Create a level 2 table.\n\n                table2 = PhpCreateHandleTableLevel2(HandleTable);\n\n#ifdef PH_HANDLE_TABLE_SAFE\n                if (!table2)\n                    return FALSE;\n#endif\n\n                // Create a new level 1 table and move the existing level into the new level 2\n                // table.\n\n                table1 = PhpCreateHandleTableLevel1(HandleTable);\n\n#ifdef PH_HANDLE_TABLE_SAFE\n                if (!table1)\n                {\n                    PhpFreeHandleTableLevel2(table2);\n                    return FALSE;\n                }\n#endif\n\n                table0 = PhpCreateHandleTableLevel0(HandleTable, Initialize);\n\n#ifdef PH_HANDLE_TABLE_SAFE\n                if (!table0)\n                {\n                    PhpFreeHandleTableLevel1(table1);\n                    PhpFreeHandleTableLevel2(table2);\n                    return FALSE;\n                }\n#endif\n\n                table1[0] = table0;\n\n                table2[0] = (PPH_HANDLE_TABLE_ENTRY *)tableValue;\n                table2[1] = table1;\n\n                tableValue = (ULONG_PTR)table2 | 2;\n                //_InterlockedExchangePointer((PVOID *)&HandleTable->TableValue, (PVOID)tableValue);\n                HandleTable->TableValue = tableValue;\n            }\n        }\n        break;\n    case 2:\n        {\n            table2 = (PPH_HANDLE_TABLE_ENTRY **)tableValue;\n\n            i = HandleTable->NextValue /\n                (PH_HANDLE_TABLE_LEVEL_ENTRIES * PH_HANDLE_TABLE_LEVEL_ENTRIES);\n            // i contains an index into the level 2 table, of the containing level 1 table.\n\n            // Check if we have exceeded the maximum number of handles.\n\n            if (i >= PH_HANDLE_TABLE_LEVEL_ENTRIES)\n                return FALSE;\n\n            // Check if we should create a new level 0 table or a new level 2 table.\n            if (table2[i])\n            {\n                table0 = PhpCreateHandleTableLevel0(HandleTable, Initialize);\n\n#ifdef PH_HANDLE_TABLE_SAFE\n                if (!table0)\n                    return FALSE;\n#endif\n\n                // Same as j = HandleTable->NextValue % (no. entries * no. entries), but we already\n                // calculated i so just use it.\n                j = HandleTable->NextValue - i *\n                    (PH_HANDLE_TABLE_LEVEL_ENTRIES * PH_HANDLE_TABLE_LEVEL_ENTRIES);\n                j /= PH_HANDLE_TABLE_LEVEL_ENTRIES;\n                // j now contains an index into the level 1 table, of the containing level 0 table\n                // (the one which was created).\n\n                //_InterlockedExchangePointer((PVOID *)&table2[i][j], table0);\n                table2[i][j] = table0;\n            }\n            else\n            {\n                table1 = PhpCreateHandleTableLevel1(HandleTable);\n\n#ifdef PH_HANDLE_TABLE_SAFE\n                if (!table1)\n                    return FALSE;\n#endif\n\n                table0 = PhpCreateHandleTableLevel0(HandleTable, TRUE);\n\n#ifdef PH_HANDLE_TABLE_SAFE\n                if (!table0)\n                {\n                    PhpFreeHandleTableLevel1(table1);\n                    return FALSE;\n                }\n#endif\n\n                table1[0] = table0;\n\n                //_InterlockedExchangePointer((PVOID *)&table2[i], table1);\n                table2[i] = table1;\n            }\n        }\n        break;\n    default:\n        ASSUME_NO_DEFAULT;\n    }\n\n    // In each of the cases above, we allocated one additional level 0 table.\n    oldNextValue = _InterlockedExchangeAdd(\n        (PLONG)&HandleTable->NextValue,\n        PH_HANDLE_TABLE_LEVEL_ENTRIES\n        );\n\n    if (Initialize)\n    {\n        // No ABA problem since these are new handles being pushed.\n\n        while (TRUE)\n        {\n            freeValue = HandleTable->FreeValue;\n            table0[PH_HANDLE_TABLE_LEVEL_ENTRIES - 1].NextFreeValue = freeValue;\n\n            if (_InterlockedCompareExchange(\n                &HandleTable->FreeValue,\n                oldNextValue,\n                freeValue\n                ) == freeValue)\n            {\n                break;\n            }\n        }\n    }\n\n    return TRUE;\n}\n\nPPH_HANDLE_TABLE_ENTRY PhpLookupHandleTableEntry(\n    _In_ PPH_HANDLE_TABLE HandleTable,\n    _In_ ULONG HandleValue\n    )\n{\n    ULONG_PTR tableValue;\n    ULONG tableLevel;\n    PPH_HANDLE_TABLE_ENTRY table0;\n    PPH_HANDLE_TABLE_ENTRY *table1;\n    PPH_HANDLE_TABLE_ENTRY **table2;\n    PPH_HANDLE_TABLE_ENTRY entry;\n\n    if (HandleValue >= HandleTable->NextValue)\n        return NULL;\n\n    // Get a pointer to the table, and its level.\n\n    tableValue = HandleTable->TableValue;\n    tableLevel = tableValue & PH_HANDLE_TABLE_LEVEL_MASK;\n    tableValue -= tableLevel;\n\n    // No additional checking needed; aleady checked against NextValue.\n\n    switch (tableLevel)\n    {\n    case 0:\n        {\n            table0 = (PPH_HANDLE_TABLE_ENTRY)tableValue;\n            entry = &table0[HandleValue];\n        }\n        break;\n    case 1:\n        {\n            table1 = (PPH_HANDLE_TABLE_ENTRY *)tableValue;\n            table0 = table1[PH_HANDLE_VALUE_LEVEL1_U(HandleValue)];\n            entry = &table0[PH_HANDLE_VALUE_LEVEL0(HandleValue)];\n        }\n        break;\n    case 2:\n        {\n            table2 = (PPH_HANDLE_TABLE_ENTRY **)tableValue;\n            table1 = table2[PH_HANDLE_VALUE_LEVEL2_U(HandleValue)];\n            table0 = table1[PH_HANDLE_VALUE_LEVEL1(HandleValue)];\n            entry = &table0[PH_HANDLE_VALUE_LEVEL0(HandleValue)];\n        }\n        break;\n    default:\n        ASSUME_NO_DEFAULT;\n    }\n\n    return entry;\n}\n\nULONG PhpMoveFreeHandleTableEntries(\n    _Inout_ PPH_HANDLE_TABLE HandleTable\n    )\n{\n    ULONG freeValueAlt;\n    ULONG flags;\n    ULONG i;\n    ULONG index;\n    ULONG nextIndex;\n    ULONG lastIndex;\n    PPH_HANDLE_TABLE_ENTRY entry;\n    PPH_HANDLE_TABLE_ENTRY firstEntry;\n    ULONG count;\n    ULONG freeValue;\n\n    // Remove all entries from the alt. free list.\n    freeValueAlt = _InterlockedExchange(&HandleTable->FreeValueAlt, PH_HANDLE_VALUE_INVALID);\n\n    if (freeValueAlt == PH_HANDLE_VALUE_INVALID)\n    {\n        // No handles on the alt. free list.\n        return PH_HANDLE_VALUE_INVALID;\n    }\n\n    // Avoid the ABA problem by testing all locks (see PhpAllocateHandleTableEntry for details).\n    // Unlike in PhpFreeHandleTableEntry we have no \"alternative\" list, so we must allow blocking.\n    for (i = 0; i < PH_HANDLE_TABLE_LOCKS; i++)\n        PhAcquireReleaseQueuedLockExclusive(&HandleTable->Locks[i]);\n\n    flags = HandleTable->Flags;\n\n    if (!(flags & PH_HANDLE_TABLE_STRICT_FIFO))\n    {\n        // Shortcut: if there are no entries in the main free list and we don't need to reverse the\n        // chain, just return.\n        if (_InterlockedCompareExchange(\n            &HandleTable->FreeValue,\n            freeValueAlt,\n            PH_HANDLE_VALUE_INVALID\n            ) == PH_HANDLE_VALUE_INVALID)\n            return freeValueAlt;\n    }\n\n    // Reverse the chain (even if strict FIFO is off; we have to traverse the list to find the last\n    // entry, so we might as well reverse it along the way).\n\n    index = freeValueAlt;\n    lastIndex = PH_HANDLE_VALUE_INVALID;\n    count = 0;\n\n    while (TRUE)\n    {\n        entry = PhpLookupHandleTableEntry(HandleTable, index);\n        count++;\n\n        if (lastIndex == PH_HANDLE_VALUE_INVALID)\n            firstEntry = entry;\n\n        nextIndex = entry->NextFreeValue;\n        entry->NextFreeValue = lastIndex;\n        lastIndex = index;\n\n        if (nextIndex == PH_HANDLE_VALUE_INVALID)\n            break;\n\n        index = nextIndex;\n    }\n\n    // Note that firstEntry actually contains the last free entry, since we reversed the list.\n    // Similarly index/lastIndex both contain the index of the first free entry.\n\n    // Push the entries onto the free list.\n    while (TRUE)\n    {\n        freeValue = HandleTable->FreeValue;\n        firstEntry->NextFreeValue = freeValue;\n\n        if (_InterlockedCompareExchange(\n            &HandleTable->FreeValue,\n            index,\n            freeValue\n            ) == freeValue)\n            break;\n    }\n\n    // Force expansion if we don't have enough free handles.\n    if (\n        (flags & PH_HANDLE_TABLE_STRICT_FIFO) &&\n        count < PH_HANDLE_TABLE_FREE_COUNT\n        )\n    {\n        index = PH_HANDLE_VALUE_INVALID;\n    }\n\n    return index;\n}\n\nPPH_HANDLE_TABLE_ENTRY PhpCreateHandleTableLevel0(\n    _In_ PPH_HANDLE_TABLE HandleTable,\n    _In_ BOOLEAN Initialize\n    )\n{\n    PPH_HANDLE_TABLE_ENTRY table;\n    PPH_HANDLE_TABLE_ENTRY entry;\n    ULONG baseValue;\n    ULONG i;\n\n#ifdef PH_HANDLE_TABLE_SAFE\n    __try\n    {\n        table = PhAllocateFromFreeList(&PhHandleTableLevel0FreeList);\n    }\n    __except (SIMPLE_EXCEPTION_FILTER(GetExceptionCode() == STATUS_NO_MEMORY))\n    {\n        return NULL;\n    }\n#else\n    table = PhAllocateFromFreeList(&PhHandleTableLevel0FreeList);\n#endif\n\n    if (Initialize)\n    {\n        entry = &table[0];\n        baseValue = HandleTable->NextValue;\n\n        for (i = baseValue + 1; i < baseValue + PH_HANDLE_TABLE_LEVEL_ENTRIES; i++)\n        {\n            entry->Value = PH_HANDLE_TABLE_ENTRY_FREE;\n            entry->NextFreeValue = i;\n            entry++;\n        }\n\n        entry->Value = PH_HANDLE_TABLE_ENTRY_FREE;\n        entry->NextFreeValue = PH_HANDLE_VALUE_INVALID;\n    }\n\n    return table;\n}\n\nVOID PhpFreeHandleTableLevel0(\n    _In_ PPH_HANDLE_TABLE_ENTRY Table\n    )\n{\n    PhFreeToFreeList(&PhHandleTableLevel0FreeList, Table);\n}\n\nPPH_HANDLE_TABLE_ENTRY *PhpCreateHandleTableLevel1(\n    _In_ PPH_HANDLE_TABLE HandleTable\n    )\n{\n    PPH_HANDLE_TABLE_ENTRY *table;\n\n#ifdef PH_HANDLE_TABLE_SAFE\n    __try\n    {\n        table = PhAllocateFromFreeList(&PhHandleTableLevel1FreeList);\n    }\n    __except (SIMPLE_EXCEPTION_FILTER(GetExceptionCode() == STATUS_NO_MEMORY))\n    {\n        return NULL;\n    }\n#else\n    table = PhAllocateFromFreeList(&PhHandleTableLevel1FreeList);\n#endif\n\n    memset(table, 0, sizeof(PPH_HANDLE_TABLE_ENTRY) * PH_HANDLE_TABLE_LEVEL_ENTRIES);\n\n    return table;\n}\n\nVOID PhpFreeHandleTableLevel1(\n    _In_ PPH_HANDLE_TABLE_ENTRY *Table\n    )\n{\n    PhFreeToFreeList(&PhHandleTableLevel1FreeList, Table);\n}\n\nPPH_HANDLE_TABLE_ENTRY **PhpCreateHandleTableLevel2(\n    _In_ PPH_HANDLE_TABLE HandleTable\n    )\n{\n    PPH_HANDLE_TABLE_ENTRY **table;\n\n#ifdef PH_HANDLE_TABLE_SAFE\n    table = PhAllocateSafe(sizeof(PPH_HANDLE_TABLE_ENTRY *) * PH_HANDLE_TABLE_LEVEL_ENTRIES);\n\n    if (!table)\n        return NULL;\n#else\n    table = PhAllocate(sizeof(PPH_HANDLE_TABLE_ENTRY *) * PH_HANDLE_TABLE_LEVEL_ENTRIES);\n#endif\n\n    memset(table, 0, sizeof(PPH_HANDLE_TABLE_ENTRY *) * PH_HANDLE_TABLE_LEVEL_ENTRIES);\n\n    return table;\n}\n\nVOID PhpFreeHandleTableLevel2(\n    _In_ PPH_HANDLE_TABLE_ENTRY **Table\n    )\n{\n    PhFree(Table);\n}\n"
  },
  {
    "path": "third_party/phlib/hexedit.c",
    "content": "/*\n * Process Hacker -\n *   hex editor control\n *\n * Copyright (C) 2010-2015 wj32\n * Copyright (C) 2017 dmex\n *\n * This file is part of Process Hacker.\n *\n * Process Hacker is free software; you can redistribute it and/or modify\n * it under the terms of the GNU General Public License as published by\n * the Free Software Foundation, either version 3 of the License, or\n * (at your option) any later version.\n *\n * Process Hacker is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n * GNU General Public License for more details.\n *\n * You should have received a copy of the GNU General Public License\n * along with Process Hacker.  If not, see <http://www.gnu.org/licenses/>.\n */\n\n#include <ph.h>\n#include <hexedit.h>\n#include <guisup.h>\n\n#include <hexeditp.h>\n\n#include <windowsx.h>\n\n// Code originally from http://www.codeguru.com/Cpp/controls/editctrl/article.php/c539\n\nBOOLEAN PhHexEditInitialization(\n    VOID\n    )\n{\n    WNDCLASSEX c = { sizeof(c) };\n\n    c.style = CS_GLOBALCLASS;\n    c.lpfnWndProc = PhpHexEditWndProc;\n    c.cbClsExtra = 0;\n    c.cbWndExtra = sizeof(PVOID);\n    c.hInstance = PhInstanceHandle;\n    c.hIcon = NULL;\n    c.hCursor = LoadCursor(NULL, IDC_ARROW);\n    c.hbrBackground = NULL;\n    c.lpszMenuName = NULL;\n    c.lpszClassName = PH_HEXEDIT_CLASSNAME;\n    c.hIconSm = NULL;\n\n    if (!RegisterClassEx(&c))\n        return FALSE;\n\n    return TRUE;\n}\n\nVOID PhpCreateHexEditContext(\n    _Out_ PPHP_HEXEDIT_CONTEXT *Context\n    )\n{\n    PPHP_HEXEDIT_CONTEXT context;\n\n    context = PhAllocate(sizeof(PHP_HEXEDIT_CONTEXT));\n    memset(context, 0, sizeof(PHP_HEXEDIT_CONTEXT)); // important, set NullWidth to 0\n\n    context->Data = NULL;\n    context->Length = 0;\n    context->TopIndex = 0;\n    context->BytesPerRow = 16;\n    context->LinesPerPage = 1;\n\n    context->ShowHex = TRUE;\n    context->ShowAscii = TRUE;\n    context->ShowAddress = TRUE;\n    context->AddressIsWide = TRUE;\n    context->AllowLengthChange = FALSE;\n\n    context->AddressOffset = 0;\n    context->HexOffset = 0;\n    context->AsciiOffset = 0;\n\n    context->Update = TRUE;\n    context->NoAddressChange = FALSE;\n    context->CurrentMode = EDIT_NONE;\n\n    context->EditPosition.x = 0;\n    context->EditPosition.y = 0;\n    context->CurrentAddress = 0;\n    context->HalfPage = TRUE;\n\n    context->SelStart = -1;\n    context->SelEnd = -1;\n\n    *Context = context;\n}\n\nVOID PhpFreeHexEditContext(\n    _In_ _Post_invalid_ PPHP_HEXEDIT_CONTEXT Context\n    )\n{\n    if (!Context->UserBuffer && Context->Data) PhFree(Context->Data);\n    if (Context->CharBuffer) PhFree(Context->CharBuffer);\n    if (Context->Font) DeleteObject(Context->Font);\n    PhFree(Context);\n}\n\nLRESULT CALLBACK PhpHexEditWndProc(\n    _In_ HWND hwnd,\n    _In_ UINT uMsg,\n    _In_ WPARAM wParam,\n    _In_ LPARAM lParam\n    )\n{\n    PPHP_HEXEDIT_CONTEXT context;\n\n    context = (PPHP_HEXEDIT_CONTEXT)GetWindowLongPtr(hwnd, 0);\n\n    if (uMsg == WM_CREATE)\n    {\n        PhpCreateHexEditContext(&context);\n        SetWindowLongPtr(hwnd, 0, (LONG_PTR)context);\n    }\n\n    if (!context)\n        return DefWindowProc(hwnd, uMsg, wParam, lParam);\n\n    switch (uMsg)\n    {\n    case WM_CREATE:\n        {\n            context->Font = CreateFont(-(LONG)PhMultiplyDivide(12, PhGlobalDpi, 96), 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, L\"Courier New\");\n        }\n        break;\n    case WM_DESTROY:\n        {\n            SetWindowLongPtr(hwnd, 0, (LONG_PTR)NULL);\n            PhpFreeHexEditContext(context);\n        }\n        break;\n    case WM_PAINT:\n        {\n            PAINTSTRUCT paintStruct;\n            HDC hdc;\n\n            if (hdc = BeginPaint(hwnd, &paintStruct))\n            {\n                PhpHexEditOnPaint(hwnd, context, &paintStruct, hdc);\n                EndPaint(hwnd, &paintStruct);\n            }\n        }\n        break;\n    case WM_SIZE:\n        {\n            PhpHexEditUpdateMetrics(hwnd, context, FALSE, NULL);\n        }\n        break;\n    case WM_SETFOCUS:\n        {\n            if (context->Data && !PhpHexEditHasSelected(context))\n            {\n                if (context->EditPosition.x == 0 && context->ShowAddress)\n                    PhpHexEditCreateAddressCaret(hwnd, context);\n                else\n                    PhpHexEditCreateEditCaret(hwnd, context);\n\n                SetCaretPos(context->EditPosition.x, context->EditPosition.y);\n                ShowCaret(hwnd);\n            }\n        }\n        break;\n    case WM_KILLFOCUS:\n        {\n            DestroyCaret();\n        }\n        break;\n    case WM_VSCROLL:\n        {\n            SHORT scrollRequest = LOWORD(wParam);\n            LONG currentPosition;\n            LONG originalTopIndex;\n            SCROLLINFO scrollInfo = { sizeof(scrollInfo) };\n\n            originalTopIndex = context->TopIndex;\n\n            scrollInfo.fMask = SIF_TRACKPOS;\n            GetScrollInfo(hwnd, SB_VERT, &scrollInfo);\n            currentPosition = scrollInfo.nTrackPos;\n\n            if (context->Data)\n            {\n                LONG mult;\n\n                mult = context->LinesPerPage * context->BytesPerRow;\n\n                switch (scrollRequest)\n                {\n                case SB_LINEDOWN:\n                    if (context->TopIndex < context->Length - mult)\n                    {\n                        context->TopIndex += context->BytesPerRow;\n                        REDRAW_WINDOW(hwnd);\n                    }\n                    break;\n                case SB_LINEUP:\n                    if (context->TopIndex >= context->BytesPerRow)\n                    {\n                        context->TopIndex -= context->BytesPerRow;\n                        REDRAW_WINDOW(hwnd);\n                    }\n                    break;\n                case SB_PAGEDOWN:\n                    if (context->TopIndex < context->Length - mult)\n                    {\n                        LONG pageEnd = 0;\n\n                        while (pageEnd < context->Length - mult)\n                            pageEnd += context->BytesPerRow;\n\n                        context->TopIndex += mult;\n\n                        if (context->TopIndex > pageEnd)\n                            context->TopIndex = pageEnd;\n\n                        REDRAW_WINDOW(hwnd);\n                    }\n                    break;\n                case SB_PAGEUP:\n                    if (context->TopIndex > 0)\n                    {\n                        context->TopIndex -= mult;\n\n                        if (context->TopIndex < 0)\n                            context->TopIndex = 0;\n\n                        REDRAW_WINDOW(hwnd);\n                    }\n                    break;\n                case SB_THUMBTRACK:\n                    context->TopIndex = currentPosition * context->BytesPerRow;\n                    REDRAW_WINDOW(hwnd);\n                    break;\n                case SB_TOP:\n                    context->TopIndex = 0;\n                    REDRAW_WINDOW(hwnd);\n                    break;\n                case SB_BOTTOM:\n                    while (context->TopIndex < context->Length - mult)\n                        context->TopIndex += context->BytesPerRow;\n                    REDRAW_WINDOW(hwnd);\n                    break;\n                }\n\n                SetScrollPos(hwnd, SB_VERT, context->TopIndex / context->BytesPerRow, TRUE);\n\n                if (!context->NoAddressChange && FALSE) // this behaviour sucks, so just leave it out\n                    context->CurrentAddress += context->TopIndex - originalTopIndex;\n\n                PhpHexEditRepositionCaret(hwnd, context, context->CurrentAddress);\n            }\n        }\n        break;\n    case WM_MOUSEWHEEL:\n        {\n            SHORT wheelDelta = GET_WHEEL_DELTA_WPARAM(wParam);\n\n            if (context->Data)\n            {\n                ULONG wheelScrollLines;\n\n                if (!SystemParametersInfo(SPI_GETWHEELSCROLLLINES, 0, &wheelScrollLines, 0))\n                    wheelScrollLines = 3;\n\n                context->TopIndex += context->BytesPerRow * (LONG)wheelScrollLines * -wheelDelta / WHEEL_DELTA;\n\n                if (context->TopIndex < 0)\n                    context->TopIndex = 0;\n\n                if (context->Length >= context->LinesPerPage * context->BytesPerRow)\n                {\n                    if (context->TopIndex > context->Length - context->LinesPerPage * context->BytesPerRow)\n                        context->TopIndex = context->Length - context->LinesPerPage * context->BytesPerRow;\n                }\n\n                REDRAW_WINDOW(hwnd);\n\n                SetScrollPos(hwnd, SB_VERT, context->TopIndex / context->BytesPerRow, TRUE);\n\n                PhpHexEditRepositionCaret(hwnd, context, context->CurrentAddress);\n            }\n        }\n        break;\n    case WM_GETDLGCODE:\n        if (wParam != VK_ESCAPE)\n            return DLGC_WANTALLKEYS;\n        break;\n    case WM_ERASEBKGND:\n        return 1;\n    case WM_LBUTTONDOWN:\n        {\n            ULONG flags = (ULONG)wParam;\n            POINT cursorPos;\n\n            cursorPos.x = GET_X_LPARAM(lParam);\n            cursorPos.y = GET_Y_LPARAM(lParam);\n\n            SetFocus(hwnd);\n\n            if (context->Data)\n            {\n                POINT point;\n\n                if (wParam & MK_SHIFT)\n                    context->SelStart = context->CurrentAddress;\n\n                PhpHexEditCalculatePosition(hwnd, context, cursorPos.x, cursorPos.y, &point);\n\n                if (point.x > -1)\n                {\n                    context->EditPosition = point;\n\n                    point.x *= context->NullWidth;\n                    point.y *= context->LineHeight;\n\n                    if (point.x == 0 && context->ShowAddress)\n                        PhpHexEditCreateAddressCaret(hwnd, context);\n                    else\n                        PhpHexEditCreateEditCaret(hwnd, context);\n\n                    SetCaretPos(point.x, point.y);\n\n                    if (flags & MK_SHIFT)\n                    {\n                        context->SelEnd = context->CurrentAddress;\n\n                        if (context->CurrentMode == EDIT_HIGH || context->CurrentMode == EDIT_LOW)\n                            context->SelEnd++;\n\n                        REDRAW_WINDOW(hwnd);\n                    }\n                }\n\n                if (!(flags & MK_SHIFT))\n                {\n                    if (DragDetect(hwnd, cursorPos))\n                    {\n                        context->SelStart = context->CurrentAddress;\n                        context->SelEnd = context->SelStart;\n                        SetCapture(hwnd);\n                        context->HasCapture = TRUE;\n                    }\n                    else\n                    {\n                        BOOLEAN selected;\n\n                        selected = context->SelStart != -1;\n                        context->SelStart = -1;\n                        context->SelEnd = -1;\n\n                        if (selected)\n                            REDRAW_WINDOW(hwnd);\n                    }\n                }\n\n                if (!PhpHexEditHasSelected(context))\n                    ShowCaret(hwnd);\n            }\n        }\n        break;\n    case WM_LBUTTONUP:\n        {\n            if (context->HasCapture && PhpHexEditHasSelected(context))\n                ReleaseCapture();\n\n            context->HasCapture = FALSE;\n        }\n        break;\n    case WM_MOUSEMOVE:\n        {\n            ULONG flags = (ULONG)wParam;\n            POINT cursorPos;\n\n            cursorPos.x = GET_X_LPARAM(lParam);\n            cursorPos.y = GET_Y_LPARAM(lParam);\n\n            if (\n                context->Data &&\n                context->HasCapture &&\n                context->SelStart != -1\n                )\n            {\n                RECT rect;\n                POINT point;\n                ULONG oldSelEnd;\n\n                // User is dragging.\n\n                GetClientRect(hwnd, &rect);\n\n                if (!PtInRect(&rect, cursorPos))\n                {\n                    if (cursorPos.y < 0)\n                    {\n                        SendMessage(hwnd, WM_VSCROLL, SB_LINEUP, 0);\n                        cursorPos.y = 0;\n                    }\n                    else if (cursorPos.y > rect.bottom)\n                    {\n                        SendMessage(hwnd, WM_VSCROLL, SB_LINEDOWN, 0);\n                        cursorPos.y = rect.bottom - 1;\n                    }\n                }\n\n                oldSelEnd = context->SelEnd;\n                PhpHexEditCalculatePosition(hwnd, context, cursorPos.x, cursorPos.y, &point);\n\n                if (point.x > -1)\n                {\n                    context->SelEnd = context->CurrentAddress;\n\n                    if (context->CurrentMode == EDIT_HIGH || context->CurrentMode == EDIT_LOW)\n                        context->SelEnd++;\n                }\n\n                if (PhpHexEditHasSelected(context))\n                    DestroyCaret();\n\n                if (context->SelEnd != oldSelEnd)\n                    REDRAW_WINDOW(hwnd);\n            }\n        }\n        break;\n    case WM_CHAR:\n        {\n            ULONG c = (ULONG)wParam;\n\n            if (!context->Data)\n                goto DefaultHandler;\n            if (c == '\\t')\n                goto DefaultHandler;\n\n            if (GetKeyState(VK_CONTROL) < 0)\n            {\n                switch (c)\n                {\n                case 0x3:\n                    if (PhpHexEditHasSelected(context))\n                        PhpHexEditCopyEdit(hwnd, context);\n                    goto DefaultHandler;\n                case 0x16:\n                    PhpHexEditPasteEdit(hwnd, context);\n                    goto DefaultHandler;\n                case 0x18:\n                    if (PhpHexEditHasSelected(context))\n                        PhpHexEditCutEdit(hwnd, context);\n                    goto DefaultHandler;\n                case 0x1a:\n                    PhpHexEditUndoEdit(hwnd, context);\n                    goto DefaultHandler;\n                }\n            }\n\n            // Disallow editing beyond the end of the data.\n            if (context->CurrentAddress >= context->Length)\n                goto DefaultHandler;\n\n            if (c == 0x8)\n            {\n                if (context->CurrentAddress != 0)\n                {\n                    context->CurrentAddress--;\n                    PhpHexEditSelDelete(hwnd, context, context->CurrentAddress, context->CurrentAddress + 1);\n                    PhpHexEditRepositionCaret(hwnd, context, context->CurrentAddress);\n                    REDRAW_WINDOW(hwnd);\n                }\n\n                goto DefaultHandler;\n            }\n\n            PhpHexEditSetSel(hwnd, context, -1, -1);\n\n            switch (context->CurrentMode)\n            {\n            case EDIT_NONE:\n                goto DefaultHandler;\n            case EDIT_HIGH:\n            case EDIT_LOW:\n                if ((c >= '0' && c <= '9') || (c >= 'a' && c <= 'f'))\n                {\n                    ULONG b = c - '0';\n\n                    if (b > 9)\n                        b = 10 + c - 'a';\n\n                    if (context->CurrentMode == EDIT_HIGH)\n                    {\n                        context->Data[context->CurrentAddress] =\n                            (UCHAR)((context->Data[context->CurrentAddress] & 0x0f) | (b << 4));\n                    }\n                    else\n                    {\n                        context->Data[context->CurrentAddress] =\n                            (UCHAR)((context->Data[context->CurrentAddress] & 0xf0) | b);\n                    }\n\n                    PhpHexEditMove(hwnd, context, 1, 0);\n                }\n                break;\n            case EDIT_ASCII:\n                context->Data[context->CurrentAddress] = (UCHAR)c;\n                PhpHexEditMove(hwnd, context, 1, 0);\n                break;\n            }\n\n            REDRAW_WINDOW(hwnd);\n        }\n        break;\n    case WM_KEYDOWN:\n        {\n            ULONG vk = (ULONG)wParam;\n            BOOLEAN shift = GetKeyState(VK_SHIFT) < 0;\n            BOOLEAN oldNoAddressChange = context->NoAddressChange;\n            BOOLEAN noScrollIntoView = FALSE;\n\n            context->NoAddressChange = TRUE;\n\n            switch (vk)\n            {\n            case VK_DOWN:\n                if (context->CurrentMode != EDIT_NONE)\n                {\n                    if (shift)\n                    {\n                        if (!PhpHexEditHasSelected(context))\n                            context->SelStart = context->CurrentAddress;\n\n                        PhpHexEditMove(hwnd, context, 0, 1);\n                        context->SelEnd = context->CurrentAddress;\n\n                        if (context->CurrentMode == EDIT_HIGH || context->CurrentMode == EDIT_LOW)\n                            context->SelEnd++;\n\n                        REDRAW_WINDOW(hwnd);\n                        break;\n                    }\n                    else\n                    {\n                        PhpHexEditSetSel(hwnd, context, -1, -1);\n                    }\n\n                    PhpHexEditMove(hwnd, context, 0, 1);\n                    noScrollIntoView = TRUE;\n                }\n                else\n                {\n                    PhpHexEditMove(hwnd, context, 0, 1);\n                }\n                break;\n            case VK_UP:\n                if (context->CurrentMode != EDIT_NONE)\n                {\n                    if (shift)\n                    {\n                        if (!PhpHexEditHasSelected(context))\n                            context->SelStart = context->CurrentAddress;\n\n                        PhpHexEditMove(hwnd, context, 0, -1);\n                        context->SelEnd = context->CurrentAddress;\n\n                        REDRAW_WINDOW(hwnd);\n                        break;\n                    }\n                    else\n                    {\n                        PhpHexEditSetSel(hwnd, context, -1, -1);\n                    }\n\n                    PhpHexEditMove(hwnd, context, 0, -1);\n                    noScrollIntoView = TRUE;\n                }\n                else\n                {\n                    PhpHexEditMove(hwnd, context, 0, -1);\n                }\n                break;\n            case VK_LEFT:\n                if (context->CurrentMode != EDIT_NONE)\n                {\n                    if (shift)\n                    {\n                        if (!PhpHexEditHasSelected(context))\n                            context->SelStart = context->CurrentAddress;\n\n                        PhpHexEditMove(hwnd, context, -1, 0);\n                        context->SelEnd = context->CurrentAddress;\n\n                        REDRAW_WINDOW(hwnd);\n                        break;\n                    }\n                    else\n                    {\n                        PhpHexEditSetSel(hwnd, context, -1, -1);\n                    }\n\n                    PhpHexEditMove(hwnd, context, -1, 0);\n                    noScrollIntoView = TRUE;\n                }\n                break;\n            case VK_RIGHT:\n                if (context->CurrentMode != EDIT_NONE)\n                {\n                    if (shift)\n                    {\n                        if (!PhpHexEditHasSelected(context))\n                            context->SelStart = context->CurrentAddress;\n\n                        PhpHexEditMove(hwnd, context, 1, 0);\n                        context->SelEnd = context->CurrentAddress;\n\n                        if (context->CurrentMode == EDIT_HIGH || context->CurrentMode == EDIT_LOW)\n                            context->SelEnd++;\n\n                        REDRAW_WINDOW(hwnd);\n                        break;\n                    }\n                    else\n                    {\n                        PhpHexEditSetSel(hwnd, context, -1, -1);\n                    }\n\n                    PhpHexEditMove(hwnd, context, 1, 0);\n                    noScrollIntoView = TRUE;\n                }\n                break;\n            case VK_PRIOR:\n                if (shift)\n                {\n                    if (!PhpHexEditHasSelected(context))\n                        context->SelStart = context->CurrentAddress;\n\n                    SendMessage(hwnd, WM_VSCROLL, SB_PAGEUP, 0);\n                    PhpHexEditMove(hwnd, context, 0, 0);\n                    context->SelEnd = context->CurrentAddress;\n\n                    REDRAW_WINDOW(hwnd);\n                    break;\n                }\n                else\n                {\n                    PhpHexEditSetSel(hwnd, context, -1, -1);\n                }\n\n                SendMessage(hwnd, WM_VSCROLL, SB_PAGEUP, 0);\n                PhpHexEditMove(hwnd, context, 0, 0);\n                noScrollIntoView = TRUE;\n                break;\n            case VK_NEXT:\n                if (shift)\n                {\n                    if (!PhpHexEditHasSelected(context))\n                        context->SelStart = context->CurrentAddress;\n\n                    SendMessage(hwnd, WM_VSCROLL, SB_PAGEDOWN, 0);\n                    PhpHexEditMove(hwnd, context, 0, 0);\n                    context->SelEnd = context->CurrentAddress;\n\n                    REDRAW_WINDOW(hwnd);\n                    break;\n                }\n                else\n                {\n                    PhpHexEditSetSel(hwnd, context, -1, -1);\n                }\n\n                SendMessage(hwnd, WM_VSCROLL, SB_PAGEDOWN, 0);\n                PhpHexEditMove(hwnd, context, 0, 0);\n                noScrollIntoView = TRUE;\n                break;\n            case VK_HOME:\n                if (shift)\n                {\n                    if (!PhpHexEditHasSelected(context))\n                        context->SelStart = context->CurrentAddress;\n\n                    if (GetKeyState(VK_CONTROL) < 0)\n                    {\n                        SendMessage(hwnd, WM_VSCROLL, SB_THUMBTRACK, 0);\n                    }\n                    else\n                    {\n                        // Round down.\n                        context->CurrentAddress /= context->BytesPerRow;\n                        context->CurrentAddress *= context->BytesPerRow;\n                    }\n\n                    PhpHexEditMove(hwnd, context, 0, 0);\n                    context->SelEnd = context->CurrentAddress;\n\n                    REDRAW_WINDOW(hwnd);\n                    break;\n                }\n                else\n                {\n                    PhpHexEditSetSel(hwnd, context, -1, -1);\n                }\n\n                if (GetKeyState(VK_CONTROL) < 0)\n                {\n                    SendMessage(hwnd, WM_VSCROLL, SB_THUMBTRACK, 0);\n                    context->CurrentAddress = 0;\n                }\n                else\n                {\n                    // Round down.\n                    context->CurrentAddress /= context->BytesPerRow;\n                    context->CurrentAddress *= context->BytesPerRow;\n                }\n\n                PhpHexEditMove(hwnd, context, 0, 0);\n                noScrollIntoView = TRUE;\n\n                break;\n            case VK_END:\n                if (shift)\n                {\n                    if (!PhpHexEditHasSelected(context))\n                        context->SelStart = context->CurrentAddress;\n\n                    if (GetKeyState(VK_CONTROL) < 0)\n                    {\n                        context->CurrentAddress = context->Length - 1;\n                        SendMessage(hwnd, WM_VSCROLL,\n                            MAKEWPARAM(SB_THUMBTRACK, ((context->Length + (context->BytesPerRow / 2)) / context->BytesPerRow) - context->LinesPerPage),\n                            0);\n                    }\n                    else\n                    {\n                        context->CurrentAddress /= context->BytesPerRow;\n                        context->CurrentAddress *= context->BytesPerRow;\n                        context->CurrentAddress += context->BytesPerRow - 1;\n\n                        if (context->CurrentAddress > context->Length)\n                            context->CurrentAddress = context->Length - 1;\n                    }\n\n                    PhpHexEditMove(hwnd, context, 0, 0);\n                    context->SelEnd = context->CurrentAddress;\n\n                    REDRAW_WINDOW(hwnd);\n                    break;\n                }\n                else\n                {\n                    PhpHexEditSetSel(hwnd, context, -1, -1);\n                }\n\n                if (GetKeyState(VK_CONTROL) < 0)\n                {\n                    context->CurrentAddress = context->Length - 1;\n\n                    if (context->HalfPage)\n                    {\n                        SendMessage(hwnd, WM_VSCROLL, 0, 0);\n                    }\n                    else\n                    {\n                        SendMessage(hwnd, WM_VSCROLL,\n                            MAKEWPARAM(SB_THUMBTRACK, ((context->Length + (context->BytesPerRow / 2)) / context->BytesPerRow) - context->LinesPerPage),\n                            0);\n                    }\n                }\n                else\n                {\n                    context->CurrentAddress /= context->BytesPerRow;\n                    context->CurrentAddress *= context->BytesPerRow;\n                    context->CurrentAddress += context->BytesPerRow - 1;\n\n                    if (context->CurrentAddress > context->Length)\n                        context->CurrentAddress = context->Length - 1;\n                }\n\n                PhpHexEditMove(hwnd, context, 0, 0);\n                noScrollIntoView = TRUE;\n\n                break;\n            case VK_INSERT:\n                PhpHexEditSelInsert(hwnd, context, context->CurrentAddress,\n                    max(1, context->SelEnd - context->SelStart));\n                REDRAW_WINDOW(hwnd);\n                break;\n            case VK_DELETE:\n                if (PhpHexEditHasSelected(context))\n                {\n                    PhpHexEditClearEdit(hwnd, context);\n                }\n                else\n                {\n                   PhpHexEditSelDelete(hwnd, context, context->CurrentAddress, context->CurrentAddress + 1);\n                   REDRAW_WINDOW(hwnd);\n                }\n                break;\n            case '\\t':\n                switch (context->CurrentMode)\n                {\n                case EDIT_NONE:\n                    context->CurrentMode = EDIT_HIGH;\n                    break;\n                case EDIT_HIGH:\n                case EDIT_LOW:\n                    context->CurrentMode = EDIT_ASCII;\n                    break;\n                case EDIT_ASCII:\n                    context->CurrentMode = EDIT_HIGH;\n                    break;\n                }\n\n                PhpHexEditMove(hwnd, context, 0, 0);\n\n                break;\n            }\n\n            // Scroll into view if not in view.\n            if (\n                !noScrollIntoView &&\n                (context->CurrentAddress < context->TopIndex ||\n                context->CurrentAddress >= context->TopIndex + context->LinesPerPage * context->BytesPerRow)\n                )\n            {\n                PhpHexEditScrollTo(hwnd, context, context->CurrentAddress);\n            }\n\n            context->NoAddressChange = oldNoAddressChange;\n        }\n        break;\n    case HEM_SETBUFFER:\n        {\n            PhpHexEditSetBuffer(hwnd, context, (PUCHAR)lParam, (ULONG)wParam);\n        }\n        return TRUE;\n    case HEM_SETDATA:\n        {\n            PhpHexEditSetData(hwnd, context, (PUCHAR)lParam, (ULONG)wParam);\n        }\n        return TRUE;\n    case HEM_GETBUFFER:\n        {\n            PULONG length = (PULONG)wParam;\n\n            if (length)\n                *length = context->Length;\n\n            return (LPARAM)context->Data;\n        }\n    case HEM_SETSEL:\n        {\n            LONG selStart = (LONG)wParam;\n            LONG selEnd = (LONG)lParam;\n\n            if (selStart <= 0)\n                return FALSE;\n            if (selEnd > context->Length)\n                return FALSE;\n\n            PhpHexEditScrollTo(hwnd, context, selStart);\n            PhpHexEditSetSel(hwnd, context, selStart, selEnd);\n            PhpHexEditRepositionCaret(hwnd, context, selStart);\n            REDRAW_WINDOW(hwnd);\n        }\n        return TRUE;\n    case HEM_SETEDITMODE:\n        {\n            context->CurrentMode = (LONG)wParam;\n            REDRAW_WINDOW(hwnd);\n        }\n        return TRUE;\n    case HEM_SETBYTESPERROW:\n        {\n            LONG bytesPerRow = (LONG)wParam;\n\n            if (bytesPerRow >= 4)\n            {\n                context->BytesPerRow = bytesPerRow;\n                PhpHexEditUpdateMetrics(hwnd, context, TRUE, NULL);\n                PhpHexEditUpdateScrollbars(hwnd, context);\n                PhpHexEditScrollTo(hwnd, context, context->CurrentAddress);\n                PhpHexEditRepositionCaret(hwnd, context, context->CurrentAddress);\n                REDRAW_WINDOW(hwnd);\n            }\n        }\n        return TRUE;\n    }\n\nDefaultHandler:\n    return DefWindowProc(hwnd, uMsg, wParam, lParam);\n}\n\nFORCEINLINE VOID PhpPrintHex(\n    _In_ HDC hdc,\n    _In_ PPHP_HEXEDIT_CONTEXT Context,\n    _Inout_ PWCHAR Buffer,\n    _In_ UCHAR Byte,\n    _Inout_ PLONG X,\n    _Inout_ PLONG Y,\n    _Inout_ PULONG N\n    )\n{\n    PWCHAR p = Buffer;\n\n    TO_HEX(p, Byte);\n    *p++ = ' ';\n    TextOut(hdc, *X, *Y, Buffer, 3);\n    *X += Context->NullWidth * 3;\n    (*N)++;\n\n    if (*N == Context->BytesPerRow)\n    {\n        *N = 0;\n        *X = Context->HexOffset;\n        *Y += Context->LineHeight;\n    }\n}\n\nFORCEINLINE VOID PhpPrintAscii(\n    _In_ HDC hdc,\n    _In_ PPHP_HEXEDIT_CONTEXT Context,\n    _In_ UCHAR Byte,\n    _Inout_ PLONG X,\n    _Inout_ PLONG Y,\n    _Inout_ PULONG N\n    )\n{\n    WCHAR c;\n\n    c = IS_PRINTABLE(Byte) ? Byte : '.';\n    TextOut(hdc, *X, *Y, &c, 1);\n    *X += Context->NullWidth;\n    (*N)++;\n\n    if (*N == Context->BytesPerRow)\n    {\n        *N = 0;\n        *X = Context->AsciiOffset;\n        *Y += Context->LineHeight;\n    }\n}\n\nFORCEINLINE COLORREF GetLighterHighlightColor(\n    VOID\n    )\n{\n    COLORREF color;\n    UCHAR r;\n    UCHAR g;\n    UCHAR b;\n\n    color = GetSysColor(COLOR_HIGHLIGHT);\n    r = (UCHAR)color;\n    g = (UCHAR)(color >> 8);\n    b = (UCHAR)(color >> 16);\n\n    if (r <= 255 - 64)\n        r += 64;\n    else\n        r = 255;\n\n    if (g <= 255 - 64)\n        g += 64;\n    else\n        g = 255;\n\n    if (b <= 255 - 64)\n        b += 64;\n    else\n        b = 255;\n\n    return RGB(r, g, b);\n}\n\nVOID PhpHexEditUpdateMetrics(\n    _In_ HWND hwnd,\n    _In_ PPHP_HEXEDIT_CONTEXT Context,\n    _In_ BOOLEAN UpdateLineHeight,\n    _In_opt_ HDC hdc\n    )\n{\n    BOOLEAN freeHdc = FALSE;\n    RECT clientRect;\n    SIZE size;\n\n    if (!hdc && UpdateLineHeight)\n    {\n        hdc = CreateCompatibleDC(hdc);\n        SelectObject(hdc, Context->Font);\n        freeHdc = TRUE;\n    }\n\n    GetClientRect(hwnd, &clientRect);\n\n    if (UpdateLineHeight)\n    {\n        GetCharWidth(hdc, '0', '0', &Context->NullWidth);\n        GetTextExtentPoint32(hdc, L\"0\", 1, &size);\n        Context->LineHeight = size.cy;\n    }\n\n    Context->HexOffset = Context->ShowAddress ? (Context->AddressIsWide ? Context->NullWidth * 9 : Context->NullWidth * 5) : 0;\n    Context->AsciiOffset = Context->HexOffset + (Context->ShowHex ? (Context->BytesPerRow * 3 * Context->NullWidth) : 0);\n\n    if (Context->LineHeight != 0)\n    {\n        Context->LinesPerPage = clientRect.bottom / Context->LineHeight;\n        Context->HalfPage = FALSE;\n\n        if (Context->LinesPerPage * Context->BytesPerRow > Context->Length)\n        {\n            Context->LinesPerPage = (Context->Length + Context->BytesPerRow / 2) / Context->BytesPerRow;\n\n            if (Context->Length % Context->BytesPerRow != 0)\n            {\n                Context->HalfPage = TRUE;\n                Context->LinesPerPage++;\n            }\n        }\n    }\n\n    if (freeHdc && hdc)\n        DeleteDC(hdc);\n}\n\nVOID PhpHexEditOnPaint(\n    _In_ HWND hwnd,\n    _In_ PPHP_HEXEDIT_CONTEXT Context,\n    _In_ PAINTSTRUCT *PaintStruct,\n    _In_ HDC hdc\n    )\n{\n    RECT clientRect;\n    HDC bufferDc;\n    HBITMAP bufferBitmap;\n    HBITMAP oldBufferBitmap;\n    LONG height;\n    LONG x;\n    LONG y;\n    LONG i;\n    ULONG requiredBufferLength;\n    PWCHAR buffer;\n\n    GetClientRect(hwnd, &clientRect);\n\n    bufferDc = CreateCompatibleDC(hdc);\n    bufferBitmap = CreateCompatibleBitmap(hdc, clientRect.right, clientRect.bottom);\n    oldBufferBitmap = SelectObject(bufferDc, bufferBitmap);\n\n    SetDCBrushColor(bufferDc, GetSysColor(COLOR_WINDOW));\n    FillRect(bufferDc, &clientRect, GetStockObject(DC_BRUSH));\n    SelectObject(bufferDc, Context->Font);\n    SetBoundsRect(bufferDc, &clientRect, DCB_DISABLE);\n\n    requiredBufferLength = (max(8, Context->BytesPerRow * 3) + 1) * sizeof(WCHAR);\n\n    if (Context->CharBufferLength < requiredBufferLength)\n    {\n        if (Context->CharBuffer)\n            PhFree(Context->CharBuffer);\n\n        Context->CharBuffer = PhAllocate(requiredBufferLength);\n        Context->CharBufferLength = requiredBufferLength;\n        buffer = Context->CharBuffer;\n    }\n\n    buffer = Context->CharBuffer;\n\n    if (Context->Data)\n    {\n        // Get character dimensions.\n        if (Context->Update)\n        {\n            PhpHexEditUpdateMetrics(hwnd, Context, TRUE, bufferDc);\n            Context->Update = FALSE;\n            PhpHexEditUpdateScrollbars(hwnd, Context);\n        }\n\n        height = (clientRect.bottom + Context->LineHeight - 1) / Context->LineHeight * Context->LineHeight; // round up to height\n\n        if (Context->ShowAddress)\n        {\n            PH_FORMAT format;\n            ULONG w;\n            RECT rect;\n\n            PhInitFormatX(&format, 0);\n            format.Type |= FormatPadZeros;\n            format.Width = Context->AddressIsWide ? 8 : 4;\n\n            w = Context->AddressIsWide ? 8 : 4;\n\n            rect = clientRect;\n            rect.left = Context->AddressOffset;\n            rect.top = 0;\n\n            for (i = Context->TopIndex; i < Context->Length && rect.top < height; i += Context->BytesPerRow)\n            {\n                format.u.Int32 = i;\n                PhFormatToBuffer(&format, 1, buffer, requiredBufferLength, NULL);\n                DrawText(bufferDc, buffer, w, &rect, DT_LEFT | DT_TOP | DT_SINGLELINE | DT_NOPREFIX | DT_NOCLIP);\n                rect.top += Context->LineHeight;\n            }\n        }\n\n        if (Context->ShowHex)\n        {\n            RECT rect;\n            LONG n = 0;\n\n            x = Context->HexOffset;\n            y = 0;\n            rect = clientRect;\n            rect.left = x;\n            rect.top = 0;\n\n            if (Context->SelStart != -1)\n            {\n                COLORREF highlightColor;\n                LONG selStart;\n                LONG selEnd;\n\n                if (Context->CurrentMode == EDIT_HIGH || Context->CurrentMode == EDIT_LOW)\n                    highlightColor = GetSysColor(COLOR_HIGHLIGHT);\n                else\n                    highlightColor = GetLighterHighlightColor();\n\n                selStart = Context->SelStart;\n                selEnd = Context->SelEnd;\n\n                if (selStart > selEnd)\n                {\n                    ULONG t;\n\n                    t = selEnd;\n                    selEnd = selStart;\n                    selStart = t;\n                }\n\n                if (selStart >= Context->Length)\n                    selStart = Context->Length - 1;\n                if (selEnd > Context->Length)\n                    selEnd = Context->Length;\n\n                // Bytes before the selection\n\n                for (i = Context->TopIndex; i < selStart && y < height; i++)\n                {\n                    PhpPrintHex(bufferDc, Context, buffer, Context->Data[i], &x, &y, &n);\n                }\n\n                // Bytes in the selection\n\n                SetTextColor(bufferDc, GetSysColor(COLOR_HIGHLIGHTTEXT));\n                SetBkColor(bufferDc, highlightColor);\n\n                for (; i < selEnd && i < Context->Length && y < height; i++)\n                {\n                    PhpPrintHex(bufferDc, Context, buffer, Context->Data[i], &x, &y, &n);\n                }\n\n                // Bytes after the selection\n\n                SetTextColor(bufferDc, GetSysColor(COLOR_WINDOWTEXT));\n                SetBkColor(bufferDc, GetSysColor(COLOR_WINDOW));\n\n                for (; i < Context->Length && y < height; i++)\n                {\n                    PhpPrintHex(bufferDc, Context, buffer, Context->Data[i], &x, &y, &n);\n                }\n            }\n            else\n            {\n                i = Context->TopIndex;\n\n                while (i < Context->Length && rect.top < height)\n                {\n                    PWCHAR p = buffer;\n\n                    for (n = 0; n < Context->BytesPerRow && i < Context->Length; n++)\n                    {\n                        TO_HEX(p, Context->Data[i]);\n                        *p++ = ' ';\n                        i++;\n                    }\n\n                    while (n < Context->BytesPerRow)\n                    {\n                        p[0] = ' ';\n                        p[1] = ' ';\n                        p[2] = ' ';\n                        p += 3;\n                        n++;\n                    }\n\n                    DrawText(bufferDc, buffer, Context->BytesPerRow * 3, &rect, DT_LEFT | DT_TOP | DT_SINGLELINE | DT_NOPREFIX | DT_NOCLIP);\n                    rect.top += Context->LineHeight;\n                }\n            }\n        }\n\n        if (Context->ShowAscii)\n        {\n            RECT rect;\n            LONG n = 0;\n\n            x = Context->AsciiOffset;\n            y = 0;\n            rect = clientRect;\n            rect.left = x;\n            rect.top = 0;\n\n            if (Context->SelStart != -1)\n            {\n                COLORREF highlightColor;\n                LONG selStart;\n                LONG selEnd;\n\n                if (Context->CurrentMode == EDIT_ASCII)\n                    highlightColor = GetSysColor(COLOR_HIGHLIGHT);\n                else\n                    highlightColor = GetLighterHighlightColor();\n\n                selStart = Context->SelStart;\n                selEnd = Context->SelEnd;\n\n                if (selStart > selEnd)\n                {\n                    LONG t;\n\n                    t = selEnd;\n                    selEnd = selStart;\n                    selStart = t;\n                }\n\n                if (selStart >= Context->Length)\n                    selStart = Context->Length - 1;\n                if (selEnd > Context->Length)\n                    selEnd = Context->Length;\n\n                // Bytes before the selection\n\n                for (i = Context->TopIndex; i < selStart && y < height; i++)\n                {\n                    PhpPrintAscii(bufferDc, Context, Context->Data[i], &x, &y, &n);\n                }\n\n                // Bytes in the selection\n\n                SetTextColor(bufferDc, GetSysColor(COLOR_HIGHLIGHTTEXT));\n                SetBkColor(bufferDc, highlightColor);\n\n                for (; i < selEnd && i < Context->Length && y < height; i++)\n                {\n                    PhpPrintAscii(bufferDc, Context, Context->Data[i], &x, &y, &n);\n                }\n\n                // Bytes after the selection\n\n                SetTextColor(bufferDc, GetSysColor(COLOR_WINDOWTEXT));\n                SetBkColor(bufferDc, GetSysColor(COLOR_WINDOW));\n\n                for (; i < Context->Length && y < height; i++)\n                {\n                    PhpPrintAscii(bufferDc, Context, Context->Data[i], &x, &y, &n);\n                }\n            }\n            else\n            {\n                i = Context->TopIndex;\n\n                while (i < Context->Length && rect.top < height)\n                {\n                    PWCHAR p = buffer;\n\n                    for (n = 0; n < Context->BytesPerRow && i < Context->Length; n++)\n                    {\n                        *p++ = IS_PRINTABLE(Context->Data[i]) ? Context->Data[i] : '.'; // 1\n                        i++;\n                    }\n\n                    DrawText(bufferDc, buffer, n, &rect, DT_LEFT | DT_TOP | DT_SINGLELINE | DT_NOPREFIX | DT_NOCLIP);\n                    rect.top += Context->LineHeight;\n                }\n            }\n        }\n    }\n\n    BitBlt(hdc, 0, 0, clientRect.right, clientRect.bottom, bufferDc, 0, 0, SRCCOPY);\n    SelectObject(bufferDc, oldBufferBitmap);\n    DeleteObject(bufferBitmap);\n    DeleteDC(bufferDc);\n}\n\nVOID PhpHexEditUpdateScrollbars(\n    _In_ HWND hwnd,\n    _In_ PPHP_HEXEDIT_CONTEXT Context\n    )\n{\n    SCROLLINFO si = { sizeof(si) };\n\n    si.fMask = SIF_ALL;\n    si.nMin = 0;\n    si.nMax = Context->Length / Context->BytesPerRow;\n    si.nPage = Context->LinesPerPage;\n    si.nPos = Context->TopIndex / Context->BytesPerRow;\n    SetScrollInfo(hwnd, SB_VERT, &si, TRUE);\n\n    if (si.nMax > (LONG)si.nPage - 1)\n        EnableScrollBar(hwnd, SB_VERT, ESB_ENABLE_BOTH);\n\n    // No horizontal scrollbar please.\n    /*si.nMin = 0;\n    si.nMax = ((Context->ShowAddress ? (Context->AddressIsWide ? 8 : 4) : 0) +\n        (Context->ShowHex ? Context->BytesPerRow * 3 : 0) +\n        (Context->ShowAscii ? Context->BytesPerRow : 0)) * Context->NullWidth;\n    si.nPage = 1;\n    si.nPos = 0;\n    SetScrollInfo(hwnd, SB_HORZ, &si, TRUE);*/\n}\n\nVOID PhpHexEditCreateAddressCaret(\n    _In_ HWND hwnd,\n    _In_ PPHP_HEXEDIT_CONTEXT Context\n    )\n{\n    DestroyCaret();\n    CreateCaret(hwnd, NULL, Context->NullWidth * (Context->AddressIsWide ? 8 : 4), Context->LineHeight);\n}\n\nVOID PhpHexEditCreateEditCaret(\n    _In_ HWND hwnd,\n    _In_ PPHP_HEXEDIT_CONTEXT Context\n    )\n{\n    DestroyCaret();\n    CreateCaret(hwnd, NULL, Context->NullWidth, Context->LineHeight);\n}\n\nVOID PhpHexEditRepositionCaret(\n    _In_ HWND hwnd,\n    _In_ PPHP_HEXEDIT_CONTEXT Context,\n    _In_ LONG Position\n    )\n{\n    ULONG x;\n    ULONG y;\n    RECT rect;\n\n    x = (Position - Context->TopIndex) % Context->BytesPerRow;\n    y = (Position - Context->TopIndex) / Context->BytesPerRow;\n\n    switch (Context->CurrentMode)\n    {\n    case EDIT_NONE:\n        PhpHexEditCreateAddressCaret(hwnd, Context);\n        x = 0;\n        break;\n    case EDIT_HIGH:\n        PhpHexEditCreateEditCaret(hwnd, Context);\n        x *= Context->NullWidth * 3;\n        x += Context->HexOffset;\n        break;\n    case EDIT_LOW:\n        PhpHexEditCreateEditCaret(hwnd, Context);\n        x *= Context->NullWidth * 3;\n        x += Context->NullWidth;\n        x += Context->HexOffset;\n        break;\n    case EDIT_ASCII:\n        PhpHexEditCreateEditCaret(hwnd, Context);\n        x *= Context->NullWidth;\n        x += Context->AsciiOffset;\n        break;\n    }\n\n    Context->EditPosition.x = x;\n    Context->EditPosition.y = y * Context->LineHeight;\n\n    GetClientRect(hwnd, &rect);\n\n    if (PtInRect(&rect, Context->EditPosition))\n    {\n        SetCaretPos(Context->EditPosition.x, Context->EditPosition.y);\n        ShowCaret(hwnd);\n    }\n}\n\nVOID PhpHexEditCalculatePosition(\n    _In_ HWND hwnd,\n    _In_ PPHP_HEXEDIT_CONTEXT Context,\n    _In_ LONG X,\n    _In_ LONG Y,\n    _Out_ POINT *Point\n    )\n{\n    LONG xp;\n\n    Y /= Context->LineHeight;\n\n    if (Y < 0 || Y >= Context->LinesPerPage)\n    {\n        Point->x = -1;\n        Point->y = -1;\n        return;\n    }\n\n    if (Y * Context->BytesPerRow >= Context->Length)\n    {\n        Point->x = -1;\n        Point->y = -1;\n        return;\n    }\n\n    X += Context->NullWidth;\n    X /= Context->NullWidth;\n\n    if (Context->ShowAddress && X <= (Context->AddressIsWide ? 8 : 4))\n    {\n        Context->CurrentAddress = Context->TopIndex + Context->BytesPerRow * Y;\n        Context->CurrentMode = EDIT_NONE;\n\n        Point->x = 0;\n        Point->y = Y;\n        return;\n    }\n\n    xp = Context->HexOffset / Context->NullWidth + Context->BytesPerRow * 3;\n\n    if (Context->ShowHex && X < xp)\n    {\n        if (X % 3)\n            X--;\n\n        Context->CurrentAddress = Context->TopIndex +\n            Context->BytesPerRow * Y +\n            (X - (Context->HexOffset / Context->NullWidth)) / 3;\n        Context->CurrentMode = ((X % 3) & 1) ? EDIT_LOW : EDIT_HIGH;\n\n        Point->x = X;\n        Point->y = Y;\n        return;\n    }\n\n    X--; // fix selection problem\n\n    xp = Context->AsciiOffset / Context->NullWidth + Context->BytesPerRow;\n\n    if (Context->ShowAscii && X * Context->NullWidth >= Context->AsciiOffset && X <= xp)\n    {\n        Context->CurrentAddress = Context->TopIndex +\n            Context->BytesPerRow * Y +\n            (X - (Context->AsciiOffset / Context->NullWidth));\n        Context->CurrentMode = EDIT_ASCII;\n\n        Point->x = X;\n        Point->y = Y;\n        return;\n    }\n\n    Point->x = -1;\n    Point->y = -1;\n}\n\nVOID PhpHexEditMove(\n    _In_ HWND hwnd,\n    _In_ PPHP_HEXEDIT_CONTEXT Context,\n    _In_ LONG X,\n    _In_ LONG Y\n    )\n{\n    switch (Context->CurrentMode)\n    {\n    case EDIT_NONE:\n        Context->CurrentAddress += Y * Context->BytesPerRow;\n        break;\n    case EDIT_HIGH:\n        if (X != 0)\n            Context->CurrentMode = EDIT_LOW;\n        if (X == -1)\n            Context->CurrentAddress--;\n        Context->CurrentAddress += Y * Context->BytesPerRow;\n        break;\n    case EDIT_LOW:\n        if (X != 0)\n            Context->CurrentMode = EDIT_HIGH;\n        if (X == 1)\n            Context->CurrentAddress++;\n        Context->CurrentAddress += Y * Context->BytesPerRow;\n        break;\n    case EDIT_ASCII:\n        Context->CurrentAddress += X;\n        Context->CurrentAddress += Y * Context->BytesPerRow;\n        break;\n    }\n\n    if (Context->CurrentAddress < 0)\n        Context->CurrentAddress = 0;\n\n    if (Context->CurrentAddress >= Context->Length)\n    {\n        Context->CurrentAddress -= X;\n        Context->CurrentAddress -= Y * Context->BytesPerRow;\n    }\n\n    Context->NoAddressChange = TRUE;\n\n    if (Context->CurrentAddress < Context->TopIndex)\n        SendMessage(hwnd, WM_VSCROLL, SB_LINEUP, 0);\n    if (Context->CurrentAddress >= Context->TopIndex + Context->LinesPerPage * Context->BytesPerRow)\n        SendMessage(hwnd, WM_VSCROLL, SB_LINEDOWN, 0);\n\n    Context->NoAddressChange = FALSE;\n    PhpHexEditRepositionCaret(hwnd, Context, Context->CurrentAddress);\n}\n\nVOID PhpHexEditSetSel(\n    _In_ HWND hwnd,\n    _In_ PPHP_HEXEDIT_CONTEXT Context,\n    _In_ LONG S,\n    _In_ LONG E\n    )\n{\n    DestroyCaret();\n    Context->SelStart = S;\n    Context->SelEnd = E;\n    REDRAW_WINDOW(hwnd);\n\n    if (S != -1 && E != -1)\n    {\n        Context->CurrentAddress = S;\n    }\n    else\n    {\n        if (Context->EditPosition.x == 0 && Context->ShowAddress)\n            PhpHexEditCreateAddressCaret(hwnd, Context);\n        else\n            PhpHexEditCreateEditCaret(hwnd, Context);\n\n        SetCaretPos(Context->EditPosition.x, Context->EditPosition.y);\n        ShowCaret(hwnd);\n    }\n}\n\nVOID PhpHexEditScrollTo(\n    _In_ HWND hwnd,\n    _In_ PPHP_HEXEDIT_CONTEXT Context,\n    _In_ LONG Position\n    )\n{\n    if (Position < Context->TopIndex || Position > Context->TopIndex + Context->LinesPerPage * Context->BytesPerRow)\n    {\n        Context->TopIndex = Position / Context->BytesPerRow * Context->BytesPerRow; // round down\n        Context->TopIndex -= Context->LinesPerPage / 3 * Context->BytesPerRow;\n\n        if (Context->TopIndex < 0)\n            Context->TopIndex = 0;\n\n        if (Context->Length >= Context->LinesPerPage * Context->BytesPerRow)\n        {\n            if (Context->TopIndex > Context->Length - Context->LinesPerPage * Context->BytesPerRow)\n                Context->TopIndex = Context->Length - Context->LinesPerPage * Context->BytesPerRow;\n        }\n\n        PhpHexEditUpdateScrollbars(hwnd, Context);\n        REDRAW_WINDOW(hwnd);\n    }\n}\n\nVOID PhpHexEditClearEdit(\n    _In_ HWND hwnd,\n    _In_ PPHP_HEXEDIT_CONTEXT Context\n    )\n{\n    if (Context->AllowLengthChange)\n    {\n        Context->CurrentAddress = Context->SelStart;\n        PhpHexEditSelDelete(hwnd, Context, Context->SelStart, Context->SelEnd);\n        PhpHexEditRepositionCaret(hwnd, Context, Context->CurrentAddress);\n        REDRAW_WINDOW(hwnd);\n    }\n}\n\nVOID PhpHexEditCopyEdit(\n    _In_ HWND hwnd,\n    _In_ PPHP_HEXEDIT_CONTEXT Context\n    )\n{\n    if (OpenClipboard(hwnd))\n    {\n        EmptyClipboard();\n        PhpHexEditNormalizeSel(hwnd, Context);\n\n        if (Context->CurrentMode != EDIT_ASCII)\n        {\n            ULONG length = Context->SelEnd - Context->SelStart;\n            HGLOBAL binaryMemory;\n            HGLOBAL hexMemory;\n\n            binaryMemory = GlobalAlloc(GMEM_MOVEABLE | GMEM_ZEROINIT, length);\n\n            if (binaryMemory)\n            {\n                PUCHAR p = GlobalLock(binaryMemory);\n                memcpy(p, &Context->Data[Context->SelStart], length);\n                GlobalUnlock(binaryMemory);\n\n                hexMemory = GlobalAlloc(GMEM_MOVEABLE | GMEM_ZEROINIT, (length * 3 + 1) * sizeof(WCHAR));\n\n                if (hexMemory)\n                {\n                    PWCHAR pw;\n                    ULONG i;\n\n                    pw = GlobalLock(hexMemory);\n\n                    for (i = 0; i < length; i++)\n                    {\n                        TO_HEX(pw, Context->Data[Context->SelStart + i]);\n                        *pw++ = ' ';\n                    }\n                    *pw = 0;\n\n                    GlobalUnlock(hexMemory);\n\n                    SetClipboardData(CF_UNICODETEXT, hexMemory);\n                }\n\n                SetClipboardData(RegisterClipboardFormat(L\"BinaryData\"), binaryMemory);\n            }\n        }\n        else\n        {\n            ULONG length = Context->SelEnd - Context->SelStart;\n            HGLOBAL binaryMemory;\n            HGLOBAL asciiMemory;\n\n            binaryMemory = GlobalAlloc(GMEM_MOVEABLE | GMEM_ZEROINIT, length);\n            asciiMemory = GlobalAlloc(GMEM_MOVEABLE | GMEM_ZEROINIT, length + 1);\n\n            if (binaryMemory)\n            {\n                PUCHAR p = GlobalLock(binaryMemory);\n                memcpy(p, &Context->Data[Context->SelStart], length);\n                GlobalUnlock(binaryMemory);\n\n                if (asciiMemory)\n                {\n                    ULONG i;\n\n                    p = GlobalLock(asciiMemory);\n                    memcpy(p, &Context->Data[Context->SelStart], length);\n\n                    for (i = 0; i < length; i++)\n                    {\n                        if (!IS_PRINTABLE(*p))\n                            *p = '.';\n                        p++;\n                    }\n                    *p = 0;\n\n                    GlobalUnlock(asciiMemory);\n\n                    SetClipboardData(CF_TEXT, asciiMemory);\n                }\n\n                SetClipboardData(RegisterClipboardFormat(L\"BinaryData\"), binaryMemory);\n            }\n        }\n\n        CloseClipboard();\n    }\n}\n\nVOID PhpHexEditCutEdit(\n    _In_ HWND hwnd,\n    _In_ PPHP_HEXEDIT_CONTEXT Context\n    )\n{\n    if (Context->AllowLengthChange)\n    {\n        PhpHexEditCopyEdit(hwnd, Context);\n        PhpHexEditSelDelete(hwnd, Context, Context->SelStart, Context->SelEnd);\n        REDRAW_WINDOW(hwnd);\n    }\n}\n\nVOID PhpHexEditPasteEdit(\n    _In_ HWND hwnd,\n    _In_ PPHP_HEXEDIT_CONTEXT Context\n    )\n{\n    if (OpenClipboard(hwnd))\n    {\n        HANDLE memory;\n\n        memory = GetClipboardData(RegisterClipboardFormat(L\"BinaryData\"));\n\n        if (!memory)\n            memory = GetClipboardData(CF_TEXT);\n\n        if (memory)\n        {\n            PUCHAR p = GlobalLock(memory);\n            ULONG length = (ULONG)GlobalSize(memory);\n            ULONG paste;\n            ULONG oldCurrentAddress = Context->CurrentAddress;\n\n            PhpHexEditNormalizeSel(hwnd, Context);\n\n            if (Context->AllowLengthChange)\n            {\n                if (Context->SelStart == -1)\n                {\n                    if (Context->CurrentMode == EDIT_LOW)\n                        Context->CurrentAddress++;\n\n                    paste = Context->CurrentAddress;\n                    PhpHexEditSelInsert(hwnd, Context, Context->CurrentAddress, length);\n                }\n                else\n                {\n                    paste = Context->SelStart;\n                    PhpHexEditSelDelete(hwnd, Context, Context->SelStart, Context->SelEnd);\n                    PhpHexEditSelInsert(hwnd, Context, paste, length);\n                    PhpHexEditSetSel(hwnd, Context, -1, -1);\n                }\n            }\n            else\n            {\n                if (Context->SelStart == -1)\n                {\n                    if (Context->CurrentMode == EDIT_LOW)\n                        Context->CurrentAddress++;\n\n                    paste = Context->CurrentAddress;\n                }\n                else\n                {\n                    paste = Context->SelStart;\n                }\n\n                if (length > Context->Length - paste)\n                    length = Context->Length - paste;\n            }\n\n            memcpy(&Context->Data[paste], p, length);\n            GlobalUnlock(memory);\n\n            Context->CurrentAddress = oldCurrentAddress;\n            REDRAW_WINDOW(hwnd);\n        }\n\n        CloseClipboard();\n    }\n}\n\nVOID PhpHexEditSelectAll(\n    _In_ HWND hwnd,\n    _In_ PPHP_HEXEDIT_CONTEXT Context\n    )\n{\n    Context->SelStart = 0;\n    Context->SelEnd = Context->Length;\n    DestroyCaret();\n    REDRAW_WINDOW(hwnd);\n}\n\nVOID PhpHexEditUndoEdit(\n    _In_ HWND hwnd,\n    _In_ PPHP_HEXEDIT_CONTEXT Context\n    )\n{\n    // TODO\n}\n\nVOID PhpHexEditNormalizeSel(\n    _In_ HWND hwnd,\n    _In_ PPHP_HEXEDIT_CONTEXT Context\n    )\n{\n    if (Context->SelStart > Context->SelEnd)\n    {\n        LONG t;\n\n        t = Context->SelEnd;\n        Context->SelEnd = Context->SelStart;\n        Context->SelStart = t;\n    }\n}\n\nVOID PhpHexEditSelDelete(\n    _In_ HWND hwnd,\n    _In_ PPHP_HEXEDIT_CONTEXT Context,\n    _In_ LONG S,\n    _In_ LONG E\n    )\n{\n    if (Context->AllowLengthChange && Context->Length > 0)\n    {\n        PUCHAR p = PhAllocate(Context->Length - (E - S) + 1);\n\n        memcpy(p, Context->Data, S);\n\n        if (S < Context->Length - (E - S))\n            memcpy(&p[S], &Context->Data[E], Context->Length - E);\n\n        PhFree(Context->Data);\n        Context->Data = p;\n        PhpHexEditSetSel(hwnd, Context, -1, -1);\n        Context->Length -= E - S;\n\n        if (Context->CurrentAddress > Context->Length)\n        {\n            Context->CurrentAddress = Context->Length;\n            PhpHexEditRepositionCaret(hwnd, Context, Context->CurrentAddress);\n        }\n\n        Context->Update = TRUE;\n    }\n}\n\nVOID PhpHexEditSelInsert(\n    _In_ HWND hwnd,\n    _In_ PPHP_HEXEDIT_CONTEXT Context,\n    _In_ LONG S,\n    _In_ LONG L\n    )\n{\n    if (Context->AllowLengthChange)\n    {\n        PUCHAR p = PhAllocate(Context->Length + L);\n\n        memset(p, 0, Context->Length + L);\n        memcpy(p, Context->Data, S);\n        memcpy(&p[S + L], &Context->Data[S], Context->Length - S);\n\n        PhFree(Context->Data);\n        Context->Data = p;\n        PhpHexEditSetSel(hwnd, Context, -1, -1);\n        Context->Length += L;\n\n        Context->Update = TRUE;\n    }\n}\n\nVOID PhpHexEditSetBuffer(\n    _In_ HWND hwnd,\n    _In_ PPHP_HEXEDIT_CONTEXT Context,\n    _In_ PUCHAR Data,\n    _In_ ULONG Length\n    )\n{\n    Context->Data = Data;\n    PhpHexEditSetSel(hwnd, Context, -1, -1);\n    Context->Length = Length;\n    Context->CurrentAddress = 0;\n    Context->EditPosition.x = Context->EditPosition.y = 0;\n    Context->CurrentMode = EDIT_HIGH;\n    Context->TopIndex = 0;\n    Context->Update = TRUE;\n\n    Context->UserBuffer = TRUE;\n    Context->AllowLengthChange = FALSE;\n}\n\nVOID PhpHexEditSetData(\n    _In_ HWND hwnd,\n    _In_ PPHP_HEXEDIT_CONTEXT Context,\n    _In_ PUCHAR Data,\n    _In_ ULONG Length\n    )\n{\n    if (Context->Data) PhFree(Context->Data);\n    Context->Data = PhAllocate(Length);\n    memcpy(Context->Data, Data, Length);\n    PhpHexEditSetBuffer(hwnd, Context, Context->Data, Length);\n    Context->UserBuffer = FALSE;\n    Context->AllowLengthChange = TRUE;\n}\n"
  },
  {
    "path": "third_party/phlib/hndlinfo.c",
    "content": "/*\n * Process Hacker -\n *   handle information\n *\n * Copyright (C) 2010-2015 wj32\n *\n * This file is part of Process Hacker.\n *\n * Process Hacker is free software; you can redistribute it and/or modify\n * it under the terms of the GNU General Public License as published by\n * the Free Software Foundation, either version 3 of the License, or\n * (at your option) any later version.\n *\n * Process Hacker is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n * GNU General Public License for more details.\n *\n * You should have received a copy of the GNU General Public License\n * along with Process Hacker.  If not, see <http://www.gnu.org/licenses/>.\n */\n\n#include <ph.h>\n#include <hndlinfo.h>\n\n#include <kphuser.h>\n#include <lsasup.h>\n\n#define PH_QUERY_HACK_MAX_THREADS 20\n\ntypedef struct _PHP_CALL_WITH_TIMEOUT_THREAD_CONTEXT\n{\n    SLIST_ENTRY ListEntry;\n\n    PUSER_THREAD_START_ROUTINE Routine;\n    PVOID Context;\n\n    HANDLE StartEventHandle;\n    HANDLE CompletedEventHandle;\n    HANDLE ThreadHandle;\n} PHP_CALL_WITH_TIMEOUT_THREAD_CONTEXT, *PPHP_CALL_WITH_TIMEOUT_THREAD_CONTEXT;\n\ntypedef enum _PHP_QUERY_OBJECT_WORK\n{\n    NtQueryObjectWork,\n    NtQuerySecurityObjectWork,\n    NtSetSecurityObjectWork\n} PHP_QUERY_OBJECT_WORK;\n\ntypedef struct _PHP_QUERY_OBJECT_COMMON_CONTEXT\n{\n    PHP_QUERY_OBJECT_WORK Work;\n    NTSTATUS Status;\n\n    union\n    {\n        struct\n        {\n            HANDLE Handle;\n            OBJECT_INFORMATION_CLASS ObjectInformationClass;\n            PVOID ObjectInformation;\n            ULONG ObjectInformationLength;\n            PULONG ReturnLength;\n        } NtQueryObject;\n        struct\n        {\n            HANDLE Handle;\n            SECURITY_INFORMATION SecurityInformation;\n            PSECURITY_DESCRIPTOR SecurityDescriptor;\n            ULONG Length;\n            PULONG LengthNeeded;\n        } NtQuerySecurityObject;\n        struct\n        {\n            HANDLE Handle;\n            SECURITY_INFORMATION SecurityInformation;\n            PSECURITY_DESCRIPTOR SecurityDescriptor;\n        } NtSetSecurityObject;\n    } u;\n} PHP_QUERY_OBJECT_COMMON_CONTEXT, *PPHP_QUERY_OBJECT_COMMON_CONTEXT;\n\nPPHP_CALL_WITH_TIMEOUT_THREAD_CONTEXT PhpAcquireCallWithTimeoutThread(\n    _In_opt_ PLARGE_INTEGER Timeout\n    );\n\nVOID PhpReleaseCallWithTimeoutThread(\n    _Inout_ PPHP_CALL_WITH_TIMEOUT_THREAD_CONTEXT ThreadContext\n    );\n\nNTSTATUS PhpCallWithTimeout(\n    _Inout_ PPHP_CALL_WITH_TIMEOUT_THREAD_CONTEXT ThreadContext,\n    _In_ PUSER_THREAD_START_ROUTINE Routine,\n    _In_opt_ PVOID Context,\n    _In_ PLARGE_INTEGER Timeout\n    );\n\nNTSTATUS PhpCallWithTimeoutThreadStart(\n    _In_ PVOID Parameter\n    );\n\nstatic PPH_STRING PhObjectTypeNames[MAX_OBJECT_TYPE_NUMBER] = { 0 };\nstatic PPH_GET_CLIENT_ID_NAME PhHandleGetClientIdName = PhStdGetClientIdName;\n\nstatic SLIST_HEADER PhpCallWithTimeoutThreadListHead;\nstatic PH_WAKE_EVENT PhpCallWithTimeoutThreadReleaseEvent = PH_WAKE_EVENT_INIT;\n\nPPH_GET_CLIENT_ID_NAME PhSetHandleClientIdFunction(\n    _In_ PPH_GET_CLIENT_ID_NAME GetClientIdName\n    )\n{\n    return _InterlockedExchangePointer(\n        (PVOID *)&PhHandleGetClientIdName,\n        GetClientIdName\n        );\n}\n\nNTSTATUS PhpGetObjectBasicInformation(\n    _In_ HANDLE ProcessHandle,\n    _In_ HANDLE Handle,\n    _Out_ POBJECT_BASIC_INFORMATION BasicInformation\n    )\n{\n    NTSTATUS status;\n\n    if (KphIsConnected())\n    {\n        status = KphQueryInformationObject(\n            ProcessHandle,\n            Handle,\n            KphObjectBasicInformation,\n            BasicInformation,\n            sizeof(OBJECT_BASIC_INFORMATION),\n            NULL\n            );\n\n        if (NT_SUCCESS(status))\n        {\n            // The object was referenced in KProcessHacker, so we need to subtract 1 from the\n            // pointer count.\n            BasicInformation->PointerCount -= 1;\n        }\n    }\n    else\n    {\n        ULONG returnLength;\n\n        status = NtQueryObject(\n            Handle,\n            ObjectBasicInformation,\n            BasicInformation,\n            sizeof(OBJECT_BASIC_INFORMATION),\n            &returnLength\n            );\n\n        if (NT_SUCCESS(status))\n        {\n            // The object was referenced in NtQueryObject and a handle was opened to the object. We\n            // need to subtract 1 from the pointer count, then subtract 1 from both counts.\n            BasicInformation->HandleCount -= 1;\n            BasicInformation->PointerCount -= 2;\n        }\n    }\n\n    return status;\n}\n\nNTSTATUS PhpGetObjectTypeName(\n    _In_ HANDLE ProcessHandle,\n    _In_ HANDLE Handle,\n    _In_ ULONG ObjectTypeNumber,\n    _Out_ PPH_STRING *TypeName\n    )\n{\n    NTSTATUS status = STATUS_SUCCESS;\n    PPH_STRING typeName = NULL;\n\n    // If the cache contains the object type name, use it. Otherwise, query the type name.\n\n    if (ObjectTypeNumber != -1 && ObjectTypeNumber < MAX_OBJECT_TYPE_NUMBER)\n        typeName = PhObjectTypeNames[ObjectTypeNumber];\n\n    if (typeName)\n    {\n        PhReferenceObject(typeName);\n    }\n    else\n    {\n        POBJECT_TYPE_INFORMATION buffer;\n        ULONG returnLength = 0;\n        PPH_STRING oldTypeName;\n\n        // Get the needed buffer size.\n        if (KphIsConnected())\n        {\n            status = KphQueryInformationObject(\n                ProcessHandle,\n                Handle,\n                KphObjectTypeInformation,\n                NULL,\n                0,\n                &returnLength\n                );\n        }\n        else\n        {\n            status = NtQueryObject(\n                Handle,\n                ObjectTypeInformation,\n                NULL,\n                0,\n                &returnLength\n                );\n        }\n\n        if (returnLength == 0)\n            return status;\n\n        buffer = PhAllocate(returnLength);\n\n        if (KphIsConnected())\n        {\n            status = KphQueryInformationObject(\n                ProcessHandle,\n                Handle,\n                KphObjectTypeInformation,\n                buffer,\n                returnLength,\n                &returnLength\n                );\n        }\n        else\n        {\n            status = NtQueryObject(\n                Handle,\n                ObjectTypeInformation,\n                buffer,\n                returnLength,\n                &returnLength\n                );\n        }\n\n        if (!NT_SUCCESS(status))\n        {\n            PhFree(buffer);\n            return status;\n        }\n\n        // Create a copy of the type name.\n        typeName = PhCreateStringFromUnicodeString(&buffer->TypeName);\n\n        if (ObjectTypeNumber != -1 && ObjectTypeNumber < MAX_OBJECT_TYPE_NUMBER)\n        {\n            // Try to store the type name in the cache.\n            oldTypeName = _InterlockedCompareExchangePointer(\n                &PhObjectTypeNames[ObjectTypeNumber],\n                typeName,\n                NULL\n                );\n\n            // Add a reference if we stored the type name\n            // successfully.\n            if (!oldTypeName)\n                PhReferenceObject(typeName);\n        }\n\n        PhFree(buffer);\n    }\n\n    // At this point typeName should contain a type name with one additional reference.\n\n    *TypeName = typeName;\n\n    return status;\n}\n\nNTSTATUS PhpGetObjectName(\n    _In_ HANDLE ProcessHandle,\n    _In_ HANDLE Handle,\n    _In_ BOOLEAN WithTimeout,\n    _Out_ PPH_STRING *ObjectName\n    )\n{\n    NTSTATUS status;\n    POBJECT_NAME_INFORMATION buffer;\n    ULONG bufferSize;\n    ULONG attempts = 8;\n\n    bufferSize = 0x200;\n    buffer = PhAllocate(bufferSize);\n\n    // A loop is needed because the I/O subsystem likes to give us the wrong return lengths...\n    do\n    {\n        if (KphIsConnected())\n        {\n            status = KphQueryInformationObject(\n                ProcessHandle,\n                Handle,\n                KphObjectNameInformation,\n                buffer,\n                bufferSize,\n                &bufferSize\n                );\n        }\n        else\n        {\n            if (WithTimeout)\n            {\n                status = PhCallNtQueryObjectWithTimeout(\n                    Handle,\n                    ObjectNameInformation,\n                    buffer,\n                    bufferSize,\n                    &bufferSize\n                    );\n            }\n            else\n            {\n                status = NtQueryObject(\n                    Handle,\n                    ObjectNameInformation,\n                    buffer,\n                    bufferSize,\n                    &bufferSize\n                    );\n            }\n        }\n\n        if (status == STATUS_BUFFER_OVERFLOW || status == STATUS_INFO_LENGTH_MISMATCH ||\n            status == STATUS_BUFFER_TOO_SMALL)\n        {\n            PhFree(buffer);\n            buffer = PhAllocate(bufferSize);\n        }\n        else\n        {\n            break;\n        }\n    } while (--attempts);\n\n    if (NT_SUCCESS(status))\n    {\n        *ObjectName = PhCreateStringFromUnicodeString(&buffer->Name);\n    }\n\n    PhFree(buffer);\n\n    return status;\n}\n\nPPH_STRING PhFormatNativeKeyName(\n    _In_ PPH_STRING Name\n    )\n{\n    static PH_STRINGREF hklmPrefix = PH_STRINGREF_INIT(L\"\\\\Registry\\\\Machine\");\n    static PH_STRINGREF hkcrPrefix = PH_STRINGREF_INIT(L\"\\\\Registry\\\\Machine\\\\Software\\\\Classes\");\n    static PH_STRINGREF hkuPrefix = PH_STRINGREF_INIT(L\"\\\\Registry\\\\User\");\n    static PPH_STRING hkcuPrefix;\n    static PPH_STRING hkcucrPrefix;\n\n    static PH_STRINGREF hklmString = PH_STRINGREF_INIT(L\"HKLM\");\n    static PH_STRINGREF hkcrString = PH_STRINGREF_INIT(L\"HKCR\");\n    static PH_STRINGREF hkuString = PH_STRINGREF_INIT(L\"HKU\");\n    static PH_STRINGREF hkcuString = PH_STRINGREF_INIT(L\"HKCU\");\n    static PH_STRINGREF hkcucrString = PH_STRINGREF_INIT(L\"HKCU\\\\Software\\\\Classes\");\n\n    static PH_INITONCE initOnce = PH_INITONCE_INIT;\n\n    PPH_STRING newName;\n    PH_STRINGREF name;\n\n    if (PhBeginInitOnce(&initOnce))\n    {\n        HANDLE currentTokenHandle;\n        PTOKEN_USER tokenUser;\n        PPH_STRING stringSid = NULL;\n\n        currentTokenHandle = PhGetOwnTokenAttributes().TokenHandle;\n\n        if (currentTokenHandle && NT_SUCCESS(PhGetTokenUser(\n            currentTokenHandle,\n            &tokenUser\n            )))\n        {\n            stringSid = PhSidToStringSid(tokenUser->User.Sid);\n            PhFree(tokenUser);\n        }\n\n        if (stringSid)\n        {\n            static PH_STRINGREF registryUserPrefix = PH_STRINGREF_INIT(L\"\\\\Registry\\\\User\\\\\");\n            static PH_STRINGREF classesString = PH_STRINGREF_INIT(L\"_Classes\");\n\n            hkcuPrefix = PhConcatStringRef2(&registryUserPrefix, &stringSid->sr);\n            hkcucrPrefix = PhConcatStringRef2(&hkcuPrefix->sr, &classesString);\n\n            PhDereferenceObject(stringSid);\n        }\n        else\n        {\n            hkcuPrefix = PhCreateString(L\"...\"); // some random string that won't ever get matched\n            hkcucrPrefix = PhCreateString(L\"...\");\n        }\n\n        PhEndInitOnce(&initOnce);\n    }\n\n    name = Name->sr;\n\n    if (PhStartsWithStringRef(&name, &hkcrPrefix, TRUE))\n    {\n        PhSkipStringRef(&name, hkcrPrefix.Length);\n        newName = PhConcatStringRef2(&hkcrString, &name);\n    }\n    else if (PhStartsWithStringRef(&name, &hklmPrefix, TRUE))\n    {\n        PhSkipStringRef(&name, hklmPrefix.Length);\n        newName = PhConcatStringRef2(&hklmString, &name);\n    }\n    else if (PhStartsWithStringRef(&name, &hkcucrPrefix->sr, TRUE))\n    {\n        PhSkipStringRef(&name, hkcucrPrefix->Length);\n        newName = PhConcatStringRef2(&hkcucrString, &name);\n    }\n    else if (PhStartsWithStringRef(&name, &hkcuPrefix->sr, TRUE))\n    {\n        PhSkipStringRef(&name, hkcuPrefix->Length);\n        newName = PhConcatStringRef2(&hkcuString, &name);\n    }\n    else if (PhStartsWithStringRef(&name, &hkuPrefix, TRUE))\n    {\n        PhSkipStringRef(&name, hkuPrefix.Length);\n        newName = PhConcatStringRef2(&hkuString, &name);\n    }\n    else\n    {\n        PhSetReference(&newName, Name);\n    }\n\n    return newName;\n}\n\nNTSTATUS PhGetSectionFileName(\n    _In_ HANDLE SectionHandle,\n    _Out_ PPH_STRING *FileName\n    )\n{\n    NTSTATUS status;\n    SIZE_T viewSize;\n    PVOID viewBase;\n\n    viewSize = 1;\n    viewBase = NULL;\n\n    status = NtMapViewOfSection(\n        SectionHandle,\n        NtCurrentProcess(),\n        &viewBase,\n        0,\n        0,\n        NULL,\n        &viewSize,\n        ViewShare,\n        0,\n        PAGE_READONLY\n        );\n\n    if (!NT_SUCCESS(status))\n        return status;\n\n    status = PhGetProcessMappedFileName(NtCurrentProcess(), viewBase, FileName);\n    NtUnmapViewOfSection(NtCurrentProcess(), viewBase);\n\n    return status;\n}\n\n_Callback_ PPH_STRING PhStdGetClientIdName(\n    _In_ PCLIENT_ID ClientId\n    )\n{\n    static PH_QUEUED_LOCK cachedProcessesLock = PH_QUEUED_LOCK_INIT;\n    static PVOID processes = NULL;\n    static ULONG64 lastProcessesTickCount = 0;\n\n    PPH_STRING name;\n    ULONG64 tickCount;\n    PSYSTEM_PROCESS_INFORMATION processInfo;\n\n    // Get a new process list only if 2 seconds have passed since the last update.\n\n    tickCount = NtGetTickCount64();\n\n    if (tickCount - lastProcessesTickCount >= 2000)\n    {\n        PhAcquireQueuedLockExclusive(&cachedProcessesLock);\n\n        // Re-check the tick count.\n        if (tickCount - lastProcessesTickCount >= 2000)\n        {\n            if (processes)\n            {\n                PhFree(processes);\n                processes = NULL;\n            }\n\n            if (!NT_SUCCESS(PhEnumProcesses(&processes)))\n            {\n                PhReleaseQueuedLockExclusive(&cachedProcessesLock);\n                return PhCreateString(L\"(Error querying processes)\");\n            }\n\n            lastProcessesTickCount = tickCount;\n        }\n\n        PhReleaseQueuedLockExclusive(&cachedProcessesLock);\n    }\n\n    // Get a lock on the process list and get a name for the client ID.\n\n    PhAcquireQueuedLockShared(&cachedProcessesLock);\n\n    if (!processes)\n    {\n        PhReleaseQueuedLockShared(&cachedProcessesLock);\n        return NULL;\n    }\n\n    processInfo = PhFindProcessInformation(processes, ClientId->UniqueProcess);\n\n    if (ClientId->UniqueThread)\n    {\n        if (processInfo)\n        {\n            name = PhFormatString(\n                L\"%.*s (%u): %u\",\n                processInfo->ImageName.Length / 2,\n                processInfo->ImageName.Buffer,\n                HandleToUlong(ClientId->UniqueProcess),\n                HandleToUlong(ClientId->UniqueThread)\n                );\n        }\n        else\n        {\n            name = PhFormatString(\n                L\"Non-existent process (%u): %u\",\n                HandleToUlong(ClientId->UniqueProcess),\n                HandleToUlong(ClientId->UniqueThread)\n                );\n        }\n    }\n    else\n    {\n        if (processInfo)\n        {\n            name = PhFormatString(\n                L\"%.*s (%u)\",\n                processInfo->ImageName.Length / 2,\n                processInfo->ImageName.Buffer,\n                HandleToUlong(ClientId->UniqueProcess)\n                );\n        }\n        else\n        {\n            name = PhFormatString(L\"Non-existent process (%u)\", HandleToUlong(ClientId->UniqueProcess));\n        }\n    }\n\n    PhReleaseQueuedLockShared(&cachedProcessesLock);\n\n    return name;\n}\n\nNTSTATUS PhpGetBestObjectName(\n    _In_ HANDLE ProcessHandle,\n    _In_ HANDLE Handle,\n    _In_ PPH_STRING ObjectName,\n    _In_ PPH_STRING TypeName,\n    _Out_ PPH_STRING *BestObjectName\n    )\n{\n    NTSTATUS status;\n    PPH_STRING bestObjectName = NULL;\n    PPH_GET_CLIENT_ID_NAME handleGetClientIdName = PhHandleGetClientIdName;\n\n    if (PhEqualString2(TypeName, L\"EtwRegistration\", TRUE))\n    {\n        if (KphIsConnected())\n        {\n            ETWREG_BASIC_INFORMATION basicInfo;\n\n            status = KphQueryInformationObject(\n                ProcessHandle,\n                Handle,\n                KphObjectEtwRegBasicInformation,\n                &basicInfo,\n                sizeof(ETWREG_BASIC_INFORMATION),\n                NULL\n                );\n\n            if (NT_SUCCESS(status))\n            {\n                static PH_STRINGREF publishersKeyName = PH_STRINGREF_INIT(L\"Software\\\\Microsoft\\\\Windows\\\\CurrentVersion\\\\WINEVT\\\\Publishers\\\\\");\n\n                PPH_STRING guidString;\n                PPH_STRING keyName;\n                HANDLE keyHandle;\n                PPH_STRING publisherName = NULL;\n\n                guidString = PhFormatGuid(&basicInfo.Guid);\n\n                // We should perform a lookup on the GUID to get the publisher name.\n\n                keyName = PhConcatStringRef2(&publishersKeyName, &guidString->sr);\n\n                if (NT_SUCCESS(PhOpenKey(\n                    &keyHandle,\n                    KEY_READ,\n                    PH_KEY_LOCAL_MACHINE,\n                    &keyName->sr,\n                    0\n                    )))\n                {\n                    publisherName = PhQueryRegistryString(keyHandle, NULL);\n\n                    if (publisherName && publisherName->Length == 0)\n                    {\n                        PhDereferenceObject(publisherName);\n                        publisherName = NULL;\n                    }\n\n                    NtClose(keyHandle);\n                }\n\n                PhDereferenceObject(keyName);\n\n                if (publisherName)\n                {\n                    bestObjectName = publisherName;\n                    PhDereferenceObject(guidString);\n                }\n                else\n                {\n                    bestObjectName = guidString;\n                }\n            }\n        }\n    }\n    else if (PhEqualString2(TypeName, L\"File\", TRUE))\n    {\n        // Convert the file name to a DOS file name.\n        bestObjectName = PhResolveDevicePrefix(ObjectName);\n\n        if (!bestObjectName)\n        {\n            // The file doesn't have a DOS name.\n            PhSetReference(&bestObjectName, ObjectName);\n        }\n\n        if (PhIsNullOrEmptyString(bestObjectName) && KphIsConnected())\n        {\n            KPH_FILE_OBJECT_DRIVER fileObjectDriver;\n            PPH_STRING driverName;\n\n            status = KphQueryInformationObject(\n                ProcessHandle,\n                Handle,\n                KphObjectFileObjectDriver,\n                &fileObjectDriver,\n                sizeof(KPH_FILE_OBJECT_DRIVER),\n                NULL\n                );\n\n            if (NT_SUCCESS(status) && fileObjectDriver.DriverHandle)\n            {\n                if (NT_SUCCESS(PhGetDriverName(fileObjectDriver.DriverHandle, &driverName)))\n                {\n                    static PH_STRINGREF prefix = PH_STRINGREF_INIT(L\"Unnamed file: \");\n\n                    PhMoveReference(&bestObjectName, PhConcatStringRef2(&prefix, &driverName->sr));\n                    PhDereferenceObject(driverName);\n                }\n\n                NtClose(fileObjectDriver.DriverHandle);\n            }\n        }\n    }\n    else if (PhEqualString2(TypeName, L\"Job\", TRUE))\n    {\n        HANDLE dupHandle;\n        PJOBOBJECT_BASIC_PROCESS_ID_LIST processIdList;\n\n        status = NtDuplicateObject(\n            ProcessHandle,\n            Handle,\n            NtCurrentProcess(),\n            &dupHandle,\n            JOB_OBJECT_QUERY,\n            0,\n            0\n            );\n\n        if (!NT_SUCCESS(status))\n            goto CleanupExit;\n\n        if (handleGetClientIdName && NT_SUCCESS(PhGetJobProcessIdList(dupHandle, &processIdList)))\n        {\n            PH_STRING_BUILDER sb;\n            ULONG i;\n            CLIENT_ID clientId;\n            PPH_STRING name;\n\n            PhInitializeStringBuilder(&sb, 40);\n            clientId.UniqueThread = NULL;\n\n            for (i = 0; i < processIdList->NumberOfProcessIdsInList; i++)\n            {\n                clientId.UniqueProcess = (HANDLE)processIdList->ProcessIdList[i];\n                name = handleGetClientIdName(&clientId);\n\n                if (name)\n                {\n                    PhAppendStringBuilder(&sb, &name->sr);\n                    PhAppendStringBuilder2(&sb, L\"; \");\n                    PhDereferenceObject(name);\n                }\n            }\n\n            PhFree(processIdList);\n\n            if (sb.String->Length != 0)\n                PhRemoveEndStringBuilder(&sb, 2);\n\n            if (sb.String->Length == 0)\n                PhAppendStringBuilder2(&sb, L\"(No processes)\");\n\n            bestObjectName = PhFinalStringBuilderString(&sb);\n        }\n\n        NtClose(dupHandle);\n    }\n    else if (PhEqualString2(TypeName, L\"Key\", TRUE))\n    {\n        bestObjectName = PhFormatNativeKeyName(ObjectName);\n    }\n    else if (PhEqualString2(TypeName, L\"Process\", TRUE))\n    {\n        CLIENT_ID clientId;\n\n        clientId.UniqueThread = NULL;\n\n        if (KphIsConnected())\n        {\n            PROCESS_BASIC_INFORMATION basicInfo;\n\n            status = KphQueryInformationObject(\n                ProcessHandle,\n                Handle,\n                KphObjectProcessBasicInformation,\n                &basicInfo,\n                sizeof(PROCESS_BASIC_INFORMATION),\n                NULL\n                );\n\n            if (!NT_SUCCESS(status))\n                goto CleanupExit;\n\n            clientId.UniqueProcess = basicInfo.UniqueProcessId;\n        }\n        else\n        {\n            HANDLE dupHandle;\n            PROCESS_BASIC_INFORMATION basicInfo;\n\n            status = NtDuplicateObject(\n                ProcessHandle,\n                Handle,\n                NtCurrentProcess(),\n                &dupHandle,\n                ProcessQueryAccess,\n                0,\n                0\n                );\n\n            if (!NT_SUCCESS(status))\n                goto CleanupExit;\n\n            status = PhGetProcessBasicInformation(dupHandle, &basicInfo);\n            NtClose(dupHandle);\n\n            if (!NT_SUCCESS(status))\n                goto CleanupExit;\n\n            clientId.UniqueProcess = basicInfo.UniqueProcessId;\n        }\n\n        if (handleGetClientIdName)\n            bestObjectName = handleGetClientIdName(&clientId);\n    }\n    else if (PhEqualString2(TypeName, L\"Section\", TRUE))\n    {\n        HANDLE dupHandle;\n        PPH_STRING fileName;\n\n        if (!PhIsNullOrEmptyString(ObjectName))\n            goto CleanupExit;\n\n        status = NtDuplicateObject(\n            ProcessHandle,\n            Handle,\n            NtCurrentProcess(),\n            &dupHandle,\n            SECTION_QUERY | SECTION_MAP_READ,\n            0,\n            0\n            );\n\n        if (!NT_SUCCESS(status))\n            goto CleanupExit;\n\n        status = PhGetSectionFileName(dupHandle, &fileName);\n\n        if (NT_SUCCESS(status))\n        {\n            bestObjectName = PhResolveDevicePrefix(fileName);\n            PhDereferenceObject(fileName);\n        }\n        else\n        {\n            SECTION_BASIC_INFORMATION basicInfo;\n\n            if (NT_SUCCESS(PhGetSectionBasicInformation(dupHandle, &basicInfo)))\n            {\n                PH_FORMAT format[4];\n                PWSTR sectionType = L\"Unknown\";\n\n                if (basicInfo.AllocationAttributes & SEC_COMMIT)\n                    sectionType = L\"Commit\";\n                else if (basicInfo.AllocationAttributes & SEC_FILE)\n                    sectionType = L\"File\";\n                else if (basicInfo.AllocationAttributes & SEC_IMAGE)\n                    sectionType = L\"Image\";\n                else if (basicInfo.AllocationAttributes & SEC_RESERVE)\n                    sectionType = L\"Reserve\";\n\n                PhInitFormatS(&format[0], sectionType);\n                PhInitFormatS(&format[1], L\" (\");\n                PhInitFormatSize(&format[2], basicInfo.MaximumSize.QuadPart);\n                PhInitFormatC(&format[3], ')');\n                bestObjectName = PhFormat(format, 4, 20);\n            }\n        }\n\n        NtClose(dupHandle);\n    }\n    else if (PhEqualString2(TypeName, L\"Thread\", TRUE))\n    {\n        CLIENT_ID clientId;\n\n        if (KphIsConnected())\n        {\n            THREAD_BASIC_INFORMATION basicInfo;\n\n            status = KphQueryInformationObject(\n                ProcessHandle,\n                Handle,\n                KphObjectThreadBasicInformation,\n                &basicInfo,\n                sizeof(THREAD_BASIC_INFORMATION),\n                NULL\n                );\n\n            if (!NT_SUCCESS(status))\n                goto CleanupExit;\n\n            clientId = basicInfo.ClientId;\n        }\n        else\n        {\n            HANDLE dupHandle;\n            THREAD_BASIC_INFORMATION basicInfo;\n\n            status = NtDuplicateObject(\n                ProcessHandle,\n                Handle,\n                NtCurrentProcess(),\n                &dupHandle,\n                ThreadQueryAccess,\n                0,\n                0\n                );\n\n            if (!NT_SUCCESS(status))\n                goto CleanupExit;\n\n            status = PhGetThreadBasicInformation(dupHandle, &basicInfo);\n            NtClose(dupHandle);\n\n            if (!NT_SUCCESS(status))\n                goto CleanupExit;\n\n            clientId = basicInfo.ClientId;\n        }\n\n        if (handleGetClientIdName)\n            bestObjectName = handleGetClientIdName(&clientId);\n    }\n    else if (PhEqualString2(TypeName, L\"TmEn\", TRUE))\n    {\n        HANDLE dupHandle;\n        ENLISTMENT_BASIC_INFORMATION basicInfo;\n\n        status = NtDuplicateObject(\n            ProcessHandle,\n            Handle,\n            NtCurrentProcess(),\n            &dupHandle,\n            ENLISTMENT_QUERY_INFORMATION,\n            0,\n            0\n            );\n\n        if (!NT_SUCCESS(status))\n            goto CleanupExit;\n\n        status = PhGetEnlistmentBasicInformation(dupHandle, &basicInfo);\n        NtClose(dupHandle);\n\n        if (NT_SUCCESS(status))\n        {\n            bestObjectName = PhFormatGuid(&basicInfo.EnlistmentId);\n        }\n    }\n    else if (PhEqualString2(TypeName, L\"TmRm\", TRUE))\n    {\n        HANDLE dupHandle;\n        GUID guid;\n        PPH_STRING description;\n\n        status = NtDuplicateObject(\n            ProcessHandle,\n            Handle,\n            NtCurrentProcess(),\n            &dupHandle,\n            RESOURCEMANAGER_QUERY_INFORMATION,\n            0,\n            0\n            );\n\n        if (!NT_SUCCESS(status))\n            goto CleanupExit;\n\n        status = PhGetResourceManagerBasicInformation(\n            dupHandle,\n            &guid,\n            &description\n            );\n        NtClose(dupHandle);\n\n        if (NT_SUCCESS(status))\n        {\n            if (!PhIsNullOrEmptyString(description))\n            {\n                bestObjectName = description;\n            }\n            else\n            {\n                bestObjectName = PhFormatGuid(&guid);\n\n                if (description)\n                    PhDereferenceObject(description);\n            }\n        }\n    }\n    else if (PhEqualString2(TypeName, L\"TmTm\", TRUE))\n    {\n        HANDLE dupHandle;\n        PPH_STRING logFileName = NULL;\n        TRANSACTIONMANAGER_BASIC_INFORMATION basicInfo;\n\n        status = NtDuplicateObject(\n            ProcessHandle,\n            Handle,\n            NtCurrentProcess(),\n            &dupHandle,\n            TRANSACTIONMANAGER_QUERY_INFORMATION,\n            0,\n            0\n            );\n\n        if (!NT_SUCCESS(status))\n            goto CleanupExit;\n\n        status = PhGetTransactionManagerLogFileName(\n            dupHandle,\n            &logFileName\n            );\n\n        if (NT_SUCCESS(status) && !PhIsNullOrEmptyString(logFileName))\n        {\n            bestObjectName = PhGetFileName(logFileName);\n            PhDereferenceObject(logFileName);\n        }\n        else\n        {\n            if (logFileName)\n                PhDereferenceObject(logFileName);\n\n            status = PhGetTransactionManagerBasicInformation(\n                dupHandle,\n                &basicInfo\n                );\n\n            if (NT_SUCCESS(status))\n            {\n                bestObjectName = PhFormatGuid(&basicInfo.TmIdentity);\n            }\n        }\n\n        NtClose(dupHandle);\n    }\n    else if (PhEqualString2(TypeName, L\"TmTx\", TRUE))\n    {\n        HANDLE dupHandle;\n        PPH_STRING description = NULL;\n        TRANSACTION_BASIC_INFORMATION basicInfo;\n\n        status = NtDuplicateObject(\n            ProcessHandle,\n            Handle,\n            NtCurrentProcess(),\n            &dupHandle,\n            TRANSACTION_QUERY_INFORMATION,\n            0,\n            0\n            );\n\n        if (!NT_SUCCESS(status))\n            goto CleanupExit;\n\n        status = PhGetTransactionPropertiesInformation(\n            dupHandle,\n            NULL,\n            NULL,\n            &description\n            );\n\n        if (NT_SUCCESS(status) && !PhIsNullOrEmptyString(description))\n        {\n            bestObjectName = description;\n        }\n        else\n        {\n            if (description)\n                PhDereferenceObject(description);\n\n            status = PhGetTransactionBasicInformation(\n                dupHandle,\n                &basicInfo\n                );\n\n            if (NT_SUCCESS(status))\n            {\n                bestObjectName = PhFormatGuid(&basicInfo.TransactionId);\n            }\n        }\n\n        NtClose(dupHandle);\n    }\n    else if (PhEqualString2(TypeName, L\"Token\", TRUE))\n    {\n        HANDLE dupHandle;\n        PTOKEN_USER tokenUser = NULL;\n        TOKEN_STATISTICS statistics = { 0 };\n\n        status = NtDuplicateObject(\n            ProcessHandle,\n            Handle,\n            NtCurrentProcess(),\n            &dupHandle,\n            TOKEN_QUERY,\n            0,\n            0\n            );\n\n        if (!NT_SUCCESS(status))\n            goto CleanupExit;\n\n        status = PhGetTokenUser(dupHandle, &tokenUser);\n        PhGetTokenStatistics(dupHandle, &statistics);\n\n        if (NT_SUCCESS(status))\n        {\n            PPH_STRING fullName;\n\n            fullName = PhGetSidFullName(tokenUser->User.Sid, TRUE, NULL);\n\n            if (fullName)\n            {\n                PH_FORMAT format[4];\n\n                PhInitFormatSR(&format[0], fullName->sr);\n                PhInitFormatS(&format[1], L\": 0x\");\n                PhInitFormatX(&format[2], statistics.AuthenticationId.LowPart);\n                PhInitFormatS(&format[3], statistics.TokenType == TokenPrimary ? L\" (Primary)\" : L\" (Impersonation)\");\n\n                bestObjectName = PhFormat(format, 4, fullName->Length + 8 + 16 + 16);\n                PhDereferenceObject(fullName);\n            }\n\n            PhFree(tokenUser);\n        }\n\n        NtClose(dupHandle);\n    }\n\nCleanupExit:\n\n    if (!bestObjectName)\n        PhSetReference(&bestObjectName, ObjectName);\n\n    *BestObjectName = bestObjectName;\n\n    return STATUS_SUCCESS;\n}\n\n/**\n * Gets information for a handle.\n *\n * \\param ProcessHandle A handle to the process in which the handle resides.\n * \\param Handle The handle value.\n * \\param ObjectTypeNumber The object type number of the handle. You can specify -1 for this\n * parameter if the object type number is not known.\n * \\param BasicInformation A variable which receives basic information about the object.\n * \\param TypeName A variable which receives the object type name.\n * \\param ObjectName A variable which receives the object name.\n * \\param BestObjectName A variable which receives the formatted object name.\n *\n * \\retval STATUS_INVALID_HANDLE The handle specified in \\c ProcessHandle or \\c Handle is invalid.\n * \\retval STATUS_INVALID_PARAMETER_3 The value specified in \\c ObjectTypeNumber is invalid.\n */\nNTSTATUS PhGetHandleInformation(\n    _In_ HANDLE ProcessHandle,\n    _In_ HANDLE Handle,\n    _In_ ULONG ObjectTypeNumber,\n    _Out_opt_ POBJECT_BASIC_INFORMATION BasicInformation,\n    _Out_opt_ PPH_STRING *TypeName,\n    _Out_opt_ PPH_STRING *ObjectName,\n    _Out_opt_ PPH_STRING *BestObjectName\n    )\n{\n    NTSTATUS status;\n    NTSTATUS subStatus;\n\n    status = PhGetHandleInformationEx(\n        ProcessHandle,\n        Handle,\n        ObjectTypeNumber,\n        0,\n        &subStatus,\n        BasicInformation,\n        TypeName,\n        ObjectName,\n        BestObjectName,\n        NULL\n        );\n\n    if (!NT_SUCCESS(status))\n        return status;\n\n    // Fail if any component failed, for compatibility reasons.\n    if (!NT_SUCCESS(subStatus))\n    {\n        if (TypeName)\n            PhClearReference(TypeName);\n        if (ObjectName)\n            PhClearReference(ObjectName);\n        if (BestObjectName)\n            PhClearReference(BestObjectName);\n\n        return subStatus;\n    }\n\n    return status;\n}\n\n/**\n * Gets information for a handle.\n *\n * \\param ProcessHandle A handle to the process in which the handle resides.\n * \\param Handle The handle value.\n * \\param ObjectTypeNumber The object type number of the handle. You can specify -1 for this\n * parameter if the object type number is not known.\n * \\param Flags Reserved.\n * \\param SubStatus A variable which receives the NTSTATUS value of the last component that fails.\n * If all operations succeed, the value will be STATUS_SUCCESS. If the function returns an error\n * status, this variable is not set.\n * \\param BasicInformation A variable which receives basic information about the object.\n * \\param TypeName A variable which receives the object type name.\n * \\param ObjectName A variable which receives the object name.\n * \\param BestObjectName A variable which receives the formatted object name.\n * \\param ExtraInformation Reserved.\n *\n * \\retval STATUS_INVALID_HANDLE The handle specified in \\c ProcessHandle or \\c Handle is invalid.\n * \\retval STATUS_INVALID_PARAMETER_3 The value specified in \\c ObjectTypeNumber is invalid.\n *\n * \\remarks If \\a BasicInformation or \\a TypeName are specified, the function will fail if either\n * cannot be queried. \\a ObjectName, \\a BestObjectName and \\a ExtraInformation will be NULL if they\n * cannot be queried.\n */\nNTSTATUS PhGetHandleInformationEx(\n    _In_ HANDLE ProcessHandle,\n    _In_ HANDLE Handle,\n    _In_ ULONG ObjectTypeNumber,\n    _Reserved_ ULONG Flags,\n    _Out_opt_ PNTSTATUS SubStatus,\n    _Out_opt_ POBJECT_BASIC_INFORMATION BasicInformation,\n    _Out_opt_ PPH_STRING *TypeName,\n    _Out_opt_ PPH_STRING *ObjectName,\n    _Out_opt_ PPH_STRING *BestObjectName,\n    _Reserved_ PVOID *ExtraInformation\n    )\n{\n    NTSTATUS status = STATUS_SUCCESS;\n    NTSTATUS subStatus = STATUS_SUCCESS;\n    HANDLE dupHandle = NULL;\n    PPH_STRING typeName = NULL;\n    PPH_STRING objectName = NULL;\n    PPH_STRING bestObjectName = NULL;\n\n    if (Handle == NULL || Handle == NtCurrentProcess() || Handle == NtCurrentThread())\n        return STATUS_INVALID_HANDLE;\n    if (ObjectTypeNumber != -1 && ObjectTypeNumber >= MAX_OBJECT_TYPE_NUMBER)\n        return STATUS_INVALID_PARAMETER_3;\n\n    // Duplicate the handle if we're not using KPH.\n    if (!KphIsConnected())\n    {\n        // However, we obviously don't need to duplicate it\n        // if the handle is in the current process.\n        if (ProcessHandle != NtCurrentProcess())\n        {\n            status = NtDuplicateObject(\n                ProcessHandle,\n                Handle,\n                NtCurrentProcess(),\n                &dupHandle,\n                0,\n                0,\n                0\n                );\n\n            if (!NT_SUCCESS(status))\n                return status;\n        }\n        else\n        {\n            dupHandle = Handle;\n        }\n    }\n\n    // Get basic information.\n    if (BasicInformation)\n    {\n        status = PhpGetObjectBasicInformation(\n            ProcessHandle,\n            KphIsConnected() ? Handle : dupHandle,\n            BasicInformation\n            );\n\n        if (!NT_SUCCESS(status))\n            goto CleanupExit;\n    }\n\n    // Exit early if we don't need to get any other information.\n    if (!TypeName && !ObjectName && !BestObjectName)\n        goto CleanupExit;\n\n    // Get the type name.\n    status = PhpGetObjectTypeName(\n        ProcessHandle,\n        KphIsConnected() ? Handle : dupHandle,\n        ObjectTypeNumber,\n        &typeName\n        );\n\n    if (!NT_SUCCESS(status))\n        goto CleanupExit;\n\n    // Exit early if we don't need to get the object name.\n    if (!ObjectName && !BestObjectName)\n        goto CleanupExit;\n\n    // Get the object name.\n    // If we're dealing with a file handle we must take special precautions so we don't hang.\n    if (PhEqualString2(typeName, L\"File\", TRUE) && !KphIsConnected())\n    {\n        status = PhpGetObjectName(\n            ProcessHandle,\n            KphIsConnected() ? Handle : dupHandle,\n            TRUE,\n            &objectName\n            );\n    }\n    else\n    {\n        // Query the object normally.\n        status = PhpGetObjectName(\n            ProcessHandle,\n            KphIsConnected() ? Handle : dupHandle,\n            FALSE,\n            &objectName\n            );\n    }\n\n    if (!NT_SUCCESS(status))\n    {\n        if (PhEqualString2(typeName, L\"File\", TRUE) && KphIsConnected())\n        {\n            // PhpGetBestObjectName can provide us with a name.\n            objectName = PhReferenceEmptyString();\n            status = STATUS_SUCCESS;\n        }\n        else\n        {\n            subStatus = status;\n            status = STATUS_SUCCESS;\n            goto CleanupExit;\n        }\n    }\n\n    // Exit early if we don't need to get the best object name.\n    if (!BestObjectName)\n        goto CleanupExit;\n\n    status = PhpGetBestObjectName(\n        ProcessHandle,\n        Handle,\n        objectName,\n        typeName,\n        &bestObjectName\n        );\n\n    if (!NT_SUCCESS(status))\n    {\n        subStatus = status;\n        status = STATUS_SUCCESS;\n        goto CleanupExit;\n    }\n\nCleanupExit:\n\n    if (NT_SUCCESS(status))\n    {\n        if (SubStatus)\n            *SubStatus = subStatus;\n        if (TypeName)\n            PhSetReference(TypeName, typeName);\n        if (ObjectName)\n            PhSetReference(ObjectName, objectName);\n        if (BestObjectName)\n            PhSetReference(BestObjectName, bestObjectName);\n    }\n\n    if (dupHandle && ProcessHandle != NtCurrentProcess())\n        NtClose(dupHandle);\n\n    PhClearReference(&typeName);\n    PhClearReference(&objectName);\n    PhClearReference(&bestObjectName);\n\n    return status;\n}\n\nNTSTATUS PhEnumObjectTypes(\n    _Out_ POBJECT_TYPES_INFORMATION *ObjectTypes\n    )\n{\n    NTSTATUS status;\n    PVOID buffer;\n    ULONG bufferSize;\n    ULONG returnLength;\n\n    bufferSize = 0x1000;\n    buffer = PhAllocate(bufferSize);\n\n    while ((status = NtQueryObject(\n        NULL,\n        ObjectTypesInformation,\n        buffer,\n        bufferSize,\n        &returnLength\n        )) == STATUS_INFO_LENGTH_MISMATCH)\n    {\n        PhFree(buffer);\n        bufferSize *= 2;\n\n        // Fail if we're resizing the buffer to something very large.\n        if (bufferSize > PH_LARGE_BUFFER_SIZE)\n            return STATUS_INSUFFICIENT_RESOURCES;\n\n        buffer = PhAllocate(bufferSize);\n    }\n\n    if (!NT_SUCCESS(status))\n    {\n        PhFree(buffer);\n        return status;\n    }\n\n    *ObjectTypes = (POBJECT_TYPES_INFORMATION)buffer;\n\n    return status;\n}\n\nULONG PhGetObjectTypeNumber(\n    _In_ PUNICODE_STRING TypeName\n    )\n{\n    POBJECT_TYPES_INFORMATION objectTypes;\n    POBJECT_TYPE_INFORMATION objectType;\n    ULONG objectIndex = -1;\n    ULONG i;\n\n    if (NT_SUCCESS(PhEnumObjectTypes(&objectTypes)))\n    {\n        objectType = PH_FIRST_OBJECT_TYPE(objectTypes);\n\n        for (i = 0; i < objectTypes->NumberOfTypes; i++)\n        {\n            if (RtlEqualUnicodeString(&objectType->TypeName, TypeName, TRUE))\n            {\n                if (WindowsVersion >= WINDOWS_8_1)\n                {\n                    objectIndex = objectType->TypeIndex;\n                    break;\n                }\n                else\n                {\n                    objectIndex = i + 2;\n                    break;\n                }\n            }\n\n            objectType = PH_NEXT_OBJECT_TYPE(objectType);\n        }\n\n        PhFree(objectTypes);\n    }\n\n    return objectIndex;\n}\n\nPPHP_CALL_WITH_TIMEOUT_THREAD_CONTEXT PhpAcquireCallWithTimeoutThread(\n    _In_opt_ PLARGE_INTEGER Timeout\n    )\n{\n    static PH_INITONCE initOnce = PH_INITONCE_INIT;\n\n    PPHP_CALL_WITH_TIMEOUT_THREAD_CONTEXT threadContext;\n    PSLIST_ENTRY listEntry;\n    PH_QUEUED_WAIT_BLOCK waitBlock;\n\n    if (PhBeginInitOnce(&initOnce))\n    {\n        ULONG i;\n\n        for (i = 0; i < PH_QUERY_HACK_MAX_THREADS; i++)\n        {\n            threadContext = PhAllocate(sizeof(PHP_CALL_WITH_TIMEOUT_THREAD_CONTEXT));\n            memset(threadContext, 0, sizeof(PHP_CALL_WITH_TIMEOUT_THREAD_CONTEXT));\n            RtlInterlockedPushEntrySList(&PhpCallWithTimeoutThreadListHead, &threadContext->ListEntry);\n        }\n\n        PhEndInitOnce(&initOnce);\n    }\n\n    while (TRUE)\n    {\n        if (listEntry = RtlInterlockedPopEntrySList(&PhpCallWithTimeoutThreadListHead))\n            break;\n\n        if (!Timeout || Timeout->QuadPart != 0)\n        {\n            PhQueueWakeEvent(&PhpCallWithTimeoutThreadReleaseEvent, &waitBlock);\n\n            if (listEntry = RtlInterlockedPopEntrySList(&PhpCallWithTimeoutThreadListHead))\n            {\n                // A new entry has just become available; cancel the wait.\n                PhSetWakeEvent(&PhpCallWithTimeoutThreadReleaseEvent, &waitBlock);\n                break;\n            }\n            else\n            {\n                PhWaitForWakeEvent(&PhpCallWithTimeoutThreadReleaseEvent, &waitBlock, FALSE, Timeout);\n                // TODO: Recompute the timeout value.\n            }\n        }\n        else\n        {\n            return NULL;\n        }\n    }\n\n    return CONTAINING_RECORD(listEntry, PHP_CALL_WITH_TIMEOUT_THREAD_CONTEXT, ListEntry);\n}\n\nVOID PhpReleaseCallWithTimeoutThread(\n    _Inout_ PPHP_CALL_WITH_TIMEOUT_THREAD_CONTEXT ThreadContext\n    )\n{\n    RtlInterlockedPushEntrySList(&PhpCallWithTimeoutThreadListHead, &ThreadContext->ListEntry);\n    PhSetWakeEvent(&PhpCallWithTimeoutThreadReleaseEvent, NULL);\n}\n\nNTSTATUS PhpCallWithTimeout(\n    _Inout_ PPHP_CALL_WITH_TIMEOUT_THREAD_CONTEXT ThreadContext,\n    _In_ PUSER_THREAD_START_ROUTINE Routine,\n    _In_opt_ PVOID Context,\n    _In_ PLARGE_INTEGER Timeout\n    )\n{\n    NTSTATUS status;\n\n    // Create objects if necessary.\n\n    if (!ThreadContext->StartEventHandle)\n    {\n        if (!NT_SUCCESS(status = NtCreateEvent(&ThreadContext->StartEventHandle, EVENT_ALL_ACCESS, NULL, SynchronizationEvent, FALSE)))\n            return status;\n    }\n\n    if (!ThreadContext->CompletedEventHandle)\n    {\n        if (!NT_SUCCESS(status = NtCreateEvent(&ThreadContext->CompletedEventHandle, EVENT_ALL_ACCESS, NULL, SynchronizationEvent, FALSE)))\n            return status;\n    }\n\n    // Create a query thread if we don't have one.\n    if (!ThreadContext->ThreadHandle)\n    {\n        CLIENT_ID clientId;\n\n        NtClearEvent(ThreadContext->StartEventHandle);\n        NtClearEvent(ThreadContext->CompletedEventHandle);\n\n        if (!NT_SUCCESS(status = RtlCreateUserThread(\n            NtCurrentProcess(),\n            NULL,\n            FALSE,\n            0,\n            0,\n            32 * 1024,\n            PhpCallWithTimeoutThreadStart,\n            ThreadContext,\n            &ThreadContext->ThreadHandle,\n            &clientId\n            )))\n        {\n            return status;\n        }\n\n        // Wait for the thread to initialize.\n        NtWaitForSingleObject(ThreadContext->CompletedEventHandle, FALSE, NULL);\n    }\n\n    ThreadContext->Routine = Routine;\n    ThreadContext->Context = Context;\n\n    NtSetEvent(ThreadContext->StartEventHandle, NULL);\n    status = NtWaitForSingleObject(ThreadContext->CompletedEventHandle, FALSE, Timeout);\n\n    ThreadContext->Routine = NULL;\n    MemoryBarrier();\n    ThreadContext->Context = NULL;\n\n    if (status != STATUS_WAIT_0)\n    {\n        // The operation timed out, or there was an error. Kill the thread. On Vista and above, the\n        // thread stack is freed automatically.\n        NtTerminateThread(ThreadContext->ThreadHandle, STATUS_UNSUCCESSFUL);\n        status = NtWaitForSingleObject(ThreadContext->ThreadHandle, FALSE, NULL);\n        NtClose(ThreadContext->ThreadHandle);\n        ThreadContext->ThreadHandle = NULL;\n\n        status = STATUS_UNSUCCESSFUL;\n    }\n\n    return status;\n}\n\nNTSTATUS PhpCallWithTimeoutThreadStart(\n    _In_ PVOID Parameter\n    )\n{\n    PPHP_CALL_WITH_TIMEOUT_THREAD_CONTEXT threadContext = Parameter;\n\n    NtSetEvent(threadContext->CompletedEventHandle, NULL);\n\n    while (TRUE)\n    {\n        if (NtWaitForSingleObject(threadContext->StartEventHandle, FALSE, NULL) != STATUS_WAIT_0)\n            continue;\n\n        if (threadContext->Routine)\n            threadContext->Routine(threadContext->Context);\n\n        NtSetEvent(threadContext->CompletedEventHandle, NULL);\n    }\n\n    return STATUS_SUCCESS;\n}\n\nNTSTATUS PhCallWithTimeout(\n    _In_ PUSER_THREAD_START_ROUTINE Routine,\n    _In_opt_ PVOID Context,\n    _In_opt_ PLARGE_INTEGER AcquireTimeout,\n    _In_ PLARGE_INTEGER CallTimeout\n    )\n{\n    NTSTATUS status;\n    PPHP_CALL_WITH_TIMEOUT_THREAD_CONTEXT threadContext;\n\n    if (threadContext = PhpAcquireCallWithTimeoutThread(AcquireTimeout))\n    {\n        status = PhpCallWithTimeout(threadContext, Routine, Context, CallTimeout);\n        PhpReleaseCallWithTimeoutThread(threadContext);\n    }\n    else\n    {\n        status = STATUS_UNSUCCESSFUL;\n    }\n\n    return status;\n}\n\nNTSTATUS PhpCommonQueryObjectRoutine(\n    _In_ PVOID Parameter\n    )\n{\n    PPHP_QUERY_OBJECT_COMMON_CONTEXT context = Parameter;\n\n    switch (context->Work)\n    {\n    case NtQueryObjectWork:\n        context->Status = NtQueryObject(\n            context->u.NtQueryObject.Handle,\n            context->u.NtQueryObject.ObjectInformationClass,\n            context->u.NtQueryObject.ObjectInformation,\n            context->u.NtQueryObject.ObjectInformationLength,\n            context->u.NtQueryObject.ReturnLength\n            );\n        break;\n    case NtQuerySecurityObjectWork:\n        context->Status = NtQuerySecurityObject(\n            context->u.NtQuerySecurityObject.Handle,\n            context->u.NtQuerySecurityObject.SecurityInformation,\n            context->u.NtQuerySecurityObject.SecurityDescriptor,\n            context->u.NtQuerySecurityObject.Length,\n            context->u.NtQuerySecurityObject.LengthNeeded\n            );\n        break;\n    case NtSetSecurityObjectWork:\n        context->Status = NtSetSecurityObject(\n            context->u.NtSetSecurityObject.Handle,\n            context->u.NtSetSecurityObject.SecurityInformation,\n            context->u.NtSetSecurityObject.SecurityDescriptor\n            );\n        break;\n    default:\n        context->Status = STATUS_INVALID_PARAMETER;\n        break;\n    }\n\n    return STATUS_SUCCESS;\n}\n\nNTSTATUS PhpCommonQueryObjectWithTimeout(\n    _In_ PPHP_QUERY_OBJECT_COMMON_CONTEXT Context\n    )\n{\n    NTSTATUS status;\n    LARGE_INTEGER timeout;\n\n    timeout.QuadPart = -1 * PH_TIMEOUT_SEC;\n    status = PhCallWithTimeout(PhpCommonQueryObjectRoutine, Context, NULL, &timeout);\n\n    if (NT_SUCCESS(status))\n        status = Context->Status;\n\n    PhFree(Context);\n\n    return status;\n}\n\nNTSTATUS PhCallNtQueryObjectWithTimeout(\n    _In_ HANDLE Handle,\n    _In_ OBJECT_INFORMATION_CLASS ObjectInformationClass,\n    _Out_writes_bytes_opt_(ObjectInformationLength) PVOID ObjectInformation,\n    _In_ ULONG ObjectInformationLength,\n    _Out_opt_ PULONG ReturnLength\n    )\n{\n    PPHP_QUERY_OBJECT_COMMON_CONTEXT context;\n\n    context = PhAllocate(sizeof(PHP_QUERY_OBJECT_COMMON_CONTEXT));\n    context->Work = NtQueryObjectWork;\n    context->Status = STATUS_UNSUCCESSFUL;\n    context->u.NtQueryObject.Handle = Handle;\n    context->u.NtQueryObject.ObjectInformationClass = ObjectInformationClass;\n    context->u.NtQueryObject.ObjectInformation = ObjectInformation;\n    context->u.NtQueryObject.ObjectInformationLength = ObjectInformationLength;\n    context->u.NtQueryObject.ReturnLength = ReturnLength;\n\n    return PhpCommonQueryObjectWithTimeout(context);\n}\n\nNTSTATUS PhCallNtQuerySecurityObjectWithTimeout(\n    _In_ HANDLE Handle,\n    _In_ SECURITY_INFORMATION SecurityInformation,\n    _Out_writes_bytes_opt_(Length) PSECURITY_DESCRIPTOR SecurityDescriptor,\n    _In_ ULONG Length,\n    _Out_ PULONG LengthNeeded\n    )\n{\n    PPHP_QUERY_OBJECT_COMMON_CONTEXT context;\n\n    context = PhAllocate(sizeof(PHP_QUERY_OBJECT_COMMON_CONTEXT));\n    context->Work = NtQuerySecurityObjectWork;\n    context->Status = STATUS_UNSUCCESSFUL;\n    context->u.NtQuerySecurityObject.Handle = Handle;\n    context->u.NtQuerySecurityObject.SecurityInformation = SecurityInformation;\n    context->u.NtQuerySecurityObject.SecurityDescriptor = SecurityDescriptor;\n    context->u.NtQuerySecurityObject.Length = Length;\n    context->u.NtQuerySecurityObject.LengthNeeded = LengthNeeded;\n\n    return PhpCommonQueryObjectWithTimeout(context);\n}\n\nNTSTATUS PhCallNtSetSecurityObjectWithTimeout(\n    _In_ HANDLE Handle,\n    _In_ SECURITY_INFORMATION SecurityInformation,\n    _In_ PSECURITY_DESCRIPTOR SecurityDescriptor\n    )\n{\n    PPHP_QUERY_OBJECT_COMMON_CONTEXT context;\n\n    context = PhAllocate(sizeof(PHP_QUERY_OBJECT_COMMON_CONTEXT));\n    context->Work = NtSetSecurityObjectWork;\n    context->Status = STATUS_UNSUCCESSFUL;\n    context->u.NtSetSecurityObject.Handle = Handle;\n    context->u.NtSetSecurityObject.SecurityInformation = SecurityInformation;\n    context->u.NtSetSecurityObject.SecurityDescriptor = SecurityDescriptor;\n\n    return PhpCommonQueryObjectWithTimeout(context);\n}\n"
  },
  {
    "path": "third_party/phlib/icotobmp.c",
    "content": "#include <ph.h>\n#include <uxtheme.h>\n#include <guisup.h>\n\n// code from http://msdn.microsoft.com/en-us/library/bb757020.aspx\n\nstatic HBITMAP PhpCreateBitmap32(\n    _In_ HDC hdc,\n    _In_ ULONG Width,\n    _In_ ULONG Height,\n    _Outptr_opt_ PVOID *Bits\n    )\n{\n    BITMAPINFO bitmapInfo;\n\n    memset(&bitmapInfo, 0, sizeof(BITMAPINFO));\n    bitmapInfo.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);\n    bitmapInfo.bmiHeader.biPlanes = 1;\n    bitmapInfo.bmiHeader.biCompression = BI_RGB;\n\n    bitmapInfo.bmiHeader.biWidth = Width;\n    bitmapInfo.bmiHeader.biHeight = Height;\n    bitmapInfo.bmiHeader.biBitCount = 32;\n\n    return CreateDIBSection(hdc, &bitmapInfo, DIB_RGB_COLORS, Bits, NULL, 0);\n}\n\nstatic BOOLEAN PhpHasAlpha(\n    _In_ PULONG Argb,\n    _In_ ULONG Width,\n    _In_ ULONG Height,\n    _In_ ULONG RowWidth\n    )\n{\n    ULONG delta;\n    ULONG x;\n    ULONG y;\n\n    delta = RowWidth - Width;\n\n    for (y = Width; y; y--)\n    {\n        for (x = Height; x; x--)\n        {\n            if (*Argb++ & 0xff000000)\n                return TRUE;\n        }\n\n        Argb += delta;\n    }\n\n    return FALSE;\n}\n\nstatic VOID PhpConvertToPArgb32(\n    _In_ HDC hdc,\n    _Inout_ PULONG Argb,\n    _In_ HBITMAP Bitmap,\n    _In_ ULONG Width,\n    _In_ ULONG Height,\n    _In_ ULONG RowWidth\n    )\n{\n    BITMAPINFO bitmapInfo;\n    PVOID bits;\n\n    memset(&bitmapInfo, 0, sizeof(BITMAPINFO));\n    bitmapInfo.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);\n    bitmapInfo.bmiHeader.biPlanes = 1;\n    bitmapInfo.bmiHeader.biCompression = BI_RGB;\n\n    bitmapInfo.bmiHeader.biWidth = Width;\n    bitmapInfo.bmiHeader.biHeight = Height;\n    bitmapInfo.bmiHeader.biBitCount = 32;\n\n    bits = PhAllocate(Width * sizeof(ULONG) * Height);\n\n    if (GetDIBits(hdc, Bitmap, 0, Height, bits, &bitmapInfo, DIB_RGB_COLORS) == Height)\n    {\n        PULONG argbMask;\n        ULONG delta;\n        ULONG x;\n        ULONG y;\n\n        argbMask = (PULONG)bits;\n        delta = RowWidth - Width;\n\n        for (y = Height; y; y--)\n        {\n            for (x = Width; x; x--)\n            {\n                if (*argbMask++)\n                {\n                    *Argb++ = 0; // transparent\n                }\n                else\n                {\n                    *Argb++ |= 0xff000000; // opaque\n                }\n            }\n\n            Argb += delta;\n        }\n    }\n\n    PhFree(bits);\n}\n\nstatic VOID PhpConvertToPArgb32IfNeeded(\n    _In_ HPAINTBUFFER PaintBuffer,\n    _In_ HDC hdc,\n    _In_ HICON Icon,\n    _In_ ULONG Width,\n    _In_ ULONG Height\n    )\n{\n    RGBQUAD *quad;\n    ULONG rowWidth;\n\n    if (SUCCEEDED(GetBufferedPaintBits(PaintBuffer, &quad, &rowWidth)))\n    {\n        PULONG argb = (PULONG)quad;\n\n        if (!PhpHasAlpha(argb, Width, Height, rowWidth))\n        {\n            ICONINFO iconInfo;\n\n            if (GetIconInfo(Icon, &iconInfo))\n            {\n                if (iconInfo.hbmMask)\n                {\n                    PhpConvertToPArgb32(hdc, argb, iconInfo.hbmMask, Width, Height, rowWidth);\n                }\n\n                DeleteObject(iconInfo.hbmColor);\n                DeleteObject(iconInfo.hbmMask);\n            }\n        }\n    }\n}\n\nHBITMAP PhIconToBitmap(\n    _In_ HICON Icon,\n    _In_ ULONG Width,\n    _In_ ULONG Height\n    )\n{\n    HBITMAP bitmap;\n    RECT iconRectangle;\n    HDC screenHdc;\n    HDC hdc;\n    HBITMAP oldBitmap;\n    BLENDFUNCTION blendFunction = { AC_SRC_OVER, 0, 255, AC_SRC_ALPHA };\n    BP_PAINTPARAMS paintParams = { sizeof(paintParams) };\n    HDC bufferHdc;\n    HPAINTBUFFER paintBuffer;\n\n    iconRectangle.left = 0;\n    iconRectangle.top = 0;\n    iconRectangle.right = Width;\n    iconRectangle.bottom = Height;\n\n    screenHdc = GetDC(NULL);\n    hdc = CreateCompatibleDC(screenHdc);\n    bitmap = PhpCreateBitmap32(screenHdc, Width, Height, NULL);\n    ReleaseDC(NULL, screenHdc);\n    oldBitmap = SelectObject(hdc, bitmap);\n\n    paintParams.dwFlags = BPPF_ERASE;\n    paintParams.pBlendFunction = &blendFunction;\n\n    if (paintBuffer = BeginBufferedPaint(hdc, &iconRectangle, BPBF_DIB, &paintParams, &bufferHdc))\n    {\n        DrawIconEx(bufferHdc, 0, 0, Icon, Width, Height, 0, NULL, DI_NORMAL);\n        // If the icon did not have an alpha channel, we need to convert the buffer to PARGB.\n        PhpConvertToPArgb32IfNeeded(paintBuffer, hdc, Icon, Width, Height);\n        // This will write the buffer contents to the destination bitmap.\n        EndBufferedPaint(paintBuffer, TRUE);\n    }\n    else\n    {\n        // Default to unbuffered painting.\n        FillRect(hdc, &iconRectangle, (HBRUSH)(COLOR_WINDOW + 1));\n        DrawIconEx(hdc, 0, 0, Icon, Width, Height, 0, NULL, DI_NORMAL);\n        SelectObject(hdc, oldBitmap);\n    }\n\n    SelectObject(hdc, oldBitmap);\n    DeleteDC(hdc);\n\n    return bitmap;\n}\n"
  },
  {
    "path": "third_party/phlib/include/apiimport.h",
    "content": "#ifndef _PH_APIIMPORT_H\n#define _PH_APIIMPORT_H\n\n// ntdll\n\ntypedef NTSTATUS (NTAPI *_NtQueryInformationEnlistment)(\n    _In_ HANDLE EnlistmentHandle,\n    _In_ ENLISTMENT_INFORMATION_CLASS EnlistmentInformationClass,\n    _Out_writes_bytes_(EnlistmentInformationLength) PVOID EnlistmentInformation,\n    _In_ ULONG EnlistmentInformationLength,\n    _Out_opt_ PULONG ReturnLength\n    );\n\ntypedef NTSTATUS (NTAPI *_NtQueryInformationResourceManager)(\n    _In_ HANDLE ResourceManagerHandle,\n    _In_ RESOURCEMANAGER_INFORMATION_CLASS ResourceManagerInformationClass,\n    _Out_writes_bytes_(ResourceManagerInformationLength) PVOID ResourceManagerInformation,\n    _In_ ULONG ResourceManagerInformationLength,\n    _Out_opt_ PULONG ReturnLength\n    );\n\ntypedef NTSTATUS (NTAPI *_NtQueryInformationTransaction)(\n    _In_ HANDLE TransactionHandle,\n    _In_ TRANSACTION_INFORMATION_CLASS TransactionInformationClass,\n    _Out_writes_bytes_(TransactionInformationLength) PVOID TransactionInformation,\n    _In_ ULONG TransactionInformationLength,\n    _Out_opt_ PULONG ReturnLength\n    );\n\ntypedef NTSTATUS (NTAPI *_NtQueryInformationTransactionManager)(\n    _In_ HANDLE TransactionManagerHandle,\n    _In_ TRANSACTIONMANAGER_INFORMATION_CLASS TransactionManagerInformationClass,\n    _Out_writes_bytes_(TransactionManagerInformationLength) PVOID TransactionManagerInformation,\n    _In_ ULONG TransactionManagerInformationLength,\n    _Out_opt_ PULONG ReturnLength\n    );\n\n// shell32\n\n#if defined(_M_IX86)\n#define __unaligned\n#endif\n\ntypedef HRESULT (WINAPI *_SHCreateShellItem)(\n    _In_opt_ const struct _ITEMIDLIST __unaligned *pidlParent,\n    _In_opt_ struct IShellFolder *psfParent,\n    _In_ const struct _ITEMIDLIST __unaligned *pidl,\n    _Out_ struct IShellItem **ppsi\n    );\n\ntypedef HRESULT (WINAPI *_SHOpenFolderAndSelectItems)(\n    _In_ const struct _ITEMIDLIST __unaligned *pidlFolder,\n    _In_ UINT cidl,\n    _In_reads_opt_(cidl) const struct _ITEMIDLIST __unaligned **apidl,\n    _In_ ULONG dwFlags\n    );\n\ntypedef HRESULT (WINAPI *_SHParseDisplayName)(\n    _In_ LPCWSTR pszName,\n    _In_opt_ struct IBindCtx *pbc,\n    _Out_ const struct _ITEMIDLIST __unaligned **ppidl,\n    _In_ ULONG sfgaoIn,\n    _Out_ ULONG *psfgaoOut\n    );\n\n#define PH_DECLARE_IMPORT(Name) _##Name Name##_Import(VOID)\n\nPH_DECLARE_IMPORT(NtQueryInformationEnlistment);\nPH_DECLARE_IMPORT(NtQueryInformationResourceManager);\nPH_DECLARE_IMPORT(NtQueryInformationTransaction);\nPH_DECLARE_IMPORT(NtQueryInformationTransactionManager);\nPH_DECLARE_IMPORT(SHCreateShellItem);\nPH_DECLARE_IMPORT(SHOpenFolderAndSelectItems);\nPH_DECLARE_IMPORT(SHParseDisplayName);\n\n#endif\n"
  },
  {
    "path": "third_party/phlib/include/appresolver.h",
    "content": "/*\n * Process Hacker -\n *   Appmodel support functions\n *\n * Copyright (C) 2017-2018 dmex\n *\n * This file is part of Process Hacker.\n *\n * Process Hacker is free software; you can redistribute it and/or modify\n * it under the terms of the GNU General Public License as published by\n * the Free Software Foundation, either version 3 of the License, or\n * (at your option) any later version.\n *\n * Process Hacker is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n * GNU General Public License for more details.\n *\n * You should have received a copy of the GNU General Public License\n * along with Process Hacker.  If not, see <http://www.gnu.org/licenses/>.\n */\n\n#ifndef _PH_APPRESOLVER_H\n#define _PH_APPRESOLVER_H\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\nBOOLEAN PhAppResolverGetAppIdForProcess(\n    _In_ HANDLE ProcessId,\n    _Out_ PPH_STRING *ApplicationUserModelId\n    );\n\nPPH_LIST PhGetPackageAssetsFromResourceFile(\n    _In_ PWSTR FilePath\n    );\n\n#ifdef __cplusplus\n}\n#endif\n\n#endif\n"
  },
  {
    "path": "third_party/phlib/include/appresolverp.h",
    "content": "/*\n * Process Hacker -\n *   Appmodel support functions\n *\n * Copyright (C) 2017-2018 dmex\n *\n * This file is part of Process Hacker.\n *\n * Process Hacker is free software; you can redistribute it and/or modify\n * it under the terms of the GNU General Public License as published by\n * the Free Software Foundation, either version 3 of the License, or\n * (at your option) any later version.\n *\n * Process Hacker is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n * GNU General Public License for more details.\n *\n * You should have received a copy of the GNU General Public License\n * along with Process Hacker.  If not, see <http://www.gnu.org/licenses/>.\n */\n\n#ifndef _PH_APPRESOLVER_P_H\n#define _PH_APPRESOLVER_P_H\n\n// \"660B90C8-73A9-4B58-8CAE-355B7F55341B\"\nstatic CLSID CLSID_StartMenuCacheAndAppResolver_I = { 0x660B90C8, 0x73A9, 0x4B58,{ 0x8C, 0xAE, 0x35, 0x5B, 0x7F, 0x55, 0x34, 0x1B } };\n// \"46A6EEFF-908E-4DC6-92A6-64BE9177B41C\"\nstatic IID IID_IApplicationResolver61_I = { 0x46A6EEFF, 0x908E, 0x4DC6,{ 0x92, 0xA6, 0x64, 0xBE, 0x91, 0x77, 0xB4, 0x1c } };\n// \"DE25675A-72DE-44b4-9373-05170450C140\"\nstatic IID IID_IApplicationResolver62_I = { 0xDE25675A, 0x72DE, 0x44b4,{ 0x93, 0x73, 0x05, 0x17, 0x04, 0x50, 0xC1, 0x40 } };\n// \"33F71155-C2E9-4FFE-9786-A32D98577CFF\"\nstatic IID IID_IStartMenuAppItems61_I = { 0x33F71155, 0xC2E9, 0x4FFE,{ 0x97, 0x86, 0xA3, 0x2D, 0x98, 0x57, 0x7C, 0xFF } };\n// \"02C5CCF3-805F-4654-A7B7-340A74335365\"\nstatic IID IID_IStartMenuAppItems62_I = { 0x02C5CCF3, 0x805F, 0x4654,{ 0xA7, 0xB7, 0x34, 0x0A, 0x74, 0x33, 0x53, 0x65 } };\n\n// \"DBCE7E40-7345-439D-B12C-114A11819A09\"\nstatic CLSID CLSID_MrtResourceManager_I = { 0xDBCE7E40, 0x7345, 0x439D,{ 0xB1, 0x2C, 0x11, 0x4A, 0x11, 0x81, 0x9A, 0x09 } };\n// \"130A2F65-2BE7-4309-9A58-A9052FF2B61C\"\nstatic IID IID_IMrtResourceManager_I = { 0x130A2F65, 0x2BE7, 0x4309,{ 0x9A, 0x58, 0xA9, 0x05, 0x2F, 0xF2, 0xB6, 0x1C } };\n// \"E3C22B30-8502-4B2F-9133-559674587E51\"\nstatic IID IID_IResourceContext_I = { 0xE3C22B30, 0x8502, 0x4B2F,{ 0x91, 0x33, 0x55, 0x96, 0x74, 0x58, 0x7E, 0x51 } };\n// \"6E21E72B-B9B0-42AE-A686-983CF784EDCD\"\nstatic IID IID_IResourceMap_I = { 0x6E21E72B, 0xB9B0, 0x42AE,{ 0xA6, 0x86, 0x98, 0x3C, 0xF7, 0x84, 0xED, 0xCD } };\n\ntypedef enum _START_MENU_APP_ITEMS_FLAGS\n{\n    SMAIF_DEFAULT = 0,\n    SMAIF_EXTENDED = 1,\n    SMAIF_USAGEINFO = 2\n} START_MENU_APP_ITEMS_FLAGS;\n\n#undef INTERFACE\n#define INTERFACE IApplicationResolver61\nDECLARE_INTERFACE_IID(IApplicationResolver61, IUnknown)\n{\n    BEGIN_INTERFACE\n\n    // IUnknown\n    STDMETHOD(QueryInterface)(THIS, REFIID riid, PVOID *ppvObject) PURE;\n    STDMETHOD_(ULONG, AddRef)(THIS) PURE;\n    STDMETHOD_(ULONG, Release)(THIS) PURE;\n\n    // IApplicationResolver61\n    STDMETHOD(GetAppIDForShortcut)(THIS,\n        _In_ IShellItem *psi,\n        _Outptr_ PWSTR *ppszAppID\n        ) PURE;\n    STDMETHOD(GetAppIDForWindow)(THIS,\n        _In_ HWND hwnd,\n        _Outptr_ PWSTR *ppszAppID,\n        _Out_opt_ BOOL *pfPinningPrevented,\n        _Out_opt_ BOOL *pfExplicitAppID,\n        _Out_opt_ BOOL *pfEmbeddedShortcutValid\n        ) PURE;\n    STDMETHOD(GetAppIDForProcess)(THIS,\n        _In_ ULONG dwProcessID,\n        _Outptr_ PWSTR *ppszAppID,\n        _Out_opt_ BOOL *pfPinningPrevented,\n        _Out_opt_ BOOL *pfExplicitAppID,\n        _Out_opt_ BOOL *pfEmbeddedShortcutValid\n        ) PURE;\n    STDMETHOD(GetShortcutForProcess)(THIS,\n        _In_ ULONG dwProcessID,\n        _Outptr_ IShellItem **ppsi\n        ) PURE;\n    STDMETHOD(GetBestShortcutForAppID)(THIS,\n        _In_ PCWSTR pszAppID,\n        _Outptr_ IShellItem **ppsi\n        ) PURE;\n    STDMETHOD(GetBestShortcutAndAppIDForAppPath)(THIS,\n        _In_ PCWSTR pszAppPath,\n        _Outptr_opt_ IShellItem **ppsi,\n        _Outptr_opt_ PWSTR *ppszAppID\n        ) PURE;\n    STDMETHOD(CanPinApp)(THIS,\n        _In_ IShellItem *psi\n        ) PURE;\n    STDMETHOD(GetRelaunchProperties)(THIS,\n        _In_ HWND hwnd,\n        _Outptr_opt_result_maybenull_ PWSTR *ppszAppID,\n        _Outptr_opt_result_maybenull_ PWSTR *ppszCmdLine,\n        _Outptr_opt_result_maybenull_ PWSTR *ppszIconResource,\n        _Outptr_opt_result_maybenull_ PWSTR *ppszDisplayNameResource,\n        _Out_opt_ BOOL *pfPinnable\n        ) PURE;\n    STDMETHOD(GenerateShortcutFromWindowProperties)(THIS,\n        _In_ HWND hwnd,\n        _Outptr_ IShellItem **ppsi\n        ) PURE;\n    STDMETHOD(GenerateShortcutFromItemProperties)(THIS,\n        _In_ IShellItem2 *psi2,\n        _Out_opt_ IShellItem **ppsi\n        ) PURE;\n\n    END_INTERFACE\n};\n\n#define IApplicationResolver_QueryInterface(This, riid, ppvObject) \\\n    ((This)->lpVtbl->QueryInterface(This, riid, ppvObject))\n#define IApplicationResolver_AddRef(This)\t\\\n    ((This)->lpVtbl->AddRef(This))\n#define IApplicationResolver_Release(This) \\\n    ((This)->lpVtbl->Release(This))\n#define IApplicationResolver_GetAppIDForShortcut(This, psi, ppszAppID) \\\n    ((This)->lpVtbl->GetAppIDForShortcut(This, psi, ppszAppID))\n#define IApplicationResolver_GetAppIDForWindow(This, hwnd, ppszAppID, pfPinningPrevented, pfExplicitAppID, pfEmbeddedShortcutValid) \\\n    ((This)->lpVtbl->GetAppIDForWindow(This, hwnd, ppszAppID, pfPinningPrevented, pfExplicitAppID, pfEmbeddedShortcutValid))\n#define IApplicationResolver_GetAppIDForProcess(This, dwProcessID, ppszAppID, pfPinningPrevented, pfExplicitAppID, pfEmbeddedShortcutValid) \\\n    ((This)->lpVtbl->GetAppIDForProcess(This, dwProcessID, ppszAppID, pfPinningPrevented, pfExplicitAppID, pfEmbeddedShortcutValid))\n#define IApplicationResolver_GetShortcutForProcess(This, dwProcessID, ppsi) \\\n    ((This)->lpVtbl->GetShortcutForProcess(This, dwProcessID, ppsi))\n#define IApplicationResolver_GetBestShortcutForAppID(This, pszAppID, ppsi) \\\n    ((This)->lpVtbl->GetBestShortcutForAppID(This, pszAppID, ppsi))\n#define IApplicationResolver_GetBestShortcutAndAppIDForAppPath(This, pszAppPath, ppsi, ppszAppID) \\\n    ((This)->lpVtbl->GetBestShortcutAndAppIDForAppPath(This, pszAppPath, ppsi, ppszAppID))\n#define IApplicationResolver_CanPinApp(This, psi) \\\n    ((This)->lpVtbl->CanPinApp(This, psi))\n#define IApplicationResolver_GetRelaunchProperties(This, hwnd, ppszAppID, ppszCmdLine, ppszIconResource, ppszDisplayNameResource, pfPinnable) \\\n    ((This)->lpVtbl->GetRelaunchProperties(This, hwnd, ppszAppID, ppszCmdLine, ppszIconResource, ppszDisplayNameResource, pfPinnable))\n#define IApplicationResolver_GenerateShortcutFromWindowProperties(This, ppsi) \\\n    ((This)->lpVtbl->GenerateShortcutFromWindowProperties(This, ppsi))\n#define IApplicationResolver_GenerateShortcutFromItemProperties(This, psi2, ppsi) \\\n    ((This)->lpVtbl->GenerateShortcutFromItemProperties(This, psi2, ppsi))\n\n#undef INTERFACE\n#define INTERFACE IApplicationResolver62\nDECLARE_INTERFACE_IID(IApplicationResolver62, IUnknown)\n{\n    BEGIN_INTERFACE\n\n    // IUnknown\n    STDMETHOD(QueryInterface)(THIS, REFIID riid, PVOID *ppvObject) PURE;\n    STDMETHOD_(ULONG, AddRef)(THIS) PURE;\n    STDMETHOD_(ULONG, Release)(THIS) PURE;\n\n    // IApplicationResolver62\n    STDMETHOD(GetAppIDForShortcut)(THIS,\n        _In_ IShellItem *psi,\n        _Outptr_ PWSTR *ppszAppID\n        ) PURE;\n    STDMETHOD(GetAppIDForShortcutObject)(THIS,\n        _In_ IShellLinkW *psl,\n        _In_ IShellItem *psi,\n        _Outptr_ PWSTR *ppszAppID\n        ) PURE;\n    STDMETHOD(GetAppIDForWindow)(THIS,\n        _In_ HWND hwnd,\n        _Outptr_ PWSTR *ppszAppID,\n        _Out_opt_ BOOL *pfPinningPrevented,\n        _Out_opt_ BOOL *pfExplicitAppID,\n        _Out_opt_ BOOL *pfEmbeddedShortcutValid\n        ) PURE;\n    STDMETHOD(GetAppIDForProcess)(THIS,\n        _In_ ULONG dwProcessID,\n        _Outptr_ PWSTR *ppszAppID,\n        _Out_opt_ BOOL *pfPinningPrevented,\n        _Out_opt_ BOOL *pfExplicitAppID,\n        _Out_opt_ BOOL *pfEmbeddedShortcutValid\n        ) PURE;\n    STDMETHOD(GetShortcutForProcess)(THIS,\n        _In_ ULONG dwProcessID,\n        _Outptr_ IShellItem **ppsi\n        ) PURE;\n    STDMETHOD(GetBestShortcutForAppID)(THIS,\n        _In_ PCWSTR pszAppID,\n        _Outptr_ IShellItem **ppsi\n        ) PURE;\n    STDMETHOD(GetBestShortcutAndAppIDForAppPath)(THIS,\n        _In_ PCWSTR pszAppPath,\n        _Outptr_opt_ IShellItem **ppsi,\n        _Outptr_opt_ PWSTR *ppszAppID\n        ) PURE;\n    STDMETHOD(CanPinApp)(THIS,\n        _In_ IShellItem *psi\n        ) PURE;\n    STDMETHOD(CanPinAppShortcut)(THIS,\n        _In_ IShellLinkW *psl,\n        _In_ IShellItem *psi\n        ) PURE;\n    STDMETHOD(GetRelaunchProperties)(THIS,\n        _In_ HWND hwnd,\n        _Outptr_opt_result_maybenull_ PWSTR *ppszAppID,\n        _Outptr_opt_result_maybenull_ PWSTR *ppszCmdLine,\n        _Outptr_opt_result_maybenull_ PWSTR *ppszIconResource,\n        _Outptr_opt_result_maybenull_ PWSTR *ppszDisplayNameResource,\n        _Out_opt_ BOOL *pfPinnable\n        ) PURE;\n    STDMETHOD(GenerateShortcutFromWindowProperties)(THIS,\n        _In_ HWND hwnd,\n        _Outptr_ IShellItem **ppsi\n        ) PURE;\n    STDMETHOD(GenerateShortcutFromItemProperties)(THIS,\n        _In_ IShellItem2 *psi2,\n        _Out_opt_ IShellItem **ppsi\n        ) PURE;\n\n    END_INTERFACE\n};\n\n#define IApplicationResolver2_QueryInterface(This, riid, ppvObject) \\\n    ((This)->lpVtbl->QueryInterface(This, riid, ppvObject))\n#define IApplicationResolver2_AddRef(This)\t\\\n    ((This)->lpVtbl->AddRef(This))\n#define IApplicationResolver2_Release(This) \\\n    ((This)->lpVtbl->Release(This))\n#define IApplicationResolver2_GetAppIDForShortcut(This, psl, psi, ppszAppID) \\\n    ((This)->lpVtbl->GetAppIDForShortcut(This, psl, psi, ppszAppID))\n#define IApplicationResolver2_GetAppIDForShortcutObject(This, psl, ppszAppID) \\\n    ((This)->lpVtbl->GetAppIDForShortcutObject(This, psl, ppszAppID))\n#define IApplicationResolver2_GetAppIDForWindow(This, hwnd, ppszAppID, pfPinningPrevented, pfExplicitAppID, pfEmbeddedShortcutValid) \\\n    ((This)->lpVtbl->GetAppIDForWindow(This, hwnd, ppszAppID, pfPinningPrevented, pfExplicitAppID, pfEmbeddedShortcutValid))\n#define IApplicationResolver2_GetAppIDForProcess(This, dwProcessID, ppszAppID, pfPinningPrevented, pfExplicitAppID, pfEmbeddedShortcutValid) \\\n    ((This)->lpVtbl->GetAppIDForProcess(This, dwProcessID, ppszAppID, pfPinningPrevented, pfExplicitAppID, pfEmbeddedShortcutValid))\n#define IApplicationResolver2_GetShortcutForProcess(This, dwProcessID, ppsi) \\\n    ((This)->lpVtbl->GetShortcutForProcess(This, dwProcessID, ppsi))\n#define IApplicationResolver2_GetBestShortcutForAppID(This, pszAppID, ppsi) \\\n    ((This)->lpVtbl->GetBestShortcutForAppID(This, pszAppID, ppsi))\n#define IApplicationResolver2_GetBestShortcutAndAppIDForAppPath(This, pszAppPath, ppsi, ppszAppID) \\\n    ((This)->lpVtbl->GetBestShortcutAndAppIDForAppPath(This, pszAppPath, ppsi, ppszAppID))\n#define IApplicationResolver2_CanPinApp(This, psi) \\\n    ((This)->lpVtbl->CanPinApp(This, psi))\n#define IApplicationResolver2_CanPinAppShortcut(This, psl, psi) \\\n    ((This)->lpVtbl->CanPinAppShortcut(This, psl, psi))\n#define IApplicationResolver2_GetRelaunchProperties(This, hwnd, ppszAppID, ppszCmdLine, ppszIconResource, ppszDisplayNameResource, pfPinnable) \\\n    ((This)->lpVtbl->GetRelaunchProperties(This, hwnd, ppszAppID, ppszCmdLine, ppszIconResource, ppszDisplayNameResource, pfPinnable))\n#define IApplicationResolver2_GenerateShortcutFromWindowProperties(This, ppsi) \\\n    ((This)->lpVtbl->GenerateShortcutFromWindowProperties(This, ppsi))\n#define IApplicationResolver2_GenerateShortcutFromItemProperties(This, psi2, ppsi) \\\n    ((This)->lpVtbl->GenerateShortcutFromItemProperties(This, psi2, ppsi))\n\n#undef INTERFACE\n#define INTERFACE IStartMenuAppItems61\nDECLARE_INTERFACE_IID(IStartMenuAppItems61, IUnknown)\n{\n    BEGIN_INTERFACE\n\n    // IUnknown\n    STDMETHOD(QueryInterface)(THIS, REFIID riid, PVOID *ppvObject) PURE;\n    STDMETHOD_(ULONG, AddRef)(THIS) PURE;\n    STDMETHOD_(ULONG, Release)(THIS) PURE;\n\n    // IStartMenuAppItems61\n    STDMETHOD(EnumItems)(THIS,\n        _In_ ULONG Flags,\n        _In_ REFIID riid,\n        _Outptr_ IEnumObjects *ppvObject\n        ) PURE;\n    STDMETHOD(GetItem)(THIS,\n        _In_ ULONG Flags,\n        _In_ PWSTR AppUserModelId,\n        _In_ REFIID riid,\n        _Outptr_ PVOID *ppvObject // ppvObject == IPropertyStore, IStartMenuAppItems61\n        ) PURE;\n\n    END_INTERFACE\n};\n\n#define IStartMenuAppItems_QueryInterface(This, riid, ppvObject) \\\n    ((This)->lpVtbl->QueryInterface(This, riid, ppvObject))\n#define IStartMenuAppItems_AddRef(This)\t\\\n    ((This)->lpVtbl->AddRef(This))\n#define IStartMenuAppItems_Release(This) \\\n    ((This)->lpVtbl->Release(This))\n#define IStartMenuAppItems_EnumItems(This, Flags, riid, ppvObject) \\\n    ((This)->lpVtbl->EnumItems(This, Flags, riid, ppvObject))\n#define IStartMenuAppItems_GetItem(This, Flags, AppUserModelId, riid, ppvObject) \\\n    ((This)->lpVtbl->GetItem(This, Flags, AppUserModelId, riid, ppvObject))\n\n#undef INTERFACE\n#define INTERFACE IStartMenuAppItems62\nDECLARE_INTERFACE_IID(IStartMenuAppItems62, IUnknown)\n{\n    BEGIN_INTERFACE\n\n    // IUnknown\n    STDMETHOD(QueryInterface)(THIS, REFIID riid, PVOID *ppvObject) PURE;\n    STDMETHOD_(ULONG, AddRef)(THIS) PURE;\n    STDMETHOD_(ULONG, Release)(THIS) PURE;\n\n    // IStartMenuAppItems62\n    STDMETHOD(EnumItems)(THIS,\n        _In_ ULONG Flags,\n        _In_ REFIID riid,\n        _Outptr_ IEnumObjects *ppvObject\n        ) PURE;\n    STDMETHOD(GetItem)(THIS,\n        _In_ ULONG Flags,\n        _In_ PWSTR AppUserModelId,\n        _In_ REFIID riid,\n        _Outptr_ PVOID *ppvObject // ppvObject == IPropertyStore, IStartMenuAppItems61\n        ) PURE;\n    // STDMETHOD(Unknown)(THIS)\n    // STDMETHOD(Unknown)(THIS)\n\n    END_INTERFACE\n};\n\n#define IStartMenuAppItems2_QueryInterface(This, riid, ppvObject) \\\n    ((This)->lpVtbl->QueryInterface(This, riid, ppvObject))\n#define IStartMenuAppItems2_AddRef(This)\t\\\n    ((This)->lpVtbl->AddRef(This))\n#define IStartMenuAppItems2_Release(This) \\\n    ((This)->lpVtbl->Release(This))\n#define IStartMenuAppItems2_EnumItems(This, Flags, riid, ppvObject) \\\n    ((This)->lpVtbl->EnumItems(This, Flags, riid, ppvObject))\n#define IStartMenuAppItems2_GetItem(This, Flags, AppUserModelId, riid, ppvObject) \\\n    ((This)->lpVtbl->GetItem(This, Flags, AppUserModelId, riid, ppvObject))\n\n#undef INTERFACE\n#define INTERFACE IMrtResourceManager\nDECLARE_INTERFACE_IID(IMrtResourceManager, IUnknown)\n{\n    BEGIN_INTERFACE\n\n    // IUnknown\n    STDMETHOD(QueryInterface)(THIS, REFIID riid, PVOID *ppvObject) PURE;\n    STDMETHOD_(ULONG, AddRef)(THIS) PURE;\n    STDMETHOD_(ULONG, Release)(THIS) PURE;\n\n    // IMrtResourceManager\n    STDMETHOD(Initialize)(THIS) PURE;\n    STDMETHOD(InitializeForCurrentApplication)(THIS) PURE;\n    STDMETHOD(InitializeForPackage)(THIS, PCWSTR PackageName) PURE;\n    STDMETHOD(InitializeForFile)(THIS, PCWSTR) PURE;\n    STDMETHOD(GetMainResourceMap)(THIS, REFIID riid, PVOID *ppvObject) PURE; // IResourceMap\n    STDMETHOD(GetResourceMap)(THIS, PCWSTR, REFIID riid, PVOID *ppvObject) PURE; // IResourceMap\n    STDMETHOD(GetDefaultContext)(THIS, REFIID riid, PVOID *ppvObject) PURE; // IResourceContext\n    STDMETHOD(GetReference)(THIS, REFIID riid, PVOID *ppvObject) PURE;\n    STDMETHOD(IsResourceReference)(THIS, PCWSTR, BOOL *IsReference) PURE;\n\n    END_INTERFACE\n};\n\n#define IMrtResourceManager_QueryInterface(This, riid, ppvObject) \\\n    ((This)->lpVtbl->QueryInterface(This, riid, ppvObject)) \n#define IMrtResourceManager_AddRef(This)\t\\\n    ((This)->lpVtbl->AddRef(This))\n#define IMrtResourceManager_Release(This) \\\n    ((This)->lpVtbl->Release(This)) \n#define IMrtResourceManager_Initialize(This) \\\n    ((This)->lpVtbl->Initialize(This)) \n#define IMrtResourceManager_InitializeForCurrentApplication(This) \\\n    ((This)->lpVtbl->InitializeForCurrentApplication(This))\n#define IMrtResourceManager_InitializeForPackage(This, PackageName) \\\n    ((This)->lpVtbl->InitializeForPackage(This, PackageName))\n#define IMrtResourceManager_InitializeForFile(This, FilePath) \\\n    ((This)->lpVtbl->InitializeForFile(This, FilePath))\n#define IMrtResourceManager_GetMainResourceMap(This, riid, ppvObject) \\\n    ((This)->lpVtbl->GetMainResourceMap(This, riid, ppvObject))\n#define IMrtResourceManager_GetResourceMap(This, Name, riid, ppvObject) \\\n    ((This)->lpVtbl->GetResourceMap(This, Name, riid, ppvObject))\n#define IMrtResourceManager_GetDefaultContext(This, riid, ppvObject) \\\n    ((This)->lpVtbl->GetDefaultContext(This, riid, ppvObject))\n#define IMrtResourceManager_GetReference(This, riid, ppvObject) \\\n    ((This)->lpVtbl->GetReference(This, riid, ppvObject))\n#define IMrtResourceManager_IsResourceReference(This, Name, IsReference) \\\n    ((This)->lpVtbl->IsResourceReference(This, Name, IsReference))\n\n#undef INTERFACE\n#define INTERFACE IResourceContext\nDECLARE_INTERFACE_IID(IResourceContext, IUnknown)\n{\n    BEGIN_INTERFACE\n\n    // IUnknown\n    STDMETHOD(QueryInterface)(THIS, REFIID riid, PVOID *ppvObject) PURE;\n    STDMETHOD_(ULONG, AddRef)(THIS) PURE;\n    STDMETHOD_(ULONG, Release)(THIS) PURE;\n\n    // IResourceContext\n    STDMETHOD(GetLanguage)(THIS, PWSTR*) PURE;\n    STDMETHOD(GetHomeRegion)(THIS, PCWSTR*) PURE;\n    STDMETHOD(GetLayoutDirection)(THIS, ULONG*) PURE; // RESOURCE_LAYOUT_DIRECTION\n    STDMETHOD(GetTargetSize)(THIS, USHORT*) PURE;\n    STDMETHOD(GetScale)(THIS, ULONG*) PURE; // RESOURCE_SCALE\n    STDMETHOD(GetContrast)(THIS, ULONG*) PURE; // RESOURCE_CONTRAST\n    STDMETHOD(GetAlternateForm)(THIS, PCWSTR*) PURE;\n    STDMETHOD(GetQualifierValue)(THIS, LPCWSTR, LPWSTR*) PURE;\n    STDMETHOD(SetLanguage)(THIS, LPCWSTR) PURE;\n    STDMETHOD(SetHomeRegion)(THIS, LPCWSTR) PURE;\n    STDMETHOD(SetLayoutDirection)(THIS, ULONG) PURE; // RESOURCE_LAYOUT_DIRECTION\n    STDMETHOD(SetTargetSize)(THIS, USHORT) PURE;\n    STDMETHOD(SetScale)(THIS, ULONG) PURE; // RESOURCE_SCALE\n    STDMETHOD(SetContrast)(THIS, ULONG) PURE; // RESOURCE_CONTRAST\n    STDMETHOD(SetAlternateForm)(THIS, LPCWSTR) PURE;\n    STDMETHOD(SetQualifierValue)(THIS, LPCWSTR, LPCWSTR) PURE;\n    STDMETHOD(TrySetQualifierValue)(THIS, LPCWSTR, LPCWSTR, HRESULT*) PURE;\n    STDMETHOD(Reset)(THIS) PURE;\n    STDMETHOD(ResetQualifierValue)(THIS, LPCWSTR) PURE;\n    STDMETHOD(Clone)(THIS, IResourceContext**) PURE;\n    STDMETHOD(OverrideToMatch)(THIS, struct IResourceCandidate*) PURE;\n\n    END_INTERFACE\n};\n\n#undef INTERFACE\n#define INTERFACE IResourceMap\nDECLARE_INTERFACE_IID(IResourceMap, IUnknown)\n{\n    BEGIN_INTERFACE\n\n    // IUnknown\n    STDMETHOD(QueryInterface)(THIS, REFIID riid, PVOID *ppvObject) PURE;\n    STDMETHOD_(ULONG, AddRef)(THIS) PURE;\n    STDMETHOD_(ULONG, Release)(THIS) PURE;\n\n    // IResourceMap\n    STDMETHOD(GetUri)(THIS, PWSTR *UriString) PURE;\n    STDMETHOD(GetSubtree)(THIS, PCWSTR *Name, IResourceMap** ResourceMap) PURE;\n    STDMETHOD(GetString)(THIS, PCWSTR Key, PWSTR *Value) PURE;\n    STDMETHOD(GetStringForContext)(THIS, IResourceContext* Context, PCWSTR Key, PWSTR *Value) PURE;\n    STDMETHOD(GetFilePath)(THIS, PCWSTR Key, PWSTR *Value) PURE;\n    STDMETHOD(GetFilePathForContext)(THIS, IResourceContext*, PCWSTR, PWSTR*) PURE;\n    STDMETHOD(GetNamedResourceCount)(THIS, PULONG) PURE;\n    STDMETHOD(GetNamedResourceUri)(THIS, ULONG, PWSTR*) PURE;\n    STDMETHOD(GetNamedResource)(THIS, PCWSTR, REFIID riid, PVOID *ppvObject) PURE;\n    STDMETHOD(GetFullyQualifiedReference)(THIS, LPCWSTR, LPCWSTR, LPWSTR*) PURE;\n    STDMETHOD(GetFilePathByUri)(THIS, IUri*, LPWSTR*) PURE;\n    STDMETHOD(GetFilePathForContextByUri)(THIS, IResourceContext*, IUri*, LPWSTR*) PURE;\n\n    END_INTERFACE\n};\n\n#define IResourceMap_QueryInterface(This, riid, ppvObject) \\\n    ((This)->lpVtbl->QueryInterface(This, riid, ppvObject)) \n#define IResourceMap_AddRef(This)\t\\\n    ((This)->lpVtbl->AddRef(This))\n#define IResourceMap_Release(This) \\\n    ((This)->lpVtbl->Release(This)) \n#define IResourceMap_GetUri(This, UriString) \\\n    ((This)->lpVtbl->GetUri(This, UriString)) \n#define IResourceMap_GetSubtree(This, Name, ResourceMap) \\\n    ((This)->lpVtbl->GetSubtree(This, Name, ResourceMap)) \n#define IResourceMap_GetString(This, Key, Value) \\\n    ((This)->lpVtbl->GetString(This, Key, Value)) \n#define IResourceMap_GetStringForContext(This, Context, Key, Value) \\\n    ((This)->lpVtbl->GetStringForContext(This, Context, Key, Value)) \n#define IResourceMap_GetFilePath(This, Key, Value) \\\n    ((This)->lpVtbl->GetFilePath(This, Key, Value)) \n#define IResourceMap_GetFilePathForContext(This) \\\n    ((This)->lpVtbl->GetFilePathForContext(This)) \n#define IResourceMap_GetNamedResourceCount(This, Count) \\\n    ((This)->lpVtbl->GetNamedResourceCount(This, Count)) \n#define IResourceMap_GetNamedResourceUri(This, Index, Name) \\\n    ((This)->lpVtbl->GetNamedResourceUri(This, Index, Name)) \n#define IResourceMap_GetNamedResource(This) \\\n    ((This)->lpVtbl->GetNamedResource(This)) \n#define IResourceMap_GetFullyQualifiedReference(This) \\\n    ((This)->lpVtbl->GetFullyQualifiedReference(This)) \n#define IResourceMap_GetFilePathByUri(This) \\\n    ((This)->lpVtbl->GetFilePathByUri(This)) \n#define IResourceMap_GetFilePathForContextByUri(This) \\\n    ((This)->lpVtbl->GetFilePathForContextByUri(This)) \n\n// Note: Documented PKEY_AppUserModel_XYZ keys can be found in propkey.h\nDEFINE_PROPERTYKEY(PKEY_AppUserModel_HostEnvironment, 0x9F4C2855, 0x9F79, 0x4B39, 0xA8, 0xD0, 0xE1, 0xD4, 0x2D, 0xE1, 0xD5, 0xF3, 14);\nDEFINE_PROPERTYKEY(PKEY_AppUserModel_PackageInstallPath, 0x9F4C2855, 0x9F79, 0x4B39, 0xA8, 0xD0, 0xE1, 0xD4, 0x2D, 0xE1, 0xD5, 0xF3, 15);\nDEFINE_PROPERTYKEY(PKEY_AppUserModel_PackageFamilyName, 0x9F4C2855, 0x9F79, 0x4B39, 0xA8, 0xD0, 0xE1, 0xD4, 0x2D, 0xE1, 0xD5, 0xF3, 17);\nDEFINE_PROPERTYKEY(PKEY_AppUserModel_ParentID, 0x9F4C2855, 0x9F79, 0x4B39, 0xA8, 0xD0, 0xE1, 0xD4, 0x2D, 0xE1, 0xD5, 0xF3, 19);\nDEFINE_PROPERTYKEY(PKEY_AppUserModel_PackageFullName, 0x9F4C2855, 0x9F79, 0x4B39, 0xA8, 0xD0, 0xE1, 0xD4, 0x2D, 0xE1, 0xD5, 0xF3, 21);\n// PKEY_AppUserModel_ExcludeFromShowInNewInstall {9f4c2855-9f79-4b39-a8d0-e1d42de1d5f3} 8\n//2\tPKEY_AppUserModel_ID {9f4c2855-9f79-4b39-a8d0-e1d42de1d5f3} 5\n//3\tPKEY_AppUserModel_IsDestListSeparator {9f4c2855-9f79-4b39-a8d0-e1d42de1d5f3} 6\n//4\tPKEY_AppUserModel_IsDualMode {9f4c2855-9f79-4b39-a8d0-e1d42de1d5f3} 11\n//5\tPKEY_AppUserModel_PreventPinning {9f4c2855-9f79-4b39-a8d0-e1d42de1d5f3} 9\n//6\tPKEY_AppUserModel_RelaunchCommand {9f4c2855-9f79-4b39-a8d0-e1d42de1d5f3} 2\n//7\tPKEY_AppUserModel_RelaunchDisplayNameResource {9f4c2855-9f79-4b39-a8d0-e1d42de1d5f3} 4\n//8\tPKEY_AppUserModel_RelaunchIconResource {9f4c2855-9f79-4b39-a8d0-e1d42de1d5f3} 3\n//9\tPKEY_AppUserModel_StartPinOption {9f4c2855-9f79-4b39-a8d0-e1d42de1d5f3} 12\n//10 PKEY_AppUserModel_ToastActivatorCLSID {9f4c2855-9f79-4b39-a8d0-e1d42de1d5f3} 26\n//11 PKEY_AppUserModel_PackageInstallPath {9f4c2855-9f79-4b39-a8d0-e1d42de1d5f3} 15\n//12 PKEY_AppUserModel_RecordState {9f4c2855-9f79-4b39-a8d0-e1d42de1d5f3} 16\n//13 PKEY_AppUserModel_PackageFullName {9f4c2855-9f79-4b39-a8d0-e1d42de1d5f3} 21\n//14 PKEY_AppUserModel_DestListProvidedTitle {9f4c2855-9f79-4b39-a8d0-e1d42de1d5f3} 27\n//15 PKEY_AppUserModel_DestListProvidedDescription {9f4c2855-9f79-4b39-a8d0-e1d42de1d5f3} 28\n//16 PKEY_AppUserModel_ParentID\t{9f4c2855-9f79-4b39-a8d0-e1d42de1d5f3} 19\n//17 PKEY_AppUserModel_HostEnvironment {9f4c2855-9f79-4b39-a8d0-e1d42de1d5f3} 14\n//18 PKEY_AppUserModel_Relevance {9f4c2855-9f79-4b39-a8d0-e1d42de1d5f3} 13\n//19 PKEY_AppUserModel_PackageRelativeApplicationID\t{9f4c2855-9f79-4b39-a8d0-e1d42de1d5f3} 22\n//20 PKEY_AppUserModel_ExcludedFromLauncher {9f4c2855-9f79-4b39-a8d0-e1d42de1d5f3} 23\n//21 PKEY_AppUserModel_DestListLogoUri {9f4c2855-9f79-4b39-a8d0-e1d42de1d5f3} 29\n//22 PKEY_AppUserModel_ActivationContext {9f4c2855-9f79-4b39-a8d0-e1d42de1d5f3} 20\n//23 PKEY_AppUserModel_PackageFamilyName {9f4c2855-9f79-4b39-a8d0-e1d42de1d5f3} 17\n//24 PKEY_AppUserModel_BestShortcut\t{9f4c2855-9f79-4b39-a8d0-e1d42de1d5f3} 10\n//25 PKEY_AppUserModel_IsDestListLink {9f4c2855-9f79-4b39-a8d0-e1d42de1d5f3} 7\n//26 PKEY_AppUserModel_InstalledBy {9f4c2855-9f79-4b39-a8d0-e1d42de1d5f3} 18\n//27 PKEY_AppUserModel_RunFlags\t{9f4c2855-9f79-4b39-a8d0-e1d42de1d5f3} 25\n//28 PKEY_AppUserModel_DestListProvidedGroupName {9f4c2855-9f79-4b39-a8d0-e1d42de1d5f3} 30\nDEFINE_PROPERTYKEY(PKEY_Tile_SmallLogoPath, 0x86D40B4D, 0x9069, 0x443C, 0x81, 0x9A, 0x2A, 0x54, 0x09, 0x0D, 0xCC, 0xEC, 2);\nDEFINE_PROPERTYKEY(PKEY_Tile_Background, 0x86D40B4D, 0x9069, 0x443C, 0x81, 0x9A, 0x2A, 0x54, 0x09, 0x0D, 0xCC, 0xEC, 4);\nDEFINE_PROPERTYKEY(PKEY_Tile_Foreground, 0x86D40B4D, 0x9069, 0x443C, 0x81, 0x9A, 0x2A, 0x54, 0x09, 0x0D, 0xCC, 0xEC, 5);\nDEFINE_PROPERTYKEY(PKEY_Tile_LongDisplayName, 0x86D40B4D, 0x9069, 0x443C, 0x81, 0x9A, 0x2A, 0x54, 0x09, 0x0D, 0xCC, 0xEC, 11);\nDEFINE_PROPERTYKEY(PKEY_Tile_Flags, 0x86D40B4D, 0x9069, 0x443C, 0x81, 0x9A, 0x2A, 0x54, 0x09, 0x0D, 0xCC, 0xEC, 14);\nDEFINE_PROPERTYKEY(PKEY_Tile_SuiteDisplayName, 0x86D40B4D, 0x9069, 0x443C, 0x81, 0x9A, 0x2A, 0x54, 0x09, 0x0D, 0xCC, 0xEC, 16);\nDEFINE_PROPERTYKEY(PKEY_Tile_SuiteSortName, 0x86D40B4D, 0x9069, 0x443C, 0x81, 0x9A, 0x2A, 0x54, 0x09, 0x0D, 0xCC, 0xEC, 17);\nDEFINE_PROPERTYKEY(PKEY_Tile_DisplayNameLanguage, 0x86D40B4D, 0x9069, 0x443C, 0x81, 0x9A, 0x2A, 0x54, 0x09, 0x0D, 0xCC, 0xEC, 18);\nDEFINE_PROPERTYKEY(PKEY_Tile_BadgeLogoPath, 0x86D40B4D, 0x9069, 0x443C, 0x81, 0x9A, 0x2A, 0x54, 0x09, 0x0D, 0xCC, 0xEC, 15);\nDEFINE_PROPERTYKEY(PKEY_Tile_Square150x150LogoPath, 0x86D40B4D, 0x9069, 0x443C, 0x81, 0x9A, 0x2A, 0x54, 0x09, 0x0D, 0xCC, 0xEC, 12);\nDEFINE_PROPERTYKEY(PKEY_Tile_Wide310x150LogoPath, 0x86D40B4D, 0x9069, 0x443C, 0x81, 0x9A, 0x2A, 0x54, 0x09, 0x0D, 0xCC, 0xEC, 13);\nDEFINE_PROPERTYKEY(PKEY_Tile_Square310x310LogoPath, 0x86D40B4D, 0x9069, 0x443C, 0x81, 0x9A, 0x2A, 0x54, 0x09, 0x0D, 0xCC, 0xEC, 19);\nDEFINE_PROPERTYKEY(PKEY_Tile_Square70x70LogoPath, 0x86D40B4D, 0x9069, 0x443C, 0x81, 0x9A, 0x2A, 0x54, 0x09, 0x0D, 0xCC, 0xEC, 20);\nDEFINE_PROPERTYKEY(PKEY_Tile_FencePost, 0x86D40B4D, 0x9069, 0x443C, 0x81, 0x9A, 0x2A, 0x54, 0x09, 0x0D, 0xCC, 0xEC, 21);\nDEFINE_PROPERTYKEY(PKEY_Tile_InstallProgress, 0x86D40B4D, 0x9069, 0x443C, 0x81, 0x9A, 0x2A, 0x54, 0x09, 0x0D, 0xCC, 0xEC, 22);\nDEFINE_PROPERTYKEY(PKEY_Tile_EncodedTargetPath, 0x86D40B4D, 0x9069, 0x443C, 0x81, 0x9A, 0x2A, 0x54, 0x09, 0x0D, 0xCC, 0xEC, 23);\n\n#endif\n"
  },
  {
    "path": "third_party/phlib/include/circbuf.h",
    "content": "#ifndef _PH_CIRCBUF_H\n#define _PH_CIRCBUF_H\n\n#define PH_CIRCULAR_BUFFER_POWER_OF_TWO_SIZE\n\n#undef T\n#define T ULONG\n#include \"circbuf_h.h\"\n\n#undef T\n#define T ULONG64\n#include \"circbuf_h.h\"\n\n#undef T\n#define T PVOID\n#include \"circbuf_h.h\"\n\n#undef T\n#define T SIZE_T\n#include \"circbuf_h.h\"\n\n#undef T\n#define T FLOAT\n#include \"circbuf_h.h\"\n\n#endif\n"
  },
  {
    "path": "third_party/phlib/include/circbuf_h.h",
    "content": "#ifdef T\n\n#include <templ.h>\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\ntypedef struct T___(_PH_CIRCULAR_BUFFER, T)\n{\n    ULONG Size;\n#ifdef PH_CIRCULAR_BUFFER_POWER_OF_TWO_SIZE\n    ULONG SizeMinusOne;\n#endif\n    ULONG Count;\n    LONG Index;\n    T *Data;\n} T___(PH_CIRCULAR_BUFFER, T), *T___(PPH_CIRCULAR_BUFFER, T);\n\nPHLIBAPI\nVOID\nNTAPI\nT___(PhInitializeCircularBuffer, T)(\n    _Out_ T___(PPH_CIRCULAR_BUFFER, T) Buffer,\n    _In_ ULONG Size\n    );\n\nPHLIBAPI\nVOID\nNTAPI\nT___(PhDeleteCircularBuffer, T)(\n    _Inout_ T___(PPH_CIRCULAR_BUFFER, T) Buffer\n    );\n\nPHLIBAPI\nVOID\nNTAPI\nT___(PhResizeCircularBuffer, T)(\n    _Inout_ T___(PPH_CIRCULAR_BUFFER, T) Buffer,\n    _In_ ULONG NewSize\n    );\n\nPHLIBAPI\nVOID\nNTAPI\nT___(PhClearCircularBuffer, T)(\n    _Inout_ T___(PPH_CIRCULAR_BUFFER, T) Buffer\n    );\n\nPHLIBAPI\nVOID\nNTAPI\nT___(PhCopyCircularBuffer, T)(\n    _Inout_ T___(PPH_CIRCULAR_BUFFER, T) Buffer,\n    _Out_writes_(Count) T *Destination,\n    _In_ ULONG Count\n    );\n\nFORCEINLINE T T___(PhGetItemCircularBuffer, T)(\n    _In_ T___(PPH_CIRCULAR_BUFFER, T) Buffer,\n    _In_ LONG Index\n    )\n{\n#ifdef PH_CIRCULAR_BUFFER_POWER_OF_TWO_SIZE\n    return Buffer->Data[(Buffer->Index + Index) & Buffer->SizeMinusOne];\n#else\n    ULONG size;\n\n    size = Buffer->Size;\n    // Modulo is dividend-based.\n    return Buffer->Data[(((Buffer->Index + Index) % size) + size) % size];\n#endif\n}\n\nFORCEINLINE VOID T___(PhSetItemCircularBuffer, T)(\n    _Inout_ T___(PPH_CIRCULAR_BUFFER, T) Buffer,\n    _In_ LONG Index,\n    _In_ T Value\n    )\n{\n#ifdef PH_CIRCULAR_BUFFER_POWER_OF_TWO_SIZE\n    Buffer->Data[(Buffer->Index + Index) & Buffer->SizeMinusOne] = Value;\n#else\n    ULONG size;\n\n    size = Buffer->Size;\n    Buffer->Data[(((Buffer->Index + Index) % size) + size) % size] = Value;\n#endif\n}\n\nFORCEINLINE VOID T___(PhAddItemCircularBuffer, T)(\n    _Inout_ T___(PPH_CIRCULAR_BUFFER, T) Buffer,\n    _In_ T Value\n    )\n{\n#ifdef PH_CIRCULAR_BUFFER_POWER_OF_TWO_SIZE\n    Buffer->Data[Buffer->Index = ((Buffer->Index - 1) & Buffer->SizeMinusOne)] = Value;\n#else\n    ULONG size;\n\n    size = Buffer->Size;\n    Buffer->Data[Buffer->Index = (((Buffer->Index - 1) % size) + size) % size] = Value;\n#endif\n\n    if (Buffer->Count < Buffer->Size)\n        Buffer->Count++;\n}\n\nFORCEINLINE T T___(PhAddItemCircularBuffer2, T)(\n    _Inout_ T___(PPH_CIRCULAR_BUFFER, T) Buffer,\n    _In_ T Value\n    )\n{\n    LONG index;\n    T oldValue;\n\n#ifdef PH_CIRCULAR_BUFFER_POWER_OF_TWO_SIZE\n    index = ((Buffer->Index - 1) & Buffer->SizeMinusOne);\n#else\n    ULONG size;\n\n    size = Buffer->Size;\n    index = (((Buffer->Index - 1) % size) + size) % size;\n#endif\n\n    Buffer->Index = index;\n    oldValue = Buffer->Data[index];\n    Buffer->Data[index] = Value;\n\n    if (Buffer->Count < Buffer->Size)\n        Buffer->Count++;\n\n    return oldValue;\n}\n\n#ifdef __cplusplus\n}\n#endif\n\n#endif\n"
  },
  {
    "path": "third_party/phlib/include/colorbox.h",
    "content": "#ifndef _PH_COLORBOX_H\n#define _PH_COLORBOX_H\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\n#define PH_COLORBOX_CLASSNAME L\"PhColorBox\"\n\nPHLIBAPI\nBOOLEAN\nNTAPI\nPhColorBoxInitialization(\n    VOID\n    );\n\n#define CBCM_SETCOLOR (WM_APP + 1501)\n#define CBCM_GETCOLOR (WM_APP + 1502)\n\n#define ColorBox_SetColor(hWnd, Color) \\\n    SendMessage((hWnd), CBCM_SETCOLOR, (WPARAM)(Color), 0)\n\n#define ColorBox_GetColor(hWnd) \\\n    ((COLORREF)SendMessage((hWnd), CBCM_GETCOLOR, 0, 0))\n\n#ifdef __cplusplus\n}\n#endif\n\n#endif\n"
  },
  {
    "path": "third_party/phlib/include/cpysave.h",
    "content": "#ifndef _PH_CPYSAVE_H\n#define _PH_CPYSAVE_H\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\n#define PH_EXPORT_MODE_TABS 0\n#define PH_EXPORT_MODE_SPACES 1\n#define PH_EXPORT_MODE_CSV 2\n\nPHLIBAPI\nVOID PhaCreateTextTable(\n    _Out_ PPH_STRING ***Table,\n    _In_ ULONG Rows,\n    _In_ ULONG Columns\n    );\n\nPHLIBAPI\nPPH_LIST PhaFormatTextTable(\n    _In_ PPH_STRING **Table,\n    _In_ ULONG Rows,\n    _In_ ULONG Columns,\n    _In_ ULONG Mode\n    );\n\nPHLIBAPI\nVOID PhMapDisplayIndexTreeNew(\n    _In_ HWND TreeNewHandle,\n    _Out_opt_ PULONG *DisplayToId,\n    _Out_opt_ PWSTR **DisplayToText,\n    _Out_ PULONG NumberOfColumns\n    );\n\nPHLIBAPI\nPPH_STRING PhGetTreeNewText(\n    _In_ HWND TreeNewHandle,\n    _Reserved_ ULONG Reserved\n    );\n\nPHLIBAPI\nPPH_LIST PhGetGenericTreeNewLines(\n    _In_ HWND TreeNewHandle,\n    _In_ ULONG Mode\n    );\n\nPHLIBAPI\nVOID PhaMapDisplayIndexListView(\n    _In_ HWND ListViewHandle,\n    _Out_writes_(Count) PULONG DisplayToId,\n    _Out_writes_opt_(Count) PPH_STRING *DisplayToText,\n    _In_ ULONG Count,\n    _Out_ PULONG NumberOfColumns\n    );\n\nPHLIBAPI\nPPH_STRING PhaGetListViewItemText(\n    _In_ HWND ListViewHandle,\n    _In_ INT Index,\n    _In_ INT SubItemIndex\n    );\n\nPHLIBAPI\nPPH_STRING PhGetListViewText(\n    _In_ HWND ListViewHandle\n    );\n\nPHLIBAPI\nPPH_LIST PhGetListViewLines(\n    _In_ HWND ListViewHandle,\n    _In_ ULONG Mode\n    );\n\n#ifdef __cplusplus\n}\n#endif\n\n#endif\n"
  },
  {
    "path": "third_party/phlib/include/dltmgr.h",
    "content": "#ifndef _PH_DLTMGR_H\n#define _PH_DLTMGR_H\n\ntypedef struct _PH_SINGLE_DELTA\n{\n    FLOAT Value;\n    FLOAT Delta;\n} PH_SINGLE_DELTA, *PPH_SINGLE_DELTA;\n\ntypedef struct _PH_UINT32_DELTA\n{\n    ULONG Value;\n    ULONG Delta;\n} PH_UINT32_DELTA, *PPH_UINT32_DELTA;\n\ntypedef struct _PH_UINT64_DELTA\n{\n    ULONG64 Value;\n    ULONG64 Delta;\n} PH_UINT64_DELTA, *PPH_UINT64_DELTA;\n\ntypedef struct _PH_UINTPTR_DELTA\n{\n    ULONG_PTR Value;\n    ULONG_PTR Delta;\n} PH_UINTPTR_DELTA, *PPH_UINTPTR_DELTA;\n\n#define PhInitializeDelta(DltMgr) \\\n    ((DltMgr)->Value = 0, (DltMgr)->Delta = 0)\n\n#define PhUpdateDelta(DltMgr, NewValue) \\\n    ((DltMgr)->Delta = (NewValue) - (DltMgr)->Value, \\\n    (DltMgr)->Value = (NewValue), (DltMgr)->Delta)\n\n#endif\n"
  },
  {
    "path": "third_party/phlib/include/dspick.h",
    "content": "#ifndef _PH_DSPICK_H\n#define _PH_DSPICK_H\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\n#define PH_DSPICK_MULTISELECT 0x1\n\ntypedef struct _PH_DSPICK_OBJECT\n{\n    PPH_STRING Name;\n    PSID Sid;\n} PH_DSPICK_OBJECT, *PPH_DSPICK_OBJECT;\n\ntypedef struct _PH_DSPICK_OBJECTS\n{\n    ULONG NumberOfObjects;\n    PH_DSPICK_OBJECT Objects[1];\n} PH_DSPICK_OBJECTS, *PPH_DSPICK_OBJECTS;\n\nPHLIBAPI\nVOID PhFreeDsObjectPickerDialog(\n    _In_ PVOID PickerDialog\n    );\n\nPHLIBAPI\nPVOID PhCreateDsObjectPickerDialog(\n    _In_ ULONG Flags\n    );\n\nPHLIBAPI\nBOOLEAN PhShowDsObjectPickerDialog(\n    _In_ HWND hWnd,\n    _In_ PVOID PickerDialog,\n    _Out_ PPH_DSPICK_OBJECTS *Objects\n    );\n\nPHLIBAPI\nVOID PhFreeDsObjectPickerObjects(\n    _In_ PPH_DSPICK_OBJECTS Objects\n    );\n\n#ifdef __cplusplus\n}\n#endif\n\n#endif\n"
  },
  {
    "path": "third_party/phlib/include/emenu.h",
    "content": "#ifndef _PH_EMENU_H\n#define _PH_EMENU_H\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\n#define PH_EMENU_DISABLED 0x1\n#define PH_EMENU_CHECKED 0x2\n#define PH_EMENU_HIGHLIGHT 0x4\n#define PH_EMENU_MENUBARBREAK 0x8\n#define PH_EMENU_MENUBREAK 0x10\n#define PH_EMENU_DEFAULT 0x20\n#define PH_EMENU_MOUSESELECT 0x40\n#define PH_EMENU_RADIOCHECK 0x80\n\n#define PH_EMENU_SEPARATECHECKSPACE 0x100000\n#define PH_EMENU_SEPARATOR 0x200000\n\n#define PH_EMENU_TEXT_OWNED 0x80000000\n#define PH_EMENU_BITMAP_OWNED 0x40000000\n\nstruct _PH_EMENU_ITEM;\n\ntypedef VOID (NTAPI *PPH_EMENU_ITEM_DELETE_FUNCTION)(\n    _In_ struct _PH_EMENU_ITEM *Item\n    );\n\ntypedef struct _PH_EMENU_ITEM\n{\n    ULONG Flags;\n    ULONG Id;\n    PWSTR Text;\n    HBITMAP Bitmap;\n\n    PVOID Parameter;\n    PVOID Context;\n    PPH_EMENU_ITEM_DELETE_FUNCTION DeleteFunction;\n    PVOID Reserved;\n\n    struct _PH_EMENU_ITEM *Parent;\n    PPH_LIST Items;\n} PH_EMENU_ITEM, *PPH_EMENU_ITEM;\n\ntypedef struct _PH_EMENU_ITEM PH_EMENU, *PPH_EMENU;\n\nPHLIBAPI\nPPH_EMENU_ITEM PhCreateEMenuItem(\n    _In_ ULONG Flags,\n    _In_ ULONG Id,\n    _In_ PWSTR Text,\n    _In_opt_ HBITMAP Bitmap,\n    _In_opt_ PVOID Context\n    );\n\nPHLIBAPI\nVOID PhDestroyEMenuItem(\n    _In_ PPH_EMENU_ITEM Item\n    );\n\n#define PH_EMENU_FIND_DESCEND 0x1\n#define PH_EMENU_FIND_STARTSWITH 0x2\n#define PH_EMENU_FIND_LITERAL 0x4\n\nPHLIBAPI\nPPH_EMENU_ITEM PhFindEMenuItem(\n    _In_ PPH_EMENU_ITEM Item,\n    _In_ ULONG Flags,\n    _In_opt_ PWSTR Text,\n    _In_opt_ ULONG Id\n    );\n\nPHLIBAPI\nPPH_EMENU_ITEM PhFindEMenuItemEx(\n    _In_ PPH_EMENU_ITEM Item,\n    _In_ ULONG Flags,\n    _In_opt_ PWSTR Text,\n    _In_opt_ ULONG Id,\n    _Out_opt_ PPH_EMENU_ITEM *FoundParent,\n    _Out_opt_ PULONG FoundIndex\n    );\n\nPHLIBAPI\nULONG PhIndexOfEMenuItem(\n    _In_ PPH_EMENU_ITEM Parent,\n    _In_ PPH_EMENU_ITEM Item\n    );\n\nPHLIBAPI\nVOID PhInsertEMenuItem(\n    _Inout_ PPH_EMENU_ITEM Parent,\n    _Inout_ PPH_EMENU_ITEM Item,\n    _In_ ULONG Index\n    );\n\nPHLIBAPI\nBOOLEAN PhRemoveEMenuItem(\n    _Inout_opt_ PPH_EMENU_ITEM Parent,\n    _In_opt_ PPH_EMENU_ITEM Item,\n    _In_opt_ ULONG Index\n    );\n\nPHLIBAPI\nVOID PhRemoveAllEMenuItems(\n    _Inout_ PPH_EMENU_ITEM Parent\n    );\n\nPHLIBAPI\nPPH_EMENU PhCreateEMenu(\n    VOID\n    );\n\nPHLIBAPI\nVOID PhDestroyEMenu(\n    _In_ PPH_EMENU Menu\n    );\n\n#define PH_EMENU_CONVERT_ID 0x1\n\ntypedef struct _PH_EMENU_DATA\n{\n    PPH_LIST IdToItem;\n} PH_EMENU_DATA, *PPH_EMENU_DATA;\n\nPHLIBAPI\nVOID PhInitializeEMenuData(\n    _Out_ PPH_EMENU_DATA Data\n    );\n\nPHLIBAPI\nVOID PhDeleteEMenuData(\n    _Inout_ PPH_EMENU_DATA Data\n    );\n\nPHLIBAPI\nHMENU PhEMenuToHMenu(\n    _In_ PPH_EMENU_ITEM Menu,\n    _In_ ULONG Flags,\n    _Inout_opt_ PPH_EMENU_DATA Data\n    );\n\nPHLIBAPI\nVOID PhEMenuToHMenu2(\n    _In_ HMENU MenuHandle,\n    _In_ PPH_EMENU_ITEM Menu,\n    _In_ ULONG Flags,\n    _Inout_opt_ PPH_EMENU_DATA Data\n    );\n\nPHLIBAPI\nVOID PhHMenuToEMenuItem(\n    _Inout_ PPH_EMENU_ITEM MenuItem,\n    _In_ HMENU MenuHandle\n    );\n\nPHLIBAPI\nVOID PhLoadResourceEMenuItem(\n    _Inout_ PPH_EMENU_ITEM MenuItem,\n    _In_ HINSTANCE InstanceHandle,\n    _In_ PWSTR Resource,\n    _In_ ULONG SubMenuIndex\n    );\n\n#define PH_EMENU_SHOW_SEND_COMMAND 0x1\n#define PH_EMENU_SHOW_LEFTRIGHT 0x2\n\nPHLIBAPI\nPPH_EMENU_ITEM PhShowEMenu(\n    _In_ PPH_EMENU Menu,\n    _In_ HWND WindowHandle,\n    _In_ ULONG Flags,\n    _In_ ULONG Align,\n    _In_ ULONG X,\n    _In_ ULONG Y\n    );\n\n// Convenience functions\n\nFORCEINLINE\nPPH_EMENU_ITEM PhCreateEMenuSeparator(\n    VOID\n    )\n{\n    return PhCreateEMenuItem(PH_EMENU_SEPARATOR, 0, NULL, NULL, NULL);\n}\n\nPHLIBAPI\nBOOLEAN PhSetFlagsEMenuItem(\n    _Inout_ PPH_EMENU_ITEM Item,\n    _In_ ULONG Id,\n    _In_ ULONG Mask,\n    _In_ ULONG Value\n    );\n\nFORCEINLINE BOOLEAN PhEnableEMenuItem(\n    _Inout_ PPH_EMENU_ITEM Item,\n    _In_ ULONG Id,\n    _In_ BOOLEAN Enable\n    )\n{\n    return PhSetFlagsEMenuItem(Item, Id, PH_EMENU_DISABLED, Enable ? 0 : PH_EMENU_DISABLED);\n}\n\nPHLIBAPI\nVOID PhSetFlagsAllEMenuItems(\n    _In_ PPH_EMENU_ITEM Item,\n    _In_ ULONG Mask,\n    _In_ ULONG Value\n    );\n\n#define PH_EMENU_MODIFY_TEXT 0x1\n#define PH_EMENU_MODIFY_BITMAP 0x2\n\nPHLIBAPI\nVOID PhModifyEMenuItem(\n    _Inout_ PPH_EMENU_ITEM Item,\n    _In_ ULONG ModifyFlags,\n    _In_ ULONG OwnedFlags,\n    _In_opt_ PWSTR Text,\n    _In_opt_ HBITMAP Bitmap\n    );\n\n#ifdef __cplusplus\n}\n#endif\n\n#endif\n"
  },
  {
    "path": "third_party/phlib/include/exlf.h",
    "content": "#ifndef _PH_EXLF_H\n#define _PH_EXLF_H\n\n/*\n * This file contains the required types for ELF bianires. \n *\n * References:\n * http://man7.org/linux/man-pages/man5/elf.5.html\n * http://www.skyfree.org/linux/references/ELF_Format.pdf\n * https://github.com/torvalds/linux/blob/master/include/uapi/linux/elf.h\n * https://chromium.googlesource.com/chromiumos/chromite/+/HEAD/lib/parseelf.py\n */\n\n#define EI_NIDENT 16\n\n// e_ident[] indexes\n#define\tEI_MAG0\t\t0\n#define\tEI_MAG1\t\t1\n#define\tEI_MAG2\t\t2\n#define\tEI_MAG3\t\t3\n#define\tEI_CLASS\t4\n#define\tEI_DATA\t\t5\n#define\tEI_VERSION\t6\n#define\tEI_OSABI\t7\n#define\tEI_PAD\t\t8\n\n// EI_MAG\n#define\tELFMAG0 0x7f\n#define\tELFMAG1\t'E'\n#define\tELFMAG2\t'L'\n#define\tELFMAG3 'F'\n// EI_CLASS \n#define\tELFCLASSNONE 0\n#define\tELFCLASS32 1\n#define\tELFCLASS64 2\n\n// EI_DATA\n#define ELFDATANONE 0\n#define ELFDATA2LSB\t1\n#define ELFDATA2MSB\t2\n\n// EI_VERSION and e_version\n#define EV_NONE\t0\n#define EV_CURRENT 1\n\n#define ELFOSABI_NONE 0\n#define ELFOSABI_LINUX 3\n\n// e_type\n#define ET_NONE 0\n#define ET_REL 1\n#define ET_EXEC 2\n#define ET_DYN 3\n#define ET_CORE 4\n#define ET_LOPROC 0xff00\n#define ET_HIPROC 0xffff\n\n// e_machine\n#define EM_386 3\n#define EM_X86_64 62\n\n/* segment types */\n#define PT_NULL    0\n#define PT_LOAD    1\n#define PT_DYNAMIC 2\n#define PT_INTERP  3\n#define PT_NOTE    4\n#define PT_SHLIB   5\n#define PT_PHDR    6\n#define PT_TLS     7               /* Thread local storage segment */\n#define PT_LOOS    0x60000000      /* OS-specific */\n#define PT_HIOS    0x6fffffff      /* OS-specific */\n#define PT_LOPROC  0x70000000\n#define PT_HIPROC  0x7fffffff\n#define PT_GNU_EH_FRAME\t\t0x6474e550\n#define PT_GNU_STACK\t(PT_LOOS + 0x474e551)\n\n/* permissions on sections in the program header, p_flags. */\n#define PF_NONE 0x0\n#define PF_X 0x1\n#define PF_W 0x2\n#define PF_R 0x4\n\n// sh_type\n#define SHT_NULL 0     // Section header table entry (unused).\n#define SHT_PROGBITS 1 // Program data.\n#define SHT_SYMTAB 2   // Link editing symbol table.\n#define SHT_STRTAB 3   // A string table.\n#define SHT_RELA 4     // Relocation entries with addends.\n#define SHT_HASH 5     // A symbol hash table.\n#define SHT_DYNAMIC 6  // Information for dynamic linking.\n#define SHT_NOTE 7     // Information that marks file.\n#define SHT_NOBITS 8   // Section occupies no space in file.\n#define SHT_REL 9      // Relocation entries, no addends.\n#define SHT_SHLIB 10   // Reserved, unspecified semantics.\n#define SHT_DYNSYM 11  // Dynamic linking symbol table.\n//#define SHT_NUM 12\n#define SHT_INIT_ARRAY 14    // Array of constructors.\n#define SHT_FINI_ARRAY 15    // Array of destructors.\n#define SHT_PREINIT_ARRAY 16 // Array of pre-constructors.\n#define SHT_GROUP 17         // Section group.\n#define SHT_SYMTAB_SHNDX 18  // Extended section indeces.\n#define SHT_NUM 19           // Number of defined types. (dmex: Some tools define this as 19 and others as 12???)\n#define SHT_LOOS 0x60000000\t// First of OS specific semantics.\n#define SHT_HIOS 0x6fffffff\t// Last of OS specific semantics.\n#define SHT_GNU_INCREMENTAL_INPUTS 0x6fff4700 // incremental build data.\n#define SHT_GNU_ATTRIBUTES 0x6ffffff5 // Object attributes.\n#define SHT_GNU_HASH 0x6ffffff6 // GNU style symbol hash table.\n#define SHT_GNU_LIBLIST\t0x6ffffff7 // List of prelink dependencies.\n#define SHT_LOPROC 0x70000000\n#define SHT_HIPROC 0x7fffffff\n#define SHT_LOUSER 0x80000000\n#define SHT_HIUSER 0xffffffff\n#define SHT_SUNW_verdef\t0x6ffffffd\t// Versions defined by file.\n#define SHT_SUNW_verneed 0x6ffffffe\t// Versions needed by file.\n#define SHT_SUNW_versym\t0x6fffffff\t// Symbol versions.\n\n// sh_flags\n#define SHF_WRITE 0x1\t/* Section contains writable data. */\n#define SHF_ALLOC 0x2\t/* Section occupies memory. */\n#define SHF_EXECINSTR 0x4\t/* Section contains instructions. */\n#define SHF_MERGE 0x10\t/* Section may be merged. */\n#define SHF_STRINGS\t0x20\t/* Section contains strings. */\n#define SHF_INFO_LINK 0x40\t/* sh_info holds section index. */\n#define SHF_LINK_ORDER 0x80\t/* Special ordering requirements. */\n#define SHF_OS_NONCONFORMING 0x100\t/* OS-specific processing required. */\n#define SHF_GROUP 0x200\t/* Member of section group. */\n#define SHF_TLS 0x400\t/* Section contains TLS data. */\n#define SHF_MASKOS\t0x0ff00000\t/* OS-specific semantics. */\n#define SHF_MASKPROC\t0xf0000000\t/* Processor-specific semantics. */\n\n// special section indexes.\n#define SHN_UNDEF 0 // An undefined symbol.\n#define SHN_LORESERVE 0xff00\n#define SHN_LOPROC 0xff00\n#define SHN_HIPROC 0xff1f\n#define SHN_LIVEPATCH 0xff20\n#define SHN_ABS 0xfff1\n#define SHN_COMMON 0xfff2\n#define SHN_HIRESERVE 0xffff\n\n// dynamic section\n#define DT_NULL\t\t0\n#define DT_NEEDED\t1\n#define DT_PLTRELSZ\t2\n#define DT_PLTGOT\t3\n#define DT_HASH\t\t4\n#define DT_STRTAB\t5\n#define DT_SYMTAB\t6\n#define DT_RELA\t\t7\n#define DT_RELASZ\t8\n#define DT_RELAENT\t9\n#define DT_STRSZ\t10\n#define DT_SYMENT\t11\n#define DT_INIT\t\t12\n#define DT_FINI\t\t13\n#define DT_SONAME\t14\n#define DT_RPATH \t15\n#define DT_SYMBOLIC\t16\n#define DT_REL\t        17\n#define DT_RELSZ\t18\n#define DT_RELENT\t19\n#define DT_PLTREL\t20\n#define DT_DEBUG\t21\n#define DT_TEXTREL\t22\n#define DT_JMPREL\t23\n#define DT_ENCODING\t32\n#define OLD_DT_LOOS\t0x60000000\n#define DT_LOOS\t\t0x6000000d\n#define DT_HIOS\t\t0x6ffff000\n#define DT_VALRNGLO\t0x6ffffd00\n#define DT_VALRNGHI\t0x6ffffdff\n#define DT_ADDRRNGLO\t0x6ffffe00\n#define DT_ADDRRNGHI\t0x6ffffeff\n#define DT_VERSYM\t0x6ffffff0\n#define DT_RELACOUNT\t0x6ffffff9\n#define DT_RELCOUNT\t0x6ffffffa\n#define DT_FLAGS_1\t0x6ffffffb\n#define DT_VERDEF\t0x6ffffffc\n#define\tDT_VERDEFNUM\t0x6ffffffd\n#define DT_VERNEED\t0x6ffffffe\n#define\tDT_VERNEEDNUM\t0x6fffffff\n#define OLD_DT_HIOS     0x6fffffff\n#define DT_LOPROC\t0x70000000\n#define DT_HIPROC\t0x7fffffff\n\n// symbol table section\n#define STB_LOCAL 0 /* Local symbol */\n#define STB_GLOBAL 1 /* Global symbol */\n#define STB_WEAK 2 /* Weak symbol */\n#define STB_NUM 3 /* Number of defined types.  */\n#define STB_LOOS 10 /* Start of OS-specific */\n#define STB_GNU_UNIQUE 10 /* Unique symbol.  */\n#define STB_HIOS 12 /* End of OS-specific */\n#define STB_LOPROC 13 /* Start of processor-specific */\n#define STB_HIPROC 15 /* End of processor-specific */\n\n#define STT_NOTYPE  0\n#define STT_OBJECT  1\n#define STT_FUNC    2\n#define STT_SECTION 3\n#define STT_FILE    4\n#define STT_COMMON  5\n#define STT_TLS     6\n#define STT_GNU_IFUNC 10\n#define STT_LOOS      10\n#define STT_HIOS      12\n#define STT_LOPROC    13\n#define STT_HIPROC    15\n\n#define STV_DEFAULT\t0 /* Default symbol visibility rules */\n#define STV_INTERNAL 1 /* Processor specific hidden class */\n#define STV_HIDDEN 2 /* Sym unavailable in other modules */\n#define STV_PROTECTED 3 /* Not preemptible, not exported */\n\n#define ELF_ST_BIND(x) ((x) >> 4)\n#define ELF_ST_TYPE(x) ((x) & 0xF)\n#define ELF_ST_VISIBILITY(x) ((x) & 0x03)\n\n#define ELF32_ST_BIND(x) ELF_ST_BIND(x)\n#define ELF32_ST_TYPE(x) ELF_ST_TYPE(x)\n#define ELF32_ST_VIS(a)\tELF_ST_VISIBILITY(a)\n#define ELF64_ST_BIND(x) ELF_ST_BIND(x)\n#define ELF64_ST_TYPE(x) ELF_ST_TYPE(x)\n#define ELF64_ST_VIS(a)\tELF_ST_VISIBILITY(a)\n\n// Non-standard ELF definitions (dmex)\n\n#define\tIMAGE_ELF_SIGNATURE 0x457f // \"\\x7fELF\"\n#define\tELFMAG ((BYTE[4]){ELFMAG0,ELFMAG1,ELFMAG2,ELFMAG3})\n\ntypedef struct _ELF_IMAGE_HEADER\n{\n    union\n    {\n        unsigned char e_ident[EI_NIDENT];\n        struct\n        {\n            unsigned char MagicNumber[4];\n            unsigned char Class;\n            unsigned char Data;\n            unsigned char Version;\n            unsigned char Abi;\n            unsigned char AbiVersion;\n            unsigned char Unused[7];\n        };\n    };\n    unsigned short e_type;\n    unsigned short e_machine;\n    unsigned int e_version;\n    //union {\n    //    PELF_IMAGE_HEADER32 Headers32;\n    //    PELF_IMAGE_HEADER64 Headers64;\n    //};\n} ELF_IMAGE_HEADER, *PELF_IMAGE_HEADER;\n\ntypedef struct _ELF_IMAGE_HEADER32\n{\n    // ELF_IMAGE_HEADER Header;\n    unsigned int e_entry; // Entry point virtual address.\n    unsigned int e_phoff; // Program header table file offset.\n    unsigned int e_shoff; // Section header table file offset.\n    unsigned int e_flags; // Processor-specific flags.\n    unsigned short e_ehsize; // ELF header size in bytes.\n    unsigned short e_phentsize; // Program header table entry size.\n    unsigned short e_phnum; // Program header table entry count.\n    unsigned short e_shentsize; // Section header table entry size.\n    unsigned short e_shnum; // Section header table entry count.\n    unsigned short e_shstrndx; // Section header string table index.\n} ELF_IMAGE_HEADER32, *PELF_IMAGE_HEADER32;\n\ntypedef struct _ELF_IMAGE_HEADER64\n{\n    // ELF_IMAGE_HEADER Header;\n    unsigned long long e_entry; // Entry point virtual address.\n    unsigned long long e_phoff; // Program header table file offset.\n    unsigned long long e_shoff; // Section header table file offset.\n    unsigned int e_flags; // Processor-specific flags.\n    unsigned short e_ehsize; // ELF header size in bytes.\n    unsigned short e_phentsize; // Program header table entry size.\n    unsigned short e_phnum; // Program header table entry count.\n    unsigned short e_shentsize; // Section header table entry size.\n    unsigned short e_shnum; // Section header table entry count.\n    unsigned short e_shstrndx; // Section header string table index.\n} ELF_IMAGE_HEADER64, *PELF_IMAGE_HEADER64;\n\ntypedef struct _ELF32_IMAGE_SEGMENT_HEADER\n{\n    unsigned int p_type; // Segment type.\n    unsigned int p_offset; // Segment file offset.\n    unsigned int p_vaddr; // Segment virtual address.\n    unsigned int p_paddr; // Segment physical address.\n    unsigned int p_filesz; // Segment size in file.\n    unsigned int p_memsz; // Segment size in memory.\n    unsigned int p_flags; // Segment flags.\n    unsigned int p_align; // Segment alignment.\n} ELF32_IMAGE_SEGMENT_HEADER;\n\ntypedef struct _ELF64_IMAGE_SEGMENT_HEADER\n{\n    unsigned int p_type; // Segment type.\n    unsigned int p_flags; // Segment flags.\n    unsigned long long p_offset; // Segment file offset.\n    unsigned long long p_vaddr; // Segment virtual address.\n    unsigned long long p_paddr; // Segment physical address.\n    unsigned long long p_filesz; // Segment size in file.\n    unsigned long long p_memsz;\t// Segment size in memory.\n    unsigned long long p_align; // Segment alignment.\n} ELF64_IMAGE_SEGMENT_HEADER, *PELF64_IMAGE_SEGMENT_HEADER;\n\n#define IMAGE_FIRST_ELF64_SEGMENT(MappedWslImage) \\\n    ((PELF64_IMAGE_SEGMENT_HEADER)PTR_ADD_OFFSET(MappedWslImage->Header, MappedWslImage->Headers64->e_phoff))\n\n#define IMAGE_ELF64_SEGMENT_BY_INDEX(SegmentHeader, Index) \\\n    ((PELF64_IMAGE_SEGMENT_HEADER)PTR_ADD_OFFSET(SegmentHeader, sizeof(ELF64_IMAGE_SEGMENT_HEADER) * Index))\n    //((PELF64_IMAGE_SEGMENT_HEADER)&SegmentHeaderTable[Index])\n\ntypedef struct _ELF32_IMAGE_SECTION_HEADER\n{\n    unsigned int sh_name;\n    unsigned int sh_type;\n    unsigned int sh_flags;\n    unsigned int sh_addr;\n    unsigned int sh_offset;\n    unsigned int sh_size;\n    unsigned int sh_link;\n    unsigned int sh_info;\n    unsigned int sh_addralign;\n    unsigned int sh_entsize;\n} ELF32_IMAGE_SECTION_HEADER;\n\ntypedef struct _ELF64_IMAGE_SECTION_HEADER\n{\n    unsigned int sh_name;            /* Section name, index in string tbl */\n    unsigned int sh_type;            /* Type of section */\n    unsigned long long sh_flags;     /* Miscellaneous section attributes */\n    unsigned long long sh_addr;      /* Section virtual addr at execution */\n    unsigned long long sh_offset;    /* Section file offset */\n    unsigned long long sh_size;      /* Size of section in bytes */\n    unsigned int sh_link;            /* Index of another section */\n    unsigned int sh_info;            /* Additional section information */\n    unsigned long long sh_addralign; /* Section alignment */\n    unsigned long long sh_entsize;   /* Entry size if section holds table */\n} ELF64_IMAGE_SECTION_HEADER, *PELF64_IMAGE_SECTION_HEADER;\n\n#define IMAGE_FIRST_ELF64_SECTION(MappedWslImage) \\\n    ((PELF64_IMAGE_SECTION_HEADER)PTR_ADD_OFFSET(MappedWslImage->Header, MappedWslImage->Headers64->e_shoff))\n\n#define IMAGE_ELF64_SECTION_BY_INDEX(SectionHeader, Index) \\\n    ((PELF64_IMAGE_SECTION_HEADER)PTR_ADD_OFFSET(SectionHeader, sizeof(ELF64_IMAGE_SECTION_HEADER) * Index))\n    // ((PELF64_IMAGE_SECTION_HEADER)&SectionHeaderTable[Index])\n\n// ELF dynamic entries\n\ntypedef struct _ELF32_IMAGE_DYNAMIC_ENTRY // Elf32_Dyn\n{\n    int d_tag;\n    unsigned int d_val;\n} ELF32_IMAGE_DYNAMIC_ENTRY, *PELF32_IMAGE_DYNAMIC_ENTRY;\n\ntypedef struct _ELF64_IMAGE_DYNAMIC_ENTRY // Elf64_Dyn\n{\n    long long d_tag;\n    unsigned long long d_val;\n} ELF64_IMAGE_DYNAMIC_ENTRY, *PELF64_IMAGE_DYNAMIC_ENTRY;\n\n// ELF symbol entries \n\ntypedef struct _ELF_IMAGE_SYMBOL_ENTRY // Elf_Sym\n{\n    unsigned int st_name;\n    unsigned char st_info;\n    unsigned char st_other;\n    unsigned short st_shndx;\n    unsigned long long st_value;\n    unsigned long long st_size;\n} ELF_IMAGE_SYMBOL_ENTRY, *PELF_IMAGE_SYMBOL_ENTRY;\n\n// ELF version entires\n\ntypedef struct _ELF_VERSION_TABLE // Elf_Versym\n{\n    unsigned short vs_vers;\n} ELF_VERSION_TABLE, *PELF_VERSION_TABLE;\n\ntypedef struct \n{\n    unsigned short vd_version;\n    unsigned short vd_flags; // flags (VER_FLG_*).\n    unsigned short vd_ndx; // version index.\n    unsigned short vd_cnt; // number of verdaux entries.\n    unsigned int vd_hash; // hash of name.\n    unsigned int vd_aux; // offset to verdaux entries.\n    unsigned int vd_next; // offset to next verdef.\n} Elf_Verdef;\n\ntypedef struct \n{\n    unsigned int vda_name;\t/* string table offset of name */\n    unsigned int vda_next;\t/* offset to verdaux */\n} Elf_Verdaux;\n\n// vn_version\n#define VER_NEED_NONE    0 /* No version */\n#define VER_NEED_CURRENT 1 /* Current version */\n#define VER_NEED_NUM     2 /* Given version number */\n\ntypedef struct _ELF_VERSION_NEED // Elf_Verneed\n{\n    unsigned short vn_version;\n    unsigned short vn_cnt;\n    unsigned int vn_file;\n    unsigned int vn_aux;\n    unsigned int vn_next;\n} ELF_VERSION_NEED, *PELF_VERSION_NEED;\n\ntypedef struct _ELF_VERSION_AUX // Elf_Vernaux\n{\n    unsigned int vna_hash; // dependency name hash.\n    unsigned short vna_flags; // flags (VER_FLG_*).\n    unsigned short vna_other;\n    unsigned int vna_name;\n    unsigned int vna_next;\n} ELF_VERSION_AUX, *PELF_VERSION_AUX;\n\n#endif\n"
  },
  {
    "path": "third_party/phlib/include/fastlock.h",
    "content": "#ifndef _PH_FASTLOCK_H\n#define _PH_FASTLOCK_H\n\n// FastLock is a port of FastResourceLock from PH 1.x.\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\ntypedef struct _PH_FAST_LOCK\n{\n    ULONG Value;\n    HANDLE ExclusiveWakeEvent;\n    HANDLE SharedWakeEvent;\n} PH_FAST_LOCK, *PPH_FAST_LOCK;\n\n#define PH_FAST_LOCK_INIT { 0, NULL, NULL }\n\nPHLIBAPI\nVOID\nNTAPI\nPhInitializeFastLock(\n    _Out_ PPH_FAST_LOCK FastLock\n    );\n\nPHLIBAPI\nVOID\nNTAPI\nPhDeleteFastLock(\n    _Inout_ PPH_FAST_LOCK FastLock\n    );\n\n#define PhAcquireFastLockExclusive PhfAcquireFastLockExclusive\n_May_raise_\n_Acquires_exclusive_lock_(*FastLock)\nPHLIBAPI\nVOID\nFASTCALL\nPhfAcquireFastLockExclusive(\n    _Inout_ PPH_FAST_LOCK FastLock\n    );\n\n#define PhAcquireFastLockShared PhfAcquireFastLockShared\n_May_raise_\n_Acquires_shared_lock_(*FastLock)\nPHLIBAPI\nVOID\nFASTCALL\nPhfAcquireFastLockShared(\n    _Inout_ PPH_FAST_LOCK FastLock\n    );\n\n#define PhReleaseFastLockExclusive PhfReleaseFastLockExclusive\n_Releases_exclusive_lock_(*FastLock)\nPHLIBAPI\nVOID\nFASTCALL\nPhfReleaseFastLockExclusive(\n    _Inout_ PPH_FAST_LOCK FastLock\n    );\n\n#define PhReleaseFastLockShared PhfReleaseFastLockShared\n_Releases_shared_lock_(*FastLock)\nPHLIBAPI\nVOID\nFASTCALL\nPhfReleaseFastLockShared(\n    _Inout_ PPH_FAST_LOCK FastLock\n    );\n\n#define PhTryAcquireFastLockExclusive PhfTryAcquireFastLockExclusive\n_When_(return != 0, _Acquires_exclusive_lock_(*FastLock))\nPHLIBAPI\nBOOLEAN\nFASTCALL\nPhfTryAcquireFastLockExclusive(\n    _Inout_ PPH_FAST_LOCK FastLock\n    );\n\n#define PhTryAcquireFastLockShared PhfTryAcquireFastLockShared\n_When_(return != 0, _Acquires_shared_lock_(*FastLock))\nPHLIBAPI\nBOOLEAN\nFASTCALL\nPhfTryAcquireFastLockShared(\n    _Inout_ PPH_FAST_LOCK FastLock\n    );\n\n#ifdef __cplusplus\n}\n#endif\n\n#endif\n"
  },
  {
    "path": "third_party/phlib/include/filepool.h",
    "content": "#ifndef _PH_FILEPOOL_H\n#define _PH_FILEPOOL_H\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\n// On-disk structures\n\n// Each file has at least one segment. Each segment has a number of blocks, which are allocated from\n// a bitmap. The segment header is always in the first block of each segment, except for the first\n// segment. In the first segment, the file header is in the first few blocks, followed by the\n// segment header.\n//\n// The segments are placed in a particular free list depending on how many blocks they have free;\n// this allows allocators to simply skip the segments which don't have enough segments free, and\n// allocate new segments if necessary. The free list does not however guarantee that a particular\n// segment has a particular number of contiguous blocks free; low performance can still occur when\n// there is fragmentation.\n\n/** The number of 32-bit integers used for each allocation bitmap. */\n#define PH_FP_BITMAP_SIZE 64\n/** The power-of-two index of the bitmap size. */\n#define PH_FP_BITMAP_SIZE_SHIFT 6\n/** The number of blocks that are available in each segment. */\n#define PH_FP_BLOCK_COUNT (PH_FP_BITMAP_SIZE * 32)\n/** The power-of-two index of the block count. */\n#define PH_FP_BLOCK_COUNT_SHIFT (PH_FP_BITMAP_SIZE_SHIFT + 5)\n/** The number of free lists for segments. */\n#define PH_FP_FREE_LIST_COUNT 8\n\n// Block flags\n/** The block is the beginning of a large allocation (one that spans several segments). */\n#define PH_FP_BLOCK_LARGE_ALLOCATION 0x1\n\ntypedef struct _PH_FP_BLOCK_HEADER\n{\n    ULONG Flags; // PH_FP_BLOCK_*\n    /** The number of blocks in the entire logical block, or the number\n     * of segments in a large allocation. */\n    ULONG Span;\n    ULONGLONG Body;\n} PH_FP_BLOCK_HEADER, *PPH_FP_BLOCK_HEADER;\n\ntypedef struct _PH_FP_SEGMENT_HEADER\n{\n    ULONG Bitmap[PH_FP_BITMAP_SIZE];\n    ULONG FreeBlocks;\n    ULONG FreeFlink;\n    ULONG FreeBlink;\n    ULONG Reserved[13];\n} PH_FP_SEGMENT_HEADER, *PPH_FP_SEGMENT_HEADER;\n\n#define PH_FP_MAGIC ('loPF')\n\ntypedef struct _PH_FP_FILE_HEADER\n{\n    ULONG Magic;\n    ULONG SegmentShift;\n    ULONG SegmentCount;\n    ULONGLONG UserContext;\n    ULONG FreeLists[PH_FP_FREE_LIST_COUNT];\n} PH_FP_FILE_HEADER, *PPH_FP_FILE_HEADER;\n\n// Runtime\n\ntypedef struct _PH_FILE_POOL_PARAMETERS\n{\n    // File options\n\n    /**\n     * The base-2 logarithm of the size of each segment. This value must be between 16 and 28,\n     * inclusive.\n     */\n    ULONG SegmentShift;\n\n    // Runtime options\n\n    /** The maximum number of inactive segments to keep mapped. */\n    ULONG MaximumInactiveViews;\n} PH_FILE_POOL_PARAMETERS, *PPH_FILE_POOL_PARAMETERS;\n\ntypedef struct _PH_FILE_POOL\n{\n    HANDLE FileHandle;\n    HANDLE SectionHandle;\n    BOOLEAN ReadOnly;\n\n    PH_FREE_LIST ViewFreeList;\n    PLIST_ENTRY *ByIndexBuckets;\n    ULONG ByIndexSize;\n    PH_AVL_TREE ByBaseSet;\n\n    ULONG MaximumInactiveViews;\n    ULONG NumberOfInactiveViews;\n    LIST_ENTRY InactiveViewsListHead;\n\n    PPH_FP_BLOCK_HEADER FirstBlockOfFirstSegment;\n    PPH_FP_FILE_HEADER Header;\n    ULONG SegmentShift; // The power-of-two size of each segment\n    ULONG SegmentSize; // The size of each segment\n    ULONG BlockShift; // The power-of-two size of each block in each segment\n    ULONG BlockSize; // The size of each block in each segment\n    ULONG FileHeaderBlockSpan; // The number of blocks needed to store a file header\n    ULONG SegmentHeaderBlockSpan; // The number of blocks needed to store a segment header\n} PH_FILE_POOL, *PPH_FILE_POOL;\n\nPHLIBAPI\nNTSTATUS PhCreateFilePool(\n    _Out_ PPH_FILE_POOL *Pool,\n    _In_ HANDLE FileHandle,\n    _In_ BOOLEAN ReadOnly,\n    _In_opt_ PPH_FILE_POOL_PARAMETERS Parameters\n    );\n\nPHLIBAPI\nNTSTATUS PhCreateFilePool2(\n    _Out_ PPH_FILE_POOL *Pool,\n    _In_ PWSTR FileName,\n    _In_ BOOLEAN ReadOnly,\n    _In_ ULONG ShareAccess,\n    _In_ ULONG CreateDisposition,\n    _In_opt_ PPH_FILE_POOL_PARAMETERS Parameters\n    );\n\nPHLIBAPI\nVOID PhDestroyFilePool(\n    _In_ _Post_invalid_ PPH_FILE_POOL Pool\n    );\n\nPHLIBAPI\nPVOID PhAllocateFilePool(\n    _Inout_ PPH_FILE_POOL Pool,\n    _In_ ULONG Size,\n    _Out_opt_ PULONG Rva\n    );\n\nPHLIBAPI\nVOID PhFreeFilePool(\n    _Inout_ PPH_FILE_POOL Pool,\n    _In_ PVOID Block\n    );\n\nPHLIBAPI\nBOOLEAN PhFreeFilePoolByRva(\n    _Inout_ PPH_FILE_POOL Pool,\n    _In_ ULONG Rva\n    );\n\nPHLIBAPI\nVOID PhReferenceFilePool(\n    _Inout_ PPH_FILE_POOL Pool,\n    _In_ PVOID Address\n    );\n\nPHLIBAPI\nVOID PhDereferenceFilePool(\n    _Inout_ PPH_FILE_POOL Pool,\n    _In_ PVOID Address\n    );\n\nPHLIBAPI\nPVOID PhReferenceFilePoolByRva(\n    _Inout_ PPH_FILE_POOL Pool,\n    _In_ ULONG Rva\n    );\n\nPHLIBAPI\nBOOLEAN PhDereferenceFilePoolByRva(\n    _Inout_ PPH_FILE_POOL Pool,\n    _In_ ULONG Rva\n    );\n\nPHLIBAPI\nULONG PhEncodeRvaFilePool(\n    _In_ PPH_FILE_POOL Pool,\n    _In_ PVOID Address\n    );\n\nPHLIBAPI\nVOID PhGetUserContextFilePool(\n    _In_ PPH_FILE_POOL Pool,\n    _Out_ PULONGLONG Context\n    );\n\nPHLIBAPI\nVOID PhSetUserContextFilePool(\n    _Inout_ PPH_FILE_POOL Pool,\n    _In_ PULONGLONG Context\n    );\n\n#ifdef __cplusplus\n}\n#endif\n\n#endif\n"
  },
  {
    "path": "third_party/phlib/include/filepoolp.h",
    "content": "#ifndef _PH_FILEPOOLP_H\n#define _PH_FILEPOOLP_H\n\ntypedef struct _PH_FILE_POOL_VIEW\n{\n    LIST_ENTRY ByIndexListEntry;\n    PH_AVL_LINKS ByBaseLinks;\n    LIST_ENTRY InactiveViewsListEntry;\n\n    ULONG RefCount;\n    ULONG SegmentIndex;\n    PVOID Base;\n} PH_FILE_POOL_VIEW, *PPH_FILE_POOL_VIEW;\n\nNTSTATUS PhpValidateFilePoolParameters(\n    _Inout_ PPH_FILE_POOL_PARAMETERS Parameters\n    );\n\nVOID PhpSetDefaultFilePoolParameters(\n    _Out_ PPH_FILE_POOL_PARAMETERS Parameters\n    );\n\n// Range mapping\n\nNTSTATUS PhFppExtendRange(\n    _Inout_ PPH_FILE_POOL Pool,\n    _In_ ULONG NewSize\n    );\n\nNTSTATUS PhFppMapRange(\n    _Inout_ PPH_FILE_POOL Pool,\n    _In_ ULONG Offset,\n    _In_ ULONG Size,\n    _Out_ PVOID *Base\n    );\n\nNTSTATUS PhFppUnmapRange(\n    _Inout_ PPH_FILE_POOL Pool,\n    _In_ PVOID Base\n    );\n\n// Segments\n\nVOID PhFppInitializeSegment(\n    _Inout_ PPH_FILE_POOL Pool,\n    _Out_ PPH_FP_BLOCK_HEADER BlockOfSegmentHeader,\n    _In_ ULONG AdditionalBlocksUsed\n    );\n\nPPH_FP_BLOCK_HEADER PhFppAllocateSegment(\n    _Inout_ PPH_FILE_POOL Pool,\n    _Out_ PULONG NewSegmentIndex\n    );\n\nPPH_FP_SEGMENT_HEADER PhFppGetHeaderSegment(\n    _Inout_ PPH_FILE_POOL Pool,\n    _In_ PPH_FP_BLOCK_HEADER FirstBlock\n    );\n\n// Views\n\nVOID PhFppAddViewByIndex(\n    _Inout_ PPH_FILE_POOL Pool,\n    _Inout_ PPH_FILE_POOL_VIEW View\n    );\n\nVOID PhFppRemoveViewByIndex(\n    _Inout_ PPH_FILE_POOL Pool,\n    _Inout_ PPH_FILE_POOL_VIEW View\n    );\n\nPPH_FILE_POOL_VIEW PhFppFindViewByIndex(\n    _Inout_ PPH_FILE_POOL Pool,\n    _In_ ULONG SegmentIndex\n    );\n\nLONG NTAPI PhpFilePoolViewByBaseCompareFunction(\n    _In_ PPH_AVL_LINKS Links1,\n    _In_ PPH_AVL_LINKS Links2\n    );\n\nVOID PhFppAddViewByBase(\n    _Inout_ PPH_FILE_POOL Pool,\n    _Inout_ PPH_FILE_POOL_VIEW View\n    );\n\nVOID PhFppRemoveViewByBase(\n    _Inout_ PPH_FILE_POOL Pool,\n    _Inout_ PPH_FILE_POOL_VIEW View\n    );\n\nPPH_FILE_POOL_VIEW PhFppFindViewByBase(\n    _Inout_ PPH_FILE_POOL Pool,\n    _In_ PVOID Base\n    );\n\nPPH_FILE_POOL_VIEW PhFppCreateView(\n    _Inout_ PPH_FILE_POOL Pool,\n    _In_ ULONG SegmentIndex\n    );\n\nVOID PhFppDestroyView(\n    _Inout_ PPH_FILE_POOL Pool,\n    _Inout_ PPH_FILE_POOL_VIEW View\n    );\n\nVOID PhFppActivateView(\n    _Inout_ PPH_FILE_POOL Pool,\n    _Inout_ PPH_FILE_POOL_VIEW View\n    );\n\nVOID PhFppDeactivateView(\n    _Inout_ PPH_FILE_POOL Pool,\n    _Inout_ PPH_FILE_POOL_VIEW View\n    );\n\nVOID PhFppReferenceView(\n    _Inout_ PPH_FILE_POOL Pool,\n    _Inout_ PPH_FILE_POOL_VIEW View\n    );\n\nVOID PhFppDereferenceView(\n    _Inout_ PPH_FILE_POOL Pool,\n    _Inout_ PPH_FILE_POOL_VIEW View\n    );\n\nPPH_FP_BLOCK_HEADER PhFppReferenceSegment(\n    _Inout_ PPH_FILE_POOL Pool,\n    _In_ ULONG SegmentIndex\n    );\n\nVOID PhFppDereferenceSegment(\n    _Inout_ PPH_FILE_POOL Pool,\n    _In_ ULONG SegmentIndex\n    );\n\nVOID PhFppReferenceSegmentByBase(\n    _Inout_ PPH_FILE_POOL Pool,\n    _In_ PVOID Base\n    );\n\nVOID PhFppDereferenceSegmentByBase(\n    _Inout_ PPH_FILE_POOL Pool,\n    _In_ PVOID Base\n    );\n\n// Bitmap allocation\n\nPPH_FP_BLOCK_HEADER PhFppAllocateBlocks(\n    _Inout_ PPH_FILE_POOL Pool,\n    _In_ PPH_FP_BLOCK_HEADER FirstBlock,\n    _Inout_ PPH_FP_SEGMENT_HEADER SegmentHeader,\n    _In_ ULONG NumberOfBlocks\n    );\n\nVOID PhFppFreeBlocks(\n    _Inout_ PPH_FILE_POOL Pool,\n    _In_ PPH_FP_BLOCK_HEADER FirstBlock,\n    _Inout_ PPH_FP_SEGMENT_HEADER SegmentHeader,\n    _In_ PPH_FP_BLOCK_HEADER BlockHeader\n    );\n\n// Free list\n\nULONG PhFppComputeFreeListIndex(\n    _In_ PPH_FILE_POOL Pool,\n    _In_ ULONG NumberOfBlocks\n    );\n\nBOOLEAN PhFppInsertFreeList(\n    _Inout_ PPH_FILE_POOL Pool,\n    _In_ ULONG FreeListIndex,\n    _In_ ULONG SegmentIndex,\n    _In_ PPH_FP_SEGMENT_HEADER SegmentHeader\n    );\n\nBOOLEAN PhFppRemoveFreeList(\n    _Inout_ PPH_FILE_POOL Pool,\n    _In_ ULONG FreeListIndex,\n    _In_ ULONG SegmentIndex,\n    _In_ PPH_FP_SEGMENT_HEADER SegmentHeader\n    );\n\n// Misc.\n\nPPH_FP_BLOCK_HEADER PhFppGetHeaderBlock(\n    _In_ PPH_FILE_POOL Pool,\n    _In_ PVOID Block\n    );\n\nULONG PhFppEncodeRva(\n    _In_ PPH_FILE_POOL Pool,\n    _In_ ULONG SegmentIndex,\n    _In_ PPH_FP_BLOCK_HEADER FirstBlock,\n    _In_ PVOID Address\n    );\n\nULONG PhFppDecodeRva(\n    _In_ PPH_FILE_POOL Pool,\n    _In_ ULONG Rva,\n    _Out_ PULONG SegmentIndex\n    );\n\n#endif\n"
  },
  {
    "path": "third_party/phlib/include/filestream.h",
    "content": "#ifndef _PH_FILESTREAM_H\n#define _PH_FILESTREAM_H\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\n// Core flags (PhCreateFileStream2)\n/** Indicates that the file stream object should not close the file handle upon deletion. */\n#define PH_FILE_STREAM_HANDLE_UNOWNED 0x1\n/**\n * Indicates that the file stream object should not buffer I/O operations. Note that this does not\n * prevent the operating system from buffering I/O.\n */\n#define PH_FILE_STREAM_UNBUFFERED 0x2\n/**\n * Indicates that the file handle supports asynchronous operations. The file handle must not have\n * been opened with FILE_SYNCHRONOUS_IO_ALERT or FILE_SYNCHRONOUS_IO_NONALERT.\n */\n#define PH_FILE_STREAM_ASYNCHRONOUS 0x4\n/**\n * Indicates that the file stream object should maintain the file position and not use the file\n * object's own file position.\n */\n#define PH_FILE_STREAM_OWN_POSITION 0x8\n\n// Higher-level flags (PhCreateFileStream)\n#define PH_FILE_STREAM_APPEND 0x00010000\n\n// Internal flags\n/** Indicates that at least one write has been issued to the file handle. */\n#define PH_FILE_STREAM_WRITTEN 0x80000000\n\n// Seek\ntypedef enum _PH_SEEK_ORIGIN\n{\n    SeekStart,\n    SeekCurrent,\n    SeekEnd\n} PH_SEEK_ORIGIN;\n\ntypedef struct _PH_FILE_STREAM\n{\n    HANDLE FileHandle;\n    ULONG Flags;\n    LARGE_INTEGER Position; // file object position, *not* the actual position\n\n    PVOID Buffer;\n    ULONG BufferLength;\n\n    ULONG ReadPosition; // read position in buffer\n    ULONG ReadLength; // how much available to read from buffer\n    ULONG WritePosition; // write position in buffer\n} PH_FILE_STREAM, *PPH_FILE_STREAM;\n\nextern PPH_OBJECT_TYPE PhFileStreamType;\n\nBOOLEAN\nNTAPI\nPhFileStreamInitialization(\n    VOID\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhCreateFileStream(\n    _Out_ PPH_FILE_STREAM *FileStream,\n    _In_ PWSTR FileName,\n    _In_ ACCESS_MASK DesiredAccess,\n    _In_ ULONG ShareMode,\n    _In_ ULONG CreateDisposition,\n    _In_ ULONG Flags\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhCreateFileStream2(\n    _Out_ PPH_FILE_STREAM *FileStream,\n    _In_ HANDLE FileHandle,\n    _In_ ULONG Flags,\n    _In_ ULONG BufferLength\n    );\n\nPHLIBAPI\nVOID\nNTAPI\nPhVerifyFileStream(\n    _In_ PPH_FILE_STREAM FileStream\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhReadFileStream(\n    _Inout_ PPH_FILE_STREAM FileStream,\n    _Out_writes_bytes_(Length) PVOID Buffer,\n    _In_ ULONG Length,\n    _Out_opt_ PULONG ReadLength\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhWriteFileStream(\n    _Inout_ PPH_FILE_STREAM FileStream,\n    _In_reads_bytes_(Length) PVOID Buffer,\n    _In_ ULONG Length\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhFlushFileStream(\n    _Inout_ PPH_FILE_STREAM FileStream,\n    _In_ BOOLEAN Full\n    );\n\nPHLIBAPI\nVOID\nNTAPI\nPhGetPositionFileStream(\n    _In_ PPH_FILE_STREAM FileStream,\n    _Out_ PLARGE_INTEGER Position\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhSeekFileStream(\n    _Inout_ PPH_FILE_STREAM FileStream,\n    _In_ PLARGE_INTEGER Offset,\n    _In_ PH_SEEK_ORIGIN Origin\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhLockFileStream(\n    _Inout_ PPH_FILE_STREAM FileStream,\n    _In_ PLARGE_INTEGER Position,\n    _In_ PLARGE_INTEGER Length,\n    _In_ BOOLEAN Wait,\n    _In_ BOOLEAN Shared\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhUnlockFileStream(\n    _Inout_ PPH_FILE_STREAM FileStream,\n    _In_ PLARGE_INTEGER Position,\n    _In_ PLARGE_INTEGER Length\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhWriteStringAsUtf8FileStream(\n    _Inout_ PPH_FILE_STREAM FileStream,\n    _In_ PPH_STRINGREF String\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhWriteStringAsUtf8FileStream2(\n    _Inout_ PPH_FILE_STREAM FileStream,\n    _In_ PWSTR String\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhWriteStringAsUtf8FileStreamEx(\n    _Inout_ PPH_FILE_STREAM FileStream,\n    _In_ PWSTR Buffer,\n    _In_ SIZE_T Length\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhWriteStringFormatAsUtf8FileStream_V(\n    _Inout_ PPH_FILE_STREAM FileStream,\n    _In_ _Printf_format_string_ PWSTR Format,\n    _In_ va_list ArgPtr\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhWriteStringFormatAsUtf8FileStream(\n    _Inout_ PPH_FILE_STREAM FileStream,\n    _In_ _Printf_format_string_ PWSTR Format,\n    ...\n    );\n\n#ifdef __cplusplus\n}\n#endif\n\n#endif\n"
  },
  {
    "path": "third_party/phlib/include/filestreamp.h",
    "content": "#ifndef _PH_FILESTREAMP_H\n#define _PH_FILESTREAMP_H\n\nVOID NTAPI PhpFileStreamDeleteProcedure(\n    _In_ PVOID Object,\n    _In_ ULONG Flags\n    );\n\nNTSTATUS PhpAllocateBufferFileStream(\n    _Inout_ PPH_FILE_STREAM FileStream\n    );\n\nNTSTATUS PhpReadFileStream(\n    _Inout_ PPH_FILE_STREAM FileStream,\n    _Out_writes_bytes_(Length) PVOID Buffer,\n    _In_ ULONG Length,\n    _Out_opt_ PULONG ReadLength\n    );\n\nNTSTATUS PhpWriteFileStream(\n    _Inout_ PPH_FILE_STREAM FileStream,\n    _In_reads_bytes_(Length) PVOID Buffer,\n    _In_ ULONG Length\n    );\n\nNTSTATUS PhpFlushReadFileStream(\n    _Inout_ PPH_FILE_STREAM FileStream\n    );\n\nNTSTATUS PhpFlushWriteFileStream(\n    _Inout_ PPH_FILE_STREAM FileStream\n    );\n\nNTSTATUS PhpSeekFileStream(\n    _Inout_ PPH_FILE_STREAM FileStream,\n    _In_ PLARGE_INTEGER Offset,\n    _In_ PH_SEEK_ORIGIN Origin\n    );\n\n#endif\n"
  },
  {
    "path": "third_party/phlib/include/graph.h",
    "content": "#ifndef _PH_GRAPH_H\n#define _PH_GRAPH_H\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\n// Graph drawing\n\nextern RECT PhNormalGraphTextMargin;\nextern RECT PhNormalGraphTextPadding;\n\n#define PH_GRAPH_USE_GRID_X 0x1\n#define PH_GRAPH_USE_GRID_Y 0x2\n#define PH_GRAPH_LOGARITHMIC_GRID_Y 0x4\n#define PH_GRAPH_USE_LINE_2 0x10\n#define PH_GRAPH_OVERLAY_LINE_2 0x20\n#define PH_GRAPH_LABEL_MAX_Y 0x1000\n\ntypedef PPH_STRING (NTAPI *PPH_GRAPH_LABEL_Y_FUNCTION)(\n    _In_ struct _PH_GRAPH_DRAW_INFO *DrawInfo,\n    _In_ ULONG DataIndex,\n    _In_ FLOAT Value,\n    _In_ FLOAT Parameter\n    );\n\ntypedef struct _PH_GRAPH_DRAW_INFO\n{\n    // Basic\n    ULONG Width;\n    ULONG Height;\n    ULONG Flags;\n    ULONG Step;\n    COLORREF BackColor;\n\n    // Data/lines\n    ULONG LineDataCount;\n    PFLOAT LineData1;\n    PFLOAT LineData2;\n    COLORREF LineColor1;\n    COLORREF LineColor2;\n    COLORREF LineBackColor1;\n    COLORREF LineBackColor2;\n\n    // Grid\n    COLORREF GridColor;\n    ULONG GridWidth;\n    FLOAT GridHeight;\n    ULONG GridXOffset;\n    ULONG GridYThreshold;\n    FLOAT GridBase; // Base for logarithmic grid\n\n    // y-axis label\n    PPH_GRAPH_LABEL_Y_FUNCTION LabelYFunction;\n    FLOAT LabelYFunctionParameter;\n    HFONT LabelYFont;\n    COLORREF LabelYColor;\n    ULONG LabelMaxYIndexLimit;\n\n    // Text\n    PH_STRINGREF Text;\n    RECT TextRect;\n    RECT TextBoxRect;\n    HFONT TextFont;\n    COLORREF TextColor;\n    COLORREF TextBoxColor;\n} PH_GRAPH_DRAW_INFO, *PPH_GRAPH_DRAW_INFO;\n\n// Graph control\n\n#define PH_GRAPH_CLASSNAME L\"PhGraph\"\n\nPHLIBAPI\nBOOLEAN PhGraphControlInitialization(\n    VOID\n    );\n\nPHLIBAPI\nVOID PhDrawGraphDirect(\n    _In_ HDC hdc,\n    _In_ PVOID Bits,\n    _In_ PPH_GRAPH_DRAW_INFO DrawInfo\n    );\n\nPHLIBAPI\nVOID PhSetGraphText(\n    _In_ HDC hdc,\n    _Inout_ PPH_GRAPH_DRAW_INFO DrawInfo,\n    _In_ PPH_STRINGREF Text,\n    _In_ PRECT Margin,\n    _In_ PRECT Padding,\n    _In_ ULONG Align\n    );\n\nPHLIBAPI\nVOID PhDrawTrayIconText(\n    _In_ HDC hdc,\n    _In_ PVOID Bits,\n    _Inout_ PPH_GRAPH_DRAW_INFO DrawInfo,\n    _In_ PPH_STRINGREF Text\n    );\n\n\n// Configuration\n\ntypedef struct _PH_GRAPH_OPTIONS\n{\n    COLORREF FadeOutBackColor;\n    ULONG FadeOutWidth;\n    HCURSOR DefaultCursor;\n} PH_GRAPH_OPTIONS, *PPH_GRAPH_OPTIONS;\n\n// Styles\n\n#define GC_STYLE_FADEOUT 0x1\n#define GC_STYLE_DRAW_PANEL 0x2\n\n// Messages\n\n#define GCM_GETDRAWINFO (WM_USER + 1301)\n#define GCM_SETDRAWINFO (WM_USER + 1302)\n#define GCM_DRAW (WM_USER + 1303)\n#define GCM_MOVEGRID (WM_USER + 1304)\n#define GCM_GETBUFFEREDCONTEXT (WM_USER + 1305)\n#define GCM_SETTOOLTIP (WM_USER + 1306)\n#define GCM_UPDATETOOLTIP (WM_USER + 1307)\n#define GCM_GETOPTIONS (WM_USER + 1308)\n#define GCM_SETOPTIONS (WM_USER + 1309)\n\n#define Graph_GetDrawInfo(hWnd, DrawInfo) \\\n    SendMessage((hWnd), GCM_GETDRAWINFO, 0, (LPARAM)(DrawInfo))\n#define Graph_SetDrawInfo(hWnd, DrawInfo) \\\n    SendMessage((hWnd), GCM_SETDRAWINFO, 0, (LPARAM)(DrawInfo))\n#define Graph_Draw(hWnd) \\\n    SendMessage((hWnd), GCM_DRAW, 0, 0)\n#define Graph_MoveGrid(hWnd, Increment) \\\n    SendMessage((hWnd), GCM_MOVEGRID, (WPARAM)(Increment), 0)\n#define Graph_GetBufferedContext(hWnd) \\\n    ((HDC)SendMessage((hWnd), GCM_GETBUFFEREDCONTEXT, 0, 0))\n#define Graph_SetTooltip(hWnd, Enable) \\\n    ((HDC)SendMessage((hWnd), GCM_SETTOOLTIP, (WPARAM)(Enable), 0))\n#define Graph_UpdateTooltip(hWnd) \\\n    ((HDC)SendMessage((hWnd), GCM_UPDATETOOLTIP, 0, 0))\n#define Graph_GetOptions(hWnd, Options) \\\n    SendMessage((hWnd), GCM_GETOPTIONS, 0, (LPARAM)(Options))\n#define Graph_SetOptions(hWnd, Options) \\\n    SendMessage((hWnd), GCM_SETOPTIONS, 0, (LPARAM)(Options))\n\n// Notifications\n\n#define GCN_GETDRAWINFO (WM_USER + 1351)\n#define GCN_GETTOOLTIPTEXT (WM_USER + 1352)\n#define GCN_MOUSEEVENT (WM_USER + 1353)\n#define GCN_DRAWPANEL (WM_USER + 1354)\n\ntypedef struct _PH_GRAPH_GETDRAWINFO\n{\n    NMHDR Header;\n    PPH_GRAPH_DRAW_INFO DrawInfo;\n} PH_GRAPH_GETDRAWINFO, *PPH_GRAPH_GETDRAWINFO;\n\ntypedef struct _PH_GRAPH_GETTOOLTIPTEXT\n{\n    NMHDR Header;\n    ULONG Index;\n    ULONG TotalCount;\n\n    PH_STRINGREF Text; // must be null-terminated\n} PH_GRAPH_GETTOOLTIPTEXT, *PPH_GRAPH_GETTOOLTIPTEXT;\n\ntypedef struct _PH_GRAPH_MOUSEEVENT\n{\n    NMHDR Header;\n    ULONG Index;\n    ULONG TotalCount;\n\n    ULONG Message;\n    ULONG Keys;\n    POINT Point;\n} PH_GRAPH_MOUSEEVENT, *PPH_GRAPH_MOUSEEVENT;\n\ntypedef struct _PH_GRAPH_DRAWPANEL\n{\n    NMHDR Header;\n    HDC hdc;\n    RECT Rect;\n} PH_GRAPH_DRAWPANEL, *PPH_GRAPH_DRAWPANEL;\n\n// Graph buffer management\n\n#define PH_GRAPH_DATA_COUNT(Width, Step) (((Width) + (Step) - 1) / (Step) + 1) // round up in division\n\ntypedef struct _PH_GRAPH_BUFFERS\n{\n    PFLOAT Data1; // invalidate by setting Valid to FALSE\n    PFLOAT Data2; // invalidate by setting Valid to FALSE\n    ULONG AllocatedCount;\n    BOOLEAN Valid; // indicates the data is valid\n} PH_GRAPH_BUFFERS, *PPH_GRAPH_BUFFERS;\n\nPHLIBAPI\nVOID PhInitializeGraphBuffers(\n    _Out_ PPH_GRAPH_BUFFERS Buffers\n    );\n\nPHLIBAPI\nVOID PhDeleteGraphBuffers(\n    _Inout_ PPH_GRAPH_BUFFERS Buffers\n    );\n\nPHLIBAPI\nVOID PhGetDrawInfoGraphBuffers(\n    _Inout_ PPH_GRAPH_BUFFERS Buffers,\n    _Inout_ PPH_GRAPH_DRAW_INFO DrawInfo,\n    _In_ ULONG DataCount\n    );\n\n// Graph control state\n\n// The basic buffer management structure was moved out of this section because\n// the text management is not needed for most cases.\n\ntypedef struct _PH_GRAPH_STATE\n{\n    // Union for compatibility\n    union\n    {\n        struct\n        {\n            PFLOAT Data1; // invalidate by setting Valid to FALSE\n            PFLOAT Data2; // invalidate by setting Valid to FALSE\n            ULONG AllocatedCount;\n            BOOLEAN Valid; // indicates the data is valid\n        };\n        PH_GRAPH_BUFFERS Buffers;\n    };\n\n    PPH_STRING Text;\n    PPH_STRING TooltipText; // invalidate by setting TooltipIndex to -1\n    ULONG TooltipIndex; // indicates the tooltip text is valid for this index\n} PH_GRAPH_STATE, *PPH_GRAPH_STATE;\n\nPHLIBAPI\nVOID PhInitializeGraphState(\n    _Out_ PPH_GRAPH_STATE State\n    );\n\nPHLIBAPI\nVOID PhDeleteGraphState(\n    _Inout_ PPH_GRAPH_STATE State\n    );\n\nPHLIBAPI\nVOID PhGraphStateGetDrawInfo(\n    _Inout_ PPH_GRAPH_STATE State,\n    _In_ PPH_GRAPH_GETDRAWINFO GetDrawInfo,\n    _In_ ULONG DataCount\n    );\n\n#ifdef __cplusplus\n}\n#endif\n\n#endif\n"
  },
  {
    "path": "third_party/phlib/include/guisup.h",
    "content": "#ifndef _PH_PHGUI_H\n#define _PH_PHGUI_H\n\n#pragma once\n\n#include <commctrl.h>\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\n// guisup\n\ntypedef BOOL (WINAPI *_IsImmersiveProcess)(\n    _In_ HANDLE hProcess\n    );\n\n#define RFF_NOBROWSE 0x0001\n#define RFF_NODEFAULT 0x0002\n#define RFF_CALCDIRECTORY 0x0004\n#define RFF_NOLABEL 0x0008\n#define RFF_NOSEPARATEMEM 0x0020\n#define RFF_OPTRUNAS 0x0040\n\n#define RFN_VALIDATE (-510)\n#define RFN_LIMITEDRUNAS (-511)\n\ntypedef struct _NMRUNFILEDLGW\n{\n    NMHDR hdr;\n    LPCWSTR lpszFile;\n    LPCWSTR lpszDirectory;\n    UINT nShow;\n} NMRUNFILEDLGW, *LPNMRUNFILEDLGW, *PNMRUNFILEDLGW;\n\ntypedef NMRUNFILEDLGW NMRUNFILEDLG;\ntypedef PNMRUNFILEDLGW PNMRUNFILEDLG;\ntypedef LPNMRUNFILEDLGW LPNMRUNFILEDLG;\n\n#define RF_OK 0x0000\n#define RF_CANCEL 0x0001\n#define RF_RETRY 0x0002\n\ntypedef HANDLE HTHEME;\n\ntypedef BOOL (WINAPI *_RunFileDlg)(\n    _In_ HWND hwndOwner,\n    _In_opt_ HICON hIcon,\n    _In_opt_ LPCWSTR lpszDirectory,\n    _In_opt_ LPCWSTR lpszTitle,\n    _In_opt_ LPCWSTR lpszDescription,\n    _In_ ULONG uFlags\n    );\n\ntypedef HRESULT (WINAPI *_SHAutoComplete)(\n    _In_ HWND hwndEdit,\n    _In_ ULONG dwFlags\n    );\n\nextern _IsImmersiveProcess IsImmersiveProcess_I;\nextern _RunFileDlg RunFileDlg;\nextern _SHAutoComplete SHAutoComplete_I;\n\nPHLIBAPI\nVOID PhGuiSupportInitialization(\n    VOID\n    );\n\nPHLIBAPI\nVOID PhSetControlTheme(\n    _In_ HWND Handle,\n    _In_ PWSTR Theme\n    );\n\nFORCEINLINE VOID PhSetWindowStyle(\n    _In_ HWND Handle,\n    _In_ LONG_PTR Mask,\n    _In_ LONG_PTR Value\n    )\n{\n    LONG_PTR style;\n\n    style = GetWindowLongPtr(Handle, GWL_STYLE);\n    style = (style & ~Mask) | (Value & Mask);\n    SetWindowLongPtr(Handle, GWL_STYLE, style);\n}\n\nFORCEINLINE VOID PhSetWindowExStyle(\n    _In_ HWND Handle,\n    _In_ LONG_PTR Mask,\n    _In_ LONG_PTR Value\n    )\n{\n    LONG_PTR style;\n\n    style = GetWindowLongPtr(Handle, GWL_EXSTYLE);\n    style = (style & ~Mask) | (Value & Mask);\n    SetWindowLongPtr(Handle, GWL_EXSTYLE, style);\n}\n\n#ifndef WM_REFLECT\n#define WM_REFLECT 0x2000\n#endif\n\n#define REFLECT_MESSAGE(hwnd, msg, wParam, lParam) \\\n    { \\\n        LRESULT result_ = PhReflectMessage(hwnd, msg, wParam, lParam); \\\n        \\\n        if (result_) \\\n            return result_; \\\n    }\n\n#define REFLECT_MESSAGE_DLG(hwndDlg, hwnd, msg, wParam, lParam) \\\n    { \\\n        LRESULT result_ = PhReflectMessage(hwnd, msg, wParam, lParam); \\\n        \\\n        if (result_) \\\n        { \\\n            SetWindowLongPtr(hwndDlg, DWLP_MSGRESULT, result_); \\\n            return TRUE; \\\n        } \\\n    }\n\nFORCEINLINE LRESULT PhReflectMessage(\n    _In_ HWND Handle,\n    _In_ UINT Message,\n    _In_ WPARAM wParam,\n    _In_ LPARAM lParam\n    )\n{\n    if (Message == WM_NOTIFY)\n    {\n        LPNMHDR header = (LPNMHDR)lParam;\n\n        if (header->hwndFrom == Handle)\n            return SendMessage(Handle, WM_REFLECT + Message, wParam, lParam);\n    }\n\n    return 0;\n}\n\n#define PH_DEFINE_MAKE_ATOM(AtomName) \\\ndo { \\\n    static UNICODE_STRING atomName = RTL_CONSTANT_STRING(AtomName); \\\n    static PH_INITONCE initOnce = PH_INITONCE_INIT; \\\n    static RTL_ATOM atom = 0; \\\n\\\n    if (PhBeginInitOnce(&initOnce)) \\\n    { \\\n        NtAddAtom(atomName.Buffer, atomName.Length, &atom); \\\n        PhEndInitOnce(&initOnce); \\\n    } \\\n\\\n    if (atom) \\\n        return (PWSTR)(ULONG_PTR)atom; \\\n    else \\\n        return atomName.Buffer; \\\n} while (0)\n\nFORCEINLINE VOID PhSetListViewStyle(\n    _In_ HWND Handle,\n    _In_ BOOLEAN AllowDragDrop,\n    _In_ BOOLEAN ShowLabelTips\n    )\n{\n    ULONG style;\n\n    style = LVS_EX_FULLROWSELECT | LVS_EX_DOUBLEBUFFER | LVS_EX_INFOTIP;\n\n    if (AllowDragDrop)\n        style |= LVS_EX_HEADERDRAGDROP;\n    if (ShowLabelTips)\n        style |= LVS_EX_LABELTIP;\n\n    ListView_SetExtendedListViewStyleEx(\n        Handle,\n        style,\n        -1\n        );\n}\n\nPHLIBAPI\nINT PhAddListViewColumn(\n    _In_ HWND ListViewHandle,\n    _In_ INT Index,\n    _In_ INT DisplayIndex,\n    _In_ INT SubItemIndex,\n    _In_ INT Format,\n    _In_ INT Width,\n    _In_ PWSTR Text\n    );\n\nPHLIBAPI\nINT PhAddListViewItem(\n    _In_ HWND ListViewHandle,\n    _In_ INT Index,\n    _In_ PWSTR Text,\n    _In_opt_ PVOID Param\n    );\n\nPHLIBAPI\nINT PhFindListViewItemByFlags(\n    _In_ HWND ListViewHandle,\n    _In_ INT StartIndex,\n    _In_ ULONG Flags\n    );\n\nPHLIBAPI\nINT PhFindListViewItemByParam(\n    _In_ HWND ListViewHandle,\n    _In_ INT StartIndex,\n    _In_opt_ PVOID Param\n    );\n\nPHLIBAPI\nLOGICAL PhGetListViewItemImageIndex(\n    _In_ HWND ListViewHandle,\n    _In_ INT Index,\n    _Out_ PINT ImageIndex\n    );\n\nPHLIBAPI\nLOGICAL PhGetListViewItemParam(\n    _In_ HWND ListViewHandle,\n    _In_ INT Index,\n    _Out_ PVOID *Param\n    );\n\nPHLIBAPI\nVOID PhRemoveListViewItem(\n    _In_ HWND ListViewHandle,\n    _In_ INT Index\n    );\n\nPHLIBAPI\nVOID PhSetListViewItemImageIndex(\n    _In_ HWND ListViewHandle,\n    _In_ INT Index,\n    _In_ INT ImageIndex\n    );\n\nPHLIBAPI\nVOID PhSetListViewSubItem(\n    _In_ HWND ListViewHandle,\n    _In_ INT Index,\n    _In_ INT SubItemIndex,\n    _In_ PWSTR Text\n    );\n\nPHLIBAPI\nINT PhAddTabControlTab(\n    _In_ HWND TabControlHandle,\n    _In_ INT Index,\n    _In_ PWSTR Text\n    );\n\n#define PhaGetDlgItemText(hwndDlg, id) \\\n    PH_AUTO_T(PH_STRING, PhGetWindowText(GetDlgItem(hwndDlg, id)))\n\nPHLIBAPI\nPPH_STRING PhGetWindowText(\n    _In_ HWND hwnd\n    );\n\n#define PH_GET_WINDOW_TEXT_INTERNAL 0x1\n#define PH_GET_WINDOW_TEXT_LENGTH_ONLY 0x2\n\nPHLIBAPI\nULONG PhGetWindowTextEx(\n    _In_ HWND hwnd,\n    _In_ ULONG Flags,\n    _Out_opt_ PPH_STRING *Text\n    );\n\nPHLIBAPI\nVOID PhAddComboBoxStrings(\n    _In_ HWND hWnd,\n    _In_ PWSTR *Strings,\n    _In_ ULONG NumberOfStrings\n    );\n\nPHLIBAPI\nPPH_STRING PhGetComboBoxString(\n    _In_ HWND hwnd,\n    _In_ INT Index\n    );\n\nPHLIBAPI\nINT PhSelectComboBoxString(\n    _In_ HWND hwnd,\n    _In_ PWSTR String,\n    _In_ BOOLEAN Partial\n    );\n\nPHLIBAPI\nPPH_STRING PhGetListBoxString(\n    _In_ HWND hwnd,\n    _In_ INT Index\n    );\n\nPHLIBAPI\nVOID PhSetStateAllListViewItems(\n    _In_ HWND hWnd,\n    _In_ ULONG State,\n    _In_ ULONG Mask\n    );\n\nPHLIBAPI\nPVOID PhGetSelectedListViewItemParam(\n    _In_ HWND hWnd\n    );\n\nPHLIBAPI\nVOID PhGetSelectedListViewItemParams(\n    _In_ HWND hWnd,\n    _Out_ PVOID **Items,\n    _Out_ PULONG NumberOfItems\n    );\n\nPHLIBAPI\nVOID PhSetImageListBitmap(\n    _In_ HIMAGELIST ImageList,\n    _In_ INT Index,\n    _In_ HINSTANCE InstanceHandle,\n    _In_ LPCWSTR BitmapName\n    );\n\n#define PH_LOAD_ICON_SHARED 0x1\n#define PH_LOAD_ICON_SIZE_SMALL 0x2\n#define PH_LOAD_ICON_SIZE_LARGE 0x4\n#define PH_LOAD_ICON_STRICT 0x8\n\nPHLIBAPI\nHICON PhLoadIcon(\n    _In_opt_ HINSTANCE InstanceHandle,\n    _In_ PWSTR Name,\n    _In_ ULONG Flags,\n    _In_opt_ ULONG Width,\n    _In_opt_ ULONG Height\n    );\n\nPHLIBAPI\nVOID PhGetStockApplicationIcon(\n    _Out_opt_ HICON *SmallIcon,\n    _Out_opt_ HICON *LargeIcon\n    );\n\nPHLIBAPI\nHICON PhGetFileShellIcon(\n    _In_opt_ PWSTR FileName,\n    _In_opt_ PWSTR DefaultExtension,\n    _In_ BOOLEAN LargeIcon\n    );\n\nPHLIBAPI\nVOID PhSetClipboardString(\n    _In_ HWND hWnd,\n    _In_ PPH_STRINGREF String\n    );\n\ntypedef struct _DLGTEMPLATEEX\n{\n    WORD dlgVer;\n    WORD signature;\n    DWORD helpID;\n    DWORD exStyle;\n    DWORD style;\n    WORD cDlgItems;\n    short x;\n    short y;\n    short cx;\n    short cy;\n} DLGTEMPLATEEX, *PDLGTEMPLATEEX;\n\nPHLIBAPI\nHWND PhCreateDialogFromTemplate(\n    _In_ HWND Parent,\n    _In_ ULONG Style,\n    _In_ PVOID Instance,\n    _In_ PWSTR Template,\n    _In_ DLGPROC DialogProc,\n    _In_ PVOID Parameter\n    );\n\nPHLIBAPI\nBOOLEAN PhModalPropertySheet(\n    _Inout_ PROPSHEETHEADER *Header\n    );\n\n#define PH_ANCHOR_LEFT 0x1\n#define PH_ANCHOR_TOP 0x2\n#define PH_ANCHOR_RIGHT 0x4\n#define PH_ANCHOR_BOTTOM 0x8\n#define PH_ANCHOR_ALL 0xf\n\n// This interface is horrible and should be rewritten, but it works for now.\n\n#define PH_LAYOUT_FORCE_INVALIDATE 0x1000 // invalidate the control when it is resized\n#define PH_LAYOUT_TAB_CONTROL 0x2000 // this is a dummy item, a hack for the tab control\n#define PH_LAYOUT_IMMEDIATE_RESIZE 0x4000 // needed for the tab control hack\n\n#define PH_LAYOUT_DUMMY_MASK (PH_LAYOUT_TAB_CONTROL) // items that don't have a window handle, or don't actually get their window resized\n\ntypedef struct _PH_LAYOUT_ITEM\n{\n    HWND Handle;\n    struct _PH_LAYOUT_ITEM *ParentItem; // for rectangle calculation\n    struct _PH_LAYOUT_ITEM *LayoutParentItem; // for actual resizing\n    ULONG LayoutNumber;\n    ULONG NumberOfChildren;\n    HDWP DeferHandle;\n\n    RECT Rect;\n    RECT OrigRect;\n    RECT Margin;\n    ULONG Anchor;\n} PH_LAYOUT_ITEM, *PPH_LAYOUT_ITEM;\n\ntypedef struct _PH_LAYOUT_MANAGER\n{\n    PPH_LIST List;\n    PH_LAYOUT_ITEM RootItem;\n\n    ULONG LayoutNumber;\n} PH_LAYOUT_MANAGER, *PPH_LAYOUT_MANAGER;\n\nPHLIBAPI\nVOID PhInitializeLayoutManager(\n    _Out_ PPH_LAYOUT_MANAGER Manager,\n    _In_ HWND RootWindowHandle\n    );\n\nPHLIBAPI\nVOID PhDeleteLayoutManager(\n    _Inout_ PPH_LAYOUT_MANAGER Manager\n    );\n\nPHLIBAPI\nPPH_LAYOUT_ITEM PhAddLayoutItem(\n    _Inout_ PPH_LAYOUT_MANAGER Manager,\n    _In_ HWND Handle,\n    _In_opt_ PPH_LAYOUT_ITEM ParentItem,\n    _In_ ULONG Anchor\n    );\n\nPHLIBAPI\nPPH_LAYOUT_ITEM PhAddLayoutItemEx(\n    _Inout_ PPH_LAYOUT_MANAGER Manager,\n    _In_ HWND Handle,\n    _In_opt_ PPH_LAYOUT_ITEM ParentItem,\n    _In_ ULONG Anchor,\n    _In_ RECT Margin\n    );\n\nPHLIBAPI\nVOID PhLayoutManagerLayout(\n    _Inout_ PPH_LAYOUT_MANAGER Manager\n    );\n\nFORCEINLINE VOID PhResizingMinimumSize(\n    _Inout_ PRECT Rect,\n    _In_ WPARAM Edge,\n    _In_ LONG MinimumWidth,\n    _In_ LONG MinimumHeight\n    )\n{\n    if (Edge == WMSZ_BOTTOMRIGHT || Edge == WMSZ_RIGHT || Edge == WMSZ_TOPRIGHT)\n    {\n        if (Rect->right - Rect->left < MinimumWidth)\n            Rect->right = Rect->left + MinimumWidth;\n    }\n    else if (Edge == WMSZ_BOTTOMLEFT || Edge == WMSZ_LEFT || Edge == WMSZ_TOPLEFT)\n    {\n        if (Rect->right - Rect->left < MinimumWidth)\n            Rect->left = Rect->right - MinimumWidth;\n    }\n\n    if (Edge == WMSZ_BOTTOMRIGHT || Edge == WMSZ_BOTTOM || Edge == WMSZ_BOTTOMLEFT)\n    {\n        if (Rect->bottom - Rect->top < MinimumHeight)\n            Rect->bottom = Rect->top + MinimumHeight;\n    }\n    else if (Edge == WMSZ_TOPRIGHT || Edge == WMSZ_TOP || Edge == WMSZ_TOPLEFT)\n    {\n        if (Rect->bottom - Rect->top < MinimumHeight)\n            Rect->top = Rect->bottom - MinimumHeight;\n    }\n}\n\nFORCEINLINE VOID PhCopyControlRectangle(\n    _In_ HWND ParentWindowHandle,\n    _In_ HWND FromControlHandle,\n    _In_ HWND ToControlHandle\n    )\n{\n    RECT windowRect;\n\n    GetWindowRect(FromControlHandle, &windowRect);\n    MapWindowPoints(NULL, ParentWindowHandle, (POINT *)&windowRect, 2);\n    MoveWindow(ToControlHandle, windowRect.left, windowRect.top,\n        windowRect.right - windowRect.left, windowRect.bottom - windowRect.top, FALSE);\n}\n\n// icotobmp\n\nPHLIBAPI\nHBITMAP\nNTAPI\nPhIconToBitmap(\n    _In_ HICON Icon,\n    _In_ ULONG Width,\n    _In_ ULONG Height\n    );\n\n// extlv\n\n#define PH_ALIGN_CENTER 0x0\n#define PH_ALIGN_LEFT 0x1\n#define PH_ALIGN_RIGHT 0x2\n#define PH_ALIGN_TOP 0x4\n#define PH_ALIGN_BOTTOM 0x8\n\ntypedef enum _PH_ITEM_STATE\n{\n    // The item is normal. Use the ItemColorFunction to determine the color of the item.\n    NormalItemState = 0,\n    // The item is new. On the next tick, change the state to NormalItemState. When an item is in\n    // this state, highlight it in NewColor.\n    NewItemState,\n    // The item is being removed. On the next tick, delete the item. When an item is in this state,\n    // highlight it in RemovingColor.\n    RemovingItemState\n} PH_ITEM_STATE;\n\ntypedef COLORREF (NTAPI *PPH_EXTLV_GET_ITEM_COLOR)(\n    _In_ INT Index,\n    _In_ PVOID Param,\n    _In_opt_ PVOID Context\n    );\n\ntypedef HFONT (NTAPI *PPH_EXTLV_GET_ITEM_FONT)(\n    _In_ INT Index,\n    _In_ PVOID Param,\n    _In_opt_ PVOID Context\n    );\n\nPHLIBAPI\nVOID\nNTAPI\nPhSetExtendedListView(\n    _In_ HWND hWnd\n    );\n\nPHLIBAPI\nVOID\nNTAPI\nPhSetHeaderSortIcon(\n    _In_ HWND hwnd,\n    _In_ INT Index,\n    _In_ PH_SORT_ORDER Order\n    );\n\n// next 1122\n\n#define ELVM_ADDFALLBACKCOLUMN (WM_APP + 1106)\n#define ELVM_ADDFALLBACKCOLUMNS (WM_APP + 1109)\n#define ELVM_RESERVED5 (WM_APP + 1120)\n#define ELVM_INIT (WM_APP + 1102)\n#define ELVM_SETCOLUMNWIDTH (WM_APP + 1121)\n#define ELVM_SETCOMPAREFUNCTION (WM_APP + 1104)\n#define ELVM_SETCONTEXT (WM_APP + 1103)\n#define ELVM_SETCURSOR (WM_APP + 1114)\n#define ELVM_RESERVED4 (WM_APP + 1118)\n#define ELVM_SETITEMCOLORFUNCTION (WM_APP + 1111)\n#define ELVM_SETITEMFONTFUNCTION (WM_APP + 1117)\n#define ELVM_RESERVED1 (WM_APP + 1112)\n#define ELVM_SETREDRAW (WM_APP + 1116)\n#define ELVM_RESERVED2 (WM_APP + 1113)\n#define ELVM_SETSORT (WM_APP + 1108)\n#define ELVM_SETSORTFAST (WM_APP + 1119)\n#define ELVM_RESERVED0 (WM_APP + 1110)\n#define ELVM_SETTRISTATE (WM_APP + 1107)\n#define ELVM_SETTRISTATECOMPAREFUNCTION (WM_APP + 1105)\n#define ELVM_SORTITEMS (WM_APP + 1101)\n#define ELVM_RESERVED3 (WM_APP + 1115)\n\n#define ExtendedListView_AddFallbackColumn(hWnd, Column) \\\n    SendMessage((hWnd), ELVM_ADDFALLBACKCOLUMN, (WPARAM)(Column), 0)\n#define ExtendedListView_AddFallbackColumns(hWnd, NumberOfColumns, Columns) \\\n    SendMessage((hWnd), ELVM_ADDFALLBACKCOLUMNS, (WPARAM)(NumberOfColumns), (LPARAM)(Columns))\n#define ExtendedListView_Init(hWnd) \\\n    SendMessage((hWnd), ELVM_INIT, 0, 0)\n#define ExtendedListView_SetColumnWidth(hWnd, Column, Width) \\\n    SendMessage((hWnd), ELVM_SETCOLUMNWIDTH, (WPARAM)(Column), (LPARAM)(Width))\n#define ExtendedListView_SetCompareFunction(hWnd, Column, CompareFunction) \\\n    SendMessage((hWnd), ELVM_SETCOMPAREFUNCTION, (WPARAM)(Column), (LPARAM)(CompareFunction))\n#define ExtendedListView_SetContext(hWnd, Context) \\\n    SendMessage((hWnd), ELVM_SETCONTEXT, 0, (LPARAM)(Context))\n#define ExtendedListView_SetCursor(hWnd, Cursor) \\\n    SendMessage((hWnd), ELVM_SETCURSOR, 0, (LPARAM)(Cursor))\n#define ExtendedListView_SetItemColorFunction(hWnd, ItemColorFunction) \\\n    SendMessage((hWnd), ELVM_SETITEMCOLORFUNCTION, 0, (LPARAM)(ItemColorFunction))\n#define ExtendedListView_SetItemFontFunction(hWnd, ItemFontFunction) \\\n    SendMessage((hWnd), ELVM_SETITEMFONTFUNCTION, 0, (LPARAM)(ItemFontFunction))\n#define ExtendedListView_SetRedraw(hWnd, Redraw) \\\n    SendMessage((hWnd), ELVM_SETREDRAW, (WPARAM)(Redraw), 0)\n#define ExtendedListView_SetSort(hWnd, Column, Order) \\\n    SendMessage((hWnd), ELVM_SETSORT, (WPARAM)(Column), (LPARAM)(Order))\n#define ExtendedListView_SetSortFast(hWnd, Fast) \\\n    SendMessage((hWnd), ELVM_SETSORTFAST, (WPARAM)(Fast), 0)\n#define ExtendedListView_SetTriState(hWnd, TriState) \\\n    SendMessage((hWnd), ELVM_SETTRISTATE, (WPARAM)(TriState), 0)\n#define ExtendedListView_SetTriStateCompareFunction(hWnd, CompareFunction) \\\n    SendMessage((hWnd), ELVM_SETTRISTATECOMPAREFUNCTION, 0, (LPARAM)(CompareFunction))\n#define ExtendedListView_SortItems(hWnd) \\\n    SendMessage((hWnd), ELVM_SORTITEMS, 0, 0)\n\n#define ELVSCW_AUTOSIZE (-1)\n#define ELVSCW_AUTOSIZE_USEHEADER (-2)\n#define ELVSCW_AUTOSIZE_REMAININGSPACE (-3)\n\n/**\n * Gets the brightness of a color.\n *\n * \\param Color The color.\n *\n * \\return A value ranging from 0 to 255, indicating the brightness of the color.\n */\nFORCEINLINE\nULONG\nPhGetColorBrightness(\n    _In_ COLORREF Color\n    )\n{\n    ULONG r = Color & 0xff;\n    ULONG g = (Color >> 8) & 0xff;\n    ULONG b = (Color >> 16) & 0xff;\n    ULONG min;\n    ULONG max;\n\n    min = r;\n    if (g < min) min = g;\n    if (b < min) min = b;\n\n    max = r;\n    if (g > max) max = g;\n    if (b > max) max = b;\n\n    return (min + max) / 2;\n}\n\nFORCEINLINE\nCOLORREF\nPhHalveColorBrightness(\n    _In_ COLORREF Color\n    )\n{\n    /*return RGB(\n        (UCHAR)Color / 2,\n        (UCHAR)(Color >> 8) / 2,\n        (UCHAR)(Color >> 16) / 2\n        );*/\n    // Since all targets are little-endian, we can use the following method.\n    *((PUCHAR)&Color) /= 2;\n    *((PUCHAR)&Color + 1) /= 2;\n    *((PUCHAR)&Color + 2) /= 2;\n\n    return Color;\n}\n\nFORCEINLINE\nCOLORREF\nPhMakeColorBrighter(\n    _In_ COLORREF Color,\n    _In_ UCHAR Increment\n    )\n{\n    UCHAR r;\n    UCHAR g;\n    UCHAR b;\n\n    r = (UCHAR)Color;\n    g = (UCHAR)(Color >> 8);\n    b = (UCHAR)(Color >> 16);\n\n    if (r <= 255 - Increment)\n        r += Increment;\n    else\n        r = 255;\n\n    if (g <= 255 - Increment)\n        g += Increment;\n    else\n        g = 255;\n\n    if (b <= 255 - Increment)\n        b += Increment;\n    else\n        b = 255;\n\n    return RGB(r, g, b);\n}\n\n#ifdef __cplusplus\n}\n#endif\n\n#endif"
  },
  {
    "path": "third_party/phlib/include/guisupp.h",
    "content": "#ifndef _PH_GUISUPP_H\n#define _PH_GUISUPP_H\n\ntypedef struct _PHP_ICON_ENTRY\n{\n    HINSTANCE InstanceHandle;\n    PWSTR Name;\n    ULONG Width;\n    ULONG Height;\n    HICON Icon;\n} PHP_ICON_ENTRY, *PPHP_ICON_ENTRY;\n\n#define PHP_ICON_ENTRY_SIZE_SMALL (-1)\n#define PHP_ICON_ENTRY_SIZE_LARGE (-2)\n\nFORCEINLINE ULONG PhpGetIconEntrySize(\n    _In_ ULONG InputSize,\n    _In_ ULONG Flags\n    )\n{\n    if (Flags & PH_LOAD_ICON_SIZE_SMALL)\n        return PHP_ICON_ENTRY_SIZE_SMALL;\n    if (Flags & PH_LOAD_ICON_SIZE_LARGE)\n        return PHP_ICON_ENTRY_SIZE_LARGE;\n    return InputSize;\n}\n\n#endif\n"
  },
  {
    "path": "third_party/phlib/include/handle.h",
    "content": "#ifndef _PH_HANDLE_H\n#define _PH_HANDLE_H\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\nstruct _PH_HANDLE_TABLE;\ntypedef struct _PH_HANDLE_TABLE *PPH_HANDLE_TABLE;\n\ntypedef struct _PH_HANDLE_TABLE_ENTRY\n{\n    union\n    {\n        PVOID Object;\n        ULONG_PTR Value;\n        struct\n        {\n            /** The type of the entry; 1 if the entry is free, otherwise 0 if the entry is in use. */\n            ULONG_PTR Type : 1;\n            /**\n             * Whether the entry is not locked; 1 if the entry is not locked, otherwise 0 if the\n             * entry is locked.\n             */\n            ULONG_PTR Locked : 1;\n            ULONG_PTR Value : sizeof(ULONG_PTR) * 8 - 2;\n        } TypeAndValue;\n    };\n    union\n    {\n        ACCESS_MASK GrantedAccess;\n        ULONG NextFreeValue;\n        ULONG_PTR Value2;\n    };\n} PH_HANDLE_TABLE_ENTRY, *PPH_HANDLE_TABLE_ENTRY;\n\n#define PH_HANDLE_TABLE_SAFE\n#define PH_HANDLE_TABLE_FREE_COUNT 64\n\n#define PH_HANDLE_TABLE_STRICT_FIFO 0x1\n#define PH_HANDLE_TABLE_VALID_FLAGS 0x1\n\nPHLIBAPI\nPPH_HANDLE_TABLE\nNTAPI\nPhCreateHandleTable(\n    VOID\n    );\n\nPHLIBAPI\nVOID\nNTAPI\nPhDestroyHandleTable(\n    _In_ _Post_invalid_ PPH_HANDLE_TABLE HandleTable\n    );\n\nPHLIBAPI\nBOOLEAN\nNTAPI\nPhLockHandleTableEntry(\n    _Inout_ PPH_HANDLE_TABLE HandleTable,\n    _Inout_ PPH_HANDLE_TABLE_ENTRY HandleTableEntry\n    );\n\nPHLIBAPI\nVOID\nNTAPI\nPhUnlockHandleTableEntry(\n    _Inout_ PPH_HANDLE_TABLE HandleTable,\n    _Inout_ PPH_HANDLE_TABLE_ENTRY HandleTableEntry\n    );\n\nPHLIBAPI\nHANDLE\nNTAPI\nPhCreateHandle(\n    _Inout_ PPH_HANDLE_TABLE HandleTable,\n    _In_ PPH_HANDLE_TABLE_ENTRY HandleTableEntry\n    );\n\nPHLIBAPI\nBOOLEAN\nNTAPI\nPhDestroyHandle(\n    _Inout_ PPH_HANDLE_TABLE HandleTable,\n    _In_ HANDLE Handle,\n    _In_opt_ PPH_HANDLE_TABLE_ENTRY HandleTableEntry\n    );\n\nPHLIBAPI\nPPH_HANDLE_TABLE_ENTRY\nNTAPI\nPhLookupHandleTableEntry(\n    _In_ PPH_HANDLE_TABLE HandleTable,\n    _In_ HANDLE Handle\n    );\n\ntypedef BOOLEAN (NTAPI *PPH_ENUM_HANDLE_TABLE_CALLBACK)(\n    _In_ PPH_HANDLE_TABLE HandleTable,\n    _In_ HANDLE Handle,\n    _In_ PPH_HANDLE_TABLE_ENTRY HandleTableEntry,\n    _In_opt_ PVOID Context\n    );\n\nPHLIBAPI\nVOID\nNTAPI\nPhEnumHandleTable(\n    _In_ PPH_HANDLE_TABLE HandleTable,\n    _In_ PPH_ENUM_HANDLE_TABLE_CALLBACK Callback,\n    _In_opt_ PVOID Context\n    );\n\nPHLIBAPI\nVOID\nNTAPI\nPhSweepHandleTable(\n    _In_ PPH_HANDLE_TABLE HandleTable,\n    _In_ PPH_ENUM_HANDLE_TABLE_CALLBACK Callback,\n    _In_opt_ PVOID Context\n    );\n\ntypedef enum _PH_HANDLE_TABLE_INFORMATION_CLASS\n{\n    HandleTableBasicInformation,\n    HandleTableFlagsInformation,\n    MaxHandleTableInfoClass\n} PH_HANDLE_TABLE_INFORMATION_CLASS;\n\ntypedef struct _PH_HANDLE_TABLE_BASIC_INFORMATION\n{\n    ULONG Count;\n    ULONG Flags;\n    ULONG TableLevel;\n} PH_HANDLE_TABLE_BASIC_INFORMATION, *PPH_HANDLE_TABLE_BASIC_INFORMATION;\n\ntypedef struct _PH_HANDLE_TABLE_FLAGS_INFORMATION\n{\n    ULONG Flags;\n} PH_HANDLE_TABLE_FLAGS_INFORMATION, *PPH_HANDLE_TABLE_FLAGS_INFORMATION;\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhQueryInformationHandleTable(\n    _In_ PPH_HANDLE_TABLE HandleTable,\n    _In_ PH_HANDLE_TABLE_INFORMATION_CLASS InformationClass,\n    _Out_writes_bytes_opt_(BufferLength) PVOID Buffer,\n    _In_ ULONG BufferLength,\n    _Out_opt_ PULONG ReturnLength\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhSetInformationHandleTable(\n    _Inout_ PPH_HANDLE_TABLE HandleTable,\n    _In_ PH_HANDLE_TABLE_INFORMATION_CLASS InformationClass,\n    _In_reads_bytes_(BufferLength) PVOID Buffer,\n    _In_ ULONG BufferLength\n    );\n\n#ifdef __cplusplus\n}\n#endif\n\n#endif\n"
  },
  {
    "path": "third_party/phlib/include/handlep.h",
    "content": "#ifndef _PH_HANDLEP_H\n#define _PH_HANDLEP_H\n\n#define PH_HANDLE_TABLE_ENTRY_TYPE 0x1\n#define PH_HANDLE_TABLE_ENTRY_IN_USE 0x0\n#define PH_HANDLE_TABLE_ENTRY_FREE 0x1\n\n// Locked actually means Not Locked. This means that an in use, locked handle table entry can be\n// used as-is.\n#define PH_HANDLE_TABLE_ENTRY_LOCKED 0x2\n#define PH_HANDLE_TABLE_ENTRY_LOCKED_SHIFT 1\n\n// There is initially one handle table level, with 256 entries. When the handle table is expanded,\n// the table is replaced with a level 1 table, which contains 256 pointers to level 0 tables (the\n// first entry already points to the initial level 0 table). Similarly, when the handle table is\n// expanded a second time, the table is replaced with a level 2 table, which contains 256 pointers\n// to level 1 tables.\n//\n// This provides a maximum of 16,777,216 handles.\n\n#define PH_HANDLE_TABLE_LEVEL_ENTRIES 256\n#define PH_HANDLE_TABLE_LEVEL_MASK 0x3\n\n#define PH_HANDLE_TABLE_LOCKS 8\n#define PH_HANDLE_TABLE_LOCK_INDEX(HandleValue) ((HandleValue) % PH_HANDLE_TABLE_LOCKS)\n\ntypedef struct _PH_HANDLE_TABLE\n{\n    PH_QUEUED_LOCK Lock;\n    PH_WAKE_EVENT HandleWakeEvent;\n\n    ULONG Count;\n    ULONG_PTR TableValue;\n    ULONG FreeValue;\n    ULONG NextValue;\n    ULONG FreeValueAlt;\n\n    ULONG Flags;\n\n    PH_QUEUED_LOCK Locks[PH_HANDLE_TABLE_LOCKS];\n} PH_HANDLE_TABLE, *PPH_HANDLE_TABLE;\n\nFORCEINLINE VOID PhpLockHandleTableShared(\n    _Inout_ PPH_HANDLE_TABLE HandleTable,\n    _In_ ULONG Index\n    )\n{\n    PhAcquireQueuedLockShared(&HandleTable->Locks[Index]);\n}\n\nFORCEINLINE VOID PhpUnlockHandleTableShared(\n    _Inout_ PPH_HANDLE_TABLE HandleTable,\n    _In_ ULONG Index\n    )\n{\n    PhReleaseQueuedLockShared(&HandleTable->Locks[Index]);\n}\n\n// Handle values work by specifying indicies into each\n// level.\n//\n// Bits 0-7: level 0\n// Bits 8-15: level 1\n// Bits 16-23: level 2\n// Bits 24-31: reserved\n\n#define PH_HANDLE_VALUE_INVALID ((ULONG)-1)\n#define PH_HANDLE_VALUE_SHIFT 2\n#define PH_HANDLE_VALUE_BIAS 4\n\n#define PH_HANDLE_VALUE_LEVEL0(HandleValue) ((HandleValue) & 0xff)\n#define PH_HANDLE_VALUE_LEVEL1_U(HandleValue) ((HandleValue) >> 8)\n#define PH_HANDLE_VALUE_LEVEL1(HandleValue) (PH_HANDLE_VALUE_LEVEL1_U(HandleValue) & 0xff)\n#define PH_HANDLE_VALUE_LEVEL2_U(HandleValue) ((HandleValue) >> 16)\n#define PH_HANDLE_VALUE_LEVEL2(HandleValue) (PH_HANDLE_VALUE_LEVEL2_U(HandleValue) & 0xff)\n#define PH_HANDLE_VALUE_IS_INVALID(HandleValue) (((HandleValue) >> 24) != 0)\n\nFORCEINLINE HANDLE PhpEncodeHandle(\n    _In_ ULONG HandleValue\n    )\n{\n    return UlongToHandle(((HandleValue << PH_HANDLE_VALUE_SHIFT) + PH_HANDLE_VALUE_BIAS));\n}\n\nFORCEINLINE ULONG PhpDecodeHandle(\n    _In_ HANDLE Handle\n    )\n{\n    return (HandleToUlong(Handle) - PH_HANDLE_VALUE_BIAS) >> PH_HANDLE_VALUE_SHIFT;\n}\n\nVOID PhpBlockOnLockedHandleTableEntry(\n    _Inout_ PPH_HANDLE_TABLE HandleTable,\n    _In_ PPH_HANDLE_TABLE_ENTRY HandleTableEntry\n    );\n\nPPH_HANDLE_TABLE_ENTRY PhpAllocateHandleTableEntry(\n    _Inout_ PPH_HANDLE_TABLE HandleTable,\n    _Out_ PULONG HandleValue\n    );\n\nVOID PhpFreeHandleTableEntry(\n    _Inout_ PPH_HANDLE_TABLE HandleTable,\n    _In_ ULONG HandleValue,\n    _Inout_ PPH_HANDLE_TABLE_ENTRY HandleTableEntry\n    );\n\nBOOLEAN PhpAllocateMoreHandleTableEntries(\n    _In_ PPH_HANDLE_TABLE HandleTable,\n    _In_ BOOLEAN Initialize\n    );\n\nPPH_HANDLE_TABLE_ENTRY PhpLookupHandleTableEntry(\n    _In_ PPH_HANDLE_TABLE HandleTable,\n    _In_ ULONG HandleValue\n    );\n\nULONG PhpMoveFreeHandleTableEntries(\n    _Inout_ PPH_HANDLE_TABLE HandleTable\n    );\n\nPPH_HANDLE_TABLE_ENTRY PhpCreateHandleTableLevel0(\n    _In_ PPH_HANDLE_TABLE HandleTable,\n    _In_ BOOLEAN Initialize\n    );\n\nVOID PhpFreeHandleTableLevel0(\n    _In_ PPH_HANDLE_TABLE_ENTRY Table\n    );\n\nPPH_HANDLE_TABLE_ENTRY *PhpCreateHandleTableLevel1(\n    _In_ PPH_HANDLE_TABLE HandleTable\n    );\n\nVOID PhpFreeHandleTableLevel1(\n    _In_ PPH_HANDLE_TABLE_ENTRY *Table\n    );\n\nPPH_HANDLE_TABLE_ENTRY **PhpCreateHandleTableLevel2(\n    _In_ PPH_HANDLE_TABLE HandleTable\n    );\n\nVOID PhpFreeHandleTableLevel2(\n    _In_ PPH_HANDLE_TABLE_ENTRY **Table\n    );\n\n#endif\n"
  },
  {
    "path": "third_party/phlib/include/hexedit.h",
    "content": "#ifndef _PH_HEXEDIT_H\n#define _PH_HEXEDIT_H\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\n#define PH_HEXEDIT_CLASSNAME L\"PhHexEdit\"\n\n#define EDIT_NONE 0\n#define EDIT_ASCII 1\n#define EDIT_HIGH 2\n#define EDIT_LOW 3\n\nPHLIBAPI\nBOOLEAN PhHexEditInitialization(\n    VOID\n    );\n\n#define HEM_SETBUFFER (WM_USER + 1)\n#define HEM_SETDATA (WM_USER + 2)\n#define HEM_GETBUFFER (WM_USER + 3)\n#define HEM_SETSEL (WM_USER + 4)\n#define HEM_SETEDITMODE (WM_USER + 5)\n#define HEM_SETBYTESPERROW (WM_USER + 6)\n\n#define HexEdit_SetBuffer(hWnd, Buffer, Length) \\\n    SendMessage((hWnd), HEM_SETBUFFER, (WPARAM)(Length), (LPARAM)(Buffer))\n\n#define HexEdit_SetData(hWnd, Buffer, Length) \\\n    SendMessage((hWnd), HEM_SETDATA, (WPARAM)(Length), (LPARAM)(Buffer))\n\n#define HexEdit_GetBuffer(hWnd, Length) \\\n    ((PUCHAR)SendMessage((hWnd), HEM_GETBUFFER, (WPARAM)(Length), 0))\n\n#define HexEdit_SetSel(hWnd, Start, End) \\\n    SendMessage((hWnd), HEM_SETSEL, (WPARAM)(Start), (LPARAM)(End))\n\n#define HexEdit_SetEditMode(hWnd, Mode) \\\n    SendMessage((hWnd), HEM_SETEDITMODE, (WPARAM)(Mode), 0)\n\n#define HexEdit_SetBytesPerRow(hWnd, BytesPerRow) \\\n    SendMessage((hWnd), HEM_SETBYTESPERROW, (WPARAM)(BytesPerRow), 0)\n\n#ifdef __cplusplus\n}\n#endif\n\n#endif\n"
  },
  {
    "path": "third_party/phlib/include/hexeditp.h",
    "content": "#ifndef _PH_HEXEDITP_H\n#define _PH_HEXEDITP_H\n\ntypedef struct _PHP_HEXEDIT_CONTEXT\n{\n    PUCHAR Data;\n    LONG Length;\n    BOOLEAN UserBuffer;\n    LONG TopIndex; // index of first visible byte on screen\n\n    LONG CurrentAddress;\n    LONG CurrentMode;\n    LONG SelStart;\n    LONG SelEnd;\n\n    LONG BytesPerRow;\n    LONG LinesPerPage;\n    BOOLEAN ShowAddress;\n    BOOLEAN ShowAscii;\n    BOOLEAN ShowHex;\n    BOOLEAN AddressIsWide;\n    BOOLEAN AllowLengthChange;\n\n    BOOLEAN NoAddressChange;\n    BOOLEAN HalfPage;\n\n    HFONT Font;\n    LONG LineHeight;\n    LONG NullWidth;\n    PWCHAR CharBuffer;\n    ULONG CharBufferLength;\n    BOOLEAN Update;\n\n    LONG HexOffset;\n    LONG AsciiOffset;\n    LONG AddressOffset;\n\n    BOOLEAN HasCapture;\n    POINT EditPosition;\n} PHP_HEXEDIT_CONTEXT, *PPHP_HEXEDIT_CONTEXT;\n\n#define IS_PRINTABLE(Byte) ((ULONG)((Byte) - ' ') <= (ULONG)('~' - ' '))\n\n#define TO_HEX(Buffer, Byte) \\\n{ \\\n    *(Buffer)++ = PhIntegerToChar[(Byte) >> 4]; \\\n    *(Buffer)++ = PhIntegerToChar[(Byte) & 0xf]; \\\n}\n\n#define REDRAW_WINDOW(hwnd) \\\n    RedrawWindow((hwnd), NULL, NULL, RDW_INVALIDATE | RDW_UPDATENOW | RDW_ERASE)\n\nVOID PhpCreateHexEditContext(\n    _Out_ PPHP_HEXEDIT_CONTEXT *Context\n    );\n\nVOID PhpFreeHexEditContext(\n    _In_ _Post_invalid_ PPHP_HEXEDIT_CONTEXT Context\n    );\n\nLRESULT CALLBACK PhpHexEditWndProc(\n    _In_ HWND hwnd,\n    _In_ UINT uMsg,\n    _In_ WPARAM wParam,\n    _In_ LPARAM lParam\n    );\n\nVOID PhpHexEditUpdateMetrics(\n    _In_ HWND hwnd,\n    _In_ PPHP_HEXEDIT_CONTEXT Context,\n    _In_ BOOLEAN UpdateLineHeight,\n    _In_opt_ HDC hdc\n    );\n\nVOID PhpHexEditOnPaint(\n    _In_ HWND hwnd,\n    _In_ PPHP_HEXEDIT_CONTEXT Context,\n    _In_ PAINTSTRUCT *PaintStruct,\n    _In_ HDC hdc\n    );\n\nVOID PhpHexEditUpdateScrollbars(\n    _In_ HWND hwnd,\n    _In_ PPHP_HEXEDIT_CONTEXT Context\n    );\n\nFORCEINLINE BOOLEAN PhpHexEditHasSelected(\n    _In_ PPHP_HEXEDIT_CONTEXT Context\n    )\n{\n    return Context->SelStart != -1;\n}\n\nVOID PhpHexEditCreateAddressCaret(\n    _In_ HWND hwnd,\n    _In_ PPHP_HEXEDIT_CONTEXT Context\n    );\n\nVOID PhpHexEditCreateEditCaret(\n    _In_ HWND hwnd,\n    _In_ PPHP_HEXEDIT_CONTEXT Context\n    );\n\nVOID PhpHexEditRepositionCaret(\n    _In_ HWND hwnd,\n    _In_ PPHP_HEXEDIT_CONTEXT Context,\n    _In_ LONG Position\n    );\n\nVOID PhpHexEditCalculatePosition(\n    _In_ HWND hwnd,\n    _In_ PPHP_HEXEDIT_CONTEXT Context,\n    _In_ LONG X,\n    _In_ LONG Y,\n    _Out_ POINT *Point\n    );\n\nVOID PhpHexEditMove(\n    _In_ HWND hwnd,\n    _In_ PPHP_HEXEDIT_CONTEXT Context,\n    _In_ LONG X,\n    _In_ LONG Y\n    );\n\nVOID PhpHexEditSetSel(\n    _In_ HWND hwnd,\n    _In_ PPHP_HEXEDIT_CONTEXT Context,\n    _In_ LONG S,\n    _In_ LONG E\n    );\n\nVOID PhpHexEditScrollTo(\n    _In_ HWND hwnd,\n    _In_ PPHP_HEXEDIT_CONTEXT Context,\n    _In_ LONG Position\n    );\n\nVOID PhpHexEditClearEdit(\n    _In_ HWND hwnd,\n    _In_ PPHP_HEXEDIT_CONTEXT Context\n    );\n\nVOID PhpHexEditCopyEdit(\n    _In_ HWND hwnd,\n    _In_ PPHP_HEXEDIT_CONTEXT Context\n    );\n\nVOID PhpHexEditCutEdit(\n    _In_ HWND hwnd,\n    _In_ PPHP_HEXEDIT_CONTEXT Context\n    );\n\nVOID PhpHexEditPasteEdit(\n    _In_ HWND hwnd,\n    _In_ PPHP_HEXEDIT_CONTEXT Context\n    );\n\nVOID PhpHexEditSelectAll(\n    _In_ HWND hwnd,\n    _In_ PPHP_HEXEDIT_CONTEXT Context\n    );\n\nVOID PhpHexEditUndoEdit(\n    _In_ HWND hwnd,\n    _In_ PPHP_HEXEDIT_CONTEXT Context\n    );\n\nVOID PhpHexEditNormalizeSel(\n    _In_ HWND hwnd,\n    _In_ PPHP_HEXEDIT_CONTEXT Context\n    );\n\nVOID PhpHexEditSelDelete(\n    _In_ HWND hwnd,\n    _In_ PPHP_HEXEDIT_CONTEXT Context,\n    _In_ LONG S,\n    _In_ LONG E\n    );\n\nVOID PhpHexEditSelInsert(\n    _In_ HWND hwnd,\n    _In_ PPHP_HEXEDIT_CONTEXT Context,\n    _In_ LONG S,\n    _In_ LONG L\n    );\n\nVOID PhpHexEditSetBuffer(\n    _In_ HWND hwnd,\n    _In_ PPHP_HEXEDIT_CONTEXT Context,\n    _In_ PUCHAR Data,\n    _In_ ULONG Length\n    );\n\nVOID PhpHexEditSetData(\n    _In_ HWND hwnd,\n    _In_ PPHP_HEXEDIT_CONTEXT Context,\n    _In_ PUCHAR Data,\n    _In_ ULONG Length\n    );\n\n#endif\n"
  },
  {
    "path": "third_party/phlib/include/hndlinfo.h",
    "content": "#ifndef _PH_HNDLINFO_H\n#define _PH_HNDLINFO_H\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\n#define MAX_OBJECT_TYPE_NUMBER 257\n\ntypedef PPH_STRING (NTAPI *PPH_GET_CLIENT_ID_NAME)(\n    _In_ PCLIENT_ID ClientId\n    );\n\nPHLIBAPI\nPPH_GET_CLIENT_ID_NAME\nNTAPI\nPhSetHandleClientIdFunction(\n    _In_ PPH_GET_CLIENT_ID_NAME GetClientIdName\n    );\n\nPHLIBAPI\nPPH_STRING\nNTAPI\nPhFormatNativeKeyName(\n    _In_ PPH_STRING Name\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhGetSectionFileName(\n    _In_ HANDLE SectionHandle,\n    _Out_ PPH_STRING *FileName\n    );\n\nPHLIBAPI\n_Callback_ PPH_STRING\nNTAPI\nPhStdGetClientIdName(\n    _In_ PCLIENT_ID ClientId\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhGetHandleInformation(\n    _In_ HANDLE ProcessHandle,\n    _In_ HANDLE Handle,\n    _In_ ULONG ObjectTypeNumber,\n    _Out_opt_ POBJECT_BASIC_INFORMATION BasicInformation,\n    _Out_opt_ PPH_STRING *TypeName,\n    _Out_opt_ PPH_STRING *ObjectName,\n    _Out_opt_ PPH_STRING *BestObjectName\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhGetHandleInformationEx(\n    _In_ HANDLE ProcessHandle,\n    _In_ HANDLE Handle,\n    _In_ ULONG ObjectTypeNumber,\n    _Reserved_ ULONG Flags,\n    _Out_opt_ PNTSTATUS SubStatus,\n    _Out_opt_ POBJECT_BASIC_INFORMATION BasicInformation,\n    _Out_opt_ PPH_STRING *TypeName,\n    _Out_opt_ PPH_STRING *ObjectName,\n    _Out_opt_ PPH_STRING *BestObjectName,\n    _Reserved_ PVOID *ExtraInformation\n    );\n\n#define PH_FIRST_OBJECT_TYPE(ObjectTypes) \\\n    PTR_ADD_OFFSET(ObjectTypes, ALIGN_UP(sizeof(OBJECT_TYPES_INFORMATION), ULONG_PTR))\n\n#define PH_NEXT_OBJECT_TYPE(ObjectType) \\\n    PTR_ADD_OFFSET(ObjectType, sizeof(OBJECT_TYPE_INFORMATION) + \\\n    ALIGN_UP(ObjectType->TypeName.MaximumLength, ULONG_PTR))\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhEnumObjectTypes(\n    _Out_ POBJECT_TYPES_INFORMATION *ObjectTypes\n    );\n\nPHLIBAPI\nULONG\nNTAPI\nPhGetObjectTypeNumber(\n    _In_ PUNICODE_STRING TypeName\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhCallWithTimeout(\n    _In_ PUSER_THREAD_START_ROUTINE Routine,\n    _In_opt_ PVOID Context,\n    _In_opt_ PLARGE_INTEGER AcquireTimeout,\n    _In_ PLARGE_INTEGER CallTimeout\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhCallNtQueryObjectWithTimeout(\n    _In_ HANDLE Handle,\n    _In_ OBJECT_INFORMATION_CLASS ObjectInformationClass,\n    _Out_writes_bytes_opt_(ObjectInformationLength) PVOID ObjectInformation,\n    _In_ ULONG ObjectInformationLength,\n    _Out_opt_ PULONG ReturnLength\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhCallNtQuerySecurityObjectWithTimeout(\n    _In_ HANDLE Handle,\n    _In_ SECURITY_INFORMATION SecurityInformation,\n    _Out_writes_bytes_opt_(Length) PSECURITY_DESCRIPTOR SecurityDescriptor,\n    _In_ ULONG Length,\n    _Out_ PULONG LengthNeeded\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhCallNtSetSecurityObjectWithTimeout(\n    _In_ HANDLE Handle,\n    _In_ SECURITY_INFORMATION SecurityInformation,\n    _In_ PSECURITY_DESCRIPTOR SecurityDescriptor\n    );\n\n#ifdef __cplusplus\n}\n#endif\n\n#endif\n"
  },
  {
    "path": "third_party/phlib/include/json.h",
    "content": "/*\n * Process Hacker -\n *   json wrapper\n *\n * Copyright (C) 2017 dmex\n *\n * This file is part of Process Hacker.\n *\n * Process Hacker is free software; you can redistribute it and/or modify\n * it under the terms of the GNU General Public License as published by\n * the Free Software Foundation, either version 3 of the License, or\n * (at your option) any later version.\n *\n * Process Hacker is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n * GNU General Public License for more details.\n *\n * You should have received a copy of the GNU General Public License\n * along with Process Hacker.  If not, see <http://www.gnu.org/licenses/>.\n */\n\n#ifndef _PH_PHJSON_H\n#define _PH_PHJSON_H\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\ntypedef struct _JSON_ARRAY_LIST_OBJECT\n{\n    PSTR Key;\n    PVOID Entry;\n} JSON_ARRAY_LIST_OBJECT, *PJSON_ARRAY_LIST_OBJECT;\n\nPHLIBAPI\nPVOID\nNTAPI\nPhCreateJsonParser(\n    _In_ PSTR JsonString\n    );\n\nPHLIBAPI\nVOID\nNTAPI\nPhFreeJsonParser(\n    _In_ PVOID Object\n    );\n\nPHLIBAPI\nPPH_STRING\nNTAPI\nPhGetJsonValueAsString(\n    _In_ PVOID Object,\n    _In_ PSTR Key\n    );\n\nPHLIBAPI\nINT64\nNTAPI\nPhGetJsonValueAsLong64(\n    _In_ PVOID Object,\n    _In_ PSTR Key\n    );\n\nPHLIBAPI\nPVOID\nNTAPI\nPhCreateJsonObject(\n    VOID\n    );\n\nPHLIBAPI\nPVOID\nNTAPI\nPhGetJsonObject(\n    _In_ PVOID Object,\n    _In_ PSTR Key\n    );\n\nPHLIBAPI\nINT\nNTAPI\nPhGetJsonObjectLength(\n    _In_ PVOID Object\n    );\n\nPHLIBAPI\nBOOLEAN\nNTAPI\nPhGetJsonObjectBool(\n    _In_ PVOID Object,\n    _In_ PSTR Key\n    );\n\nPHLIBAPI\nVOID\nNTAPI\nPhAddJsonObject(\n    _In_ PVOID Object,\n    _In_ PSTR Key,\n    _In_ PSTR Value\n    );\n\nPHLIBAPI\nPVOID\nNTAPI\nPhCreateJsonArray(\n    VOID\n    );\n\nPHLIBAPI\nVOID\nNTAPI\nPhAddJsonArrayObject(\n    _In_ PVOID Object,\n    _In_ PVOID jsonEntry\n    );\n\nPHLIBAPI\nPPH_STRING\nNTAPI\nPhGetJsonArrayString(\n    _In_ PVOID Object\n    );\n\nPHLIBAPI\nINT64\nNTAPI\nPhGetJsonArrayLong64(\n    _In_ PVOID Object,\n    _In_ INT Index\n    );\n\nPHLIBAPI\nINT\nNTAPI\nPhGetJsonArrayLength(\n    _In_ PVOID Object\n    );\n\nPHLIBAPI\nPVOID\nNTAPI\nPhGetJsonArrayIndexObject(\n    _In_ PVOID Object,\n    _In_ INT Index\n    );\n\nPHLIBAPI\nPPH_LIST\nNTAPI\nPhGetJsonObjectAsArrayList(\n    _In_ PVOID Object\n    );\n\nPHLIBAPI\nPVOID\nNTAPI\nPhLoadJsonObjectFromFile(\n    _In_ PWSTR FileName\n    );\n\nPHLIBAPI\nVOID\nNTAPI\nPhSaveJsonObjectToFile(\n    _In_ PWSTR FileName,\n    _In_ PVOID Object\n    );\n\n#ifdef __cplusplus\n}\n#endif\n\n#endif\n"
  },
  {
    "path": "third_party/phlib/include/kphapi.h",
    "content": "#ifndef _KPHAPI_H\n#define _KPHAPI_H\n\n// This file contains KProcessHacker definitions shared across kernel-mode and user-mode.\n\n// Process information\n\ntypedef enum _KPH_PROCESS_INFORMATION_CLASS\n{\n    KphProcessReserved1 = 1,\n    KphProcessReserved2 = 2,\n    KphProcessReserved3 = 3,\n    MaxKphProcessInfoClass\n} KPH_PROCESS_INFORMATION_CLASS;\n\n// Thread information\n\ntypedef enum _KPH_THREAD_INFORMATION_CLASS\n{\n    KphThreadReserved1 = 1,\n    KphThreadReserved2 = 2,\n    KphThreadReserved3 = 3,\n    MaxKphThreadInfoClass\n} KPH_THREAD_INFORMATION_CLASS;\n\n// Process handle information\n\ntypedef struct _KPH_PROCESS_HANDLE\n{\n    HANDLE Handle;\n    PVOID Object;\n    ACCESS_MASK GrantedAccess;\n    USHORT ObjectTypeIndex;\n    USHORT Reserved1;\n    ULONG HandleAttributes;\n    ULONG Reserved2;\n} KPH_PROCESS_HANDLE, *PKPH_PROCESS_HANDLE;\n\ntypedef struct _KPH_PROCESS_HANDLE_INFORMATION\n{\n    ULONG HandleCount;\n    KPH_PROCESS_HANDLE Handles[1];\n} KPH_PROCESS_HANDLE_INFORMATION, *PKPH_PROCESS_HANDLE_INFORMATION;\n\n// Object information\n\ntypedef enum _KPH_OBJECT_INFORMATION_CLASS\n{\n    KphObjectBasicInformation, // q: OBJECT_BASIC_INFORMATION\n    KphObjectNameInformation, // q: OBJECT_NAME_INFORMATION\n    KphObjectTypeInformation, // q: OBJECT_TYPE_INFORMATION\n    KphObjectHandleFlagInformation, // qs: OBJECT_HANDLE_FLAG_INFORMATION\n    KphObjectProcessBasicInformation, // q: PROCESS_BASIC_INFORMATION\n    KphObjectThreadBasicInformation, // q: THREAD_BASIC_INFORMATION\n    KphObjectEtwRegBasicInformation, // q: ETWREG_BASIC_INFORMATION\n    KphObjectFileObjectInformation, // q: KPH_FILE_OBJECT_INFORMATION\n    KphObjectFileObjectDriver, // q: KPH_FILE_OBJECT_DRIVER\n    MaxKphObjectInfoClass\n} KPH_OBJECT_INFORMATION_CLASS;\n\ntypedef struct _KPH_FILE_OBJECT_INFORMATION\n{\n    BOOLEAN LockOperation;\n    BOOLEAN DeletePending;\n    BOOLEAN ReadAccess;\n    BOOLEAN WriteAccess;\n    BOOLEAN DeleteAccess;\n    BOOLEAN SharedRead;\n    BOOLEAN SharedWrite;\n    BOOLEAN SharedDelete;\n    LARGE_INTEGER CurrentByteOffset;\n    ULONG Flags;\n} KPH_FILE_OBJECT_INFORMATION, *PKPH_FILE_OBJECT_INFORMATION;\n\ntypedef struct _KPH_FILE_OBJECT_DRIVER\n{\n    HANDLE DriverHandle;\n} KPH_FILE_OBJECT_DRIVER, *PKPH_FILE_OBJECT_DRIVER;\n\n// Driver information\n\ntypedef enum _DRIVER_INFORMATION_CLASS\n{\n    DriverBasicInformation,\n    DriverNameInformation,\n    DriverServiceKeyNameInformation,\n    MaxDriverInfoClass\n} DRIVER_INFORMATION_CLASS;\n\ntypedef struct _DRIVER_BASIC_INFORMATION\n{\n    ULONG Flags;\n    PVOID DriverStart;\n    ULONG DriverSize;\n} DRIVER_BASIC_INFORMATION, *PDRIVER_BASIC_INFORMATION;\n\ntypedef struct _DRIVER_NAME_INFORMATION\n{\n    UNICODE_STRING DriverName;\n} DRIVER_NAME_INFORMATION, *PDRIVER_NAME_INFORMATION;\n\ntypedef struct _DRIVER_SERVICE_KEY_NAME_INFORMATION\n{\n    UNICODE_STRING ServiceKeyName;\n} DRIVER_SERVICE_KEY_NAME_INFORMATION, *PDRIVER_SERVICE_KEY_NAME_INFORMATION;\n\n// ETW registration object information\n\ntypedef struct _ETWREG_BASIC_INFORMATION\n{\n    GUID Guid;\n    ULONG_PTR SessionId;\n} ETWREG_BASIC_INFORMATION, *PETWREG_BASIC_INFORMATION;\n\n// Device\n\n#define KPH_DEVICE_SHORT_NAME L\"KProcessHacker3\"\n#define KPH_DEVICE_TYPE 0x9999\n#define KPH_DEVICE_NAME (L\"\\\\Device\\\\\" KPH_DEVICE_SHORT_NAME)\n\n// Parameters\n\ntypedef enum _KPH_SECURITY_LEVEL\n{\n    KphSecurityNone = 0, // all clients are allowed\n    KphSecurityPrivilegeCheck = 1, // require SeDebugPrivilege\n    KphSecuritySignatureCheck = 2, // require trusted signature\n    KphSecuritySignatureAndPrivilegeCheck = 3, // require trusted signature and SeDebugPrivilege\n    KphMaxSecurityLevel\n} KPH_SECURITY_LEVEL, *PKPH_SECURITY_LEVEL;\n\ntypedef struct _KPH_DYN_STRUCT_DATA\n{\n    SHORT EgeGuid;                  // dt nt!_ETW_GUID_ENTRY Guid\n    SHORT EpObjectTable;            // dt nt!_EPROCESS ObjectTable\n    SHORT Reserved0;\n    SHORT Reserved1;\n    SHORT Reserved2;\n    SHORT EreGuidEntry;             // dt nt!_ETW_REG_ENTRY GuidEntry\n    SHORT HtHandleContentionEvent;  // dt nt!_HANDLE_TABLE HandleContentionEvent\n    SHORT OtName;                   // dt nt!_OBJECT_ATTRIBUTES ObjectName\n    SHORT OtIndex;                  // dt nt!_OBJECT_TYPE Index\n    SHORT ObDecodeShift;\n    SHORT ObAttributesShift;        // dt nt!_HANDLE_TABLE_ENTRY\n} KPH_DYN_STRUCT_DATA, *PKPH_DYN_STRUCT_DATA;\n\ntypedef struct _KPH_DYN_PACKAGE\n{\n    USHORT MajorVersion;\n    USHORT MinorVersion;\n    USHORT ServicePackMajor; // -1 to ignore\n    USHORT BuildNumber; // -1 to ignore\n    ULONG ResultingNtVersion; // PHNT_*\n    KPH_DYN_STRUCT_DATA StructData;\n} KPH_DYN_PACKAGE, *PKPH_DYN_PACKAGE;\n\n#define KPH_DYN_CONFIGURATION_VERSION 3\n#define KPH_DYN_MAXIMUM_PACKAGES 64\n\ntypedef struct _KPH_DYN_CONFIGURATION\n{\n    ULONG Version;\n    ULONG NumberOfPackages;\n    KPH_DYN_PACKAGE Packages[1];\n} KPH_DYN_CONFIGURATION, *PKPH_DYN_CONFIGURATION;\n\n// Verification\n\n#ifdef __BCRYPT_H__\n#define KPH_SIGN_ALGORITHM BCRYPT_ECDSA_P256_ALGORITHM\n#define KPH_SIGN_ALGORITHM_BITS 256\n#define KPH_HASH_ALGORITHM BCRYPT_SHA256_ALGORITHM\n#define KPH_BLOB_PUBLIC BCRYPT_ECCPUBLIC_BLOB\n#endif\n\n#define KPH_SIGNATURE_MAX_SIZE (128 * 1024) // 128 kB\n\ntypedef ULONG KPH_KEY, *PKPH_KEY;\n\ntypedef enum _KPH_KEY_LEVEL\n{\n    KphKeyLevel1 = 1,\n    KphKeyLevel2 = 2\n} KPH_KEY_LEVEL;\n\n#define KPH_KEY_BACKOFF_TIME ((LONGLONG)(100 * 1000 * 10)) // 100ms\n\n#define KPH_PROCESS_READ_ACCESS (STANDARD_RIGHTS_READ | SYNCHRONIZE |  PROCESS_QUERY_INFORMATION | \\\n    PROCESS_QUERY_LIMITED_INFORMATION | PROCESS_VM_READ)\n#define KPH_THREAD_READ_ACCESS (STANDARD_RIGHTS_READ | SYNCHRONIZE | THREAD_QUERY_INFORMATION | \\\n    THREAD_QUERY_LIMITED_INFORMATION | THREAD_GET_CONTEXT)\n#define KPH_TOKEN_READ_ACCESS TOKEN_READ\n\n// Features\n\n// No features defined.\n\n// Control codes\n\n#define KPH_CTL_CODE(x) CTL_CODE(KPH_DEVICE_TYPE, 0x800 + x, METHOD_NEITHER, FILE_ANY_ACCESS)\n\n// General\n#define KPH_GETFEATURES KPH_CTL_CODE(0)\n#define KPH_VERIFYCLIENT KPH_CTL_CODE(1)\n#define KPH_RETRIEVEKEY KPH_CTL_CODE(2) // User-mode only\n\n// Processes\n#define KPH_OPENPROCESS KPH_CTL_CODE(50) // L1/L2 protected API\n#define KPH_OPENPROCESSTOKEN KPH_CTL_CODE(51) // L1/L2 protected API\n#define KPH_OPENPROCESSJOB KPH_CTL_CODE(52)\n#define KPH_RESERVED53 KPH_CTL_CODE(53)\n#define KPH_RESERVED54 KPH_CTL_CODE(54)\n#define KPH_TERMINATEPROCESS KPH_CTL_CODE(55) // L2 protected API\n#define KPH_RESERVED56 KPH_CTL_CODE(56)\n#define KPH_RESERVED57 KPH_CTL_CODE(57)\n#define KPH_READVIRTUALMEMORYUNSAFE KPH_CTL_CODE(58) // L2 protected API\n#define KPH_QUERYINFORMATIONPROCESS KPH_CTL_CODE(59)\n#define KPH_SETINFORMATIONPROCESS KPH_CTL_CODE(60)\n\n// Threads\n#define KPH_OPENTHREAD KPH_CTL_CODE(100) // L1/L2 protected API\n#define KPH_OPENTHREADPROCESS KPH_CTL_CODE(101)\n#define KPH_RESERVED102 KPH_CTL_CODE(102)\n#define KPH_RESERVED103 KPH_CTL_CODE(103)\n#define KPH_RESERVED104 KPH_CTL_CODE(104)\n#define KPH_RESERVED105 KPH_CTL_CODE(105)\n#define KPH_CAPTURESTACKBACKTRACETHREAD KPH_CTL_CODE(106)\n#define KPH_QUERYINFORMATIONTHREAD KPH_CTL_CODE(107)\n#define KPH_SETINFORMATIONTHREAD KPH_CTL_CODE(108)\n\n// Handles\n#define KPH_ENUMERATEPROCESSHANDLES KPH_CTL_CODE(150)\n#define KPH_QUERYINFORMATIONOBJECT KPH_CTL_CODE(151)\n#define KPH_SETINFORMATIONOBJECT KPH_CTL_CODE(152)\n#define KPH_RESERVED153 KPH_CTL_CODE(153)\n\n// Misc.\n#define KPH_OPENDRIVER KPH_CTL_CODE(200)\n#define KPH_QUERYINFORMATIONDRIVER KPH_CTL_CODE(201)\n\n#endif"
  },
  {
    "path": "third_party/phlib/include/kphuser.h",
    "content": "#ifndef _PH_KPHUSER_H\n#define _PH_KPHUSER_H\n\n#include <kphapi.h>\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\ntypedef struct _KPH_PARAMETERS\n{\n    KPH_SECURITY_LEVEL SecurityLevel;\n    BOOLEAN CreateDynamicConfiguration;\n} KPH_PARAMETERS, *PKPH_PARAMETERS;\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nKphConnect(\n    _In_opt_ PWSTR DeviceName\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nKphConnect2(\n    _In_opt_ PWSTR DeviceName,\n    _In_ PWSTR FileName\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nKphConnect2Ex(\n    _In_opt_ PWSTR DeviceName,\n    _In_ PWSTR FileName,\n    _In_opt_ PKPH_PARAMETERS Parameters\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nKphDisconnect(\n    VOID\n    );\n\nPHLIBAPI\nBOOLEAN\nNTAPI\nKphIsConnected(\n    VOID\n    );\n\nPHLIBAPI\nBOOLEAN\nNTAPI\nKphIsVerified(\n    VOID\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nKphSetParameters(\n    _In_opt_ PWSTR DeviceName,\n    _In_ PKPH_PARAMETERS Parameters\n    );\n\nPHLIBAPI\nVOID\nNTAPI\nKphSetServiceSecurity(\n    _In_ SC_HANDLE ServiceHandle\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nKphInstall(\n    _In_opt_ PWSTR DeviceName,\n    _In_ PWSTR FileName\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nKphInstallEx(\n    _In_opt_ PWSTR DeviceName,\n    _In_ PWSTR FileName,\n    _In_opt_ PKPH_PARAMETERS Parameters\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nKphUninstall(\n    _In_opt_ PWSTR DeviceName\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nKphGetFeatures(\n    _Out_ PULONG Features\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nKphVerifyClient(\n    _In_reads_bytes_(SignatureSize) PUCHAR Signature,\n    _In_ ULONG SignatureSize\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nKphOpenProcess(\n    _Out_ PHANDLE ProcessHandle,\n    _In_ ACCESS_MASK DesiredAccess,\n    _In_ PCLIENT_ID ClientId\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nKphOpenProcessToken(\n    _In_ HANDLE ProcessHandle,\n    _In_ ACCESS_MASK DesiredAccess,\n    _Out_ PHANDLE TokenHandle\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nKphOpenProcessJob(\n    _In_ HANDLE ProcessHandle,\n    _In_ ACCESS_MASK DesiredAccess,\n    _Out_ PHANDLE JobHandle\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nKphTerminateProcess(\n    _In_ HANDLE ProcessHandle,\n    _In_ NTSTATUS ExitStatus\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nKphReadVirtualMemoryUnsafe(\n    _In_opt_ HANDLE ProcessHandle,\n    _In_ PVOID BaseAddress,\n    _Out_writes_bytes_(BufferSize) PVOID Buffer,\n    _In_ SIZE_T BufferSize,\n    _Out_opt_ PSIZE_T NumberOfBytesRead\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nKphQueryInformationProcess(\n    _In_ HANDLE ProcessHandle,\n    _In_ KPH_PROCESS_INFORMATION_CLASS ProcessInformationClass,\n    _Out_writes_bytes_(ProcessInformationLength) PVOID ProcessInformation,\n    _In_ ULONG ProcessInformationLength,\n    _Out_opt_ PULONG ReturnLength\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nKphSetInformationProcess(\n    _In_ HANDLE ProcessHandle,\n    _In_ KPH_PROCESS_INFORMATION_CLASS ProcessInformationClass,\n    _In_reads_bytes_(ProcessInformationLength) PVOID ProcessInformation,\n    _In_ ULONG ProcessInformationLength\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nKphOpenThread(\n    _Out_ PHANDLE ThreadHandle,\n    _In_ ACCESS_MASK DesiredAccess,\n    _In_ PCLIENT_ID ClientId\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nKphOpenThreadProcess(\n    _In_ HANDLE ThreadHandle,\n    _In_ ACCESS_MASK DesiredAccess,\n    _Out_ PHANDLE ProcessHandle\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nKphCaptureStackBackTraceThread(\n    _In_ HANDLE ThreadHandle,\n    _In_ ULONG FramesToSkip,\n    _In_ ULONG FramesToCapture,\n    _Out_writes_(FramesToCapture) PVOID *BackTrace,\n    _Out_opt_ PULONG CapturedFrames,\n    _Out_opt_ PULONG BackTraceHash\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nKphQueryInformationThread(\n    _In_ HANDLE ThreadHandle,\n    _In_ KPH_THREAD_INFORMATION_CLASS ThreadInformationClass,\n    _Out_writes_bytes_(ThreadInformationLength) PVOID ThreadInformation,\n    _In_ ULONG ThreadInformationLength,\n    _Out_opt_ PULONG ReturnLength\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nKphSetInformationThread(\n    _In_ HANDLE ThreadHandle,\n    _In_ KPH_THREAD_INFORMATION_CLASS ThreadInformationClass,\n    _In_reads_bytes_(ThreadInformationLength) PVOID ThreadInformation,\n    _In_ ULONG ThreadInformationLength\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nKphEnumerateProcessHandles(\n    _In_ HANDLE ProcessHandle,\n    _Out_writes_bytes_(BufferLength) PVOID Buffer,\n    _In_opt_ ULONG BufferLength,\n    _Out_opt_ PULONG ReturnLength\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nKphEnumerateProcessHandles2(\n    _In_ HANDLE ProcessHandle,\n    _Out_ PKPH_PROCESS_HANDLE_INFORMATION *Handles\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nKphQueryInformationObject(\n    _In_ HANDLE ProcessHandle,\n    _In_ HANDLE Handle,\n    _In_ KPH_OBJECT_INFORMATION_CLASS ObjectInformationClass,\n    _Out_writes_bytes_(ObjectInformationLength) PVOID ObjectInformation,\n    _In_ ULONG ObjectInformationLength,\n    _Out_opt_ PULONG ReturnLength\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nKphSetInformationObject(\n    _In_ HANDLE ProcessHandle,\n    _In_ HANDLE Handle,\n    _In_ KPH_OBJECT_INFORMATION_CLASS ObjectInformationClass,\n    _In_reads_bytes_(ObjectInformationLength) PVOID ObjectInformation,\n    _In_ ULONG ObjectInformationLength\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nKphOpenDriver(\n    _Out_ PHANDLE DriverHandle,\n    _In_ ACCESS_MASK DesiredAccess,\n    _In_ POBJECT_ATTRIBUTES ObjectAttributes\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nKphQueryInformationDriver(\n    _In_ HANDLE DriverHandle,\n    _In_ DRIVER_INFORMATION_CLASS DriverInformationClass,\n    _Out_writes_bytes_(DriverInformationLength) PVOID DriverInformation,\n    _In_ ULONG DriverInformationLength,\n    _Out_opt_ PULONG ReturnLength\n    );\n\n// kphdata\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nKphInitializeDynamicPackage(\n    _Out_ PKPH_DYN_PACKAGE Package\n    );\n\n#ifdef __cplusplus\n}\n#endif\n\n#endif\n"
  },
  {
    "path": "third_party/phlib/include/kphuserp.h",
    "content": "#ifndef _PH_KPHUSERP_H\n#define _PH_KPHUSERP_H\n\ntypedef NTSTATUS (NTAPI *PKPHP_WITH_KEY_CONTINUATION)(\n    _In_ KPH_KEY Key,\n    _In_ PVOID Context\n    );\n\nNTSTATUS KphpDeviceIoControl(\n    _In_ ULONG KphControlCode,\n    _In_ PVOID InBuffer,\n    _In_ ULONG InBufferLength\n    );\n\ntypedef struct _KPHP_RETRIEVE_KEY_CONTEXT\n{\n    IO_STATUS_BLOCK Iosb;\n    PKPHP_WITH_KEY_CONTINUATION Continuation;\n    PVOID Context;\n    NTSTATUS Status;\n} KPHP_RETRIEVE_KEY_CONTEXT, *PKPHP_RETRIEVE_KEY_CONTEXT;\n\nVOID KphpWithKeyApcRoutine(\n    _In_ PVOID ApcContext,\n    _In_ PIO_STATUS_BLOCK IoStatusBlock,\n    _In_ ULONG Reserved\n    );\n\nNTSTATUS KphpWithKey(\n    _In_ KPH_KEY_LEVEL KeyLevel,\n    _In_ PKPHP_WITH_KEY_CONTINUATION Continuation,\n    _In_ PVOID Context\n    );\n\n// Get L1 key\n\ntypedef struct _KPHP_GET_L1_KEY_CONTEXT\n{\n    PKPH_KEY Key;\n} KPHP_GET_L1_KEY_CONTEXT, *PKPHP_GET_L1_KEY_CONTEXT;\n\nNTSTATUS KphpGetL1KeyContinuation(\n    _In_ KPH_KEY Key,\n    _In_ PVOID Context\n    );\n\nNTSTATUS KphpGetL1Key(\n    _Out_ PKPH_KEY Key\n    );\n\n// Open process\n\ntypedef struct _KPH_OPEN_PROCESS_INPUT\n{\n    PHANDLE ProcessHandle;\n    ACCESS_MASK DesiredAccess;\n    PCLIENT_ID ClientId;\n    KPH_KEY Key;\n} KPH_OPEN_PROCESS_INPUT, *PKPH_OPEN_PROCESS_INPUT;\n\nNTSTATUS KphpOpenProcessContinuation(\n    _In_ KPH_KEY Key,\n    _In_ PVOID Context\n    );\n\n// Open process token\n\ntypedef struct _KPH_OPEN_PROCESS_TOKEN_INPUT\n{\n    HANDLE ProcessHandle;\n    ACCESS_MASK DesiredAccess;\n    PHANDLE TokenHandle;\n    KPH_KEY Key;\n} KPH_OPEN_PROCESS_TOKEN_INPUT, *PKPH_OPEN_PROCESS_TOKEN_INPUT;\n\nNTSTATUS KphpOpenProcessTokenContinuation(\n    _In_ KPH_KEY Key,\n    _In_ PVOID Context\n    );\n\n// Terminate process\n\ntypedef struct _KPH_TERMINATE_PROCESS_INPUT\n{\n    HANDLE ProcessHandle;\n    NTSTATUS ExitStatus;\n    KPH_KEY Key;\n} KPH_TERMINATE_PROCESS_INPUT, *PKPH_TERMINATE_PROCESS_INPUT;\n\nNTSTATUS KphpTerminateProcessContinuation(\n    _In_ KPH_KEY Key,\n    _In_ PVOID Context\n    );\n\n// Read virtual memory, unsafe\n\ntypedef struct _KPH_READ_VIRTUAL_MEMORY_UNSAFE_INPUT\n{\n    HANDLE ProcessHandle;\n    PVOID BaseAddress;\n    PVOID Buffer;\n    SIZE_T BufferSize;\n    PSIZE_T NumberOfBytesRead;\n    KPH_KEY Key;\n} KPH_READ_VIRTUAL_MEMORY_UNSAFE_INPUT, *PKPH_READ_VIRTUAL_MEMORY_UNSAFE_INPUT;\n\nNTSTATUS KphpReadVirtualMemoryUnsafeContinuation(\n    _In_ KPH_KEY Key,\n    _In_ PVOID Context\n    );\n\n// Open thread\n\ntypedef struct _KPH_OPEN_THREAD_INPUT\n{\n    PHANDLE ThreadHandle;\n    ACCESS_MASK DesiredAccess;\n    PCLIENT_ID ClientId;\n    KPH_KEY Key;\n} KPH_OPEN_THREAD_INPUT, *PKPH_OPEN_THREAD_INPUT;\n\nNTSTATUS KphpOpenThreadContinuation(\n    _In_ KPH_KEY Key,\n    _In_ PVOID Context\n    );\n\n#endif\n"
  },
  {
    "path": "third_party/phlib/include/lsasup.h",
    "content": "#ifndef _PH_LSASUP_H\n#define _PH_LSASUP_H\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhOpenLsaPolicy(\n    _Out_ PLSA_HANDLE PolicyHandle,\n    _In_ ACCESS_MASK DesiredAccess,\n    _In_opt_ PUNICODE_STRING SystemName\n    );\n\nPHLIBAPI\nLSA_HANDLE\nNTAPI\nPhGetLookupPolicyHandle(\n    VOID\n    );\n\nPHLIBAPI\nBOOLEAN\nNTAPI\nPhLookupPrivilegeName(\n    _In_ PLUID PrivilegeValue,\n    _Out_ PPH_STRING *PrivilegeName\n    );\n\nPHLIBAPI\nBOOLEAN\nNTAPI\nPhLookupPrivilegeDisplayName(\n    _In_ PPH_STRINGREF PrivilegeName,\n    _Out_ PPH_STRING *PrivilegeDisplayName\n    );\n\nPHLIBAPI\nBOOLEAN\nNTAPI\nPhLookupPrivilegeValue(\n    _In_ PPH_STRINGREF PrivilegeName,\n    _Out_ PLUID PrivilegeValue\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhLookupSid(\n    _In_ PSID Sid,\n    _Out_opt_ PPH_STRING *Name,\n    _Out_opt_ PPH_STRING *DomainName,\n    _Out_opt_ PSID_NAME_USE NameUse\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhLookupName(\n    _In_ PPH_STRINGREF Name,\n    _Out_opt_ PSID *Sid,\n    _Out_opt_ PPH_STRING *DomainName,\n    _Out_opt_ PSID_NAME_USE NameUse\n    );\n\nPHLIBAPI\nPPH_STRING\nNTAPI\nPhGetSidFullName(\n    _In_ PSID Sid,\n    _In_ BOOLEAN IncludeDomain,\n    _Out_opt_ PSID_NAME_USE NameUse\n    );\n\nPHLIBAPI\nPPH_STRING\nNTAPI\nPhSidToStringSid(\n    _In_ PSID Sid\n    );\n\n#ifdef __cplusplus\n}\n#endif\n\n#endif\n"
  },
  {
    "path": "third_party/phlib/include/mapimg.h",
    "content": "#ifndef _PH_MAPIMG_H\n#define _PH_MAPIMG_H\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\n#include <exlf.h>\n\ntypedef struct _PH_MAPPED_IMAGE\n{\n    USHORT Signature;\n    PVOID ViewBase;\n    SIZE_T Size;\n\n    union \n    {\n        struct \n        {\n            union \n            {\n                PIMAGE_NT_HEADERS32 NtHeaders32;\n                PIMAGE_NT_HEADERS NtHeaders;\n            };\n\n            ULONG NumberOfSections;\n            PIMAGE_SECTION_HEADER Sections;\n            USHORT Magic;\n        };\n        struct\n        {\n            struct _ELF_IMAGE_HEADER *Header;\n            union \n            {\n                struct _ELF_IMAGE_HEADER32 *Headers32;\n                struct _ELF_IMAGE_HEADER64 *Headers64;\n            };\n        };\n    };\n} PH_MAPPED_IMAGE, *PPH_MAPPED_IMAGE;\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhInitializeMappedImage(\n    _Out_ PPH_MAPPED_IMAGE MappedImage,\n    _In_ PVOID ViewBase,\n    _In_ SIZE_T Size\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhLoadMappedImage(\n    _In_opt_ PWSTR FileName,\n    _In_opt_ HANDLE FileHandle,\n    _In_ BOOLEAN ReadOnly,\n    _Out_ PPH_MAPPED_IMAGE MappedImage\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhLoadMappedImageEx(\n    _In_opt_ PWSTR FileName,\n    _In_opt_ HANDLE FileHandle,\n    _In_ BOOLEAN ReadOnly,\n    _Out_ PPH_MAPPED_IMAGE MappedImage\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhUnloadMappedImage(\n    _Inout_ PPH_MAPPED_IMAGE MappedImage\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhMapViewOfEntireFile(\n    _In_opt_ PWSTR FileName,\n    _In_opt_ HANDLE FileHandle,\n    _In_ BOOLEAN ReadOnly,\n    _Out_ PVOID *ViewBase,\n    _Out_ PSIZE_T Size\n    );\n\nPHLIBAPI\nPIMAGE_SECTION_HEADER\nNTAPI\nPhMappedImageRvaToSection(\n    _In_ PPH_MAPPED_IMAGE MappedImage,\n    _In_ ULONG Rva\n    );\n\nPHLIBAPI\nPVOID\nNTAPI\nPhMappedImageRvaToVa(\n    _In_ PPH_MAPPED_IMAGE MappedImage,\n    _In_ ULONG Rva,\n    _Out_opt_ PIMAGE_SECTION_HEADER *Section\n    );\n\nPHLIBAPI\nBOOLEAN\nNTAPI\nPhGetMappedImageSectionName(\n    _In_ PIMAGE_SECTION_HEADER Section,\n    _Out_writes_opt_z_(Count) PWSTR Buffer,\n    _In_ ULONG Count,\n    _Out_opt_ PULONG ReturnCount\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhGetMappedImageDataEntry(\n    _In_ PPH_MAPPED_IMAGE MappedImage,\n    _In_ ULONG Index,\n    _Out_ PIMAGE_DATA_DIRECTORY *Entry\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhGetMappedImageLoadConfig32(\n    _In_ PPH_MAPPED_IMAGE MappedImage,\n    _Out_ PIMAGE_LOAD_CONFIG_DIRECTORY32 *LoadConfig\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhGetMappedImageLoadConfig64(\n    _In_ PPH_MAPPED_IMAGE MappedImage,\n    _Out_ PIMAGE_LOAD_CONFIG_DIRECTORY64 *LoadConfig\n    );\n\ntypedef struct _PH_REMOTE_MAPPED_IMAGE\n{\n    PVOID ViewBase;\n\n    PIMAGE_NT_HEADERS NtHeaders;\n    ULONG NumberOfSections;\n    PIMAGE_SECTION_HEADER Sections;\n    USHORT Magic;\n} PH_REMOTE_MAPPED_IMAGE, *PPH_REMOTE_MAPPED_IMAGE;\n\nNTSTATUS\nNTAPI\nPhLoadRemoteMappedImage(\n    _In_ HANDLE ProcessHandle,\n    _In_ PVOID ViewBase,\n    _Out_ PPH_REMOTE_MAPPED_IMAGE RemoteMappedImage\n    );\n\nNTSTATUS\nNTAPI\nPhUnloadRemoteMappedImage(\n    _Inout_ PPH_REMOTE_MAPPED_IMAGE RemoteMappedImage\n    );\n\ntypedef struct _PH_MAPPED_IMAGE_EXPORTS\n{\n    PPH_MAPPED_IMAGE MappedImage;\n    ULONG NumberOfEntries;\n\n    PIMAGE_DATA_DIRECTORY DataDirectory;\n    PIMAGE_EXPORT_DIRECTORY ExportDirectory;\n    PULONG AddressTable;\n    PULONG NamePointerTable;\n    PUSHORT OrdinalTable;\n} PH_MAPPED_IMAGE_EXPORTS, *PPH_MAPPED_IMAGE_EXPORTS;\n\ntypedef struct _PH_MAPPED_IMAGE_EXPORT_ENTRY\n{\n    USHORT Ordinal;\n    PSTR Name;\n} PH_MAPPED_IMAGE_EXPORT_ENTRY, *PPH_MAPPED_IMAGE_EXPORT_ENTRY;\n\ntypedef struct _PH_MAPPED_IMAGE_EXPORT_FUNCTION\n{\n    PVOID Function;\n    PSTR ForwardedName;\n} PH_MAPPED_IMAGE_EXPORT_FUNCTION, *PPH_MAPPED_IMAGE_EXPORT_FUNCTION;\n\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhGetMappedImageExports(\n    _Out_ PPH_MAPPED_IMAGE_EXPORTS Exports,\n    _In_ PPH_MAPPED_IMAGE MappedImage\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhGetMappedImageExportEntry(\n    _In_ PPH_MAPPED_IMAGE_EXPORTS Exports,\n    _In_ ULONG Index,\n    _Out_ PPH_MAPPED_IMAGE_EXPORT_ENTRY Entry\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhGetMappedImageExportFunction(\n    _In_ PPH_MAPPED_IMAGE_EXPORTS Exports,\n    _In_opt_ PSTR Name,\n    _In_opt_ USHORT Ordinal,\n    _Out_ PPH_MAPPED_IMAGE_EXPORT_FUNCTION Function\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhGetMappedImageExportFunctionRemote(\n    _In_ PPH_MAPPED_IMAGE_EXPORTS Exports,\n    _In_opt_ PSTR Name,\n    _In_opt_ USHORT Ordinal,\n    _In_ PVOID RemoteBase,\n    _Out_ PVOID *Function\n    );\n\n#define PH_MAPPED_IMAGE_DELAY_IMPORTS 0x1\n#define PH_MAPPED_IMAGE_DELAY_IMPORTS_V1 0x2\n\ntypedef struct _PH_MAPPED_IMAGE_IMPORTS\n{\n    PPH_MAPPED_IMAGE MappedImage;\n    ULONG Flags;\n    ULONG NumberOfDlls;\n\n    union\n    {\n        PIMAGE_IMPORT_DESCRIPTOR DescriptorTable;\n        PIMAGE_DELAYLOAD_DESCRIPTOR DelayDescriptorTable;\n    };\n} PH_MAPPED_IMAGE_IMPORTS, *PPH_MAPPED_IMAGE_IMPORTS;\n\ntypedef struct _PH_MAPPED_IMAGE_IMPORT_DLL\n{\n    PPH_MAPPED_IMAGE MappedImage;\n    ULONG Flags;\n    PSTR Name;\n    ULONG NumberOfEntries;\n\n    union\n    {\n        PIMAGE_IMPORT_DESCRIPTOR Descriptor;\n        PIMAGE_DELAYLOAD_DESCRIPTOR DelayDescriptor;\n    };\n    PVOID LookupTable;\n} PH_MAPPED_IMAGE_IMPORT_DLL, *PPH_MAPPED_IMAGE_IMPORT_DLL;\n\ntypedef struct _PH_MAPPED_IMAGE_IMPORT_ENTRY\n{\n    PSTR Name;\n    union\n    {\n        USHORT Ordinal;\n        USHORT NameHint;\n    };\n} PH_MAPPED_IMAGE_IMPORT_ENTRY, *PPH_MAPPED_IMAGE_IMPORT_ENTRY;\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhGetMappedImageImports(\n    _Out_ PPH_MAPPED_IMAGE_IMPORTS Imports,\n    _In_ PPH_MAPPED_IMAGE MappedImage\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhGetMappedImageImportDll(\n    _In_ PPH_MAPPED_IMAGE_IMPORTS Imports,\n    _In_ ULONG Index,\n    _Out_ PPH_MAPPED_IMAGE_IMPORT_DLL ImportDll\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhGetMappedImageImportEntry(\n    _In_ PPH_MAPPED_IMAGE_IMPORT_DLL ImportDll,\n    _In_ ULONG Index,\n    _Out_ PPH_MAPPED_IMAGE_IMPORT_ENTRY Entry\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhGetMappedImageDelayImports(\n    _Out_ PPH_MAPPED_IMAGE_IMPORTS Imports,\n    _In_ PPH_MAPPED_IMAGE MappedImage\n    );\n\nUSHORT\nNTAPI\nPhCheckSum(\n    _In_ ULONG Sum,\n    _In_reads_(Count) PUSHORT Buffer,\n    _In_ ULONG Count\n    );\n\nPHLIBAPI\nULONG\nNTAPI\nPhCheckSumMappedImage(\n    _In_ PPH_MAPPED_IMAGE MappedImage\n    );\n\ntypedef struct _IMAGE_CFG_ENTRY\n{\n    ULONG Rva;\n    struct\n    {\n        BOOLEAN SuppressedCall : 1;\n        BOOLEAN Reserved : 7;\n    };\n} IMAGE_CFG_ENTRY, *PIMAGE_CFG_ENTRY;\n\ntypedef struct _PH_MAPPED_IMAGE_CFG\n{\n    PPH_MAPPED_IMAGE MappedImage;\n    ULONG EntrySize;\n\n    union\n    {\n        ULONG GuardFlags;\n        struct\n        {\n            ULONG CfgInstrumented : 1;\n            ULONG WriteIntegrityChecks : 1;\n            ULONG CfgFunctionTablePresent : 1;\n            ULONG SecurityCookieUnused : 1;\n            ULONG ProtectDelayLoadedIat : 1;\n            ULONG DelayLoadInDidatSection : 1;\n            ULONG HasExportSuppressionInfos : 1;\n            ULONG EnableExportSuppression : 1;\n            ULONG CfgLongJumpTablePresent : 1;\n            ULONG Spare : 23;\n        };\n    };\n\n    PULONGLONG GuardFunctionTable;\n    ULONGLONG NumberOfGuardFunctionEntries;\n\n    PULONGLONG GuardAdressIatTable; // not currently used\n    ULONGLONG NumberOfGuardAdressIatEntries;\n\n    PULONGLONG GuardLongJumpTable; // not currently used\n    ULONGLONG NumberOfGuardLongJumpEntries;\n} PH_MAPPED_IMAGE_CFG, *PPH_MAPPED_IMAGE_CFG;\n\ntypedef enum _CFG_ENTRY_TYPE\n{\n    ControlFlowGuardFunction,\n    ControlFlowGuardtakenIatEntry,\n    ControlFlowGuardLongJump\n} CFG_ENTRY_TYPE;\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhGetMappedImageCfg(\n    _Out_ PPH_MAPPED_IMAGE_CFG CfgConfig,\n    _In_ PPH_MAPPED_IMAGE MappedImage\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhGetMappedImageCfgEntry(\n    _In_ PPH_MAPPED_IMAGE_CFG CfgConfig,\n    _In_ ULONGLONG Index,\n    _In_ CFG_ENTRY_TYPE Type,\n    _Out_ PIMAGE_CFG_ENTRY Entry\n    );\n\ntypedef struct _PH_IMAGE_RESOURCE_ENTRY\n{\n    ULONG_PTR Type;\n    ULONG_PTR Name;\n    ULONG_PTR Language;\n    ULONG Size;\n    PVOID Data;\n} PH_IMAGE_RESOURCE_ENTRY, *PPH_IMAGE_RESOURCE_ENTRY;\n\ntypedef struct _PH_MAPPED_IMAGE_RESOURCES\n{\n    PPH_MAPPED_IMAGE MappedImage;\n    PIMAGE_DATA_DIRECTORY DataDirectory;\n    PIMAGE_RESOURCE_DIRECTORY ResourceDirectory;\n\n    ULONG NumberOfEntries;\n    PPH_IMAGE_RESOURCE_ENTRY ResourceEntries;\n} PH_MAPPED_IMAGE_RESOURCES, *PPH_MAPPED_IMAGE_RESOURCES;\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhGetMappedImageResources(\n    _Out_ PPH_MAPPED_IMAGE_RESOURCES Resources,\n    _In_ PPH_MAPPED_IMAGE MappedImage\n    );\n\n// maplib\n\nstruct _PH_MAPPED_ARCHIVE;\ntypedef struct _PH_MAPPED_ARCHIVE *PPH_MAPPED_ARCHIVE;\n\ntypedef enum _PH_MAPPED_ARCHIVE_MEMBER_TYPE\n{\n    NormalArchiveMemberType,\n    LinkerArchiveMemberType,\n    LongnamesArchiveMemberType\n} PH_MAPPED_ARCHIVE_MEMBER_TYPE;\n\ntypedef struct _PH_MAPPED_ARCHIVE_MEMBER\n{\n    PPH_MAPPED_ARCHIVE MappedArchive;\n    PH_MAPPED_ARCHIVE_MEMBER_TYPE Type;\n    PSTR Name;\n    ULONG Size;\n    PVOID Data;\n\n    PIMAGE_ARCHIVE_MEMBER_HEADER Header;\n    CHAR NameBuffer[20];\n} PH_MAPPED_ARCHIVE_MEMBER, *PPH_MAPPED_ARCHIVE_MEMBER;\n\ntypedef struct _PH_MAPPED_ARCHIVE\n{\n    PVOID ViewBase;\n    SIZE_T Size;\n\n    PH_MAPPED_ARCHIVE_MEMBER FirstLinkerMember;\n    PH_MAPPED_ARCHIVE_MEMBER SecondLinkerMember;\n    PH_MAPPED_ARCHIVE_MEMBER LongnamesMember;\n    BOOLEAN HasLongnamesMember;\n\n    PPH_MAPPED_ARCHIVE_MEMBER FirstStandardMember;\n    PPH_MAPPED_ARCHIVE_MEMBER LastStandardMember;\n} PH_MAPPED_ARCHIVE, *PPH_MAPPED_ARCHIVE;\n\ntypedef struct _PH_MAPPED_ARCHIVE_IMPORT_ENTRY\n{\n    PSTR Name;\n    PSTR DllName;\n    union\n    {\n        USHORT Ordinal;\n        USHORT NameHint;\n    };\n    BYTE Type;\n    BYTE NameType;\n    USHORT Machine;\n} PH_MAPPED_ARCHIVE_IMPORT_ENTRY, *PPH_MAPPED_ARCHIVE_IMPORT_ENTRY;\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhInitializeMappedArchive(\n    _Out_ PPH_MAPPED_ARCHIVE MappedArchive,\n    _In_ PVOID ViewBase,\n    _In_ SIZE_T Size\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhLoadMappedArchive(\n    _In_opt_ PWSTR FileName,\n    _In_opt_ HANDLE FileHandle,\n    _In_ BOOLEAN ReadOnly,\n    _Out_ PPH_MAPPED_ARCHIVE MappedArchive\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhUnloadMappedArchive(\n    _Inout_ PPH_MAPPED_ARCHIVE MappedArchive\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhGetNextMappedArchiveMember(\n    _In_ PPH_MAPPED_ARCHIVE_MEMBER Member,\n    _Out_ PPH_MAPPED_ARCHIVE_MEMBER NextMember\n    );\n\nPHLIBAPI\nBOOLEAN\nNTAPI\nPhIsMappedArchiveMemberShortFormat(\n    _In_ PPH_MAPPED_ARCHIVE_MEMBER Member\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhGetMappedArchiveImportEntry(\n    _In_ PPH_MAPPED_ARCHIVE_MEMBER Member,\n    _Out_ PPH_MAPPED_ARCHIVE_IMPORT_ENTRY Entry\n    );\n\n// ELF binary support\n\nNTSTATUS PhInitializeMappedWslImage(\n    _Out_ PPH_MAPPED_IMAGE MappedWslImage,\n    _In_ PVOID ViewBase,\n    _In_ SIZE_T Size\n    );\n\nULONG64 PhGetMappedWslImageBaseAddress(\n    _In_ PPH_MAPPED_IMAGE MappedWslImage\n    );\n\ntypedef struct _PH_ELF_IMAGE_SECTION\n{\n    UINT32 Type;\n    ULONGLONG Flags;\n    ULONGLONG Address;\n    ULONGLONG Offset;\n    ULONGLONG Size;\n    WCHAR Name[MAX_PATH];\n} PH_ELF_IMAGE_SECTION, *PPH_ELF_IMAGE_SECTION;\n\nBOOLEAN PhGetMappedWslImageSections(\n    _In_ PPH_MAPPED_IMAGE MappedWslImage,\n    _Out_ USHORT *NumberOfSections,\n    _Out_ PPH_ELF_IMAGE_SECTION *ImageSections\n    );\n\ntypedef struct _PH_ELF_IMAGE_SYMBOL_ENTRY\n{\n    union\n    {\n        BOOLEAN Flags;\n        struct\n        {\n            BOOLEAN ImportSymbol : 1;\n            BOOLEAN ExportSymbol : 1;\n            BOOLEAN UnknownSymbol : 1;\n            BOOLEAN Spare : 5;\n        };\n    };\n    UCHAR TypeInfo;\n    ULONGLONG Address;\n    ULONGLONG Size;\n    WCHAR Name[0x80];\n    WCHAR Module[0x80];\n} PH_ELF_IMAGE_SYMBOL_ENTRY, *PPH_ELF_IMAGE_SYMBOL_ENTRY;\n\nBOOLEAN PhGetMappedWslImageSymbols(\n    _In_ PPH_MAPPED_IMAGE MappedWslImage,\n    _Out_ PPH_LIST *ImageSymbols\n    );\n\nVOID PhFreeMappedWslImageSymbols(\n    _In_ PPH_LIST ImageSymbols\n    );\n\n#ifdef __cplusplus\n}\n#endif\n\n#endif\n"
  },
  {
    "path": "third_party/phlib/include/ph.h",
    "content": "#ifndef _PH_PH_H\n#define _PH_PH_H\n\n#pragma once\n\n#include <phbase.h>\n#include <phnative.h>\n#include <phnativeinl.h>\n#include <phutil.h>\n\n#endif\n"
  },
  {
    "path": "third_party/phlib/include/phbase.h",
    "content": "#ifndef _PH_PHBASE_H\n#define _PH_PHBASE_H\n\n#pragma once\n\n#ifndef PHLIB_NO_DEFAULT_LIB\n#pragma comment(lib, \"ntdll.lib\")\n#pragma comment(lib, \"comctl32.lib\")\n#pragma comment(lib, \"version.lib\")\n#endif\n\n#ifndef UNICODE\n#define UNICODE\n#endif\n\n#ifndef _CRT_SECURE_NO_WARNINGS\n#define _CRT_SECURE_NO_WARNINGS\n#endif\n\n#if defined(_PHLIB_)\n#define PHLIBAPI\n#elif defined(_PHDLL_)\n#define PHLIBAPI __declspec(dllexport)\n#else\n#if defined(__cplusplus)\n#define PHLIBAPI __declspec(dllimport)\n#else\n#define PHLIBAPI \n#endif //  defined(__cplusplus)\n#endif //  defined(_PHLIB_)\n\n#include <phnt_windows.h>\n#include <phnt.h>\n#include <phsup.h>\n#include <ref.h>\n#include <queuedlock.h>\n#include <stdlib.h>\n\n#include <phconfig.h>\n#include <phbasesup.h>\n#include <phdata.h>\n\n#endif"
  },
  {
    "path": "third_party/phlib/include/phbasesup.h",
    "content": "#ifndef _PH_PHBASESUP_H\n#define _PH_PHBASESUP_H\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\nBOOLEAN\nPhBaseInitialization(\n    VOID\n    );\n\n// Threads\n\n#ifdef DEBUG\nstruct _PH_AUTO_POOL;\ntypedef struct _PH_AUTO_POOL *PPH_AUTO_POOL;\n\ntypedef struct _PHP_BASE_THREAD_DBG\n{\n    CLIENT_ID ClientId;\n    LIST_ENTRY ListEntry;\n    PVOID StartAddress;\n    PVOID Parameter;\n\n    PPH_AUTO_POOL CurrentAutoPool;\n} PHP_BASE_THREAD_DBG, *PPHP_BASE_THREAD_DBG;\n\nextern ULONG PhDbgThreadDbgTlsIndex;\nextern LIST_ENTRY PhDbgThreadListHead;\nextern PH_QUEUED_LOCK PhDbgThreadListLock;\n#endif\n\nPHLIBAPI\nHANDLE\nNTAPI\nPhCreateThread(\n    _In_opt_ SIZE_T StackSize,\n    _In_ PUSER_THREAD_START_ROUTINE StartAddress,\n    _In_opt_ PVOID Parameter\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhCreateThread2(\n    _In_ PUSER_THREAD_START_ROUTINE StartAddress,\n    _In_opt_ PVOID Parameter\n    );\n\n// DLLs\n\nFORCEINLINE\nPVOID\nPhGetDllHandle(\n    _In_ PWSTR DllName\n    )\n{\n    UNICODE_STRING dllName;\n    PVOID dllHandle;\n\n    RtlInitUnicodeString(&dllName, DllName);\n\n    if (NT_SUCCESS(LdrGetDllHandle(NULL, NULL, &dllName, &dllHandle)))\n        return dllHandle;\n    else\n        return NULL;\n}\n\nFORCEINLINE\nPVOID\nPhGetProcedureAddress(\n    _In_ PVOID DllHandle,\n    _In_opt_ PSTR ProcedureName,\n    _In_opt_ ULONG ProcedureNumber\n    )\n{\n    NTSTATUS status;\n    ANSI_STRING procedureName;\n    PVOID procedureAddress;\n\n    if (ProcedureName)\n    {\n        RtlInitAnsiString(&procedureName, ProcedureName);\n        status = LdrGetProcedureAddress(\n            DllHandle,\n            &procedureName,\n            0,\n            &procedureAddress\n            );\n    }\n    else\n    {\n        status = LdrGetProcedureAddress(\n            DllHandle,\n            NULL,\n            ProcedureNumber,\n            &procedureAddress\n            );\n    }\n\n    if (!NT_SUCCESS(status))\n        return NULL;\n\n    return procedureAddress;\n}\n\nFORCEINLINE\nPVOID\nPhGetModuleProcAddress(\n    _In_ PWSTR ModuleName,\n    _In_ PSTR ProcName\n    )\n{\n    PVOID module;\n\n    module = (HMODULE) PhGetDllHandle(ModuleName);\n\n    if (module)\n        return PhGetProcedureAddress(module, ProcName, 0);\n    else\n        return NULL;\n}\n\n// Misc. system\n\nPHLIBAPI\nVOID\nNTAPI\nPhQuerySystemTime(\n    _Out_ PLARGE_INTEGER SystemTime\n    );\n\nPHLIBAPI\nVOID\nNTAPI\nPhQueryTimeZoneBias(\n    _Out_ PLARGE_INTEGER TimeZoneBias\n    );\n\nPHLIBAPI\nVOID\nNTAPI\nPhSystemTimeToLocalTime(\n    _In_ PLARGE_INTEGER SystemTime,\n    _Out_ PLARGE_INTEGER LocalTime\n    );\n\nPHLIBAPI\nVOID\nNTAPI\nPhLocalTimeToSystemTime(\n    _In_ PLARGE_INTEGER LocalTime,\n    _Out_ PLARGE_INTEGER SystemTime\n    );\n\n// Heap\n\n_May_raise_\n_Check_return_\n_Ret_notnull_\n_Post_writable_byte_size_(Size)\nPHLIBAPI\nPVOID\nNTAPI\nPhAllocate(\n    _In_ SIZE_T Size\n    );\n\nPHLIBAPI\nPVOID\nNTAPI\nPhAllocateSafe(\n    _In_ SIZE_T Size\n    );\n\nPHLIBAPI\nPVOID\nNTAPI\nPhAllocateExSafe(\n    _In_ SIZE_T Size,\n    _In_ ULONG Flags\n    );\n\nPHLIBAPI\nVOID\nNTAPI\nPhFree(\n    _Frees_ptr_opt_ PVOID Memory\n    );\n\n_May_raise_\n_Post_writable_byte_size_(Size)\nPHLIBAPI\nPVOID\nNTAPI\nPhReAllocate(\n    _Frees_ptr_ PVOID Memory,\n    _In_ SIZE_T Size\n    );\n\nPHLIBAPI\nPVOID\nNTAPI\nPhReAllocateSafe(\n    _In_ PVOID Memory,\n    _In_ SIZE_T Size\n    );\n\n_Check_return_\n_Ret_maybenull_\nPHLIBAPI\nPVOID\nNTAPI\nPhAllocatePage(\n    _In_ SIZE_T Size,\n    _Out_opt_ PSIZE_T NewSize\n    );\n\nPHLIBAPI\nVOID\nNTAPI\nPhFreePage(\n    _Frees_ptr_opt_ PVOID Memory\n    );\n\nFORCEINLINE\nPVOID\nPhAllocateCopy(\n    _In_ PVOID Data,\n    _In_ SIZE_T Size\n    )\n{\n    PVOID copy;\n\n    copy = PhAllocate(Size);\n    memcpy(copy, Data, Size);\n\n    return copy;\n}\n\n// Event\n\n#define PH_EVENT_SET 0x1\n#define PH_EVENT_SET_SHIFT 0\n#define PH_EVENT_REFCOUNT_SHIFT 1\n#define PH_EVENT_REFCOUNT_INC 0x2\n#define PH_EVENT_REFCOUNT_MASK (((ULONG_PTR)1 << 15) - 1)\n\n/**\n * A fast event object.\n *\n * \\remarks This event object does not use a kernel event object until necessary, and frees the\n * object automatically when it is no longer needed.\n */\ntypedef struct _PH_EVENT\n{\n    union\n    {\n        ULONG_PTR Value;\n        struct\n        {\n            USHORT Set : 1;\n            USHORT RefCount : 15;\n            UCHAR Reserved;\n            UCHAR AvailableForUse;\n#ifdef _WIN64\n            ULONG Spare;\n#endif\n        };\n    };\n    HANDLE EventHandle;\n} PH_EVENT, *PPH_EVENT;\n\nC_ASSERT(sizeof(PH_EVENT) == sizeof(ULONG_PTR) + sizeof(HANDLE));\n\n#define PH_EVENT_INIT { { PH_EVENT_REFCOUNT_INC }, NULL }\n\nPHLIBAPI\nVOID\nFASTCALL\nPhfInitializeEvent(\n    _Out_ PPH_EVENT Event\n    );\n\n#define PhSetEvent PhfSetEvent\nPHLIBAPI\nVOID\nFASTCALL\nPhfSetEvent(\n    _Inout_ PPH_EVENT Event\n    );\n\nPHLIBAPI\nBOOLEAN\nFASTCALL\nPhfWaitForEvent(\n    _Inout_ PPH_EVENT Event,\n    _In_opt_ PLARGE_INTEGER Timeout\n    );\n\nFORCEINLINE\nBOOLEAN\nPhWaitForEvent(\n    _Inout_ PPH_EVENT Event,\n    _In_opt_ PLARGE_INTEGER Timeout\n    )\n{\n    if (Event->Set)\n        return TRUE;\n\n    return PhfWaitForEvent(Event, Timeout);\n}\n\n#define PhResetEvent PhfResetEvent\nPHLIBAPI\nVOID\nFASTCALL\nPhfResetEvent(\n    _Inout_ PPH_EVENT Event\n    );\n\nFORCEINLINE\nVOID\nPhInitializeEvent(\n    _Out_ PPH_EVENT Event\n    )\n{\n    Event->Value = PH_EVENT_REFCOUNT_INC;\n    Event->EventHandle = NULL;\n}\n\n/**\n * Determines whether an event object is set.\n *\n * \\param Event A pointer to an event object.\n *\n * \\return TRUE if the event object is set, otherwise FALSE.\n */\nFORCEINLINE\nBOOLEAN\nPhTestEvent(\n    _In_ PPH_EVENT Event\n    )\n{\n    return (BOOLEAN)Event->Set;\n}\n\n// Barrier\n\n#define PH_BARRIER_COUNT_SHIFT 0\n#define PH_BARRIER_COUNT_MASK (((LONG_PTR)1 << (sizeof(ULONG_PTR) * 8 / 2 - 1)) - 1)\n#define PH_BARRIER_COUNT_INC ((LONG_PTR)1 << PH_BARRIER_COUNT_SHIFT)\n#define PH_BARRIER_TARGET_SHIFT (sizeof(ULONG_PTR) * 8 / 2)\n#define PH_BARRIER_TARGET_MASK (((LONG_PTR)1 << (sizeof(ULONG_PTR) * 8 / 2 - 1)) - 1)\n#define PH_BARRIER_TARGET_INC ((LONG_PTR)1 << PH_BARRIER_TARGET_SHIFT)\n#define PH_BARRIER_WAKING ((LONG_PTR)1 << (sizeof(ULONG_PTR) * 8 - 1))\n\n#define PH_BARRIER_MASTER 1\n#define PH_BARRIER_SLAVE 2\n#define PH_BARRIER_OBSERVER 3\n\ntypedef struct _PH_BARRIER\n{\n    ULONG_PTR Value;\n    PH_WAKE_EVENT WakeEvent;\n} PH_BARRIER, *PPH_BARRIER;\n\n#define PH_BARRIER_INIT(Target) { (ULONG_PTR)(Target) << PH_BARRIER_TARGET_SHIFT, PH_WAKE_EVENT_INIT }\n\nPHLIBAPI\nVOID\nFASTCALL\nPhfInitializeBarrier(\n    _Out_ PPH_BARRIER Barrier,\n    _In_ ULONG_PTR Target\n    );\n\n#define PhWaitForBarrier PhfWaitForBarrier\nPHLIBAPI\nBOOLEAN\nFASTCALL\nPhfWaitForBarrier(\n    _Inout_ PPH_BARRIER Barrier,\n    _In_ BOOLEAN Spin\n    );\n\nFORCEINLINE\nVOID\nPhInitializeBarrier(\n    _Out_ PPH_BARRIER Barrier,\n    _In_ ULONG_PTR Target\n    )\n{\n    Barrier->Value = Target << PH_BARRIER_TARGET_SHIFT;\n    PhInitializeQueuedLock(&Barrier->WakeEvent);\n}\n\n// Rundown protection\n\n#define PH_RUNDOWN_ACTIVE 0x1\n#define PH_RUNDOWN_REF_SHIFT 1\n#define PH_RUNDOWN_REF_INC 0x2\n\ntypedef struct _PH_RUNDOWN_PROTECT\n{\n    ULONG_PTR Value;\n} PH_RUNDOWN_PROTECT, *PPH_RUNDOWN_PROTECT;\n\n#define PH_RUNDOWN_PROTECT_INIT { 0 }\n\ntypedef struct _PH_RUNDOWN_WAIT_BLOCK\n{\n    ULONG_PTR Count;\n    PH_EVENT WakeEvent;\n} PH_RUNDOWN_WAIT_BLOCK, *PPH_RUNDOWN_WAIT_BLOCK;\n\nPHLIBAPI\nVOID\nFASTCALL\nPhfInitializeRundownProtection(\n    _Out_ PPH_RUNDOWN_PROTECT Protection\n    );\n\nPHLIBAPI\nBOOLEAN\nFASTCALL\nPhfAcquireRundownProtection(\n    _Inout_ PPH_RUNDOWN_PROTECT Protection\n    );\n\nPHLIBAPI\nVOID\nFASTCALL\nPhfReleaseRundownProtection(\n    _Inout_ PPH_RUNDOWN_PROTECT Protection\n    );\n\nPHLIBAPI\nVOID\nFASTCALL\nPhfWaitForRundownProtection(\n    _Inout_ PPH_RUNDOWN_PROTECT Protection\n    );\n\nFORCEINLINE\nVOID\nPhInitializeRundownProtection(\n    _Out_ PPH_RUNDOWN_PROTECT Protection\n    )\n{\n    Protection->Value = 0;\n}\n\nFORCEINLINE\nBOOLEAN\nPhAcquireRundownProtection(\n    _Inout_ PPH_RUNDOWN_PROTECT Protection\n    )\n{\n    ULONG_PTR value;\n\n    value = Protection->Value & ~PH_RUNDOWN_ACTIVE; // fail fast path when rundown is active\n\n    if ((ULONG_PTR)_InterlockedCompareExchangePointer(\n        (PVOID *)&Protection->Value,\n        (PVOID)(value + PH_RUNDOWN_REF_INC),\n        (PVOID)value\n        ) == value)\n    {\n        return TRUE;\n    }\n    else\n    {\n        return PhfAcquireRundownProtection(Protection);\n    }\n}\n\nFORCEINLINE\nVOID\nPhReleaseRundownProtection(\n    _Inout_ PPH_RUNDOWN_PROTECT Protection\n    )\n{\n    ULONG_PTR value;\n\n    value = Protection->Value & ~PH_RUNDOWN_ACTIVE; // Fail fast path when rundown is active\n\n    if ((ULONG_PTR)_InterlockedCompareExchangePointer(\n        (PVOID *)&Protection->Value,\n        (PVOID)(value - PH_RUNDOWN_REF_INC),\n        (PVOID)value\n        ) != value)\n    {\n        PhfReleaseRundownProtection(Protection);\n    }\n}\n\nFORCEINLINE\nVOID\nPhWaitForRundownProtection(\n    _Inout_ PPH_RUNDOWN_PROTECT Protection\n    )\n{\n    ULONG_PTR value;\n\n    value = (ULONG_PTR)_InterlockedCompareExchangePointer(\n        (PVOID *)&Protection->Value,\n        (PVOID)PH_RUNDOWN_ACTIVE,\n        (PVOID)0\n        );\n\n    if (value != 0 && value != PH_RUNDOWN_ACTIVE)\n        PhfWaitForRundownProtection(Protection);\n}\n\n// One-time initialization\n\n#define PH_INITONCE_SHIFT 31\n#define PH_INITONCE_INITIALIZING (0x1 << PH_INITONCE_SHIFT)\n#define PH_INITONCE_INITIALIZING_SHIFT PH_INITONCE_SHIFT\n\ntypedef struct _PH_INITONCE\n{\n    PH_EVENT Event;\n} PH_INITONCE, *PPH_INITONCE;\n\nC_ASSERT(PH_INITONCE_SHIFT >= FIELD_OFFSET(PH_EVENT, AvailableForUse) * 8);\n\n#define PH_INITONCE_INIT { PH_EVENT_INIT }\n\n#define PhInitializeInitOnce PhfInitializeInitOnce\nPHLIBAPI\nVOID\nFASTCALL\nPhfInitializeInitOnce(\n    _Out_ PPH_INITONCE InitOnce\n    );\n\nPHLIBAPI\nBOOLEAN\nFASTCALL\nPhfBeginInitOnce(\n    _Inout_ PPH_INITONCE InitOnce\n    );\n\n#define PhEndInitOnce PhfEndInitOnce\nPHLIBAPI\nVOID\nFASTCALL\nPhfEndInitOnce(\n    _Inout_ PPH_INITONCE InitOnce\n    );\n\nFORCEINLINE\nBOOLEAN\nPhBeginInitOnce(\n    _Inout_ PPH_INITONCE InitOnce\n    )\n{\n    if (InitOnce->Event.Set)\n        return FALSE;\n    else\n        return PhfBeginInitOnce(InitOnce);\n}\n\nFORCEINLINE\nBOOLEAN\nPhTestInitOnce(\n    _In_ PPH_INITONCE InitOnce\n    )\n{\n    return (BOOLEAN)InitOnce->Event.Set;\n}\n\n// String\n\nPHLIBAPI\nSIZE_T\nNTAPI\nPhCountStringZ(\n    _In_ PWSTR String\n    );\n\nPHLIBAPI\nPSTR\nNTAPI\nPhDuplicateBytesZ(\n    _In_ PSTR String\n    );\n\nPHLIBAPI\nPSTR\nNTAPI\nPhDuplicateBytesZSafe(\n    _In_ PSTR String\n    );\n\nPHLIBAPI\nPWSTR\nNTAPI\nPhDuplicateStringZ(\n    _In_ PWSTR String\n    );\n\nPHLIBAPI\nBOOLEAN\nNTAPI\nPhCopyBytesZ(\n    _In_ PSTR InputBuffer,\n    _In_ SIZE_T InputCount,\n    _Out_writes_opt_z_(OutputCount) PSTR OutputBuffer,\n    _In_ SIZE_T OutputCount,\n    _Out_opt_ PSIZE_T ReturnCount\n    );\n\nPHLIBAPI\nBOOLEAN\nNTAPI\nPhCopyStringZ(\n    _In_ PWSTR InputBuffer,\n    _In_ SIZE_T InputCount,\n    _Out_writes_opt_z_(OutputCount) PWSTR OutputBuffer,\n    _In_ SIZE_T OutputCount,\n    _Out_opt_ PSIZE_T ReturnCount\n    );\n\nPHLIBAPI\nBOOLEAN\nNTAPI\nPhCopyStringZFromBytes(\n    _In_ PSTR InputBuffer,\n    _In_ SIZE_T InputCount,\n    _Out_writes_opt_z_(OutputCount) PWSTR OutputBuffer,\n    _In_ SIZE_T OutputCount,\n    _Out_opt_ PSIZE_T ReturnCount\n    );\n\nPHLIBAPI\nBOOLEAN\nNTAPI\nPhCopyStringZFromMultiByte(\n    _In_ PSTR InputBuffer,\n    _In_ SIZE_T InputCount,\n    _Out_writes_opt_z_(OutputCount) PWSTR OutputBuffer,\n    _In_ SIZE_T OutputCount,\n    _Out_opt_ PSIZE_T ReturnCount\n    );\n\nPHLIBAPI\nLONG\nNTAPI\nPhCompareStringZNatural(\n    _In_ PWSTR A,\n    _In_ PWSTR B,\n    _In_ BOOLEAN IgnoreCase\n    );\n\nFORCEINLINE\nBOOLEAN\nPhAreCharactersDifferent(\n    _In_ WCHAR Char1,\n    _In_ WCHAR Char2\n    )\n{\n    WCHAR d;\n\n    d = Char1 ^ Char2;\n\n    // We ignore bits beyond bit 5 because bit 6 is the case bit, and also we\n    // don't support localization here.\n    if (d & 0x1f)\n        return TRUE;\n\n    return FALSE;\n}\n\nFORCEINLINE\nBOOLEAN\nPhIsDigitCharacter(\n    _In_ WCHAR Char\n    )\n{\n    return (USHORT)(Char - '0') < 10;\n}\n\nFORCEINLINE\nLONG\nPhCompareBytesZ(\n    _In_ PSTR String1,\n    _In_ PSTR String2,\n    _In_ BOOLEAN IgnoreCase\n    )\n{\n    if (!IgnoreCase)\n        return strcmp(String1, String2);\n    else\n        return _stricmp(String1, String2);\n}\n\nFORCEINLINE\nBOOLEAN\nPhEqualBytesZ(\n    _In_ PSTR String1,\n    _In_ PSTR String2,\n    _In_ BOOLEAN IgnoreCase\n    )\n{\n    if (!IgnoreCase)\n        return strcmp(String1, String2) == 0;\n    else\n        return _stricmp(String1, String2) == 0;\n}\n\nFORCEINLINE\nLONG\nPhCompareStringZ(\n    _In_ PWSTR String1,\n    _In_ PWSTR String2,\n    _In_ BOOLEAN IgnoreCase\n    )\n{\n    if (!IgnoreCase)\n        return wcscmp(String1, String2);\n    else\n        return _wcsicmp(String1, String2);\n}\n\nFORCEINLINE\nBOOLEAN\nPhEqualStringZ(\n    _In_ PWSTR String1,\n    _In_ PWSTR String2,\n    _In_ BOOLEAN IgnoreCase\n    )\n{\n    if (!IgnoreCase)\n    {\n        return wcscmp(String1, String2) == 0;\n    }\n    else\n    {\n        // wcsicmp is very expensive, so we do a quick check for negatives first.\n        if (PhAreCharactersDifferent(String1[0], String2[0]))\n            return FALSE;\n\n        return _wcsicmp(String1, String2) == 0;\n    }\n}\n\ntypedef struct _PH_STRINGREF\n{\n    /** The length, in bytes, of the string. */\n    SIZE_T Length;\n    /** The buffer containing the contents of the string. */\n    PWCH Buffer;\n} PH_STRINGREF, *PPH_STRINGREF;\n\ntypedef struct _PH_BYTESREF\n{\n    /** The length, in bytes, of the string. */\n    SIZE_T Length;\n    /** The buffer containing the contents of the string. */\n    PCH Buffer;\n} PH_BYTESREF, *PPH_BYTESREF;\n\ntypedef struct _PH_RELATIVE_BYTESREF\n{\n    /** The length, in bytes, of the string. */\n    ULONG Length;\n    /** A user-defined offset. */\n    ULONG Offset;\n} PH_RELATIVE_BYTESREF, *PPH_RELATIVE_BYTESREF, PH_RELATIVE_STRINGREF, *PPH_RELATIVE_STRINGREF;\n\n#define PH_STRINGREF_INIT(String) { sizeof(String) - sizeof(WCHAR), (String) }\n#define PH_BYTESREF_INIT(String) { sizeof(String) - sizeof(CHAR), (String) }\n\nFORCEINLINE\nVOID\nPhInitializeStringRef(\n    _Out_ PPH_STRINGREF String,\n    _In_ PWSTR Buffer\n    )\n{\n    String->Length = wcslen(Buffer) * sizeof(WCHAR);\n    String->Buffer = Buffer;\n}\n\nFORCEINLINE\nVOID\nPhInitializeStringRefLongHint(\n    _Out_ PPH_STRINGREF String,\n    _In_ PWSTR Buffer\n    )\n{\n    String->Length = PhCountStringZ(Buffer) * sizeof(WCHAR);\n    String->Buffer = Buffer;\n}\n\nFORCEINLINE\nVOID\nPhInitializeBytesRef(\n    _Out_ PPH_BYTESREF Bytes,\n    _In_ PSTR Buffer\n    )\n{\n    Bytes->Length = strlen(Buffer) * sizeof(CHAR);\n    Bytes->Buffer = Buffer;\n}\n\nFORCEINLINE\nVOID\nPhInitializeEmptyStringRef(\n    _Out_ PPH_STRINGREF String\n    )\n{\n    String->Length = 0;\n    String->Buffer = NULL;\n}\n\nFORCEINLINE\nBOOLEAN\nPhStringRefToUnicodeString(\n    _In_ PPH_STRINGREF String,\n    _Out_ PUNICODE_STRING UnicodeString\n    )\n{\n    UnicodeString->Length = (USHORT)String->Length;\n    UnicodeString->MaximumLength = (USHORT)String->Length;\n    UnicodeString->Buffer = String->Buffer;\n\n    return String->Length <= UNICODE_STRING_MAX_BYTES;\n}\n\nFORCEINLINE\nVOID\nPhUnicodeStringToStringRef(\n    _In_ PUNICODE_STRING UnicodeString,\n    _Out_ PPH_STRINGREF String\n    )\n{\n    String->Length = UnicodeString->Length;\n    String->Buffer = UnicodeString->Buffer;\n}\n\nPHLIBAPI\nLONG\nNTAPI\nPhCompareStringRef(\n    _In_ PPH_STRINGREF String1,\n    _In_ PPH_STRINGREF String2,\n    _In_ BOOLEAN IgnoreCase\n    );\n\nPHLIBAPI\nBOOLEAN\nNTAPI\nPhEqualStringRef(\n    _In_ PPH_STRINGREF String1,\n    _In_ PPH_STRINGREF String2,\n    _In_ BOOLEAN IgnoreCase\n    );\n\nPHLIBAPI\nULONG_PTR\nNTAPI\nPhFindCharInStringRef(\n    _In_ PPH_STRINGREF String,\n    _In_ WCHAR Character,\n    _In_ BOOLEAN IgnoreCase\n    );\n\nPHLIBAPI\nULONG_PTR\nNTAPI\nPhFindLastCharInStringRef(\n    _In_ PPH_STRINGREF String,\n    _In_ WCHAR Character,\n    _In_ BOOLEAN IgnoreCase\n    );\n\nPHLIBAPI\nULONG_PTR\nNTAPI\nPhFindStringInStringRef(\n    _In_ PPH_STRINGREF String,\n    _In_ PPH_STRINGREF SubString,\n    _In_ BOOLEAN IgnoreCase\n    );\n\nPHLIBAPI\nBOOLEAN\nNTAPI\nPhSplitStringRefAtChar(\n    _In_ PPH_STRINGREF Input,\n    _In_ WCHAR Separator,\n    _Out_ PPH_STRINGREF FirstPart,\n    _Out_ PPH_STRINGREF SecondPart\n    );\n\nPHLIBAPI\nBOOLEAN\nNTAPI\nPhSplitStringRefAtLastChar(\n    _In_ PPH_STRINGREF Input,\n    _In_ WCHAR Separator,\n    _Out_ PPH_STRINGREF FirstPart,\n    _Out_ PPH_STRINGREF SecondPart\n    );\n\nPHLIBAPI\nBOOLEAN\nNTAPI\nPhSplitStringRefAtString(\n    _In_ PPH_STRINGREF Input,\n    _In_ PPH_STRINGREF Separator,\n    _In_ BOOLEAN IgnoreCase,\n    _Out_ PPH_STRINGREF FirstPart,\n    _Out_ PPH_STRINGREF SecondPart\n    );\n\n#define PH_SPLIT_AT_CHAR_SET 0x0 // default\n#define PH_SPLIT_AT_STRING 0x1\n#define PH_SPLIT_AT_RANGE 0x2\n#define PH_SPLIT_CASE_INSENSITIVE 0x1000\n#define PH_SPLIT_COMPLEMENT_CHAR_SET 0x2000\n#define PH_SPLIT_START_AT_END 0x4000\n#define PH_SPLIT_CHAR_SET_IS_UPPERCASE 0x8000\n\nPHLIBAPI\nBOOLEAN\nNTAPI\nPhSplitStringRefEx(\n    _In_ PPH_STRINGREF Input,\n    _In_ PPH_STRINGREF Separator,\n    _In_ ULONG Flags,\n    _Out_ PPH_STRINGREF FirstPart,\n    _Out_ PPH_STRINGREF SecondPart,\n    _Out_opt_ PPH_STRINGREF SeparatorPart\n    );\n\n#define PH_TRIM_START_ONLY 0x1\n#define PH_TRIM_END_ONLY 0x2\n\nPHLIBAPI\nVOID\nNTAPI\nPhTrimStringRef(\n    _Inout_ PPH_STRINGREF String,\n    _In_ PPH_STRINGREF CharSet,\n    _In_ ULONG Flags\n    );\n\nFORCEINLINE\nLONG\nPhCompareStringRef2(\n    _In_ PPH_STRINGREF String1,\n    _In_ PWSTR String2,\n    _In_ BOOLEAN IgnoreCase\n    )\n{\n    PH_STRINGREF sr2;\n\n    PhInitializeStringRef(&sr2, String2);\n\n    return PhCompareStringRef(String1, &sr2, IgnoreCase);\n}\n\nFORCEINLINE\nBOOLEAN\nPhEqualStringRef2(\n    _In_ PPH_STRINGREF String1,\n    _In_ PWSTR String2,\n    _In_ BOOLEAN IgnoreCase\n    )\n{\n    PH_STRINGREF sr2;\n\n    PhInitializeStringRef(&sr2, String2);\n\n    return PhEqualStringRef(String1, &sr2, IgnoreCase);\n}\n\nFORCEINLINE\nBOOLEAN\nPhStartsWithStringRef(\n    _In_ PPH_STRINGREF String,\n    _In_ PPH_STRINGREF Prefix,\n    _In_ BOOLEAN IgnoreCase\n    )\n{\n    PH_STRINGREF sr;\n\n    sr.Buffer = String->Buffer;\n    sr.Length = Prefix->Length;\n\n    if (String->Length < sr.Length)\n        return FALSE;\n\n    return PhEqualStringRef(&sr, Prefix, IgnoreCase);\n}\n\nFORCEINLINE\nBOOLEAN\nPhStartsWithStringRef2(\n    _In_ PPH_STRINGREF String,\n    _In_ PWSTR Prefix,\n    _In_ BOOLEAN IgnoreCase\n    )\n{\n    PH_STRINGREF prefix;\n\n    PhInitializeStringRef(&prefix, Prefix);\n\n    return PhStartsWithStringRef(String, &prefix, IgnoreCase);\n}\n\nFORCEINLINE\nBOOLEAN\nPhEndsWithStringRef(\n    _In_ PPH_STRINGREF String,\n    _In_ PPH_STRINGREF Suffix,\n    _In_ BOOLEAN IgnoreCase\n    )\n{\n    PH_STRINGREF sr;\n\n    if (Suffix->Length > String->Length)\n        return FALSE;\n\n    sr.Buffer = (PWCHAR)PTR_ADD_OFFSET(String->Buffer, String->Length - Suffix->Length);\n    sr.Length = Suffix->Length;\n\n    return PhEqualStringRef(&sr, Suffix, IgnoreCase);\n}\n\nFORCEINLINE\nBOOLEAN\nPhEndsWithStringRef2(\n    _In_ PPH_STRINGREF String,\n    _In_ PWSTR Suffix,\n    _In_ BOOLEAN IgnoreCase\n    )\n{\n    PH_STRINGREF suffix;\n\n    PhInitializeStringRef(&suffix, Suffix);\n\n    return PhEndsWithStringRef(String, &suffix, IgnoreCase);\n}\n\nFORCEINLINE\nVOID\nPhSkipStringRef(\n    _Inout_ PPH_STRINGREF String,\n    _In_ LONG_PTR Length\n    )\n{\n    String->Buffer = (PWCH)PTR_ADD_OFFSET(String->Buffer, Length);\n    String->Length -= Length;\n}\n\nFORCEINLINE\nVOID\nPhReverseStringRef(\n    _In_ PPH_STRINGREF String\n    )\n{\n    SIZE_T i;\n    SIZE_T j;\n    WCHAR t;\n\n    for (i = 0, j = String->Length / sizeof(WCHAR) - 1; i <= j; i++, j--)\n    {\n        t = String->Buffer[i];\n        String->Buffer[i] = String->Buffer[j];\n        String->Buffer[j] = t;\n    }\n}\n\nextern PPH_OBJECT_TYPE PhStringType;\n\n/**\n * A 16-bit string object, which supports UTF-16.\n *\n * \\remarks The \\a Length never includes the null terminator. Every string must have a null\n * terminator at the end, for compatibility reasons. The invariant is:\n * \\code Buffer[Length / sizeof(WCHAR)] = 0 \\endcode\n */\ntypedef struct _PH_STRING\n{\n    // Header\n    union\n    {\n        PH_STRINGREF sr;\n        struct\n        {\n            /** The length, in bytes, of the string. */\n            SIZE_T Length;\n            /** The buffer containing the contents of the string. */\n            PWCH Buffer;\n        };\n    };\n\n    // Data\n    union\n    {\n        WCHAR Data[1];\n        struct\n        {\n            /** Reserved. */\n            ULONG AllocationFlags;\n            /** Reserved. */\n            PVOID Allocation;\n        };\n    };\n} PH_STRING, *PPH_STRING;\n\nPHLIBAPI\nPPH_STRING\nNTAPI\nPhCreateString(\n    _In_ PWSTR Buffer\n    );\n\nPHLIBAPI\nPPH_STRING\nNTAPI\nPhCreateStringEx(\n    _In_opt_ PWCHAR Buffer,\n    _In_ SIZE_T Length\n    );\n\nPHLIBAPI\nPPH_STRING\nNTAPI\nPhReferenceEmptyString(\n    VOID\n    );\n\nFORCEINLINE\nPPH_STRING\nPhCreateString2(\n    _In_ PPH_STRINGREF String\n    )\n{\n    if (String->Length == 0)\n        return PhReferenceEmptyString();\n\n    return PhCreateStringEx(String->Buffer, String->Length);\n}\n\nFORCEINLINE\nPPH_STRING\nPhCreateStringFromUnicodeString(\n    _In_ PUNICODE_STRING UnicodeString\n    )\n{\n    if (UnicodeString->Length == 0)\n        return PhReferenceEmptyString();\n\n    return PhCreateStringEx(UnicodeString->Buffer, UnicodeString->Length);\n}\n\nPHLIBAPI\nPPH_STRING\nNTAPI\nPhConcatStrings(\n    _In_ ULONG Count,\n    ...\n    );\n\n#define PH_CONCAT_STRINGS_LENGTH_CACHE_SIZE 16\n\nPHLIBAPI\nPPH_STRING\nNTAPI\nPhConcatStrings_V(\n    _In_ ULONG Count,\n    _In_ va_list ArgPtr\n    );\n\nPHLIBAPI\nPPH_STRING\nNTAPI\nPhConcatStrings2(\n    _In_ PWSTR String1,\n    _In_ PWSTR String2\n    );\n\nPHLIBAPI\nPPH_STRING\nNTAPI\nPhConcatStringRef2(\n    _In_ PPH_STRINGREF String1,\n    _In_ PPH_STRINGREF String2\n    );\n\nPPH_STRING\nNTAPI\nPhConcatStringRef3(\n    _In_ PPH_STRINGREF String1,\n    _In_ PPH_STRINGREF String2,\n    _In_ PPH_STRINGREF String3\n    );\n\nPHLIBAPI\nPPH_STRING\nNTAPI\nPhFormatString(\n    _In_ _Printf_format_string_ PWSTR Format,\n    ...\n    );\n\nPHLIBAPI\nPPH_STRING\nNTAPI\nPhFormatString_V(\n    _In_ _Printf_format_string_ PWSTR Format,\n    _In_ va_list ArgPtr\n    );\n\n/**\n * Retrieves a pointer to a string object's buffer or returns NULL.\n *\n * \\param String A pointer to a string object.\n *\n * \\return A pointer to the string object's buffer if the supplied pointer is non-NULL, otherwise\n * NULL.\n */\nFORCEINLINE\nPWSTR\nPhGetString(\n    _In_opt_ PPH_STRING String\n    )\n{\n    if (String)\n        return String->Buffer;\n    else\n        return NULL;\n}\n\nFORCEINLINE\nPH_STRINGREF\nPhGetStringRef(\n    _In_opt_ PPH_STRING String\n    )\n{\n    PH_STRINGREF sr;\n\n    if (String)\n        sr = String->sr;\n    else\n        PhInitializeEmptyStringRef(&sr);\n\n    return sr;\n}\n\n/**\n * Retrieves a pointer to a string object's buffer or returns an empty string.\n *\n * \\param String A pointer to a string object.\n *\n * \\return A pointer to the string object's buffer if the supplied pointer is non-NULL, otherwise an\n * empty string.\n */\nFORCEINLINE\nPWSTR\nPhGetStringOrEmpty(\n    _In_opt_ PPH_STRING String\n    )\n{\n    if (String)\n        return String->Buffer;\n    else\n        return L\"\";\n}\n\n/**\n * Retrieves a pointer to a string object's buffer or returns the specified alternative string.\n *\n * \\param String A pointer to a string object.\n * \\param DefaultString The alternative string.\n *\n * \\return A pointer to the string object's buffer if the supplied pointer is non-NULL, otherwise\n * the specified alternative string.\n */\nFORCEINLINE\nPWSTR\nPhGetStringOrDefault(\n    _In_opt_ PPH_STRING String,\n    _In_ PWSTR DefaultString\n    )\n{\n    if (String)\n        return String->Buffer;\n    else\n        return DefaultString;\n}\n\n/**\n * Determines whether a string is null or empty.\n *\n * \\param String A pointer to a string object.\n */\nFORCEINLINE\nBOOLEAN\nPhIsNullOrEmptyString(\n    _In_opt_ PPH_STRING String\n    )\n{\n    return !String || String->Length == 0;\n}\n\n/**\n * Duplicates a string.\n *\n * \\param String A string to duplicate.\n */\nFORCEINLINE\nPPH_STRING\nPhDuplicateString(\n    _In_ PPH_STRING String\n    )\n{\n    return PhCreateStringEx(String->Buffer, String->Length);\n}\n\n/**\n * Compares two strings.\n *\n * \\param String1 The first string.\n * \\param String2 The second string.\n * \\param IgnoreCase Whether to ignore character cases.\n */\nFORCEINLINE\nLONG\nPhCompareString(\n    _In_ PPH_STRING String1,\n    _In_ PPH_STRING String2,\n    _In_ BOOLEAN IgnoreCase\n    )\n{\n    if (!IgnoreCase)\n        return wcscmp(String1->Buffer, String2->Buffer);\n    else\n        return PhCompareStringRef(&String1->sr, &String2->sr, IgnoreCase); // faster than wcsicmp\n}\n\n/**\n * Compares two strings.\n *\n * \\param String1 The first string.\n * \\param String2 The second string.\n * \\param IgnoreCase Whether to ignore character cases.\n */\nFORCEINLINE\nLONG\nPhCompareString2(\n    _In_ PPH_STRING String1,\n    _In_ PWSTR String2,\n    _In_ BOOLEAN IgnoreCase\n    )\n{\n    if (!IgnoreCase)\n    {\n        return wcscmp(String1->Buffer, String2);\n    }\n    else\n    {\n        return PhCompareStringRef2(&String1->sr, String2, IgnoreCase);\n    }\n}\n\n/**\n * Compares two strings, handling NULL strings.\n *\n * \\param String1 The first string.\n * \\param String2 The second string.\n * \\param IgnoreCase Whether to ignore character cases.\n */\nFORCEINLINE\nLONG\nPhCompareStringWithNull(\n    _In_opt_ PPH_STRING String1,\n    _In_opt_ PPH_STRING String2,\n    _In_ BOOLEAN IgnoreCase\n    )\n{\n    if (String1 && String2)\n    {\n        return PhCompareString(String1, String2, IgnoreCase);\n    }\n    else if (!String1)\n    {\n        return !String2 ? 0 : -1;\n    }\n    else\n    {\n        return 1;\n    }\n}\n\n/**\n * Determines whether two strings are equal.\n *\n * \\param String1 The first string.\n * \\param String2 The second string.\n * \\param IgnoreCase Whether to ignore character cases.\n */\nFORCEINLINE\nBOOLEAN\nPhEqualString(\n    _In_ PPH_STRING String1,\n    _In_ PPH_STRING String2,\n    _In_ BOOLEAN IgnoreCase\n    )\n{\n    return PhEqualStringRef(&String1->sr, &String2->sr, IgnoreCase);\n}\n\n/**\n * Determines whether two strings are equal.\n *\n * \\param String1 The first string.\n * \\param String2 The second string.\n * \\param IgnoreCase Whether to ignore character cases.\n */\nFORCEINLINE\nBOOLEAN\nPhEqualString2(\n    _In_ PPH_STRING String1,\n    _In_ PWSTR String2,\n    _In_ BOOLEAN IgnoreCase\n    )\n{\n    if (!IgnoreCase)\n    {\n        return wcscmp(String1->Buffer, String2) == 0;\n    }\n    else\n    {\n        return PhEqualStringRef2(&String1->sr, String2, IgnoreCase);\n    }\n}\n\n/**\n * Determines whether a string starts with another.\n *\n * \\param String The first string.\n * \\param Prefix The second string.\n * \\param IgnoreCase Whether to ignore character cases.\n *\n * \\return TRUE if \\a String starts with \\a Prefix, otherwise FALSE.\n */\nFORCEINLINE\nBOOLEAN\nPhStartsWithString(\n    _In_ PPH_STRING String,\n    _In_ PPH_STRING Prefix,\n    _In_ BOOLEAN IgnoreCase\n    )\n{\n    return PhStartsWithStringRef(&String->sr, &Prefix->sr, IgnoreCase);\n}\n\n/**\n * Determines whether a string starts with another.\n *\n * \\param String The first string.\n * \\param Prefix The second string.\n * \\param IgnoreCase Whether to ignore character cases.\n *\n * \\return TRUE if \\a String starts with \\a Prefix, otherwise FALSE.\n */\nFORCEINLINE\nBOOLEAN\nPhStartsWithString2(\n    _In_ PPH_STRING String,\n    _In_ PWSTR Prefix,\n    _In_ BOOLEAN IgnoreCase\n    )\n{\n    PH_STRINGREF prefix;\n\n    PhInitializeStringRef(&prefix, Prefix);\n\n    return PhStartsWithStringRef(&String->sr, &prefix, IgnoreCase);\n}\n\n/**\n * Determines whether a string ends with another.\n *\n * \\param String The first string.\n * \\param Suffix The second string.\n * \\param IgnoreCase Whether to ignore character cases.\n *\n * \\return TRUE if \\a String ends with \\a Suffix, otherwise FALSE.\n */\nFORCEINLINE\nBOOLEAN\nPhEndsWithString(\n    _In_ PPH_STRING String,\n    _In_ PPH_STRING Suffix,\n    _In_ BOOLEAN IgnoreCase\n    )\n{\n    return PhEndsWithStringRef(&String->sr, &Suffix->sr, IgnoreCase);\n}\n\n/**\n * Determines whether a string ends with another.\n *\n * \\param String The first string.\n * \\param Suffix The second string.\n * \\param IgnoreCase Whether to ignore character cases.\n *\n * \\return TRUE if \\a String ends with \\a Suffix, otherwise FALSE.\n */\nFORCEINLINE\nBOOLEAN\nPhEndsWithString2(\n    _In_ PPH_STRING String,\n    _In_ PWSTR Suffix,\n    _In_ BOOLEAN IgnoreCase\n    )\n{\n    PH_STRINGREF suffix;\n\n    PhInitializeStringRef(&suffix, Suffix);\n\n    return PhEndsWithStringRef(&String->sr, &suffix, IgnoreCase);\n}\n\n/**\n * Locates a character in a string.\n *\n * \\param String The string to search.\n * \\param StartIndex The index, in characters, to start searching at.\n * \\param Char The character to search for.\n *\n * \\return The index, in characters, of the first occurrence of \\a Char in \\a String after\n * \\a StartIndex. If \\a Char was not found, -1 is returned.\n */\nFORCEINLINE\nULONG_PTR\nPhFindCharInString(\n    _In_ PPH_STRING String,\n    _In_ SIZE_T StartIndex,\n    _In_ WCHAR Char\n    )\n{\n    if (StartIndex != 0)\n    {\n        ULONG_PTR r;\n        PH_STRINGREF sr;\n\n        sr = String->sr;\n        PhSkipStringRef(&sr, StartIndex * sizeof(WCHAR));\n        r = PhFindCharInStringRef(&sr, Char, FALSE);\n\n        if (r != -1)\n            return r + StartIndex;\n        else\n            return -1;\n    }\n    else\n    {\n        return PhFindCharInStringRef(&String->sr, Char, FALSE);\n    }\n}\n\n/**\n * Locates a character in a string, backwards.\n *\n * \\param String The string to search.\n * \\param StartIndex The index, in characters, to start searching at.\n * \\param Char The character to search for.\n *\n * \\return The index, in characters, of the last occurrence of \\a Char in \\a String after\n * \\a StartIndex. If \\a Char was not found, -1 is returned.\n */\nFORCEINLINE\nULONG_PTR\nPhFindLastCharInString(\n    _In_ PPH_STRING String,\n    _In_ SIZE_T StartIndex,\n    _In_ WCHAR Char\n    )\n{\n    if (StartIndex != 0)\n    {\n        ULONG_PTR r;\n        PH_STRINGREF sr;\n\n        sr = String->sr;\n        PhSkipStringRef(&sr, StartIndex * sizeof(WCHAR));\n        r = PhFindLastCharInStringRef(&sr, Char, FALSE);\n\n        if (r != -1)\n            return r + StartIndex;\n        else\n            return -1;\n    }\n    else\n    {\n        return PhFindLastCharInStringRef(&String->sr, Char, FALSE);\n    }\n}\n\n/**\n * Locates a string in a string.\n *\n * \\param String The string to search.\n * \\param StartIndex The index, in characters, to start searching at.\n * \\param SubString The string to search for.\n *\n * \\return The index, in characters, of the first occurrence of \\a SubString in \\a String after\n * \\a StartIndex. If \\a SubString was not found, -1 is returned.\n */\nFORCEINLINE\nULONG_PTR\nPhFindStringInString(\n    _In_ PPH_STRING String,\n    _In_ SIZE_T StartIndex,\n    _In_ PWSTR SubString\n    )\n{\n    PH_STRINGREF sr2;\n\n    PhInitializeStringRef(&sr2, SubString);\n\n    if (StartIndex != 0)\n    {\n        ULONG_PTR r;\n        PH_STRINGREF sr1;\n\n        sr1 = String->sr;\n        PhSkipStringRef(&sr1, StartIndex * sizeof(WCHAR));\n        r = PhFindStringInStringRef(&sr1, &sr2, FALSE);\n\n        if (r != -1)\n            return r + StartIndex;\n        else\n            return -1;\n    }\n    else\n    {\n        return PhFindStringInStringRef(&String->sr, &sr2, FALSE);\n    }\n}\n\n/**\n * Creates a substring of a string.\n *\n * \\param String The original string.\n * \\param StartIndex The start index, in characters.\n * \\param Count The number of characters to use.\n */\nFORCEINLINE\nPPH_STRING\nPhSubstring(\n    _In_ PPH_STRING String,\n    _In_ SIZE_T StartIndex,\n    _In_ SIZE_T Count\n    )\n{\n    return PhCreateStringEx(&String->Buffer[StartIndex], Count * sizeof(WCHAR));\n}\n\n/**\n * Updates a string object's length with its true length as determined by an embedded null\n * terminator.\n *\n * \\param String The string to modify.\n *\n * \\remarks Use this function after modifying a string object's buffer manually.\n */\nFORCEINLINE\nVOID\nPhTrimToNullTerminatorString(\n    _Inout_ PPH_STRING String\n    )\n{\n    String->Length = PhCountStringZ(String->Buffer) * sizeof(WCHAR);\n}\n\n// Byte string\n\nextern PPH_OBJECT_TYPE PhBytesType;\n\n/**\n * An 8-bit string object, which supports ASCII, UTF-8 and Windows multi-byte encodings, as well as\n * binary data.\n */\ntypedef struct _PH_BYTES\n{\n    // Header\n    union\n    {\n        PH_BYTESREF br;\n        struct\n        {\n            /** The length, in bytes, of the string. */\n            SIZE_T Length;\n            /** The buffer containing the contents of the string. */\n            PCH Buffer;\n        };\n    };\n\n    // Data\n    union\n    {\n        CHAR Data[1];\n        struct\n        {\n            /** Reserved. */\n            ULONG AllocationFlags;\n            /** Reserved. */\n            PVOID Allocation;\n        };\n    };\n} PH_BYTES, *PPH_BYTES;\n\nPHLIBAPI\nPPH_BYTES\nNTAPI\nPhCreateBytes(\n    _In_ PSTR Buffer\n    );\n\nPHLIBAPI\nPPH_BYTES\nNTAPI\nPhCreateBytesEx(\n    _In_opt_ PCHAR Buffer,\n    _In_ SIZE_T Length\n    );\n\nFORCEINLINE\nPPH_BYTES\nPhCreateBytes2(\n    _In_ PPH_BYTESREF Bytes\n    )\n{\n    return PhCreateBytesEx(Bytes->Buffer, Bytes->Length);\n}\n\n// Unicode\n\n#define PH_UNICODE_BYTE_ORDER_MARK 0xfeff\n#define PH_UNICODE_MAX_CODE_POINT 0x10ffff\n\n#define PH_UNICODE_UTF16_TO_HIGH_SURROGATE(CodePoint) ((USHORT)((CodePoint) >> 10) + 0xd7c0)\n#define PH_UNICODE_UTF16_TO_LOW_SURROGATE(CodePoint) ((USHORT)((CodePoint) & 0x3ff) + 0xdc00)\n#define PH_UNICODE_UTF16_IS_HIGH_SURROGATE(CodeUnit) ((CodeUnit) >= 0xd800 && (CodeUnit) <= 0xdbff)\n#define PH_UNICODE_UTF16_IS_LOW_SURROGATE(CodeUnit) ((CodeUnit) >= 0xdc00 && (CodeUnit) <= 0xdfff)\n#define PH_UNICODE_UTF16_TO_CODE_POINT(HighSurrogate, LowSurrogate) (((ULONG)(HighSurrogate) << 10) + (ULONG)(LowSurrogate) - 0x35fdc00)\n\n#define PH_UNICODE_UTF8 0\n#define PH_UNICODE_UTF16 1\n#define PH_UNICODE_UTF32 2\n\ntypedef struct _PH_UNICODE_DECODER\n{\n    UCHAR Encoding; // PH_UNICODE_*\n    UCHAR State;\n    UCHAR InputCount;\n    UCHAR Reserved;\n    union\n    {\n        UCHAR Utf8[4];\n        USHORT Utf16[2];\n        ULONG Utf32;\n    } Input;\n    union\n    {\n        struct\n        {\n            UCHAR Input[4];\n            UCHAR CodeUnit1;\n            UCHAR CodeUnit2;\n            UCHAR CodeUnit3;\n            UCHAR CodeUnit4;\n        } Utf8;\n        struct\n        {\n            USHORT Input[2];\n            USHORT CodeUnit;\n        } Utf16;\n        struct\n        {\n            ULONG Input;\n        } Utf32;\n    } u;\n} PH_UNICODE_DECODER, *PPH_UNICODE_DECODER;\n\nFORCEINLINE\nVOID\nPhInitializeUnicodeDecoder(\n    _Out_ PPH_UNICODE_DECODER Decoder,\n    _In_ UCHAR Encoding\n    )\n{\n    memset(Decoder, 0, sizeof(PH_UNICODE_DECODER));\n    Decoder->Encoding = Encoding;\n}\n\nPHLIBAPI\nBOOLEAN\nNTAPI\nPhWriteUnicodeDecoder(\n    _Inout_ PPH_UNICODE_DECODER Decoder,\n    _In_ ULONG CodeUnit\n    );\n\nPHLIBAPI\nBOOLEAN\nNTAPI\nPhDecodeUnicodeDecoder(\n    _Inout_ PPH_UNICODE_DECODER Decoder,\n    _Out_ PULONG CodePoint\n    );\n\nPHLIBAPI\nBOOLEAN\nNTAPI\nPhEncodeUnicode(\n    _In_ UCHAR Encoding,\n    _In_ ULONG CodePoint,\n    _Out_opt_ PVOID CodeUnits,\n    _Out_ PULONG NumberOfCodeUnits\n    );\n\n// 8-bit to UTF-16\n\nPHLIBAPI\nVOID\nNTAPI\nPhZeroExtendToUtf16Buffer(\n    _In_reads_bytes_(InputLength) PCH Input,\n    _In_ SIZE_T InputLength,\n    _Out_writes_bytes_(InputLength * sizeof(WCHAR)) PWCH Output\n    );\n\nPHLIBAPI\nPPH_STRING\nNTAPI\nPhZeroExtendToUtf16Ex(\n    _In_reads_bytes_(InputLength) PCH Input,\n    _In_ SIZE_T InputLength\n    );\n\nFORCEINLINE\nPPH_STRING\nPhZeroExtendToUtf16(\n    _In_ PSTR Input\n    )\n{\n    return PhZeroExtendToUtf16Ex(Input, strlen(Input));\n}\n\n// UTF-16 to ASCII\n\nPHLIBAPI\nPPH_BYTES\nNTAPI\nPhConvertUtf16ToAsciiEx(\n    _In_ PWCH Buffer,\n    _In_ SIZE_T Length,\n    _In_opt_ CHAR Replacement\n    );\n\nFORCEINLINE\nPPH_BYTES\nPhConvertUtf16ToAscii(\n    _In_ PWSTR Buffer,\n    _In_opt_ CHAR Replacement\n    )\n{\n    return PhConvertUtf16ToAsciiEx(Buffer, PhCountStringZ(Buffer) * sizeof(WCHAR), Replacement);\n}\n\n// Multi-byte to UTF-16\n// In-place: RtlMultiByteToUnicodeN, RtlMultiByteToUnicodeSize\n\nPHLIBAPI\nPPH_STRING\nNTAPI\nPhConvertMultiByteToUtf16(\n    _In_ PSTR Buffer\n    );\n\nPHLIBAPI\nPPH_STRING\nNTAPI\nPhConvertMultiByteToUtf16Ex(\n    _In_ PCHAR Buffer,\n    _In_ SIZE_T Length\n    );\n\n// UTF-16 to multi-byte\n// In-place: RtlUnicodeToMultiByteN, RtlUnicodeToMultiByteSize\n\nPHLIBAPI\nPPH_BYTES\nNTAPI\nPhConvertUtf16ToMultiByte(\n    _In_ PWSTR Buffer\n    );\n\nPHLIBAPI\nPPH_BYTES\nNTAPI\nPhConvertUtf16ToMultiByteEx(\n    _In_ PWCHAR Buffer,\n    _In_ SIZE_T Length\n    );\n\n// UTF-8 to UTF-16\n\nPHLIBAPI\nBOOLEAN\nNTAPI\nPhConvertUtf8ToUtf16Size(\n    _Out_ PSIZE_T BytesInUtf16String,\n    _In_reads_bytes_(BytesInUtf8String) PCH Utf8String,\n    _In_ SIZE_T BytesInUtf8String\n    );\n\nPHLIBAPI\nBOOLEAN\nNTAPI\nPhConvertUtf8ToUtf16Buffer(\n    _Out_writes_bytes_to_(MaxBytesInUtf16String, *BytesInUtf16String) PWCH Utf16String,\n    _In_ SIZE_T MaxBytesInUtf16String,\n    _Out_opt_ PSIZE_T BytesInUtf16String,\n    _In_reads_bytes_(BytesInUtf8String) PCH Utf8String,\n    _In_ SIZE_T BytesInUtf8String\n    );\n\nPHLIBAPI\nPPH_STRING\nNTAPI\nPhConvertUtf8ToUtf16(\n    _In_ PSTR Buffer\n    );\n\nPHLIBAPI\nPPH_STRING\nNTAPI\nPhConvertUtf8ToUtf16Ex(\n    _In_ PCHAR Buffer,\n    _In_ SIZE_T Length\n    );\n\n// UTF-16 to UTF-8\n\nPHLIBAPI\nBOOLEAN\nNTAPI\nPhConvertUtf16ToUtf8Size(\n    _Out_ PSIZE_T BytesInUtf8String,\n    _In_reads_bytes_(BytesInUtf16String) PWCH Utf16String,\n    _In_ SIZE_T BytesInUtf16String\n    );\n\nPHLIBAPI\nBOOLEAN\nNTAPI\nPhConvertUtf16ToUtf8Buffer(\n    _Out_writes_bytes_to_(MaxBytesInUtf8String, *BytesInUtf8String) PCH Utf8String,\n    _In_ SIZE_T MaxBytesInUtf8String,\n    _Out_opt_ PSIZE_T BytesInUtf8String,\n    _In_reads_bytes_(BytesInUtf16String) PWCH Utf16String,\n    _In_ SIZE_T BytesInUtf16String\n    );\n\nPHLIBAPI\nPPH_BYTES\nNTAPI\nPhConvertUtf16ToUtf8(\n    _In_ PWSTR Buffer\n    );\n\nPHLIBAPI\nPPH_BYTES\nNTAPI\nPhConvertUtf16ToUtf8Ex(\n    _In_ PWCHAR Buffer,\n    _In_ SIZE_T Length\n    );\n\n// String builder\n\n/**\n * A string builder structure.\n * The string builder object allows you to easily construct complex strings without allocating\n * a great number of strings in the process.\n */\ntypedef struct _PH_STRING_BUILDER\n{\n    /** Allocated length of the string, not including the null terminator. */\n    SIZE_T AllocatedLength;\n    /**\n     * The constructed string.\n     * \\a String will be allocated for \\a AllocatedLength, we will modify the \\a Length field to be\n     * the correct length.\n     */\n    PPH_STRING String;\n} PH_STRING_BUILDER, *PPH_STRING_BUILDER;\n\nPHLIBAPI\nVOID\nNTAPI\nPhInitializeStringBuilder(\n    _Out_ PPH_STRING_BUILDER StringBuilder,\n    _In_ SIZE_T InitialCapacity\n    );\n\nPHLIBAPI\nVOID\nNTAPI\nPhDeleteStringBuilder(\n    _Inout_ PPH_STRING_BUILDER StringBuilder\n    );\n\nPHLIBAPI\nPPH_STRING\nNTAPI\nPhFinalStringBuilderString(\n    _Inout_ PPH_STRING_BUILDER StringBuilder\n    );\n\nPHLIBAPI\nVOID\nNTAPI\nPhAppendStringBuilder(\n    _Inout_ PPH_STRING_BUILDER StringBuilder,\n    _In_ PPH_STRINGREF String\n    );\n\nPHLIBAPI\nVOID\nNTAPI\nPhAppendStringBuilder2(\n    _Inout_ PPH_STRING_BUILDER StringBuilder,\n    _In_ PWSTR String\n    );\n\nPHLIBAPI\nVOID\nNTAPI\nPhAppendStringBuilderEx(\n    _Inout_ PPH_STRING_BUILDER StringBuilder,\n    _In_opt_ PWCHAR String,\n    _In_ SIZE_T Length\n    );\n\nPHLIBAPI\nVOID\nNTAPI\nPhAppendCharStringBuilder(\n    _Inout_ PPH_STRING_BUILDER StringBuilder,\n    _In_ WCHAR Character\n    );\n\nPHLIBAPI\nVOID\nNTAPI\nPhAppendCharStringBuilder2(\n    _Inout_ PPH_STRING_BUILDER StringBuilder,\n    _In_ WCHAR Character,\n    _In_ SIZE_T Count\n    );\n\nPHLIBAPI\nVOID\nNTAPI\nPhAppendFormatStringBuilder(\n    _Inout_ PPH_STRING_BUILDER StringBuilder,\n    _In_ _Printf_format_string_ PWSTR Format,\n    ...\n    );\n\nVOID\nNTAPI\nPhAppendFormatStringBuilder_V(\n    _Inout_ PPH_STRING_BUILDER StringBuilder,\n    _In_ _Printf_format_string_ PWSTR Format,\n    _In_ va_list ArgPtr\n    );\n\nPHLIBAPI\nVOID\nNTAPI\nPhInsertStringBuilder(\n    _Inout_ PPH_STRING_BUILDER StringBuilder,\n    _In_ SIZE_T Index,\n    _In_ PPH_STRINGREF String\n    );\n\nPHLIBAPI\nVOID\nNTAPI\nPhInsertStringBuilder2(\n    _Inout_ PPH_STRING_BUILDER StringBuilder,\n    _In_ SIZE_T Index,\n    _In_ PWSTR String\n    );\n\nPHLIBAPI\nVOID\nNTAPI\nPhInsertStringBuilderEx(\n    _Inout_ PPH_STRING_BUILDER StringBuilder,\n    _In_ SIZE_T Index,\n    _In_opt_ PWCHAR String,\n    _In_ SIZE_T Length\n    );\n\nPHLIBAPI\nVOID\nNTAPI\nPhRemoveStringBuilder(\n    _Inout_ PPH_STRING_BUILDER StringBuilder,\n    _In_ SIZE_T StartIndex,\n    _In_ SIZE_T Count\n    );\n\nFORCEINLINE\nVOID\nPhRemoveEndStringBuilder(\n    _Inout_ PPH_STRING_BUILDER StringBuilder,\n    _In_ SIZE_T Count\n    )\n{\n    PhRemoveStringBuilder(\n        StringBuilder,\n        StringBuilder->String->Length / sizeof(WCHAR) - Count,\n        Count\n        );\n}\n\n// Byte string builder\n\n/**\n * A byte string builder structure.\n * This is similar to string builder, but is based on PH_BYTES and is suitable for general binary\n * data.\n */\ntypedef struct _PH_BYTES_BUILDER\n{\n    /** Allocated length of the byte string, not including the null terminator. */\n    SIZE_T AllocatedLength;\n    /**\n     * The constructed byte string.\n     * \\a Bytes will be allocated for \\a AllocatedLength, we will modify the \\a Length field to be\n     * the correct length.\n     */\n    PPH_BYTES Bytes;\n} PH_BYTES_BUILDER, *PPH_BYTES_BUILDER;\n\nPHLIBAPI\nVOID\nNTAPI\nPhInitializeBytesBuilder(\n    _Out_ PPH_BYTES_BUILDER BytesBuilder,\n    _In_ SIZE_T InitialCapacity\n    );\n\nPHLIBAPI\nVOID\nNTAPI\nPhDeleteBytesBuilder(\n    _Inout_ PPH_BYTES_BUILDER BytesBuilder\n    );\n\nPHLIBAPI\nPPH_BYTES\nNTAPI\nPhFinalBytesBuilderBytes(\n    _Inout_ PPH_BYTES_BUILDER BytesBuilder\n    );\n\nFORCEINLINE\nPVOID\nPhOffsetBytesBuilder(\n    _In_ PPH_BYTES_BUILDER BytesBuilder,\n    _In_ SIZE_T Offset\n    )\n{\n    return BytesBuilder->Bytes->Buffer + Offset;\n}\n\nPHLIBAPI\nVOID\nNTAPI\nPhAppendBytesBuilder(\n    _Inout_ PPH_BYTES_BUILDER BytesBuilder,\n    _In_ PPH_BYTESREF Bytes\n    );\n\nPHLIBAPI\nVOID\nNTAPI\nPhAppendBytesBuilder2(\n    _Inout_ PPH_BYTES_BUILDER BytesBuilder,\n    _In_ PCHAR Bytes\n    );\n\nPHLIBAPI\nPVOID\nNTAPI\nPhAppendBytesBuilderEx(\n    _Inout_ PPH_BYTES_BUILDER BytesBuilder,\n    _In_opt_ PVOID Buffer,\n    _In_ SIZE_T Length,\n    _In_opt_ SIZE_T Alignment,\n    _Out_opt_ PSIZE_T Offset\n    );\n\n// Array\n\n/** An array structure. Storage is automatically allocated for new elements. */\ntypedef struct _PH_ARRAY\n{\n    /** The number of items in the list. */\n    SIZE_T Count;\n    /** The number of items for which storage is allocated. */\n    SIZE_T AllocatedCount;\n    /** The size of each item, in bytes. */\n    SIZE_T ItemSize;\n    /** The base address of the array. */\n    PVOID Items;\n} PH_ARRAY, *PPH_ARRAY;\n\nFORCEINLINE\nPVOID\nPhItemArray(\n    _In_ PPH_ARRAY Array,\n    _In_ SIZE_T Index\n    )\n{\n    return PTR_ADD_OFFSET(Array->Items, Index * Array->ItemSize);\n}\n\nPHLIBAPI\nVOID\nNTAPI\nPhInitializeArray(\n    _Out_ PPH_ARRAY Array,\n    _In_ SIZE_T ItemSize,\n    _In_ SIZE_T InitialCapacity\n    );\n\nPHLIBAPI\nVOID\nNTAPI\nPhDeleteArray(\n    _Inout_ PPH_ARRAY Array\n    );\n\nPHLIBAPI\nPVOID\nNTAPI\nPhFinalArrayItems(\n    _Inout_ PPH_ARRAY Array\n    );\n\nPHLIBAPI\nVOID\nNTAPI\nPhResizeArray(\n    _Inout_ PPH_ARRAY Array,\n    _In_ SIZE_T NewCapacity\n    );\n\nPHLIBAPI\nVOID\nNTAPI\nPhAddItemArray(\n    _Inout_ PPH_ARRAY Array,\n    _In_ PVOID Item\n    );\n\nPHLIBAPI\nVOID\nNTAPI\nPhAddItemsArray(\n    _Inout_ PPH_ARRAY Array,\n    _In_ PVOID Items,\n    _In_ SIZE_T Count\n    );\n\nPHLIBAPI\nVOID\nNTAPI\nPhClearArray(\n    _Inout_ PPH_ARRAY Array\n    );\n\nPHLIBAPI\nVOID\nNTAPI\nPhRemoveItemArray(\n    _Inout_ PPH_ARRAY Array,\n    _In_ SIZE_T Index\n    );\n\nPHLIBAPI\nVOID\nNTAPI\nPhRemoveItemsArray(\n    _Inout_ PPH_ARRAY Array,\n    _In_ SIZE_T StartIndex,\n    _In_ SIZE_T Count\n    );\n\n// List\n\nextern PPH_OBJECT_TYPE PhListType;\n\n/** A list structure. Storage is automatically allocated for new elements. */\ntypedef struct _PH_LIST\n{\n    /** The number of items in the list. */\n    ULONG Count;\n    /** The number of items for which storage is allocated. */\n    ULONG AllocatedCount;\n    /** The array of list items. */\n    PVOID *Items;\n} PH_LIST, *PPH_LIST;\n\nPHLIBAPI\nPPH_LIST\nNTAPI\nPhCreateList(\n    _In_ ULONG InitialCapacity\n    );\n\nPHLIBAPI\nVOID\nNTAPI\nPhResizeList(\n    _Inout_ PPH_LIST List,\n    _In_ ULONG NewCapacity\n    );\n\nPHLIBAPI\nVOID\nNTAPI\nPhAddItemList(\n    _Inout_ PPH_LIST List,\n    _In_ PVOID Item\n    );\n\nPHLIBAPI\nVOID\nNTAPI\nPhAddItemsList(\n    _Inout_ PPH_LIST List,\n    _In_ PVOID *Items,\n    _In_ ULONG Count\n    );\n\nPHLIBAPI\nVOID\nNTAPI\nPhClearList(\n    _Inout_ PPH_LIST List\n    );\n\n_Success_(return != -1)\nPHLIBAPI\nULONG\nNTAPI\nPhFindItemList(\n    _In_ PPH_LIST List,\n    _In_ PVOID Item\n    );\n\nPHLIBAPI\nVOID\nNTAPI\nPhInsertItemList(\n    _Inout_ PPH_LIST List,\n    _In_ ULONG Index,\n    _In_ PVOID Item\n    );\n\nPHLIBAPI\nVOID\nNTAPI\nPhInsertItemsList(\n    _Inout_ PPH_LIST List,\n    _In_ ULONG Index,\n    _In_ PVOID *Items,\n    _In_ ULONG Count\n    );\n\nPHLIBAPI\nVOID\nNTAPI\nPhRemoveItemList(\n    _Inout_ PPH_LIST List,\n    _In_ ULONG Index\n    );\n\nPHLIBAPI\nVOID\nNTAPI\nPhRemoveItemsList(\n    _Inout_ PPH_LIST List,\n    _In_ ULONG StartIndex,\n    _In_ ULONG Count\n    );\n\n/**\n * A comparison function.\n *\n * \\param Item1 The first item.\n * \\param Item2 The second item.\n * \\param Context A user-defined value.\n *\n * \\return\n * \\li A positive value if \\a Item1 > \\a Item2,\n * \\li A negative value if \\a Item1 < \\a Item2, and\n * \\li 0 if \\a Item1 = \\a Item2.\n */\ntypedef LONG (NTAPI *PPH_COMPARE_FUNCTION)(\n    _In_ PVOID Item1,\n    _In_ PVOID Item2,\n    _In_opt_ PVOID Context\n    );\n\n// Pointer list\n\nextern PPH_OBJECT_TYPE PhPointerListType;\n\n/**\n * A pointer list structure. The pointer list is similar to the normal list structure, but both\n * insertions and deletions occur in constant time. The list is not ordered.\n */\ntypedef struct _PH_POINTER_LIST\n{\n    /** The number of pointers in the list. */\n    ULONG Count;\n    /** The number of pointers for which storage is allocated. */\n    ULONG AllocatedCount;\n    /** Index into pointer array for free list. */\n    ULONG FreeEntry;\n    /** Index of next usable index into pointer array. */\n    ULONG NextEntry;\n    /** The array of pointers. */\n    PVOID *Items;\n} PH_POINTER_LIST, *PPH_POINTER_LIST;\n\n#define PH_IS_LIST_POINTER_VALID(Pointer) (!((ULONG_PTR)(Pointer) & 0x1))\n\nPHLIBAPI\nPPH_POINTER_LIST\nNTAPI\nPhCreatePointerList(\n    _In_ ULONG InitialCapacity\n    );\n\nPHLIBAPI\nHANDLE\nNTAPI\nPhAddItemPointerList(\n    _Inout_ PPH_POINTER_LIST PointerList,\n    _In_ PVOID Pointer\n    );\n\nPHLIBAPI\nBOOLEAN\nNTAPI\nPhEnumPointerListEx(\n    _In_ PPH_POINTER_LIST PointerList,\n    _Inout_ PULONG EnumerationKey,\n    _Out_ PVOID *Pointer,\n    _Out_ PHANDLE PointerHandle\n    );\n\nPHLIBAPI\nHANDLE\nNTAPI\nPhFindItemPointerList(\n    _In_ PPH_POINTER_LIST PointerList,\n    _In_ PVOID Pointer\n    );\n\nPHLIBAPI\nVOID\nNTAPI\nPhRemoveItemPointerList(\n    _Inout_ PPH_POINTER_LIST PointerList,\n    _In_ HANDLE PointerHandle\n    );\n\nFORCEINLINE\nBOOLEAN\nPhEnumPointerList(\n    _In_ PPH_POINTER_LIST PointerList,\n    _Inout_ PULONG EnumerationKey,\n    _Out_ PVOID *Pointer\n    )\n{\n    while (*EnumerationKey < PointerList->NextEntry)\n    {\n        PVOID pointer = PointerList->Items[*EnumerationKey];\n\n        (*EnumerationKey)++;\n\n        if (PH_IS_LIST_POINTER_VALID(pointer))\n        {\n            *Pointer = pointer;\n            return TRUE;\n        }\n    }\n\n    return FALSE;\n}\n\n// Hash\n\ntypedef struct _PH_HASH_ENTRY\n{\n    struct _PH_HASH_ENTRY *Next;\n    ULONG Hash;\n} PH_HASH_ENTRY, *PPH_HASH_ENTRY;\n\n#define PH_HASH_SET_INIT { 0 }\n#define PH_HASH_SET_SIZE(Buckets) (sizeof(Buckets) / sizeof(PPH_HASH_ENTRY))\n\n/**\n * Initializes a hash set.\n *\n * \\param Buckets The bucket array.\n * \\param NumberOfBuckets The number of buckets.\n */\nFORCEINLINE\nVOID\nPhInitializeHashSet(\n    _Out_ PPH_HASH_ENTRY *Buckets,\n    _In_ ULONG NumberOfBuckets\n    )\n{\n    memset(Buckets, 0, sizeof(PPH_HASH_ENTRY) * NumberOfBuckets);\n}\n\n/**\n * Allocates and initializes a hash set.\n *\n * \\param NumberOfBuckets The number of buckets.\n *\n * \\return The allocated hash set. You must free it with PhFree() when you no longer need it.\n */\nFORCEINLINE\nPPH_HASH_ENTRY *\nPhCreateHashSet(\n    _In_ ULONG NumberOfBuckets\n    )\n{\n    PPH_HASH_ENTRY *buckets;\n\n    buckets = (PPH_HASH_ENTRY *)PhAllocate(sizeof(PPH_HASH_ENTRY) * NumberOfBuckets);\n    PhInitializeHashSet(buckets, NumberOfBuckets);\n\n    return buckets;\n}\n\n/**\n * Determines the number of entries in a hash set.\n *\n * \\param Buckets The bucket array.\n * \\param NumberOfBuckets The number of buckets.\n *\n * \\return The number of entries in the hash set.\n */\nFORCEINLINE\nULONG\nPhCountHashSet(\n    _In_ PPH_HASH_ENTRY *Buckets,\n    _In_ ULONG NumberOfBuckets\n    )\n{\n    ULONG i;\n    PPH_HASH_ENTRY entry;\n    ULONG count;\n\n    count = 0;\n\n    for (i = 0; i < NumberOfBuckets; i++)\n    {\n        for (entry = Buckets[i]; entry; entry = entry->Next)\n            count++;\n    }\n\n    return count;\n}\n\n/**\n * Moves entries from one hash set to another.\n *\n * \\param NewBuckets The new bucket array.\n * \\param NumberOfNewBuckets The number of buckets in \\a NewBuckets.\n * \\param OldBuckets The old bucket array.\n * \\param NumberOfOldBuckets The number of buckets in \\a OldBuckets.\n *\n * \\remarks \\a NewBuckets and \\a OldBuckets must be different.\n */\nFORCEINLINE\nVOID\nPhDistributeHashSet(\n    _Inout_ PPH_HASH_ENTRY *NewBuckets,\n    _In_ ULONG NumberOfNewBuckets,\n    _In_ PPH_HASH_ENTRY *OldBuckets,\n    _In_ ULONG NumberOfOldBuckets\n    )\n{\n    ULONG i;\n    PPH_HASH_ENTRY entry;\n    PPH_HASH_ENTRY nextEntry;\n    ULONG index;\n\n    for (i = 0; i < NumberOfOldBuckets; i++)\n    {\n        entry = OldBuckets[i];\n\n        while (entry)\n        {\n            nextEntry = entry->Next;\n\n            index = entry->Hash & (NumberOfNewBuckets - 1);\n            entry->Next = NewBuckets[index];\n            NewBuckets[index] = entry;\n\n            entry = nextEntry;\n        }\n    }\n}\n\n/**\n * Adds an entry to a hash set.\n *\n * \\param Buckets The bucket array.\n * \\param NumberOfBuckets The number of buckets.\n * \\param Entry The entry.\n * \\param Hash The hash for the entry.\n *\n * \\remarks This function does not check for duplicates.\n */\nFORCEINLINE\nVOID\nPhAddEntryHashSet(\n    _Inout_ PPH_HASH_ENTRY *Buckets,\n    _In_ ULONG NumberOfBuckets,\n    _Out_ PPH_HASH_ENTRY Entry,\n    _In_ ULONG Hash\n    )\n{\n    ULONG index;\n\n    index = Hash & (NumberOfBuckets - 1);\n\n    Entry->Hash = Hash;\n    Entry->Next = Buckets[index];\n    Buckets[index] = Entry;\n}\n\n/**\n * Begins the process of finding an entry in a hash set.\n *\n * \\param Buckets The bucket array.\n * \\param NumberOfBuckets The number of buckets.\n * \\param Hash The hash for the entry.\n *\n * \\return The first entry in the chain.\n *\n * \\remarks If the function returns NULL, the entry does not exist in the hash set.\n */\nFORCEINLINE\nPPH_HASH_ENTRY\nPhFindEntryHashSet(\n    _In_ PPH_HASH_ENTRY *Buckets,\n    _In_ ULONG NumberOfBuckets,\n    _In_ ULONG Hash\n    )\n{\n    return Buckets[Hash & (NumberOfBuckets - 1)];\n}\n\n/**\n * Removes an entry from a hash set.\n *\n * \\param Buckets The bucket array.\n * \\param NumberOfBuckets The number of buckets.\n * \\param Entry An entry present in the hash set.\n */\nFORCEINLINE\nVOID\nPhRemoveEntryHashSet(\n    _Inout_ PPH_HASH_ENTRY *Buckets,\n    _In_ ULONG NumberOfBuckets,\n    _Inout_ PPH_HASH_ENTRY Entry\n    )\n{\n    ULONG index;\n    PPH_HASH_ENTRY entry;\n    PPH_HASH_ENTRY previousEntry;\n\n    index = Entry->Hash & (NumberOfBuckets - 1);\n    previousEntry = NULL;\n\n    entry = Buckets[index];\n\n    do\n    {\n        if (entry == Entry)\n        {\n            if (!previousEntry)\n                Buckets[index] = entry->Next;\n            else\n                previousEntry->Next = entry->Next;\n\n            return;\n        }\n\n        previousEntry = entry;\n        entry = entry->Next;\n    } while (entry);\n\n    // Entry doesn't actually exist in the set. This is a fatal logic error.\n    PhRaiseStatus(STATUS_INTERNAL_ERROR);\n}\n\n/**\n * Resizes a hash set.\n *\n * \\param Buckets A pointer to the bucket array. On return the new bucket array is stored in this\n * variable.\n * \\param NumberOfBuckets A pointer to the number of buckets. On return the new number of buckets is\n * stored in this variable.\n * \\param NewNumberOfBuckets The new number of buckets.\n */\nFORCEINLINE\nVOID\nPhResizeHashSet(\n    _Inout_ PPH_HASH_ENTRY **Buckets,\n    _Inout_ PULONG NumberOfBuckets,\n    _In_ ULONG NewNumberOfBuckets\n    )\n{\n    PPH_HASH_ENTRY *newBuckets;\n\n    newBuckets = PhCreateHashSet(NewNumberOfBuckets);\n    PhDistributeHashSet(newBuckets, NewNumberOfBuckets, *Buckets, *NumberOfBuckets);\n\n    PhFree(*Buckets);\n    *Buckets = newBuckets;\n    *NumberOfBuckets = NewNumberOfBuckets;\n}\n\n// Hashtable\n\nextern PPH_OBJECT_TYPE PhHashtableType;\n\ntypedef struct _PH_HASHTABLE_ENTRY\n{\n    /** Hash code of the entry. -1 if entry is unused. */\n    ULONG HashCode;\n    /**\n     * Either the index of the next entry in the bucket, the index of the next free entry, or -1 for\n     * invalid.\n     */\n    ULONG Next;\n    /** The beginning of user data. */\n    QUAD Body;\n} PH_HASHTABLE_ENTRY, *PPH_HASHTABLE_ENTRY;\n\n/**\n * A comparison function used by a hashtable.\n *\n * \\param Entry1 The first entry.\n * \\param Entry2 The second entry.\n *\n * \\return TRUE if the entries are equal, otherwise FALSE.\n */\ntypedef BOOLEAN (NTAPI *PPH_HASHTABLE_EQUAL_FUNCTION)(\n    _In_ PVOID Entry1,\n    _In_ PVOID Entry2\n    );\n\n/**\n * A hash function used by a hashtable.\n *\n * \\param Entry The entry.\n *\n * \\return A hash code for the entry.\n *\n * \\remarks\n * \\li Two entries which are considered to be equal by the comparison function must be given the\n * same hash code.\n * \\li Two different entries do not have to be given different hash codes.\n */\ntypedef ULONG (NTAPI *PPH_HASHTABLE_HASH_FUNCTION)(\n    _In_ PVOID Entry\n    );\n\n// Use power-of-two sizes instead of primes\n#define PH_HASHTABLE_POWER_OF_TWO_SIZE\n\n// Enables 2^32-1 possible hash codes instead of only 2^31\n//#define PH_HASHTABLE_FULL_HASH\n\n/**\n * A hashtable structure.\n */\ntypedef struct _PH_HASHTABLE\n{\n    /** Size of user data in each entry. */\n    ULONG EntrySize;\n    /** The comparison function. */\n    PPH_HASHTABLE_EQUAL_FUNCTION EqualFunction;\n    /** The hash function. */\n    PPH_HASHTABLE_HASH_FUNCTION HashFunction;\n\n    /** The number of allocated buckets. */\n    ULONG AllocatedBuckets;\n    /** The bucket array. */\n    PULONG Buckets;\n    /** The number of allocated entries. */\n    ULONG AllocatedEntries;\n    /** The entry array. */\n    PVOID Entries;\n\n    /** Number of entries in the hashtable. */\n    ULONG Count;\n    /** Index into entry array for free list. */\n    ULONG FreeEntry;\n    /**\n     * Index of next usable index into entry array, a.k.a. the count of entries that were ever\n     * allocated.\n     */\n    ULONG NextEntry;\n} PH_HASHTABLE, *PPH_HASHTABLE;\n\n#define PH_HASHTABLE_ENTRY_SIZE(InnerSize) (FIELD_OFFSET(PH_HASHTABLE_ENTRY, Body) + (InnerSize))\n#define PH_HASHTABLE_GET_ENTRY(Hashtable, Index) \\\n    ((PPH_HASHTABLE_ENTRY)PTR_ADD_OFFSET((Hashtable)->Entries, \\\n    PH_HASHTABLE_ENTRY_SIZE((Hashtable)->EntrySize) * (Index)))\n#define PH_HASHTABLE_GET_ENTRY_INDEX(Hashtable, Entry) \\\n    ((ULONG)(PTR_ADD_OFFSET(Entry, -(Hashtable)->Entries) / \\\n    PH_HASHTABLE_ENTRY_SIZE((Hashtable)->EntrySize)))\n\nPHLIBAPI\nPPH_HASHTABLE\nNTAPI\nPhCreateHashtable(\n    _In_ ULONG EntrySize,\n    _In_ PPH_HASHTABLE_EQUAL_FUNCTION EqualFunction,\n    _In_ PPH_HASHTABLE_HASH_FUNCTION HashFunction,\n    _In_ ULONG InitialCapacity\n    );\n\nPHLIBAPI\nPVOID\nNTAPI\nPhAddEntryHashtable(\n    _Inout_ PPH_HASHTABLE Hashtable,\n    _In_ PVOID Entry\n    );\n\nPHLIBAPI\nPVOID\nNTAPI\nPhAddEntryHashtableEx(\n    _Inout_ PPH_HASHTABLE Hashtable,\n    _In_ PVOID Entry,\n    _Out_opt_ PBOOLEAN Added\n    );\n\nPHLIBAPI\nVOID\nNTAPI\nPhClearHashtable(\n    _Inout_ PPH_HASHTABLE Hashtable\n    );\n\nPHLIBAPI\nBOOLEAN\nNTAPI\nPhEnumHashtable(\n    _In_ PPH_HASHTABLE Hashtable,\n    _Out_ PVOID *Entry,\n    _Inout_ PULONG EnumerationKey\n    );\n\nPHLIBAPI\nPVOID\nNTAPI\nPhFindEntryHashtable(\n    _In_ PPH_HASHTABLE Hashtable,\n    _In_ PVOID Entry\n    );\n\nPHLIBAPI\nBOOLEAN\nNTAPI\nPhRemoveEntryHashtable(\n    _Inout_ PPH_HASHTABLE Hashtable,\n    _In_ PVOID Entry\n    );\n\n// New faster enumeration method\n\ntypedef struct _PH_HASHTABLE_ENUM_CONTEXT\n{\n    ULONG_PTR Current;\n    ULONG_PTR End;\n    ULONG_PTR Step;\n} PH_HASHTABLE_ENUM_CONTEXT, *PPH_HASHTABLE_ENUM_CONTEXT;\n\nFORCEINLINE\nVOID\nPhBeginEnumHashtable(\n    _In_ PPH_HASHTABLE Hashtable,\n    _Out_ PPH_HASHTABLE_ENUM_CONTEXT Context\n    )\n{\n    Context->Current = (ULONG_PTR)Hashtable->Entries;\n    Context->Step = PH_HASHTABLE_ENTRY_SIZE(Hashtable->EntrySize);\n    Context->End = Context->Current + (ULONG_PTR)Hashtable->NextEntry * Context->Step;\n}\n\nFORCEINLINE\nPVOID\nPhNextEnumHashtable(\n    _Inout_ PPH_HASHTABLE_ENUM_CONTEXT Context\n    )\n{\n    PPH_HASHTABLE_ENTRY entry;\n\n    while (Context->Current != Context->End)\n    {\n        entry = (PPH_HASHTABLE_ENTRY)Context->Current;\n        Context->Current += Context->Step;\n\n        if (entry->HashCode != -1)\n            return &entry->Body;\n    }\n\n    return NULL;\n}\n\nPHLIBAPI\nULONG\nNTAPI\nPhHashBytes(\n    _In_reads_(Length) PUCHAR Bytes,\n    _In_ SIZE_T Length\n    );\n\nPHLIBAPI\nULONG\nNTAPI\nPhHashStringRef(\n    _In_ PPH_STRINGREF String,\n    _In_ BOOLEAN IgnoreCase\n    );\n\nFORCEINLINE\nULONG\nPhHashInt32(\n    _In_ ULONG Value\n    )\n{\n    // Java style.\n    Value ^= (Value >> 20) ^ (Value >> 12);\n    return Value ^ (Value >> 7) ^ (Value >> 4);\n}\n\nFORCEINLINE\nULONG\nPhHashInt64(\n    _In_ ULONG64 Value\n    )\n{\n    // http://www.concentric.net/~Ttwang/tech/inthash.htm\n\n    Value = ~Value + (Value << 18);\n    Value ^= Value >> 31;\n    Value *= 21;\n    Value ^= Value >> 11;\n    Value += Value << 6;\n    Value ^= Value >> 22;\n\n    return (ULONG)Value;\n}\n\nFORCEINLINE\nULONG\nPhHashIntPtr(\n    _In_ ULONG_PTR Value\n    )\n{\n#ifdef _WIN64\n    return PhHashInt64(Value);\n#else\n    return PhHashInt32(Value);\n#endif\n}\n\n// Simple hashtable\n\ntypedef struct _PH_KEY_VALUE_PAIR\n{\n    PVOID Key;\n    PVOID Value;\n} PH_KEY_VALUE_PAIR, *PPH_KEY_VALUE_PAIR;\n\nPHLIBAPI\nPPH_HASHTABLE\nNTAPI\nPhCreateSimpleHashtable(\n    _In_ ULONG InitialCapacity\n    );\n\nPHLIBAPI\nPVOID\nNTAPI\nPhAddItemSimpleHashtable(\n    _Inout_ PPH_HASHTABLE SimpleHashtable,\n    _In_opt_ PVOID Key,\n    _In_opt_ PVOID Value\n    );\n\nPHLIBAPI\nPVOID *\nNTAPI\nPhFindItemSimpleHashtable(\n    _In_ PPH_HASHTABLE SimpleHashtable,\n    _In_opt_ PVOID Key\n    );\n\nFORCEINLINE\nPVOID\nNTAPI\nPhFindItemSimpleHashtable2(\n    _In_ PPH_HASHTABLE SimpleHashtable,\n    _In_opt_ PVOID Key\n    )\n{\n    PVOID *item;\n\n    item = PhFindItemSimpleHashtable(SimpleHashtable, Key);\n\n    if (item)\n        return *item;\n    else\n        return NULL;\n}\n\nPHLIBAPI\nBOOLEAN\nNTAPI\nPhRemoveItemSimpleHashtable(\n    _Inout_ PPH_HASHTABLE SimpleHashtable,\n    _In_opt_ PVOID Key\n    );\n\n// Free list\n\ntypedef struct _PH_FREE_LIST\n{\n    SLIST_HEADER ListHead;\n\n    ULONG Count;\n    ULONG MaximumCount;\n    SIZE_T Size;\n} PH_FREE_LIST, *PPH_FREE_LIST;\n\ntypedef struct _PH_FREE_LIST_ENTRY\n{\n    SLIST_ENTRY ListEntry;\n    QUAD_PTR Body;\n} PH_FREE_LIST_ENTRY, *PPH_FREE_LIST_ENTRY;\n\n#ifdef _WIN64\nC_ASSERT(FIELD_OFFSET(PH_FREE_LIST_ENTRY, ListEntry) == 0x0);\nC_ASSERT(FIELD_OFFSET(PH_FREE_LIST_ENTRY, Body) == 0x10);\n#else\nC_ASSERT(FIELD_OFFSET(PH_FREE_LIST_ENTRY, ListEntry) == 0x0);\nC_ASSERT(FIELD_OFFSET(PH_FREE_LIST_ENTRY, Body) == 0x8);\n#endif\n\nPHLIBAPI\nVOID\nNTAPI\nPhInitializeFreeList(\n    _Out_ PPH_FREE_LIST FreeList,\n    _In_ SIZE_T Size,\n    _In_ ULONG MaximumCount\n    );\n\nPHLIBAPI\nVOID\nNTAPI\nPhDeleteFreeList(\n    _Inout_ PPH_FREE_LIST FreeList\n    );\n\nPHLIBAPI\nPVOID\nNTAPI\nPhAllocateFromFreeList(\n    _Inout_ PPH_FREE_LIST FreeList\n    );\n\nPHLIBAPI\nVOID\nNTAPI\nPhFreeToFreeList(\n    _Inout_ PPH_FREE_LIST FreeList,\n    _In_ PVOID Memory\n    );\n\n// Callback\n\n/**\n * A callback function.\n *\n * \\param Parameter A value given to all callback functions being notified.\n * \\param Context A user-defined value passed to PhRegisterCallback().\n */\ntypedef VOID (NTAPI *PPH_CALLBACK_FUNCTION)(\n    _In_opt_ PVOID Parameter,\n    _In_opt_ PVOID Context\n    );\n\n/** A callback registration structure. */\ntypedef struct _PH_CALLBACK_REGISTRATION\n{\n    /** The list entry in the callbacks list. */\n    LIST_ENTRY ListEntry;\n    /** The callback function. */\n    PPH_CALLBACK_FUNCTION Function;\n    /** A user-defined value to be passed to the callback function. */\n    PVOID Context;\n    /** A value indicating whether the registration structure is being used. */\n    LONG Busy;\n    /** Whether the registration structure is being removed. */\n    BOOLEAN Unregistering;\n    BOOLEAN Reserved;\n    /** Flags controlling the callback. */\n    USHORT Flags;\n} PH_CALLBACK_REGISTRATION, *PPH_CALLBACK_REGISTRATION;\n\n/**\n * A callback structure. The callback object allows multiple callback functions to be registered and\n * notified in a thread-safe way.\n */\ntypedef struct _PH_CALLBACK\n{\n    /** The list of registered callbacks. */\n    LIST_ENTRY ListHead;\n    /** A lock protecting the callbacks list. */\n    PH_QUEUED_LOCK ListLock;\n    /** A condition variable pulsed when the callback becomes free. */\n    PH_CONDITION BusyCondition;\n} PH_CALLBACK, *PPH_CALLBACK;\n\n#define PH_CALLBACK_DECLARE(Name) PH_CALLBACK Name = { &Name.ListHead, &Name.ListHead, PH_QUEUED_LOCK_INIT, PH_CONDITION_INIT }\n\nPHLIBAPI\nVOID\nNTAPI\nPhInitializeCallback(\n    _Out_ PPH_CALLBACK Callback\n    );\n\nPHLIBAPI\nVOID\nNTAPI\nPhDeleteCallback(\n    _Inout_ PPH_CALLBACK Callback\n    );\n\nPHLIBAPI\nVOID\nNTAPI\nPhRegisterCallback(\n    _Inout_ PPH_CALLBACK Callback,\n    _In_ PPH_CALLBACK_FUNCTION Function,\n    _In_opt_ PVOID Context,\n    _Out_ PPH_CALLBACK_REGISTRATION Registration\n    );\n\nPHLIBAPI\nVOID\nNTAPI\nPhRegisterCallbackEx(\n    _Inout_ PPH_CALLBACK Callback,\n    _In_ PPH_CALLBACK_FUNCTION Function,\n    _In_opt_ PVOID Context,\n    _In_ USHORT Flags,\n    _Out_ PPH_CALLBACK_REGISTRATION Registration\n    );\n\nPHLIBAPI\nVOID\nNTAPI\nPhUnregisterCallback(\n    _Inout_ PPH_CALLBACK Callback,\n    _Inout_ PPH_CALLBACK_REGISTRATION Registration\n    );\n\nPHLIBAPI\nVOID\nNTAPI\nPhInvokeCallback(\n    _In_ PPH_CALLBACK Callback,\n    _In_opt_ PVOID Parameter\n    );\n\n// General\n\nPHLIBAPI\nULONG\nNTAPI\nPhGetPrimeNumber(\n    _In_ ULONG Minimum\n    );\n\nPHLIBAPI\nULONG\nNTAPI\nPhRoundUpToPowerOfTwo(\n    _In_ ULONG Number\n    );\n\nPHLIBAPI\nULONG\nNTAPI\nPhExponentiate(\n    _In_ ULONG Base,\n    _In_ ULONG Exponent\n    );\n\nPHLIBAPI\nULONG64\nNTAPI\nPhExponentiate64(\n    _In_ ULONG64 Base,\n    _In_ ULONG Exponent\n    );\n\nPHLIBAPI\nBOOLEAN\nNTAPI\nPhHexStringToBuffer(\n    _In_ PPH_STRINGREF String,\n    _Out_writes_bytes_(String->Length / sizeof(WCHAR) / 2) PUCHAR Buffer\n    );\n\nPHLIBAPI\nPPH_STRING\nNTAPI\nPhBufferToHexString(\n    _In_reads_bytes_(Length) PUCHAR Buffer,\n    _In_ ULONG Length\n    );\n\nPPH_STRING\nNTAPI\nPhBufferToHexStringEx(\n    _In_reads_bytes_(Length) PUCHAR Buffer,\n    _In_ ULONG Length,\n    _In_ BOOLEAN UpperCase\n    );\n\nPHLIBAPI\nBOOLEAN\nNTAPI\nPhStringToInteger64(\n    _In_ PPH_STRINGREF String,\n    _In_opt_ ULONG Base,\n    _Out_opt_ PLONG64 Integer\n    );\n\nPHLIBAPI\nBOOLEAN\nNTAPI\nPhStringToDouble(\n    _In_ PPH_STRINGREF String,\n    _Reserved_ ULONG Base,\n    _Out_opt_ DOUBLE *Double\n    );\n\nPHLIBAPI\nPPH_STRING\nNTAPI\nPhIntegerToString64(\n    _In_ LONG64 Integer,\n    _In_opt_ ULONG Base,\n    _In_ BOOLEAN Signed\n    );\n\n#define PH_TIMESPAN_STR_LEN 30\n#define PH_TIMESPAN_STR_LEN_1 (PH_TIMESPAN_STR_LEN + 1)\n\n#define PH_TIMESPAN_HMS 0\n#define PH_TIMESPAN_HMSM 1\n#define PH_TIMESPAN_DHMS 2\n\nPHLIBAPI\nVOID\nNTAPI\nPhPrintTimeSpan(\n    _Out_writes_(PH_TIMESPAN_STR_LEN_1) PWSTR Destination,\n    _In_ ULONG64 Ticks,\n    _In_opt_ ULONG Mode\n    );\n\nPHLIBAPI\nVOID\nNTAPI\nPhFillMemoryUlong(\n    _Inout_updates_(Count) _Needs_align_(4) PULONG Memory,\n    _In_ ULONG Value,\n    _In_ SIZE_T Count\n    );\n\nPHLIBAPI\nVOID\nNTAPI\nPhDivideSinglesBySingle(\n    _Inout_updates_(Count) PFLOAT A,\n    _In_ FLOAT B,\n    _In_ SIZE_T Count\n    );\n\n// Auto-dereference convenience functions\n\nFORCEINLINE\nPPH_STRING\nPhaCreateString(\n    _In_ PWSTR Buffer\n    )\n{\n    return PH_AUTO_T(PH_STRING, PhCreateString(Buffer));\n}\n\nFORCEINLINE\nPPH_STRING\nPhaCreateStringEx(\n    _In_opt_ PWSTR Buffer,\n    _In_ SIZE_T Length\n    )\n{\n    return PH_AUTO_T(PH_STRING, PhCreateStringEx(Buffer, Length));\n}\n\nFORCEINLINE\nPPH_STRING\nPhaDuplicateString(\n    _In_ PPH_STRING String\n    )\n{\n    return PH_AUTO_T(PH_STRING, PhDuplicateString(String));\n}\n\nFORCEINLINE\nPPH_STRING\nPhaConcatStrings(\n    _In_ ULONG Count,\n    ...\n    )\n{\n    va_list argptr;\n\n    va_start(argptr, Count);\n\n    return PH_AUTO_T(PH_STRING, PhConcatStrings_V(Count, argptr));\n}\n\nFORCEINLINE\nPPH_STRING\nPhaConcatStrings2(\n    _In_ PWSTR String1,\n    _In_ PWSTR String2\n    )\n{\n    return PH_AUTO_T(PH_STRING, PhConcatStrings2(String1, String2));\n}\n\nFORCEINLINE\nPPH_STRING\nPhaFormatString(\n    _In_ _Printf_format_string_ PWSTR Format,\n    ...\n    )\n{\n    va_list argptr;\n\n    va_start(argptr, Format);\n\n    return PH_AUTO_T(PH_STRING, PhFormatString_V(Format, argptr));\n}\n\nFORCEINLINE\nPPH_STRING\nPhaLowerString(\n    _In_ PPH_STRING String\n    )\n{\n    PPH_STRING newString;\n\n    newString = PhaDuplicateString(String);\n    _wcslwr(newString->Buffer);\n\n    return newString;\n}\n\nFORCEINLINE\nPPH_STRING\nPhaUpperString(\n    _In_ PPH_STRING String\n    )\n{\n    PPH_STRING newString;\n\n    newString = PhaDuplicateString(String);\n    _wcsupr(newString->Buffer);\n\n    return newString;\n}\n\nFORCEINLINE\nPPH_STRING\nPhaSubstring(\n    _In_ PPH_STRING String,\n    _In_ SIZE_T StartIndex,\n    _In_ SIZE_T Count\n    )\n{\n    return PH_AUTO_T(PH_STRING, PhSubstring(String, StartIndex, Count));\n}\n\n// Format\n\ntypedef enum _PH_FORMAT_TYPE\n{\n    CharFormatType,\n    StringFormatType,\n    StringZFormatType,\n    MultiByteStringFormatType,\n    MultiByteStringZFormatType,\n    Int32FormatType,\n    Int64FormatType,\n    IntPtrFormatType,\n    UInt32FormatType,\n    UInt64FormatType,\n    UIntPtrFormatType,\n    DoubleFormatType,\n    SizeFormatType,\n    FormatTypeMask = 0x3f,\n\n    /** If not specified, for floating-point 6 is assumed **/\n    FormatUsePrecision = 0x40,\n    /** If not specified, ' ' is assumed */\n    FormatUsePad = 0x80,\n    /** If not specified, 10 is assumed */\n    FormatUseRadix = 0x100,\n    /** If not specified, the default value is assumed */\n    FormatUseParameter = 0x200,\n\n    // Floating-point flags\n    /** Use standard form instead of normal form */\n    FormatStandardForm = 0x1000,\n    /** Use hexadecimal form instead of normal form */\n    FormatHexadecimalForm = 0x2000,\n    /** Reserved */\n    FormatForceDecimalPoint = 0x4000,\n    /** Trailing zeros and possibly the decimal point are trimmed */\n    FormatCropZeros = 0x8000,\n\n    // Floating-point and integer flags\n    /** Group digits (with floating-point, only works when in normal form) */\n    FormatGroupDigits = 0x10000,\n    /** Always insert a prefix, '+' for positive and '-' for negative */\n    FormatPrefixSign = 0x20000,\n    /**\n     * Pad left with zeros, taking into consideration the sign. Width must be specified.\n     * Format*Align cannot be used in conjunction with this flag. If FormatGroupDigits is specified,\n     * this flag is ignored.\n     */\n    FormatPadZeros = 0x40000,\n\n    // General flags\n    /** Applies left alignment. Width must be specified. */\n    FormatLeftAlign = 0x80000000,\n    /** Applies right alignment. Width must be specified. */\n    FormatRightAlign = 0x40000000,\n    /** Make characters uppercase (only available for some types) */\n    FormatUpperCase = 0x20000000\n} PH_FORMAT_TYPE;\n\n/** Describes an element to be formatted to a string. */\ntypedef struct _PH_FORMAT\n{\n    /** Specifies the type of the element and optional flags. */\n    PH_FORMAT_TYPE Type;\n    /**\n     * The precision of the element. The meaning of this field depends on the element type. For\n     * \\a Double and \\a Size, this field specifies the number of decimal points to include.\n     */\n    USHORT Precision;\n    /**\n     * The width of the element. This field specifies the minimum number of characters to output.\n     * The remaining space is padded with either spaces, zeros, or a custom character.\n     */\n    USHORT Width;\n    /** The pad character. */\n    WCHAR Pad;\n    /**\n     * The meaning of this field depends on the element type. For integer types, this field\n     * specifies the base to convert the number into. For \\a Size, this field specifies the maximum\n     * size unit.\n     */\n    UCHAR Radix;\n    /**\n     * The meaning of this field depends on the element type. For \\a Size, this field specifies the\n     * minimum size unit.\n     */\n    UCHAR Parameter;\n    union\n    {\n        WCHAR Char;\n        PH_STRINGREF String;\n        PWSTR StringZ;\n        PH_BYTESREF MultiByteString;\n        PSTR MultiByteStringZ;\n        LONG Int32;\n        LONG64 Int64;\n        LONG_PTR IntPtr;\n        ULONG UInt32;\n        ULONG64 UInt64;\n        ULONG_PTR UIntPtr;\n        DOUBLE Double;\n\n        ULONG64 Size;\n    } u;\n} PH_FORMAT, *PPH_FORMAT;\n\n// Convenience macros\n#define PhInitFormatC(f, v) do { (f)->Type = CharFormatType; (f)->u.Char = (v); } while (0)\n#define PhInitFormatS(f, v) do { (f)->Type = StringFormatType; PhInitializeStringRef(&(f)->u.String, (v)); } while (0)\n#define PhInitFormatSR(f, v) do { (f)->Type = StringFormatType; (f)->u.String = (v); } while (0)\n#define PhInitFormatMultiByteS(f, v) do { (f)->Type = MultiByteStringFormatType; PhInitializeBytesRef(&(f)->u.MultiByteString, (v)); } while (0)\n#define PhInitFormatD(f, v) do { (f)->Type = Int32FormatType; (f)->u.Int32 = (v); } while (0)\n#define PhInitFormatU(f, v) do { (f)->Type = UInt32FormatType; (f)->u.UInt32 = (v); } while (0)\n#define PhInitFormatX(f, v) do { (f)->Type = UInt32FormatType | FormatUseRadix; (f)->u.UInt32 = (v); (f)->Radix = 16; } while (0)\n#define PhInitFormatI64D(f, v) do { (f)->Type = Int64FormatType; (f)->u.Int64 = (v); } while (0)\n#define PhInitFormatI64U(f, v) do { (f)->Type = UInt64FormatType; (f)->u.UInt64 = (v); } while (0)\n#define PhInitFormatI64X(f, v) do { (f)->Type = UInt64FormatType | FormatUseRadix; (f)->u.UInt64 = (v); (f)->Radix = 16; } while (0)\n#define PhInitFormatIU(f, v) do { (f)->Type = UIntPtrFormatType; (f)->u.UIntPtr = (v); } while (0)\n#define PhInitFormatIX(f, v) do { (f)->Type = UIntPtrFormatType | FormatUseRadix; (f)->u.UIntPtr = (v); (f)->Radix = 16; } while (0)\n#define PhInitFormatF(f, v, p) do { (f)->Type = DoubleFormatType | FormatUsePrecision; (f)->u.Double = (v); (f)->Precision = (p); } while (0)\n#define PhInitFormatE(f, v, p) do { (f)->Type = DoubleFormatType | FormatStandardForm | FormatUsePrecision; (f)->u.Double = (v); (f)->Precision = (p); } while (0)\n#define PhInitFormatA(f, v, p) do { (f)->Type = DoubleFormatType | FormatHexadecimalForm | FormatUsePrecision; (f)->u.Double = (v); (f)->Precision = (p); } while (0)\n#define PhInitFormatSize(f, v) do { (f)->Type = SizeFormatType; (f)->u.Size = (v); } while (0)\n\nPHLIBAPI\nPPH_STRING\nNTAPI\nPhFormat(\n    _In_reads_(Count) PPH_FORMAT Format,\n    _In_ ULONG Count,\n    _In_opt_ SIZE_T InitialCapacity\n    );\n\nPHLIBAPI\nBOOLEAN\nNTAPI\nPhFormatToBuffer(\n    _In_reads_(Count) PPH_FORMAT Format,\n    _In_ ULONG Count,\n    _Out_writes_bytes_opt_(BufferLength) PWSTR Buffer,\n    _In_opt_ SIZE_T BufferLength,\n    _Out_opt_ PSIZE_T ReturnLength\n    );\n\n// error\n\nPHLIBAPI\nULONG\nNTAPI\nPhNtStatusToDosError(\n    _In_ NTSTATUS Status\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhDosErrorToNtStatus(\n    _In_ ULONG DosError\n    );\n\nPHLIBAPI\nBOOLEAN\nNTAPI\nPhNtStatusFileNotFound(\n    _In_ NTSTATUS Status\n    );\n\n// Generic tree definitions\n\ntypedef enum _PH_TREE_ENUMERATION_ORDER\n{\n    TreeEnumerateInOrder,\n    TreeEnumerateInReverseOrder\n} PH_TREE_ENUMERATION_ORDER;\n\n#define PhIsLeftChildElement(Links) ((Links)->Parent->Left == (Links))\n#define PhIsRightChildElement(Links) ((Links)->Parent->Right == (Links))\n\n// avltree\n\ntypedef struct _PH_AVL_LINKS\n{\n    struct _PH_AVL_LINKS *Parent;\n    struct _PH_AVL_LINKS *Left;\n    struct _PH_AVL_LINKS *Right;\n    LONG Balance;\n} PH_AVL_LINKS, *PPH_AVL_LINKS;\n\nstruct _PH_AVL_TREE;\n\ntypedef LONG (NTAPI *PPH_AVL_TREE_COMPARE_FUNCTION)(\n    _In_ PPH_AVL_LINKS Links1,\n    _In_ PPH_AVL_LINKS Links2\n    );\n\ntypedef struct _PH_AVL_TREE\n{\n    PH_AVL_LINKS Root; // Right contains real root\n    ULONG Count;\n\n    PPH_AVL_TREE_COMPARE_FUNCTION CompareFunction;\n} PH_AVL_TREE, *PPH_AVL_TREE;\n\n#define PH_AVL_TREE_INIT(CompareFunction) { { NULL, NULL, NULL, 0 }, 0, CompareFunction }\n\n#define PhRootElementAvlTree(Tree) ((Tree)->Root.Right)\n\nPHLIBAPI\nVOID\nNTAPI\nPhInitializeAvlTree(\n    _Out_ PPH_AVL_TREE Tree,\n    _In_ PPH_AVL_TREE_COMPARE_FUNCTION CompareFunction\n    );\n\nPHLIBAPI\nPPH_AVL_LINKS\nNTAPI\nPhAddElementAvlTree(\n    _Inout_ PPH_AVL_TREE Tree,\n    _Out_ PPH_AVL_LINKS Element\n    );\n\nPHLIBAPI\nVOID\nNTAPI\nPhRemoveElementAvlTree(\n    _Inout_ PPH_AVL_TREE Tree,\n    _Inout_ PPH_AVL_LINKS Element\n    );\n\nPHLIBAPI\nPPH_AVL_LINKS\nNTAPI\nPhFindElementAvlTree(\n    _In_ PPH_AVL_TREE Tree,\n    _In_ PPH_AVL_LINKS Element\n    );\n\nPHLIBAPI\nPPH_AVL_LINKS\nNTAPI\nPhLowerBoundElementAvlTree(\n    _In_ PPH_AVL_TREE Tree,\n    _In_ PPH_AVL_LINKS Element\n    );\n\nPHLIBAPI\nPPH_AVL_LINKS\nNTAPI\nPhUpperBoundElementAvlTree(\n    _In_ PPH_AVL_TREE Tree,\n    _In_ PPH_AVL_LINKS Element\n    );\n\nPHLIBAPI\nPPH_AVL_LINKS\nNTAPI\nPhLowerDualBoundElementAvlTree(\n    _In_ PPH_AVL_TREE Tree,\n    _In_ PPH_AVL_LINKS Element\n    );\n\nPHLIBAPI\nPPH_AVL_LINKS\nNTAPI\nPhUpperDualBoundElementAvlTree(\n    _In_ PPH_AVL_TREE Tree,\n    _In_ PPH_AVL_LINKS Element\n    );\n\nPHLIBAPI\nPPH_AVL_LINKS\nNTAPI\nPhMinimumElementAvlTree(\n    _In_ PPH_AVL_TREE Tree\n    );\n\nPHLIBAPI\nPPH_AVL_LINKS\nNTAPI\nPhMaximumElementAvlTree(\n    _In_ PPH_AVL_TREE Tree\n    );\n\nPHLIBAPI\nPPH_AVL_LINKS\nNTAPI\nPhSuccessorElementAvlTree(\n    _In_ PPH_AVL_LINKS Element\n    );\n\nPHLIBAPI\nPPH_AVL_LINKS\nNTAPI\nPhPredecessorElementAvlTree(\n    _In_ PPH_AVL_LINKS Element\n    );\n\ntypedef BOOLEAN (NTAPI *PPH_ENUM_AVL_TREE_CALLBACK)(\n    _In_ PPH_AVL_TREE Tree,\n    _In_ PPH_AVL_LINKS Element,\n    _In_opt_ PVOID Context\n    );\n\nPHLIBAPI\nVOID\nNTAPI\nPhEnumAvlTree(\n    _In_ PPH_AVL_TREE Tree,\n    _In_ PH_TREE_ENUMERATION_ORDER Order,\n    _In_ PPH_ENUM_AVL_TREE_CALLBACK Callback,\n    _In_opt_ PVOID Context\n    );\n\n#ifdef __cplusplus\n}\n#endif\n\n#endif\n"
  },
  {
    "path": "third_party/phlib/include/phconfig.h",
    "content": "#ifndef _PH_PHCONFIG_H\n#define _PH_PHCONFIG_H\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\n#define _User_set_\n\nPHLIBAPI extern _User_set_ PVOID PhInstanceHandle;\nPHLIBAPI extern _User_set_ PWSTR PhApplicationName;\nPHLIBAPI extern _User_set_ ULONG PhGlobalDpi;\nPHLIBAPI extern PVOID PhHeapHandle;\nPHLIBAPI extern RTL_OSVERSIONINFOEXW PhOsVersion;\nPHLIBAPI extern SYSTEM_BASIC_INFORMATION PhSystemBasicInformation;\nPHLIBAPI extern ULONG WindowsVersion;\n\nPHLIBAPI extern ACCESS_MASK ProcessQueryAccess;\nPHLIBAPI extern ACCESS_MASK ProcessAllAccess;\nPHLIBAPI extern ACCESS_MASK ThreadQueryAccess;\nPHLIBAPI extern ACCESS_MASK ThreadSetAccess;\nPHLIBAPI extern ACCESS_MASK ThreadAllAccess;\n\n#define WINDOWS_ANCIENT 0\n#define WINDOWS_XP 51\n#define WINDOWS_VISTA 60\n#define WINDOWS_7 61\n#define WINDOWS_8 62\n#define WINDOWS_8_1 63\n#define WINDOWS_10 100 // TH1\n#define WINDOWS_10_TH2 101\n#define WINDOWS_10_RS1 102\n#define WINDOWS_10_RS2 103\n#define WINDOWS_10_RS3 104\n#define WINDOWS_NEW MAXLONG\n\n#define WINDOWS_HAS_IMMERSIVE (WindowsVersion >= WINDOWS_8)\n\n// Debugging\n\n#ifdef DEBUG\n#define dprintf(format, ...) DbgPrint(format, __VA_ARGS__)\n#else\n#define dprintf(format, ...)\n#endif\n\n// global\n\n// Initialization flags\n\n// Features\n\n// Imports\n\n#define PHLIB_INIT_MODULE_RESERVED1 0x1\n#define PHLIB_INIT_MODULE_RESERVED2 0x2\n/** Needed to use work queues. */\n#define PHLIB_INIT_MODULE_RESERVED3 0x4\n#define PHLIB_INIT_MODULE_RESERVED4 0x8\n/** Needed to use file streams. */\n#define PHLIB_INIT_MODULE_FILE_STREAM 0x10\n/** Needed to use symbol providers. */\n#define PHLIB_INIT_MODULE_SYMBOL_PROVIDER 0x20\n#define PHLIB_INIT_MODULE_RESERVED5 0x40\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhInitializePhLib(\n    VOID\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhInitializePhLibEx(\n    _In_ ULONG Flags,\n    _In_ PVOID ImageBaseAddress,\n    _In_opt_ SIZE_T HeapReserveSize,\n    _In_opt_ SIZE_T HeapCommitSize\n    );\n\n#ifdef _WIN64\nFORCEINLINE\nBOOLEAN\nPhIsExecutingInWow64(\n    VOID\n    )\n{\n    return FALSE;\n}\n#else\nPHLIBAPI\nBOOLEAN\nNTAPI\nPhIsExecutingInWow64(\n    VOID\n    );\n#endif\n\n#ifdef __cplusplus\n}\n#endif\n\n#endif\n"
  },
  {
    "path": "third_party/phlib/include/phdata.h",
    "content": "#ifndef _PH_PHDATA_H\n#define _PH_PHDATA_H\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\n// SIDs\n\nextern SID PhSeNobodySid;\n\nextern SID PhSeEveryoneSid;\n\nextern SID PhSeLocalSid;\n\nextern SID PhSeCreatorOwnerSid;\nextern SID PhSeCreatorGroupSid;\n\nextern SID PhSeDialupSid;\nextern SID PhSeNetworkSid;\nextern SID PhSeBatchSid;\nextern SID PhSeInteractiveSid;\nextern SID PhSeServiceSid;\nextern SID PhSeAnonymousLogonSid;\nextern SID PhSeProxySid;\nextern SID PhSeAuthenticatedUserSid;\nextern SID PhSeRestrictedCodeSid;\nextern SID PhSeTerminalServerUserSid;\nextern SID PhSeRemoteInteractiveLogonSid;\nextern SID PhSeLocalSystemSid;\nextern SID PhSeLocalServiceSid;\nextern SID PhSeNetworkServiceSid;\n\n// Unicode\n\nextern PH_STRINGREF PhUnicodeByteOrderMark;\n\n// Characters\n\nextern BOOLEAN PhCharIsPrintable[256];\nextern ULONG PhCharToInteger[256];\nextern CHAR PhIntegerToChar[69];\nextern CHAR PhIntegerToCharUpper[69];\n\n// CRC32\n\nextern ULONG PhCrc32Table[256];\n\n// Enums\n\nextern WCHAR *PhIoPriorityHintNames[MaxIoPriorityTypes];\nextern WCHAR *PhPagePriorityNames[MEMORY_PRIORITY_NORMAL + 1];\nextern WCHAR *PhKThreadStateNames[MaximumThreadState];\nextern WCHAR *PhKWaitReasonNames[MaximumWaitReason];\n\n#ifdef __cplusplus\n}\n#endif\n\n#endif\n"
  },
  {
    "path": "third_party/phlib/include/phintrnl.h",
    "content": "#ifndef _PH_PHINTRNL_H\n#define _PH_PHINTRNL_H\n\ntypedef struct _PHLIB_STATISTICS_BLOCK\n{\n    // basesup\n    ULONG BaseThreadsCreated;\n    ULONG BaseThreadsCreateFailed;\n    ULONG BaseStringBuildersCreated;\n    ULONG BaseStringBuildersResized;\n\n    // ref\n    ULONG RefObjectsCreated;\n    ULONG RefObjectsDestroyed;\n    ULONG RefObjectsAllocated;\n    ULONG RefObjectsFreed;\n    ULONG RefObjectsAllocatedFromSmallFreeList;\n    ULONG RefObjectsFreedToSmallFreeList;\n    ULONG RefObjectsAllocatedFromTypeFreeList;\n    ULONG RefObjectsFreedToTypeFreeList;\n    ULONG RefObjectsDeleteDeferred;\n    ULONG RefAutoPoolsCreated;\n    ULONG RefAutoPoolsDestroyed;\n    ULONG RefAutoPoolsDynamicAllocated;\n    ULONG RefAutoPoolsDynamicResized;\n\n    // queuedlock\n    ULONG QlBlockSpins;\n    ULONG QlBlockWaits;\n    ULONG QlAcquireExclusiveBlocks;\n    ULONG QlAcquireSharedBlocks;\n\n    // workqueue\n    ULONG WqWorkQueueThreadsCreated;\n    ULONG WqWorkQueueThreadsCreateFailed;\n    ULONG WqWorkItemsQueued;\n} PHLIB_STATISTICS_BLOCK;\n\n#ifdef DEBUG\nextern PHLIB_STATISTICS_BLOCK PhLibStatisticsBlock;\n#endif\n\n#ifdef DEBUG\n#define PHLIB_INC_STATISTIC(Name) (_InterlockedIncrement(&PhLibStatisticsBlock.Name))\n#else\n#define PHLIB_INC_STATISTIC(Name)\n#endif\n\n#endif\n"
  },
  {
    "path": "third_party/phlib/include/phnative.h",
    "content": "#ifndef _PH_PHNATIVE_H\n#define _PH_PHNATIVE_H\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\n/** The PID of the idle process. */\n#define SYSTEM_IDLE_PROCESS_ID ((HANDLE)0)\n/** The PID of the system process. */\n#define SYSTEM_PROCESS_ID ((HANDLE)4)\n\n#define SYSTEM_IDLE_PROCESS_NAME (L\"System Idle Process\")\n\n// General object-related function types\n\ntypedef NTSTATUS (NTAPI *PPH_OPEN_OBJECT)(\n    _Out_ PHANDLE Handle,\n    _In_ ACCESS_MASK DesiredAccess,\n    _In_opt_ PVOID Context\n    );\n\ntypedef NTSTATUS (NTAPI *PPH_GET_OBJECT_SECURITY)(\n    _Out_ PSECURITY_DESCRIPTOR *SecurityDescriptor,\n    _In_ SECURITY_INFORMATION SecurityInformation,\n    _In_opt_ PVOID Context\n    );\n\ntypedef NTSTATUS (NTAPI *PPH_SET_OBJECT_SECURITY)(\n    _In_ PSECURITY_DESCRIPTOR SecurityDescriptor,\n    _In_ SECURITY_INFORMATION SecurityInformation,\n    _In_opt_ PVOID Context\n    );\n\ntypedef struct _PH_TOKEN_ATTRIBUTES\n{\n    HANDLE TokenHandle;\n    struct\n    {\n        ULONG Elevated : 1;\n        ULONG ElevationType : 2;\n        ULONG ReservedBits : 29;\n    };\n    ULONG Reserved;\n} PH_TOKEN_ATTRIBUTES, *PPH_TOKEN_ATTRIBUTES;\n\nPHLIBAPI\nPH_TOKEN_ATTRIBUTES\nNTAPI\nPhGetOwnTokenAttributes(\n    VOID\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhOpenProcess(\n    _Out_ PHANDLE ProcessHandle,\n    _In_ ACCESS_MASK DesiredAccess,\n    _In_ HANDLE ProcessId\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhOpenProcessPublic(\n    _Out_ PHANDLE ProcessHandle,\n    _In_ ACCESS_MASK DesiredAccess,\n    _In_ HANDLE ProcessId\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhOpenThread(\n    _Out_ PHANDLE ThreadHandle,\n    _In_ ACCESS_MASK DesiredAccess,\n    _In_ HANDLE ThreadId\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhOpenThreadPublic(\n    _Out_ PHANDLE ThreadHandle,\n    _In_ ACCESS_MASK DesiredAccess,\n    _In_ HANDLE ThreadId\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhOpenThreadProcess(\n    _In_ HANDLE ThreadHandle,\n    _In_ ACCESS_MASK DesiredAccess,\n    _Out_ PHANDLE ProcessHandle\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhOpenProcessToken(\n    _In_ HANDLE ProcessHandle,\n    _In_ ACCESS_MASK DesiredAccess,\n    _Out_ PHANDLE TokenHandle\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhGetObjectSecurity(\n    _In_ HANDLE Handle,\n    _In_ SECURITY_INFORMATION SecurityInformation,\n    _Out_ PSECURITY_DESCRIPTOR *SecurityDescriptor\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhSetObjectSecurity(\n    _In_ HANDLE Handle,\n    _In_ SECURITY_INFORMATION SecurityInformation,\n    _In_ PSECURITY_DESCRIPTOR SecurityDescriptor\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhTerminateProcess(\n    _In_ HANDLE ProcessHandle,\n    _In_ NTSTATUS ExitStatus\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhTerminateProcessPublic(\n    _In_ HANDLE ProcessHandle,\n    _In_ NTSTATUS ExitStatus\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhGetProcessImageFileName(\n    _In_ HANDLE ProcessHandle,\n    _Out_ PPH_STRING *FileName\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhGetProcessImageFileNameWin32(\n    _In_ HANDLE ProcessHandle,\n    _Out_ PPH_STRING *FileName\n    );\n\n/** Specifies a PEB string. */\ntypedef enum _PH_PEB_OFFSET\n{\n    PhpoCurrentDirectory,\n    PhpoDllPath,\n    PhpoImagePathName,\n    PhpoCommandLine,\n    PhpoWindowTitle,\n    PhpoDesktopInfo,\n    PhpoShellInfo,\n    PhpoRuntimeData,\n    PhpoTypeMask = 0xffff,\n\n    PhpoWow64 = 0x10000\n} PH_PEB_OFFSET;\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhGetProcessPebString(\n    _In_ HANDLE ProcessHandle,\n    _In_ PH_PEB_OFFSET Offset,\n    _Out_ PPH_STRING *String\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhGetProcessCommandLine(\n    _In_ HANDLE ProcessHandle,\n    _Out_ PPH_STRING *CommandLine\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhGetProcessWindowTitle(\n    _In_ HANDLE ProcessHandle,\n    _Out_ PULONG WindowFlags,\n    _Out_ PPH_STRING *WindowTitle\n    );\n\n#define PH_PROCESS_DEP_ENABLED 0x1\n#define PH_PROCESS_DEP_ATL_THUNK_EMULATION_DISABLED 0x2\n#define PH_PROCESS_DEP_PERMANENT 0x4\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhGetProcessDepStatus(\n    _In_ HANDLE ProcessHandle,\n    _Out_ PULONG DepStatus\n    );\n\n#define PH_GET_PROCESS_ENVIRONMENT_WOW64 0x1 // retrieve the WOW64 environment\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhGetProcessEnvironment(\n    _In_ HANDLE ProcessHandle,\n    _In_ ULONG Flags,\n    _Out_ PVOID *Environment,\n    _Out_ PULONG EnvironmentLength\n    );\n\ntypedef struct _PH_ENVIRONMENT_VARIABLE\n{\n    PH_STRINGREF Name;\n    PH_STRINGREF Value;\n} PH_ENVIRONMENT_VARIABLE, *PPH_ENVIRONMENT_VARIABLE;\n\nPHLIBAPI\nBOOLEAN\nNTAPI\nPhEnumProcessEnvironmentVariables(\n    _In_ PVOID Environment,\n    _In_ ULONG EnvironmentLength,\n    _Inout_ PULONG EnumerationKey,\n    _Out_ PPH_ENVIRONMENT_VARIABLE Variable\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhGetProcessMappedFileName(\n    _In_ HANDLE ProcessHandle,\n    _In_ PVOID BaseAddress,\n    _Out_ PPH_STRING *FileName\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhGetProcessWorkingSetInformation(\n    _In_ HANDLE ProcessHandle,\n    _Out_ PMEMORY_WORKING_SET_INFORMATION *WorkingSetInformation\n    );\n\ntypedef struct _PH_PROCESS_WS_COUNTERS\n{\n    SIZE_T NumberOfPages;\n    SIZE_T NumberOfPrivatePages;\n    SIZE_T NumberOfSharedPages;\n    SIZE_T NumberOfShareablePages;\n} PH_PROCESS_WS_COUNTERS, *PPH_PROCESS_WS_COUNTERS;\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhGetProcessWsCounters(\n    _In_ HANDLE ProcessHandle,\n    _Out_ PPH_PROCESS_WS_COUNTERS WsCounters\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhUnloadDllProcess(\n    _In_ HANDLE ProcessHandle,\n    _In_ PVOID BaseAddress,\n    _In_opt_ PLARGE_INTEGER Timeout\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhSetEnvironmentVariableRemote(\n    _In_ HANDLE ProcessHandle,\n    _In_ PPH_STRINGREF Name,\n    _In_opt_ PPH_STRINGREF Value,\n    _In_opt_ PLARGE_INTEGER Timeout\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhGetJobProcessIdList(\n    _In_ HANDLE JobHandle,\n    _Out_ PJOBOBJECT_BASIC_PROCESS_ID_LIST *ProcessIdList\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhQueryTokenVariableSize(\n    _In_ HANDLE TokenHandle,\n    _In_ TOKEN_INFORMATION_CLASS TokenInformationClass,\n    _Out_ PVOID *Buffer\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhGetTokenUser(\n    _In_ HANDLE TokenHandle,\n    _Out_ PTOKEN_USER *User\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhGetTokenOwner(\n    _In_ HANDLE TokenHandle,\n    _Out_ PTOKEN_OWNER *Owner\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhGetTokenPrimaryGroup(\n    _In_ HANDLE TokenHandle,\n    _Out_ PTOKEN_PRIMARY_GROUP *PrimaryGroup\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhGetTokenGroups(\n    _In_ HANDLE TokenHandle,\n    _Out_ PTOKEN_GROUPS *Groups\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhGetTokenRestrictedSids(\n    _In_ HANDLE TokenHandle,\n    _Out_ PTOKEN_GROUPS* RestrictedSids\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhGetTokenPrivileges(\n    _In_ HANDLE TokenHandle,\n    _Out_ PTOKEN_PRIVILEGES *Privileges\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhSetTokenSessionId(\n    _In_ HANDLE TokenHandle,\n    _In_ ULONG SessionId\n    );\n\nPHLIBAPI\nBOOLEAN\nNTAPI\nPhSetTokenPrivilege(\n    _In_ HANDLE TokenHandle,\n    _In_opt_ PWSTR PrivilegeName,\n    _In_opt_ PLUID PrivilegeLuid,\n    _In_ ULONG Attributes\n    );\n\nPHLIBAPI\nBOOLEAN\nNTAPI\nPhSetTokenPrivilege2(\n    _In_ HANDLE TokenHandle,\n    _In_ LONG Privilege,\n    _In_ ULONG Attributes\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhSetTokenIsVirtualizationEnabled(\n    _In_ HANDLE TokenHandle,\n    _In_ BOOLEAN IsVirtualizationEnabled\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhGetTokenIntegrityLevel(\n    _In_ HANDLE TokenHandle,\n    _Out_opt_ PMANDATORY_LEVEL IntegrityLevel,\n    _Out_opt_ PWSTR *IntegrityString\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhGetFileSize(\n    _In_ HANDLE FileHandle,\n    _Out_ PLARGE_INTEGER Size\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhSetFileSize(\n    _In_ HANDLE FileHandle,\n    _In_ PLARGE_INTEGER Size\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhGetTransactionManagerBasicInformation(\n    _In_ HANDLE TransactionManagerHandle,\n    _Out_ PTRANSACTIONMANAGER_BASIC_INFORMATION BasicInformation\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhGetTransactionManagerLogFileName(\n    _In_ HANDLE TransactionManagerHandle,\n    _Out_ PPH_STRING *LogFileName\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhGetTransactionBasicInformation(\n    _In_ HANDLE TransactionHandle,\n    _Out_ PTRANSACTION_BASIC_INFORMATION BasicInformation\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhGetTransactionPropertiesInformation(\n    _In_ HANDLE TransactionHandle,\n    _Out_opt_ PLARGE_INTEGER Timeout,\n    _Out_opt_ TRANSACTION_OUTCOME *Outcome,\n    _Out_opt_ PPH_STRING *Description\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhGetResourceManagerBasicInformation(\n    _In_ HANDLE ResourceManagerHandle,\n    _Out_opt_ PGUID Guid,\n    _Out_opt_ PPH_STRING *Description\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhGetEnlistmentBasicInformation(\n    _In_ HANDLE EnlistmentHandle,\n    _Out_ PENLISTMENT_BASIC_INFORMATION BasicInformation\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhOpenDriverByBaseAddress(\n    _Out_ PHANDLE DriverHandle,\n    _In_ PVOID BaseAddress\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhGetDriverName(\n    _In_ HANDLE DriverHandle,\n    _Out_ PPH_STRING *Name\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhGetDriverServiceKeyName(\n    _In_ HANDLE DriverHandle,\n    _Out_ PPH_STRING *ServiceKeyName\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhUnloadDriver(\n    _In_opt_ PVOID BaseAddress,\n    _In_opt_ PWSTR Name\n    );\n\n#define PH_ENUM_PROCESS_MODULES_LIMIT 0x800\n\n/**\n * A callback function passed to PhEnumProcessModules() and called for each process module.\n *\n * \\param Module A structure providing information about the module.\n * \\param Context A user-defined value passed to PhEnumProcessModules().\n *\n * \\return TRUE to continue the enumeration, FALSE to stop.\n */\ntypedef BOOLEAN (NTAPI *PPH_ENUM_PROCESS_MODULES_CALLBACK)(\n    _In_ PLDR_DATA_TABLE_ENTRY Module,\n    _In_opt_ PVOID Context\n    );\n\n#define PH_ENUM_PROCESS_MODULES_DONT_RESOLVE_WOW64_FS 0x1\n#define PH_ENUM_PROCESS_MODULES_TRY_MAPPED_FILE_NAME 0x2\n\ntypedef struct _PH_ENUM_PROCESS_MODULES_PARAMETERS\n{\n    PPH_ENUM_PROCESS_MODULES_CALLBACK Callback;\n    PVOID Context;\n    ULONG Flags;\n} PH_ENUM_PROCESS_MODULES_PARAMETERS, *PPH_ENUM_PROCESS_MODULES_PARAMETERS;\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhEnumProcessModules(\n    _In_ HANDLE ProcessHandle,\n    _In_ PPH_ENUM_PROCESS_MODULES_CALLBACK Callback,\n    _In_opt_ PVOID Context\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhEnumProcessModulesEx(\n    _In_ HANDLE ProcessHandle,\n    _In_ PPH_ENUM_PROCESS_MODULES_PARAMETERS Parameters\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhSetProcessModuleLoadCount(\n    _In_ HANDLE ProcessHandle,\n    _In_ PVOID BaseAddress,\n    _In_ ULONG LoadCount\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhEnumProcessModules32(\n    _In_ HANDLE ProcessHandle,\n    _In_ PPH_ENUM_PROCESS_MODULES_CALLBACK Callback,\n    _In_opt_ PVOID Context\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhEnumProcessModules32Ex(\n    _In_ HANDLE ProcessHandle,\n    _In_ PPH_ENUM_PROCESS_MODULES_PARAMETERS Parameters\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhSetProcessModuleLoadCount32(\n    _In_ HANDLE ProcessHandle,\n    _In_ PVOID BaseAddress,\n    _In_ ULONG LoadCount\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhGetProcedureAddressRemote(\n    _In_ HANDLE ProcessHandle,\n    _In_ PWSTR FileName,\n    _In_opt_ PSTR ProcedureName,\n    _In_opt_ ULONG ProcedureNumber,\n    _Out_ PVOID *ProcedureAddress,\n    _Out_opt_ PVOID *DllBase\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhEnumKernelModules(\n    _Out_ PRTL_PROCESS_MODULES *Modules\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhEnumKernelModulesEx(\n    _Out_ PRTL_PROCESS_MODULE_INFORMATION_EX *Modules\n    );\n\nPHLIBAPI\nPPH_STRING\nNTAPI\nPhGetKernelFileName(\n    VOID\n    );\n\n/**\n * Gets a pointer to the first process information structure in a buffer returned by\n * PhEnumProcesses().\n *\n * \\param Processes A pointer to a buffer returned by PhEnumProcesses().\n */\n#define PH_FIRST_PROCESS(Processes) ((PSYSTEM_PROCESS_INFORMATION)(Processes))\n\n/**\n * Gets a pointer to the process information structure after a given structure.\n *\n * \\param Process A pointer to a process information structure.\n *\n * \\return A pointer to the next process information structure, or NULL if there are no more.\n */\n#define PH_NEXT_PROCESS(Process) ( \\\n    ((PSYSTEM_PROCESS_INFORMATION)(Process))->NextEntryOffset ? \\\n    (PSYSTEM_PROCESS_INFORMATION)PTR_ADD_OFFSET((Process), \\\n    ((PSYSTEM_PROCESS_INFORMATION)(Process))->NextEntryOffset) : \\\n    NULL \\\n    )\n\n#define PH_PROCESS_EXTENSION(Process) \\\n    ((PSYSTEM_PROCESS_INFORMATION_EXTENSION)PTR_ADD_OFFSET((Process), \\\n    FIELD_OFFSET(SYSTEM_PROCESS_INFORMATION, Threads) + \\\n    sizeof(SYSTEM_THREAD_INFORMATION) * \\\n    ((PSYSTEM_PROCESS_INFORMATION)(Process))->NumberOfThreads))\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhEnumProcesses(\n    _Out_ PVOID *Processes\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhEnumProcessesEx(\n    _Out_ PVOID *Processes,\n    _In_ SYSTEM_INFORMATION_CLASS SystemInformationClass\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhEnumProcessesForSession(\n    _Out_ PVOID *Processes,\n    _In_ ULONG SessionId\n    );\n\nPHLIBAPI\nPSYSTEM_PROCESS_INFORMATION\nNTAPI\nPhFindProcessInformation(\n    _In_ PVOID Processes,\n    _In_ HANDLE ProcessId\n    );\n\nPHLIBAPI\nPSYSTEM_PROCESS_INFORMATION\nNTAPI\nPhFindProcessInformationByImageName(\n    _In_ PVOID Processes,\n    _In_ PPH_STRINGREF ImageName\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhEnumHandles(\n    _Out_ PSYSTEM_HANDLE_INFORMATION *Handles\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhEnumHandlesEx(\n    _Out_ PSYSTEM_HANDLE_INFORMATION_EX *Handles\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhEnumHandlesEx2(\n    _In_ HANDLE ProcessHandle,\n    _Out_ PPROCESS_HANDLE_SNAPSHOT_INFORMATION *Handles\n    );\n\n#define PH_FIRST_PAGEFILE(Pagefiles) ( \\\n    /* The size of a pagefile can never be 0. A TotalSize of 0\n     * is used to indicate that there are no pagefiles.\n     */ ((PSYSTEM_PAGEFILE_INFORMATION)(Pagefiles))->TotalSize ? \\\n    (PSYSTEM_PAGEFILE_INFORMATION)(Pagefiles) : \\\n    NULL \\\n    )\n#define PH_NEXT_PAGEFILE(Pagefile) ( \\\n    ((PSYSTEM_PAGEFILE_INFORMATION)(Pagefile))->NextEntryOffset ? \\\n    (PSYSTEM_PAGEFILE_INFORMATION)PTR_ADD_OFFSET((Pagefile), \\\n    ((PSYSTEM_PAGEFILE_INFORMATION)(Pagefile))->NextEntryOffset) : \\\n    NULL \\\n    )\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhEnumPagefiles(\n    _Out_ PVOID *Pagefiles\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhGetProcessImageFileNameByProcessId(\n    _In_ HANDLE ProcessId,\n    _Out_ PPH_STRING *FileName\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhGetProcessIsDotNet(\n    _In_ HANDLE ProcessId,\n    _Out_ PBOOLEAN IsDotNet\n    );\n\n#define PH_CLR_USE_SECTION_CHECK 0x1\n#define PH_CLR_NO_WOW64_CHECK 0x2\n#define PH_CLR_KNOWN_IS_WOW64 0x4\n\n#define PH_CLR_VERSION_1_0 0x1\n#define PH_CLR_VERSION_1_1 0x2\n#define PH_CLR_VERSION_2_0 0x4\n#define PH_CLR_VERSION_4_ABOVE 0x8\n#define PH_CLR_VERSION_MASK 0xf\n#define PH_CLR_MSCORLIB_PRESENT 0x10000\n#define PH_CLR_JIT_PRESENT 0x20000\n#define PH_CLR_PROCESS_IS_WOW64 0x100000\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhGetProcessIsDotNetEx(\n    _In_ HANDLE ProcessId,\n    _In_opt_ HANDLE ProcessHandle,\n    _In_ ULONG InFlags,\n    _Out_opt_ PBOOLEAN IsDotNet,\n    _Out_opt_ PULONG Flags\n    );\n\n/**\n * A callback function passed to PhEnumDirectoryObjects() and called for each directory object.\n *\n * \\param Name The name of the object.\n * \\param TypeName The name of the object's type.\n * \\param Context A user-defined value passed to PhEnumDirectoryObjects().\n *\n * \\return TRUE to continue the enumeration, FALSE to stop.\n */\ntypedef BOOLEAN (NTAPI *PPH_ENUM_DIRECTORY_OBJECTS)(\n    _In_ PPH_STRINGREF Name,\n    _In_ PPH_STRINGREF TypeName,\n    _In_opt_ PVOID Context\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhEnumDirectoryObjects(\n    _In_ HANDLE DirectoryHandle,\n    _In_ PPH_ENUM_DIRECTORY_OBJECTS Callback,\n    _In_opt_ PVOID Context\n    );\n\ntypedef BOOLEAN (NTAPI *PPH_ENUM_DIRECTORY_FILE)(\n    _In_ PFILE_DIRECTORY_INFORMATION Information,\n    _In_opt_ PVOID Context\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhEnumDirectoryFile(\n    _In_ HANDLE FileHandle,\n    _In_opt_ PUNICODE_STRING SearchPattern,\n    _In_ PPH_ENUM_DIRECTORY_FILE Callback,\n    _In_opt_ PVOID Context\n    );\n\n#define PH_FIRST_STREAM(Streams) ((PFILE_STREAM_INFORMATION)(Streams))\n#define PH_NEXT_STREAM(Stream) ( \\\n    ((PFILE_STREAM_INFORMATION)(Stream))->NextEntryOffset ? \\\n    (PFILE_STREAM_INFORMATION)((PCHAR)(Stream) + \\\n    ((PFILE_STREAM_INFORMATION)(Stream))->NextEntryOffset) : \\\n    NULL \\\n    )\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhEnumFileStreams(\n    _In_ HANDLE FileHandle,\n    _Out_ PVOID *Streams\n    );\n\nPHLIBAPI\nVOID\nNTAPI\nPhUpdateMupDevicePrefixes(\n    VOID\n    );\n\nPHLIBAPI\nVOID\nNTAPI\nPhUpdateDosDevicePrefixes(\n    VOID\n    );\n\nPHLIBAPI\nPPH_STRING\nNTAPI\nPhResolveDevicePrefix(\n    _In_ PPH_STRING Name\n    );\n\nPHLIBAPI\nPPH_STRING\nNTAPI\nPhGetFileName(\n    _In_ PPH_STRING FileName\n    );\n\n#define PH_MODULE_TYPE_MODULE 1\n#define PH_MODULE_TYPE_MAPPED_FILE 2\n#define PH_MODULE_TYPE_WOW64_MODULE 3\n#define PH_MODULE_TYPE_KERNEL_MODULE 4\n#define PH_MODULE_TYPE_MAPPED_IMAGE 5\n\ntypedef struct _PH_MODULE_INFO\n{\n    ULONG Type;\n    PVOID BaseAddress;\n    ULONG Size;\n    PVOID EntryPoint;\n    ULONG Flags;\n    PPH_STRING Name;\n    PPH_STRING FileName;\n    PPH_STRING OriginalFileName;\n\n    USHORT LoadOrderIndex; // -1 if N/A\n    USHORT LoadCount; // -1 if N/A\n    USHORT LoadReason; // -1 if N/A\n    USHORT Reserved;\n    LARGE_INTEGER LoadTime; // 0 if N/A\n} PH_MODULE_INFO, *PPH_MODULE_INFO;\n\n/**\n * A callback function passed to PhEnumGenericModules() and called for each process module.\n *\n * \\param Module A structure providing information about the module.\n * \\param Context A user-defined value passed to PhEnumGenericModules().\n *\n * \\return TRUE to continue the enumeration, FALSE to stop.\n */\ntypedef BOOLEAN (NTAPI *PPH_ENUM_GENERIC_MODULES_CALLBACK)(\n    _In_ PPH_MODULE_INFO Module,\n    _In_opt_ PVOID Context\n    );\n\n#define PH_ENUM_GENERIC_MAPPED_FILES 0x1\n#define PH_ENUM_GENERIC_MAPPED_IMAGES 0x2\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhEnumGenericModules(\n    _In_ HANDLE ProcessId,\n    _In_opt_ HANDLE ProcessHandle,\n    _In_ ULONG Flags,\n    _In_ PPH_ENUM_GENERIC_MODULES_CALLBACK Callback,\n    _In_opt_ PVOID Context\n    );\n\n#define PH_KEY_PREDEFINE(Number) ((HANDLE)(LONG_PTR)(-3 - (Number) * 2))\n#define PH_KEY_IS_PREDEFINED(Predefine) (((LONG_PTR)(Predefine) < 0) && ((LONG_PTR)(Predefine) & 0x1))\n#define PH_KEY_PREDEFINE_TO_NUMBER(Predefine) (ULONG)(((-(LONG_PTR)(Predefine) - 3) >> 1))\n\n#define PH_KEY_LOCAL_MACHINE PH_KEY_PREDEFINE(0) // \\Registry\\Machine\n#define PH_KEY_USERS PH_KEY_PREDEFINE(1) // \\Registry\\User\n#define PH_KEY_CLASSES_ROOT PH_KEY_PREDEFINE(2) // \\Registry\\Machine\\Software\\Classes\n#define PH_KEY_CURRENT_USER PH_KEY_PREDEFINE(3) // \\Registry\\User\\<SID>\n#define PH_KEY_CURRENT_USER_NUMBER 3\n#define PH_KEY_MAXIMUM_PREDEFINE 4\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhCreateKey(\n    _Out_ PHANDLE KeyHandle,\n    _In_ ACCESS_MASK DesiredAccess,\n    _In_opt_ HANDLE RootDirectory,\n    _In_ PPH_STRINGREF ObjectName,\n    _In_ ULONG Attributes,\n    _In_ ULONG CreateOptions,\n    _Out_opt_ PULONG Disposition\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhOpenKey(\n    _Out_ PHANDLE KeyHandle,\n    _In_ ACCESS_MASK DesiredAccess,\n    _In_opt_ HANDLE RootDirectory,\n    _In_ PPH_STRINGREF ObjectName,\n    _In_ ULONG Attributes\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhLoadAppKey(\n    _Out_ PHANDLE KeyHandle,\n    _In_ PWSTR FileName,\n    _In_ ACCESS_MASK DesiredAccess,\n    _In_opt_ ULONG Flags\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhQueryKey(\n    _In_ HANDLE KeyHandle,\n    _In_ KEY_INFORMATION_CLASS KeyInformationClass,\n    _Out_ PVOID *Buffer\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhQueryValueKey(\n    _In_ HANDLE KeyHandle,\n    _In_opt_ PPH_STRINGREF ValueName,\n    _In_ KEY_VALUE_INFORMATION_CLASS KeyValueInformationClass,\n    _Out_ PVOID *Buffer\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhCreateFileWin32(\n    _Out_ PHANDLE FileHandle,\n    _In_ PWSTR FileName,\n    _In_ ACCESS_MASK DesiredAccess,\n    _In_opt_ ULONG FileAttributes,\n    _In_ ULONG ShareAccess,\n    _In_ ULONG CreateDisposition,\n    _In_ ULONG CreateOptions\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhCreateFileWin32Ex(\n    _Out_ PHANDLE FileHandle,\n    _In_ PWSTR FileName,\n    _In_ ACCESS_MASK DesiredAccess,\n    _In_opt_ ULONG FileAttributes,\n    _In_ ULONG ShareAccess,\n    _In_ ULONG CreateDisposition,\n    _In_ ULONG CreateOptions,\n    _Out_opt_ PULONG CreateStatus\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhQueryFullAttributesFileWin32(\n    _In_ PWSTR FileName,\n    _Out_ PFILE_NETWORK_OPEN_INFORMATION FileInformation\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhDeleteFileWin32(\n    _In_ PWSTR FileName\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhCreateDirectory(\n    _In_ PPH_STRING DirectoryPath\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhDeleteDirectory(\n    _In_ PPH_STRING DirectoryPath\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhCreatePipe(\n    _Out_ PHANDLE PipeReadHandle,\n    _Out_ PHANDLE PipeWriteHandle\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhCreateNamedPipe(\n    _Out_ PHANDLE PipeHandle,\n    _In_ PWSTR PipeName\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhConnectPipe(\n    _Out_ PHANDLE PipeHandle,\n    _In_ PWSTR PipeName\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhListenNamedPipe(\n    _In_ HANDLE PipeHandle\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhDisconnectNamedPipe(\n    _In_ HANDLE PipeHandle\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhPeekNamedPipe(\n    _In_ HANDLE PipeHandle,\n    _Out_writes_bytes_opt_(Length) PVOID Buffer,\n    _In_ ULONG Length,\n    _Out_opt_ PULONG NumberOfBytesRead,\n    _Out_opt_ PULONG NumberOfBytesAvailable,\n    _Out_opt_ PULONG NumberOfBytesLeftInMessage\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhTransceiveNamedPipe(\n    _In_ HANDLE PipeHandle,\n    _In_reads_bytes_(InputBufferLength) PVOID InputBuffer,\n    _In_ ULONG InputBufferLength,\n    _Out_writes_bytes_(OutputBufferLength) PVOID OutputBuffer,\n    _In_ ULONG OutputBufferLength\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhWaitForNamedPipe(\n    _In_ PWSTR PipeName,\n    _In_opt_ ULONG Timeout\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhImpersonateClientOfNamedPipe(\n    _In_ HANDLE PipeHandle\n    );\n\n#ifdef __cplusplus\n}\n#endif\n\n#endif\n"
  },
  {
    "path": "third_party/phlib/include/phnativeinl.h",
    "content": "#ifndef _PH_PHNATINL_H\n#define _PH_PHNATINL_H\n\n#pragma once\n\n// This file contains inlined native API wrapper functions. These functions were previously\n// exported, but are now inlined because they are extremely simple wrappers around equivalent native\n// API functions.\n\n/**\n * Gets basic information for a process.\n *\n * \\param ProcessHandle A handle to a process. The handle must have\n * PROCESS_QUERY_LIMITED_INFORMATION access.\n * \\param BasicInformation A variable which receives the information.\n */\nFORCEINLINE\nNTSTATUS\nPhGetProcessBasicInformation(\n    _In_ HANDLE ProcessHandle,\n    _Out_ PPROCESS_BASIC_INFORMATION BasicInformation\n    )\n{\n    return NtQueryInformationProcess(\n        ProcessHandle,\n        ProcessBasicInformation,\n        BasicInformation,\n        sizeof(PROCESS_BASIC_INFORMATION),\n        NULL\n        );\n}\n\n/**\n * Gets extended basic information for a process.\n *\n * \\param ProcessHandle A handle to a process. The handle must have\n * PROCESS_QUERY_LIMITED_INFORMATION access.\n * \\param ExtendedBasicInformation A variable which receives the information.\n */\nFORCEINLINE\nNTSTATUS\nPhGetProcessExtendedBasicInformation(\n    _In_ HANDLE ProcessHandle,\n    _Out_ PPROCESS_EXTENDED_BASIC_INFORMATION ExtendedBasicInformation\n    )\n{\n    ExtendedBasicInformation->Size = sizeof(PROCESS_EXTENDED_BASIC_INFORMATION);\n\n    return NtQueryInformationProcess(\n        ProcessHandle,\n        ProcessBasicInformation,\n        ExtendedBasicInformation,\n        sizeof(PROCESS_EXTENDED_BASIC_INFORMATION),\n        NULL\n        );\n}\n\n/**\n * Gets time information for a process.\n *\n * \\param ProcessHandle A handle to a process. The handle must have\n * PROCESS_QUERY_LIMITED_INFORMATION access.\n * \\param Times A variable which receives the information.\n */\nFORCEINLINE\nNTSTATUS\nPhGetProcessTimes(\n    _In_ HANDLE ProcessHandle,\n    _Out_ PKERNEL_USER_TIMES Times\n    )\n{\n    return NtQueryInformationProcess(\n        ProcessHandle,\n        ProcessTimes,\n        Times,\n        sizeof(KERNEL_USER_TIMES),\n        NULL\n        );\n}\n\n/**\n * Gets a process' session ID.\n *\n * \\param ProcessHandle A handle to a process. The handle must have\n * PROCESS_QUERY_LIMITED_INFORMATION access.\n * \\param SessionId A variable which receives the process' session ID.\n */\nFORCEINLINE\nNTSTATUS\nPhGetProcessSessionId(\n    _In_ HANDLE ProcessHandle,\n    _Out_ PULONG SessionId\n    )\n{\n    NTSTATUS status;\n    PROCESS_SESSION_INFORMATION sessionInfo;\n\n    status = NtQueryInformationProcess(\n        ProcessHandle,\n        ProcessSessionInformation,\n        &sessionInfo,\n        sizeof(PROCESS_SESSION_INFORMATION),\n        NULL\n        );\n\n    if (NT_SUCCESS(status))\n    {\n        *SessionId = sessionInfo.SessionId;\n    }\n\n    return status;\n}\n\n/**\n * Gets whether a process is running under 32-bit emulation.\n *\n * \\param ProcessHandle A handle to a process. The handle must have\n * PROCESS_QUERY_LIMITED_INFORMATION access.\n * \\param IsWow64 A variable which receives a boolean indicating whether the process is 32-bit.\n */\nFORCEINLINE\nNTSTATUS\nPhGetProcessIsWow64(\n    _In_ HANDLE ProcessHandle,\n    _Out_ PBOOLEAN IsWow64\n    )\n{\n    NTSTATUS status;\n    ULONG_PTR wow64;\n\n    status = NtQueryInformationProcess(\n        ProcessHandle,\n        ProcessWow64Information,\n        &wow64,\n        sizeof(ULONG_PTR),\n        NULL\n        );\n\n    if (NT_SUCCESS(status))\n    {\n        *IsWow64 = !!wow64;\n    }\n\n    return status;\n}\n\n/**\n * Gets a process' WOW64 PEB address.\n *\n * \\param ProcessHandle A handle to a process. The handle must have\n * PROCESS_QUERY_LIMITED_INFORMATION access.\n * \\param Peb32 A variable which receives the base address of the process' WOW64 PEB. If the process\n * is 64-bit, the variable receives NULL.\n */\nFORCEINLINE\nNTSTATUS\nPhGetProcessPeb32(\n    _In_ HANDLE ProcessHandle,\n    _Out_ PVOID *Peb32\n    )\n{\n    NTSTATUS status;\n    ULONG_PTR wow64;\n\n    status = NtQueryInformationProcess(\n        ProcessHandle,\n        ProcessWow64Information,\n        &wow64,\n        sizeof(ULONG_PTR),\n        NULL\n        );\n\n    if (NT_SUCCESS(status))\n    {\n        *Peb32 = (PVOID)wow64;\n    }\n\n    return status;\n}\n\n/**\n * Gets whether a process is being debugged.\n *\n * \\param ProcessHandle A handle to a process. The handle must have PROCESS_QUERY_INFORMATION\n * access.\n * \\param IsBeingDebugged A variable which receives a boolean indicating whether the process is\n * being debugged.\n */\nFORCEINLINE\nNTSTATUS\nPhGetProcessIsBeingDebugged(\n    _In_ HANDLE ProcessHandle,\n    _Out_ PBOOLEAN IsBeingDebugged\n    )\n{\n    NTSTATUS status;\n    PVOID debugPort;\n\n    status = NtQueryInformationProcess(\n        ProcessHandle,\n        ProcessDebugPort,\n        &debugPort,\n        sizeof(PVOID),\n        NULL\n        );\n\n    if (NT_SUCCESS(status))\n    {\n        *IsBeingDebugged = !!debugPort;\n    }\n\n    return status;\n}\n\n/**\n * Gets a handle to a process' debug object.\n *\n * \\param ProcessHandle A handle to a process. The handle must have PROCESS_QUERY_INFORMATION\n * access.\n * \\param DebugObjectHandle A variable which receives a handle to the debug object associated with\n * the process. You must close the handle when you no longer need it.\n *\n * \\retval STATUS_PORT_NOT_SET The process is not being debugged and has no associated debug object.\n */\nFORCEINLINE\nNTSTATUS\nPhGetProcessDebugObject(\n    _In_ HANDLE ProcessHandle,\n    _Out_ PHANDLE DebugObjectHandle\n    )\n{\n    return NtQueryInformationProcess(\n        ProcessHandle,\n        ProcessDebugObjectHandle,\n        DebugObjectHandle,\n        sizeof(HANDLE),\n        NULL\n        );\n}\n\n/**\n * Gets a process' no-execute status.\n *\n * \\param ProcessHandle A handle to a process. The handle must have PROCESS_QUERY_INFORMATION\n * access.\n * \\param ExecuteFlags A variable which receives the no-execute flags.\n */\nFORCEINLINE\nNTSTATUS\nPhGetProcessExecuteFlags(\n    _In_ HANDLE ProcessHandle,\n    _Out_ PULONG ExecuteFlags\n    )\n{\n    return NtQueryInformationProcess(\n        ProcessHandle,\n        ProcessExecuteFlags,\n        ExecuteFlags,\n        sizeof(ULONG),\n        NULL\n        );\n}\n\n/**\n * Gets a process' I/O priority.\n *\n * \\param ProcessHandle A handle to a process. The handle must have\n * PROCESS_QUERY_LIMITED_INFORMATION access.\n * \\param IoPriority A variable which receives the I/O priority of the process.\n */\nFORCEINLINE\nNTSTATUS\nPhGetProcessIoPriority(\n    _In_ HANDLE ProcessHandle,\n    _Out_ IO_PRIORITY_HINT *IoPriority\n    )\n{\n    return NtQueryInformationProcess(\n        ProcessHandle,\n        ProcessIoPriority,\n        IoPriority,\n        sizeof(IO_PRIORITY_HINT),\n        NULL\n        );\n}\n\n/**\n * Gets a process' page priority.\n *\n * \\param ProcessHandle A handle to a process. The handle must have\n * PROCESS_QUERY_LIMITED_INFORMATION access.\n * \\param PagePriority A variable which receives the page priority of the process.\n */\nFORCEINLINE\nNTSTATUS\nPhGetProcessPagePriority(\n    _In_ HANDLE ProcessHandle,\n    _Out_ PULONG PagePriority\n    )\n{\n    NTSTATUS status;\n    PAGE_PRIORITY_INFORMATION pagePriorityInfo;\n\n    status = NtQueryInformationProcess(\n        ProcessHandle,\n        ProcessPagePriority,\n        &pagePriorityInfo,\n        sizeof(PAGE_PRIORITY_INFORMATION),\n        NULL\n        );\n\n    if (NT_SUCCESS(status))\n    {\n        *PagePriority = pagePriorityInfo.PagePriority;\n    }\n\n    return status;\n}\n\n/**\n * Gets a process' cycle count.\n *\n * \\param ProcessHandle A handle to a process. The handle must have\n * PROCESS_QUERY_LIMITED_INFORMATION access.\n * \\param CycleTime A variable which receives the 64-bit cycle time.\n */\nFORCEINLINE\nNTSTATUS\nPhGetProcessCycleTime(\n    _In_ HANDLE ProcessHandle,\n    _Out_ PULONG64 CycleTime\n    )\n{\n    NTSTATUS status;\n    PROCESS_CYCLE_TIME_INFORMATION cycleTimeInfo;\n\n    status = NtQueryInformationProcess(\n        ProcessHandle,\n        ProcessCycleTime,\n        &cycleTimeInfo,\n        sizeof(PROCESS_CYCLE_TIME_INFORMATION),\n        NULL\n        );\n\n    if (!NT_SUCCESS(status))\n        return status;\n\n    *CycleTime = cycleTimeInfo.AccumulatedCycles;\n\n    return status;\n}\n\nFORCEINLINE\nNTSTATUS\nPhGetProcessConsoleHostProcessId(\n    _In_ HANDLE ProcessHandle,\n    _Out_ PHANDLE ConsoleHostProcessId\n    )\n{\n    NTSTATUS status;\n    ULONG_PTR consoleHostProcess;\n\n    status = NtQueryInformationProcess(\n        ProcessHandle,\n        ProcessConsoleHostProcess,\n        &consoleHostProcess,\n        sizeof(ULONG_PTR),\n        NULL\n        );\n\n    if (!NT_SUCCESS(status))\n        return status;\n\n    *ConsoleHostProcessId = (HANDLE)consoleHostProcess;\n\n    return status;\n}\n\nFORCEINLINE\nNTSTATUS\nPhGetProcessProtection(\n    _In_ HANDLE ProcessHandle,\n    _Out_ PPS_PROTECTION Protection\n    )\n{\n    return NtQueryInformationProcess(\n        ProcessHandle,\n        ProcessProtectionInformation,\n        Protection,\n        sizeof(PS_PROTECTION),\n        NULL\n        );\n}\n\nFORCEINLINE\nNTSTATUS\nPhGetProcessIsCFGuardEnabled(\n    _In_ HANDLE ProcessHandle,\n    _Out_ PBOOLEAN IsControlFlowGuardEnabled\n    )\n{\n    NTSTATUS status;\n    PROCESS_MITIGATION_POLICY_INFORMATION policyInfo;\n\n    policyInfo.Policy = ProcessControlFlowGuardPolicy;\n\n    status = NtQueryInformationProcess(\n        ProcessHandle,\n        ProcessMitigationPolicy,\n        &policyInfo,\n        sizeof(PROCESS_MITIGATION_POLICY_INFORMATION),\n        NULL\n        );\n\n    if (!NT_SUCCESS(status))\n        return status;\n\n    *IsControlFlowGuardEnabled = !!policyInfo.ControlFlowGuardPolicy.EnableControlFlowGuard;\n\n    return status;\n}\n\n/**\n * Sets a process' affinity mask.\n *\n * \\param ProcessHandle A handle to a process. The handle must have PROCESS_SET_INFORMATION access.\n * \\param AffinityMask The new affinity mask.\n */\nFORCEINLINE\nNTSTATUS\nPhSetProcessAffinityMask(\n    _In_ HANDLE ProcessHandle,\n    _In_ ULONG_PTR AffinityMask\n    )\n{\n    return NtSetInformationProcess(\n        ProcessHandle,\n        ProcessAffinityMask,\n        &AffinityMask,\n        sizeof(ULONG_PTR)\n        );\n}\n\n/**\n * Sets a process' I/O priority.\n *\n * \\param ProcessHandle A handle to a process. The handle must have PROCESS_SET_INFORMATION access.\n * \\param IoPriority The new I/O priority.\n */\nFORCEINLINE\nNTSTATUS\nPhSetProcessIoPriority(\n    _In_ HANDLE ProcessHandle,\n    _In_ IO_PRIORITY_HINT IoPriority\n    )\n{\n    return NtSetInformationProcess(\n        ProcessHandle,\n        ProcessIoPriority,\n        &IoPriority,\n        sizeof(IO_PRIORITY_HINT)\n        );\n}\n\n/**\n * Gets basic information for a thread.\n *\n * \\param ThreadHandle A handle to a thread. The handle must have THREAD_QUERY_LIMITED_INFORMATION\n * access.\n * \\param BasicInformation A variable which receives the information.\n */\nFORCEINLINE\nNTSTATUS\nPhGetThreadBasicInformation(\n    _In_ HANDLE ThreadHandle,\n    _Out_ PTHREAD_BASIC_INFORMATION BasicInformation\n    )\n{\n    return NtQueryInformationThread(\n        ThreadHandle,\n        ThreadBasicInformation,\n        BasicInformation,\n        sizeof(THREAD_BASIC_INFORMATION),\n        NULL\n        );\n}\n\n/**\n * Gets a thread's I/O priority.\n *\n * \\param ThreadHandle A handle to a thread. The handle must have THREAD_QUERY_LIMITED_INFORMATION\n * access.\n * \\param IoPriority A variable which receives the I/O priority of the thread.\n */\nFORCEINLINE\nNTSTATUS\nPhGetThreadIoPriority(\n    _In_ HANDLE ThreadHandle,\n    _Out_ IO_PRIORITY_HINT *IoPriority\n    )\n{\n    return NtQueryInformationThread(\n        ThreadHandle,\n        ThreadIoPriority,\n        IoPriority,\n        sizeof(IO_PRIORITY_HINT),\n        NULL\n        );\n}\n\n/**\n * Gets a thread's page priority.\n *\n * \\param ThreadHandle A handle to a thread. The handle must have THREAD_QUERY_LIMITED_INFORMATION\n * access.\n * \\param PagePriority A variable which receives the page priority of the thread.\n */\nFORCEINLINE\nNTSTATUS\nPhGetThreadPagePriority(\n    _In_ HANDLE ThreadHandle,\n    _Out_ PULONG PagePriority\n    )\n{\n    NTSTATUS status;\n    PAGE_PRIORITY_INFORMATION pagePriorityInfo;\n\n    status = NtQueryInformationThread(\n        ThreadHandle,\n        ThreadPagePriority,\n        &pagePriorityInfo,\n        sizeof(PAGE_PRIORITY_INFORMATION),\n        NULL\n        );\n\n    if (NT_SUCCESS(status))\n    {\n        *PagePriority = pagePriorityInfo.PagePriority;\n    }\n\n    return status;\n}\n\n/**\n * Gets a thread's cycle count.\n *\n * \\param ThreadHandle A handle to a thread. The handle must have THREAD_QUERY_LIMITED_INFORMATION\n * access.\n * \\param CycleTime A variable which receives the 64-bit cycle time.\n */\nFORCEINLINE\nNTSTATUS\nPhGetThreadCycleTime(\n    _In_ HANDLE ThreadHandle,\n    _Out_ PULONG64 CycleTime\n    )\n{\n    NTSTATUS status;\n    THREAD_CYCLE_TIME_INFORMATION cycleTimeInfo;\n\n    status = NtQueryInformationThread(\n        ThreadHandle,\n        ThreadCycleTime,\n        &cycleTimeInfo,\n        sizeof(THREAD_CYCLE_TIME_INFORMATION),\n        NULL\n        );\n\n    if (!NT_SUCCESS(status))\n        return status;\n\n    *CycleTime = cycleTimeInfo.AccumulatedCycles;\n\n    return status;\n}\n\n/**\n * Sets a thread's affinity mask.\n *\n * \\param ThreadHandle A handle to a thread. The handle must have THREAD_SET_LIMITED_INFORMATION\n * access.\n * \\param AffinityMask The new affinity mask.\n */\nFORCEINLINE\nNTSTATUS\nPhSetThreadAffinityMask(\n    _In_ HANDLE ThreadHandle,\n    _In_ ULONG_PTR AffinityMask\n    )\n{\n    return NtSetInformationThread(\n        ThreadHandle,\n        ThreadAffinityMask,\n        &AffinityMask,\n        sizeof(ULONG_PTR)\n        );\n}\n\n/**\n * Sets a thread's I/O priority.\n *\n * \\param ThreadHandle A handle to a thread. The handle must have THREAD_SET_LIMITED_INFORMATION\n * access.\n * \\param IoPriority The new I/O priority.\n */\nFORCEINLINE\nNTSTATUS\nPhSetThreadIoPriority(\n    _In_ HANDLE ThreadHandle,\n    _In_ IO_PRIORITY_HINT IoPriority\n    )\n{\n    return NtSetInformationThread(\n        ThreadHandle,\n        ThreadIoPriority,\n        &IoPriority,\n        sizeof(IO_PRIORITY_HINT)\n        );\n}\n\nFORCEINLINE\nNTSTATUS\nPhGetJobBasicAndIoAccounting(\n    _In_ HANDLE JobHandle,\n    _Out_ PJOBOBJECT_BASIC_AND_IO_ACCOUNTING_INFORMATION BasicAndIoAccounting\n    )\n{\n    return NtQueryInformationJobObject(\n        JobHandle,\n        (JOBOBJECTINFOCLASS) JobObjectBasicAndIoAccountingInformation,\n        BasicAndIoAccounting,\n        sizeof(JOBOBJECT_BASIC_AND_IO_ACCOUNTING_INFORMATION),\n        NULL\n        );\n}\n\nFORCEINLINE\nNTSTATUS\nPhGetJobBasicLimits(\n    _In_ HANDLE JobHandle,\n    _Out_ PJOBOBJECT_BASIC_LIMIT_INFORMATION BasicLimits\n    )\n{\n    return NtQueryInformationJobObject(\n        JobHandle,\n\t\t(JOBOBJECTINFOCLASS) JobObjectBasicLimitInformation,\n        BasicLimits,\n        sizeof(JOBOBJECT_BASIC_LIMIT_INFORMATION),\n        NULL\n        );\n}\n\nFORCEINLINE\nNTSTATUS\nPhGetJobExtendedLimits(\n    _In_ HANDLE JobHandle,\n    _Out_ PJOBOBJECT_EXTENDED_LIMIT_INFORMATION ExtendedLimits\n    )\n{\n    return NtQueryInformationJobObject(\n        JobHandle,\n\t\t(JOBOBJECTINFOCLASS) JobObjectExtendedLimitInformation,\n        ExtendedLimits,\n        sizeof(JOBOBJECT_EXTENDED_LIMIT_INFORMATION),\n        NULL\n        );\n}\n\nFORCEINLINE\nNTSTATUS\nPhGetJobBasicUiRestrictions(\n    _In_ HANDLE JobHandle,\n    _Out_ PJOBOBJECT_BASIC_UI_RESTRICTIONS BasicUiRestrictions\n    )\n{\n    return NtQueryInformationJobObject(\n        JobHandle,\n\t\t(JOBOBJECTINFOCLASS) JobObjectBasicUIRestrictions,\n        BasicUiRestrictions,\n        sizeof(JOBOBJECT_BASIC_UI_RESTRICTIONS),\n        NULL\n        );\n}\n\n/**\n * Gets a token's session ID.\n *\n * \\param TokenHandle A handle to a token. The handle must have TOKEN_QUERY access.\n * \\param SessionId A variable which receives the session ID.\n */\nFORCEINLINE\nNTSTATUS\nPhGetTokenSessionId(\n    _In_ HANDLE TokenHandle,\n    _Out_ PULONG SessionId\n    )\n{\n    ULONG returnLength;\n\n    return NtQueryInformationToken(\n        TokenHandle,\n        TokenSessionId,\n        SessionId,\n        sizeof(ULONG),\n        &returnLength\n        );\n}\n\n/**\n * Gets a token's elevation type.\n *\n * \\param TokenHandle A handle to a token. The handle must have TOKEN_QUERY access.\n * \\param ElevationType A variable which receives the elevation type.\n */\nFORCEINLINE\nNTSTATUS\nPhGetTokenElevationType(\n    _In_ HANDLE TokenHandle,\n    _Out_ PTOKEN_ELEVATION_TYPE ElevationType\n    )\n{\n    ULONG returnLength;\n\n    return NtQueryInformationToken(\n        TokenHandle,\n        TokenElevationType,\n        ElevationType,\n        sizeof(TOKEN_ELEVATION_TYPE),\n        &returnLength\n        );\n}\n\n/**\n * Gets whether a token is elevated.\n *\n * \\param TokenHandle A handle to a token. The handle must have TOKEN_QUERY access.\n * \\param Elevated A variable which receives a boolean indicating whether the token is elevated.\n */\nFORCEINLINE\nNTSTATUS\nPhGetTokenIsElevated(\n    _In_ HANDLE TokenHandle,\n    _Out_ PBOOLEAN Elevated\n    )\n{\n    NTSTATUS status;\n    TOKEN_ELEVATION elevation;\n    ULONG returnLength;\n\n    status = NtQueryInformationToken(\n        TokenHandle,\n        TokenElevation,\n        &elevation,\n        sizeof(TOKEN_ELEVATION),\n        &returnLength\n        );\n\n    if (NT_SUCCESS(status))\n    {\n        *Elevated = !!elevation.TokenIsElevated;\n    }\n\n    return status;\n}\n\n/**\n * Gets a token's statistics.\n *\n * \\param TokenHandle A handle to a token. The handle must have TOKEN_QUERY access.\n * \\param Statistics A variable which receives the token's statistics.\n */\nFORCEINLINE\nNTSTATUS\nPhGetTokenStatistics(\n    _In_ HANDLE TokenHandle,\n    _Out_ PTOKEN_STATISTICS Statistics\n    )\n{\n    ULONG returnLength;\n\n    return NtQueryInformationToken(\n        TokenHandle,\n        TokenStatistics,\n        Statistics,\n        sizeof(TOKEN_STATISTICS),\n        &returnLength\n        );\n}\n\n/**\n * Gets a token's source.\n *\n * \\param TokenHandle A handle to a token. The handle must have TOKEN_QUERY_SOURCE access.\n * \\param Source A variable which receives the token's source.\n */\nFORCEINLINE\nNTSTATUS\nPhGetTokenSource(\n    _In_ HANDLE TokenHandle,\n    _Out_ PTOKEN_SOURCE Source\n    )\n{\n    ULONG returnLength;\n\n    return NtQueryInformationToken(\n        TokenHandle,\n        TokenSource,\n        Source,\n        sizeof(TOKEN_SOURCE),\n        &returnLength\n        );\n}\n\n/**\n * Gets a handle to a token's linked token.\n *\n * \\param TokenHandle A handle to a token. The handle must have TOKEN_QUERY access.\n * \\param LinkedTokenHandle A variable which receives a handle to the linked token. You must close\n * the handle using NtClose() when you no longer need it.\n */\nFORCEINLINE\nNTSTATUS\nPhGetTokenLinkedToken(\n    _In_ HANDLE TokenHandle,\n    _Out_ PHANDLE LinkedTokenHandle\n    )\n{\n    NTSTATUS status;\n    ULONG returnLength;\n    TOKEN_LINKED_TOKEN linkedToken;\n\n    status = NtQueryInformationToken(\n        TokenHandle,\n        TokenLinkedToken,\n        &linkedToken,\n        sizeof(TOKEN_LINKED_TOKEN),\n        &returnLength\n        );\n\n    if (!NT_SUCCESS(status))\n        return status;\n\n    *LinkedTokenHandle = linkedToken.LinkedToken;\n\n    return status;\n}\n\n/**\n * Gets whether virtualization is allowed for a token.\n *\n * \\param TokenHandle A handle to a token. The handle must have TOKEN_QUERY access.\n * \\param IsVirtualizationAllowed A variable which receives a boolean indicating whether\n * virtualization is allowed for the token.\n */\nFORCEINLINE\nNTSTATUS\nPhGetTokenIsVirtualizationAllowed(\n    _In_ HANDLE TokenHandle,\n    _Out_ PBOOLEAN IsVirtualizationAllowed\n    )\n{\n    NTSTATUS status;\n    ULONG returnLength;\n    ULONG virtualizationAllowed;\n\n    status = NtQueryInformationToken(\n        TokenHandle,\n        TokenVirtualizationAllowed,\n        &virtualizationAllowed,\n        sizeof(ULONG),\n        &returnLength\n        );\n\n    if (!NT_SUCCESS(status))\n        return status;\n\n    *IsVirtualizationAllowed = !!virtualizationAllowed;\n\n    return status;\n}\n\n/**\n * Gets whether virtualization is enabled for a token.\n *\n * \\param TokenHandle A handle to a token. The handle must have TOKEN_QUERY access.\n * \\param IsVirtualizationEnabled A variable which receives a boolean indicating whether\n * virtualization is enabled for the token.\n */\nFORCEINLINE\nNTSTATUS\nPhGetTokenIsVirtualizationEnabled(\n    _In_ HANDLE TokenHandle,\n    _Out_ PBOOLEAN IsVirtualizationEnabled\n    )\n{\n    NTSTATUS status;\n    ULONG returnLength;\n    ULONG virtualizationEnabled;\n\n    status = NtQueryInformationToken(\n        TokenHandle,\n        TokenVirtualizationEnabled,\n        &virtualizationEnabled,\n        sizeof(ULONG),\n        &returnLength\n        );\n\n    if (!NT_SUCCESS(status))\n        return status;\n\n    *IsVirtualizationEnabled = !!virtualizationEnabled;\n\n    return status;\n}\n\nFORCEINLINE\nNTSTATUS\nPhGetEventBasicInformation(\n    _In_ HANDLE EventHandle,\n    _Out_ PEVENT_BASIC_INFORMATION BasicInformation\n    )\n{\n    return NtQueryEvent(\n        EventHandle,\n        EventBasicInformation,\n        BasicInformation,\n        sizeof(EVENT_BASIC_INFORMATION),\n        NULL\n        );\n}\n\nFORCEINLINE\nNTSTATUS\nPhGetMutantBasicInformation(\n    _In_ HANDLE MutantHandle,\n    _Out_ PMUTANT_BASIC_INFORMATION BasicInformation\n    )\n{\n    return NtQueryMutant(\n        MutantHandle,\n        MutantBasicInformation,\n        BasicInformation,\n        sizeof(MUTANT_BASIC_INFORMATION),\n        NULL\n        );\n}\n\nFORCEINLINE\nNTSTATUS\nPhGetMutantOwnerInformation(\n    _In_ HANDLE MutantHandle,\n    _Out_ PMUTANT_OWNER_INFORMATION OwnerInformation\n    )\n{\n    return NtQueryMutant(\n        MutantHandle,\n        MutantOwnerInformation,\n        OwnerInformation,\n        sizeof(MUTANT_OWNER_INFORMATION),\n        NULL\n        );\n}\n\nFORCEINLINE\nNTSTATUS\nPhGetSectionBasicInformation(\n    _In_ HANDLE SectionHandle,\n    _Out_ PSECTION_BASIC_INFORMATION BasicInformation\n    )\n{\n    return NtQuerySection(\n        SectionHandle,\n        SectionBasicInformation,\n        BasicInformation,\n        sizeof(SECTION_BASIC_INFORMATION),\n        NULL\n        );\n}\n\nFORCEINLINE\nNTSTATUS\nPhGetSemaphoreBasicInformation(\n    _In_ HANDLE SemaphoreHandle,\n    _Out_ PSEMAPHORE_BASIC_INFORMATION BasicInformation\n    )\n{\n    return NtQuerySemaphore(\n        SemaphoreHandle,\n        SemaphoreBasicInformation,\n        BasicInformation,\n        sizeof(SEMAPHORE_BASIC_INFORMATION),\n        NULL\n        );\n}\n\nFORCEINLINE\nNTSTATUS\nPhGetTimerBasicInformation(\n    _In_ HANDLE TimerHandle,\n    _Out_ PTIMER_BASIC_INFORMATION BasicInformation\n    )\n{\n    return NtQueryTimer(\n        TimerHandle,\n        TimerBasicInformation,\n        BasicInformation,\n        sizeof(TIMER_BASIC_INFORMATION),\n        NULL\n        );\n}\n\n#endif\n"
  },
  {
    "path": "third_party/phlib/include/phnet.h",
    "content": "#ifndef _PH_PHNET_H\n#define _PH_PHNET_H\n\n#include <inaddr.h>\n#include <in6addr.h>\n\n#define PH_IPV4_NETWORK_TYPE 0x1\n#define PH_IPV6_NETWORK_TYPE 0x2\n#define PH_NETWORK_TYPE_MASK 0x3\n\n#define PH_TCP_PROTOCOL_TYPE 0x10\n#define PH_UDP_PROTOCOL_TYPE 0x20\n#define PH_PROTOCOL_TYPE_MASK 0x30\n\n#define PH_NO_NETWORK_PROTOCOL 0x0\n#define PH_TCP4_NETWORK_PROTOCOL (PH_IPV4_NETWORK_TYPE | PH_TCP_PROTOCOL_TYPE)\n#define PH_TCP6_NETWORK_PROTOCOL (PH_IPV6_NETWORK_TYPE | PH_TCP_PROTOCOL_TYPE)\n#define PH_UDP4_NETWORK_PROTOCOL (PH_IPV4_NETWORK_TYPE | PH_UDP_PROTOCOL_TYPE)\n#define PH_UDP6_NETWORK_PROTOCOL (PH_IPV6_NETWORK_TYPE | PH_UDP_PROTOCOL_TYPE)\n\ntypedef struct _PH_IP_ADDRESS\n{\n    ULONG Type;\n    union\n    {\n        ULONG Ipv4;\n        struct in_addr InAddr;\n        UCHAR Ipv6[16];\n        struct in6_addr In6Addr;\n    };\n} PH_IP_ADDRESS, *PPH_IP_ADDRESS;\n\nFORCEINLINE BOOLEAN PhEqualIpAddress(\n    _In_ PPH_IP_ADDRESS Address1,\n    _In_ PPH_IP_ADDRESS Address2\n    )\n{\n    if ((Address1->Type | Address2->Type) == 0) // don't check addresses if both are invalid\n        return TRUE;\n    if (Address1->Type != Address2->Type)\n        return FALSE;\n\n    if (Address1->Type == PH_IPV4_NETWORK_TYPE)\n    {\n        return Address1->Ipv4 == Address2->Ipv4;\n    }\n    else\n    {\n#ifdef _WIN64\n        return\n            *(PULONG64)(Address1->Ipv6) == *(PULONG64)(Address2->Ipv6) &&\n            *(PULONG64)(Address1->Ipv6 + 8) == *(PULONG64)(Address2->Ipv6 + 8);\n#else\n        return\n            *(PULONG)(Address1->Ipv6) == *(PULONG)(Address2->Ipv6) &&\n            *(PULONG)(Address1->Ipv6 + 4) == *(PULONG)(Address2->Ipv6 + 4) &&\n            *(PULONG)(Address1->Ipv6 + 8) == *(PULONG)(Address2->Ipv6 + 8) &&\n            *(PULONG)(Address1->Ipv6 + 12) == *(PULONG)(Address2->Ipv6 + 12);\n#endif\n    }\n}\n\nFORCEINLINE ULONG PhHashIpAddress(\n    _In_ PPH_IP_ADDRESS Address\n    )\n{\n    ULONG hash = 0;\n\n    if (Address->Type == 0)\n        return 0;\n\n    hash = Address->Type | (Address->Type << 16);\n\n    if (Address->Type == PH_IPV4_NETWORK_TYPE)\n    {\n        hash ^= Address->Ipv4;\n    }\n    else\n    {\n        hash += *(PULONG)(Address->Ipv6);\n        hash ^= *(PULONG)(Address->Ipv6 + 4);\n        hash += *(PULONG)(Address->Ipv6 + 8);\n        hash ^= *(PULONG)(Address->Ipv6 + 12);\n    }\n\n    return hash;\n}\n\nFORCEINLINE BOOLEAN PhIsNullIpAddress(\n    _In_ PPH_IP_ADDRESS Address\n    )\n{\n    if (Address->Type == 0)\n    {\n        return TRUE;\n    }\n    else if (Address->Type == PH_IPV4_NETWORK_TYPE)\n    {\n        return Address->Ipv4 == 0;\n    }\n    else if (Address->Type == PH_IPV6_NETWORK_TYPE)\n    {\n#ifdef _WIN64\n        return (*(PULONG64)(Address->Ipv6) | *(PULONG64)(Address->Ipv6 + 8)) == 0;\n#else\n        return (*(PULONG)(Address->Ipv6) | *(PULONG)(Address->Ipv6 + 4) |\n            *(PULONG)(Address->Ipv6 + 8) | *(PULONG)(Address->Ipv6 + 12)) == 0;\n#endif\n    }\n    else\n    {\n        return TRUE;\n    }\n}\n\ntypedef struct _PH_IP_ENDPOINT\n{\n    PH_IP_ADDRESS Address;\n    ULONG Port;\n} PH_IP_ENDPOINT, *PPH_IP_ENDPOINT;\n\nFORCEINLINE BOOLEAN PhEqualIpEndpoint(\n    _In_ PPH_IP_ENDPOINT Endpoint1,\n    _In_ PPH_IP_ENDPOINT Endpoint2\n    )\n{\n    return\n        PhEqualIpAddress(&Endpoint1->Address, &Endpoint2->Address) &&\n        Endpoint1->Port == Endpoint2->Port;\n}\n\nFORCEINLINE ULONG PhHashIpEndpoint(\n    _In_ PPH_IP_ENDPOINT Endpoint\n    )\n{\n    return PhHashIpAddress(&Endpoint->Address) ^ Endpoint->Port;\n}\n\n#endif\n"
  },
  {
    "path": "third_party/phlib/include/phsup.h",
    "content": "#ifndef _PH_PHSUP_H\n#define _PH_PHSUP_H\n\n// This header file provides some useful definitions specific to phlib.\n\n#include <intrin.h>\n#include <wchar.h>\n#include <assert.h>\n#include <stdio.h>\n\n// Memory\n\n#define PTR_ADD_OFFSET(Pointer, Offset) ((PVOID)((ULONG_PTR)(Pointer) + (ULONG_PTR)(Offset)))\n#define PTR_SUB_OFFSET(Pointer, Offset) ((PVOID)((ULONG_PTR)(Pointer) - (ULONG_PTR)(Offset)))\n#define ALIGN_UP_BY(Address, Align) (((ULONG_PTR)(Address) + (Align) - 1) & ~((Align) - 1))\n#define ALIGN_UP_POINTER_BY(Pointer, Align) ((PVOID)ALIGN_UP_BY(Pointer, Align))\n#define ALIGN_UP(Address, Type) ALIGN_UP_BY(Address, sizeof(Type))\n#define ALIGN_UP_POINTER(Pointer, Type) ((PVOID)ALIGN_UP(Pointer, Type))\n#define ALIGN_DOWN_BY(Address, Align) ((ULONG_PTR)(Address) & ~((ULONG_PTR)(Align) - 1))\n#define ALIGN_DOWN_POINTER_BY(Pointer, Align) ((PVOID)ALIGN_DOWN_BY(Pointer, Align))\n#define ALIGN_DOWN(Address, Type) ALIGN_DOWN_BY(Address, sizeof(Type))\n#define ALIGN_DOWN_POINTER(Pointer, Type) ((PVOID)ALIGN_DOWN(Pointer, Type))\n\n#define PAGE_SIZE 0x1000\n\n#define PH_LARGE_BUFFER_SIZE (256 * 1024 * 1024)\n\n// Exceptions\n\n#define PhRaiseStatus(Status) RtlRaiseStatus(Status)\n\n#define SIMPLE_EXCEPTION_FILTER(Condition) \\\n    ((Condition) ? EXCEPTION_EXECUTE_HANDLER : EXCEPTION_CONTINUE_SEARCH)\n\n// Compiler\n\n#ifdef DEBUG\n#define ASSUME_ASSERT(Expression) assert(Expression)\n#define ASSUME_NO_DEFAULT assert(FALSE)\n#else\n#define ASSUME_ASSERT(Expression) __assume(Expression)\n#define ASSUME_NO_DEFAULT __assume(FALSE)\n#endif\n\n// Time\n\n#define PH_TICKS_PER_NS ((LONG64)1 * 10)\n#define PH_TICKS_PER_MS (PH_TICKS_PER_NS * 1000)\n#define PH_TICKS_PER_SEC (PH_TICKS_PER_MS * 1000)\n#define PH_TICKS_PER_MIN (PH_TICKS_PER_SEC * 60)\n#define PH_TICKS_PER_HOUR (PH_TICKS_PER_MIN * 60)\n#define PH_TICKS_PER_DAY (PH_TICKS_PER_HOUR * 24)\n\n#define PH_TICKS_PARTIAL_MS(Ticks) (((ULONG64)(Ticks) / PH_TICKS_PER_MS) % 1000)\n#define PH_TICKS_PARTIAL_SEC(Ticks) (((ULONG64)(Ticks) / PH_TICKS_PER_SEC) % 60)\n#define PH_TICKS_PARTIAL_MIN(Ticks) (((ULONG64)(Ticks) / PH_TICKS_PER_MIN) % 60)\n#define PH_TICKS_PARTIAL_HOURS(Ticks) (((ULONG64)(Ticks) / PH_TICKS_PER_HOUR) % 24)\n#define PH_TICKS_PARTIAL_DAYS(Ticks) ((ULONG64)(Ticks) / PH_TICKS_PER_DAY)\n\n#define PH_TIMEOUT_MS PH_TICKS_PER_MS\n#define PH_TIMEOUT_SEC PH_TICKS_PER_SEC\n\n// Annotations\n\n/**\n * Indicates that a function assumes the specified number of references are available for the\n * object.\n *\n * \\remarks Usually functions reference objects if they store them for later usage; this annotation\n * specifies that the caller must supply these extra references itself. In effect these references\n * are \"transferred\" to the function and must not be used. E.g. if you create an object and\n * immediately call a function with _Assume_refs_(1), you may no longer use the object since that\n * one reference you held is no longer yours.\n */\n#define _Assume_refs_(count)\n\n#define _Callback_\n\n/**\n * Indicates that a function may raise a software exception.\n *\n * \\remarks Do not use this annotation for temporary usages of exceptions, e.g. unimplemented\n * functions.\n */\n#define _May_raise_\n\n/**\n * Indicates that a function requires the specified value to be aligned at the specified number of\n * bytes.\n */\n#define _Needs_align_(align)\n\n// Casts\n\n// Zero extension and sign extension macros\n#define C_1uTo2(x) ((unsigned short)(unsigned char)(x))\n#define C_1sTo2(x) ((unsigned short)(signed char)(x))\n#define C_1uTo4(x) ((unsigned int)(unsigned char)(x))\n#define C_1sTo4(x) ((unsigned int)(signed char)(x))\n#define C_2uTo4(x) ((unsigned int)(unsigned short)(x))\n#define C_2sTo4(x) ((unsigned int)(signed short)(x))\n#define C_4uTo8(x) ((unsigned __int64)(unsigned int)(x))\n#define C_4sTo8(x) ((unsigned __int64)(signed int)(x))\n\n// Sorting\n\ntypedef enum _PH_SORT_ORDER\n{\n    NoSortOrder = 0,\n    AscendingSortOrder,\n    DescendingSortOrder\n} PH_SORT_ORDER, *PPH_SORT_ORDER;\n\nFORCEINLINE LONG PhModifySort(\n    _In_ LONG Result,\n    _In_ PH_SORT_ORDER Order\n    )\n{\n    if (Order == AscendingSortOrder)\n        return Result;\n    else if (Order == DescendingSortOrder)\n        return -Result;\n    else\n        return Result;\n}\n\n#define PH_BUILTIN_COMPARE(value1, value2) \\\n    if (value1 > value2) \\\n        return 1; \\\n    else if (value1 < value2) \\\n        return -1; \\\n    \\\n    return 0\n\nFORCEINLINE int charcmp(\n    _In_ signed char value1,\n    _In_ signed char value2\n    )\n{\n    return C_1sTo4(value1 - value2);\n}\n\nFORCEINLINE int ucharcmp(\n    _In_ unsigned char value1,\n    _In_ unsigned char value2\n    )\n{\n    PH_BUILTIN_COMPARE(value1, value2);\n}\n\nFORCEINLINE int shortcmp(\n    _In_ signed short value1,\n    _In_ signed short value2\n    )\n{\n    return C_2sTo4(value1 - value2);\n}\n\nFORCEINLINE int ushortcmp(\n    _In_ unsigned short value1,\n    _In_ unsigned short value2\n    )\n{\n    PH_BUILTIN_COMPARE(value1, value2);\n}\n\nFORCEINLINE int intcmp(\n    _In_ int value1,\n    _In_ int value2\n    )\n{\n    return value1 - value2;\n}\n\nFORCEINLINE int uintcmp(\n    _In_ unsigned int value1,\n    _In_ unsigned int value2\n    )\n{\n    PH_BUILTIN_COMPARE(value1, value2);\n}\n\nFORCEINLINE int int64cmp(\n    _In_ __int64 value1,\n    _In_ __int64 value2\n    )\n{\n    PH_BUILTIN_COMPARE(value1, value2);\n}\n\nFORCEINLINE int uint64cmp(\n    _In_ unsigned __int64 value1,\n    _In_ unsigned __int64 value2\n    )\n{\n    PH_BUILTIN_COMPARE(value1, value2);\n}\n\nFORCEINLINE int intptrcmp(\n    _In_ LONG_PTR value1,\n    _In_ LONG_PTR value2\n    )\n{\n    PH_BUILTIN_COMPARE(value1, value2);\n}\n\nFORCEINLINE int uintptrcmp(\n    _In_ ULONG_PTR value1,\n    _In_ ULONG_PTR value2\n    )\n{\n    PH_BUILTIN_COMPARE(value1, value2);\n}\n\nFORCEINLINE int singlecmp(\n    _In_ float value1,\n    _In_ float value2\n    )\n{\n    PH_BUILTIN_COMPARE(value1, value2);\n}\n\nFORCEINLINE int doublecmp(\n    _In_ double value1,\n    _In_ double value2\n    )\n{\n    PH_BUILTIN_COMPARE(value1, value2);\n}\n\nFORCEINLINE int wcsicmp2(\n    _In_opt_ PWSTR Value1,\n    _In_opt_ PWSTR Value2\n    )\n{\n    if (Value1 && Value2)\n        return _wcsicmp(Value1, Value2);\n    else if (!Value1)\n        return !Value2 ? 0 : -1;\n    else\n        return 1;\n}\n\ntypedef int (__cdecl *PC_COMPARE_FUNCTION)(void *, const void *, const void *);\n\n// Synchronization\n\n#ifndef _WIN64\n\n#ifndef _InterlockedCompareExchangePointer\nvoid *_InterlockedCompareExchangePointer(\n    void *volatile *Destination,\n    void *Exchange,\n    void *Comparand\n    );\n#endif\n\n#if (_MSC_VER < 1900)\n#ifndef _InterlockedExchangePointer\nFORCEINLINE void *_InterlockedExchangePointer(\n    void *volatile *Destination,\n    void *Exchange\n    )\n{\n    return (PVOID)_InterlockedExchange(\n        (PLONG_PTR)Destination,\n        (LONG_PTR)Exchange\n        );\n}\n#endif\n#endif\n\n#endif\n\nFORCEINLINE LONG_PTR _InterlockedExchangeAddPointer(\n    _Inout_ _Interlocked_operand_ LONG_PTR volatile *Addend,\n    _In_ LONG_PTR Value\n    )\n{\n#ifdef _WIN64\n    return (LONG_PTR)_InterlockedExchangeAdd64((PLONG64)Addend, (LONG64)Value);\n#else\n    return (LONG_PTR)_InterlockedExchangeAdd((PLONG)Addend, (LONG)Value);\n#endif\n}\n\nFORCEINLINE LONG_PTR _InterlockedIncrementPointer(\n    _Inout_ _Interlocked_operand_ LONG_PTR volatile *Addend\n    )\n{\n#ifdef _WIN64\n    return (LONG_PTR)_InterlockedIncrement64((PLONG64)Addend);\n#else\n    return (LONG_PTR)_InterlockedIncrement((PLONG)Addend);\n#endif\n}\n\nFORCEINLINE LONG_PTR _InterlockedDecrementPointer(\n    _Inout_ _Interlocked_operand_ LONG_PTR volatile *Addend\n    )\n{\n#ifdef _WIN64\n    return (LONG_PTR)_InterlockedDecrement64((PLONG64)Addend);\n#else\n    return (LONG_PTR)_InterlockedDecrement((PLONG)Addend);\n#endif\n}\n\nFORCEINLINE BOOLEAN _InterlockedBitTestAndResetPointer(\n    _Inout_ _Interlocked_operand_ LONG_PTR volatile *Base,\n    _In_ LONG_PTR Bit\n    )\n{\n#ifdef _WIN64\n    return _interlockedbittestandreset64((PLONG64)Base, (LONG64)Bit);\n#else\n    return _interlockedbittestandreset((PLONG)Base, (LONG)Bit);\n#endif\n}\n\nFORCEINLINE BOOLEAN _InterlockedBitTestAndSetPointer(\n    _Inout_ _Interlocked_operand_ LONG_PTR volatile *Base,\n    _In_ LONG_PTR Bit\n    )\n{\n#ifdef _WIN64\n    return _interlockedbittestandset64((PLONG64)Base, (LONG64)Bit);\n#else\n    return _interlockedbittestandset((PLONG)Base, (LONG)Bit);\n#endif\n}\n\nFORCEINLINE BOOLEAN _InterlockedIncrementNoZero(\n    _Inout_ _Interlocked_operand_ LONG volatile *Addend\n    )\n{\n    LONG value;\n    LONG newValue;\n\n    value = *Addend;\n\n    while (TRUE)\n    {\n        if (value == 0)\n            return FALSE;\n\n        if ((newValue = _InterlockedCompareExchange(\n            Addend,\n            value + 1,\n            value\n            )) == value)\n        {\n            return TRUE;\n        }\n\n        value = newValue;\n    }\n}\n\nFORCEINLINE BOOLEAN _InterlockedIncrementPositive(\n    _Inout_ _Interlocked_operand_ LONG volatile *Addend\n    )\n{\n    LONG value;\n    LONG newValue;\n\n    value = *Addend;\n\n    while (TRUE)\n    {\n        if (value <= 0)\n            return FALSE;\n\n        if ((newValue = _InterlockedCompareExchange(\n            Addend,\n            value + 1,\n            value\n            )) == value)\n        {\n            return TRUE;\n        }\n\n        value = newValue;\n    }\n}\n\n// Strings\n\n#define PH_INT32_STR_LEN 12\n#define PH_INT32_STR_LEN_1 (PH_INT32_STR_LEN + 1)\n\n#define PH_INT64_STR_LEN 50\n#define PH_INT64_STR_LEN_1 (PH_INT64_STR_LEN + 1)\n\n#define PH_PTR_STR_LEN 24\n#define PH_PTR_STR_LEN_1 (PH_PTR_STR_LEN + 1)\n\nFORCEINLINE VOID PhPrintInt32(\n    _Out_writes_(PH_INT32_STR_LEN_1) PWSTR Destination,\n    _In_ LONG Int32\n    )\n{\n    _ltow(Int32, Destination, 10);\n}\n\nFORCEINLINE VOID PhPrintUInt32(\n    _Out_writes_(PH_INT32_STR_LEN_1) PWSTR Destination,\n    _In_ ULONG UInt32\n    )\n{\n    _ultow(UInt32, Destination, 10);\n}\n\nFORCEINLINE VOID PhPrintInt64(\n    _Out_writes_(PH_INT64_STR_LEN_1) PWSTR Destination,\n    _In_ LONG64 Int64\n    )\n{\n    _i64tow(Int64, Destination, 10);\n}\n\nFORCEINLINE VOID PhPrintUInt64(\n    _Out_writes_(PH_INT64_STR_LEN_1) PWSTR Destination,\n    _In_ ULONG64 UInt64\n    )\n{\n    _ui64tow(UInt64, Destination, 10);\n}\n\nFORCEINLINE VOID PhPrintPointer(\n    _Out_writes_(PH_PTR_STR_LEN_1) PWSTR Destination,\n    _In_ PVOID Pointer\n    )\n{\n    Destination[0] = '0';\n    Destination[1] = 'x';\n#ifdef _WIN64\n    _ui64tow((ULONG64)Pointer, &Destination[2], 16);\n#else\n    _ultow((ULONG)Pointer, &Destination[2], 16);\n#endif\n}\n\n// Misc.\n\nFORCEINLINE ULONG PhCountBits(\n    _In_ ULONG Value\n    )\n{\n    ULONG count = 0;\n\n    while (Value)\n    {\n        count++;\n        Value &= Value - 1;\n    }\n\n    return count;\n}\n\nFORCEINLINE ULONG64 PhRoundNumber(\n    _In_ ULONG64 Value,\n    _In_ ULONG64 Granularity\n    )\n{\n    return (Value + Granularity / 2) / Granularity * Granularity;\n}\n\nFORCEINLINE ULONG PhMultiplyDivide(\n    _In_ ULONG Number,\n    _In_ ULONG Numerator,\n    _In_ ULONG Denominator\n    )\n{\n    return (ULONG)(((ULONG64)Number * (ULONG64)Numerator + Denominator / 2) / (ULONG64)Denominator);\n}\n\nFORCEINLINE LONG PhMultiplyDivideSigned(\n    _In_ LONG Number,\n    _In_ ULONG Numerator,\n    _In_ ULONG Denominator\n    )\n{\n    if (Number >= 0)\n        return PhMultiplyDivide(Number, Numerator, Denominator);\n    else\n        return -(LONG)PhMultiplyDivide(-Number, Numerator, Denominator);\n}\n\nFORCEINLINE VOID PhProbeAddress(\n    _In_ PVOID UserAddress,\n    _In_ SIZE_T UserLength,\n    _In_ PVOID BufferAddress,\n    _In_ SIZE_T BufferLength,\n    _In_ ULONG Alignment\n    )\n{\n    if (UserLength != 0)\n    {\n        if (((ULONG_PTR)UserAddress & (Alignment - 1)) != 0)\n            PhRaiseStatus(STATUS_DATATYPE_MISALIGNMENT);\n\n        if (\n            ((ULONG_PTR)UserAddress + UserLength < (ULONG_PTR)UserAddress) ||\n            ((ULONG_PTR)UserAddress < (ULONG_PTR)BufferAddress) ||\n            ((ULONG_PTR)UserAddress + UserLength > (ULONG_PTR)BufferAddress + BufferLength)\n            )\n            PhRaiseStatus(STATUS_ACCESS_VIOLATION);\n    }\n}\n\nFORCEINLINE PLARGE_INTEGER PhTimeoutFromMilliseconds(\n    _Out_ PLARGE_INTEGER Timeout,\n    _In_ ULONG Milliseconds\n    )\n{\n    if (Milliseconds == INFINITE)\n        return NULL;\n\n    Timeout->QuadPart = -(LONGLONG)UInt32x32To64(Milliseconds, PH_TIMEOUT_MS);\n\n    return Timeout;\n}\n\nFORCEINLINE NTSTATUS PhGetLastWin32ErrorAsNtStatus()\n{\n    ULONG win32Result;\n\n    // This is needed because NTSTATUS_FROM_WIN32 uses the argument multiple times.\n    win32Result = GetLastError();\n\n    return NTSTATUS_FROM_WIN32(win32Result);\n}\n\n#endif\n"
  },
  {
    "path": "third_party/phlib/include/phutil.h",
    "content": "#ifndef _PH_PHUTIL_H\n#define _PH_PHUTIL_H\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\nextern WCHAR *PhSizeUnitNames[7];\nextern ULONG PhMaxSizeUnit;\n\ntypedef struct _PH_INTEGER_PAIR\n{\n    LONG X;\n    LONG Y;\n} PH_INTEGER_PAIR, *PPH_INTEGER_PAIR;\n\ntypedef struct _PH_SCALABLE_INTEGER_PAIR\n{\n    union\n    {\n        PH_INTEGER_PAIR Pair;\n        struct\n        {\n            LONG X;\n            LONG Y;\n        };\n    };\n    ULONG Scale;\n} PH_SCALABLE_INTEGER_PAIR, *PPH_SCALABLE_INTEGER_PAIR;\n\ntypedef struct _PH_RECTANGLE\n{\n    union\n    {\n        PH_INTEGER_PAIR Position;\n        struct\n        {\n            LONG Left;\n            LONG Top;\n        };\n    };\n    union\n    {\n        PH_INTEGER_PAIR Size;\n        struct\n        {\n            LONG Width;\n            LONG Height;\n        };\n    };\n} PH_RECTANGLE, *PPH_RECTANGLE;\n\nFORCEINLINE\nPH_RECTANGLE\nPhRectToRectangle(\n    _In_ RECT Rect\n    )\n{\n    PH_RECTANGLE rectangle;\n\n    rectangle.Left = Rect.left;\n    rectangle.Top = Rect.top;\n    rectangle.Width = Rect.right - Rect.left;\n    rectangle.Height = Rect.bottom - Rect.top;\n\n    return rectangle;\n}\n\nFORCEINLINE\nRECT\nPhRectangleToRect(\n    _In_ PH_RECTANGLE Rectangle\n    )\n{\n    RECT rect;\n\n    rect.left = Rectangle.Left;\n    rect.top = Rectangle.Top;\n    rect.right = Rectangle.Left + Rectangle.Width;\n    rect.bottom = Rectangle.Top + Rectangle.Height;\n\n    return rect;\n}\n\nFORCEINLINE\nVOID\nPhConvertRect(\n    _Inout_ PRECT Rect,\n    _In_ PRECT ParentRect\n    )\n{\n    Rect->right = ParentRect->right - ParentRect->left - Rect->right;\n    Rect->bottom = ParentRect->bottom - ParentRect->top - Rect->bottom;\n}\n\nFORCEINLINE\nRECT\nPhMapRect(\n    _In_ RECT InnerRect,\n    _In_ RECT OuterRect\n    )\n{\n    RECT rect;\n\n    rect.left = InnerRect.left - OuterRect.left;\n    rect.top = InnerRect.top - OuterRect.top;\n    rect.right = InnerRect.right - OuterRect.left;\n    rect.bottom = InnerRect.bottom - OuterRect.top;\n\n    return rect;\n}\n\nPHLIBAPI\nVOID\nNTAPI\nPhAdjustRectangleToBounds(\n    _Inout_ PPH_RECTANGLE Rectangle,\n    _In_ PPH_RECTANGLE Bounds\n    );\n\nPHLIBAPI\nVOID\nNTAPI\nPhCenterRectangle(\n    _Inout_ PPH_RECTANGLE Rectangle,\n    _In_ PPH_RECTANGLE Bounds\n    );\n\nPHLIBAPI\nVOID\nNTAPI\nPhAdjustRectangleToWorkingArea(\n    _In_opt_ HWND hWnd,\n    _Inout_ PPH_RECTANGLE Rectangle\n    );\n\nPHLIBAPI\nVOID\nNTAPI\nPhCenterWindow(\n    _In_ HWND WindowHandle,\n    _In_opt_ HWND ParentWindowHandle\n    );\n\nFORCEINLINE\nVOID\nPhLargeIntegerToSystemTime(\n    _Out_ PSYSTEMTIME SystemTime,\n    _In_ PLARGE_INTEGER LargeInteger\n    )\n{\n    FILETIME fileTime;\n\n    fileTime.dwLowDateTime = LargeInteger->LowPart;\n    fileTime.dwHighDateTime = LargeInteger->HighPart;\n    FileTimeToSystemTime(&fileTime, SystemTime);\n}\n\nFORCEINLINE\nVOID\nPhLargeIntegerToLocalSystemTime(\n    _Out_ PSYSTEMTIME SystemTime,\n    _In_ PLARGE_INTEGER LargeInteger\n    )\n{\n    FILETIME fileTime;\n    FILETIME newFileTime;\n\n    fileTime.dwLowDateTime = LargeInteger->LowPart;\n    fileTime.dwHighDateTime = LargeInteger->HighPart;\n    FileTimeToLocalFileTime(&fileTime, &newFileTime);\n    FileTimeToSystemTime(&newFileTime, SystemTime);\n}\n\nPHLIBAPI\nVOID\nNTAPI\nPhReferenceObjects(\n    _In_reads_(NumberOfObjects) PVOID *Objects,\n    _In_ ULONG NumberOfObjects\n    );\n\nPHLIBAPI\nVOID\nNTAPI\nPhDereferenceObjects(\n    _In_reads_(NumberOfObjects) PVOID *Objects,\n    _In_ ULONG NumberOfObjects\n    );\n\nPHLIBAPI\nPPH_STRING\nNTAPI\nPhGetMessage(\n    _In_ PVOID DllHandle,\n    _In_ ULONG MessageTableId,\n    _In_ ULONG MessageLanguageId,\n    _In_ ULONG MessageId\n    );\n\nPHLIBAPI\nPPH_STRING\nNTAPI\nPhGetNtMessage(\n    _In_ NTSTATUS Status\n    );\n\nPHLIBAPI\nPPH_STRING\nNTAPI\nPhGetWin32Message(\n    _In_ ULONG Result\n    );\n\nPHLIBAPI\nINT\nNTAPI\nPhShowMessage(\n    _In_ HWND hWnd,\n    _In_ ULONG Type,\n    _In_ PWSTR Format,\n    ...\n    );\n\n#define PhShowError(hWnd, Format, ...) PhShowMessage(hWnd, MB_OK | MB_ICONERROR, Format, __VA_ARGS__)\n#define PhShowWarning(hWnd, Format, ...) PhShowMessage(hWnd, MB_OK | MB_ICONWARNING, Format, __VA_ARGS__)\n#define PhShowInformation(hWnd, Format, ...) PhShowMessage(hWnd, MB_OK | MB_ICONINFORMATION, Format, __VA_ARGS__)\n\nPHLIBAPI\nINT \nNTAPI\nPhShowMessage2(\n    _In_ HWND hWnd,\n    _In_ ULONG Buttons,\n    _In_opt_ PWSTR Icon,\n    _In_opt_ PWSTR Title,\n    _In_ PWSTR Format,\n    ...\n    );\n\n#define PhShowError2(hWnd, Format, ...) PhShowMessage2(hWnd, TDCBF_CLOSE_BUTTON, TD_ERROR_ICON, Format, __VA_ARGS__)\n#define PhShowWarning2(hWnd, Format, ...) PhShowMessage2(hWnd, TDCBF_CLOSE_BUTTON, TD_WARNING_ICON, Format, __VA_ARGS__)\n#define PhShowInformation2(hWnd, Format, ...) PhShowMessage2(hWnd, TDCBF_CLOSE_BUTTON, TD_INFORMATION_ICON, Format, __VA_ARGS__)\n\nPHLIBAPI\nPPH_STRING\nNTAPI\nPhGetStatusMessage(\n    _In_ NTSTATUS Status,\n    _In_opt_ ULONG Win32Result\n    );\n\nPHLIBAPI\nVOID\nNTAPI\nPhShowStatus(\n    _In_ HWND hWnd,\n    _In_opt_ PWSTR Message,\n    _In_ NTSTATUS Status,\n    _In_opt_ ULONG Win32Result\n    );\n\nPHLIBAPI\nBOOLEAN\nNTAPI\nPhShowContinueStatus(\n    _In_ HWND hWnd,\n    _In_opt_ PWSTR Message,\n    _In_ NTSTATUS Status,\n    _In_opt_ ULONG Win32Result\n    );\n\nPHLIBAPI\nBOOLEAN\nNTAPI\nPhShowConfirmMessage(\n    _In_ HWND hWnd,\n    _In_ PWSTR Verb,\n    _In_ PWSTR Object,\n    _In_opt_ PWSTR Message,\n    _In_ BOOLEAN Warning\n    );\n\nPHLIBAPI\nBOOLEAN\nNTAPI\nPhFindIntegerSiKeyValuePairs(\n    _In_ PPH_KEY_VALUE_PAIR KeyValuePairs,\n    _In_ ULONG SizeOfKeyValuePairs,\n    _In_ PWSTR String,\n    _Out_ PULONG Integer\n    );\n\nPHLIBAPI\nBOOLEAN\nNTAPI\nPhFindStringSiKeyValuePairs(\n    _In_ PPH_KEY_VALUE_PAIR KeyValuePairs,\n    _In_ ULONG SizeOfKeyValuePairs,\n    _In_ ULONG Integer,\n    _Out_ PWSTR *String\n    );\n\n#define GUID_VERSION_MAC 1\n#define GUID_VERSION_DCE 2\n#define GUID_VERSION_MD5 3\n#define GUID_VERSION_RANDOM 4\n#define GUID_VERSION_SHA1 5\n\n#define GUID_VARIANT_NCS_MASK 0x80\n#define GUID_VARIANT_NCS 0x00\n#define GUID_VARIANT_STANDARD_MASK 0xc0\n#define GUID_VARIANT_STANDARD 0x80\n#define GUID_VARIANT_MICROSOFT_MASK 0xe0\n#define GUID_VARIANT_MICROSOFT 0xc0\n#define GUID_VARIANT_RESERVED_MASK 0xe0\n#define GUID_VARIANT_RESERVED 0xe0\n\ntypedef union _GUID_EX\n{\n    GUID Guid;\n    UCHAR Data[16];\n    struct\n    {\n        ULONG TimeLowPart;\n        USHORT TimeMidPart;\n        USHORT TimeHighPart;\n        UCHAR ClockSequenceHigh;\n        UCHAR ClockSequenceLow;\n        UCHAR Node[6];\n    } s;\n    struct\n    {\n        ULONG Part0;\n        USHORT Part32;\n        UCHAR Part48;\n        UCHAR Part56 : 4;\n        UCHAR Version : 4;\n        UCHAR Variant;\n        UCHAR Part72;\n        USHORT Part80;\n        ULONG Part96;\n    } s2;\n} GUID_EX, *PGUID_EX;\n\nPHLIBAPI\nVOID\nNTAPI\nPhGenerateGuid(\n    _Out_ PGUID Guid\n    );\n\nPHLIBAPI\nVOID\nNTAPI\nPhGenerateGuidFromName(\n    _Out_ PGUID Guid,\n    _In_ PGUID Namespace,\n    _In_ PCHAR Name,\n    _In_ ULONG NameLength,\n    _In_ UCHAR Version\n    );\n\nPHLIBAPI\nVOID\nNTAPI\nPhGenerateRandomAlphaString(\n    _Out_writes_z_(Count) PWSTR Buffer,\n    _In_ ULONG Count\n    );\n\nPHLIBAPI\nPPH_STRING\nNTAPI\nPhEllipsisString(\n    _In_ PPH_STRING String,\n    _In_ ULONG DesiredCount\n    );\n\nPHLIBAPI\nPPH_STRING\nNTAPI\nPhEllipsisStringPath(\n    _In_ PPH_STRING String,\n    _In_ ULONG DesiredCount\n    );\n\nPHLIBAPI\nBOOLEAN\nNTAPI\nPhMatchWildcards(\n    _In_ PWSTR Pattern,\n    _In_ PWSTR String,\n    _In_ BOOLEAN IgnoreCase\n    );\n\nPHLIBAPI\nPPH_STRING\nNTAPI\nPhEscapeStringForMenuPrefix(\n    _In_ PPH_STRINGREF String\n    );\n\nPHLIBAPI\nLONG\nNTAPI\nPhCompareUnicodeStringZIgnoreMenuPrefix(\n    _In_ PWSTR A,\n    _In_ PWSTR B,\n    _In_ BOOLEAN IgnoreCase,\n    _In_ BOOLEAN MatchIfPrefix\n    );\n\nPHLIBAPI\nPPH_STRING\nNTAPI\nPhFormatDate(\n    _In_opt_ PSYSTEMTIME Date,\n    _In_opt_ PWSTR Format\n    );\n\nPHLIBAPI\nPPH_STRING\nNTAPI\nPhFormatTime(\n    _In_opt_ PSYSTEMTIME Time,\n    _In_opt_ PWSTR Format\n    );\n\nPHLIBAPI\nPPH_STRING\nNTAPI\nPhFormatDateTime(\n    _In_opt_ PSYSTEMTIME DateTime\n    );\n\n#define PhaFormatDateTime(DateTime) PH_AUTO_T(PH_STRING, PhFormatDateTime(DateTime))\n\nPHLIBAPI\nPPH_STRING\nNTAPI\nPhFormatTimeSpan(\n    _In_ ULONG64 Ticks,\n    _In_opt_ ULONG Mode\n    );\n\nPHLIBAPI\nPPH_STRING\nNTAPI\nPhFormatTimeSpanRelative(\n    _In_ ULONG64 TimeSpan\n    );\n\nPHLIBAPI\nPPH_STRING\nNTAPI\nPhFormatUInt64(\n    _In_ ULONG64 Value,\n    _In_ BOOLEAN GroupDigits\n    );\n\n#define PhaFormatUInt64(Value, GroupDigits) PH_AUTO_T(PH_STRING, PhFormatUInt64((Value), (GroupDigits)))\n\nPHLIBAPI\nPPH_STRING\nNTAPI\nPhFormatDecimal(\n    _In_ PWSTR Value,\n    _In_ ULONG FractionalDigits,\n    _In_ BOOLEAN GroupDigits\n    );\n\n#define PhaFormatDecimal(Value, FractionalDigits, GroupDigits) \\\n    PH_AUTO_T(PH_STRING, PhFormatDecimal((Value), (FractionalDigits), (GroupDigits)))\n\nPHLIBAPI\nPPH_STRING\nNTAPI\nPhFormatSize(\n    _In_ ULONG64 Size,\n    _In_ ULONG MaxSizeUnit\n    );\n\n#define PhaFormatSize(Size, MaxSizeUnit) PH_AUTO_T(PH_STRING, PhFormatSize((Size), (MaxSizeUnit)))\n\nPHLIBAPI\nPPH_STRING\nNTAPI\nPhFormatGuid(\n    _In_ PGUID Guid\n    );\n\nPHLIBAPI\nPVOID\nNTAPI\nPhGetFileVersionInfo(\n    _In_ PWSTR FileName\n    );\n\nPHLIBAPI\nULONG\nNTAPI\nPhGetFileVersionInfoLangCodePage(\n    _In_ PVOID VersionInfo\n    );\n\nPHLIBAPI\nPPH_STRING\nNTAPI\nPhGetFileVersionInfoString(\n    _In_ PVOID VersionInfo,\n    _In_ PWSTR SubBlock\n    );\n\nPHLIBAPI\nPPH_STRING\nNTAPI\nPhGetFileVersionInfoString2(\n    _In_ PVOID VersionInfo,\n    _In_ ULONG LangCodePage,\n    _In_ PWSTR StringName\n    );\n\ntypedef struct _PH_IMAGE_VERSION_INFO\n{\n    PPH_STRING CompanyName;\n    PPH_STRING FileDescription;\n    PPH_STRING FileVersion;\n    PPH_STRING ProductName;\n} PH_IMAGE_VERSION_INFO, *PPH_IMAGE_VERSION_INFO;\n\nPHLIBAPI\nBOOLEAN\nNTAPI\nPhInitializeImageVersionInfo(\n    _Out_ PPH_IMAGE_VERSION_INFO ImageVersionInfo,\n    _In_ PWSTR FileName\n    );\n\nPHLIBAPI\nVOID\nNTAPI\nPhDeleteImageVersionInfo(\n    _Inout_ PPH_IMAGE_VERSION_INFO ImageVersionInfo\n    );\n\nPHLIBAPI\nPPH_STRING\nNTAPI\nPhFormatImageVersionInfo(\n    _In_opt_ PPH_STRING FileName,\n    _In_ PPH_IMAGE_VERSION_INFO ImageVersionInfo,\n    _In_opt_ PPH_STRINGREF Indent,\n    _In_opt_ ULONG LineLimit\n    );\n\nPHLIBAPI\nPPH_STRING\nNTAPI\nPhGetFullPath(\n    _In_ PWSTR FileName,\n    _Out_opt_ PULONG IndexOfFileName\n    );\n\nPHLIBAPI\nPPH_STRING\nNTAPI\nPhExpandEnvironmentStrings(\n    _In_ PPH_STRINGREF String\n    );\n\nPHLIBAPI\nPPH_STRING\nNTAPI\nPhGetBaseName(\n    _In_ PPH_STRING FileName\n    );\n\nPHLIBAPI\nPPH_STRING\nNTAPI\nPhGetBaseDirectory(\n    _In_ PPH_STRING FileName\n    );\n\nPHLIBAPI\nPPH_STRING\nNTAPI\nPhGetSystemDirectory(\n    VOID\n    );\n\nPHLIBAPI\nVOID\nNTAPI\nPhGetSystemRoot(\n    _Out_ PPH_STRINGREF SystemRoot\n    );\n\nPHLIBAPI\nPLDR_DATA_TABLE_ENTRY\nNTAPI\nPhFindLoaderEntry(\n    _In_opt_ PVOID DllBase,\n    _In_opt_ PPH_STRINGREF FullDllName,\n    _In_opt_ PPH_STRINGREF BaseDllName\n    );\n\nPHLIBAPI\nPPH_STRING\nNTAPI\nPhGetDllFileName(\n    _In_ PVOID DllHandle,\n    _Out_opt_ PULONG IndexOfFileName\n    );\n\nPHLIBAPI\nPPH_STRING\nNTAPI\nPhGetApplicationFileName(\n    VOID\n    );\n\nPHLIBAPI\nPPH_STRING\nNTAPI\nPhGetApplicationDirectory(\n    VOID\n    );\n\nPHLIBAPI\nPPH_STRING\nNTAPI\nPhGetKnownLocation(\n    _In_ ULONG Folder,\n    _In_opt_ PWSTR AppendPath\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhWaitForMultipleObjectsAndPump(\n    _In_opt_ HWND hWnd,\n    _In_ ULONG NumberOfHandles,\n    _In_ PHANDLE Handles,\n    _In_ ULONG Timeout\n    );\n\ntypedef struct _PH_CREATE_PROCESS_INFO\n{\n    PUNICODE_STRING DllPath;\n    PUNICODE_STRING WindowTitle;\n    PUNICODE_STRING DesktopInfo;\n    PUNICODE_STRING ShellInfo;\n    PUNICODE_STRING RuntimeData;\n} PH_CREATE_PROCESS_INFO, *PPH_CREATE_PROCESS_INFO;\n\n#define PH_CREATE_PROCESS_INHERIT_HANDLES 0x1\n#define PH_CREATE_PROCESS_UNICODE_ENVIRONMENT 0x2\n#define PH_CREATE_PROCESS_SUSPENDED 0x4\n#define PH_CREATE_PROCESS_BREAKAWAY_FROM_JOB 0x8\n#define PH_CREATE_PROCESS_NEW_CONSOLE 0x10\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhCreateProcess(\n    _In_ PWSTR FileName,\n    _In_opt_ PPH_STRINGREF CommandLine,\n    _In_opt_ PVOID Environment,\n    _In_opt_ PPH_STRINGREF CurrentDirectory,\n    _In_opt_ PPH_CREATE_PROCESS_INFO Information,\n    _In_ ULONG Flags,\n    _In_opt_ HANDLE ParentProcessHandle,\n    _Out_opt_ PCLIENT_ID ClientId,\n    _Out_opt_ PHANDLE ProcessHandle,\n    _Out_opt_ PHANDLE ThreadHandle\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhCreateProcessWin32(\n    _In_opt_ PWSTR FileName,\n    _In_opt_ PWSTR CommandLine,\n    _In_opt_ PVOID Environment,\n    _In_opt_ PWSTR CurrentDirectory,\n    _In_ ULONG Flags,\n    _In_opt_ HANDLE TokenHandle,\n    _Out_opt_ PHANDLE ProcessHandle,\n    _Out_opt_ PHANDLE ThreadHandle\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhCreateProcessWin32Ex(\n    _In_opt_ PWSTR FileName,\n    _In_opt_ PWSTR CommandLine,\n    _In_opt_ PVOID Environment,\n    _In_opt_ PWSTR CurrentDirectory,\n    _In_opt_ STARTUPINFO *StartupInfo,\n    _In_ ULONG Flags,\n    _In_opt_ HANDLE TokenHandle,\n    _Out_opt_ PCLIENT_ID ClientId,\n    _Out_opt_ PHANDLE ProcessHandle,\n    _Out_opt_ PHANDLE ThreadHandle\n    );\n\ntypedef struct _PH_CREATE_PROCESS_AS_USER_INFO\n{\n    _In_opt_ PWSTR ApplicationName;\n    _In_opt_ PWSTR CommandLine;\n    _In_opt_ PWSTR CurrentDirectory;\n    _In_opt_ PVOID Environment;\n    _In_opt_ PWSTR DesktopName;\n    _In_opt_ ULONG SessionId; // use PH_CREATE_PROCESS_SET_SESSION_ID\n    union\n    {\n        struct\n        {\n            _In_ PWSTR DomainName;\n            _In_ PWSTR UserName;\n            _In_ PWSTR Password;\n            _In_opt_ ULONG LogonType;\n        };\n        _In_ HANDLE ProcessIdWithToken; // use PH_CREATE_PROCESS_USE_PROCESS_TOKEN\n        _In_ ULONG SessionIdWithToken; // use PH_CREATE_PROCESS_USE_SESSION_TOKEN\n    };\n} PH_CREATE_PROCESS_AS_USER_INFO, *PPH_CREATE_PROCESS_AS_USER_INFO;\n\n#define PH_CREATE_PROCESS_USE_PROCESS_TOKEN 0x1000\n#define PH_CREATE_PROCESS_USE_SESSION_TOKEN 0x2000\n#define PH_CREATE_PROCESS_USE_LINKED_TOKEN 0x10000\n#define PH_CREATE_PROCESS_SET_SESSION_ID 0x20000\n#define PH_CREATE_PROCESS_WITH_PROFILE 0x40000\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhCreateProcessAsUser(\n    _In_ PPH_CREATE_PROCESS_AS_USER_INFO Information,\n    _In_ ULONG Flags,\n    _Out_opt_ PCLIENT_ID ClientId,\n    _Out_opt_ PHANDLE ProcessHandle,\n    _Out_opt_ PHANDLE ThreadHandle\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhFilterTokenForLimitedUser(\n    _In_ HANDLE TokenHandle,\n    _Out_ PHANDLE NewTokenHandle\n    );\n\nPHLIBAPI\nVOID\nNTAPI\nPhShellExecute(\n    _In_ HWND hWnd,\n    _In_ PWSTR FileName,\n    _In_opt_ PWSTR Parameters\n    );\n\n#define PH_SHELL_EXECUTE_ADMIN 0x1\n#define PH_SHELL_EXECUTE_PUMP_MESSAGES 0x2\n\nPHLIBAPI\nBOOLEAN\nNTAPI\nPhShellExecuteEx(\n    _In_opt_ HWND hWnd,\n    _In_ PWSTR FileName,\n    _In_opt_ PWSTR Parameters,\n    _In_ ULONG ShowWindowType,\n    _In_ ULONG Flags,\n    _In_opt_ ULONG Timeout,\n    _Out_opt_ PHANDLE ProcessHandle\n    );\n\nPHLIBAPI\nVOID\nNTAPI\nPhShellExploreFile(\n    _In_ HWND hWnd,\n    _In_ PWSTR FileName\n    );\n\nPHLIBAPI\nVOID\nNTAPI\nPhShellProperties(\n    _In_ HWND hWnd,\n    _In_ PWSTR FileName\n    );\n\nPHLIBAPI\nPPH_STRING\nNTAPI\nPhExpandKeyName(\n    _In_ PPH_STRING KeyName,\n    _In_ BOOLEAN Computer\n    );\n\nPHLIBAPI\nVOID\nNTAPI\nPhShellOpenKey(\n    _In_ HWND hWnd,\n    _In_ PPH_STRING KeyName\n    );\n\nPHLIBAPI\nPPH_STRING\nNTAPI\nPhQueryRegistryString(\n    _In_ HANDLE KeyHandle,\n    _In_opt_ PWSTR ValueName\n    );\n\nPHLIBAPI\nULONG\nNTAPI\nPhQueryRegistryUlong(\n    _In_ HANDLE KeyHandle,\n    _In_opt_ PWSTR ValueName\n    );\n\nPHLIBAPI\nULONG64\nNTAPI\nPhQueryRegistryUlong64(\n    _In_ HANDLE KeyHandle,\n    _In_opt_ PWSTR ValueName\n    );\n\ntypedef struct _PH_FLAG_MAPPING\n{\n    ULONG Flag1;\n    ULONG Flag2;\n} PH_FLAG_MAPPING, *PPH_FLAG_MAPPING;\n\nPHLIBAPI\nVOID\nNTAPI\nPhMapFlags1(\n    _Inout_ PULONG Value2,\n    _In_ ULONG Value1,\n    _In_ const PH_FLAG_MAPPING *Mappings,\n    _In_ ULONG NumberOfMappings\n    );\n\nPHLIBAPI\nVOID\nNTAPI\nPhMapFlags2(\n    _Inout_ PULONG Value1,\n    _In_ ULONG Value2,\n    _In_ const PH_FLAG_MAPPING *Mappings,\n    _In_ ULONG NumberOfMappings\n    );\n\nPHLIBAPI\nPVOID\nNTAPI\nPhCreateOpenFileDialog(\n    VOID\n    );\n\nPHLIBAPI\nPVOID\nNTAPI\nPhCreateSaveFileDialog(\n    VOID\n    );\n\nPHLIBAPI\nVOID\nNTAPI\nPhFreeFileDialog(\n    _In_ PVOID FileDialog\n    );\n\nPHLIBAPI\nBOOLEAN\nNTAPI\nPhShowFileDialog(\n    _In_ HWND hWnd,\n    _In_ PVOID FileDialog\n    );\n\n#define PH_FILEDIALOG_CREATEPROMPT 0x1\n#define PH_FILEDIALOG_PATHMUSTEXIST 0x2 // default both\n#define PH_FILEDIALOG_FILEMUSTEXIST 0x4 // default open\n#define PH_FILEDIALOG_SHOWHIDDEN 0x8\n#define PH_FILEDIALOG_NODEREFERENCELINKS 0x10\n#define PH_FILEDIALOG_OVERWRITEPROMPT 0x20 // default save\n#define PH_FILEDIALOG_DEFAULTEXPANDED 0x40\n#define PH_FILEDIALOG_STRICTFILETYPES 0x80\n#define PH_FILEDIALOG_PICKFOLDERS 0x100\n#define PH_FILEDIALOG_NOPATHVALIDATE 0x200\n\nPHLIBAPI\nULONG\nNTAPI\nPhGetFileDialogOptions(\n    _In_ PVOID FileDialog\n    );\n\nPHLIBAPI\nVOID\nNTAPI\nPhSetFileDialogOptions(\n    _In_ PVOID FileDialog,\n    _In_ ULONG Options\n    );\n\nPHLIBAPI\nULONG\nNTAPI\nPhGetFileDialogFilterIndex(\n    _In_ PVOID FileDialog\n    );\n\ntypedef struct _PH_FILETYPE_FILTER\n{\n    PWSTR Name;\n    PWSTR Filter;\n} PH_FILETYPE_FILTER, *PPH_FILETYPE_FILTER;\n\nPHLIBAPI\nVOID\nNTAPI\nPhSetFileDialogFilter(\n    _In_ PVOID FileDialog,\n    _In_ PPH_FILETYPE_FILTER Filters,\n    _In_ ULONG NumberOfFilters\n    );\n\nPHLIBAPI\nPPH_STRING\nNTAPI\nPhGetFileDialogFileName(\n    _In_ PVOID FileDialog\n    );\n\nPHLIBAPI\nVOID\nNTAPI\nPhSetFileDialogFileName(\n    _In_ PVOID FileDialog,\n    _In_ PWSTR FileName\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhIsExecutablePacked(\n    _In_ PWSTR FileName,\n    _Out_ PBOOLEAN IsPacked,\n    _Out_opt_ PULONG NumberOfModules,\n    _Out_opt_ PULONG NumberOfFunctions\n    );\n\nPHLIBAPI\nULONG\nNTAPI\nPhCrc32(\n    _In_ ULONG Crc,\n    _In_reads_(Length) PCHAR Buffer,\n    _In_ SIZE_T Length\n    );\n\ntypedef enum _PH_HASH_ALGORITHM\n{\n    Md5HashAlgorithm,\n    Sha1HashAlgorithm,\n    Crc32HashAlgorithm,\n    Sha256HashAlgorithm\n} PH_HASH_ALGORITHM;\n\ntypedef struct _PH_HASH_CONTEXT\n{\n    PH_HASH_ALGORITHM Algorithm;\n    ULONG Context[64];\n} PH_HASH_CONTEXT, *PPH_HASH_CONTEXT;\n\nPHLIBAPI\nVOID\nNTAPI\nPhInitializeHash(\n    _Out_ PPH_HASH_CONTEXT Context,\n    _In_ PH_HASH_ALGORITHM Algorithm\n    );\n\nPHLIBAPI\nVOID\nNTAPI\nPhUpdateHash(\n    _Inout_ PPH_HASH_CONTEXT Context,\n    _In_reads_bytes_(Length) PVOID Buffer,\n    _In_ ULONG Length\n    );\n\nPHLIBAPI\nBOOLEAN\nNTAPI\nPhFinalHash(\n    _Inout_ PPH_HASH_CONTEXT Context,\n    _Out_writes_bytes_(HashLength) PVOID Hash,\n    _In_ ULONG HashLength,\n    _Out_opt_ PULONG ReturnLength\n    );\n\ntypedef enum _PH_COMMAND_LINE_OPTION_TYPE\n{\n    NoArgumentType,\n    MandatoryArgumentType,\n    OptionalArgumentType\n} PH_COMMAND_LINE_OPTION_TYPE, *PPH_COMMAND_LINE_OPTION_TYPE;\n\ntypedef struct _PH_COMMAND_LINE_OPTION\n{\n    ULONG Id;\n    PWSTR Name;\n    PH_COMMAND_LINE_OPTION_TYPE Type;\n} PH_COMMAND_LINE_OPTION, *PPH_COMMAND_LINE_OPTION;\n\ntypedef BOOLEAN (NTAPI *PPH_COMMAND_LINE_CALLBACK)(\n    _In_opt_ PPH_COMMAND_LINE_OPTION Option,\n    _In_opt_ PPH_STRING Value,\n    _In_opt_ PVOID Context\n    );\n\n#define PH_COMMAND_LINE_IGNORE_UNKNOWN_OPTIONS 0x1\n#define PH_COMMAND_LINE_IGNORE_FIRST_PART 0x2\n\nPHLIBAPI\nPPH_STRING\nNTAPI\nPhParseCommandLinePart(\n    _In_ PPH_STRINGREF CommandLine,\n    _Inout_ PULONG_PTR Index\n    );\n\nPHLIBAPI\nBOOLEAN\nNTAPI\nPhParseCommandLine(\n    _In_ PPH_STRINGREF CommandLine,\n    _In_opt_ PPH_COMMAND_LINE_OPTION Options,\n    _In_ ULONG NumberOfOptions,\n    _In_ ULONG Flags,\n    _In_ PPH_COMMAND_LINE_CALLBACK Callback,\n    _In_opt_ PVOID Context\n    );\n\nPHLIBAPI\nPPH_STRING\nNTAPI\nPhEscapeCommandLinePart(\n    _In_ PPH_STRINGREF String\n    );\n\nPHLIBAPI\nBOOLEAN\nNTAPI\nPhParseCommandLineFuzzy(\n    _In_ PPH_STRINGREF CommandLine,\n    _Out_ PPH_STRINGREF FileName,\n    _Out_ PPH_STRINGREF Arguments,\n    _Out_opt_ PPH_STRING *FullFileName\n    );\n\nPHLIBAPI\nBOOLEAN\nNTAPI\nPhSearchFilePath(\n    _In_ PWSTR FileName,\n    _In_opt_ PWSTR Extension,\n    _Out_writes_(MAX_PATH) PWSTR Buffer\n    );\n\nPHLIBAPI\nPPH_STRING\nNTAPI\nPhGetCacheDirectory(\n    VOID\n    );\n\nPHLIBAPI\nVOID\nNTAPI\nPhClearCacheDirectory(\n    VOID\n    );\n\nPHLIBAPI\nPPH_STRING\nNTAPI\nPhCreateCacheFile(\n    _In_ PPH_STRING FileName\n    );\n\nPHLIBAPI\nVOID\nNTAPI\nPhDeleteCacheFile(\n    _In_ PPH_STRING FileName\n    );\n\nPHLIBAPI\nHANDLE\nNTAPI\nPhGetNamespaceHandle(\n    VOID\n    );\n\nPHLIBAPI\nBOOLEAN\nNTAPI\nPhLoadResource(\n    _In_ PVOID DllBase,\n    _In_ PCWSTR Name,\n    _In_ PCWSTR Type,\n    _Out_opt_ ULONG *ResourceLength,\n    _Out_ PVOID *ResourceBuffer\n    );\n\nPHLIBAPI\nPPH_STRING\nNTAPI\nPhLoadIndirectString(\n    _In_ PWSTR SourceString\n    );\n\nPHLIBAPI\nBOOLEAN\nNTAPI\nPhExtractIcon(\n    _In_ PWSTR FileName,\n    _In_ HICON *IconLarge,\n    _In_ HICON *IconSmall\n    );\n\n#ifdef __cplusplus\n}\n#endif\n\n#endif\n"
  },
  {
    "path": "third_party/phlib/include/provider.h",
    "content": "#ifndef _PH_PROVIDER_H\n#define _PH_PROVIDER_H\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\n#if defined(DEBUG)\nextern PPH_LIST PhDbgProviderList;\nextern PH_QUEUED_LOCK PhDbgProviderListLock;\n#endif\n\ntypedef enum _PH_PROVIDER_THREAD_STATE\n{\n    ProviderThreadRunning,\n    ProviderThreadStopped,\n    ProviderThreadStopping\n} PH_PROVIDER_THREAD_STATE;\n\ntypedef VOID (NTAPI *PPH_PROVIDER_FUNCTION)(\n    _In_ PVOID Object\n    );\n\nstruct _PH_PROVIDER_THREAD;\ntypedef struct _PH_PROVIDER_THREAD *PPH_PROVIDER_THREAD;\n\ntypedef struct _PH_PROVIDER_REGISTRATION\n{\n    LIST_ENTRY ListEntry;\n    PPH_PROVIDER_THREAD ProviderThread;\n    PPH_PROVIDER_FUNCTION Function;\n    PVOID Object;\n    ULONG RunId;\n    BOOLEAN Enabled;\n    BOOLEAN Unregistering;\n    BOOLEAN Boosting;\n} PH_PROVIDER_REGISTRATION, *PPH_PROVIDER_REGISTRATION;\n\ntypedef struct _PH_PROVIDER_THREAD\n{\n    HANDLE ThreadHandle;\n    HANDLE TimerHandle;\n    ULONG Interval;\n    PH_PROVIDER_THREAD_STATE State;\n\n    PH_QUEUED_LOCK Lock;\n    LIST_ENTRY ListHead;\n    ULONG BoostCount;\n} PH_PROVIDER_THREAD, *PPH_PROVIDER_THREAD;\n\nPHLIBAPI\nVOID\nNTAPI\nPhInitializeProviderThread(\n    _Out_ PPH_PROVIDER_THREAD ProviderThread,\n    _In_ ULONG Interval\n    );\n\nPHLIBAPI\nVOID\nNTAPI\nPhDeleteProviderThread(\n    _Inout_ PPH_PROVIDER_THREAD ProviderThread\n    );\n\nPHLIBAPI\nVOID\nNTAPI\nPhStartProviderThread(\n    _Inout_ PPH_PROVIDER_THREAD ProviderThread\n    );\n\nPHLIBAPI\nVOID\nNTAPI\nPhStopProviderThread(\n    _Inout_ PPH_PROVIDER_THREAD ProviderThread\n    );\n\nPHLIBAPI\nVOID\nNTAPI\nPhSetIntervalProviderThread(\n    _Inout_ PPH_PROVIDER_THREAD ProviderThread,\n    _In_ ULONG Interval\n    );\n\nPHLIBAPI\nVOID\nNTAPI\nPhRegisterProvider(\n    _Inout_ PPH_PROVIDER_THREAD ProviderThread,\n    _In_ PPH_PROVIDER_FUNCTION Function,\n    _In_opt_ PVOID Object,\n    _Out_ PPH_PROVIDER_REGISTRATION Registration\n    );\n\nPHLIBAPI\nVOID\nNTAPI\nPhUnregisterProvider(\n    _Inout_ PPH_PROVIDER_REGISTRATION Registration\n    );\n\nPHLIBAPI\nBOOLEAN\nNTAPI\nPhBoostProvider(\n    _Inout_ PPH_PROVIDER_REGISTRATION Registration,\n    _Out_opt_ PULONG FutureRunId\n    );\n\nPHLIBAPI\nULONG\nNTAPI\nPhGetRunIdProvider(\n    _In_ PPH_PROVIDER_REGISTRATION Registration\n    );\n\nPHLIBAPI\nBOOLEAN\nNTAPI\nPhGetEnabledProvider(\n    _In_ PPH_PROVIDER_REGISTRATION Registration\n    );\n\nPHLIBAPI\nVOID\nNTAPI\nPhSetEnabledProvider(\n    _Inout_ PPH_PROVIDER_REGISTRATION Registration,\n    _In_ BOOLEAN Enabled\n    );\n\n#ifdef __cplusplus\n}\n#endif\n\n#endif\n"
  },
  {
    "path": "third_party/phlib/include/queuedlock.h",
    "content": "#ifndef _PH_QUEUEDLOCK_H\n#define _PH_QUEUEDLOCK_H\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\n#define PH_QUEUED_LOCK_OWNED ((ULONG_PTR)0x1)\n#define PH_QUEUED_LOCK_OWNED_SHIFT 0\n#define PH_QUEUED_LOCK_WAITERS ((ULONG_PTR)0x2)\n\n// Valid only if Waiters = 0\n#define PH_QUEUED_LOCK_SHARED_INC ((ULONG_PTR)0x4)\n#define PH_QUEUED_LOCK_SHARED_SHIFT 2\n\n// Valid only if Waiters = 1\n#define PH_QUEUED_LOCK_TRAVERSING ((ULONG_PTR)0x4)\n#define PH_QUEUED_LOCK_MULTIPLE_SHARED ((ULONG_PTR)0x8)\n\n#define PH_QUEUED_LOCK_FLAGS ((ULONG_PTR)0xf)\n\n#define PhGetQueuedLockSharedOwners(Value) \\\n    ((ULONG_PTR)(Value) >> PH_QUEUED_LOCK_SHARED_SHIFT)\n#define PhGetQueuedLockWaitBlock(Value) \\\n    ((PPH_QUEUED_WAIT_BLOCK)((ULONG_PTR)(Value) & ~PH_QUEUED_LOCK_FLAGS))\n\ntypedef struct _PH_QUEUED_LOCK\n{\n    ULONG_PTR Value;\n} PH_QUEUED_LOCK, *PPH_QUEUED_LOCK;\n\n#define PH_QUEUED_LOCK_INIT { 0 }\n\n#define PH_QUEUED_WAITER_EXCLUSIVE 0x1\n#define PH_QUEUED_WAITER_SPINNING 0x2\n#define PH_QUEUED_WAITER_SPINNING_SHIFT 1\n\ntypedef struct DECLSPEC_ALIGN(16) _PH_QUEUED_WAIT_BLOCK\n{\n    /** A pointer to the next wait block, i.e. the wait block pushed onto the list before this one. */\n    struct _PH_QUEUED_WAIT_BLOCK *Next;\n    /**\n     * A pointer to the previous wait block, i.e. the wait block pushed onto the list after this\n     * one.\n     */\n    struct _PH_QUEUED_WAIT_BLOCK *Previous;\n    /** A pointer to the last wait block, i.e. the first waiter pushed onto the list. */\n    struct _PH_QUEUED_WAIT_BLOCK *Last;\n\n    ULONG SharedOwners;\n    ULONG Flags;\n} PH_QUEUED_WAIT_BLOCK, *PPH_QUEUED_WAIT_BLOCK;\n\nBOOLEAN PhQueuedLockInitialization(\n    VOID\n    );\n\n// Queued lock\n\nFORCEINLINE\nVOID\nPhInitializeQueuedLock(\n    _Out_ PPH_QUEUED_LOCK QueuedLock\n    )\n{\n    QueuedLock->Value = 0;\n}\n\nPHLIBAPI\nVOID\nFASTCALL\nPhfAcquireQueuedLockExclusive(\n    _Inout_ PPH_QUEUED_LOCK QueuedLock\n    );\n\n_Acquires_exclusive_lock_(*QueuedLock)\nFORCEINLINE\nVOID\nPhAcquireQueuedLockExclusive(\n    _Inout_ PPH_QUEUED_LOCK QueuedLock\n    )\n{\n    if (_InterlockedBitTestAndSetPointer((PLONG_PTR)&QueuedLock->Value, PH_QUEUED_LOCK_OWNED_SHIFT))\n    {\n        // Owned bit was already set. Slow path.\n        PhfAcquireQueuedLockExclusive(QueuedLock);\n    }\n}\n\nPHLIBAPI\nVOID\nFASTCALL\nPhfAcquireQueuedLockShared(\n    _Inout_ PPH_QUEUED_LOCK QueuedLock\n    );\n\n_Acquires_shared_lock_(*QueuedLock)\nFORCEINLINE\nVOID\nPhAcquireQueuedLockShared(\n    _Inout_ PPH_QUEUED_LOCK QueuedLock\n    )\n{\n    if ((ULONG_PTR)_InterlockedCompareExchangePointer(\n        (PVOID *)&QueuedLock->Value,\n        (PVOID)(PH_QUEUED_LOCK_OWNED | PH_QUEUED_LOCK_SHARED_INC),\n        (PVOID)0\n        ) != 0)\n    {\n        PhfAcquireQueuedLockShared(QueuedLock);\n    }\n}\n\n_When_(return != 0, _Acquires_exclusive_lock_(*QueuedLock))\nFORCEINLINE\nBOOLEAN\nPhTryAcquireQueuedLockExclusive(\n    _Inout_ PPH_QUEUED_LOCK QueuedLock\n    )\n{\n    if (!_InterlockedBitTestAndSetPointer((PLONG_PTR)&QueuedLock->Value, PH_QUEUED_LOCK_OWNED_SHIFT))\n    {\n        return TRUE;\n    }\n    else\n    {\n        return FALSE;\n    }\n}\n\nPHLIBAPI\nVOID\nFASTCALL\nPhfReleaseQueuedLockExclusive(\n    _Inout_ PPH_QUEUED_LOCK QueuedLock\n    );\n\nPHLIBAPI\nVOID\nFASTCALL\nPhfWakeForReleaseQueuedLock(\n    _Inout_ PPH_QUEUED_LOCK QueuedLock,\n    _In_ ULONG_PTR Value\n    );\n\n_Releases_exclusive_lock_(*QueuedLock)\nFORCEINLINE\nVOID\nPhReleaseQueuedLockExclusive(\n    _Inout_ PPH_QUEUED_LOCK QueuedLock\n    )\n{\n    ULONG_PTR value;\n\n    value = (ULONG_PTR)_InterlockedExchangeAddPointer((PLONG_PTR)&QueuedLock->Value, -(LONG_PTR)PH_QUEUED_LOCK_OWNED);\n\n    if ((value & (PH_QUEUED_LOCK_WAITERS | PH_QUEUED_LOCK_TRAVERSING)) == PH_QUEUED_LOCK_WAITERS)\n    {\n        PhfWakeForReleaseQueuedLock(QueuedLock, value - PH_QUEUED_LOCK_OWNED);\n    }\n}\n\nPHLIBAPI\nVOID\nFASTCALL\nPhfReleaseQueuedLockShared(\n    _Inout_ PPH_QUEUED_LOCK QueuedLock\n    );\n\n_Releases_shared_lock_(*QueuedLock)\nFORCEINLINE\nVOID\nPhReleaseQueuedLockShared(\n    _Inout_ PPH_QUEUED_LOCK QueuedLock\n    )\n{\n    ULONG_PTR value;\n\n    value = PH_QUEUED_LOCK_OWNED | PH_QUEUED_LOCK_SHARED_INC;\n\n    if ((ULONG_PTR)_InterlockedCompareExchangePointer(\n        (PVOID *)&QueuedLock->Value,\n        (PVOID)0,\n        (PVOID)value\n        ) != value)\n    {\n        PhfReleaseQueuedLockShared(QueuedLock);\n    }\n}\n\nFORCEINLINE\nVOID\nPhAcquireReleaseQueuedLockExclusive(\n    _Inout_ PPH_QUEUED_LOCK QueuedLock\n    )\n{\n    BOOLEAN owned;\n\n    MemoryBarrier();\n    owned = !!(QueuedLock->Value & PH_QUEUED_LOCK_OWNED);\n    MemoryBarrier();\n\n    if (owned)\n    {\n        PhAcquireQueuedLockExclusive(QueuedLock);\n        PhReleaseQueuedLockExclusive(QueuedLock);\n    }\n}\n\nFORCEINLINE\nBOOLEAN\nPhTryAcquireReleaseQueuedLockExclusive(\n    _Inout_ PPH_QUEUED_LOCK QueuedLock\n    )\n{\n    BOOLEAN owned;\n\n    // Need two memory barriers because we don't want the compiler re-ordering the following check\n    // in either direction.\n    MemoryBarrier();\n    owned = !(QueuedLock->Value & PH_QUEUED_LOCK_OWNED);\n    MemoryBarrier();\n\n    return owned;\n}\n\n// Condition variable\n\ntypedef struct _PH_QUEUED_LOCK PH_CONDITION, *PPH_CONDITION;\n\n#define PH_CONDITION_INIT PH_QUEUED_LOCK_INIT\n\nFORCEINLINE\nVOID\nPhInitializeCondition(\n    _Out_ PPH_CONDITION Condition\n    )\n{\n    PhInitializeQueuedLock(Condition);\n}\n\n#define PhPulseCondition PhfPulseCondition\nPHLIBAPI\nVOID\nFASTCALL\nPhfPulseCondition(\n    _Inout_ PPH_CONDITION Condition\n    );\n\n#define PhPulseAllCondition PhfPulseAllCondition\nPHLIBAPI\nVOID\nFASTCALL\nPhfPulseAllCondition(\n    _Inout_ PPH_CONDITION Condition\n    );\n\n#define PhWaitForCondition PhfWaitForCondition\nPHLIBAPI\nVOID\nFASTCALL\nPhfWaitForCondition(\n    _Inout_ PPH_CONDITION Condition,\n    _Inout_ PPH_QUEUED_LOCK Lock,\n    _In_opt_ PLARGE_INTEGER Timeout\n    );\n\n#define PH_CONDITION_WAIT_QUEUED_LOCK 0x1\n#define PH_CONDITION_WAIT_CRITICAL_SECTION 0x2\n#define PH_CONDITION_WAIT_FAST_LOCK 0x4\n#define PH_CONDITION_WAIT_LOCK_TYPE_MASK 0xfff\n\n#define PH_CONDITION_WAIT_SHARED 0x1000\n#define PH_CONDITION_WAIT_SPIN 0x2000\n\n#define PhWaitForConditionEx PhfWaitForConditionEx\nPHLIBAPI\nVOID\nFASTCALL\nPhfWaitForConditionEx(\n    _Inout_ PPH_CONDITION Condition,\n    _Inout_ PVOID Lock,\n    _In_ ULONG Flags,\n    _In_opt_ PLARGE_INTEGER Timeout\n    );\n\n// Wake event\n\ntypedef struct _PH_QUEUED_LOCK PH_WAKE_EVENT, *PPH_WAKE_EVENT;\n\n#define PH_WAKE_EVENT_INIT PH_QUEUED_LOCK_INIT\n\nFORCEINLINE\nVOID\nPhInitializeWakeEvent(\n    _Out_ PPH_WAKE_EVENT WakeEvent\n    )\n{\n    PhInitializeQueuedLock(WakeEvent);\n}\n\n#define PhQueueWakeEvent PhfQueueWakeEvent\nPHLIBAPI\nVOID\nFASTCALL\nPhfQueueWakeEvent(\n    _Inout_ PPH_WAKE_EVENT WakeEvent,\n    _Out_ PPH_QUEUED_WAIT_BLOCK WaitBlock\n    );\n\nPHLIBAPI\nVOID\nFASTCALL\nPhfSetWakeEvent(\n    _Inout_ PPH_WAKE_EVENT WakeEvent,\n    _Inout_opt_ PPH_QUEUED_WAIT_BLOCK WaitBlock\n    );\n\nFORCEINLINE\nVOID\nPhSetWakeEvent(\n    _Inout_ PPH_WAKE_EVENT WakeEvent,\n    _Inout_opt_ PPH_QUEUED_WAIT_BLOCK WaitBlock\n    )\n{\n    // The wake event is similar to a synchronization event in that it does not have thread-safe\n    // pulsing; we can simply skip the function call if there's nothing to wake. However, if we're\n    // cancelling a wait (WaitBlock != NULL) we need to make the call.\n\n    if (WakeEvent->Value || WaitBlock)\n        PhfSetWakeEvent(WakeEvent, WaitBlock);\n}\n\n#define PhWaitForWakeEvent PhfWaitForWakeEvent\nPHLIBAPI\nNTSTATUS\nFASTCALL\nPhfWaitForWakeEvent(\n    _Inout_ PPH_WAKE_EVENT WakeEvent,\n    _Inout_ PPH_QUEUED_WAIT_BLOCK WaitBlock,\n    _In_ BOOLEAN Spin,\n    _In_opt_ PLARGE_INTEGER Timeout\n    );\n\n#ifdef __cplusplus\n}\n#endif\n\n#endif\n"
  },
  {
    "path": "third_party/phlib/include/ref.h",
    "content": "/*\n * Process Hacker -\n *   internal object manager\n *\n * Copyright (C) 2009-2016 wj32\n *\n * This file is part of Process Hacker.\n *\n * Process Hacker is free software; you can redistribute it and/or modify\n * it under the terms of the GNU General Public License as published by\n * the Free Software Foundation, either version 3 of the License, or\n * (at your option) any later version.\n *\n * Process Hacker is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n * GNU General Public License for more details.\n *\n * You should have received a copy of the GNU General Public License\n * along with Process Hacker.  If not, see <http://www.gnu.org/licenses/>.\n */\n\n#ifndef _PH_REF_H\n#define _PH_REF_H\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\n// Configuration\n\n#define PH_OBJECT_SMALL_OBJECT_SIZE 48\n#define PH_OBJECT_SMALL_OBJECT_COUNT 512\n\n// Object type flags\n#define PH_OBJECT_TYPE_USE_FREE_LIST 0x00000001\n#define PH_OBJECT_TYPE_VALID_FLAGS 0x00000001\n\n// Object type callbacks\n\n/**\n * The delete procedure for an object type, called when an object of the type is being freed.\n *\n * \\param Object A pointer to the object being freed.\n * \\param Flags Reserved.\n */\ntypedef VOID (NTAPI *PPH_TYPE_DELETE_PROCEDURE)(\n    _In_ PVOID Object,\n    _In_ ULONG Flags\n    );\n\nstruct _PH_OBJECT_TYPE;\ntypedef struct _PH_OBJECT_TYPE *PPH_OBJECT_TYPE;\n\nstruct _PH_QUEUED_LOCK;\ntypedef struct _PH_QUEUED_LOCK PH_QUEUED_LOCK, *PPH_QUEUED_LOCK;\n\n#ifdef DEBUG\ntypedef VOID (NTAPI *PPH_CREATE_OBJECT_HOOK)(\n    _In_ PVOID Object,\n    _In_ SIZE_T Size,\n    _In_ ULONG Flags,\n    _In_ PPH_OBJECT_TYPE ObjectType\n    );\n#endif\n\ntypedef struct _PH_OBJECT_TYPE_PARAMETERS\n{\n    SIZE_T FreeListSize;\n    ULONG FreeListCount;\n} PH_OBJECT_TYPE_PARAMETERS, *PPH_OBJECT_TYPE_PARAMETERS;\n\ntypedef struct _PH_OBJECT_TYPE_INFORMATION\n{\n    PWSTR Name;\n    ULONG NumberOfObjects;\n    USHORT Flags;\n    UCHAR TypeIndex;\n    UCHAR Reserved;\n} PH_OBJECT_TYPE_INFORMATION, *PPH_OBJECT_TYPE_INFORMATION;\n\nextern PPH_OBJECT_TYPE PhObjectTypeObject;\nextern PPH_OBJECT_TYPE PhAllocType;\n\n#ifdef DEBUG\nextern LIST_ENTRY PhDbgObjectListHead;\nextern PH_QUEUED_LOCK PhDbgObjectListLock;\nextern PPH_CREATE_OBJECT_HOOK PhDbgCreateObjectHook;\n#endif\n\nNTSTATUS PhRefInitialization(\n    VOID\n    );\n\n_May_raise_\nPHLIBAPI\nPVOID\nNTAPI\nPhCreateObject(\n    _In_ SIZE_T ObjectSize,\n    _In_ PPH_OBJECT_TYPE ObjectType\n    );\n\nPHLIBAPI\nPVOID\nNTAPI\nPhReferenceObject(\n    _In_ PVOID Object\n    );\n\n_May_raise_\nPHLIBAPI\nPVOID\nNTAPI\nPhReferenceObjectEx(\n    _In_ PVOID Object,\n    _In_ LONG RefCount\n    );\n\nPHLIBAPI\nPVOID\nNTAPI\nPhReferenceObjectSafe(\n    _In_ PVOID Object\n    );\n\nPHLIBAPI\nVOID\nNTAPI\nPhDereferenceObject(\n    _In_ PVOID Object\n    );\n\nPHLIBAPI\nVOID\nNTAPI\nPhDereferenceObjectDeferDelete(\n    _In_ PVOID Object\n    );\n\n_May_raise_\nPHLIBAPI\nVOID\nNTAPI\nPhDereferenceObjectEx(\n    _In_ PVOID Object,\n    _In_ LONG RefCount,\n    _In_ BOOLEAN DeferDelete\n    );\n\nPHLIBAPI\nPPH_OBJECT_TYPE\nNTAPI\nPhGetObjectType(\n    _In_ PVOID Object\n    );\n\nPHLIBAPI\nPPH_OBJECT_TYPE\nNTAPI\nPhCreateObjectType(\n    _In_ PWSTR Name,\n    _In_ ULONG Flags,\n    _In_opt_ PPH_TYPE_DELETE_PROCEDURE DeleteProcedure\n    );\n\nPHLIBAPI\nPPH_OBJECT_TYPE\nNTAPI\nPhCreateObjectTypeEx(\n    _In_ PWSTR Name,\n    _In_ ULONG Flags,\n    _In_opt_ PPH_TYPE_DELETE_PROCEDURE DeleteProcedure,\n    _In_opt_ PPH_OBJECT_TYPE_PARAMETERS Parameters\n    );\n\nPHLIBAPI\nVOID\nNTAPI\nPhGetObjectTypeInformation(\n    _In_ PPH_OBJECT_TYPE ObjectType,\n    _Out_ PPH_OBJECT_TYPE_INFORMATION Information\n    );\n\nPHLIBAPI\nPVOID\nNTAPI\nPhCreateAlloc(\n    _In_ SIZE_T Size\n    );\n\n// Object reference functions\n\nFORCEINLINE\nVOID\nPhSwapReference(\n    _Inout_ PVOID *ObjectReference,\n    _In_opt_ PVOID NewObject\n    )\n{\n    PVOID oldObject;\n\n    oldObject = *ObjectReference;\n    *ObjectReference = NewObject;\n\n    if (NewObject) PhReferenceObject(NewObject);\n    if (oldObject) PhDereferenceObject(oldObject);\n}\n\nFORCEINLINE\nVOID\nPhMoveReference(\n    _Inout_ PVOID *ObjectReference,\n    _In_opt_ _Assume_refs_(1) PVOID NewObject\n    )\n{\n    PVOID oldObject;\n\n    oldObject = *ObjectReference;\n    *ObjectReference = NewObject;\n\n    if (oldObject) PhDereferenceObject(oldObject);\n}\n\nFORCEINLINE\nVOID\nPhSetReference(\n    _Out_ PVOID *ObjectReference,\n    _In_opt_ PVOID NewObject\n    )\n{\n    *ObjectReference = NewObject;\n\n    if (NewObject) PhReferenceObject(NewObject);\n}\n\nFORCEINLINE\nVOID\nPhClearReference(\n    _Inout_ PVOID *ObjectReference\n    )\n{\n    PhMoveReference(ObjectReference, NULL);\n}\n\n// Auto-dereference pool\n\n/** The size of the static array in an auto-release pool. */\n#define PH_AUTO_POOL_STATIC_SIZE 64\n/** The maximum size of the dynamic array for it to be kept after the auto-release pool is drained. */\n#define PH_AUTO_POOL_DYNAMIC_BIG_SIZE 256\n\n/**\n * An auto-dereference pool can be used for semi-automatic reference counting. Batches of objects\n * are dereferenced at a certain time.\n *\n * This object is not thread-safe and cannot be used across thread boundaries. Always store them as\n * local variables.\n */\ntypedef struct _PH_AUTO_POOL\n{\n    ULONG StaticCount;\n    PVOID StaticObjects[PH_AUTO_POOL_STATIC_SIZE];\n\n    ULONG DynamicCount;\n    ULONG DynamicAllocated;\n    PVOID *DynamicObjects;\n\n    struct _PH_AUTO_POOL *NextPool;\n} PH_AUTO_POOL, *PPH_AUTO_POOL;\n\nPHLIBAPI\nVOID\nNTAPI\nPhInitializeAutoPool(\n    _Out_ PPH_AUTO_POOL AutoPool\n    );\n\n_May_raise_\nPHLIBAPI\nVOID\nNTAPI\nPhDeleteAutoPool(\n    _Inout_ PPH_AUTO_POOL AutoPool\n    );\n\nPHLIBAPI\nVOID\nNTAPI\nPhDrainAutoPool(\n    _In_ PPH_AUTO_POOL AutoPool\n    );\n\n_May_raise_\nPHLIBAPI\nPVOID\nNTAPI\nPhAutoDereferenceObject(\n    _In_opt_ PVOID Object\n    );\n\n#define PH_AUTO PhAutoDereferenceObject\n#define PH_AUTO_T(Type, Object) ((Type *)PH_AUTO(Object))\n\n#ifdef __cplusplus\n}\n#endif\n\n#endif\n"
  },
  {
    "path": "third_party/phlib/include/refp.h",
    "content": "/*\n * Process Hacker -\n *   internal object manager\n *\n * Copyright (C) 2009-2016 wj32\n *\n * This file is part of Process Hacker.\n *\n * Process Hacker is free software; you can redistribute it and/or modify\n * it under the terms of the GNU General Public License as published by\n * the Free Software Foundation, either version 3 of the License, or\n * (at your option) any later version.\n *\n * Process Hacker is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n * GNU General Public License for more details.\n *\n * You should have received a copy of the GNU General Public License\n * along with Process Hacker.  If not, see <http://www.gnu.org/licenses/>.\n */\n\n#ifndef _PH_REFP_H\n#define _PH_REFP_H\n\n#define PH_OBJECT_TYPE_TABLE_SIZE 256\n\n/** The object was allocated from the small free list. */\n#define PH_OBJECT_FROM_SMALL_FREE_LIST 0x1\n/** The object was allocated from the type free list. */\n#define PH_OBJECT_FROM_TYPE_FREE_LIST 0x2\n\n/**\n * The object header contains object manager information including the reference count of an object\n * and its type.\n */\ntypedef struct _PH_OBJECT_HEADER\n{\n    union\n    {\n        struct\n        {\n            USHORT TypeIndex;\n            UCHAR Flags;\n            UCHAR Reserved1;\n#ifdef _WIN64\n            ULONG Reserved2;\n#endif\n            union\n            {\n                LONG RefCount;\n                struct\n                {\n                    LONG SavedTypeIndex : 16;\n                    LONG SavedFlags : 8;\n                    LONG Reserved : 7;\n                    LONG DeferDelete : 1; // MUST be the high bit, so that RefCount < 0 when deferring delete\n                };\n            };\n#ifdef _WIN64\n            ULONG Reserved3;\n#endif\n        };\n        SLIST_ENTRY DeferDeleteListEntry;\n    };\n\n#ifdef DEBUG\n    PVOID StackBackTrace[16];\n    LIST_ENTRY ObjectListEntry;\n#endif\n\n    /**\n     * The body of the object. For use by the \\ref PhObjectToObjectHeader and\n     * \\ref PhObjectHeaderToObject macros.\n     */\n    QUAD_PTR Body;\n} PH_OBJECT_HEADER, *PPH_OBJECT_HEADER;\n\n#ifndef DEBUG\n#ifdef _WIN64\nC_ASSERT(FIELD_OFFSET(PH_OBJECT_HEADER, TypeIndex) == 0x0);\nC_ASSERT(FIELD_OFFSET(PH_OBJECT_HEADER, Flags) == 0x2);\nC_ASSERT(FIELD_OFFSET(PH_OBJECT_HEADER, Reserved1) == 0x3);\nC_ASSERT(FIELD_OFFSET(PH_OBJECT_HEADER, Reserved2) == 0x4);\nC_ASSERT(FIELD_OFFSET(PH_OBJECT_HEADER, RefCount) == 0x8);\nC_ASSERT(FIELD_OFFSET(PH_OBJECT_HEADER, Reserved3) == 0xc);\nC_ASSERT(FIELD_OFFSET(PH_OBJECT_HEADER, DeferDeleteListEntry) == 0x0);\nC_ASSERT(FIELD_OFFSET(PH_OBJECT_HEADER, Body) == 0x10);\n#else\nC_ASSERT(FIELD_OFFSET(PH_OBJECT_HEADER, TypeIndex) == 0x0);\nC_ASSERT(FIELD_OFFSET(PH_OBJECT_HEADER, Flags) == 0x2);\nC_ASSERT(FIELD_OFFSET(PH_OBJECT_HEADER, Reserved1) == 0x3);\nC_ASSERT(FIELD_OFFSET(PH_OBJECT_HEADER, RefCount) == 0x4);\nC_ASSERT(FIELD_OFFSET(PH_OBJECT_HEADER, DeferDeleteListEntry) == 0x0);\nC_ASSERT(FIELD_OFFSET(PH_OBJECT_HEADER, Body) == 0x8);\n#endif\n#endif\n\n/**\n * Gets a pointer to the object header for an object.\n *\n * \\param Object A pointer to an object.\n *\n * \\return A pointer to the object header of the object.\n */\n#define PhObjectToObjectHeader(Object) ((PPH_OBJECT_HEADER)CONTAINING_RECORD((PCHAR)(Object), PH_OBJECT_HEADER, Body))\n\n/**\n * Gets a pointer to an object from an object header.\n *\n * \\param ObjectHeader A pointer to an object header.\n *\n * \\return A pointer to an object.\n */\n#define PhObjectHeaderToObject(ObjectHeader) ((PVOID)&((PPH_OBJECT_HEADER)(ObjectHeader))->Body)\n\n/**\n * Calculates the total size to allocate for an object.\n *\n * \\param Size The size of the object to allocate.\n *\n * \\return The new size, including space for the object header.\n */\n#define PhAddObjectHeaderSize(Size) ((Size) + FIELD_OFFSET(PH_OBJECT_HEADER, Body))\n\n/** An object type specifies a kind of object and its delete procedure. */\ntypedef struct _PH_OBJECT_TYPE\n{\n    /** The flags that were used to create the object type. */\n    USHORT Flags;\n    UCHAR TypeIndex;\n    UCHAR Reserved;\n    /** The total number of objects of this type that are alive. */\n    ULONG NumberOfObjects;\n    /** An optional procedure called when objects of this type are freed. */\n    PPH_TYPE_DELETE_PROCEDURE DeleteProcedure;\n    /** The name of the type. */\n    PWSTR Name;\n    /** A free list to use when allocating for this type. */\n    PH_FREE_LIST FreeList;\n} PH_OBJECT_TYPE, *PPH_OBJECT_TYPE;\n\n/**\n * Increments a reference count, but will never increment from a nonpositive value to 1.\n *\n * \\param RefCount A pointer to a reference count.\n */\nFORCEINLINE\nBOOLEAN\nPhpInterlockedIncrementSafe(\n    _Inout_ PLONG RefCount\n    )\n{\n    /* Here we will attempt to increment the reference count, making sure that it is positive. */\n    return _InterlockedIncrementPositive(RefCount);\n}\n\nPPH_OBJECT_HEADER PhpAllocateObject(\n    _In_ PPH_OBJECT_TYPE ObjectType,\n    _In_ SIZE_T ObjectSize\n    );\n\nVOID PhpFreeObject(\n    _In_ PPH_OBJECT_HEADER ObjectHeader\n    );\n\nVOID PhpDeferDeleteObject(\n    _In_ PPH_OBJECT_HEADER ObjectHeader\n    );\n\nNTSTATUS PhpDeferDeleteObjectRoutine(\n    _In_ PVOID Parameter\n    );\n\n#endif\n"
  },
  {
    "path": "third_party/phlib/include/secedit.h",
    "content": "#ifndef _PH_SECEDIT_H\n#define _PH_SECEDIT_H\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\ntypedef struct _PSP *HPROPSHEETPAGE;\n\n// secedit\n\ntypedef struct _PH_ACCESS_ENTRY\n{\n    PWSTR Name;\n    ACCESS_MASK Access;\n    BOOLEAN General;\n    BOOLEAN Specific;\n    PWSTR ShortName;\n} PH_ACCESS_ENTRY, *PPH_ACCESS_ENTRY;\n\nPHLIBAPI\nHPROPSHEETPAGE\nNTAPI\nPhCreateSecurityPage(\n    _In_ PWSTR ObjectName,\n    _In_ PPH_GET_OBJECT_SECURITY GetObjectSecurity,\n    _In_ PPH_SET_OBJECT_SECURITY SetObjectSecurity,\n    _In_opt_ PVOID Context,\n    _In_ PPH_ACCESS_ENTRY AccessEntries,\n    _In_ ULONG NumberOfAccessEntries\n    );\n\nPHLIBAPI\nVOID\nNTAPI\nPhEditSecurity(\n    _In_ HWND hWnd,\n    _In_ PWSTR ObjectName,\n    _In_ PPH_GET_OBJECT_SECURITY GetObjectSecurity,\n    _In_ PPH_SET_OBJECT_SECURITY SetObjectSecurity,\n    _In_opt_ PVOID Context,\n    _In_ PPH_ACCESS_ENTRY AccessEntries,\n    _In_ ULONG NumberOfAccessEntries\n    );\n\ntypedef struct _PH_STD_OBJECT_SECURITY\n{\n    PPH_OPEN_OBJECT OpenObject;\n    PWSTR ObjectType;\n    PVOID Context;\n} PH_STD_OBJECT_SECURITY, *PPH_STD_OBJECT_SECURITY;\n\nFORCEINLINE ACCESS_MASK PhGetAccessForGetSecurity(\n    _In_ SECURITY_INFORMATION SecurityInformation\n    )\n{\n    ACCESS_MASK access = 0;\n\n    if (\n        (SecurityInformation & OWNER_SECURITY_INFORMATION) ||\n        (SecurityInformation & GROUP_SECURITY_INFORMATION) ||\n        (SecurityInformation & DACL_SECURITY_INFORMATION) ||\n        (SecurityInformation & LABEL_SECURITY_INFORMATION) ||\n        (SecurityInformation & ATTRIBUTE_SECURITY_INFORMATION) ||\n        (SecurityInformation & SCOPE_SECURITY_INFORMATION)\n        )\n    {\n        access |= READ_CONTROL;\n    }\n\n    if (SecurityInformation & SACL_SECURITY_INFORMATION)\n    {\n        access |= ACCESS_SYSTEM_SECURITY;\n    }\n\n    if (SecurityInformation & BACKUP_SECURITY_INFORMATION)\n    {\n        access |= READ_CONTROL | ACCESS_SYSTEM_SECURITY;\n    }\n\n    return access;\n}\n\nFORCEINLINE ACCESS_MASK PhGetAccessForSetSecurity(\n    _In_ SECURITY_INFORMATION SecurityInformation\n    )\n{\n    ACCESS_MASK access = 0;\n\n    if (\n        (SecurityInformation & OWNER_SECURITY_INFORMATION) ||\n        (SecurityInformation & GROUP_SECURITY_INFORMATION) ||\n        (SecurityInformation & LABEL_SECURITY_INFORMATION)\n        )\n    {\n        access |= WRITE_OWNER;\n    }\n\n    if (\n        (SecurityInformation & DACL_SECURITY_INFORMATION) ||\n        (SecurityInformation & ATTRIBUTE_SECURITY_INFORMATION) ||\n        (SecurityInformation & PROTECTED_DACL_SECURITY_INFORMATION) ||\n        (SecurityInformation & UNPROTECTED_DACL_SECURITY_INFORMATION)\n        )\n    {\n        access |= WRITE_DAC;\n    }\n\n    if (\n        (SecurityInformation & SACL_SECURITY_INFORMATION) ||\n        (SecurityInformation & SCOPE_SECURITY_INFORMATION) ||\n        (SecurityInformation & PROTECTED_SACL_SECURITY_INFORMATION) ||\n        (SecurityInformation & UNPROTECTED_SACL_SECURITY_INFORMATION)\n        )\n    {\n        access |= ACCESS_SYSTEM_SECURITY;\n    }\n\n    if (SecurityInformation & BACKUP_SECURITY_INFORMATION)\n    {\n        access |= WRITE_DAC | WRITE_OWNER | ACCESS_SYSTEM_SECURITY;\n    }\n\n    return access;\n}\n\nPHLIBAPI\n_Callback_ NTSTATUS\nNTAPI\nPhStdGetObjectSecurity(\n    _Out_ PSECURITY_DESCRIPTOR *SecurityDescriptor,\n    _In_ SECURITY_INFORMATION SecurityInformation,\n    _In_opt_ PVOID Context\n    );\n\nPHLIBAPI\n_Callback_ NTSTATUS\nNTAPI\nPhStdSetObjectSecurity(\n    _In_ PSECURITY_DESCRIPTOR SecurityDescriptor,\n    _In_ SECURITY_INFORMATION SecurityInformation,\n    _In_opt_ PVOID Context\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhGetSeObjectSecurity(\n    _In_ HANDLE Handle,\n    _In_ ULONG ObjectType,\n    _In_ SECURITY_INFORMATION SecurityInformation,\n    _Out_ PSECURITY_DESCRIPTOR *SecurityDescriptor\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhSetSeObjectSecurity(\n    _In_ HANDLE Handle,\n    _In_ ULONG ObjectType,\n    _In_ SECURITY_INFORMATION SecurityInformation,\n    _In_ PSECURITY_DESCRIPTOR SecurityDescriptor\n    );\n\n// secdata\n\nPHLIBAPI\nBOOLEAN\nNTAPI\nPhGetAccessEntries(\n    _In_ PWSTR Type,\n    _Out_ PPH_ACCESS_ENTRY *AccessEntries,\n    _Out_ PULONG NumberOfAccessEntries\n    );\n\nPHLIBAPI\nPPH_STRING\nNTAPI\nPhGetAccessString(\n    _In_ ACCESS_MASK Access,\n    _In_ PPH_ACCESS_ENTRY AccessEntries,\n    _In_ ULONG NumberOfAccessEntries\n    );\n\n#ifdef __cplusplus\n}\n#endif\n\n#endif"
  },
  {
    "path": "third_party/phlib/include/seceditp.h",
    "content": "#ifndef _PH_SECEDITP_H\n#define _PH_SECEDITP_H\n\n#include <aclui.h>\n#include <aclapi.h>\n\ntypedef struct\n{\n    ISecurityInformationVtbl *VTable;\n\n    ULONG RefCount;\n\n    PPH_STRING ObjectName;\n    PPH_GET_OBJECT_SECURITY GetObjectSecurity;\n    PPH_SET_OBJECT_SECURITY SetObjectSecurity;\n    PVOID Context;\n    PSI_ACCESS AccessEntries;\n    ULONG NumberOfAccessEntries;\n    BOOLEAN IsPage;\n} PhSecurityInformation;\n\ntypedef struct\n{\n    ISecurityInformation2Vtbl *VTable;\n\n    ULONG RefCount;\n} PhSecurityInformation2;\n\ntypedef struct\n{\n    IDataObjectVtbl *VTable;\n\n    ULONG RefCount;\n\n    ULONG SidCount;\n    PSID *Sids;\n\n    PPH_LIST NameCache;\n} PhSecurityIDataObject;\n\nISecurityInformation *PhSecurityInformation_Create(\n    _In_ PWSTR ObjectName,\n    _In_ PPH_GET_OBJECT_SECURITY GetObjectSecurity,\n    _In_ PPH_SET_OBJECT_SECURITY SetObjectSecurity,\n    _In_opt_ PVOID Context,\n    _In_ PPH_ACCESS_ENTRY AccessEntries,\n    _In_ ULONG NumberOfAccessEntries,\n    _In_ BOOLEAN IsPage\n    );\n\nHRESULT STDMETHODCALLTYPE PhSecurityInformation_QueryInterface(\n    _In_ ISecurityInformation *This,\n    _In_ REFIID Riid,\n    _Out_ PVOID *Object\n    );\n\nULONG STDMETHODCALLTYPE PhSecurityInformation_AddRef(\n    _In_ ISecurityInformation *This\n    );\n\nULONG STDMETHODCALLTYPE PhSecurityInformation_Release(\n    _In_ ISecurityInformation *This\n    );\n\nHRESULT STDMETHODCALLTYPE PhSecurityInformation_GetObjectInformation(\n    _In_ ISecurityInformation *This,\n    _Out_ PSI_OBJECT_INFO ObjectInfo\n    );\n\nHRESULT STDMETHODCALLTYPE PhSecurityInformation_GetSecurity(\n    _In_ ISecurityInformation *This,\n    _In_ SECURITY_INFORMATION RequestedInformation,\n    _Out_ PSECURITY_DESCRIPTOR *SecurityDescriptor,\n    _In_ BOOL Default\n    );\n\nHRESULT STDMETHODCALLTYPE PhSecurityInformation_SetSecurity(\n    _In_ ISecurityInformation *This,\n    _In_ SECURITY_INFORMATION SecurityInformation,\n    _In_ PSECURITY_DESCRIPTOR SecurityDescriptor\n    );\n\nHRESULT STDMETHODCALLTYPE PhSecurityInformation_GetAccessRights(\n    _In_ ISecurityInformation *This,\n    _In_ const GUID *ObjectType,\n    _In_ ULONG Flags,\n    _Out_ PSI_ACCESS *Access,\n    _Out_ PULONG Accesses,\n    _Out_ PULONG DefaultAccess\n    );\n\nHRESULT STDMETHODCALLTYPE PhSecurityInformation_MapGeneric(\n    _In_ ISecurityInformation *This,\n    _In_ const GUID *ObjectType,\n    _In_ PUCHAR AceFlags,\n    _Inout_ PACCESS_MASK Mask\n    );\n\nHRESULT STDMETHODCALLTYPE PhSecurityInformation_GetInheritTypes(\n    _In_ ISecurityInformation *This,\n    _Out_ PSI_INHERIT_TYPE *InheritTypes,\n    _Out_ PULONG InheritTypesCount\n    );\n\nHRESULT STDMETHODCALLTYPE PhSecurityInformation_PropertySheetPageCallback(\n    _In_ ISecurityInformation *This,\n    _In_ HWND hwnd,\n    _In_ UINT uMsg,\n    _In_ SI_PAGE_TYPE uPage\n    );\n\nHRESULT STDMETHODCALLTYPE PhSecurityInformation2_QueryInterface(\n    _In_ ISecurityInformation2 *This,\n    _In_ REFIID Riid,\n    _Out_ PVOID *Object\n    );\n\nULONG STDMETHODCALLTYPE PhSecurityInformation2_AddRef(\n    _In_ ISecurityInformation2 *This\n    );\n\nULONG STDMETHODCALLTYPE PhSecurityInformation2_Release(\n    _In_ ISecurityInformation2 *This\n    );\n\nBOOL STDMETHODCALLTYPE PhSecurityInformation2_IsDaclCanonical(\n    _In_ ISecurityInformation2 *This,\n    _In_ PACL pDacl\n    );\n\nHRESULT STDMETHODCALLTYPE PhSecurityInformation2_LookupSids(\n    _In_ ISecurityInformation2 *This,\n    _In_ ULONG cSids,\n    _In_ PSID *rgpSids,\n    _Out_ LPDATAOBJECT *ppdo\n    );\n\nHRESULT STDMETHODCALLTYPE PhSecurityDataObject_QueryInterface(\n    _In_ IDataObject *This,\n    _In_ REFIID Riid,\n    _Out_ PVOID *Object\n    );\n\nULONG STDMETHODCALLTYPE PhSecurityDataObject_AddRef(\n    _In_ IDataObject *This\n    );\n\nULONG STDMETHODCALLTYPE PhSecurityDataObject_Release(\n    _In_ IDataObject *This\n    );\n\nHRESULT STDMETHODCALLTYPE PhSecurityDataObject_GetData(\n    _In_ IDataObject *This,\n    _In_ FORMATETC *pformatetcIn,\n    _Out_ STGMEDIUM *pmedium);\n\nHRESULT STDMETHODCALLTYPE PhSecurityDataObject_GetDataHere(\n    IDataObject *This,\n    _In_ FORMATETC *pformatetc,\n    _Inout_ STGMEDIUM *pmedium\n    );\n\nHRESULT STDMETHODCALLTYPE PhSecurityDataObject_QueryGetData(\n    _In_ IDataObject *This,\n    _In_opt_ FORMATETC *pformatetc\n    );\n\nHRESULT STDMETHODCALLTYPE PhSecurityDataObject_GetCanonicalFormatEtc(\n    _In_ IDataObject *This,\n    _In_opt_ FORMATETC *pformatectIn,\n    _Out_ FORMATETC *pformatetcOut\n    );\n\nHRESULT STDMETHODCALLTYPE PhSecurityDataObject_SetData(\n    _In_ IDataObject *This,\n    _In_ FORMATETC *pformatetc,\n    _In_ STGMEDIUM *pmedium,\n    _In_ BOOL fRelease\n    );\n\nHRESULT STDMETHODCALLTYPE PhSecurityDataObject_EnumFormatEtc(\n    _In_ IDataObject *This,\n    _In_ ULONG dwDirection,\n    _Out_opt_ IEnumFORMATETC **ppenumFormatEtc\n    );\n\nHRESULT STDMETHODCALLTYPE PhSecurityDataObject_DAdvise(\n    _In_ IDataObject *This,\n    _In_ FORMATETC *pformatetc,\n    _In_ ULONG advf,\n    _In_opt_ IAdviseSink *pAdvSink,\n    _Out_ ULONG *pdwConnection\n    );\n\nHRESULT STDMETHODCALLTYPE PhSecurityDataObject_DUnadvise(\n    _In_ IDataObject *This,\n    _In_ ULONG dwConnection\n    );\n\nHRESULT STDMETHODCALLTYPE PhSecurityDataObject_EnumDAdvise(\n    _In_ IDataObject *This,\n    _Out_opt_ IEnumSTATDATA **ppenumAdvise\n    );\n\n#endif\n"
  },
  {
    "path": "third_party/phlib/include/settings.h",
    "content": "#ifndef PHLIB_SETTINGS_H\n#define PHLIB_SETTINGS_H\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\n// begin_phapppub\n\n// These macros make sure the C strings can be seamlessly converted into\n// PH_STRINGREFs at compile time, for a small speed boost.\n\n#define ADD_SETTING_WRAPPER(Type, Name, DefaultValue) \\\n{ \\\n    static PH_STRINGREF name = PH_STRINGREF_INIT(Name); \\\n    static PH_STRINGREF defaultValue = PH_STRINGREF_INIT(DefaultValue); \\\n    PhAddSetting(Type, &name, &defaultValue); \\\n}\n\n#define PhpAddStringSetting(A, B) ADD_SETTING_WRAPPER(StringSettingType, A, B)\n#define PhpAddIntegerSetting(A, B) ADD_SETTING_WRAPPER(IntegerSettingType, A, B)\n#define PhpAddIntegerPairSetting(A, B) ADD_SETTING_WRAPPER(IntegerPairSettingType, A, B)\n#define PhpAddScalableIntegerPairSetting(A, B) ADD_SETTING_WRAPPER(ScalableIntegerPairSettingType, A, B)\n\ntypedef enum _PH_SETTING_TYPE\n{\n    StringSettingType,\n    IntegerSettingType,\n    IntegerPairSettingType,\n    ScalableIntegerPairSettingType\n} PH_SETTING_TYPE, PPH_SETTING_TYPE;\n// end_phapppub\n\ntypedef struct _PH_SETTING\n{\n    PH_SETTING_TYPE Type;\n    PH_STRINGREF Name;\n    PH_STRINGREF DefaultValue;\n\n    union\n    {\n        PVOID Pointer;\n        ULONG Integer;\n        PH_INTEGER_PAIR IntegerPair;\n    } u;\n} PH_SETTING, *PPH_SETTING;\n\nPHLIBAPI\nVOID \nPhSettingsInitialization(\n    VOID\n    );\n\n// Note: Program specific function.\nVOID PhAddDefaultSettings(\n    VOID\n    );\n\n// Note: Program specific function.\nVOID PhUpdateCachedSettings(\n    VOID\n    );\n\n// private\n\nPPH_STRING PhSettingToString(\n    _In_ PH_SETTING_TYPE Type,\n    _In_ PPH_SETTING Setting\n    );\n\nBOOLEAN PhSettingFromString(\n    _In_ PH_SETTING_TYPE Type,\n    _In_ PPH_STRINGREF StringRef,\n    _In_opt_ PPH_STRING String,\n    _Inout_ PPH_SETTING Setting\n    );\n\ntypedef BOOLEAN (NTAPI *PPH_SETTINGS_ENUM_CALLBACK)(\n    _In_ PPH_SETTING Setting,\n    _In_ PVOID Context\n    );\n\nVOID PhEnumSettings(\n    _In_ PPH_SETTINGS_ENUM_CALLBACK Callback,\n    _In_ PVOID Context\n    );\n\n// begin_phapppub\n_May_raise_\nPHLIBAPI\nULONG\nNTAPI\nPhGetIntegerSetting(\n    _In_ PWSTR Name\n    );\n\n_May_raise_\nPHLIBAPI\nPH_INTEGER_PAIR\nNTAPI\nPhGetIntegerPairSetting(\n    _In_ PWSTR Name\n    );\n\n_May_raise_\nPHLIBAPI\nPH_SCALABLE_INTEGER_PAIR\nNTAPI\nPhGetScalableIntegerPairSetting(\n    _In_ PWSTR Name,\n    _In_ BOOLEAN ScaleToCurrent\n    );\n\n_May_raise_\nPHLIBAPI\nPPH_STRING\nNTAPI\nPhGetStringSetting(\n    _In_ PWSTR Name\n    );\n\nFORCEINLINE \nPPH_STRING \nPhGetExpandStringSetting(\n    _In_ PWSTR Name\n    )\n{\n    PPH_STRING setting;\n\n    setting = PhGetStringSetting(Name);\n    PhMoveReference(&setting, PhExpandEnvironmentStrings(&setting->sr));\n\n    return setting;\n}\n\n_May_raise_\nPHLIBAPI\nVOID\nNTAPI\nPhSetIntegerSetting(\n    _In_ PWSTR Name,\n    _In_ ULONG Value\n    );\n\n_May_raise_\nPHLIBAPI\nVOID\nNTAPI\nPhSetIntegerPairSetting(\n    _In_ PWSTR Name,\n    _In_ PH_INTEGER_PAIR Value\n    );\n\n_May_raise_\nPHLIBAPI\nVOID\nNTAPI\nPhSetScalableIntegerPairSetting(\n    _In_ PWSTR Name,\n    _In_ PH_SCALABLE_INTEGER_PAIR Value\n    );\n\n_May_raise_\nPHLIBAPI\nVOID\nNTAPI\nPhSetScalableIntegerPairSetting2(\n    _In_ PWSTR Name,\n    _In_ PH_INTEGER_PAIR Value\n    );\n\n_May_raise_\nPHLIBAPI\nVOID\nNTAPI\nPhSetStringSetting(\n    _In_ PWSTR Name,\n    _In_ PWSTR Value\n    );\n\n_May_raise_\nPHLIBAPI\nVOID\nNTAPI\nPhSetStringSetting2(\n    _In_ PWSTR Name,\n    _In_ PPH_STRINGREF Value\n    );\n// end_phapppub\n\nVOID PhClearIgnoredSettings(\n    VOID\n    );\n\nVOID PhConvertIgnoredSettings(\n    VOID\n    );\n\nNTSTATUS PhLoadSettings(\n    _In_ PWSTR FileName\n    );\n\nNTSTATUS PhSaveSettings(\n    _In_ PWSTR FileName\n    );\n\nVOID PhResetSettings(\n    VOID\n    );\n\n#define PhaGetStringSetting(Name) PH_AUTO_T(PH_STRING, PhGetStringSetting(Name)) // phapppub\n\n// begin_phapppub\n// High-level settings creation\n\nVOID PhAddSetting(\n    _In_ PH_SETTING_TYPE Type,\n    _In_ PPH_STRINGREF Name,\n    _In_ PPH_STRINGREF DefaultValue\n    );\n\ntypedef struct _PH_SETTING_CREATE\n{\n    PH_SETTING_TYPE Type;\n    PWSTR Name;\n    PWSTR DefaultValue;\n} PH_SETTING_CREATE, *PPH_SETTING_CREATE;\n\nPHLIBAPI\nVOID\nNTAPI\nPhAddSettings(\n    _In_ PPH_SETTING_CREATE Settings,\n    _In_ ULONG NumberOfSettings\n    );\n\nVOID\nNTAPI\nPhLoadWindowPlacementFromSetting(\n    _In_opt_ PWSTR PositionSettingName,\n    _In_opt_ PWSTR SizeSettingName,\n    _In_ HWND WindowHandle\n    );\n\nVOID\nNTAPI\nPhSaveWindowPlacementToSetting(\n    _In_opt_ PWSTR PositionSettingName,\n    _In_opt_ PWSTR SizeSettingName,\n    _In_ HWND WindowHandle\n    );\n\nVOID\nNTAPI\nPhLoadListViewColumnsFromSetting(\n    _In_ PWSTR Name,\n    _In_ HWND ListViewHandle\n    );\n\nVOID\nNTAPI\nPhSaveListViewColumnsToSetting(\n    _In_ PWSTR Name,\n    _In_ HWND ListViewHandle\n    );\n// end_phapppub\n\n#define PH_SET_INTEGER_CACHED_SETTING(Name, Value) (PhSetIntegerSetting(L#Name, PhCs##Name = (Value)))\n\n#ifdef __cplusplus\n}\n#endif\n\n#endif\n"
  },
  {
    "path": "third_party/phlib/include/svcsup.h",
    "content": "#ifndef _PH_SVCSUP_H\n#define _PH_SVCSUP_H\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\nextern WCHAR *PhServiceTypeStrings[10];\nextern WCHAR *PhServiceStartTypeStrings[5];\nextern WCHAR *PhServiceErrorControlStrings[4];\n\nPHLIBAPI\nPVOID\nNTAPI\nPhEnumServices(\n    _In_ SC_HANDLE ScManagerHandle,\n    _In_opt_ ULONG Type,\n    _In_opt_ ULONG State,\n    _Out_ PULONG Count\n    );\n\nPHLIBAPI\nSC_HANDLE\nNTAPI\nPhOpenService(\n    _In_ PWSTR ServiceName,\n    _In_ ACCESS_MASK DesiredAccess\n    );\n\nPHLIBAPI\nPVOID\nNTAPI\nPhGetServiceConfig(\n    _In_ SC_HANDLE ServiceHandle\n    );\n\nPHLIBAPI\nPVOID\nNTAPI\nPhQueryServiceVariableSize(\n    _In_ SC_HANDLE ServiceHandle,\n    _In_ ULONG InfoLevel\n    );\n\nPHLIBAPI\nPPH_STRING\nNTAPI\nPhGetServiceDescription(\n    _In_ SC_HANDLE ServiceHandle\n    );\n\nPHLIBAPI\nBOOLEAN\nNTAPI\nPhGetServiceDelayedAutoStart(\n    _In_ SC_HANDLE ServiceHandle,\n    _Out_ PBOOLEAN DelayedAutoStart\n    );\n\nPHLIBAPI\nBOOLEAN\nNTAPI\nPhSetServiceDelayedAutoStart(\n    _In_ SC_HANDLE ServiceHandle,\n    _In_ BOOLEAN DelayedAutoStart\n    );\n\nPHLIBAPI\nPWSTR\nNTAPI\nPhGetServiceStateString(\n    _In_ ULONG ServiceState\n    );\n\nPHLIBAPI\nPWSTR\nNTAPI\nPhGetServiceTypeString(\n    _In_ ULONG ServiceType\n    );\n\nPHLIBAPI\nULONG\nNTAPI\nPhGetServiceTypeInteger(\n    _In_ PWSTR ServiceType\n    );\n\nPHLIBAPI\nPWSTR\nNTAPI\nPhGetServiceStartTypeString(\n    _In_ ULONG ServiceStartType\n    );\n\nPHLIBAPI\nULONG\nNTAPI\nPhGetServiceStartTypeInteger(\n    _In_ PWSTR ServiceStartType\n    );\n\nPHLIBAPI\nPWSTR\nNTAPI\nPhGetServiceErrorControlString(\n    _In_ ULONG ServiceErrorControl\n    );\n\nPHLIBAPI\nULONG\nNTAPI\nPhGetServiceErrorControlInteger(\n    _In_ PWSTR ServiceErrorControl\n    );\n\nPHLIBAPI\nPPH_STRING\nNTAPI\nPhGetServiceNameFromTag(\n    _In_ HANDLE ProcessId,\n    _In_ PVOID ServiceTag\n    );\n\nPHLIBAPI\nPPH_STRING\nNTAPI\nPhGetServiceNameForModuleReference(\n    _In_ HANDLE ProcessId,\n    _In_ PWSTR ModuleName\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhGetThreadServiceTag(\n    _In_ HANDLE ThreadHandle,\n    _In_opt_ HANDLE ProcessHandle,\n    _Out_ PVOID *ServiceTag\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhGetServiceDllParameter(\n    _In_ PPH_STRINGREF ServiceName,\n    _Out_ PPH_STRING *ServiceDll\n    );\n\n#ifdef __cplusplus\n}\n#endif\n\n#endif\n"
  },
  {
    "path": "third_party/phlib/include/symprv.h",
    "content": "#ifndef _PH_SYMPRV_H\n#define _PH_SYMPRV_H\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\nextern PPH_OBJECT_TYPE PhSymbolProviderType;\nextern PH_CALLBACK PhSymInitCallback;\n\n#define PH_MAX_SYMBOL_NAME_LEN 128\n\ntypedef struct _PH_SYMBOL_PROVIDER\n{\n    LIST_ENTRY ModulesListHead;\n    PH_QUEUED_LOCK ModulesListLock;\n    HANDLE ProcessHandle;\n    BOOLEAN IsRealHandle;\n    BOOLEAN IsRegistered;\n\n    PH_INITONCE InitOnce;\n    PH_AVL_TREE ModulesSet;\n    PH_CALLBACK EventCallback;\n} PH_SYMBOL_PROVIDER, *PPH_SYMBOL_PROVIDER;\n\ntypedef enum _PH_SYMBOL_RESOLVE_LEVEL\n{\n    PhsrlFunction,\n    PhsrlModule,\n    PhsrlAddress,\n    PhsrlInvalid\n} PH_SYMBOL_RESOLVE_LEVEL, *PPH_SYMBOL_RESOLVE_LEVEL;\n\ntypedef struct _PH_SYMBOL_INFORMATION\n{\n    ULONG64 Address;\n    ULONG64 ModuleBase;\n    ULONG Index;\n    ULONG Size;\n} PH_SYMBOL_INFORMATION, *PPH_SYMBOL_INFORMATION;\n\ntypedef struct _PH_SYMBOL_LINE_INFORMATION\n{\n    ULONG LineNumber;\n    ULONG64 Address;\n} PH_SYMBOL_LINE_INFORMATION, *PPH_SYMBOL_LINE_INFORMATION;\n\ntypedef enum _PH_SYMBOL_EVENT_TYPE\n{\n    SymbolDeferredSymbolLoadStart = 1,\n    SymbolDeferredSymbolLoadComplete = 2,\n    SymbolDeferredSymbolLoadFailure = 3,\n    SymbolSymbolsUnloaded = 4,\n    SymbolDeferredSymbolLoadCancel = 7\n} PH_SYMBOL_EVENT_TYPE;\n\ntypedef struct _PH_SYMBOL_EVENT_DATA\n{\n    PPH_SYMBOL_PROVIDER SymbolProvider;\n    PH_SYMBOL_EVENT_TYPE Type;\n\n    ULONG64 BaseAddress;\n    ULONG CheckSum;\n    ULONG TimeStamp;\n    PPH_STRING FileName;\n} PH_SYMBOL_EVENT_DATA, *PPH_SYMBOL_EVENT_DATA;\n\nPHLIBAPI\nBOOLEAN\nNTAPI\nPhSymbolProviderInitialization(\n    VOID\n    );\n\nPHLIBAPI\nVOID\nNTAPI\nPhSymbolProviderCompleteInitialization(\n    _In_opt_ PVOID DbgHelpBase\n    );\n\nPHLIBAPI\nPPH_SYMBOL_PROVIDER\nNTAPI\nPhCreateSymbolProvider(\n    _In_opt_ HANDLE ProcessId\n    );\n\nPHLIBAPI\nBOOLEAN\nNTAPI\nPhGetLineFromAddress(\n    _In_ PPH_SYMBOL_PROVIDER SymbolProvider,\n    _In_ ULONG64 Address,\n    _Out_ PPH_STRING *FileName,\n    _Out_opt_ PULONG Displacement,\n    _Out_opt_ PPH_SYMBOL_LINE_INFORMATION Information\n    );\n\nPHLIBAPI\nULONG64\nNTAPI\nPhGetModuleFromAddress(\n    _In_ PPH_SYMBOL_PROVIDER SymbolProvider,\n    _In_ ULONG64 Address,\n    _Out_opt_ PPH_STRING *FileName\n    );\n\nPHLIBAPI\nPPH_STRING\nNTAPI\nPhGetSymbolFromAddress(\n    _In_ PPH_SYMBOL_PROVIDER SymbolProvider,\n    _In_ ULONG64 Address,\n    _Out_opt_ PPH_SYMBOL_RESOLVE_LEVEL ResolveLevel,\n    _Out_opt_ PPH_STRING *FileName,\n    _Out_opt_ PPH_STRING *SymbolName,\n    _Out_opt_ PULONG64 Displacement\n    );\n\nPHLIBAPI\nBOOLEAN\nNTAPI\nPhGetSymbolFromName(\n    _In_ PPH_SYMBOL_PROVIDER SymbolProvider,\n    _In_ PWSTR Name,\n    _Out_ PPH_SYMBOL_INFORMATION Information\n    );\n\nPHLIBAPI\nBOOLEAN\nNTAPI\nPhLoadModuleSymbolProvider(\n    _In_ PPH_SYMBOL_PROVIDER SymbolProvider,\n    _In_ PWSTR FileName,\n    _In_ ULONG64 BaseAddress,\n    _In_ ULONG Size\n    );\n\nPHLIBAPI\nVOID\nNTAPI\nPhSetOptionsSymbolProvider(\n    _In_ ULONG Mask,\n    _In_ ULONG Value\n    );\n\nPHLIBAPI\nVOID\nNTAPI\nPhSetSearchPathSymbolProvider(\n    _In_ PPH_SYMBOL_PROVIDER SymbolProvider,\n    _In_ PWSTR Path\n    );\n\n#ifdef _WIN64\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhAccessOutOfProcessFunctionEntry(\n    _In_ HANDLE ProcessHandle,\n    _In_ ULONG64 ControlPc,\n    _Out_ PRUNTIME_FUNCTION Function\n    );\n#endif\n\nPHLIBAPI\nULONG64\n__stdcall\nPhGetModuleBase64(\n    _In_ HANDLE hProcess,\n    _In_ ULONG64 dwAddr\n    );\n\nPHLIBAPI\nPVOID\n__stdcall\nPhFunctionTableAccess64(\n    _In_ HANDLE hProcess,\n    _In_ ULONG64 AddrBase\n    );\n\n#ifndef _DBGHELP_\n\n// Some of the types used below are defined in dbghelp.h.\n\ntypedef struct _tagSTACKFRAME64 *LPSTACKFRAME64;\ntypedef struct _tagADDRESS64 *LPADDRESS64;\n\ntypedef BOOL (__stdcall *PREAD_PROCESS_MEMORY_ROUTINE64)(\n    _In_ HANDLE hProcess,\n    _In_ ULONG64 qwBaseAddress,\n    _Out_writes_bytes_(nSize) PVOID lpBuffer,\n    _In_ ULONG nSize,\n    _Out_ PULONG lpNumberOfBytesRead\n    );\n\ntypedef PVOID (__stdcall *PFUNCTION_TABLE_ACCESS_ROUTINE64)(\n    _In_ HANDLE ahProcess,\n    _In_ ULONG64 AddrBase\n    );\n\ntypedef ULONG64 (__stdcall *PGET_MODULE_BASE_ROUTINE64)(\n    _In_ HANDLE hProcess,\n    _In_ ULONG64 Address\n    );\n\ntypedef ULONG64 (__stdcall *PTRANSLATE_ADDRESS_ROUTINE64)(\n    _In_ HANDLE hProcess,\n    _In_ HANDLE hThread,\n    _In_ LPADDRESS64 lpaddr\n    );\n\ntypedef enum _MINIDUMP_TYPE MINIDUMP_TYPE;\ntypedef struct _MINIDUMP_EXCEPTION_INFORMATION *PMINIDUMP_EXCEPTION_INFORMATION;\ntypedef struct _MINIDUMP_USER_STREAM_INFORMATION *PMINIDUMP_USER_STREAM_INFORMATION;\ntypedef struct _MINIDUMP_CALLBACK_INFORMATION *PMINIDUMP_CALLBACK_INFORMATION;\n\n#endif\n\nPHLIBAPI\nBOOLEAN\nNTAPI\nPhStackWalk(\n    _In_ ULONG MachineType,\n    _In_ HANDLE ProcessHandle,\n    _In_ HANDLE ThreadHandle,\n    _Inout_ LPSTACKFRAME64 StackFrame,\n    _Inout_ PVOID ContextRecord,\n    _In_opt_ PPH_SYMBOL_PROVIDER SymbolProvider,\n    _In_opt_ PREAD_PROCESS_MEMORY_ROUTINE64 ReadMemoryRoutine,\n    _In_opt_ PFUNCTION_TABLE_ACCESS_ROUTINE64 FunctionTableAccessRoutine,\n    _In_opt_ PGET_MODULE_BASE_ROUTINE64 GetModuleBaseRoutine,\n    _In_opt_ PTRANSLATE_ADDRESS_ROUTINE64 TranslateAddress\n    );\n\nPHLIBAPI\nBOOLEAN\nNTAPI\nPhWriteMiniDumpProcess(\n    _In_ HANDLE ProcessHandle,\n    _In_ HANDLE ProcessId,\n    _In_ HANDLE FileHandle,\n    _In_ MINIDUMP_TYPE DumpType,\n    _In_opt_ PMINIDUMP_EXCEPTION_INFORMATION ExceptionParam,\n    _In_opt_ PMINIDUMP_USER_STREAM_INFORMATION UserStreamParam,\n    _In_opt_ PMINIDUMP_CALLBACK_INFORMATION CallbackParam\n    );\n\n// High-level stack walking\n\n#define PH_THREAD_STACK_FRAME_I386 0x1\n#define PH_THREAD_STACK_FRAME_AMD64 0x2\n#define PH_THREAD_STACK_FRAME_KERNEL 0x4\n#define PH_THREAD_STACK_FRAME_FPO_DATA_PRESENT 0x100\n\n/** Contains information about a thread stack frame. */\ntypedef struct _PH_THREAD_STACK_FRAME\n{\n    PVOID PcAddress;\n    PVOID ReturnAddress;\n    PVOID FrameAddress;\n    PVOID StackAddress;\n    PVOID BStoreAddress;\n    PVOID Params[4];\n    ULONG Flags;\n} PH_THREAD_STACK_FRAME, *PPH_THREAD_STACK_FRAME;\n\n#define PH_WALK_I386_STACK 0x1\n#define PH_WALK_AMD64_STACK 0x2\n#define PH_WALK_KERNEL_STACK 0x10\n\n/**\n * A callback function passed to PhWalkThreadStack() and called for each stack frame.\n *\n * \\param StackFrame A structure providing information about the stack frame.\n * \\param Context A user-defined value passed to PhWalkThreadStack().\n *\n * \\return TRUE to continue the stack walk, FALSE to stop.\n */\ntypedef BOOLEAN (NTAPI *PPH_WALK_THREAD_STACK_CALLBACK)(\n    _In_ PPH_THREAD_STACK_FRAME StackFrame,\n    _In_opt_ PVOID Context\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhWalkThreadStack(\n    _In_ HANDLE ThreadHandle,\n    _In_opt_ HANDLE ProcessHandle,\n    _In_opt_ PCLIENT_ID ClientId,\n    _In_opt_ PPH_SYMBOL_PROVIDER SymbolProvider,\n    _In_ ULONG Flags,\n    _In_ PPH_WALK_THREAD_STACK_CALLBACK Callback,\n    _In_opt_ PVOID Context\n    );\n\nPHLIBAPI\nPPH_STRING\nNTAPI\nPhUndecorateName(\n    _In_ PPH_SYMBOL_PROVIDER SymbolProvider,\n    _In_ PSTR DecoratedName\n    );\n\nPHLIBAPI\nPPH_STRING\nNTAPI\nPhUndecorateNameW(\n    _In_ PPH_SYMBOL_PROVIDER SymbolProvider,\n    _In_ PWSTR DecoratedName\n    );\n\n#ifdef __cplusplus\n}\n#endif\n\n#endif\n"
  },
  {
    "path": "third_party/phlib/include/symprvp.h",
    "content": "#ifndef _PH_SYMPRVP_H\n#define _PH_SYMPRVP_H\n\ntypedef BOOL (WINAPI *_SymInitialize)(\n    _In_ HANDLE hProcess,\n    _In_opt_ PCSTR UserSearchPath,\n    _In_ BOOL fInvadeProcess\n    );\n\ntypedef BOOL (WINAPI *_SymCleanup)(\n    _In_ HANDLE hProcess\n    );\n\ntypedef BOOL (WINAPI *_SymEnumSymbols)(\n    _In_ HANDLE hProcess,\n    _In_ ULONG64 BaseOfDll,\n    _In_opt_ PCSTR Mask,\n    _In_ PSYM_ENUMERATESYMBOLS_CALLBACK EnumSymbolsCallback,\n    _In_opt_ const PVOID UserContext\n    );\n\ntypedef BOOL (WINAPI *_SymEnumSymbolsW)(\n    _In_ HANDLE hProcess,\n    _In_ ULONG64 BaseOfDll,\n    _In_opt_ PCWSTR Mask,\n    _In_ PSYM_ENUMERATESYMBOLS_CALLBACKW EnumSymbolsCallback,\n    _In_opt_ const PVOID UserContext\n    );\n\ntypedef BOOL (WINAPI *_SymFromAddr)(\n    _In_ HANDLE hProcess,\n    _In_ ULONG64 Address,\n    _Out_opt_ PULONG64 Displacement,\n    _Inout_ PSYMBOL_INFO Symbol\n    );\n\ntypedef BOOL (WINAPI *_SymFromAddrW)(\n    _In_ HANDLE hProcess,\n    _In_ ULONG64 Address,\n    _Out_opt_ PULONG64 Displacement,\n    _Inout_ PSYMBOL_INFOW Symbol\n    );\n\ntypedef BOOL (WINAPI *_SymFromName)(\n    _In_ HANDLE hProcess,\n    _In_ PCSTR Name,\n    _Inout_ PSYMBOL_INFO Symbol\n    );\n\ntypedef BOOL (WINAPI *_SymFromNameW)(\n    _In_ HANDLE hProcess,\n    _In_ PCWSTR Name,\n    _Inout_ PSYMBOL_INFOW Symbol\n    );\n\ntypedef BOOL (WINAPI *_SymEnumTypesW)(\n    _In_ HANDLE hProcess,\n    _In_ ULONG64 BaseOfDll,\n    _In_ PSYM_ENUMERATESYMBOLS_CALLBACKW EnumSymbolsCallback,\n    _In_opt_ PVOID UserContext\n    );\n\ntypedef BOOL (WINAPI *_SymEnumTypes)(\n    _In_ HANDLE hProcess,\n    _In_ ULONG64 BaseOfDll,\n    _In_ PSYM_ENUMERATESYMBOLS_CALLBACK EnumSymbolsCallback,\n    _In_opt_ PVOID UserContext\n    );\n\ntypedef BOOL (WINAPI *_SymGetModuleInfoW64)(\n    _In_ HANDLE hProcess,\n    _In_ ULONG64 qwAddr,\n    _Out_ PIMAGEHLP_MODULEW64 ModuleInfo\n    );\n\ntypedef BOOL (WINAPI *_SymGetTypeFromName)(\n    _In_ HANDLE hProcess,\n    _In_ ULONG64 BaseOfDll,\n    _In_ PCSTR Name,\n    _Inout_ PSYMBOL_INFO Symbol\n    );\n\ntypedef BOOL(WINAPI *_SymGetTypeFromNameW)(\n    _In_ HANDLE hProcess,\n    _In_ ULONG64 BaseOfDll,\n    _In_ PCWSTR Name,\n    _Inout_ PSYMBOL_INFOW Symbol\n    );\n\ntypedef BOOL (WINAPI *_SymGetLineFromAddr64)(\n    _In_ HANDLE hProcess,\n    _In_ ULONG64 dwAddr,\n    _Out_ PULONG pdwDisplacement,\n    _Out_ PIMAGEHLP_LINE64 Line\n    );\n\ntypedef BOOL (WINAPI *_SymGetLineFromAddrW64)(\n    _In_ HANDLE hProcess,\n    _In_ ULONG64 dwAddr,\n    _Out_ PULONG pdwDisplacement,\n    _Out_ PIMAGEHLP_LINEW64 Line\n    );\n\ntypedef ULONG64 (WINAPI *_SymLoadModule64)(\n    _In_ HANDLE hProcess,\n    _In_opt_ HANDLE hFile,\n    _In_opt_ PCSTR ImageName,\n    _In_opt_ PCSTR ModuleName,\n    _In_ ULONG64 BaseOfDll,\n    _In_ ULONG SizeOfDll\n    );\n\ntypedef ULONG64 (WINAPI *_SymLoadModuleExW)(\n    _In_ HANDLE hProcess,\n    _In_ HANDLE hFile,\n    _In_ PCWSTR ImageName,\n    _In_ PCWSTR ModuleName,\n    _In_ ULONG64 BaseOfDll,\n    _In_ ULONG DllSize,\n    _In_ PMODLOAD_DATA Data,\n    _In_ ULONG Flags\n    );\n\ntypedef ULONG (WINAPI *_SymGetOptions)();\n\ntypedef ULONG (WINAPI *_SymSetOptions)(\n    _In_ ULONG SymOptions\n    );\n\ntypedef BOOL (WINAPI *_SymGetSearchPath)(\n    _In_ HANDLE hProcess,\n    _Out_ PSTR SearchPath,\n    _In_ ULONG SearchPathLength\n    );\n\ntypedef BOOL (WINAPI *_SymGetSearchPathW)(\n    _In_ HANDLE hProcess,\n    _Out_ PWSTR SearchPath,\n    _In_ ULONG SearchPathLength\n    );\n\ntypedef BOOL (WINAPI *_SymSetSearchPath)(\n    _In_ HANDLE hProcess,\n    _In_opt_ PCSTR SearchPath\n    );\n\ntypedef BOOL (WINAPI *_SymSetSearchPathW)(\n    _In_ HANDLE hProcess,\n    _In_opt_ PCWSTR SearchPath\n    );\n\ntypedef BOOL (WINAPI *_SymUnloadModule64)(\n    _In_ HANDLE hProcess,\n    _In_ ULONG64 BaseOfDll\n    );\n\ntypedef PVOID (WINAPI *_SymFunctionTableAccess64)(\n    _In_ HANDLE hProcess,\n    _In_ ULONG64 AddrBase\n    );\n\ntypedef ULONG64 (WINAPI *_SymGetModuleBase64)(\n    _In_ HANDLE hProcess,\n    _In_ ULONG64 dwAddr\n    );\n\ntypedef BOOL (WINAPI *_SymRegisterCallbackW64)(\n    _In_ HANDLE hProcess,\n    _In_ PSYMBOL_REGISTERED_CALLBACK64 CallbackFunction,\n    _In_ ULONG64 UserContext\n    );\n\ntypedef BOOL (WINAPI *_StackWalk64)(\n    _In_ ULONG MachineType,\n    _In_ HANDLE hProcess,\n    _In_ HANDLE hThread,\n    _Inout_ LPSTACKFRAME64 StackFrame,\n    _Inout_ PVOID ContextRecord,\n    _In_opt_ PREAD_PROCESS_MEMORY_ROUTINE64 ReadMemoryRoutine,\n    _In_opt_ PFUNCTION_TABLE_ACCESS_ROUTINE64 FunctionTableAccessRoutine,\n    _In_opt_ PGET_MODULE_BASE_ROUTINE64 GetModuleBaseRoutine,\n    _In_opt_ PTRANSLATE_ADDRESS_ROUTINE64 TranslateAddress\n    );\n\ntypedef BOOL (WINAPI *_MiniDumpWriteDump)(\n    _In_ HANDLE hProcess,\n    _In_ ULONG ProcessId,\n    _In_ HANDLE hFile,\n    _In_ MINIDUMP_TYPE DumpType,\n    _In_ PMINIDUMP_EXCEPTION_INFORMATION ExceptionParam,\n    _In_ PMINIDUMP_USER_STREAM_INFORMATION UserStreamParam,\n    _In_ PMINIDUMP_CALLBACK_INFORMATION CallbackParam\n    );\n\ntypedef UINT_PTR (CALLBACK *_SymbolServerGetOptions)(\n    VOID\n    );\n\ntypedef BOOL (CALLBACK *_SymbolServerSetOptions)(\n    _In_ UINT_PTR options,\n    _In_ ULONG64 data\n    );\n\ntypedef ULONG (WINAPI *_UnDecorateSymbolName)(\n    _In_ PCSTR DecoratedName,\n    _Out_ PSTR UnDecoratedName,\n    _In_ ULONG UndecoratedLength,\n    _In_ ULONG Flags\n    );\n\ntypedef ULONG (WINAPI *_UnDecorateSymbolNameW)(\n    _In_ PCWSTR DecoratedName,\n    _Out_ PWSTR UnDecoratedName,\n    _In_ ULONG UndecoratedLength,\n    _In_ ULONG Flags\n    );\n\n#endif"
  },
  {
    "path": "third_party/phlib/include/templ.h",
    "content": "#ifndef _PH_TEMPL_H\n#define _PH_TEMPL_H\n\n#define TEMPLATE_(f,T) f##_##T\n#define T___(f,T) TEMPLATE_(f,T)\n\n#endif\n"
  },
  {
    "path": "third_party/phlib/include/treenew.h",
    "content": "#ifndef _PH_TREENEW_H\n#define _PH_TREENEW_H\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\n#define PH_TREENEW_CLASSNAME L\"PhTreeNew\"\n\n#define PH_TREENEW_SEARCH_TIMEOUT 1000\n#define PH_TREENEW_SEARCH_MAXIMUM_LENGTH 1023\n\ntypedef struct _PH_TREENEW_COLUMN\n{\n    union\n    {\n        ULONG Flags;\n        struct\n        {\n            ULONG Visible : 1;\n            ULONG CustomDraw : 1;\n            ULONG Fixed : 1; // Whether this is the fixed column\n            ULONG SortDescending : 1; // Sort descending on initial click rather than ascending\n            ULONG DpiScaleOnAdd : 1; // Whether to DPI scale the width (only when adding)\n            ULONG SpareFlags : 27;\n        };\n    };\n    ULONG Id;\n    PVOID Context;\n    PWSTR Text;\n    LONG Width;\n    ULONG Alignment;\n    ULONG DisplayIndex; // -1 for fixed column or invalid\n\n    ULONG TextFlags;\n\n    struct\n    {\n        LONG ViewIndex; // Actual index in header control\n        LONG ViewX; // 0 for the fixed column, and an offset from the divider for normal columns\n    } s;\n} PH_TREENEW_COLUMN, *PPH_TREENEW_COLUMN;\n\ntypedef struct _PH_TREENEW_NODE\n{\n    union\n    {\n        ULONG Flags;\n        struct\n        {\n            ULONG Visible : 1;\n            ULONG Selected : 1;\n            ULONG Expanded : 1;\n            ULONG UseAutoForeColor : 1;\n            ULONG UseTempBackColor : 1;\n            ULONG Unselectable : 1;\n            ULONG SpareFlags : 26;\n        };\n    };\n\n    COLORREF BackColor;\n    COLORREF ForeColor;\n    COLORREF TempBackColor;\n    HFONT Font;\n    HICON Icon;\n\n    PPH_STRINGREF TextCache;\n    ULONG TextCacheSize;\n\n    ULONG Index; // Index within the flat list\n    ULONG Level; // 0 for root, 1, 2, ...\n\n    struct\n    {\n        union\n        {\n            ULONG Flags2;\n            struct\n            {\n                ULONG IsLeaf : 1;\n                ULONG CachedColorValid : 1;\n                ULONG CachedFontValid : 1;\n                ULONG CachedIconValid : 1;\n                ULONG PlusMinusHot : 1;\n                ULONG SpareFlags2 : 27;\n            };\n        };\n\n        // Temp. drawing data\n        COLORREF DrawBackColor;\n        COLORREF DrawForeColor;\n    } s;\n} PH_TREENEW_NODE, *PPH_TREENEW_NODE;\n\n// Styles\n#define TN_STYLE_ICONS 0x1\n#define TN_STYLE_DOUBLE_BUFFERED 0x2\n#define TN_STYLE_NO_DIVIDER 0x4\n#define TN_STYLE_ANIMATE_DIVIDER 0x8\n#define TN_STYLE_NO_COLUMN_SORT 0x10\n#define TN_STYLE_NO_COLUMN_REORDER 0x20\n#define TN_STYLE_THIN_ROWS 0x40\n#define TN_STYLE_NO_COLUMN_HEADER 0x80\n\n// Extended flags\n#define TN_FLAG_ITEM_DRAG_SELECT 0x1\n#define TN_FLAG_NO_UNFOLDING_TOOLTIPS 0x2\n\n// Callback flags\n#define TN_CACHE 0x1\n#define TN_AUTO_FORECOLOR 0x1000\n\n// Column change flags\n#define TN_COLUMN_CONTEXT 0x1\n#define TN_COLUMN_TEXT 0x2\n#define TN_COLUMN_WIDTH 0x4\n#define TN_COLUMN_ALIGNMENT 0x8\n#define TN_COLUMN_DISPLAYINDEX 0x10\n#define TN_COLUMN_TEXTFLAGS 0x20\n#define TN_COLUMN_FLAG_VISIBLE 0x100000\n#define TN_COLUMN_FLAG_CUSTOMDRAW 0x200000\n#define TN_COLUMN_FLAG_FIXED 0x400000\n#define TN_COLUMN_FLAG_SORTDESCENDING 0x800000\n#define TN_COLUMN_FLAG_NODPISCALEONADD 0x1000000\n#define TN_COLUMN_FLAGS 0xfff00000\n\n// Cache flags\n#define TN_CACHE_COLOR 0x1\n#define TN_CACHE_FONT 0x2\n#define TN_CACHE_ICON 0x4\n\n// Cell part input flags\n#define TN_MEASURE_TEXT 0x1\n\n// Cell part flags\n#define TN_PART_CELL 0x1\n#define TN_PART_PLUSMINUS 0x2\n#define TN_PART_ICON 0x4\n#define TN_PART_CONTENT 0x8\n#define TN_PART_TEXT 0x10\n\n// Hit test input flags\n#define TN_TEST_COLUMN 0x1\n#define TN_TEST_SUBITEM 0x2 // requires TN_TEST_COLUMN\n\n// Hit test flags\n#define TN_HIT_LEFT 0x1\n#define TN_HIT_RIGHT 0x2\n#define TN_HIT_ABOVE 0x4\n#define TN_HIT_BELOW 0x8\n#define TN_HIT_ITEM 0x10\n#define TN_HIT_ITEM_PLUSMINUS 0x20 // requires TN_TEST_SUBITEM\n#define TN_HIT_ITEM_ICON 0x40 // requires TN_TEST_SUBITEM\n#define TN_HIT_ITEM_CONTENT 0x80 // requires TN_TEST_SUBITEM\n#define TN_HIT_DIVIDER 0x100\n\n// Selection flags\n#define TN_SELECT_DESELECT 0x1\n#define TN_SELECT_TOGGLE 0x2\n#define TN_SELECT_RESET 0x4\n\n// Auto-size flags\n#define TN_AUTOSIZE_REMAINING_SPACE 0x1\n\ntypedef struct _PH_TREENEW_CELL_PARTS\n{\n    ULONG Flags;\n    RECT RowRect;\n    RECT CellRect; // TN_PART_CELL\n    RECT PlusMinusRect; // TN_PART_PLUSMINUS\n    RECT IconRect; // TN_PART_ICON\n    RECT ContentRect; // TN_PART_CONTENT\n    RECT TextRect; // TN_PART_TEXT\n    PH_STRINGREF Text; // TN_PART_TEXT\n    HFONT Font; // TN_PART_TEXT\n} PH_TREENEW_CELL_PARTS, *PPH_TREENEW_CELL_PARTS;\n\ntypedef struct _PH_TREENEW_HIT_TEST\n{\n    POINT Point;\n    ULONG InFlags;\n\n    ULONG Flags;\n    PPH_TREENEW_NODE Node;\n    PPH_TREENEW_COLUMN Column; // requires TN_TEST_COLUMN\n} PH_TREENEW_HIT_TEST, *PPH_TREENEW_HIT_TEST;\n\ntypedef enum _PH_TREENEW_MESSAGE\n{\n    TreeNewGetChildren, // PPH_TREENEW_GET_CHILDREN Parameter1\n    TreeNewIsLeaf, // PPH_TREENEW_IS_LEAF Parameter1\n    TreeNewGetCellText, // PPH_TREENEW_GET_CELL_TEXT Parameter1\n    TreeNewGetNodeColor, // PPH_TREENEW_GET_NODE_COLOR Parameter1\n    TreeNewGetNodeFont, // PPH_TREENEW_GET_NODE_FONT Parameter1\n    TreeNewGetNodeIcon, // PPH_TREENEW_GET_NODE_ICON Parameter1\n    TreeNewGetCellTooltip, // PPH_TREENEW_GET_CELL_TOOLTIP Parameter1\n    TreeNewCustomDraw, // PPH_TREENEW_CUSTOM_DRAW Parameter1\n\n    // Notifications\n    TreeNewNodeExpanding, // PPH_TREENEW_NODE Parameter1, PPH_TREENEW_NODE_EVENT Parameter2\n    TreeNewNodeSelecting, // PPH_TREENEW_NODE Parameter1\n\n    TreeNewSortChanged,\n    TreeNewSelectionChanged,\n\n    TreeNewKeyDown, // PPH_TREENEW_KEY_EVENT Parameter1\n    TreeNewLeftClick, // PPH_TREENEW_MOUSE_EVENT Parameter1\n    TreeNewRightClick, // PPH_TREENEW_MOUSE_EVENT Parameter1\n    TreeNewLeftDoubleClick, // PPH_TREENEW_MOUSE_EVENT Parameter1\n    TreeNewRightDoubleClick, // PPH_TREENEW_MOUSE_EVENT Parameter1\n    TreeNewContextMenu, // PPH_TREENEW_CONTEXT_MENU Parameter1\n\n    TreeNewHeaderRightClick, // PPH_TREENEW_HEADER_MOUSE_EVENT Parameter1\n    TreeNewIncrementalSearch, // PPH_TREENEW_SEARCH_EVENT Parameter1\n\n    TreeNewColumnResized, // PPH_TREENEW_COLUMN Parameter1\n    TreeNewColumnReordered,\n\n    TreeNewDestroying,\n    TreeNewGetDialogCode, // ULONG Parameter1, PULONG Parameter2\n\n    MaxTreeNewMessage\n} PH_TREENEW_MESSAGE;\n\ntypedef BOOLEAN (NTAPI *PPH_TREENEW_CALLBACK)(\n    _In_ HWND hwnd,\n    _In_ PH_TREENEW_MESSAGE Message,\n    _In_opt_ PVOID Parameter1,\n    _In_opt_ PVOID Parameter2,\n    _In_opt_ PVOID Context\n    );\n\ntypedef struct _PH_TREENEW_GET_CHILDREN\n{\n    ULONG Flags;\n    PPH_TREENEW_NODE Node;\n\n    ULONG NumberOfChildren;\n    PPH_TREENEW_NODE *Children; // can be NULL if no children\n} PH_TREENEW_GET_CHILDREN, *PPH_TREENEW_GET_CHILDREN;\n\ntypedef struct _PH_TREENEW_IS_LEAF\n{\n    ULONG Flags;\n    PPH_TREENEW_NODE Node;\n\n    BOOLEAN IsLeaf;\n} PH_TREENEW_IS_LEAF, *PPH_TREENEW_IS_LEAF;\n\ntypedef struct _PH_TREENEW_GET_CELL_TEXT\n{\n    ULONG Flags;\n    PPH_TREENEW_NODE Node;\n    ULONG Id;\n\n    PH_STRINGREF Text;\n} PH_TREENEW_GET_CELL_TEXT, *PPH_TREENEW_GET_CELL_TEXT;\n\ntypedef struct _PH_TREENEW_GET_NODE_COLOR\n{\n    ULONG Flags;\n    PPH_TREENEW_NODE Node;\n\n    COLORREF BackColor;\n    COLORREF ForeColor;\n} PH_TREENEW_GET_NODE_COLOR, *PPH_TREENEW_GET_NODE_COLOR;\n\ntypedef struct _PH_TREENEW_GET_NODE_FONT\n{\n    ULONG Flags;\n    PPH_TREENEW_NODE Node;\n\n    HFONT Font;\n} PH_TREENEW_GET_NODE_FONT, *PPH_TREENEW_GET_NODE_FONT;\n\ntypedef struct _PH_TREENEW_GET_NODE_ICON\n{\n    ULONG Flags;\n    PPH_TREENEW_NODE Node;\n\n    HICON Icon;\n} PH_TREENEW_GET_NODE_ICON, *PPH_TREENEW_GET_NODE_ICON;\n\ntypedef struct _PH_TREENEW_GET_CELL_TOOLTIP\n{\n    ULONG Flags;\n    PPH_TREENEW_NODE Node;\n    PPH_TREENEW_COLUMN Column;\n\n    BOOLEAN Unfolding;\n    PH_STRINGREF Text;\n    HFONT Font;\n    ULONG MaximumWidth;\n} PH_TREENEW_GET_CELL_TOOLTIP, *PPH_TREENEW_GET_CELL_TOOLTIP;\n\ntypedef struct _PH_TREENEW_CUSTOM_DRAW\n{\n    PPH_TREENEW_NODE Node;\n    PPH_TREENEW_COLUMN Column;\n\n    HDC Dc;\n    RECT CellRect;\n    RECT TextRect;\n} PH_TREENEW_CUSTOM_DRAW, *PPH_TREENEW_CUSTOM_DRAW;\n\ntypedef struct _PH_TREENEW_MOUSE_EVENT\n{\n    POINT Location;\n    PPH_TREENEW_NODE Node;\n    PPH_TREENEW_COLUMN Column;\n    ULONG KeyFlags;\n} PH_TREENEW_MOUSE_EVENT, *PPH_TREENEW_MOUSE_EVENT;\n\ntypedef struct _PH_TREENEW_KEY_EVENT\n{\n    BOOLEAN Handled;\n    ULONG VirtualKey;\n    ULONG Data;\n} PH_TREENEW_KEY_EVENT, *PPH_TREENEW_KEY_EVENT;\n\ntypedef struct _PH_TREENEW_NODE_EVENT\n{\n    BOOLEAN Handled;\n    ULONG Flags;\n    PVOID Reserved1;\n    PVOID Reserved2;\n} PH_TREENEW_NODE_EVENT, *PPH_TREENEW_NODE_EVENT;\n\ntypedef struct _PH_TREENEW_CONTEXT_MENU\n{\n    POINT Location;\n    POINT ClientLocation;\n    PPH_TREENEW_NODE Node;\n    PPH_TREENEW_COLUMN Column;\n    BOOLEAN KeyboardInvoked;\n} PH_TREENEW_CONTEXT_MENU, *PPH_TREENEW_CONTEXT_MENU;\n\ntypedef struct _PH_TREENEW_HEADER_MOUSE_EVENT\n{\n    POINT ScreenLocation;\n    POINT Location;\n    POINT HeaderLocation;\n    PPH_TREENEW_COLUMN Column;\n} PH_TREENEW_HEADER_MOUSE_EVENT, *PPH_TREENEW_HEADER_MOUSE_EVENT;\n\ntypedef struct _PH_TREENEW_SEARCH_EVENT\n{\n    LONG FoundIndex;\n    LONG StartIndex;\n    PH_STRINGREF String;\n} PH_TREENEW_SEARCH_EVENT, *PPH_TREENEW_SEARCH_EVENT;\n\n#define TNM_FIRST (WM_USER + 1)\n#define TNM_SETCALLBACK (WM_USER + 1)\n#define TNM_NODESADDED (WM_USER + 2) // unimplemented\n#define TNM_NODESREMOVED (WM_USER + 3) // unimplemented\n#define TNM_NODESSTRUCTURED (WM_USER + 4)\n#define TNM_ADDCOLUMN (WM_USER + 5)\n#define TNM_REMOVECOLUMN (WM_USER + 6)\n#define TNM_GETCOLUMN (WM_USER + 7)\n#define TNM_SETCOLUMN (WM_USER + 8)\n#define TNM_GETCOLUMNORDERARRAY (WM_USER + 9)\n#define TNM_SETCOLUMNORDERARRAY (WM_USER + 10)\n#define TNM_SETCURSOR (WM_USER + 11)\n#define TNM_GETSORT (WM_USER + 12)\n#define TNM_SETSORT (WM_USER + 13)\n#define TNM_SETTRISTATE (WM_USER + 14)\n#define TNM_ENSUREVISIBLE (WM_USER + 15)\n#define TNM_SCROLL (WM_USER + 16)\n#define TNM_GETFLATNODECOUNT (WM_USER + 17)\n#define TNM_GETFLATNODE (WM_USER + 18)\n#define TNM_GETCELLTEXT (WM_USER + 19)\n#define TNM_SETNODEEXPANDED (WM_USER + 20)\n#define TNM_GETMAXID (WM_USER + 21)\n#define TNM_SETMAXID (WM_USER + 22)\n#define TNM_INVALIDATENODE (WM_USER + 23)\n#define TNM_INVALIDATENODES (WM_USER + 24)\n#define TNM_GETFIXEDHEADER (WM_USER + 25)\n#define TNM_GETHEADER (WM_USER + 26)\n#define TNM_GETTOOLTIPS (WM_USER + 27)\n#define TNM_SELECTRANGE (WM_USER + 28)\n#define TNM_DESELECTRANGE (WM_USER + 29)\n#define TNM_GETCOLUMNCOUNT (WM_USER + 30)\n#define TNM_SETREDRAW (WM_USER + 31)\n#define TNM_GETVIEWPARTS (WM_USER + 32)\n#define TNM_GETFIXEDCOLUMN (WM_USER + 33)\n#define TNM_GETFIRSTCOLUMN (WM_USER + 34)\n#define TNM_SETFOCUSNODE (WM_USER + 35)\n#define TNM_SETMARKNODE (WM_USER + 36)\n#define TNM_SETHOTNODE (WM_USER + 37)\n#define TNM_SETEXTENDEDFLAGS (WM_USER + 38)\n#define TNM_GETCALLBACK (WM_USER + 39)\n#define TNM_HITTEST (WM_USER + 40)\n#define TNM_GETVISIBLECOLUMNCOUNT (WM_USER + 41)\n#define TNM_AUTOSIZECOLUMN (WM_USER + 42)\n#define TNM_SETEMPTYTEXT (WM_USER + 43)\n#define TNM_SETROWHEIGHT (WM_USER + 44)\n#define TNM_ISFLATNODEVALID (WM_USER + 45)\n#define TNM_LAST (WM_USER + 45)\n\n#define TreeNew_SetCallback(hWnd, Callback, Context) \\\n    SendMessage((hWnd), TNM_SETCALLBACK, (WPARAM)(Context), (LPARAM)(Callback))\n\n#define TreeNew_NodesStructured(hWnd) \\\n    SendMessage((hWnd), TNM_NODESSTRUCTURED, 0, 0)\n\n#define TreeNew_AddColumn(hWnd, Column) \\\n    SendMessage((hWnd), TNM_ADDCOLUMN, 0, (LPARAM)(Column))\n\n#define TreeNew_RemoveColumn(hWnd, Id) \\\n    SendMessage((hWnd), TNM_REMOVECOLUMN, (WPARAM)(Id), 0)\n\n#define TreeNew_GetColumn(hWnd, Id, Column) \\\n    SendMessage((hWnd), TNM_GETCOLUMN, (WPARAM)(Id), (LPARAM)(Column))\n\n#define TreeNew_SetColumn(hWnd, Mask, Column) \\\n    SendMessage((hWnd), TNM_SETCOLUMN, (WPARAM)(Mask), (LPARAM)(Column))\n\n#define TreeNew_GetColumnOrderArray(hWnd, Count, Array) \\\n    SendMessage((hWnd), TNM_GETCOLUMNORDERARRAY, (WPARAM)(Count), (LPARAM)(Array))\n\n#define TreeNew_SetColumnOrderArray(hWnd, Count, Array) \\\n    SendMessage((hWnd), TNM_SETCOLUMNORDERARRAY, (WPARAM)(Count), (LPARAM)(Array))\n\n#define TreeNew_SetCursor(hWnd, Cursor) \\\n    SendMessage((hWnd), TNM_SETCURSOR, 0, (LPARAM)(Cursor))\n\n#define TreeNew_GetSort(hWnd, Column, Order) \\\n    SendMessage((hWnd), TNM_GETSORT, (WPARAM)(Column), (LPARAM)(Order))\n\n#define TreeNew_SetSort(hWnd, Column, Order) \\\n    SendMessage((hWnd), TNM_SETSORT, (WPARAM)(Column), (LPARAM)(Order))\n\n#define TreeNew_SetTriState(hWnd, TriState) \\\n    SendMessage((hWnd), TNM_SETTRISTATE, (WPARAM)(TriState), 0)\n\n#define TreeNew_EnsureVisible(hWnd, Node) \\\n    SendMessage((hWnd), TNM_ENSUREVISIBLE, 0, (LPARAM)(Node))\n\n#define TreeNew_Scroll(hWnd, DeltaRows, DeltaX) \\\n    SendMessage((hWnd), TNM_SCROLL, (WPARAM)(DeltaRows), (LPARAM)(DeltaX))\n\n#define TreeNew_GetFlatNodeCount(hWnd) \\\n    ((ULONG)SendMessage((hWnd), TNM_GETFLATNODECOUNT, 0, 0))\n\n#define TreeNew_GetFlatNode(hWnd, Index) \\\n    ((PPH_TREENEW_NODE)SendMessage((hWnd), TNM_GETFLATNODE, (WPARAM)(Index), 0))\n\n#define TreeNew_GetCellText(hWnd, GetCellText) \\\n    SendMessage((hWnd), TNM_GETCELLTEXT, 0, (LPARAM)(GetCellText))\n\n#define TreeNew_SetNodeExpanded(hWnd, Node, Expanded) \\\n    SendMessage((hWnd), TNM_SETNODEEXPANDED, (WPARAM)(Expanded), (LPARAM)(Node))\n\n#define TreeNew_GetMaxId(hWnd) \\\n    ((ULONG)SendMessage((hWnd), TNM_GETMAXID, 0, 0))\n\n#define TreeNew_SetMaxId(hWnd, MaxId) \\\n    SendMessage((hWnd), TNM_SETMAXID, (WPARAM)(MaxId), 0)\n\n#define TreeNew_InvalidateNode(hWnd, Node) \\\n    SendMessage((hWnd), TNM_INVALIDATENODE, 0, (LPARAM)(Node))\n\n#define TreeNew_InvalidateNodes(hWnd, Start, End) \\\n    SendMessage((hWnd), TNM_INVALIDATENODES, (WPARAM)(Start), (LPARAM)(End))\n\n#define TreeNew_GetFixedHeader(hWnd) \\\n    ((HWND)SendMessage((hWnd), TNM_GETFIXEDHEADER, 0, 0))\n\n#define TreeNew_GetHeader(hWnd) \\\n    ((HWND)SendMessage((hWnd), TNM_GETHEADER, 0, 0))\n\n#define TreeNew_GetTooltips(hWnd) \\\n    ((HWND)SendMessage((hWnd), TNM_GETTOOLTIPS, 0, 0))\n\n#define TreeNew_SelectRange(hWnd, Start, End) \\\n    SendMessage((hWnd), TNM_SELECTRANGE, (WPARAM)(Start), (LPARAM)(End))\n\n#define TreeNew_DeselectRange(hWnd, Start, End) \\\n    SendMessage((hWnd), TNM_DESELECTRANGE, (WPARAM)(Start), (LPARAM)(End))\n\n#define TreeNew_GetColumnCount(hWnd) \\\n    ((ULONG)SendMessage((hWnd), TNM_GETCOLUMNCOUNT, 0, 0))\n\n#define TreeNew_SetRedraw(hWnd, Redraw) \\\n    ((LONG)SendMessage((hWnd), TNM_SETREDRAW, (WPARAM)(Redraw), 0))\n\n#define TreeNew_GetViewParts(hWnd, Parts) \\\n    SendMessage((hWnd), TNM_GETVIEWPARTS, 0, (LPARAM)(Parts))\n\n#define TreeNew_GetFixedColumn(hWnd) \\\n    ((PPH_TREENEW_COLUMN)SendMessage((hWnd), TNM_GETFIXEDCOLUMN, 0, 0))\n\n#define TreeNew_GetFirstColumn(hWnd) \\\n    ((PPH_TREENEW_COLUMN)SendMessage((hWnd), TNM_GETFIRSTCOLUMN, 0, 0))\n\n#define TreeNew_SetFocusNode(hWnd, Node) \\\n    SendMessage((hWnd), TNM_SETFOCUSNODE, 0, (LPARAM)(Node))\n\n#define TreeNew_SetMarkNode(hWnd, Node) \\\n    SendMessage((hWnd), TNM_SETMARKNODE, 0, (LPARAM)(Node))\n\n#define TreeNew_SetHotNode(hWnd, Node) \\\n    SendMessage((hWnd), TNM_SETHOTNODE, 0, (LPARAM)(Node))\n\n#define TreeNew_SetExtendedFlags(hWnd, Mask, Value) \\\n    SendMessage((hWnd), TNM_SETEXTENDEDFLAGS, (WPARAM)(Mask), (LPARAM)(Value))\n\n#define TreeNew_GetCallback(hWnd, Callback, Context) \\\n    SendMessage((hWnd), TNM_GETCALLBACK, (WPARAM)(Context), (LPARAM)(Callback))\n\n#define TreeNew_HitTest(hWnd, HitTest) \\\n    SendMessage((hWnd), TNM_HITTEST, 0, (LPARAM)(HitTest))\n\n#define TreeNew_GetVisibleColumnCount(hWnd) \\\n    ((ULONG)SendMessage((hWnd), TNM_GETVISIBLECOLUMNCOUNT, 0, 0))\n\n#define TreeNew_AutoSizeColumn(hWnd, Id, Flags) \\\n    SendMessage((hWnd), TNM_AUTOSIZECOLUMN, (WPARAM)(Id), (LPARAM)(Flags))\n\n#define TreeNew_SetEmptyText(hWnd, Text, Flags) \\\n    SendMessage((hWnd), TNM_SETEMPTYTEXT, (WPARAM)(Flags), (LPARAM)(Text))\n\n#define TreeNew_SetRowHeight(hWnd, RowHeight) \\\n    SendMessage((hWnd), TNM_SETROWHEIGHT, (WPARAM)(RowHeight), 0)\n\n#define TreeNew_IsFlatNodeValid(hWnd) \\\n    ((BOOLEAN)SendMessage((hWnd), TNM_ISFLATNODEVALID, 0, 0))\n\ntypedef struct _PH_TREENEW_VIEW_PARTS\n{\n    RECT ClientRect;\n    LONG HeaderHeight;\n    LONG RowHeight;\n    ULONG VScrollWidth;\n    ULONG HScrollHeight;\n    LONG VScrollPosition;\n    LONG HScrollPosition;\n    LONG FixedWidth;\n    LONG NormalLeft;\n    LONG NormalWidth;\n} PH_TREENEW_VIEW_PARTS, *PPH_TREENEW_VIEW_PARTS;\n\nPHLIBAPI\nBOOLEAN PhTreeNewInitialization(\n    VOID\n    );\n\nFORCEINLINE VOID PhInitializeTreeNewNode(\n    _In_ PPH_TREENEW_NODE Node\n    )\n{\n    memset(Node, 0, sizeof(PH_TREENEW_NODE));\n\n    Node->Visible = TRUE;\n    Node->Expanded = TRUE;\n}\n\nFORCEINLINE VOID PhInvalidateTreeNewNode(\n    _Inout_ PPH_TREENEW_NODE Node,\n    _In_ ULONG Flags\n    )\n{\n    if (Flags & TN_CACHE_COLOR)\n        Node->s.CachedColorValid = FALSE;\n    if (Flags & TN_CACHE_FONT)\n        Node->s.CachedFontValid = FALSE;\n    if (Flags & TN_CACHE_ICON)\n        Node->s.CachedIconValid = FALSE;\n}\n\nFORCEINLINE BOOLEAN PhAddTreeNewColumn(\n    _In_ HWND hwnd,\n    _In_ ULONG Id,\n    _In_ BOOLEAN Visible,\n    _In_ PWSTR Text,\n    _In_ ULONG Width,\n    _In_ ULONG Alignment,\n    _In_ ULONG DisplayIndex,\n    _In_ ULONG TextFlags\n    )\n{\n    PH_TREENEW_COLUMN column;\n\n    memset(&column, 0, sizeof(PH_TREENEW_COLUMN));\n    column.Id = Id;\n    column.Visible = Visible;\n    column.Text = Text;\n    column.Width = Width;\n    column.Alignment = Alignment;\n    column.DisplayIndex = DisplayIndex;\n    column.TextFlags = TextFlags;\n    column.DpiScaleOnAdd = TRUE;\n\n    if (DisplayIndex == -2)\n        column.Fixed = TRUE;\n\n    return !!TreeNew_AddColumn(hwnd, &column);\n}\n\nFORCEINLINE BOOLEAN PhAddTreeNewColumnEx(\n    _In_ HWND hwnd,\n    _In_ ULONG Id,\n    _In_ BOOLEAN Visible,\n    _In_ PWSTR Text,\n    _In_ ULONG Width,\n    _In_ ULONG Alignment,\n    _In_ ULONG DisplayIndex,\n    _In_ ULONG TextFlags,\n    _In_ BOOLEAN SortDescending\n    )\n{\n    PH_TREENEW_COLUMN column;\n\n    memset(&column, 0, sizeof(PH_TREENEW_COLUMN));\n    column.Id = Id;\n    column.Visible = Visible;\n    column.Text = Text;\n    column.Width = Width;\n    column.Alignment = Alignment;\n    column.DisplayIndex = DisplayIndex;\n    column.TextFlags = TextFlags;\n    column.DpiScaleOnAdd = TRUE;\n\n    if (DisplayIndex == -2)\n        column.Fixed = TRUE;\n    if (SortDescending)\n        column.SortDescending = TRUE;\n\n    return !!TreeNew_AddColumn(hwnd, &column);\n}\n\nFORCEINLINE BOOLEAN PhAddTreeNewColumnEx2(\n    _In_ HWND hwnd,\n    _In_ ULONG Id,\n    _In_ BOOLEAN Visible,\n    _In_ PWSTR Text,\n    _In_ ULONG Width,\n    _In_ ULONG Alignment,\n    _In_ ULONG DisplayIndex,\n    _In_ ULONG TextFlags,\n    _In_ ULONG ExtraFlags\n    )\n{\n    PH_TREENEW_COLUMN column;\n\n    memset(&column, 0, sizeof(PH_TREENEW_COLUMN));\n    column.Id = Id;\n    column.Visible = Visible;\n    column.Text = Text;\n    column.Width = Width;\n    column.Alignment = Alignment;\n    column.DisplayIndex = DisplayIndex;\n    column.TextFlags = TextFlags;\n\n    if (DisplayIndex == -2)\n        column.Fixed = TRUE;\n    if (ExtraFlags & TN_COLUMN_FLAG_CUSTOMDRAW)\n        column.CustomDraw = TRUE;\n    if (ExtraFlags & TN_COLUMN_FLAG_SORTDESCENDING)\n        column.SortDescending = TRUE;\n    if (!(ExtraFlags & TN_COLUMN_FLAG_NODPISCALEONADD))\n        column.DpiScaleOnAdd = TRUE;\n\n    return !!TreeNew_AddColumn(hwnd, &column);\n}\n\n#ifdef __cplusplus\n}\n#endif\n\n#endif\n"
  },
  {
    "path": "third_party/phlib/include/treenewp.h",
    "content": "#ifndef _PH_TREENEWP_H\n#define _PH_TREENEWP_H\n\n// Important notes about pointers:\n//\n// All memory allocation for nodes and strings is handled by the user. This usually means there is a\n// very limited time during which they can be safely accessed.\n//\n// Node pointers are valid through the duration of message processing, and also up to the next\n// restructure operation, either user- or control- initiated. This means that state such as the\n// focused node, hot node and mark node must be carefully preserved through restructuring. If\n// restructuring is suspended by a set-redraw call, all nodes must be considered invalid and no user\n// input can be handled.\n//\n// Strings are valid only through the duration of message processing.\n\ntypedef struct _PH_TREENEW_CONTEXT\n{\n    HWND Handle;\n    PVOID InstanceHandle;\n    HWND FixedHeaderHandle;\n    HWND HeaderHandle;\n    HWND VScrollHandle;\n    HWND HScrollHandle;\n    HWND FillerBoxHandle;\n    HWND TooltipsHandle;\n\n    union\n    {\n        struct\n        {\n            ULONG FontOwned : 1;\n            ULONG Tracking : 1; // tracking for fixed divider\n            ULONG VScrollVisible : 1;\n            ULONG HScrollVisible : 1;\n            ULONG FixedColumnVisible : 1;\n            ULONG FixedDividerVisible : 1;\n            ULONG AnimateDivider : 1;\n            ULONG AnimateDividerFadingIn : 1;\n            ULONG AnimateDividerFadingOut : 1;\n            ULONG CanAnyExpand : 1;\n            ULONG TriState : 1;\n            ULONG HasFocus : 1;\n            ULONG ThemeInitialized : 1; // delay load theme data\n            ULONG ThemeActive : 1;\n            ULONG ThemeHasItemBackground : 1;\n            ULONG ThemeHasGlyph : 1;\n            ULONG ThemeHasHotGlyph : 1;\n            ULONG FocusNodeFound : 1; // used to preserve the focused node across restructuring\n            ULONG SearchFailed : 1; // used to prevent multiple beeps\n            ULONG SearchSingleCharMode : 1; // LV style single-character search\n            ULONG TooltipUnfolding : 1; // whether the current tooltip is unfolding\n            ULONG DoubleBuffered : 1;\n            ULONG SuspendUpdateStructure : 1;\n            ULONG SuspendUpdateLayout : 1;\n            ULONG SuspendUpdateMoveMouse : 1;\n            ULONG DragSelectionActive : 1;\n            ULONG SelectionRectangleAlpha : 1; // use alpha blending for the selection rectangle\n            ULONG CustomRowHeight : 1;\n            ULONG Spare : 4;\n        };\n        ULONG Flags;\n    };\n    ULONG Style;\n    ULONG ExtendedStyle;\n    ULONG ExtendedFlags;\n\n    HFONT Font;\n    HCURSOR Cursor;\n    HCURSOR DividerCursor;\n\n    RECT ClientRect;\n    LONG HeaderHeight;\n    LONG RowHeight;\n    ULONG VScrollWidth;\n    ULONG HScrollHeight;\n    LONG VScrollPosition;\n    LONG HScrollPosition;\n    LONG FixedWidth; // width of the fixed part of the tree list\n    LONG FixedWidthMinimum;\n    LONG NormalLeft; // FixedWidth + 1 if there is a fixed column, otherwise 0\n\n    PPH_TREENEW_NODE FocusNode;\n    ULONG HotNodeIndex;\n    ULONG MarkNodeIndex; // selection mark\n\n    ULONG MouseDownLast;\n    POINT MouseDownLocation;\n\n    PPH_TREENEW_CALLBACK Callback;\n    PVOID CallbackContext;\n\n    PPH_TREENEW_COLUMN *Columns; // columns, indexed by ID\n    ULONG NextId;\n    ULONG AllocatedColumns;\n    ULONG NumberOfColumns; // just a statistic; do not use for actual logic\n\n    PPH_TREENEW_COLUMN *ColumnsByDisplay; // columns, indexed by display order (excluding the fixed column)\n    ULONG AllocatedColumnsByDisplay;\n    ULONG NumberOfColumnsByDisplay; // the number of visible columns (excluding the fixed column)\n    LONG TotalViewX; // total width of normal columns\n    PPH_TREENEW_COLUMN FixedColumn;\n    PPH_TREENEW_COLUMN FirstColumn; // first column, by display order (including the fixed column)\n    PPH_TREENEW_COLUMN LastColumn; // last column, by display order (including the fixed column)\n\n    PPH_TREENEW_COLUMN ResizingColumn;\n    LONG OldColumnWidth;\n    LONG TrackStartX;\n    LONG TrackOldFixedWidth;\n    ULONG DividerHot; // 0 for un-hot, 100 for completely hot\n\n    PPH_LIST FlatList;\n\n    ULONG SortColumn; // ID of the column to sort by\n    PH_SORT_ORDER SortOrder;\n\n    FLOAT VScrollRemainder;\n    FLOAT HScrollRemainder;\n\n    LONG SearchMessageTime;\n    PWSTR SearchString;\n    ULONG SearchStringCount;\n    ULONG AllocatedSearchString;\n\n    ULONG TooltipIndex;\n    ULONG TooltipId;\n    PPH_STRING TooltipText;\n    RECT TooltipRect; // text rectangle of an unfolding tooltip\n    HFONT TooltipFont;\n    HFONT NewTooltipFont;\n    ULONG TooltipColumnId;\n\n    TEXTMETRIC TextMetrics;\n    HTHEME ThemeData;\n    COLORREF DefaultBackColor;\n    COLORREF DefaultForeColor;\n    LONG SystemBorderX;\n    LONG SystemBorderY;\n    LONG SystemEdgeX;\n    LONG SystemEdgeY;\n\n    HDC BufferedContext;\n    HBITMAP BufferedOldBitmap;\n    HBITMAP BufferedBitmap;\n    RECT BufferedContextRect;\n\n    LONG SystemDragX;\n    LONG SystemDragY;\n    RECT DragRect;\n\n    LONG EnableRedraw;\n    HRGN SuspendUpdateRegion;\n\n    PH_STRINGREF EmptyText;\n} PH_TREENEW_CONTEXT, *PPH_TREENEW_CONTEXT;\n\nLRESULT CALLBACK PhTnpWndProc(\n    _In_ HWND hwnd,\n    _In_ UINT uMsg,\n    _In_ WPARAM wParam,\n    _In_ LPARAM lParam\n    );\n\nBOOLEAN NTAPI PhTnpNullCallback(\n    _In_ HWND hwnd,\n    _In_ PH_TREENEW_MESSAGE Message,\n    _In_opt_ PVOID Parameter1,\n    _In_opt_ PVOID Parameter2,\n    _In_opt_ PVOID Context\n    );\n\nVOID PhTnpCreateTreeNewContext(\n    _Out_ PPH_TREENEW_CONTEXT *Context\n    );\n\nVOID PhTnpDestroyTreeNewContext(\n    _In_ PPH_TREENEW_CONTEXT Context\n    );\n\n// Event handlers\n\nBOOLEAN PhTnpOnCreate(\n    _In_ HWND hwnd,\n    _In_ PPH_TREENEW_CONTEXT Context,\n    _In_ CREATESTRUCT *CreateStruct\n    );\n\nVOID PhTnpOnSize(\n    _In_ HWND hwnd,\n    _In_ PPH_TREENEW_CONTEXT Context\n    );\n\nVOID PhTnpOnSetFont(\n    _In_ HWND hwnd,\n    _In_ PPH_TREENEW_CONTEXT Context,\n    _In_opt_ HFONT Font,\n    _In_ LOGICAL Redraw\n    );\n\nVOID PhTnpOnStyleChanged(\n    _In_ HWND hwnd,\n    _In_ PPH_TREENEW_CONTEXT Context,\n    _In_ LONG Type,\n    _In_ STYLESTRUCT *StyleStruct\n    );\n\nVOID PhTnpOnSettingChange(\n    _In_ HWND hwnd,\n    _In_ PPH_TREENEW_CONTEXT Context\n    );\n\nVOID PhTnpOnThemeChanged(\n    _In_ HWND hwnd,\n    _In_ PPH_TREENEW_CONTEXT Context\n    );\n\nULONG PhTnpOnGetDlgCode(\n    _In_ HWND hwnd,\n    _In_ PPH_TREENEW_CONTEXT Context,\n    _In_ ULONG VirtualKey,\n    _In_opt_ PMSG Message\n    );\n\nVOID PhTnpOnPaint(\n    _In_ HWND hwnd,\n    _In_ PPH_TREENEW_CONTEXT Context\n    );\n\nVOID PhTnpOnPrintClient(\n    _In_ HWND hwnd,\n    _In_ PPH_TREENEW_CONTEXT Context,\n    _In_ HDC hdc,\n    _In_ ULONG Flags\n    );\n\nBOOLEAN PhTnpOnNcPaint(\n    _In_ HWND hwnd,\n    _In_ PPH_TREENEW_CONTEXT Context,\n    _In_opt_ HRGN UpdateRegion\n    );\n\nBOOLEAN PhTnpOnSetCursor(\n    _In_ HWND hwnd,\n    _In_ PPH_TREENEW_CONTEXT Context,\n    _In_ HWND CursorWindowHandle\n    );\n\nVOID PhTnpOnTimer(\n    _In_ HWND hwnd,\n    _In_ PPH_TREENEW_CONTEXT Context,\n    _In_ ULONG Id\n    );\n\nVOID PhTnpOnMouseMove(\n    _In_ HWND hwnd,\n    _In_ PPH_TREENEW_CONTEXT Context,\n    _In_ ULONG VirtualKeys,\n    _In_ LONG CursorX,\n    _In_ LONG CursorY\n    );\n\nVOID PhTnpOnMouseLeave(\n    _In_ HWND hwnd,\n    _In_ PPH_TREENEW_CONTEXT Context\n    );\n\nVOID PhTnpOnXxxButtonXxx(\n    _In_ HWND hwnd,\n    _In_ PPH_TREENEW_CONTEXT Context,\n    _In_ ULONG Message,\n    _In_ ULONG VirtualKeys,\n    _In_ LONG CursorX,\n    _In_ LONG CursorY\n    );\n\nVOID PhTnpOnCaptureChanged(\n    _In_ HWND hwnd,\n    _In_ PPH_TREENEW_CONTEXT Context\n    );\n\nVOID PhTnpOnKeyDown(\n    _In_ HWND hwnd,\n    _In_ PPH_TREENEW_CONTEXT Context,\n    _In_ ULONG VirtualKey,\n    _In_ ULONG Data\n    );\n\nVOID PhTnpOnChar(\n    _In_ HWND hwnd,\n    _In_ PPH_TREENEW_CONTEXT Context,\n    _In_ ULONG Character,\n    _In_ ULONG Data\n    );\n\nVOID PhTnpOnMouseWheel(\n    _In_ HWND hwnd,\n    _In_ PPH_TREENEW_CONTEXT Context,\n    _In_ LONG Distance,\n    _In_ ULONG VirtualKeys,\n    _In_ LONG CursorX,\n    _In_ LONG CursorY\n    );\n\nVOID PhTnpOnMouseHWheel(\n    _In_ HWND hwnd,\n    _In_ PPH_TREENEW_CONTEXT Context,\n    _In_ LONG Distance,\n    _In_ ULONG VirtualKeys,\n    _In_ LONG CursorX,\n    _In_ LONG CursorY\n    );\n\nVOID PhTnpOnContextMenu(\n    _In_ HWND hwnd,\n    _In_ PPH_TREENEW_CONTEXT Context,\n    _In_ LONG CursorScreenX,\n    _In_ LONG CursorScreenY\n    );\n\nVOID PhTnpOnVScroll(\n    _In_ HWND hwnd,\n    _In_ PPH_TREENEW_CONTEXT Context,\n    _In_ ULONG Request,\n    _In_ USHORT Position\n    );\n\nVOID PhTnpOnHScroll(\n    _In_ HWND hwnd,\n    _In_ PPH_TREENEW_CONTEXT Context,\n    _In_ ULONG Request,\n    _In_ USHORT Position\n    );\n\nBOOLEAN PhTnpOnNotify(\n    _In_ HWND hwnd,\n    _In_ PPH_TREENEW_CONTEXT Context,\n    _In_ NMHDR *Header,\n    _Out_ LRESULT *Result\n    );\n\nULONG_PTR PhTnpOnUserMessage(\n    _In_ HWND hwnd,\n    _In_ PPH_TREENEW_CONTEXT Context,\n    _In_ ULONG Message,\n    _In_ ULONG_PTR WParam,\n    _In_ ULONG_PTR LParam\n    );\n\n// Misc.\n\nVOID PhTnpSetFont(\n    _In_ PPH_TREENEW_CONTEXT Context,\n    _In_opt_ HFONT Font,\n    _In_ BOOLEAN Redraw\n    );\n\nVOID PhTnpUpdateSystemMetrics(\n    _In_ PPH_TREENEW_CONTEXT Context\n    );\n\nVOID PhTnpUpdateTextMetrics(\n    _In_ PPH_TREENEW_CONTEXT Context\n    );\n\nVOID PhTnpUpdateThemeData(\n    _In_ PPH_TREENEW_CONTEXT Context\n    );\n\nVOID PhTnpInitializeThemeData(\n    _In_ PPH_TREENEW_CONTEXT Context\n    );\n\nVOID PhTnpCancelTrack(\n    _In_ PPH_TREENEW_CONTEXT Context\n    );\n\nVOID PhTnpLayout(\n    _In_ PPH_TREENEW_CONTEXT Context\n    );\n\nVOID PhTnpLayoutHeader(\n    _In_ PPH_TREENEW_CONTEXT Context\n    );\n\nVOID PhTnpSetFixedWidth(\n    _In_ PPH_TREENEW_CONTEXT Context,\n    _In_ ULONG FixedWidth\n    );\n\nVOID PhTnpSetRedraw(\n    _In_ PPH_TREENEW_CONTEXT Context,\n    _In_ BOOLEAN Redraw\n    );\n\nVOID PhTnpSendMouseEvent(\n    _In_ PPH_TREENEW_CONTEXT Context,\n    _In_ PH_TREENEW_MESSAGE Message,\n    _In_ LONG CursorX,\n    _In_ LONG CursorY,\n    _In_ PPH_TREENEW_NODE Node,\n    _In_ PPH_TREENEW_COLUMN Column,\n    _In_ ULONG VirtualKeys\n    );\n\n// Columns\n\nPPH_TREENEW_COLUMN PhTnpLookupColumnById(\n    _In_ PPH_TREENEW_CONTEXT Context,\n    _In_ ULONG Id\n    );\n\nBOOLEAN PhTnpAddColumn(\n    _In_ PPH_TREENEW_CONTEXT Context,\n    _In_ PPH_TREENEW_COLUMN Column\n    );\n\nBOOLEAN PhTnpRemoveColumn(\n    _In_ PPH_TREENEW_CONTEXT Context,\n    _In_ ULONG Id\n    );\n\nBOOLEAN PhTnpCopyColumn(\n    _In_ PPH_TREENEW_CONTEXT Context,\n    _In_ ULONG Id,\n    _Out_ PPH_TREENEW_COLUMN Column\n    );\n\nBOOLEAN PhTnpChangeColumn(\n    _In_ PPH_TREENEW_CONTEXT Context,\n    _In_ ULONG Mask,\n    _In_ ULONG Id,\n    _In_ PPH_TREENEW_COLUMN Column\n    );\n\nVOID PhTnpExpandAllocatedColumns(\n    _In_ PPH_TREENEW_CONTEXT Context\n    );\n\nVOID PhTnpUpdateColumnMaps(\n    _In_ PPH_TREENEW_CONTEXT Context\n    );\n\n// Columns (header control)\n\nLONG PhTnpInsertColumnHeader(\n    _In_ PPH_TREENEW_CONTEXT Context,\n    _In_ PPH_TREENEW_COLUMN Column\n    );\n\nVOID PhTnpChangeColumnHeader(\n    _In_ PPH_TREENEW_CONTEXT Context,\n    _In_ ULONG Mask,\n    _In_ PPH_TREENEW_COLUMN Column\n    );\n\nVOID PhTnpDeleteColumnHeader(\n    _In_ PPH_TREENEW_CONTEXT Context,\n    _Inout_ PPH_TREENEW_COLUMN Column\n    );\n\nVOID PhTnpUpdateColumnHeaders(\n    _In_ PPH_TREENEW_CONTEXT Context\n    );\n\nVOID PhTnpProcessResizeColumn(\n    _In_ PPH_TREENEW_CONTEXT Context,\n    _In_ PPH_TREENEW_COLUMN Column,\n    _In_ LONG Delta\n    );\n\nVOID PhTnpProcessSortColumn(\n    _In_ PPH_TREENEW_CONTEXT Context,\n    _In_ PPH_TREENEW_COLUMN NewColumn\n    );\n\nBOOLEAN PhTnpSetColumnHeaderSortIcon(\n    _In_ PPH_TREENEW_CONTEXT Context,\n    _In_opt_ PPH_TREENEW_COLUMN SortColumnPointer\n    );\n\nVOID PhTnpAutoSizeColumnHeader(\n    _In_ PPH_TREENEW_CONTEXT Context,\n    _In_ HWND HeaderHandle,\n    _In_ PPH_TREENEW_COLUMN Column,\n    _In_ ULONG Flags\n    );\n\n// Nodes\n\nBOOLEAN PhTnpGetNodeChildren(\n    _In_ PPH_TREENEW_CONTEXT Context,\n    _In_opt_ PPH_TREENEW_NODE Node,\n    _Out_ PPH_TREENEW_NODE **Children,\n    _Out_ PULONG NumberOfChildren\n    );\n\nBOOLEAN PhTnpIsNodeLeaf(\n    _In_ PPH_TREENEW_CONTEXT Context,\n    _In_ PPH_TREENEW_NODE Node\n    );\n\nBOOLEAN PhTnpGetCellText(\n    _In_ PPH_TREENEW_CONTEXT Context,\n    _In_ PPH_TREENEW_NODE Node,\n    _In_ ULONG Id,\n    _Out_ PPH_STRINGREF Text\n    );\n\nVOID PhTnpRestructureNodes(\n    _In_ PPH_TREENEW_CONTEXT Context\n    );\n\nVOID PhTnpInsertNodeChildren(\n    _In_ PPH_TREENEW_CONTEXT Context,\n    _In_ PPH_TREENEW_NODE Node,\n    _In_ ULONG Level\n    );\n\nVOID PhTnpSetExpandedNode(\n    _In_ PPH_TREENEW_CONTEXT Context,\n    _In_ PPH_TREENEW_NODE Node,\n    _In_ BOOLEAN Expanded\n    );\n\nBOOLEAN PhTnpGetCellParts(\n    _In_ PPH_TREENEW_CONTEXT Context,\n    _In_ ULONG Index,\n    _In_opt_ PPH_TREENEW_COLUMN Column,\n    _In_ ULONG Flags,\n    _Out_ PPH_TREENEW_CELL_PARTS Parts\n    );\n\nBOOLEAN PhTnpGetRowRects(\n    _In_ PPH_TREENEW_CONTEXT Context,\n    _In_ ULONG Start,\n    _In_ ULONG End,\n    _In_ BOOLEAN Clip,\n    _Out_ PRECT Rect\n    );\n\nVOID PhTnpHitTest(\n    _In_ PPH_TREENEW_CONTEXT Context,\n    _Inout_ PPH_TREENEW_HIT_TEST HitTest\n    );\n\nVOID PhTnpSelectRange(\n    _In_ PPH_TREENEW_CONTEXT Context,\n    _In_ ULONG Start,\n    _In_ ULONG End,\n    _In_ ULONG Flags,\n    _Out_opt_ PULONG ChangedStart,\n    _Out_opt_ PULONG ChangedEnd\n    );\n\nVOID PhTnpSetHotNode(\n    _In_ PPH_TREENEW_CONTEXT Context,\n    _In_opt_ PPH_TREENEW_NODE NewHotNode,\n    _In_ BOOLEAN NewPlusMinusHot\n    );\n\nVOID PhTnpProcessSelectNode(\n    _In_ PPH_TREENEW_CONTEXT Context,\n    _In_ PPH_TREENEW_NODE Node,\n    _In_ LOGICAL ControlKey,\n    _In_ LOGICAL ShiftKey,\n    _In_ LOGICAL RightButton\n    );\n\nBOOLEAN PhTnpEnsureVisibleNode(\n    _In_ PPH_TREENEW_CONTEXT Context,\n    _In_ ULONG Index\n    );\n\n// Mouse\n\nVOID PhTnpProcessMoveMouse(\n    _In_ PPH_TREENEW_CONTEXT Context,\n    _In_ LONG CursorX,\n    _In_ LONG CursorY\n    );\n\nVOID PhTnpProcessMouseVWheel(\n    _In_ PPH_TREENEW_CONTEXT Context,\n    _In_ LONG Distance\n    );\n\nVOID PhTnpProcessMouseHWheel(\n    _In_ PPH_TREENEW_CONTEXT Context,\n    _In_ LONG Distance\n    );\n\n// Keyboard\n\nBOOLEAN PhTnpProcessFocusKey(\n    _In_ PPH_TREENEW_CONTEXT Context,\n    _In_ ULONG VirtualKey\n    );\n\nBOOLEAN PhTnpProcessNodeKey(\n    _In_ PPH_TREENEW_CONTEXT Context,\n    _In_ ULONG VirtualKey\n    );\n\nVOID PhTnpProcessSearchKey(\n    _In_ PPH_TREENEW_CONTEXT Context,\n    _In_ ULONG Character\n    );\n\nBOOLEAN PhTnpDefaultIncrementalSearch(\n    _In_ PPH_TREENEW_CONTEXT Context,\n    _Inout_ PPH_TREENEW_SEARCH_EVENT SearchEvent,\n    _In_ BOOLEAN Partial,\n    _In_ BOOLEAN Wrap\n    );\n\n// Scrolling\n\nVOID PhTnpUpdateScrollBars(\n    _In_ PPH_TREENEW_CONTEXT Context\n    );\n\nVOID PhTnpScroll(\n    _In_ PPH_TREENEW_CONTEXT Context,\n    _In_ LONG DeltaRows,\n    _In_ LONG DeltaX\n    );\n\nVOID PhTnpProcessScroll(\n    _In_ PPH_TREENEW_CONTEXT Context,\n    _In_ LONG DeltaRows,\n    _In_ LONG DeltaX\n    );\n\nBOOLEAN PhTnpCanScroll(\n    _In_ PPH_TREENEW_CONTEXT Context,\n    _In_ BOOLEAN Horizontal,\n    _In_ BOOLEAN Positive\n    );\n\n// Drawing\n\nVOID PhTnpPaint(\n    _In_ HWND hwnd,\n    _In_ PPH_TREENEW_CONTEXT Context,\n    _In_ HDC hdc,\n    _In_ PRECT PaintRect\n    );\n\nVOID PhTnpPrepareRowForDraw(\n    _In_ PPH_TREENEW_CONTEXT Context,\n    _In_ HDC hdc,\n    _Inout_ PPH_TREENEW_NODE Node\n    );\n\nVOID PhTnpDrawCell(\n    _In_ PPH_TREENEW_CONTEXT Context,\n    _In_ HDC hdc,\n    _In_ PRECT CellRect,\n    _In_ PPH_TREENEW_NODE Node,\n    _In_ PPH_TREENEW_COLUMN Column,\n    _In_ LONG RowIndex,\n    _In_ LONG ColumnIndex\n    );\n\nVOID PhTnpDrawDivider(\n    _In_ PPH_TREENEW_CONTEXT Context,\n    _In_ HDC hdc\n    );\n\nVOID PhTnpDrawPlusMinusGlyph(\n    _In_ HDC hdc,\n    _In_ PRECT Rect,\n    _In_ BOOLEAN Plus\n    );\n\nVOID PhTnpDrawSelectionRectangle(\n    _In_ PPH_TREENEW_CONTEXT Context,\n    _In_ HDC hdc,\n    _In_ PRECT Rect\n    );\n\nVOID PhTnpDrawThemedBorder(\n    _In_ PPH_TREENEW_CONTEXT Context,\n    _In_ HDC hdc\n    );\n\n// Tooltips\n\nVOID PhTnpInitializeTooltips(\n    _In_ PPH_TREENEW_CONTEXT Context\n    );\n\nVOID PhTnpGetTooltipText(\n    _In_ PPH_TREENEW_CONTEXT Context,\n    _In_ PPOINT Point,\n    _Out_ PWSTR *Text\n    );\n\nBOOLEAN PhTnpPrepareTooltipShow(\n    _In_ PPH_TREENEW_CONTEXT Context\n    );\n\nVOID PhTnpPrepareTooltipPop(\n    _In_ PPH_TREENEW_CONTEXT Context\n    );\n\nVOID PhTnpPopTooltip(\n    _In_ PPH_TREENEW_CONTEXT Context\n    );\n\nPPH_TREENEW_COLUMN PhTnpHitTestHeader(\n    _In_ PPH_TREENEW_CONTEXT Context,\n    _In_ BOOLEAN Fixed,\n    _In_ PPOINT Point,\n    _Out_opt_ PRECT ItemRect\n    );\n\nVOID PhTnpGetHeaderTooltipText(\n    _In_ PPH_TREENEW_CONTEXT Context,\n    _In_ BOOLEAN Fixed,\n    _In_ PPOINT Point,\n    _Out_ PWSTR *Text\n    );\n\n\nLRESULT CALLBACK PhTnpHeaderHookWndProc(\n    _In_ HWND hwnd,\n    _In_ UINT uMsg,\n    _In_ WPARAM wParam,\n    _In_ LPARAM lParam,\n    _In_ UINT_PTR uIdSubclass,\n    _In_ ULONG_PTR dwRefData\n    );\n\n// Drag selection\n\nBOOLEAN PhTnpDetectDrag(\n    _In_ PPH_TREENEW_CONTEXT Context,\n    _In_ LONG CursorX,\n    _In_ LONG CursorY,\n    _In_ BOOLEAN DispatchMessages,\n    _Out_opt_ PULONG CancelledByMessage\n    );\n\nVOID PhTnpDragSelect(\n    _In_ PPH_TREENEW_CONTEXT Context,\n    _In_ LONG CursorX,\n    _In_ LONG CursorY\n    );\n\nVOID PhTnpProcessDragSelect(\n    _In_ PPH_TREENEW_CONTEXT Context,\n    _In_ ULONG VirtualKeys,\n    _In_ PRECT OldRect,\n    _In_ PRECT NewRect,\n    _In_ PRECT TotalRect\n    );\n\n// Double buffering\n\nVOID PhTnpCreateBufferedContext(\n    _In_ PPH_TREENEW_CONTEXT Context\n    );\n\nVOID PhTnpDestroyBufferedContext(\n    _In_ PPH_TREENEW_CONTEXT Context\n    );\n\n// Support functions\n\nVOID PhTnpGetMessagePos(\n    _In_ HWND hwnd,\n    _Out_ PPOINT ClientPoint\n    );\n\n// Macros\n\n#define HRGN_FULL ((HRGN)1) // passed by WM_NCPAINT even though it's completely undocumented\n\n#define TNP_CELL_LEFT_MARGIN 6\n#define TNP_CELL_RIGHT_MARGIN 6\n#define TNP_ICON_RIGHT_PADDING 4\n\n#define TNP_TIMER_NULL 1\n#define TNP_TIMER_ANIMATE_DIVIDER 2\n\n#define TNP_TOOLTIPS_ITEM 0\n#define TNP_TOOLTIPS_FIXED_HEADER 1\n#define TNP_TOOLTIPS_HEADER 2\n#define TNP_TOOLTIPS_DEFAULT_MAXIMUM_WIDTH 550\n\n#define TNP_ANIMATE_DIVIDER_INTERVAL 10\n#define TNP_ANIMATE_DIVIDER_INCREMENT 17\n#define TNP_ANIMATE_DIVIDER_DECREMENT 2\n\n#define TNP_HIT_TEST_FIXED_DIVIDER(X, Context) \\\n    ((Context)->FixedDividerVisible && (X) >= (Context)->FixedWidth - 8 && (X) < (Context)->FixedWidth + 8)\n#define TNP_HIT_TEST_PLUS_MINUS_GLYPH(X, NodeLevel) \\\n    (((X) >= TNP_CELL_LEFT_MARGIN + ((LONG)(NodeLevel) * SmallIconWidth)) && ((X) < TNP_CELL_LEFT_MARGIN + ((LONG)(NodeLevel) * SmallIconWidth) + SmallIconWidth))\n\n#endif\n"
  },
  {
    "path": "third_party/phlib/include/verify.h",
    "content": "#ifndef _PH_VERIFY_H\n#define _PH_VERIFY_H\n\n#include <wintrust.h>\n#include <softpub.h>\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\n#define PH_VERIFY_DEFAULT_SIZE_LIMIT (32 * 1024 * 1024)\n\ntypedef enum _VERIFY_RESULT\n{\n    VrUnknown = 0,\n    VrNoSignature,\n    VrTrusted,\n    VrExpired,\n    VrRevoked,\n    VrDistrust,\n    VrSecuritySettings,\n    VrBadSignature\n} VERIFY_RESULT, *PVERIFY_RESULT;\n\n#define PH_VERIFY_PREVENT_NETWORK_ACCESS 0x1\n#define PH_VERIFY_VIEW_PROPERTIES 0x2\n\ntypedef struct _PH_VERIFY_FILE_INFO\n{\n    PWSTR FileName;\n    ULONG Flags; // PH_VERIFY_*\n\n    ULONG FileSizeLimitForHash; // 0 for PH_VERIFY_DEFAULT_SIZE_LIMIT, -1 for unlimited\n    ULONG NumberOfCatalogFileNames;\n    PWSTR *CatalogFileNames;\n\n    HWND hWnd; // for PH_VERIFY_VIEW_PROPERTIES\n} PH_VERIFY_FILE_INFO, *PPH_VERIFY_FILE_INFO;\n\nPHLIBAPI\nVERIFY_RESULT\nNTAPI\nPhVerifyFile(\n    _In_ PWSTR FileName,\n    _Out_opt_ PPH_STRING *SignerName\n    );\n\nPHLIBAPI\nNTSTATUS\nNTAPI\nPhVerifyFileEx(\n    _In_ PPH_VERIFY_FILE_INFO Information,\n    _Out_ VERIFY_RESULT *VerifyResult,\n    _Out_opt_ PCERT_CONTEXT **Signatures,\n    _Out_opt_ PULONG NumberOfSignatures\n    );\n\nPHLIBAPI\nVOID\nNTAPI\nPhFreeVerifySignatures(\n    _In_ PCERT_CONTEXT *Signatures,\n    _In_ ULONG NumberOfSignatures\n    );\n\nPHLIBAPI\nPPH_STRING\nNTAPI\nPhGetSignerNameFromCertificate(\n    _In_ PCERT_CONTEXT Certificate\n    );\n\n#ifdef __cplusplus\n}\n#endif\n\n#endif\n"
  },
  {
    "path": "third_party/phlib/include/verifyp.h",
    "content": "#ifndef _PH_VERIFYP_H\n#define _PH_VERIFYP_H\n\n#include <commdlg.h>\n\ntypedef struct _CATALOG_INFO\n{\n    ULONG cbStruct;\n    WCHAR wszCatalogFile[MAX_PATH];\n} CATALOG_INFO, *PCATALOG_INFO;\n\ntypedef struct tagCRYPTUI_VIEWSIGNERINFO_STRUCT {\n    ULONG dwSize;\n    HWND hwndParent;\n    ULONG dwFlags;\n    LPCTSTR szTitle;\n    CMSG_SIGNER_INFO *pSignerInfo;\n    HCRYPTMSG hMsg;\n    LPCSTR pszOID;\n    ULONG_PTR dwReserved;\n    ULONG cStores;\n    HCERTSTORE *rghStores;\n    ULONG cPropSheetPages;\n    LPCPROPSHEETPAGE rgPropSheetPages;\n} CRYPTUI_VIEWSIGNERINFO_STRUCT, *PCRYPTUI_VIEWSIGNERINFO_STRUCT;\n\ntypedef BOOL (WINAPI *_CryptCATAdminCalcHashFromFileHandle)(\n    HANDLE hFile,\n    ULONG *pcbHash,\n    BYTE *pbHash,\n    ULONG dwFlags\n    );\n\ntypedef BOOL (WINAPI *_CryptCATAdminCalcHashFromFileHandle2)(\n    HCATADMIN hCatAdmin,\n    HANDLE hFile,\n    ULONG *pcbHash,\n    BYTE *pbHash,\n    ULONG dwFlags\n    );\n\ntypedef BOOL (WINAPI *_CryptCATAdminAcquireContext)(\n    HANDLE *phCatAdmin,\n    GUID *pgSubsystem,\n    ULONG dwFlags\n    );\n\ntypedef BOOL (WINAPI *_CryptCATAdminAcquireContext2)(\n    HCATADMIN *phCatAdmin,\n    const GUID *pgSubsystem,\n    PCWSTR pwszHashAlgorithm,\n    PCCERT_STRONG_SIGN_PARA pStrongHashPolicy,\n    ULONG dwFlags\n    );\n\ntypedef HANDLE (WINAPI *_CryptCATAdminEnumCatalogFromHash)(\n    HANDLE hCatAdmin,\n    BYTE *pbHash,\n    ULONG cbHash,\n    ULONG dwFlags,\n    HANDLE *phPrevCatInfo\n    );\n\ntypedef BOOL (WINAPI *_CryptCATCatalogInfoFromContext)(\n    HANDLE hCatInfo,\n    CATALOG_INFO *psCatInfo,\n    ULONG dwFlags\n    );\n\ntypedef BOOL (WINAPI *_CryptCATAdminReleaseCatalogContext)(\n    HANDLE hCatAdmin,\n    HANDLE hCatInfo,\n    ULONG dwFlags\n    );\n\ntypedef BOOL (WINAPI *_CryptCATAdminReleaseContext)(\n    HANDLE hCatAdmin,\n    ULONG dwFlags\n    );\n\ntypedef PCRYPT_PROVIDER_DATA (WINAPI *_WTHelperProvDataFromStateData)(\n    HANDLE hStateData\n    );\n\ntypedef PCRYPT_PROVIDER_SGNR (WINAPI *_WTHelperGetProvSignerFromChain)(\n    CRYPT_PROVIDER_DATA *pProvData,\n    ULONG idxSigner,\n    BOOL fCounterSigner,\n    ULONG idxCounterSigner\n    );\n\ntypedef LONG (WINAPI *_WinVerifyTrust)(\n    HWND hWnd,\n    GUID *pgActionID,\n    LPVOID pWVTData\n    );\n\ntypedef ULONG (WINAPI *_CertNameToStr)(\n    ULONG dwCertEncodingType,\n    PCERT_NAME_BLOB pName,\n    ULONG dwStrType,\n    LPTSTR psz,\n    ULONG csz\n    );\n\ntypedef PCCERT_CONTEXT (WINAPI *_CertDuplicateCertificateContext)(\n    _In_ PCCERT_CONTEXT pCertContext\n    );\n\ntypedef BOOL (WINAPI *_CertFreeCertificateContext)(\n    _In_ PCCERT_CONTEXT pCertContext\n    );\n\ntypedef BOOL (WINAPI *_CryptUIDlgViewSignerInfo)(\n    _In_ CRYPTUI_VIEWSIGNERINFO_STRUCT *pcvsi\n    );\n\n#endif\n"
  },
  {
    "path": "third_party/phlib/include/workqueue.h",
    "content": "#ifndef _PH_WORKQUEUE_H\n#define _PH_WORKQUEUE_H\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\n#if defined(DEBUG)\nextern PPH_LIST PhDbgWorkQueueList;\nextern PH_QUEUED_LOCK PhDbgWorkQueueListLock;\n#endif\n\ntypedef struct _PH_WORK_QUEUE\n{\n    PH_RUNDOWN_PROTECT RundownProtect;\n    BOOLEAN Terminating;\n\n    LIST_ENTRY QueueListHead;\n    PH_QUEUED_LOCK QueueLock;\n    PH_CONDITION QueueEmptyCondition;\n\n    ULONG MaximumThreads;\n    ULONG MinimumThreads;\n    ULONG NoWorkTimeout;\n\n    PH_QUEUED_LOCK StateLock;\n    HANDLE SemaphoreHandle;\n    ULONG CurrentThreads;\n    ULONG BusyCount;\n} PH_WORK_QUEUE, *PPH_WORK_QUEUE;\n\ntypedef VOID (NTAPI *PPH_WORK_QUEUE_ITEM_DELETE_FUNCTION)(\n    _In_ PUSER_THREAD_START_ROUTINE Function,\n    _In_ PVOID Context\n    );\n\ntypedef struct _PH_WORK_QUEUE_ENVIRONMENT\n{\n    LONG BasePriority : 6; // Base priority increment\n    ULONG IoPriority : 3; // I/O priority hint\n    ULONG PagePriority : 3; // Page/memory priority\n    ULONG ForceUpdate : 1; // Always set priorities regardless of cached values\n    ULONG SpareBits : 19;\n} PH_WORK_QUEUE_ENVIRONMENT, *PPH_WORK_QUEUE_ENVIRONMENT;\n\nPHLIBAPI\nVOID\nNTAPI\nPhInitializeWorkQueue(\n    _Out_ PPH_WORK_QUEUE WorkQueue,\n    _In_ ULONG MinimumThreads,\n    _In_ ULONG MaximumThreads,\n    _In_ ULONG NoWorkTimeout\n    );\n\nPHLIBAPI\nVOID\nNTAPI\nPhDeleteWorkQueue(\n    _Inout_ PPH_WORK_QUEUE WorkQueue\n    );\n\nPHLIBAPI\nVOID\nNTAPI\nPhWaitForWorkQueue(\n    _Inout_ PPH_WORK_QUEUE WorkQueue\n    );\n\nPHLIBAPI\nVOID\nNTAPI\nPhQueueItemWorkQueue(\n    _Inout_ PPH_WORK_QUEUE WorkQueue,\n    _In_ PUSER_THREAD_START_ROUTINE Function,\n    _In_opt_ PVOID Context\n    );\n\nPHLIBAPI\nVOID\nNTAPI\nPhQueueItemWorkQueueEx(\n    _Inout_ PPH_WORK_QUEUE WorkQueue,\n    _In_ PUSER_THREAD_START_ROUTINE Function,\n    _In_opt_ PVOID Context,\n    _In_opt_ PPH_WORK_QUEUE_ITEM_DELETE_FUNCTION DeleteFunction,\n    _In_opt_ PPH_WORK_QUEUE_ENVIRONMENT Environment\n    );\n\nPHLIBAPI\nVOID\nNTAPI\nPhInitializeWorkQueueEnvironment(\n    _Out_ PPH_WORK_QUEUE_ENVIRONMENT Environment\n    );\n\nPHLIBAPI\nPPH_WORK_QUEUE\nNTAPI\nPhGetGlobalWorkQueue(\n    VOID\n    );\n\n#ifdef __cplusplus\n}\n#endif\n\n#endif\n"
  },
  {
    "path": "third_party/phlib/include/workqueuep.h",
    "content": "#ifndef _PH_WORKQUEUEP_H\n#define _PH_WORKQUEUEP_H\n\ntypedef struct _PH_WORK_QUEUE_ITEM\n{\n    LIST_ENTRY ListEntry;\n    PUSER_THREAD_START_ROUTINE Function;\n    PVOID Context;\n    PPH_WORK_QUEUE_ITEM_DELETE_FUNCTION DeleteFunction;\n    PH_WORK_QUEUE_ENVIRONMENT Environment;\n} PH_WORK_QUEUE_ITEM, *PPH_WORK_QUEUE_ITEM;\n\nVOID PhpGetDefaultWorkQueueEnvironment(\n    _Out_ PPH_WORK_QUEUE_ENVIRONMENT Environment\n    );\n\nVOID PhpUpdateWorkQueueEnvironment(\n    _Inout_ PPH_WORK_QUEUE_ENVIRONMENT CurrentEnvironment,\n    _In_ PPH_WORK_QUEUE_ENVIRONMENT NewEnvironment\n    );\n\nPPH_WORK_QUEUE_ITEM PhpCreateWorkQueueItem(\n    _In_ PUSER_THREAD_START_ROUTINE Function,\n    _In_opt_ PVOID Context,\n    _In_opt_ PPH_WORK_QUEUE_ITEM_DELETE_FUNCTION DeleteFunction,\n    _In_opt_ PPH_WORK_QUEUE_ENVIRONMENT Environment\n    );\n\nVOID PhpDestroyWorkQueueItem(\n    _In_ PPH_WORK_QUEUE_ITEM WorkQueueItem\n    );\n\nVOID PhpExecuteWorkQueueItem(\n    _Inout_ PPH_WORK_QUEUE_ITEM WorkQueueItem\n    );\n\nHANDLE PhpGetSemaphoreWorkQueue(\n    _Inout_ PPH_WORK_QUEUE WorkQueue\n    );\n\nBOOLEAN PhpCreateWorkQueueThread(\n    _Inout_ PPH_WORK_QUEUE WorkQueue\n    );\n\nNTSTATUS PhpWorkQueueThreadStart(\n    _In_ PVOID Parameter\n    );\n\n#endif\n"
  },
  {
    "path": "third_party/phlib/json.c",
    "content": "/*\n * Process Hacker -\n *   json wrapper\n *\n * Copyright (C) 2017 dmex\n *\n * This file is part of Process Hacker.\n *\n * Process Hacker is free software; you can redistribute it and/or modify\n * it under the terms of the GNU General Public License as published by\n * the Free Software Foundation, either version 3 of the License, or\n * (at your option) any later version.\n *\n * Process Hacker is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n * GNU General Public License for more details.\n *\n * You should have received a copy of the GNU General Public License\n * along with Process Hacker.  If not, see <http://www.gnu.org/licenses/>.\n */\n\n#include <ph.h>\n#include <phbasesup.h>\n#include <phutil.h>\n\n#include \"jsonc\\json.h\"\n#include <json.h>\n\nstatic json_object_ptr json_get_object(\n    _In_ json_object_ptr rootObj, \n    _In_ const PSTR key\n    )\n{\n    json_object_ptr returnObj;\n\n    if (json_object_object_get_ex(rootObj, key, &returnObj))\n    {\n        return returnObj;\n    }\n\n    return NULL;\n}\n\nPVOID PhCreateJsonParser(\n    _In_ PSTR JsonString\n    )\n{\n    return json_tokener_parse(JsonString);\n}\n\nVOID PhFreeJsonParser(\n    _In_ PVOID Object\n    )\n{\n    json_object_put(Object);\n}\n\nPPH_STRING PhGetJsonValueAsString(\n    _In_ PVOID Object,\n    _In_ PSTR Key\n    )\n{\n    PSTR value;\n\n    if (value = json_object_get_string(json_get_object(Object, Key)))\n        return PhConvertUtf8ToUtf16(value);\n    else\n        return NULL;\n}\n\nINT64 PhGetJsonValueAsLong64(\n    _In_ PVOID Object,\n    _In_ PSTR Key\n    )\n{\n    return json_object_get_int64(json_get_object(Object, Key));\n}\n\nPVOID PhCreateJsonObject(\n    VOID\n    )\n{\n    return json_object_new_object();\n}\n\nPVOID PhGetJsonObject(\n    _In_ PVOID Object,\n    _In_ PSTR Key\n    )\n{\n    return json_get_object(Object, Key);\n}\n\nINT PhGetJsonObjectLength(\n    _In_ PVOID Object\n    )\n{\n    return json_object_object_length(Object);\n}\n\nBOOLEAN PhGetJsonObjectBool(\n    _In_ PVOID Object,\n    _In_ PSTR Key\n    )\n{\n    return json_object_get_boolean(json_get_object(Object, Key)) == TRUE;\n}\n\nVOID PhAddJsonObject(\n    _In_ PVOID Object,\n    _In_ PSTR Key,\n    _In_ PSTR Value\n    )\n{\n    json_object_object_add(Object, Key, json_object_new_string(Value));\n}\n\nPVOID PhCreateJsonArray(\n    VOID\n    )\n{\n    return json_object_new_array();\n}\n\nVOID PhAddJsonArrayObject(\n    _In_ PVOID Object,\n    _In_ PVOID jsonEntry\n    )\n{\n    json_object_array_add(Object, jsonEntry);\n}\n\nPPH_STRING PhGetJsonArrayString(\n    _In_ PVOID Object\n    )\n{\n    PSTR value;\n\n    if (value = json_object_to_json_string(Object))\n        return PhConvertUtf8ToUtf16(value);\n    else\n        return NULL;\n}\n\nINT64 PhGetJsonArrayLong64(\n    _In_ PVOID Object,\n    _In_ INT Index\n    )\n{\n    return json_object_get_int64(json_object_array_get_idx(Object, Index));\n}\n\nINT PhGetJsonArrayLength(\n    _In_ PVOID Object\n    )\n{\n    return json_object_array_length(Object);\n}\n\nPVOID PhGetJsonArrayIndexObject(\n    _In_ PVOID Object,\n    _In_ INT Index\n    )\n{\n    return json_object_array_get_idx(Object, Index);\n}\n\nPPH_LIST PhGetJsonObjectAsArrayList(\n    _In_ PVOID Object\n    )\n{\n    PPH_LIST listArray;\n    json_object_iter json_array_ptr;\n\n    listArray = PhCreateList(1);\n\n    json_object_object_foreachC(Object, json_array_ptr)\n    {\n        PJSON_ARRAY_LIST_OBJECT object;\n        \n        object = PhAllocate(sizeof(JSON_ARRAY_LIST_OBJECT));\n        memset(object, 0, sizeof(JSON_ARRAY_LIST_OBJECT));\n\n        object->Key = json_array_ptr.key;\n        object->Entry = json_array_ptr.val;\n\n        PhAddItemList(listArray, object);\n    }\n\n    return listArray;\n}\n\nPVOID PhLoadJsonObjectFromFile(\n    _In_ PWSTR FileName\n    )\n{\n    return json_object_from_file(FileName);\n}\n\nVOID PhSaveJsonObjectToFile(\n    _In_ PWSTR FileName,\n    _In_ PVOID Object\n    )\n{\n    json_object_to_file(FileName, Object);\n}"
  },
  {
    "path": "third_party/phlib/jsonc/AUTHORS",
    "content": "Michael Clark <michael@metaparadigm.com>\nJehiah Czebotar <jehiah@gmail.com>\nEric Haszlakiewicz <hawicz+json-c@gmail.com>\nC. Watford (christopher.watford@gmail.com)\n\n"
  },
  {
    "path": "third_party/phlib/jsonc/COPYING",
    "content": "\nCopyright (c) 2009-2012 Eric Haszlakiewicz\n\nPermission is hereby granted, free of charge, to any person obtaining a\ncopy of this software and associated documentation files (the \"Software\"),\nto deal in the Software without restriction, including without limitation\nthe rights to use, copy, modify, merge, publish, distribute, sublicense,\nand/or sell copies of the Software, and to permit persons to whom the\nSoftware is furnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included\nin all copies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n\n----------------------------------------------------------------\n\nCopyright (c) 2004, 2005 Metaparadigm Pte Ltd\n\nPermission is hereby granted, free of charge, to any person obtaining a\ncopy of this software and associated documentation files (the \"Software\"),\nto deal in the Software without restriction, including without limitation\nthe rights to use, copy, modify, merge, publish, distribute, sublicense,\nand/or sell copies of the Software, and to permit persons to whom the\nSoftware is furnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included\nin all copies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n"
  },
  {
    "path": "third_party/phlib/jsonc/ChangeLog",
    "content": "\n0.12\n\n  * Address security issues:\n    * CVE-2013-6371: hash collision denial of service\n    * CVE-2013-6370: buffer overflow if size_t is larger than int\n\n  * Avoid potential overflow in json_object_get_double\n\n  * Eliminate the mc_abort() function and MC_ABORT macro.\n\n  * Make the json_tokener_errors array local.  It has been deprecated for\n     a while, and json_tokener_error_desc() should be used instead.\n\n  * change the floating point output format to %.17g so values with \n     more than 6 digits show up in the output.\n\n  * Remove the old libjson.so name compatibility support.  The library is\n      only created as libjson-c.so now and headers are only installed \n      into the ${prefix}/json-c directory.\n\n  * When supported by the linker, add the -Bsymbolic-functions flag.\n\n  * Various changes to fix the build on MSVC.\n\n  * Make strict mode more strict:\n    * number must not start with 0\n    * no single-quote strings\n    * no comments\n    * trailing char not allowed\n    * only allow lowercase literals\n\n  * Added a json_object_new_double_s() convenience function to allow\n    an exact string representation of a double to be specified when\n    creating the object and use it in json_tokener_parse_ex() so\n    a re-serialized object more exactly matches the input.\n\n  * Add support NaN and Infinity\n\n\n0.11\n\n  * IMPORTANT: the name of the library has changed to libjson-c.so and\n     the header files are now in include/json-c.\n     The pkgconfig name has also changed from json to json-c.\n     You should change your build to use appropriate -I and -l options.\n     A compatibility shim is in place so builds using the old name will\n     continue to work, but that will be removed in the next release.\n  * Maximum recursion depth is now a runtime option.\n     json_tokener_new() is provided for compatibility.\n     json_tokener_new_ex(depth)\n  * Include json_object_iterator.h in the installed headers.\n  * Add support for building on Android.\n  * Rewrite json_object_object_add to replace just the value if the key already exists so keys remain valid.\n  * Make it safe to delete keys while iterating with the json_object_object_foreach macro.\n  * Add a json_set_serializer() function to allow the string output of a json_object to be customized.\n  * Make float parsing locale independent.\n  * Add a json_tokener_set_flags() function and a JSON_TOKENER_STRICT flag.\n  * Enable -Werror when building.\n  * speed improvements to parsing 64-bit integers on systems with working sscanf\n  * Add a json_object_object_length function.\n  * Fix a bug (buffer overrun) when expanding arrays to more than 64 entries.\n\n0.10\n\n  * Add a json_object_to_json_string_ext() function to allow output to be\n     formatted in a more human readable form.\n  * Add json_object_object_get_ex(), a NULL-safe get object method, to be able\n     to distinguish between a key not present and the value being NULL.\n  * Add an alternative iterator implementation, see json_object_iterator.h\n  * Make json_object_iter public to enable external use of the\n     json_object_object_foreachC macro.\n  * Add a printbuf_memset() function to provide an effecient way to set and\n     append things like whitespace indentation.\n  * Adjust json_object_is_type and json_object_get_type so they return\n      json_type_null for NULL objects and handle NULL passed to\n      json_objct_object_get().\n  * Rename boolean type to json_bool.\n  * Fix various compile issues for Visual Studio and MinGW.\n  * Allow json_tokener_parse_ex() to be re-used to parse multiple object.\n     Also, fix some parsing issues with capitalized hexadecimal numbers and\n     number in E notation.\n  * Add json_tokener_get_error() and json_tokener_error_desc() to better \n     encapsulate the process of retrieving errors while parsing.\n  * Various improvements to the documentation of many functions.\n  * Add new json_object_array_sort() function.\n  * Fix a bug in json_object_get_int(), which would incorrectly return 0\n    when called on a string type object.\n    Eric Haszlakiewicz\n  * Add a json_type_to_name() function.\n    Eric Haszlakiewicz\n  * Add a json_tokener_parse_verbose() function.\n    Jehiah Czebotar\n  * Improve support for null bytes within JSON strings.\n    Jehiah Czebotar\n  * Fix file descriptor leak if memory allocation fails in json_util\n    Zachary Blair, zack_blair at hotmail dot com\n  * Add int64 support. Two new functions json_object_net_int64 and\n    json_object_get_int64. Binary compatibility preserved.\n    Eric Haszlakiewicz, EHASZLA at transunion com\n    Rui Miguel Silva Seabra, rms at 1407 dot org\n  * Fix subtle bug in linkhash where lookup could hang after all slots\n    were filled then successively freed.\n    Spotted by Jean-Marc Naud, j dash m at newtraxtech dot com\n  * Make json_object_from_file take const char *filename\n    Spotted by Vikram Raj V, vsagar at attinteractive dot com\n  * Add handling of surrogate pairs (json_tokener.c, test4.c, Makefile.am)\n    Brent Miller, bdmiller at yahoo dash inc dot com\n  * Correction to comment describing printbuf_memappend in printbuf.h\n    Brent Miller, bdmiller at yahoo dash inc dot com\n\n0.9\n  * Add README.html README-WIN32.html config.h.win32 to Makefile.am\n    Michael Clark, <michael@metaparadigm.com>\n  * Add const qualifier to the json_tokener_parse functions\n    Eric Haszlakiewicz, EHASZLA at transunion dot com\n  * Rename min and max so we can never clash with C or C++ std library\n    Ian Atha, thatha at yahoo dash inc dot com\n  * Fix any noticeable spelling or grammar errors.\n  * Make sure every va_start has a va_end.\n  * Check all pointers for validity.\n    Erik Hovland, erik at hovland dot org\n  * Fix json_object_get_boolean to return false for empty string\n    Spotted by Vitaly Kruglikov, Vitaly dot Kruglikov at palm dot com\n  * optimizations to json_tokener_parse_ex(), printbuf_memappend()\n    Brent Miller, bdmiller at yahoo dash inc dot com\n  * Disable REFCOUNT_DEBUG by default in json_object.c\n  * Don't use this as a variable, so we can compile with a C++ compiler\n  * Add casts from void* to type of assignment when using malloc \n  * Add #ifdef __cplusplus guards to all of the headers\n  * Add typedefs for json_object, json_tokener, array_list, printbuf, lh_table\n    Michael Clark, <michael@metaparadigm.com>\n  * Null pointer dereference fix. Fix json_object_get_boolean strlen test\n    to not return TRUE for zero length string. Remove redundant includes.\n    Erik Hovland, erik at hovland dot org\n  * Fixed warning reported by adding -Wstrict-prototypes\n    -Wold-style-definition to the compilatin flags.\n    Dotan Barak, dotanba at gmail dot com\n  * Add const correctness to public interfaces\n    Gerard Krol, g dot c dot krol at student dot tudelft dot nl\n\n0.8\n  * Add va_end for every va_start\n    Dotan Barak, dotanba at gmail dot com\n  * Add macros to enable compiling out debug code\n    Geoffrey Young, geoff at modperlcookbook dot org\n  * Fix bug with use of capital E in numbers with exponents\n    Mateusz Loskot, mateusz at loskot dot net\n  * Add stddef.h include\n  * Patch allows for json-c compile with -Werror and not fail due to\n    -Wmissing-prototypes -Wstrict-prototypes -Wmissing-declarations\n    Geoffrey Young, geoff at modperlcookbook dot org\n\n0.7\n  * Add escaping of backslash to json output\n  * Add escaping of foward slash on tokenizing and output\n  * Changes to internal tokenizer from using recursion to\n    using a depth state structure to allow incremental parsing\n\n0.6\n  * Fix bug in escaping of control characters\n    Johan Bjrklund, johbjo09 at kth dot se\n  * Remove include \"config.h\" from headers (should only\n    be included from .c files)\n    Michael Clark <michael@metaparadigm.com>\n\n0.5\n  * Make headers C++ compatible by change *this to *obj\n  * Add ifdef C++ extern \"C\" to headers\n  * Use simpler definition of min and max in bits.h\n    Larry Lansing, llansing at fuzzynerd dot com\n\n  * Remove automake 1.6 requirement\n  * Move autogen commands into autogen.sh. Update README\n  * Remove error pointer special case for Windows\n  * Change license from LGPL to MIT\n    Michael Clark <michael@metaparadigm.com>\n\n0.4\n  * Fix additional error case in object parsing\n  * Add back sign reversal in nested object parse as error pointer\n    value is negative, while error value is positive.\n    Michael Clark <michael@metaparadigm.com>\n\n0.3\n  * fix pointer arithmetic bug for error pointer check in is_error() macro\n  * fix type passed to printbuf_memappend in json_tokener\n  * update autotools bootstrap instructions in README\n    Michael Clark <michael@metaparadigm.com>\n\n0.2\n  * printbuf.c - C. Watford (christopher.watford@gmail.com)\n    Added a Win32/Win64 compliant implementation of vasprintf\n  * debug.c - C. Watford (christopher.watford@gmail.com)\n    Removed usage of vsyslog on Win32/Win64 systems, needs to be handled\n    by a configure script\n  * json_object.c - C. Watford (christopher.watford@gmail.com)\n    Added scope operator to wrap usage of json_object_object_foreach, this\n    needs to be rethought to be more ANSI C friendly\n  * json_object.h - C. Watford (christopher.watford@gmail.com)\n    Added Microsoft C friendly version of json_object_object_foreach\n  * json_tokener.c - C. Watford (christopher.watford@gmail.com)\n    Added a Win32/Win64 compliant implementation of strndup\n  * json_util.c - C. Watford (christopher.watford@gmail.com)\n    Added cast and mask to suffice size_t v. unsigned int conversion\n    correctness \n  * json_tokener.c - sign reversal issue on error info for nested object parse\n    spotted by Johan Bjrklund (johbjo09 at kth.se)\n  * json_object.c - escape \" in json_escape_str\n  * Change to automake and libtool to build shared and static library\n    Michael Clark <michael@metaparadigm.com>\n\t\n0.1\n  * initial release\n"
  },
  {
    "path": "third_party/phlib/jsonc/arraylist.c",
    "content": "/*\n * $Id: arraylist.c,v 1.4 2006/01/26 02:16:28 mclark Exp $\n *\n * Copyright (c) 2004, 2005 Metaparadigm Pte. Ltd.\n * Michael Clark <michael@metaparadigm.com>\n *\n * This library is free software; you can redistribute it and/or modify\n * it under the terms of the MIT license. See COPYING for details.\n *\n */\n\n#include \"config.h\"\n\n#ifdef STDC_HEADERS\n# include <stdlib.h>\n# include <string.h>\n#endif /* STDC_HEADERS */\n\n#if defined(HAVE_STRINGS_H) && !defined(_STRING_H) && !defined(__USE_BSD)\n# include <strings.h>\n#endif /* HAVE_STRINGS_H */\n\n#include \"bits.h\"\n#include \"arraylist.h\"\n\nstruct array_list*\narray_list_new(array_list_free_fn *free_fn)\n{\n  struct array_list *arr;\n\n  arr = (struct array_list*)calloc(1, sizeof(struct array_list));\n  if(!arr) return NULL;\n  arr->size = ARRAY_LIST_DEFAULT_SIZE;\n  arr->length = 0;\n  arr->free_fn = free_fn;\n  if(!(arr->array = (void**)calloc(sizeof(void*), arr->size))) {\n    free(arr);\n    return NULL;\n  }\n  return arr;\n}\n\nextern void\narray_list_free(struct array_list *arr)\n{\n  int i;\n  for(i = 0; i < arr->length; i++)\n    if(arr->array[i]) arr->free_fn(arr->array[i]);\n  free(arr->array);\n  free(arr);\n}\n\nvoid*\narray_list_get_idx(struct array_list *arr, int i)\n{\n  if(i >= arr->length) return NULL;\n  return arr->array[i];\n}\n\nstatic int array_list_expand_internal(struct array_list *arr, int max)\n{\n  void *t;\n  int new_size;\n\n  if(max < arr->size) return 0;\n  new_size = json_max(arr->size << 1, max);\n  if(!(t = realloc(arr->array, new_size*sizeof(void*)))) return -1;\n  arr->array = (void**)t;\n  (void)memset(arr->array + arr->size, 0, (new_size-arr->size)*sizeof(void*));\n  arr->size = new_size;\n  return 0;\n}\n\nint\narray_list_put_idx(struct array_list *arr, int idx, void *data)\n{\n  if(array_list_expand_internal(arr, idx+1)) return -1;\n  if(arr->array[idx]) arr->free_fn(arr->array[idx]);\n  arr->array[idx] = data;\n  if(arr->length <= idx) arr->length = idx + 1;\n  return 0;\n}\n\nint\narray_list_add(struct array_list *arr, void *data)\n{\n  return array_list_put_idx(arr, arr->length, data);\n}\n\nvoid\narray_list_sort(struct array_list *arr, int(__cdecl* sort_fn)(const void *, const void *))\n{\n  qsort(arr->array, arr->length, sizeof(arr->array[0]),\n    (int (__cdecl*)(const void *, const void *))sort_fn);\n}\n\nint\narray_list_length(struct array_list *arr)\n{\n  return arr->length;\n}\n"
  },
  {
    "path": "third_party/phlib/jsonc/arraylist.h",
    "content": "/*\n * $Id: arraylist.h,v 1.4 2006/01/26 02:16:28 mclark Exp $\n *\n * Copyright (c) 2004, 2005 Metaparadigm Pte. Ltd.\n * Michael Clark <michael@metaparadigm.com>\n *\n * This library is free software; you can redistribute it and/or modify\n * it under the terms of the MIT license. See COPYING for details.\n *\n */\n\n#ifndef _arraylist_h_\n#define _arraylist_h_\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\n#define ARRAY_LIST_DEFAULT_SIZE 32\n\ntypedef void (array_list_free_fn) (void *data);\n\nstruct array_list\n{\n  void **array;\n  int length;\n  int size;\n  array_list_free_fn *free_fn;\n};\n\nextern struct array_list*\narray_list_new(array_list_free_fn *free_fn);\n\nextern void\narray_list_free(struct array_list *al);\n\nextern void*\narray_list_get_idx(struct array_list *al, int i);\n\nextern int\narray_list_put_idx(struct array_list *al, int i, void *data);\n\nextern int\narray_list_add(struct array_list *al, void *data);\n\nextern int\narray_list_length(struct array_list *al);\n\nextern void\narray_list_sort(struct array_list *arr, int(__cdecl* compar)(const void *, const void *));\n\n#ifdef __cplusplus\n}\n#endif\n\n#endif\n"
  },
  {
    "path": "third_party/phlib/jsonc/bits.h",
    "content": "/*\n * $Id: bits.h,v 1.10 2006/01/30 23:07:57 mclark Exp $\n *\n * Copyright (c) 2004, 2005 Metaparadigm Pte. Ltd.\n * Michael Clark <michael@metaparadigm.com>\n *\n * This library is free software; you can redistribute it and/or modify\n * it under the terms of the MIT license. See COPYING for details.\n *\n */\n\n#ifndef _bits_h_\n#define _bits_h_\n\n#ifndef json_min\n#define json_min(a,b) ((a) < (b) ? (a) : (b))\n#endif\n\n#ifndef json_max\n#define json_max(a,b) ((a) > (b) ? (a) : (b))\n#endif\n\n#define hexdigit(x) (((x) <= '9') ? (x) - '0' : ((x) & 7) + 9)\n#define error_ptr(error) ((void*)error)\n#define error_description(error)  (json_tokener_errors[error])\n#define is_error(ptr) (ptr == NULL)\n\n#endif\n"
  },
  {
    "path": "third_party/phlib/jsonc/config.h",
    "content": "#define PACKAGE_STRING \"JSON C Library 0.12-20140410\"\n#define PACKAGE_BUGREPORT \"json-c@googlegroups.com\"\n#define PACKAGE_NAME \"JSON C Library\"\n#define PACKAGE_TARNAME \"json-c\"\n#define PACKAGE_VERSION \"0.12-20140410\"\n\n\n#define HAVE_SETLOCALE 1\n#define HAVE_LOCALE_H 1\n\n#define HAVE_DECL_NAN 1 \n#define HAVE_DECL_INFINITY 1\n//#define HAVE_DECL__ISNAN 1\n//#define HAVE_DECL__FINITE 1\n\n/* Define to 1 if you don't have `vprintf' but do have `_doprnt.' */\n/* #undef HAVE_DOPRNT */\n\n/* Define to 1 if you have the <fcntl.h> header file. */\n#define HAVE_FCNTL_H 1\n\n/* Define to 1 if you have the <inttypes.h> header file. */\n#define HAVE_INTTYPES_H 1\n\n/* Define to 1 if you have the <limits.h> header file. */\n#define HAVE_LIMITS_H 1\n\n/* Define to 1 if your system has a GNU libc compatible `malloc' function, and\n   to 0 otherwise. */\n#define HAVE_MALLOC 1\n\n/* Define to 1 if you have the <memory.h> header file. */\n#define HAVE_MEMORY_H 1\n\n/* Define to 1 if you have the `open' function. */\n#define HAVE_OPEN 1\n\n/* Define to 1 if your system has a GNU libc compatible `realloc' function,\n   and to 0 otherwise. */\n#define HAVE_REALLOC 1\n\n/* Define to 1 if you have the <stdint.h> header file. */\n#define HAVE_STDINT_H 1\n\n/* Define to 1 if you have the <stdlib.h> header file. */\n#define HAVE_STDLIB_H 1\n\n/* Define to 1 if you have the `strdup' function. */\n#define HAVE_STRNDUP 1\n\n/* Define to 1 if you have the <stdarg.h> header file. */\n#define HAVE_STDARG_H 1\n\n/* Define to 1 if you have the `strerror' function. */\n#define HAVE_STRERROR 1\n\n/* Define to 1 if you have the <strings.h> header file. */\n#undef HAVE_STRINGS_H\n\n/* Define to 1 if you have the <string.h> header file. */\n#define HAVE_STRING_H 1\n\n/* Define to 1 if you have the <syslog.h> header file. */\n#undef HAVE_SYSLOG_H\n\n/* Define to 1 if you have the <sys/param.h> header file. */\n#undef HAVE_SYS_PARAM_H\n\n/* Define to 1 if you have the <sys/stat.h> header file. */\n#define HAVE_SYS_STAT_H 1\n\n/* Define to 1 if you have the <sys/types.h> header file. */\n#define HAVE_SYS_TYPES_H 1\n\n/* Define to 1 if you have the <unistd.h> header file. */\n#undef HAVE_UNISTD_H\n\n/* Define to 1 if you have the `vprintf' function. */\n#undef HAVE_VPRINTF\n\n/* Define to 1 if you have the `vsyslog' function. */\n#undef HAVE_VSYSLOG\n\n/* Define to 1 if you have the `strncasecmp' function. */\n#undef HAVE_STRNCASECMP\n\n/* Define to 1 if you have the ANSI C header files. */\n#define STDC_HEADERS 1\n\n"
  },
  {
    "path": "third_party/phlib/jsonc/config.h.in",
    "content": "/* config.h.in.  Generated from configure.ac by autoheader.  */\n\n/* Enable RDRANR Hardware RNG Hash Seed */\n#undef ENABLE_RDRAND\n\n/* Define if .gnu.warning accepts long strings. */\n#undef HAS_GNU_WARNING_LONG\n\n/* Define to 1 if you have the declaration of `INFINITY', and to 0 if you\n   don't. */\n#undef HAVE_DECL_INFINITY\n\n/* Define to 1 if you have the declaration of `isinf', and to 0 if you don't.\n   */\n#undef HAVE_DECL_ISINF\n\n/* Define to 1 if you have the declaration of `isnan', and to 0 if you don't.\n   */\n#undef HAVE_DECL_ISNAN\n\n/* Define to 1 if you have the declaration of `nan', and to 0 if you don't. */\n#undef HAVE_DECL_NAN\n\n/* Define to 1 if you have the declaration of `_finite', and to 0 if you\n   don't. */\n#undef HAVE_DECL__FINITE\n\n/* Define to 1 if you have the declaration of `_isnan', and to 0 if you don't.\n   */\n#undef HAVE_DECL__ISNAN\n\n/* Define to 1 if you have the <dlfcn.h> header file. */\n#undef HAVE_DLFCN_H\n\n/* Define to 1 if you don't have `vprintf' but do have `_doprnt.' */\n#undef HAVE_DOPRNT\n\n/* Define to 1 if you have the <endian.h> header file. */\n#undef HAVE_ENDIAN_H\n\n/* Define to 1 if you have the <fcntl.h> header file. */\n#undef HAVE_FCNTL_H\n\n/* Define to 1 if you have the <inttypes.h> header file. */\n#undef HAVE_INTTYPES_H\n\n/* Define to 1 if you have the <limits.h> header file. */\n#undef HAVE_LIMITS_H\n\n/* Define to 1 if you have the <locale.h> header file. */\n#undef HAVE_LOCALE_H\n\n/* Define to 1 if your system has a GNU libc compatible `malloc' function, and\n   to 0 otherwise. */\n#undef HAVE_MALLOC\n\n/* Define to 1 if you have the <memory.h> header file. */\n#undef HAVE_MEMORY_H\n\n/* Define to 1 if you have the `open' function. */\n#undef HAVE_OPEN\n\n/* Define to 1 if your system has a GNU libc compatible `realloc' function,\n   and to 0 otherwise. */\n#undef HAVE_REALLOC\n\n/* Define to 1 if you have the `setlocale' function. */\n#undef HAVE_SETLOCALE\n\n/* Define to 1 if you have the `snprintf' function. */\n#undef HAVE_SNPRINTF\n\n/* Define to 1 if you have the <stdarg.h> header file. */\n#undef HAVE_STDARG_H\n\n/* Define to 1 if you have the <stdint.h> header file. */\n#undef HAVE_STDINT_H\n\n/* Define to 1 if you have the <stdlib.h> header file. */\n#undef HAVE_STDLIB_H\n\n/* Define to 1 if you have the `strcasecmp' function. */\n#undef HAVE_STRCASECMP\n\n/* Define to 1 if you have the `strdup' function. */\n#undef HAVE_STRDUP\n\n/* Define to 1 if you have the `strerror' function. */\n#undef HAVE_STRERROR\n\n/* Define to 1 if you have the <strings.h> header file. */\n#undef HAVE_STRINGS_H\n\n/* Define to 1 if you have the <string.h> header file. */\n#undef HAVE_STRING_H\n\n/* Define to 1 if you have the `strncasecmp' function. */\n#undef HAVE_STRNCASECMP\n\n/* Define to 1 if you have the <syslog.h> header file. */\n#undef HAVE_SYSLOG_H\n\n/* Define to 1 if you have the <sys/cdefs.h> header file. */\n#undef HAVE_SYS_CDEFS_H\n\n/* Define to 1 if you have the <sys/param.h> header file. */\n#undef HAVE_SYS_PARAM_H\n\n/* Define to 1 if you have the <sys/stat.h> header file. */\n#undef HAVE_SYS_STAT_H\n\n/* Define to 1 if you have the <sys/types.h> header file. */\n#undef HAVE_SYS_TYPES_H\n\n/* Define to 1 if you have the <unistd.h> header file. */\n#undef HAVE_UNISTD_H\n\n/* Define to 1 if you have the `vasprintf' function. */\n#undef HAVE_VASPRINTF\n\n/* Define to 1 if you have the `vprintf' function. */\n#undef HAVE_VPRINTF\n\n/* Define to 1 if you have the `vsnprintf' function. */\n#undef HAVE_VSNPRINTF\n\n/* Define to 1 if you have the `vsyslog' function. */\n#undef HAVE_VSYSLOG\n\n/* Public define for json_inttypes.h */\n#undef JSON_C_HAVE_INTTYPES_H\n\n/* Define to the sub-directory in which libtool stores uninstalled libraries.\n   */\n#undef LT_OBJDIR\n\n/* Name of package */\n#undef PACKAGE\n\n/* Define to the address where bug reports for this package should be sent. */\n#undef PACKAGE_BUGREPORT\n\n/* Define to the full name of this package. */\n#undef PACKAGE_NAME\n\n/* Define to the full name and version of this package. */\n#undef PACKAGE_STRING\n\n/* Define to the one symbol short name of this package. */\n#undef PACKAGE_TARNAME\n\n/* Define to the home page for this package. */\n#undef PACKAGE_URL\n\n/* Define to the version of this package. */\n#undef PACKAGE_VERSION\n\n/* Define to 1 if you have the ANSI C header files. */\n#undef STDC_HEADERS\n\n/* Version number of package */\n#undef VERSION\n\n/* Define to empty if `const' does not conform to ANSI C. */\n#undef const\n\n/* Define to rpl_malloc if the replacement function should be used. */\n#undef malloc\n\n/* Define to rpl_realloc if the replacement function should be used. */\n#undef realloc\n\n/* Define to `unsigned int' if <sys/types.h> does not define. */\n#undef size_t\n"
  },
  {
    "path": "third_party/phlib/jsonc/debug.c",
    "content": "/*\n * $Id: debug.c,v 1.5 2006/01/26 02:16:28 mclark Exp $\n *\n * Copyright (c) 2004, 2005 Metaparadigm Pte. Ltd.\n * Michael Clark <michael@metaparadigm.com>\n *\n * This library is free software; you can redistribute it and/or modify\n * it under the terms of the MIT license. See COPYING for details.\n *\n */\n\n#include \"config.h\"\n\n#include <stdio.h>\n#include <stdlib.h>\n#include <string.h>\n#include <stdarg.h>\n\n#if HAVE_SYSLOG_H\n# include <syslog.h>\n#endif /* HAVE_SYSLOG_H */\n\n#if HAVE_UNISTD_H\n# include <unistd.h>\n#endif /* HAVE_UNISTD_H */\n\n#if HAVE_SYS_PARAM_H\n#include <sys/param.h>\n#endif /* HAVE_SYS_PARAM_H */\n\n#include \"debug.h\"\n\nstatic int _syslog = 0;\nstatic int _debug = 0;\n\nvoid mc_set_debug(int debug) { _debug = debug; }\nint mc_get_debug(void) { return _debug; }\n\nextern void mc_set_syslog(int syslog)\n{\n  _syslog = syslog;\n}\n\nvoid mc_debug(const char *msg, ...)\n{\n  va_list ap;\n  if(_debug) {\n    va_start(ap, msg);\n#if HAVE_VSYSLOG\n    if(_syslog) {\n        vsyslog(LOG_DEBUG, msg, ap);\n    } else\n#endif\n        vprintf(msg, ap);\n    va_end(ap);\n  }\n}\n\nvoid mc_error(const char *msg, ...)\n{\n  va_list ap;\n  va_start(ap, msg);\n#if HAVE_VSYSLOG\n    if(_syslog) {\n        vsyslog(LOG_ERR, msg, ap);\n    } else\n#endif\n        vfprintf(stderr, msg, ap);\n  va_end(ap);\n}\n\nvoid mc_info(const char *msg, ...)\n{\n  va_list ap;\n  va_start(ap, msg);\n#if HAVE_VSYSLOG\n    if(_syslog) {\n        vsyslog(LOG_INFO, msg, ap);\n    } else \n#endif\n        vfprintf(stderr, msg, ap);\n  va_end(ap);\n}\n"
  },
  {
    "path": "third_party/phlib/jsonc/debug.h",
    "content": "/*\n * $Id: debug.h,v 1.5 2006/01/30 23:07:57 mclark Exp $\n *\n * Copyright (c) 2004, 2005 Metaparadigm Pte. Ltd.\n * Michael Clark <michael@metaparadigm.com>\n * Copyright (c) 2009 Hewlett-Packard Development Company, L.P.\n *\n * This library is free software; you can redistribute it and/or modify\n * it under the terms of the MIT license. See COPYING for details.\n *\n */\n\n#ifndef _DEBUG_H_\n#define _DEBUG_H_\n\n#include <stdlib.h>\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\nextern void mc_set_debug(int debug);\nextern int mc_get_debug(void);\n\nextern void mc_set_syslog(int syslog);\n\nextern void mc_debug(const char *msg, ...);\nextern void mc_error(const char *msg, ...);\nextern void mc_info(const char *msg, ...);\n\n#ifndef __STRING\n#define __STRING(x) #x\n#endif\n\n#ifndef PARSER_BROKEN_FIXED\n\n#define JASSERT(cond) do {} while(0)\n\n#else\n\n#define JASSERT(cond) do { \\\n\t\tif (!(cond)) { \\\n\t\t\tmc_error(\"cjson assert failure %s:%d : cond \\\"\" __STRING(cond) \"failed\\n\", __FILE__, __LINE__); \\\n\t\t\t*(int *)0 = 1;\\\n\t\t\tabort(); \\\n\t\t}\\\n\t} while(0)\n\n#endif\n\n#define MC_ERROR(x, ...) mc_error(x, ##__VA_ARGS__)\n\n#ifdef MC_MAINTAINER_MODE\n#define MC_SET_DEBUG(x) mc_set_debug(x)\n#define MC_GET_DEBUG() mc_get_debug()\n#define MC_SET_SYSLOG(x) mc_set_syslog(x)\n#define MC_DEBUG(x, ...) mc_debug(x, ##__VA_ARGS__)\n#define MC_INFO(x, ...) mc_info(x, ##__VA_ARGS__)\n#else\n#define MC_SET_DEBUG(x) if (0) mc_set_debug(x)\n#define MC_GET_DEBUG() (0)\n#define MC_SET_SYSLOG(x) if (0) mc_set_syslog(x)\n#define MC_DEBUG(x, ...) if (0) mc_debug(x, ##__VA_ARGS__)\n#define MC_INFO(x, ...) if (0) mc_info(x, ##__VA_ARGS__)\n#endif\n\n#ifdef __cplusplus\n}\n#endif\n\n#endif\n"
  },
  {
    "path": "third_party/phlib/jsonc/json.h",
    "content": "/*\n * $Id: json.h,v 1.6 2006/01/26 02:16:28 mclark Exp $\n *\n * Copyright (c) 2004, 2005 Metaparadigm Pte. Ltd.\n * Michael Clark <michael@metaparadigm.com>\n * Copyright (c) 2009 Hewlett-Packard Development Company, L.P.\n *\n * This library is free software; you can redistribute it and/or modify\n * it under the terms of the MIT license. See COPYING for details.\n *\n */\n\n#ifndef _json_h_\n#define _json_h_\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\n#include \"bits.h\"\n#include \"debug.h\"\n#include \"linkhash.h\"\n#include \"arraylist.h\"\n#include \"json_util.h\"\n#include \"json_object.h\"\n#include \"json_tokener.h\"\n#include \"json_object_iterator.h\"\n#include \"json_c_version.h\"\n\n#ifdef __cplusplus\n}\n#endif\n\n#endif\n"
  },
  {
    "path": "third_party/phlib/jsonc/json_c_version.c",
    "content": "/*\n * Copyright (c) 2012 Eric Haszlakiewicz\n *\n * This library is free software; you can redistribute it and/or modify\n * it under the terms of the MIT license. See COPYING for details.\n */\n#include \"config.h\"\n\n#include \"json_c_version.h\"\n\nconst char *json_c_version(void)\n{\n\treturn JSON_C_VERSION;\n}\n\nint json_c_version_num(void)\n{\n\treturn JSON_C_VERSION_NUM;\n}\n\n"
  },
  {
    "path": "third_party/phlib/jsonc/json_c_version.h",
    "content": "/*\n * Copyright (c) 2012 Eric Haszlakiewicz\n *\n * This library is free software; you can redistribute it and/or modify\n * it under the terms of the MIT license. See COPYING for details.\n */\n\n#ifndef _json_c_version_h_\n#define _json_c_version_h_\n\n#define JSON_C_MAJOR_VERSION 0\n#define JSON_C_MINOR_VERSION 12\n#define JSON_C_MICRO_VERSION 0\n#define JSON_C_VERSION_NUM ((JSON_C_MAJOR_VERSION << 16) | \\\n                            (JSON_C_MINOR_VERSION << 8) | \\\n                            JSON_C_MICRO_VERSION)\n#define JSON_C_VERSION \"0.12\"\n\nconst char *json_c_version(void); /* Returns JSON_C_VERSION */\nint json_c_version_num(void);     /* Returns JSON_C_VERSION_NUM */\n\n#endif\n"
  },
  {
    "path": "third_party/phlib/jsonc/json_config.h",
    "content": "\n/* Define to 1 if you have the <inttypes.h> header file. */\n#define JSON_C_HAVE_INTTYPES_H 1\n"
  },
  {
    "path": "third_party/phlib/jsonc/json_inttypes.h",
    "content": "\n#ifndef _json_inttypes_h_\n#define _json_inttypes_h_\n\n#include \"json_config.h\"\n\n#if defined(_MSC_VER) && _MSC_VER <= 1700\n\n/* Anything less than Visual Studio C++ 10 is missing stdint.h and inttypes.h */\ntypedef __int32 int32_t;\n#define INT32_MIN    ((int32_t)_I32_MIN)\n#define INT32_MAX    ((int32_t)_I32_MAX)\ntypedef __int64 int64_t;\n#define INT64_MIN    ((int64_t)_I64_MIN)\n#define INT64_MAX    ((int64_t)_I64_MAX)\n#define PRId64 \"I64d\"\n#define SCNd64 \"I64d\"\n\n#else\n\n#ifdef JSON_C_HAVE_INTTYPES_H\n#include <inttypes.h>\n#endif\n/* inttypes.h includes stdint.h */\n\n#endif\n\n#endif\n"
  },
  {
    "path": "third_party/phlib/jsonc/json_object.c",
    "content": "/*\n * $Id: json_object.c,v 1.17 2006/07/25 03:24:50 mclark Exp $\n *\n * Copyright (c) 2004, 2005 Metaparadigm Pte. Ltd.\n * Michael Clark <michael@metaparadigm.com>\n * Copyright (c) 2009 Hewlett-Packard Development Company, L.P.\n *\n * This library is free software; you can redistribute it and/or modify\n * it under the terms of the MIT license. See COPYING for details.\n *\n */\n\n#include \"config.h\"\n\n#include <stdio.h>\n#include <stdlib.h>\n#include <stddef.h>\n#include <string.h>\n#include <math.h>\n#include <errno.h>\n\n#include \"debug.h\"\n#include \"printbuf.h\"\n#include \"linkhash.h\"\n#include \"arraylist.h\"\n#include \"json_inttypes.h\"\n#include \"json_object.h\"\n#include \"json_object_private.h\"\n#include \"json_util.h\"\n#include \"math_compat.h\"\n\n#if !defined(HAVE_STRDUP) && defined(_MSC_VER)\n  /* MSC has the version as _strdup */\n# define strdup _strdup\n#elif !defined(HAVE_STRDUP)\n# error You do not have strdup on your system.\n#endif /* HAVE_STRDUP */\n\n#if !defined(HAVE_SNPRINTF) && defined(_MSC_VER)\n  /* MSC has the version as _snprintf */\n# define snprintf _snprintf\n#elif !defined(HAVE_SNPRINTF)\n# error You do not have snprintf on your system.\n#endif /* HAVE_SNPRINTF */\n\n// Don't define this.  It's not thread-safe.\n/* #define REFCOUNT_DEBUG 1 */\n\nconst char *json_number_chars = \"0123456789.+-eE\";\nconst char *json_hex_chars = \"0123456789abcdefABCDEF\";\n\nstatic void json_object_generic_delete(struct json_object* jso);\nstatic struct json_object* json_object_new(enum json_type o_type);\n\nstatic json_object_to_json_string_fn json_object_object_to_json_string;\nstatic json_object_to_json_string_fn json_object_boolean_to_json_string;\nstatic json_object_to_json_string_fn json_object_int_to_json_string;\nstatic json_object_to_json_string_fn json_object_double_to_json_string;\nstatic json_object_to_json_string_fn json_object_string_to_json_string;\nstatic json_object_to_json_string_fn json_object_array_to_json_string;\n\n\n/* ref count debugging */\n\n#ifdef REFCOUNT_DEBUG\n\nstatic struct lh_table *json_object_table;\n\nstatic void json_object_init(void) __attribute__ ((constructor));\nstatic void json_object_init(void) {\n  MC_DEBUG(\"json_object_init: creating object table\\n\");\n  json_object_table = lh_kptr_table_new(128, \"json_object_table\", NULL);\n}\n\nstatic void json_object_fini(void) __attribute__ ((destructor));\nstatic void json_object_fini(void) {\n  struct lh_entry *ent;\n  if(MC_GET_DEBUG()) {\n    if (json_object_table->count) {\n      MC_DEBUG(\"json_object_fini: %d referenced objects at exit\\n\",\n           json_object_table->count);\n      lh_foreach(json_object_table, ent) {\n        struct json_object* obj = (struct json_object*)ent->v;\n        MC_DEBUG(\"\\t%s:%p\\n\", json_type_to_name(obj->o_type), obj);\n      }\n    }\n  }\n  MC_DEBUG(\"json_object_fini: freeing object table\\n\");\n  lh_table_free(json_object_table);\n}\n#endif /* REFCOUNT_DEBUG */\n\n\n/* string escaping */\n\nstatic int json_escape_str(struct printbuf *pb, char *str, size_t len)\n{\n  int pos = 0, start_offset = 0;\n  unsigned char c;\n  while (len--) {\n    c = str[pos];\n    switch(c) {\n    case '\\b':\n    case '\\n':\n    case '\\r':\n    case '\\t':\n    case '\\f':\n    case '\"':\n    case '\\\\':\n    case '/':\n      if(pos - start_offset > 0)\n    printbuf_memappend(pb, str + start_offset, pos - start_offset);\n      if(c == '\\b') printbuf_memappend(pb, \"\\\\b\", 2);\n      else if(c == '\\n') printbuf_memappend(pb, \"\\\\n\", 2);\n      else if(c == '\\r') printbuf_memappend(pb, \"\\\\r\", 2);\n      else if(c == '\\t') printbuf_memappend(pb, \"\\\\t\", 2);\n      else if(c == '\\f') printbuf_memappend(pb, \"\\\\f\", 2);\n      else if(c == '\"') printbuf_memappend(pb, \"\\\\\\\"\", 2);\n      else if(c == '\\\\') printbuf_memappend(pb, \"\\\\\\\\\", 2);\n      else if(c == '/') printbuf_memappend(pb, \"\\\\/\", 2);\n      start_offset = ++pos;\n      break;\n    default:\n      if(c < ' ') {\n    if(pos - start_offset > 0)\n      printbuf_memappend(pb, str + start_offset, pos - start_offset);\n    sprintbuf(pb, \"\\\\u00%c%c\",\n          json_hex_chars[c >> 4],\n          json_hex_chars[c & 0xf]);\n    start_offset = ++pos;\n      } else pos++;\n    }\n  }\n  if(pos - start_offset > 0)\n    printbuf_memappend(pb, str + start_offset, pos - start_offset);\n  return 0;\n}\n\n\n/* reference counting */\n\nextern struct json_object* json_object_get(struct json_object *jso)\n{\n  if(jso) {\n    jso->_ref_count++;\n  }\n  return jso;\n}\n\nint json_object_put(struct json_object *jso)\n{\n    if(jso)\n    {\n        jso->_ref_count--;\n        if(!jso->_ref_count)\n        {\n            if (jso->_user_delete)\n                jso->_user_delete(jso, jso->_userdata);\n            jso->_delete(jso);\n            return 1;\n        }\n    }\n    return 0;\n}\n\n\n/* generic object construction and destruction parts */\n\nstatic void json_object_generic_delete(struct json_object* jso)\n{\n#ifdef REFCOUNT_DEBUG\n  MC_DEBUG(\"json_object_delete_%s: %p\\n\",\n       json_type_to_name(jso->o_type), jso);\n  lh_table_delete(json_object_table, jso);\n#endif /* REFCOUNT_DEBUG */\n  printbuf_free(jso->_pb);\n  free(jso);\n}\n\nstatic struct json_object* json_object_new(enum json_type o_type)\n{\n  struct json_object *jso;\n\n  jso = (struct json_object*)calloc(sizeof(struct json_object), 1);\n  if(!jso) return NULL;\n  jso->o_type = o_type;\n  jso->_ref_count = 1;\n  jso->_delete = &json_object_generic_delete;\n#ifdef REFCOUNT_DEBUG\n  lh_table_insert(json_object_table, jso, jso);\n  MC_DEBUG(\"json_object_new_%s: %p\\n\", json_type_to_name(jso->o_type), jso);\n#endif /* REFCOUNT_DEBUG */\n  return jso;\n}\n\n\n/* type checking functions */\n\nint json_object_is_type(struct json_object *jso, enum json_type type)\n{\n  if (!jso)\n    return (type == json_type_null);\n  return (jso->o_type == type);\n}\n\nenum json_type json_object_get_type(struct json_object *jso)\n{\n  if (!jso)\n    return json_type_null;\n  return jso->o_type;\n}\n\n/* set a custom conversion to string */\n\nvoid json_object_set_serializer(json_object *jso,\n    json_object_to_json_string_fn to_string_func,\n    void *userdata,\n    json_object_delete_fn *user_delete)\n{\n    // First, clean up any previously existing user info\n    if (jso->_user_delete)\n    {\n        jso->_user_delete(jso, jso->_userdata);\n    }\n    jso->_userdata = NULL;\n    jso->_user_delete = NULL;\n\n    if (to_string_func == NULL)\n    {\n        // Reset to the standard serialization function\n        switch(jso->o_type)\n        {\n        case json_type_null:\n            jso->_to_json_string = NULL;\n            break;\n        case json_type_boolean:\n            jso->_to_json_string = &json_object_boolean_to_json_string;\n            break;\n        case json_type_double:\n            jso->_to_json_string = &json_object_double_to_json_string;\n            break;\n        case json_type_int:\n            jso->_to_json_string = &json_object_int_to_json_string;\n            break;\n        case json_type_object:\n            jso->_to_json_string = &json_object_object_to_json_string;\n            break;\n        case json_type_array:\n            jso->_to_json_string = &json_object_array_to_json_string;\n            break;\n        case json_type_string:\n            jso->_to_json_string = &json_object_string_to_json_string;\n            break;\n        }\n        return;\n    }\n\n    jso->_to_json_string = to_string_func;\n    jso->_userdata = userdata;\n    jso->_user_delete = user_delete;\n}\n\n\n/* extended conversion to string */\n\nchar* json_object_to_json_string_ext(struct json_object *jso, int flags)\n{\n    if (!jso)\n        return \"null\";\n\n    if ((!jso->_pb) && !(jso->_pb = printbuf_new()))\n        return NULL;\n\n    printbuf_reset(jso->_pb);\n\n    if(jso->_to_json_string(jso, jso->_pb, 0, flags) < 0)\n        return NULL;\n\n    return jso->_pb->buf;\n}\n\n/* backwards-compatible conversion to string */\n\nchar* json_object_to_json_string(struct json_object *jso)\n{\n    return json_object_to_json_string_ext(jso, JSON_C_TO_STRING_SPACED);\n}\n\nstatic void indent(struct printbuf *pb, int level, int flags)\n{\n    if (flags & JSON_C_TO_STRING_PRETTY)\n    {\n        printbuf_memset(pb, -1, ' ', level * 2);\n    }\n}\n\n/* json_object_object */\n\nstatic int json_object_object_to_json_string(struct json_object* jso,\n                         struct printbuf *pb,\n                         int level,\n                         int flags)\n{\n    int had_children = 0;\n    struct json_object_iter iter;\n\n    sprintbuf(pb, \"{\" /*}*/);\n    if (flags & JSON_C_TO_STRING_PRETTY)\n        sprintbuf(pb, \"\\n\");\n    json_object_object_foreachC(jso, iter)\n    {\n        if (had_children)\n        {\n            sprintbuf(pb, \",\");\n            if (flags & JSON_C_TO_STRING_PRETTY)\n                sprintbuf(pb, \"\\n\");\n        }\n        had_children = 1;\n        if (flags & JSON_C_TO_STRING_SPACED)\n            sprintbuf(pb, \" \");\n        indent(pb, level+1, flags);\n        sprintbuf(pb, \"\\\"\");\n        json_escape_str(pb, iter.key, strlen(iter.key));\n        if (flags & JSON_C_TO_STRING_SPACED)\n            sprintbuf(pb, \"\\\": \");\n        else\n            sprintbuf(pb, \"\\\":\");\n        if(iter.val == NULL)\n            sprintbuf(pb, \"null\");\n        else\n            iter.val->_to_json_string(iter.val, pb, level+1,flags);\n    }\n    if (flags & JSON_C_TO_STRING_PRETTY)\n    {\n        if (had_children)\n            sprintbuf(pb, \"\\n\");\n        indent(pb,level,flags);\n    }\n    if (flags & JSON_C_TO_STRING_SPACED)\n        return sprintbuf(pb, /*{*/ \" }\");\n    else\n        return sprintbuf(pb, /*{*/ \"}\");\n}\n\n\nstatic void json_object_lh_entry_free(struct lh_entry *ent)\n{\n  free(ent->k);\n  json_object_put((struct json_object*)ent->v);\n}\n\nstatic void json_object_object_delete(struct json_object* jso)\n{\n  lh_table_free(jso->o.c_object);\n  json_object_generic_delete(jso);\n}\n\nstruct json_object* json_object_new_object(void)\n{\n    struct json_object* jso = json_object_new(json_type_object);\n\n    if (!jso) \n    {\n        return NULL;\n    }\n\n    jso->_delete = &json_object_object_delete;\n    jso->_to_json_string = &json_object_object_to_json_string;\n    jso->o.c_object = lh_kchar_table_new(JSON_OBJECT_DEF_HASH_ENTRIES, NULL, &json_object_lh_entry_free);\n\n    return jso;\n}\n\nstruct lh_table* json_object_get_object(struct json_object *jso)\n{\n  if(!jso) return NULL;\n  switch(jso->o_type) {\n  case json_type_object:\n    return jso->o.c_object;\n  default:\n    return NULL;\n  }\n}\n\nvoid json_object_object_add(struct json_object* jso, const char *key,\n                struct json_object *val)\n{\n    // We lookup the entry and replace the value, rather than just deleting\n    // and re-adding it, so the existing key remains valid.\n    json_object *existing_value = NULL;\n    struct lh_entry *existing_entry;\n    existing_entry = lh_table_lookup_entry(jso->o.c_object, (void*)key);\n    if (!existing_entry)\n    {\n        lh_table_insert(jso->o.c_object, strdup(key), val);\n        return;\n    }\n    existing_value = (void *)existing_entry->v;\n    if (existing_value)\n        json_object_put(existing_value);\n    existing_entry->v = val;\n}\n\nint json_object_object_length(struct json_object *jso)\n{\n    return lh_table_length(jso->o.c_object);\n}\n\nstruct json_object* json_object_object_get(struct json_object* jso, const char *key)\n{\n    struct json_object *result = NULL;\n    json_object_object_get_ex(jso, key, &result);\n    return result;\n}\n\njson_bool json_object_object_get_ex(struct json_object* jso, const char *key, struct json_object **value)\n{\n    if (value != NULL)\n        *value = NULL;\n\n    if (NULL == jso)\n        return FALSE;\n\n    switch(jso->o_type)\n    {\n    case json_type_object:\n        return lh_table_lookup_ex(jso->o.c_object, (void*)key, (void**)value);\n    default:\n        if (value != NULL)\n            *value = NULL;\n        return FALSE;\n    }\n}\n\nvoid json_object_object_del(struct json_object* jso, const char *key)\n{\n    lh_table_delete(jso->o.c_object, key);\n}\n\n\n/* json_object_boolean */\n\nstatic int json_object_boolean_to_json_string(struct json_object* jso,\n                          struct printbuf *pb,\n                          int level,\n                          int flags)\n{\n  if(jso->o.c_boolean) return sprintbuf(pb, \"true\");\n  else return sprintbuf(pb, \"false\");\n}\n\nstruct json_object* json_object_new_boolean(json_bool b)\n{\n  struct json_object *jso = json_object_new(json_type_boolean);\n  if(!jso) return NULL;\n  jso->_to_json_string = &json_object_boolean_to_json_string;\n  jso->o.c_boolean = b;\n  return jso;\n}\n\njson_bool json_object_get_boolean(struct json_object *jso)\n{\n  if(!jso) return FALSE;\n  switch(jso->o_type) {\n  case json_type_boolean:\n    return jso->o.c_boolean;\n  case json_type_int:\n    return (jso->o.c_int64 != 0);\n  case json_type_double:\n    return (jso->o.c_double != 0);\n  case json_type_string:\n    return (jso->o.c_string.len != 0);\n  default:\n    return FALSE;\n  }\n}\n\n\n/* json_object_int */\n\nstatic int json_object_int_to_json_string(struct json_object* jso,\n                      struct printbuf *pb,\n                      int level,\n                      int flags)\n{\n  return sprintbuf(pb, \"%\"PRId64, jso->o.c_int64);\n}\n\nstruct json_object* json_object_new_int(int32_t i)\n{\n  struct json_object *jso = json_object_new(json_type_int);\n  if(!jso) return NULL;\n  jso->_to_json_string = &json_object_int_to_json_string;\n  jso->o.c_int64 = i;\n  return jso;\n}\n\nint32_t json_object_get_int(struct json_object *jso)\n{\n  int64_t cint64;\n  enum json_type o_type;\n\n  if(!jso) return 0;\n\n  o_type = jso->o_type;\n  cint64 = jso->o.c_int64;\n\n  if (o_type == json_type_string)\n  {\n    /*\n     * Parse strings into 64-bit numbers, then use the\n     * 64-to-32-bit number handling below.\n     */\n    if (json_parse_int64(jso->o.c_string.str, &cint64) != 0)\n        return 0; /* whoops, it didn't work. */\n    o_type = json_type_int;\n  }\n\n  switch(o_type) {\n  case json_type_int:\n    /* Make sure we return the correct values for out of range numbers. */\n    if (cint64 <= INT32_MIN)\n        return INT32_MIN;\n    else if (cint64 >= INT32_MAX)\n        return INT32_MAX;\n    else\n        return (int32_t)cint64;\n  case json_type_double:\n    return (int32_t)jso->o.c_double;\n  case json_type_boolean:\n    return jso->o.c_boolean;\n  default:\n    return 0;\n  }\n}\n\nstruct json_object* json_object_new_int64(int64_t i)\n{\n  struct json_object *jso = json_object_new(json_type_int);\n  if(!jso) return NULL;\n  jso->_to_json_string = &json_object_int_to_json_string;\n  jso->o.c_int64 = i;\n  return jso;\n}\n\nint64_t json_object_get_int64(struct json_object *jso)\n{\n   int64_t cint;\n\n  if(!jso) return 0;\n  switch(jso->o_type) {\n  case json_type_int:\n    return jso->o.c_int64;\n  case json_type_double:\n    return (int64_t)jso->o.c_double;\n  case json_type_boolean:\n    return jso->o.c_boolean;\n  case json_type_string:\n    if (json_parse_int64(jso->o.c_string.str, &cint) == 0) return cint;\n  default:\n    return 0;\n  }\n}\n\n\n/* json_object_double */\n\nstatic int json_object_double_to_json_string(struct json_object* jso,\n                         struct printbuf *pb,\n                         int level,\n                         int flags)\n{\n  char buf[128], *p, *q;\n  size_t size;\n  /* Although JSON RFC does not support\n     NaN or Infinity as numeric values\n     ECMA 262 section 9.8.1 defines\n     how to handle these cases as strings */\n  if(isnan(jso->o.c_double))\n    size = _snprintf_s(buf, sizeof(buf), _TRUNCATE, \"NaN\");\n  else if(isinf(jso->o.c_double))\n    if(jso->o.c_double > 0)\n      size = _snprintf_s(buf, sizeof(buf), _TRUNCATE, \"Infinity\");\n    else\n      size = _snprintf_s(buf, sizeof(buf), _TRUNCATE, \"-Infinity\");\n  else\n    size = _snprintf_s(buf, sizeof(buf), _TRUNCATE, \"%.17g\", jso->o.c_double);\n\n  p = strchr(buf, ',');\n  if (p) {\n    *p = '.';\n  } else {\n    p = strchr(buf, '.');\n  }\n  if (p && (flags & JSON_C_TO_STRING_NOZERO)) {\n    /* last useful digit, always keep 1 zero */\n    p++;\n    for (q=p ; *q ; q++) {\n      if (*q!='0') p=q;\n    }\n    /* drop trailing zeroes */\n    *(++p) = 0;\n    size = p-buf;\n  }\n  printbuf_memappend(pb, buf, size);\n  return (int)size;\n}\n\nstruct json_object* json_object_new_double(double d)\n{\n    struct json_object *jso = json_object_new(json_type_double);\n    if (!jso)\n        return NULL;\n    jso->_to_json_string = &json_object_double_to_json_string;\n    jso->o.c_double = d;\n    return jso;\n}\n\nstruct json_object* json_object_new_double_s(double d, const char *ds)\n{\n    struct json_object *jso = json_object_new_double(d);\n    if (!jso)\n        return NULL;\n\n    json_object_set_serializer(jso, json_object_userdata_to_json_string, strdup(ds), json_object_free_userdata);\n    return jso;\n}\n\nint json_object_userdata_to_json_string(struct json_object *jso, struct printbuf *pb, int level, int flags)\n{\n    size_t userdata_len = strlen(jso->_userdata);\n    printbuf_memappend(pb, jso->_userdata, userdata_len);\n    return (int)userdata_len;\n}\n\nvoid json_object_free_userdata(struct json_object *jso, void *userdata)\n{\n    free(userdata);\n}\n\ndouble json_object_get_double(struct json_object *jso)\n{\n  double cdouble;\n  char *errPtr = NULL;\n\n  if(!jso) return 0.0;\n  switch(jso->o_type) {\n  case json_type_double:\n    return jso->o.c_double;\n  case json_type_int:\n    return (double)jso->o.c_int64;\n  case json_type_boolean:\n    return jso->o.c_boolean;\n  case json_type_string:\n    errno = 0;\n    cdouble = strtod(jso->o.c_string.str,&errPtr);\n\n    /* if conversion stopped at the first character, return 0.0 */\n    if (errPtr == jso->o.c_string.str)\n        return 0.0;\n\n    /*\n     * Check that the conversion terminated on something sensible\n     *\n     * For example, { \"pay\" : 123AB } would parse as 123.\n     */\n    if (*errPtr != '\\0')\n        return 0.0;\n\n    /*\n     * If strtod encounters a string which would exceed the\n     * capacity of a double, it returns +/- HUGE_VAL and sets\n     * errno to ERANGE. But +/- HUGE_VAL is also a valid result\n     * from a conversion, so we need to check errno.\n     *\n     * Underflow also sets errno to ERANGE, but it returns 0 in\n     * that case, which is what we will return anyway.\n     *\n     * See CERT guideline ERR30-C\n     */\n    if ((HUGE_VAL == cdouble || -HUGE_VAL == cdouble) &&\n        (ERANGE == errno))\n            cdouble = 0.0;\n    return cdouble;\n  default:\n    return 0.0;\n  }\n}\n\n\n/* json_object_string */\n\nstatic int json_object_string_to_json_string(struct json_object* jso,\n                         struct printbuf *pb,\n                         int level,\n                         int flags)\n{\n  sprintbuf(pb, \"\\\"\");\n  json_escape_str(pb, jso->o.c_string.str, jso->o.c_string.len);\n  sprintbuf(pb, \"\\\"\");\n  return 0;\n}\n\nstatic void json_object_string_delete(struct json_object* jso)\n{\n  free(jso->o.c_string.str);\n  json_object_generic_delete(jso);\n}\n\nstruct json_object* json_object_new_string(const char *s)\n{\n  struct json_object *jso = json_object_new(json_type_string);\n  if(!jso) return NULL;\n  jso->_delete = &json_object_string_delete;\n  jso->_to_json_string = &json_object_string_to_json_string;\n  jso->o.c_string.str = strdup(s);\n  jso->o.c_string.len = (int)strlen(s);\n  return jso;\n}\n\nstruct json_object* json_object_new_string_len(const char *s, size_t len)\n{\n  struct json_object *jso = json_object_new(json_type_string);\n  if(!jso) return NULL;\n  jso->_delete = &json_object_string_delete;\n  jso->_to_json_string = &json_object_string_to_json_string;\n  jso->o.c_string.str = (char*)malloc(len + 1);\n  memcpy(jso->o.c_string.str, (void *)s, len);\n  jso->o.c_string.str[len] = '\\0';\n  jso->o.c_string.len = len;\n  return jso;\n}\n\nchar* json_object_get_string(struct json_object *jso)\n{\n    if (!jso) \n        return NULL;\n    switch (jso->o_type)\n    {\n    case json_type_string:\n        return jso->o.c_string.str;\n    default:\n        return json_object_to_json_string(jso);\n    }\n}\n\nint json_object_get_string_len(struct json_object *jso)  {\n  if(!jso) return 0;\n  switch(jso->o_type) {\n  case json_type_string:\n    return (int)jso->o.c_string.len;\n  default:\n    return 0;\n  }\n}\n\n\n/* json_object_array */\n\nstatic int json_object_array_to_json_string(struct json_object* jso,\n                                            struct printbuf *pb,\n                                            int level,\n                                            int flags)\n{\n    int had_children = 0;\n    int ii;\n    sprintbuf(pb, \"[\");\n    if (flags & JSON_C_TO_STRING_PRETTY)\n        sprintbuf(pb, \"\\n\");\n    for(ii=0; ii < json_object_array_length(jso); ii++)\n    {\n        struct json_object *val;\n        if (had_children)\n        {\n            sprintbuf(pb, \",\");\n            if (flags & JSON_C_TO_STRING_PRETTY)\n                sprintbuf(pb, \"\\n\");\n        }\n        had_children = 1;\n        if (flags & JSON_C_TO_STRING_SPACED)\n            sprintbuf(pb, \" \");\n        indent(pb, level + 1, flags);\n        val = json_object_array_get_idx(jso, ii);\n        if(val == NULL)\n            sprintbuf(pb, \"null\");\n        else\n            val->_to_json_string(val, pb, level+1, flags);\n    }\n    if (flags & JSON_C_TO_STRING_PRETTY)\n    {\n        if (had_children)\n            sprintbuf(pb, \"\\n\");\n        indent(pb,level,flags);\n    }\n\n    if (flags & JSON_C_TO_STRING_SPACED)\n        return sprintbuf(pb, \" ]\");\n    else\n        return sprintbuf(pb, \"]\");\n}\n\nstatic void json_object_array_entry_free(void *data)\n{\n  json_object_put((struct json_object*)data);\n}\n\nstatic void json_object_array_delete(struct json_object* jso)\n{\n  array_list_free(jso->o.c_array);\n  json_object_generic_delete(jso);\n}\n\nstruct json_object* json_object_new_array(void)\n{\n  struct json_object *jso = json_object_new(json_type_array);\n  if(!jso) return NULL;\n  jso->_delete = &json_object_array_delete;\n  jso->_to_json_string = &json_object_array_to_json_string;\n  jso->o.c_array = array_list_new(&json_object_array_entry_free);\n  return jso;\n}\n\nstruct array_list* json_object_get_array(struct json_object *jso)\n{\n  if(!jso) return NULL;\n  switch(jso->o_type) {\n  case json_type_array:\n    return jso->o.c_array;\n  default:\n    return NULL;\n  }\n}\n\nvoid json_object_array_sort(struct json_object *jso, int(__cdecl* sort_fn)(const void *, const void *))\n{\n  array_list_sort(jso->o.c_array, sort_fn);\n}\n\nint json_object_array_length(struct json_object *jso)\n{\n  return array_list_length(jso->o.c_array);\n}\n\nint json_object_array_add(struct json_object *jso,struct json_object *val)\n{\n  return array_list_add(jso->o.c_array, val);\n}\n\nint json_object_array_put_idx(struct json_object *jso, int idx,\n                  struct json_object *val)\n{\n  return array_list_put_idx(jso->o.c_array, idx, val);\n}\n\nstruct json_object* json_object_array_get_idx(struct json_object *jso,\n                          int idx)\n{\n  return (struct json_object*)array_list_get_idx(jso->o.c_array, idx);\n}\n\n"
  },
  {
    "path": "third_party/phlib/jsonc/json_object.h",
    "content": "/*\n * $Id: json_object.h,v 1.12 2006/01/30 23:07:57 mclark Exp $\n *\n * Copyright (c) 2004, 2005 Metaparadigm Pte. Ltd.\n * Michael Clark <michael@metaparadigm.com>\n * Copyright (c) 2009 Hewlett-Packard Development Company, L.P.\n *\n * This library is free software; you can redistribute it and/or modify\n * it under the terms of the MIT license. See COPYING for details.\n *\n */\n\n#ifndef _json_object_h_\n#define _json_object_h_\n\n#ifdef __GNUC__\n#define THIS_FUNCTION_IS_DEPRECATED(func) func __attribute__ ((deprecated))\n#elif defined(_MSC_VER)\n#define THIS_FUNCTION_IS_DEPRECATED(func) __declspec(deprecated) func\n#else\n#define THIS_FUNCTION_IS_DEPRECATED(func) func\n#endif\n\n#include \"json_inttypes.h\"\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\n#define JSON_OBJECT_DEF_HASH_ENTRIES 16\n\n/**\n * A flag for the json_object_to_json_string_ext() and\n * json_object_to_file_ext() functions which causes the output\n * to have no extra whitespace or formatting applied.\n */\n#define JSON_C_TO_STRING_PLAIN      0\n/**\n * A flag for the json_object_to_json_string_ext() and\n * json_object_to_file_ext() functions which causes the output to have\n * minimal whitespace inserted to make things slightly more readable.\n */\n#define JSON_C_TO_STRING_SPACED     (1<<0)\n/**\n * A flag for the json_object_to_json_string_ext() and\n * json_object_to_file_ext() functions which causes\n * the output to be formatted.\n *\n * See the \"Two Space Tab\" option at http://jsonformatter.curiousconcept.com/\n * for an example of the format.\n */\n#define JSON_C_TO_STRING_PRETTY     (1<<1)\n/**\n * A flag to drop trailing zero for float values\n */\n#define JSON_C_TO_STRING_NOZERO     (1<<2)\n\n#undef FALSE\n#define FALSE ((json_bool)0)\n\n#undef TRUE\n#define TRUE ((json_bool)1)\n\nextern const char *json_number_chars;\nextern const char *json_hex_chars;\n\n/* CAW: added for ANSI C iteration correctness */\nstruct json_object_iter\n{\n    char *key;\n    struct json_object *val;\n    struct lh_entry *entry;\n};\n\n/* forward structure definitions */\n\ntypedef int json_bool;\ntypedef struct printbuf printbuf;\ntypedef struct lh_table lh_table;\ntypedef struct array_list array_list;\ntypedef struct json_object json_object, *json_object_ptr;\ntypedef struct json_object_iter json_object_iter;\ntypedef struct json_tokener json_tokener;\n\n/**\n * Type of custom user delete functions.  See json_object_set_serializer.\n */\ntypedef void (json_object_delete_fn)(struct json_object *jso, void *userdata);\n\n/**\n * Type of a custom serialization function.  See json_object_set_serializer.\n */\ntypedef int (json_object_to_json_string_fn)(struct json_object *jso,\n                        struct printbuf *pb,\n                        int level,\n                        int flags);\n\n/* supported object types */\n\ntypedef enum json_type {\n  /* If you change this, be sure to update json_type_to_name() too */\n  json_type_null,\n  json_type_boolean,\n  json_type_double,\n  json_type_int,\n  json_type_object,\n  json_type_array,\n  json_type_string,\n} json_type;\n\n/* reference counting functions */\n\n/**\n * Increment the reference count of json_object, thereby grabbing shared \n * ownership of obj.\n *\n * @param obj the json_object instance\n */\nextern struct json_object* json_object_get(struct json_object *obj);\n\n/**\n * Decrement the reference count of json_object and free if it reaches zero.\n * You must have ownership of obj prior to doing this or you will cause an\n * imbalance in the reference count.\n *\n * @param obj the json_object instance\n * @returns 1 if the object was freed.\n */\nint json_object_put(struct json_object *obj);\n\n/**\n * Check if the json_object is of a given type\n * @param obj the json_object instance\n * @param type one of:\n     json_type_null (i.e. obj == NULL),\n     json_type_boolean,\n     json_type_double,\n     json_type_int,\n     json_type_object,\n     json_type_array,\n     json_type_string,\n */\nextern int json_object_is_type(struct json_object *obj, enum json_type type);\n\n/**\n * Get the type of the json_object.  See also json_type_to_name() to turn this\n * into a string suitable, for instance, for logging.\n *\n * @param obj the json_object instance\n * @returns type being one of:\n     json_type_null (i.e. obj == NULL),\n     json_type_boolean,\n     json_type_double,\n     json_type_int,\n     json_type_object,\n     json_type_array,\n     json_type_string,\n */\nextern enum json_type json_object_get_type(struct json_object *obj);\n\n\n/** Stringify object to json format.\n * Equivalent to json_object_to_json_string_ext(obj, JSON_C_TO_STRING_SPACED)\n * @param obj the json_object instance\n * @returns a string in JSON format\n */\nextern char* json_object_to_json_string(struct json_object *obj);\n\n/** Stringify object to json format\n * @param obj the json_object instance\n * @param flags formatting options, see JSON_C_TO_STRING_PRETTY and other constants\n * @returns a string in JSON format\n */\nextern char* json_object_to_json_string_ext(struct json_object *obj, int flags);\n\n/**\n * Set a custom serialization function to be used when this particular object\n * is converted to a string by json_object_to_json_string.\n *\n * If a custom serializer is already set on this object, any existing \n * user_delete function is called before the new one is set.\n *\n * If to_string_func is NULL, the other parameters are ignored\n * and the default behaviour is reset.\n *\n * The userdata parameter is optional and may be passed as NULL.  If provided,\n * it is passed to to_string_func as-is.  This parameter may be NULL even\n * if user_delete is non-NULL.\n *\n * The user_delete parameter is optional and may be passed as NULL, even if\n * the userdata parameter is non-NULL.  It will be called just before the\n * json_object is deleted, after it's reference count goes to zero\n * (see json_object_put()).\n * If this is not provided, it is up to the caller to free the userdata at\n * an appropriate time. (i.e. after the json_object is deleted)\n *\n * @param jso the object to customize\n * @param to_string_func the custom serialization function\n * @param userdata an optional opaque cookie\n * @param user_delete an optional function from freeing userdata\n */\nextern void json_object_set_serializer(json_object *jso,\n    json_object_to_json_string_fn to_string_func,\n    void *userdata,\n    json_object_delete_fn *user_delete);\n\n/**\n * Simply call free on the userdata pointer.\n * Can be used with json_object_set_serializer().\n *\n * @param jso unused\n * @param userdata the pointer that is passed to free().\n */\njson_object_delete_fn json_object_free_userdata;\n\n/**\n * Copy the jso->_userdata string over to pb as-is.\n * Can be used with json_object_set_serializer().\n *\n * @param jso The object whose _userdata is used.\n * @param pb The destination buffer.\n * @param level Ignored.\n * @param flags Ignored.\n */\njson_object_to_json_string_fn json_object_userdata_to_json_string;\n\n\n/* object type methods */\n\n/** Create a new empty object with a reference count of 1.  The caller of\n * this object initially has sole ownership.  Remember, when using\n * json_object_object_add or json_object_array_put_idx, ownership will\n * transfer to the object/array.  Call json_object_get if you want to maintain\n * shared ownership or also add this object as a child of multiple objects or\n * arrays.  Any ownerships you acquired but did not transfer must be released\n * through json_object_put.\n *\n * @returns a json_object of type json_type_object\n */\nextern struct json_object* json_object_new_object(void);\n\n/** Get the hashtable of a json_object of type json_type_object\n * @param obj the json_object instance\n * @returns a linkhash\n */\nextern struct lh_table* json_object_get_object(struct json_object *obj);\n\n/** Get the size of an object in terms of the number of fields it has.\n * @param obj the json_object whose length to return\n */\nextern int json_object_object_length(struct json_object* obj);\n\n/** Add an object field to a json_object of type json_type_object\n *\n * The reference count will *not* be incremented. This is to make adding\n * fields to objects in code more compact. If you want to retain a reference\n * to an added object, independent of the lifetime of obj, you must wrap the\n * passed object with json_object_get.\n *\n * Upon calling this, the ownership of val transfers to obj.  Thus you must\n * make sure that you do in fact have ownership over this object.  For instance,\n * json_object_new_object will give you ownership until you transfer it,\n * whereas json_object_object_get does not.\n *\n * @param obj the json_object instance\n * @param key the object field name (a private copy will be duplicated)\n * @param val a json_object or NULL member to associate with the given field\n */\nextern void json_object_object_add(struct json_object* obj, const char *key,\n                   struct json_object *val);\n\n/** Get the json_object associate with a given object field\n *\n * *No* reference counts will be changed.  There is no need to manually adjust\n * reference counts through the json_object_put/json_object_get methods unless\n * you need to have the child (value) reference maintain a different lifetime\n * than the owning parent (obj). Ownership of the returned value is retained\n * by obj (do not do json_object_put unless you have done a json_object_get).\n * If you delete the value from obj (json_object_object_del) and wish to access\n * the returned reference afterwards, make sure you have first gotten shared\n * ownership through json_object_get (& don't forget to do a json_object_put\n * or transfer ownership to prevent a memory leak).\n *\n * @param obj the json_object instance\n * @param key the object field name\n * @returns the json_object associated with the given field name\n * @deprecated Please use json_object_object_get_ex\n */\nTHIS_FUNCTION_IS_DEPRECATED(extern struct json_object* json_object_object_get(struct json_object* obj,\n                          const char *key));\n\n/** Get the json_object associated with a given object field.  \n *\n * This returns true if the key is found, false in all other cases (including \n * if obj isn't a json_type_object).\n *\n * *No* reference counts will be changed.  There is no need to manually adjust\n * reference counts through the json_object_put/json_object_get methods unless\n * you need to have the child (value) reference maintain a different lifetime\n * than the owning parent (obj).  Ownership of value is retained by obj.\n *\n * @param obj the json_object instance\n * @param key the object field name\n * @param value a pointer where to store a reference to the json_object \n *              associated with the given field name.\n *\n *              It is safe to pass a NULL value.\n * @returns whether or not the key exists\n */\nextern json_bool json_object_object_get_ex(struct json_object* obj,\n                          const char *key,\n                                                  struct json_object **value);\n\n/** Delete the given json_object field\n *\n * The reference count will be decremented for the deleted object.  If there\n * are no more owners of the value represented by this key, then the value is\n * freed.  Otherwise, the reference to the value will remain in memory.\n *\n * @param obj the json_object instance\n * @param key the object field name\n */\nextern void json_object_object_del(struct json_object* obj, const char *key);\n\n/**\n * Iterate through all keys and values of an object.\n *\n * Adding keys to the object while iterating is NOT allowed.\n *\n * Deleting an existing key, or replacing an existing key with a\n * new value IS allowed.\n *\n * @param obj the json_object instance\n * @param key the local name for the char* key variable defined in the body\n * @param val the local name for the json_object* object variable defined in\n *            the body\n */\n#if defined(__GNUC__) && !defined(__STRICT_ANSI__) && __STDC_VERSION__ >= 199901L\n\n# define json_object_object_foreach(obj,key,val) \\\n    char *key; \\\n    struct json_object *val __attribute__((__unused__)); \\\n    for(struct lh_entry *entry ## key = json_object_get_object(obj)->head, *entry_next ## key = NULL; \\\n        ({ if(entry ## key) { \\\n            key = (char*)entry ## key->k; \\\n            val = (struct json_object*)entry ## key->v; \\\n            entry_next ## key = entry ## key->next; \\\n        } ; entry ## key; }); \\\n        entry ## key = entry_next ## key )\n\n#else /* ANSI C or MSC */\n\n# define json_object_object_foreach(obj,key,val) \\\n    char *key;\\\n    struct json_object *val; \\\n    struct lh_entry *entry ## key; \\\n    struct lh_entry *entry_next ## key = NULL; \\\n    for(entry ## key = json_object_get_object(obj)->head; \\\n        (entry ## key ? ( \\\n            key = (char*)entry ## key->k, \\\n            val = (struct json_object*)entry ## key->v, \\\n            entry_next ## key = entry ## key->next, \\\n            entry ## key) : 0); \\\n        entry ## key = entry_next ## key)\n\n#endif /* defined(__GNUC__) && !defined(__STRICT_ANSI__) && __STDC_VERSION__ >= 199901L */\n\n/** Iterate through all keys and values of an object (ANSI C Safe)\n * @param obj the json_object instance\n * @param iter the object iterator\n */\n#define json_object_object_foreachC(obj,iter) \\\n for(iter.entry = json_object_get_object(obj)->head; (iter.entry ? (iter.key = (char*)iter.entry->k, iter.val = (struct json_object*)iter.entry->v, iter.entry) : 0); iter.entry = iter.entry->next)\n\n/* Array type methods */\n\n/** Create a new empty json_object of type json_type_array\n * @returns a json_object of type json_type_array\n */\nextern struct json_object* json_object_new_array(void);\n\n/** Get the arraylist of a json_object of type json_type_array\n * @param obj the json_object instance\n * @returns an arraylist\n */\nextern struct array_list* json_object_get_array(struct json_object *obj);\n\n/** Get the length of a json_object of type json_type_array\n * @param obj the json_object instance\n * @returns an int\n */\nextern int json_object_array_length(struct json_object *obj);\n\n/** Sorts the elements of jso of type json_type_array\n*\n* Pointers to the json_object pointers will be passed as the two arguments\n* to @sort_fn\n*\n* @param obj the json_object instance\n* @param sort_fn a sorting function\n*/\nextern void json_object_array_sort(struct json_object *jso, int(__cdecl* sort_fn)(const void *, const void *));\n\n/** Add an element to the end of a json_object of type json_type_array\n *\n * The reference count will *not* be incremented. This is to make adding\n * fields to objects in code more compact. If you want to retain a reference\n * to an added object you must wrap the passed object with json_object_get\n *\n * @param obj the json_object instance\n * @param val the json_object to be added\n */\nextern int json_object_array_add(struct json_object *obj,\n                 struct json_object *val);\n\n/** Insert or replace an element at a specified index in an array (a json_object of type json_type_array)\n *\n * The reference count will *not* be incremented. This is to make adding\n * fields to objects in code more compact. If you want to retain a reference\n * to an added object you must wrap the passed object with json_object_get\n *\n * The reference count of a replaced object will be decremented.\n *\n * The array size will be automatically be expanded to the size of the\n * index if the index is larger than the current size.\n *\n * @param obj the json_object instance\n * @param idx the index to insert the element at\n * @param val the json_object to be added\n */\nextern int json_object_array_put_idx(struct json_object *obj, int idx,\n                     struct json_object *val);\n\n/** Get the element at specificed index of the array (a json_object of type json_type_array)\n * @param obj the json_object instance\n * @param idx the index to get the element at\n * @returns the json_object at the specified index (or NULL)\n */\nextern struct json_object* json_object_array_get_idx(struct json_object *obj,\n                             int idx);\n\n/* json_bool type methods */\n\n/** Create a new empty json_object of type json_type_boolean\n * @param b a json_bool TRUE or FALSE (0 or 1)\n * @returns a json_object of type json_type_boolean\n */\nextern struct json_object* json_object_new_boolean(json_bool b);\n\n/** Get the json_bool value of a json_object\n *\n * The type is coerced to a json_bool if the passed object is not a json_bool.\n * integer and double objects will return FALSE if there value is zero\n * or TRUE otherwise. If the passed object is a string it will return\n * TRUE if it has a non zero length. If any other object type is passed\n * TRUE will be returned if the object is not NULL.\n *\n * @param obj the json_object instance\n * @returns a json_bool\n */\nextern json_bool json_object_get_boolean(struct json_object *obj);\n\n\n/* int type methods */\n\n/** Create a new empty json_object of type json_type_int\n * Note that values are stored as 64-bit values internally.\n * To ensure the full range is maintained, use json_object_new_int64 instead.\n * @param i the integer\n * @returns a json_object of type json_type_int\n */\nextern struct json_object* json_object_new_int(int32_t i);\n\n\n/** Create a new empty json_object of type json_type_int\n * @param i the integer\n * @returns a json_object of type json_type_int\n */\nextern struct json_object* json_object_new_int64(int64_t i);\n\n\n/** Get the int value of a json_object\n *\n * The type is coerced to a int if the passed object is not a int.\n * double objects will return their integer conversion. Strings will be\n * parsed as an integer. If no conversion exists then 0 is returned\n * and errno is set to EINVAL. null is equivalent to 0 (no error values set)\n *\n * Note that integers are stored internally as 64-bit values.\n * If the value of too big or too small to fit into 32-bit, INT32_MAX or\n * INT32_MIN are returned, respectively.\n *\n * @param obj the json_object instance\n * @returns an int\n */\nextern int32_t json_object_get_int(struct json_object *obj);\n\n/** Get the int value of a json_object\n *\n * The type is coerced to a int64 if the passed object is not a int64.\n * double objects will return their int64 conversion. Strings will be\n * parsed as an int64. If no conversion exists then 0 is returned.\n *\n * NOTE: Set errno to 0 directly before a call to this function to determine\n * whether or not conversion was successful (it does not clear the value for\n * you).\n *\n * @param obj the json_object instance\n * @returns an int64\n */\nextern int64_t json_object_get_int64(struct json_object *obj);\n\n\n/* double type methods */\n\n/** Create a new empty json_object of type json_type_double\n * @param d the double\n * @returns a json_object of type json_type_double\n */\nextern struct json_object* json_object_new_double(double d);\n\n/**\n * Create a new json_object of type json_type_double, using\n * the exact serialized representation of the value.\n *\n * This allows for numbers that would otherwise get displayed\n * inefficiently (e.g. 12.3 => \"12.300000000000001\") to be\n * serialized with the more convenient form.\n *\n * Note: this is used by json_tokener_parse_ex() to allow for\n *   an exact re-serialization of a parsed object.\n *\n * An equivalent sequence of calls is:\n * @code\n *   jso = json_object_new_double(d);\n *   json_object_set_serializer(d, json_object_userdata_to_json_string,\n *       strdup(ds), json_object_free_userdata)\n * @endcode\n *\n * @param d the numeric value of the double.\n * @param ds the string representation of the double.  This will be copied.\n */\nextern struct json_object* json_object_new_double_s(double d, const char *ds);\n\n/** Get the double floating point value of a json_object\n *\n * The type is coerced to a double if the passed object is not a double.\n * integer objects will return their double conversion. Strings will be\n * parsed as a double. If no conversion exists then 0.0 is returned and\n * errno is set to EINVAL. null is equivalent to 0 (no error values set)\n *\n * If the value is too big to fit in a double, then the value is set to\n * the closest infinity with errno set to ERANGE. If strings cannot be\n * converted to their double value, then EINVAL is set & NaN is returned.\n *\n * Arrays of length 0 are interpreted as 0 (with no error flags set).\n * Arrays of length 1 are effectively cast to the equivalent object and\n * converted using the above rules.  All other arrays set the error to\n * EINVAL & return NaN.\n *\n * NOTE: Set errno to 0 directly before a call to this function to\n * determine whether or not conversion was successful (it does not clear\n * the value for you).\n *\n * @param obj the json_object instance\n * @returns a double floating point number\n */\nextern double json_object_get_double(struct json_object *obj);\n\n\n/* string type methods */\n\n/** Create a new empty json_object of type json_type_string\n *\n * A copy of the string is made and the memory is managed by the json_object\n *\n * @param s the string\n * @returns a json_object of type json_type_string\n */\nextern struct json_object* json_object_new_string(const char *s);\n\nextern struct json_object* json_object_new_string_len(const char *s, size_t len);\n\n/** Get the string value of a json_object\n *\n * If the passed object is not of type json_type_string then the JSON\n * representation of the object is returned.\n *\n * The returned string memory is managed by the json_object and will\n * be freed when the reference count of the json_object drops to zero.\n *\n * @param obj the json_object instance\n * @returns a string\n */\nextern char* json_object_get_string(struct json_object *obj);\n\n/** Get the string length of a json_object\n *\n * If the passed object is not of type json_type_string then zero\n * will be returned.\n *\n * @param obj the json_object instance\n * @returns int\n */\nextern int json_object_get_string_len(struct json_object *obj);\n\n#ifdef __cplusplus\n}\n#endif\n\n#endif\n"
  },
  {
    "path": "third_party/phlib/jsonc/json_object_iterator.c",
    "content": "/**\n*******************************************************************************\n* @file json_object_iterator.c\n*\n* Copyright (c) 2009-2012 Hewlett-Packard Development Company, L.P.\n*\n* This library is free software; you can redistribute it and/or modify\n* it under the terms of the MIT license. See COPYING for details.\n*\n* @brief  json-c forces clients to use its private data\n*         structures for JSON Object iteration.  This API\n*         implementation corrects that by abstracting the\n*         private json-c details.\n*\n*******************************************************************************\n*/\n\n#include <stddef.h>\n\n#include \"json.h\"\n#include \"json_object_private.h\"\n\n#include \"json_object_iterator.h\"\n\n/**\n * How It Works\n *\n * For each JSON Object, json-c maintains a linked list of zero\n * or more lh_entry (link-hash entry) structures inside the\n * Object's link-hash table (lh_table).\n *\n * Each lh_entry structure on the JSON Object's linked list\n * represents a single name/value pair.  The \"next\" field of the\n * last lh_entry in the list is set to NULL, which terminates\n * the list.\n *\n * We represent a valid iterator that refers to an actual\n * name/value pair via a pointer to the pair's lh_entry\n * structure set as the iterator's opaque_ field.\n *\n * We follow json-c's current pair list representation by\n * representing a valid \"end\" iterator (one that refers past the\n * last pair) with a NULL value in the iterator's opaque_ field.\n *\n * A JSON Object without any pairs in it will have the \"head\"\n * field of its lh_table structure set to NULL.  For such an\n * object, json_object_iter_begin will return an iterator with\n * the opaque_ field set to NULL, which is equivalent to the\n * \"end\" iterator.\n *\n * When iterating, we simply update the iterator's opaque_ field\n * to point to the next lh_entry structure in the linked list.\n * opaque_ will become NULL once we iterate past the last pair\n * in the list, which makes the iterator equivalent to the \"end\"\n * iterator.\n */\n\n/// Our current representation of the \"end\" iterator;\n///\n/// @note May not always be NULL\nstatic const void* kObjectEndIterValue = NULL;\n\n/**\n * ****************************************************************************\n */\nstruct json_object_iterator\njson_object_iter_begin(struct json_object* obj)\n{\n    struct json_object_iterator iter;\n    struct lh_table* pTable;\n\n    /// @note json_object_get_object will return NULL if passed NULL\n    ///       or a non-json_type_object instance\n    pTable = json_object_get_object(obj);\n    JASSERT(NULL != pTable);\n\n    /// @note For a pair-less Object, head is NULL, which matches our\n    ///       definition of the \"end\" iterator\n    iter.opaque_ = pTable->head;\n    return iter;\n}\n\n/**\n * ****************************************************************************\n */\nstruct json_object_iterator\njson_object_iter_end(const struct json_object* obj)\n{\n    struct json_object_iterator iter;\n\n    JASSERT(NULL != obj);\n    JASSERT(json_object_is_type(obj, json_type_object));\n\n    iter.opaque_ = kObjectEndIterValue;\n\n    return iter;\n}\n\n/**\n * ****************************************************************************\n */\nvoid\njson_object_iter_next(struct json_object_iterator* iter)\n{\n    JASSERT(NULL != iter);\n    JASSERT(kObjectEndIterValue != iter->opaque_);\n\n    iter->opaque_ = ((struct lh_entry *)iter->opaque_)->next;\n}\n\n\n/**\n * ****************************************************************************\n */\nconst char*\njson_object_iter_peek_name(const struct json_object_iterator* iter)\n{\n    JASSERT(NULL != iter);\n    JASSERT(kObjectEndIterValue != iter->opaque_);\n\n    return (const char*)(((struct lh_entry *)iter->opaque_)->k);\n}\n\n\n/**\n * ****************************************************************************\n */\nstruct json_object*\njson_object_iter_peek_value(const struct json_object_iterator* iter)\n{\n    JASSERT(NULL != iter);\n    JASSERT(kObjectEndIterValue != iter->opaque_);\n\n    return (struct json_object*)(((struct lh_entry *)iter->opaque_)->v);\n}\n\n\n/**\n * ****************************************************************************\n */\njson_bool\njson_object_iter_equal(const struct json_object_iterator* iter1,\n                       const struct json_object_iterator* iter2)\n{\n    JASSERT(NULL != iter1);\n    JASSERT(NULL != iter2);\n\n    return (iter1->opaque_ == iter2->opaque_);\n}\n\n\n/**\n * ****************************************************************************\n */\nstruct json_object_iterator\njson_object_iter_init_default(void)\n{\n    struct json_object_iterator iter;\n\n    /**\n     * @note Make this a negative, invalid value, such that\n     *       accidental access to it would likely be trapped by the\n     *       hardware as an invalid address.\n     */\n    iter.opaque_ = NULL;\n\n    return iter;\n}\n"
  },
  {
    "path": "third_party/phlib/jsonc/json_object_iterator.h",
    "content": "/**\n*******************************************************************************\n* @file json_object_iterator.h\n*\n* Copyright (c) 2009-2012 Hewlett-Packard Development Company, L.P.\n*\n* This library is free software; you can redistribute it and/or modify\n* it under the terms of the MIT license. See COPYING for details.\n*\n* @brief  json-c forces clients to use its private data\n*         structures for JSON Object iteration.  This API\n*         corrects that by abstracting the private json-c\n*         details.\n*\n* API attributes: <br>\n*   * Thread-safe: NO<br>\n*   * Reentrant: NO\n*\n*******************************************************************************\n*/\n\n\n#ifndef JSON_OBJECT_ITERATOR_H\n#define JSON_OBJECT_ITERATOR_H\n\n#include <stddef.h>\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\n/**\n * Forward declaration for the opaque iterator information.\n */\nstruct json_object_iter_info_;\n\n/**\n * The opaque iterator that references a name/value pair within\n * a JSON Object instance or the \"end\" iterator value.\n */\nstruct json_object_iterator {\n    const void* opaque_;\n};\n\n\n/**\n * forward declaration of json-c's JSON value instance structure\n */\nstruct json_object;\n\n\n/**\n * Initializes an iterator structure to a \"default\" value that\n * is convenient for initializing an iterator variable to a\n * default state (e.g., initialization list in a class'\n * constructor).\n *\n * @code\n * struct json_object_iterator iter = json_object_iter_init_default();\n * MyClass() : iter_(json_object_iter_init_default())\n * @endcode\n *\n * @note The initialized value doesn't reference any specific\n *       pair, is considered an invalid iterator, and MUST NOT\n *       be passed to any json-c API that expects a valid\n *       iterator.\n *\n * @note User and internal code MUST NOT make any assumptions\n *       about and dependencies on the value of the \"default\"\n *       iterator value.\n *\n * @return json_object_iterator\n */\nstruct json_object_iterator\njson_object_iter_init_default(void);\n\n/** Retrieves an iterator to the first pair of the JSON Object.\n *\n * @warning \tAny modification of the underlying pair invalidates all\n * \t\titerators to that pair.\n *\n * @param obj\tJSON Object instance (MUST be of type json_object)\n *\n * @return json_object_iterator If the JSON Object has at\n *              least one pair, on return, the iterator refers\n *              to the first pair. If the JSON Object doesn't\n *              have any pairs, the returned iterator is\n *              equivalent to the \"end\" iterator for the same\n *              JSON Object instance.\n *\n * @code\n * struct json_object_iterator it;\n * struct json_object_iterator itEnd;\n * struct json_object* obj;\n *\n * obj = json_tokener_parse(\"{'first':'george', 'age':100}\");\n * it = json_object_iter_begin(obj);\n * itEnd = json_object_iter_end(obj);\n *\n * while (!json_object_iter_equal(&it, &itEnd)) {\n *     printf(\"%s\\n\",\n *            json_object_iter_peek_name(&it));\n *     json_object_iter_next(&it);\n * }\n *\n * @endcode\n */\nstruct json_object_iterator\njson_object_iter_begin(struct json_object* obj);\n\n/** Retrieves the iterator that represents the position beyond the\n *  last pair of the given JSON Object instance.\n *\n *  @warning Do NOT write code that assumes that the \"end\"\n *        iterator value is NULL, even if it is so in a\n *        particular instance of the implementation.\n *\n *  @note The reason we do not (and MUST NOT) provide\n *        \"json_object_iter_is_end(json_object_iterator* iter)\"\n *        type of API is because it would limit the underlying\n *        representation of name/value containment (or force us\n *        to add additional, otherwise unnecessary, fields to\n *        the iterator structure). The \"end\" iterator and the\n *        equality test method, on the other hand, permit us to\n *        cleanly abstract pretty much any reasonable underlying\n *        representation without burdening the iterator\n *        structure with unnecessary data.\n *\n *  @note For performance reasons, memorize the \"end\" iterator prior\n *        to any loop.\n *\n * @param obj JSON Object instance (MUST be of type json_object)\n *\n * @return json_object_iterator On return, the iterator refers\n *              to the \"end\" of the Object instance's pairs\n *              (i.e., NOT the last pair, but \"beyond the last\n *              pair\" value)\n */\nstruct json_object_iterator\njson_object_iter_end(const struct json_object* obj);\n\n/** Returns an iterator to the next pair, if any\n *\n * @warning\tAny modification of the underlying pair\n *       \tinvalidates all iterators to that pair.\n *\n * @param iter [IN/OUT] Pointer to iterator that references a\n *         name/value pair; MUST be a valid, non-end iterator.\n *         WARNING: bad things will happen if invalid or \"end\"\n *         iterator is passed. Upon return will contain the\n *         reference to the next pair if there is one; if there\n *         are no more pairs, will contain the \"end\" iterator\n *         value, which may be compared against the return value\n *         of json_object_iter_end() for the same JSON Object\n *         instance.\n */\nvoid\njson_object_iter_next(struct json_object_iterator* iter);\n\n\n/** Returns a const pointer to the name of the pair referenced\n *  by the given iterator.\n *\n * @param iter pointer to iterator that references a name/value\n *             pair; MUST be a valid, non-end iterator.\n *\n * @warning\tbad things will happen if an invalid or\n *             \t\"end\" iterator is passed.\n *\n * @return const char* Pointer to the name of the referenced\n *         name/value pair.  The name memory belongs to the\n *         name/value pair, will be freed when the pair is\n *         deleted or modified, and MUST NOT be modified or\n *         freed by the user.\n */\nconst char*\njson_object_iter_peek_name(const struct json_object_iterator* iter);\n\n\n/** Returns a pointer to the json-c instance representing the\n *  value of the referenced name/value pair, without altering\n *  the instance's reference count.\n *\n * @param iter \tpointer to iterator that references a name/value\n *             \tpair; MUST be a valid, non-end iterator.\n *\n * @warning\tbad things will happen if invalid or\n *             \"end\" iterator is passed.\n *\n * @return struct json_object* Pointer to the json-c value\n *         instance of the referenced name/value pair;  the\n *         value's reference count is not changed by this\n *         function: if you plan to hold on to this json-c node,\n *         take a look at json_object_get() and\n *         json_object_put(). IMPORTANT: json-c API represents\n *         the JSON Null value as a NULL json_object instance\n *         pointer.\n */\nstruct json_object*\njson_object_iter_peek_value(const struct json_object_iterator* iter);\n\n\n/** Tests two iterators for equality.  Typically used to test\n *  for end of iteration by comparing an iterator to the\n *  corresponding \"end\" iterator (that was derived from the same\n *  JSON Object instance).\n *\n *  @note The reason we do not (and MUST NOT) provide\n *        \"json_object_iter_is_end(json_object_iterator* iter)\"\n *        type of API is because it would limit the underlying\n *        representation of name/value containment (or force us\n *        to add additional, otherwise unnecessary, fields to\n *        the iterator structure). The equality test method, on\n *        the other hand, permits us to cleanly abstract pretty\n *        much any reasonable underlying representation.\n *\n * @param iter1 Pointer to first valid, non-NULL iterator\n * @param iter2 POinter to second valid, non-NULL iterator\n *\n * @warning\tif a NULL iterator pointer or an uninitialized\n *       \tor invalid iterator, or iterators derived from\n *       \tdifferent JSON Object instances are passed, bad things\n *       \twill happen!\n *\n * @return json_bool non-zero if iterators are equal (i.e., both\n *         reference the same name/value pair or are both at\n *         \"end\"); zero if they are not equal.\n */\njson_bool\njson_object_iter_equal(const struct json_object_iterator* iter1,\n                       const struct json_object_iterator* iter2);\n\n\n#ifdef __cplusplus\n}\n#endif\n\n\n#endif /* JSON_OBJECT_ITERATOR_H */\n"
  },
  {
    "path": "third_party/phlib/jsonc/json_object_private.h",
    "content": "/*\n * $Id: json_object_private.h,v 1.4 2006/01/26 02:16:28 mclark Exp $\n *\n * Copyright (c) 2004, 2005 Metaparadigm Pte. Ltd.\n * Michael Clark <michael@metaparadigm.com>\n *\n * This library is free software; you can redistribute it and/or modify\n * it under the terms of the MIT license. See COPYING for details.\n *\n */\n\n#ifndef _json_object_private_h_\n#define _json_object_private_h_\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\ntypedef void (json_object_private_delete_fn)(struct json_object *o);\n\nstruct json_object\n{\n  enum json_type o_type;\n  json_object_private_delete_fn *_delete;\n  json_object_to_json_string_fn *_to_json_string;\n  int _ref_count;\n  struct printbuf *_pb;\n  union data {\n    json_bool c_boolean;\n    double c_double;\n    int64_t c_int64;\n    struct lh_table *c_object;\n    struct array_list *c_array;\n    struct {\n        char *str;\n        size_t len;\n    } c_string;\n  } o;\n  json_object_delete_fn *_user_delete;\n  void *_userdata;\n};\n\n#ifdef __cplusplus\n}\n#endif\n\n#endif\n"
  },
  {
    "path": "third_party/phlib/jsonc/json_tokener.c",
    "content": "/*\n * $Id: json_tokener.c,v 1.20 2006/07/25 03:24:50 mclark Exp $\n *\n * Copyright (c) 2004, 2005 Metaparadigm Pte. Ltd.\n * Michael Clark <michael@metaparadigm.com>\n *\n * This library is free software; you can redistribute it and/or modify\n * it under the terms of the MIT license. See COPYING for details.\n *\n *\n * Copyright (c) 2008-2009 Yahoo! Inc.  All rights reserved.\n * The copyrights to the contents of this file are licensed under the MIT License\n * (http://www.opensource.org/licenses/mit-license.php)\n */\n\n#include \"config.h\"\n\n#include <math.h>\n#include <stdio.h>\n#include <stdlib.h>\n#include <stddef.h>\n#include <ctype.h>\n#include <string.h>\n#include <limits.h>\n\n#include \"bits.h\"\n#include \"debug.h\"\n#include \"printbuf.h\"\n#include \"arraylist.h\"\n#include \"json_inttypes.h\"\n#include \"json_object.h\"\n#include \"json_tokener.h\"\n#include \"json_util.h\"\n\n#ifdef HAVE_LOCALE_H\n#include <locale.h>\n#endif /* HAVE_LOCALE_H */\n\n#if !HAVE_STRDUP && defined(_MSC_VER)\n  /* MSC has the version as _strdup */\n# define strdup _strdup\n#elif !HAVE_STRDUP\n# error You do not have strdup on your system.\n#endif /* HAVE_STRDUP */\n\n#if !HAVE_STRNCASECMP && defined(_MSC_VER)\n  /* MSC has the version as _strnicmp */\n# define strncasecmp _strnicmp\n#elif !HAVE_STRNCASECMP\n# error You do not have strncasecmp on your system.\n#endif /* HAVE_STRNCASECMP */\n\n/* Use C99 NAN by default; if not available, nan(\"\") should work too. */\n#ifndef NAN\n#define NAN nan(\"\")\n#endif /* !NAN */\n\nstatic const char json_null_str[] = \"null\";\nstatic const int json_null_str_len = sizeof(json_null_str) - 1;\nstatic const char json_inf_str[] = \"Infinity\";\nstatic const int json_inf_str_len = sizeof(json_inf_str) - 1;\nstatic const char json_nan_str[] = \"NaN\";\nstatic const int json_nan_str_len = sizeof(json_nan_str) - 1;\nstatic const char json_true_str[] = \"true\";\nstatic const int json_true_str_len = sizeof(json_true_str) - 1;\nstatic const char json_false_str[] = \"false\";\nstatic const int json_false_str_len = sizeof(json_false_str) - 1;\n\nstatic const char* json_tokener_errors[] = {\n  \"success\",\n  \"continue\",\n  \"nesting too deep\",\n  \"unexpected end of data\",\n  \"unexpected character\",\n  \"null expected\",\n  \"boolean expected\",\n  \"number expected\",\n  \"array value separator ',' expected\",\n  \"quoted object property name expected\",\n  \"object property name separator ':' expected\",\n  \"object value separator ',' expected\",\n  \"invalid string sequence\",\n  \"expected comment\",\n  \"buffer size overflow\"\n};\n\nconst char *json_tokener_error_desc(enum json_tokener_error jerr)\n{\n    int jerr_int = (int)jerr;\n    if (jerr_int < 0 || jerr_int >= (int)(sizeof(json_tokener_errors) / sizeof(json_tokener_errors[0])))\n        return \"Unknown error, invalid json_tokener_error value passed to json_tokener_error_desc()\";\n    return json_tokener_errors[jerr];\n}\n\nenum json_tokener_error json_tokener_get_error(json_tokener *tok)\n{\n    return tok->err;\n}\n\n/* Stuff for decoding unicode sequences */\n#define IS_HIGH_SURROGATE(uc) (((uc) & 0xFC00) == 0xD800)\n#define IS_LOW_SURROGATE(uc)  (((uc) & 0xFC00) == 0xDC00)\n#define DECODE_SURROGATE_PAIR(hi,lo) ((((hi) & 0x3FF) << 10) + ((lo) & 0x3FF) + 0x10000)\nstatic unsigned char utf8_replacement_char[3] = { 0xEF, 0xBF, 0xBD };\n\nstruct json_tokener* json_tokener_new_ex(int depth)\n{\n  struct json_tokener *tok;\n\n  tok = (struct json_tokener*)calloc(1, sizeof(struct json_tokener));\n  if (!tok) return NULL;\n  tok->stack = (struct json_tokener_srec *)calloc(depth, sizeof(struct json_tokener_srec));\n  if (!tok->stack) {\n    free(tok);\n    return NULL;\n  }\n  tok->pb = printbuf_new();\n  tok->max_depth = depth;\n  json_tokener_reset(tok);\n  return tok;\n}\n\nstruct json_tokener* json_tokener_new(void)\n{\n  return json_tokener_new_ex(JSON_TOKENER_DEFAULT_DEPTH);\n}\n\nvoid json_tokener_free(struct json_tokener *tok)\n{\n  json_tokener_reset(tok);\n  if (tok->pb) printbuf_free(tok->pb);\n  if (tok->stack) free(tok->stack);\n  free(tok);\n}\n\nstatic void json_tokener_reset_level(struct json_tokener *tok, int depth)\n{\n  tok->stack[depth].state = json_tokener_state_eatws;\n  tok->stack[depth].saved_state = json_tokener_state_start;\n  json_object_put(tok->stack[depth].current);\n  tok->stack[depth].current = NULL;\n  free(tok->stack[depth].obj_field_name);\n  tok->stack[depth].obj_field_name = NULL;\n}\n\nvoid json_tokener_reset(struct json_tokener *tok)\n{\n  int i;\n  if (!tok)\n    return;\n\n  for(i = tok->depth; i >= 0; i--)\n    json_tokener_reset_level(tok, i);\n  tok->depth = 0;\n  tok->err = json_tokener_success;\n}\n\nstruct json_object* json_tokener_parse(const char *str)\n{\n    enum json_tokener_error jerr_ignored;\n    struct json_object* obj;\n    obj = json_tokener_parse_verbose(str, &jerr_ignored);\n    return obj;\n}\n\nstruct json_object* json_tokener_parse_verbose(const char *str, enum json_tokener_error *error)\n{\n    struct json_tokener* tok;\n    struct json_object* obj;\n\n    tok = json_tokener_new();\n    if (!tok)\n      return NULL;\n    obj = json_tokener_parse_ex(tok, str, -1);\n    *error = tok->err;\n    if(tok->err != json_tokener_success) {\n        if (obj != NULL)\n            json_object_put(obj);\n        obj = NULL;\n    }\n\n    json_tokener_free(tok);\n    return obj;\n}\n\n#define state  tok->stack[tok->depth].state\n#define saved_state  tok->stack[tok->depth].saved_state\n#define current tok->stack[tok->depth].current\n#define obj_field_name tok->stack[tok->depth].obj_field_name\n\n/* Optimization:\n * json_tokener_parse_ex() consumed a lot of CPU in its main loop,\n * iterating character-by character.  A large performance boost is\n * achieved by using tighter loops to locally handle units such as\n * comments and strings.  Loops that handle an entire token within\n * their scope also gather entire strings and pass them to\n * printbuf_memappend() in a single call, rather than calling\n * printbuf_memappend() one char at a time.\n *\n * PEEK_CHAR() and ADVANCE_CHAR() macros are used for code that is\n * common to both the main loop and the tighter loops.\n */\n\n/* PEEK_CHAR(dest, tok) macro:\n *   Peeks at the current char and stores it in dest.\n *   Returns 1 on success, sets tok->err and returns 0 if no more chars.\n *   Implicit inputs:  str, len vars\n */\n#define PEEK_CHAR(dest, tok)                                                  \\\n  (((tok)->char_offset == len) ?                                          \\\n   (((tok)->depth == 0 && state == json_tokener_state_eatws && saved_state == json_tokener_state_finish) ? \\\n    (((tok)->err = json_tokener_success), 0)                              \\\n    :                                                                   \\\n    (((tok)->err = json_tokener_continue), 0)                             \\\n    ) :                                                                 \\\n   (((dest) = *str), 1)                                                 \\\n   )\n\n/* ADVANCE_CHAR() macro:\n *   Incrementes str & tok->char_offset.\n *   For convenience of existing conditionals, returns the old value of c (0 on eof)\n *   Implicit inputs:  c var\n */\n#define ADVANCE_CHAR(str, tok) \\\n  ( ++(str), ((tok)->char_offset)++, c)\n\n\n/* End optimization macro defs */\n\n\nstruct json_object* json_tokener_parse_ex(struct json_tokener *tok,\n                      const char *str, int len)\n{\n  struct json_object *obj = NULL;\n  char c = '\\1';\n#ifdef HAVE_SETLOCALE\n  char *oldlocale=NULL, *tmplocale;\n\n  tmplocale = setlocale(LC_NUMERIC, NULL);\n  if (tmplocale) oldlocale = strdup(tmplocale);\n  setlocale(LC_NUMERIC, \"C\");\n#endif\n\n  tok->char_offset = 0;\n  tok->err = json_tokener_success;\n\n  /* this interface is presently not 64-bit clean due to the int len argument\n     and the internal printbuf interface that takes 32-bit int len arguments\n     so the function limits the maximum string size to INT32_MAX (2GB).\n     If the function is called with len == -1 then strlen is called to check\n     the string length is less than INT32_MAX (2GB) */\n  if ((len < -1) || (len == -1 && strlen(str) > INT32_MAX)) {\n    tok->err = json_tokener_error_size;\n    return NULL;\n  }\n\n  while (PEEK_CHAR(c, tok)) {\n\n  redo_char:\n    switch(state) {\n\n    case json_tokener_state_eatws:\n      /* Advance until we change state */\n      while (isspace((int)c)) {\n    if ((!ADVANCE_CHAR(str, tok)) || (!PEEK_CHAR(c, tok)))\n      goto out;\n      }\n      if(c == '/' && !(tok->flags & JSON_TOKENER_STRICT)) {\n    printbuf_reset(tok->pb);\n    printbuf_memappend_fast(tok->pb, &c, 1);\n    state = json_tokener_state_comment_start;\n      } else {\n    state = saved_state;\n    goto redo_char;\n      }\n      break;\n\n    case json_tokener_state_start:\n      switch(c) {\n      case '{':\n    state = json_tokener_state_eatws;\n    saved_state = json_tokener_state_object_field_start;\n    current = json_object_new_object();\n    break;\n      case '[':\n    state = json_tokener_state_eatws;\n    saved_state = json_tokener_state_array;\n    current = json_object_new_array();\n    break;\n      case 'I':\n      case 'i':\n    state = json_tokener_state_inf;\n    printbuf_reset(tok->pb);\n    tok->st_pos = 0;\n    goto redo_char;\n      case 'N':\n      case 'n':\n    state = json_tokener_state_null; // or NaN\n    printbuf_reset(tok->pb);\n    tok->st_pos = 0;\n    goto redo_char;\n      case '\\'':\n        if (tok->flags & JSON_TOKENER_STRICT) {\n            /* in STRICT mode only double-quote are allowed */\n            tok->err = json_tokener_error_parse_unexpected;\n            goto out;\n        }\n      case '\"':\n    state = json_tokener_state_string;\n    printbuf_reset(tok->pb);\n    tok->quote_char = c;\n    break;\n      case 'T':\n      case 't':\n      case 'F':\n      case 'f':\n    state = json_tokener_state_boolean;\n    printbuf_reset(tok->pb);\n    tok->st_pos = 0;\n    goto redo_char;\n#if defined(__GNUC__)\n      case '0' ... '9':\n#else\n      case '0':\n      case '1':\n      case '2':\n      case '3':\n      case '4':\n      case '5':\n      case '6':\n      case '7':\n      case '8':\n      case '9':\n#endif\n      case '-':\n    state = json_tokener_state_number;\n    printbuf_reset(tok->pb);\n    tok->is_double = 0;\n    goto redo_char;\n      default:\n    tok->err = json_tokener_error_parse_unexpected;\n    goto out;\n      }\n      break;\n\n    case json_tokener_state_finish:\n      if(tok->depth == 0) goto out;\n      obj = json_object_get(current);\n      json_tokener_reset_level(tok, tok->depth);\n      tok->depth--;\n      goto redo_char;\n\n    case json_tokener_state_inf: /* aka starts with 'i' */\n      {\n    int size;\n    int size_inf;\n    int is_negative = 0;\n\n    printbuf_memappend_fast(tok->pb, &c, 1);\n    size = json_min(tok->st_pos+1, json_null_str_len);\n    size_inf = json_min(tok->st_pos+1, json_inf_str_len);\n    char *infbuf = tok->pb->buf;\n    if (*infbuf == '-')\n    {\n        infbuf++;\n        is_negative = 1;\n    }\n    if ((!(tok->flags & JSON_TOKENER_STRICT) &&\n              strncasecmp(json_inf_str, infbuf, size_inf) == 0) ||\n             (strncmp(json_inf_str, infbuf, size_inf) == 0)\n            )\n    {\n        if (tok->st_pos == json_inf_str_len)\n        {\n            current = json_object_new_double(is_negative ? -INFINITY : INFINITY); \n            saved_state = json_tokener_state_finish;\n            state = json_tokener_state_eatws;\n            goto redo_char;\n        }\n    } else {\n        tok->err = json_tokener_error_parse_unexpected;\n        goto out;\n    }\n    tok->st_pos++;\n      }\n      break;\n    case json_tokener_state_null: /* aka starts with 'n' */\n      {\n    int size;\n    int size_nan;\n    printbuf_memappend_fast(tok->pb, &c, 1);\n    size = json_min(tok->st_pos+1, json_null_str_len);\n    size_nan = json_min(tok->st_pos+1, json_nan_str_len);\n    if((!(tok->flags & JSON_TOKENER_STRICT) &&\n      strncasecmp(json_null_str, tok->pb->buf, size) == 0)\n      || (strncmp(json_null_str, tok->pb->buf, size) == 0)\n      ) {\n      if (tok->st_pos == json_null_str_len) {\n        current = NULL;\n        saved_state = json_tokener_state_finish;\n        state = json_tokener_state_eatws;\n        goto redo_char;\n      }\n    }\n    else if ((!(tok->flags & JSON_TOKENER_STRICT) &&\n              strncasecmp(json_nan_str, tok->pb->buf, size_nan) == 0) ||\n             (strncmp(json_nan_str, tok->pb->buf, size_nan) == 0)\n            )\n    {\n        if (tok->st_pos == json_nan_str_len)\n        {\n            current = json_object_new_double(NAN);\n            saved_state = json_tokener_state_finish;\n            state = json_tokener_state_eatws;\n            goto redo_char;\n        }\n    } else {\n      tok->err = json_tokener_error_parse_null;\n      goto out;\n    }\n    tok->st_pos++;\n      }\n      break;\n\n    case json_tokener_state_comment_start:\n      if(c == '*') {\n    state = json_tokener_state_comment;\n      } else if(c == '/') {\n    state = json_tokener_state_comment_eol;\n      } else {\n    tok->err = json_tokener_error_parse_comment;\n    goto out;\n      }\n      printbuf_memappend_fast(tok->pb, &c, 1);\n      break;\n\n    case json_tokener_state_comment:\n              {\n          /* Advance until we change state */\n          const char *case_start = str;\n          while(c != '*') {\n            if (!ADVANCE_CHAR(str, tok) || !PEEK_CHAR(c, tok)) {\n              printbuf_memappend_fast(tok->pb, case_start, str-case_start);\n              goto out;\n            }\n          }\n          printbuf_memappend_fast(tok->pb, case_start, 1+str-case_start);\n          state = json_tokener_state_comment_end;\n        }\n            break;\n\n    case json_tokener_state_comment_eol:\n      {\n    /* Advance until we change state */\n    const char *case_start = str;\n    while(c != '\\n') {\n      if (!ADVANCE_CHAR(str, tok) || !PEEK_CHAR(c, tok)) {\n        printbuf_memappend_fast(tok->pb, case_start, str-case_start);\n        goto out;\n      }\n    }\n    printbuf_memappend_fast(tok->pb, case_start, str-case_start);\n    MC_DEBUG(\"json_tokener_comment: %s\\n\", tok->pb->buf);\n    state = json_tokener_state_eatws;\n      }\n      break;\n\n    case json_tokener_state_comment_end:\n      printbuf_memappend_fast(tok->pb, &c, 1);\n      if(c == '/') {\n    MC_DEBUG(\"json_tokener_comment: %s\\n\", tok->pb->buf);\n    state = json_tokener_state_eatws;\n      } else {\n    state = json_tokener_state_comment;\n      }\n      break;\n\n    case json_tokener_state_string:\n      {\n    /* Advance until we change state */\n    const char *case_start = str;\n    while(1) {\n      if(c == tok->quote_char) {\n        printbuf_memappend_fast(tok->pb, case_start, str-case_start);\n        current = json_object_new_string_len(tok->pb->buf, tok->pb->bpos);\n        saved_state = json_tokener_state_finish;\n        state = json_tokener_state_eatws;\n        break;\n      } else if(c == '\\\\') {\n        printbuf_memappend_fast(tok->pb, case_start, str-case_start);\n        saved_state = json_tokener_state_string;\n        state = json_tokener_state_string_escape;\n        break;\n      }\n      if (!ADVANCE_CHAR(str, tok) || !PEEK_CHAR(c, tok)) {\n        printbuf_memappend_fast(tok->pb, case_start, str-case_start);\n        goto out;\n      }\n    }\n      }\n      break;\n\n    case json_tokener_state_string_escape:\n      switch(c) {\n      case '\"':\n      case '\\\\':\n      case '/':\n    printbuf_memappend_fast(tok->pb, &c, 1);\n    state = saved_state;\n    break;\n      case 'b':\n      case 'n':\n      case 'r':\n      case 't':\n      case 'f':\n    if(c == 'b') printbuf_memappend_fast(tok->pb, \"\\b\", 1);\n    else if(c == 'n') printbuf_memappend_fast(tok->pb, \"\\n\", 1);\n    else if(c == 'r') printbuf_memappend_fast(tok->pb, \"\\r\", 1);\n    else if(c == 't') printbuf_memappend_fast(tok->pb, \"\\t\", 1);\n    else if(c == 'f') printbuf_memappend_fast(tok->pb, \"\\f\", 1);\n    state = saved_state;\n    break;\n      case 'u':\n    tok->ucs_char = 0;\n    tok->st_pos = 0;\n    state = json_tokener_state_escape_unicode;\n    break;\n      default:\n    tok->err = json_tokener_error_parse_string;\n    goto out;\n      }\n      break;\n\n    case json_tokener_state_escape_unicode:\n    {\n          unsigned int got_hi_surrogate = 0;\n\n      /* Handle a 4-byte sequence, or two sequences if a surrogate pair */\n      while(1) {\n        if(strchr(json_hex_chars, c)) {\n          tok->ucs_char += ((unsigned int)hexdigit(c) << ((3-tok->st_pos++)*4));\n          if(tok->st_pos == 4) {\n        unsigned char unescaped_utf[4];\n\n                if (got_hi_surrogate) {\n          if (IS_LOW_SURROGATE(tok->ucs_char)) {\n                    /* Recalculate the ucs_char, then fall thru to process normally */\n                    tok->ucs_char = DECODE_SURROGATE_PAIR(got_hi_surrogate, tok->ucs_char);\n                  } else {\n                    /* Hi surrogate was not followed by a low surrogate */\n                    /* Replace the hi and process the rest normally */\n            printbuf_memappend_fast(tok->pb, (char*)utf8_replacement_char, 3);\n                  }\n                  got_hi_surrogate = 0;\n                }\n\n        if (tok->ucs_char < 0x80) {\n          unescaped_utf[0] = tok->ucs_char;\n          printbuf_memappend_fast(tok->pb, (char*)unescaped_utf, 1);\n        } else if (tok->ucs_char < 0x800) {\n          unescaped_utf[0] = 0xc0 | (tok->ucs_char >> 6);\n          unescaped_utf[1] = 0x80 | (tok->ucs_char & 0x3f);\n          printbuf_memappend_fast(tok->pb, (char*)unescaped_utf, 2);\n        } else if (IS_HIGH_SURROGATE(tok->ucs_char)) {\n                  /* Got a high surrogate.  Remember it and look for the\n                   * the beginning of another sequence, which should be the\n                   * low surrogate.\n                   */\n                  got_hi_surrogate = tok->ucs_char;\n                  /* Not at end, and the next two chars should be \"\\u\" */\n                  if ((tok->char_offset+1 != len) &&\n                      (tok->char_offset+2 != len) &&\n                      (str[1] == '\\\\') &&\n                      (str[2] == 'u'))\n                  {\n                /* Advance through the 16 bit surrogate, and move on to the\n                 * next sequence. The next step is to process the following\n                 * characters.\n                 */\n                if( !ADVANCE_CHAR(str, tok) || !ADVANCE_CHAR(str, tok) ) {\n                    printbuf_memappend_fast(tok->pb, (char*)utf8_replacement_char, 3);\n                }\n                    /* Advance to the first char of the next sequence and\n                     * continue processing with the next sequence.\n                     */\n                if (!ADVANCE_CHAR(str, tok) || !PEEK_CHAR(c, tok)) {\n                  printbuf_memappend_fast(tok->pb, (char*)utf8_replacement_char, 3);\n                  goto out;\n                    }\n                tok->ucs_char = 0;\n                    tok->st_pos = 0;\n                    continue; /* other json_tokener_state_escape_unicode */\n                  } else {\n                    /* Got a high surrogate without another sequence following\n                     * it.  Put a replacement char in for the hi surrogate\n                     * and pretend we finished.\n                     */\n            printbuf_memappend_fast(tok->pb, (char*)utf8_replacement_char, 3);\n                  }\n        } else if (IS_LOW_SURROGATE(tok->ucs_char)) {\n                  /* Got a low surrogate not preceded by a high */\n          printbuf_memappend_fast(tok->pb, (char*)utf8_replacement_char, 3);\n                } else if (tok->ucs_char < 0x10000) {\n          unescaped_utf[0] = 0xe0 | (tok->ucs_char >> 12);\n          unescaped_utf[1] = 0x80 | ((tok->ucs_char >> 6) & 0x3f);\n          unescaped_utf[2] = 0x80 | (tok->ucs_char & 0x3f);\n          printbuf_memappend_fast(tok->pb, (char*)unescaped_utf, 3);\n        } else if (tok->ucs_char < 0x110000) {\n          unescaped_utf[0] = 0xf0 | ((tok->ucs_char >> 18) & 0x07);\n          unescaped_utf[1] = 0x80 | ((tok->ucs_char >> 12) & 0x3f);\n          unescaped_utf[2] = 0x80 | ((tok->ucs_char >> 6) & 0x3f);\n          unescaped_utf[3] = 0x80 | (tok->ucs_char & 0x3f);\n          printbuf_memappend_fast(tok->pb, (char*)unescaped_utf, 4);\n        } else {\n                  /* Don't know what we got--insert the replacement char */\n          printbuf_memappend_fast(tok->pb, (char*)utf8_replacement_char, 3);\n                }\n        state = saved_state;\n        break;\n          }\n        } else {\n          tok->err = json_tokener_error_parse_string;\n          goto out;\n        }\n      if (!ADVANCE_CHAR(str, tok) || !PEEK_CHAR(c, tok)) {\n            if (got_hi_surrogate) /* Clean up any pending chars */\n          printbuf_memappend_fast(tok->pb, (char*)utf8_replacement_char, 3);\n        goto out;\n      }\n    }\n      }\n      break;\n\n    case json_tokener_state_boolean:\n      {\n    int size1, size2;\n    printbuf_memappend_fast(tok->pb, &c, 1);\n    size1 = json_min(tok->st_pos+1, json_true_str_len);\n    size2 = json_min(tok->st_pos+1, json_false_str_len);\n    if((!(tok->flags & JSON_TOKENER_STRICT) &&\n      strncasecmp(json_true_str, tok->pb->buf, size1) == 0)\n      || (strncmp(json_true_str, tok->pb->buf, size1) == 0)\n      ) {\n      if(tok->st_pos == json_true_str_len) {\n        current = json_object_new_boolean(1);\n        saved_state = json_tokener_state_finish;\n        state = json_tokener_state_eatws;\n        goto redo_char;\n      }\n    } else if((!(tok->flags & JSON_TOKENER_STRICT) &&\n      strncasecmp(json_false_str, tok->pb->buf, size2) == 0)\n      || (strncmp(json_false_str, tok->pb->buf, size2) == 0)) {\n      if(tok->st_pos == json_false_str_len) {\n        current = json_object_new_boolean(0);\n        saved_state = json_tokener_state_finish;\n        state = json_tokener_state_eatws;\n        goto redo_char;\n      }\n    } else {\n      tok->err = json_tokener_error_parse_boolean;\n      goto out;\n    }\n    tok->st_pos++;\n      }\n      break;\n\n    case json_tokener_state_number:\n      {\n    /* Advance until we change state */\n    const char *case_start = str;\n    int case_len=0;\n    while(c && strchr(json_number_chars, c)) {\n      ++case_len;\n      if(c == '.' || c == 'e' || c == 'E')\n        tok->is_double = 1;\n      if (!ADVANCE_CHAR(str, tok) || !PEEK_CHAR(c, tok)) {\n        printbuf_memappend_fast(tok->pb, case_start, case_len);\n        goto out;\n      }\n    }\n        if (case_len>0)\n          printbuf_memappend_fast(tok->pb, case_start, case_len);\n\n    // Check for -Infinity\n    if (tok->pb->buf[0] == '-' && case_len == 1 &&\n        (c == 'i' || c == 'I'))\n    {\n        state = json_tokener_state_inf;\n        goto redo_char;\n    }\n      }\n      {\n    int64_t num64;\n    double  numd;\n    if (!tok->is_double && json_parse_int64(tok->pb->buf, &num64) == 0) {\n        if (num64 && tok->pb->buf[0]=='0' && (tok->flags & JSON_TOKENER_STRICT)) {\n            /* in strict mode, number must not start with 0 */\n            tok->err = json_tokener_error_parse_number;\n            goto out;\n        }\n        current = json_object_new_int64(num64);\n    }\n    else if(tok->is_double && json_parse_double(tok->pb->buf, &numd) == 0)\n    {\n          current = json_object_new_double_s(numd, tok->pb->buf);\n        } else {\n          tok->err = json_tokener_error_parse_number;\n          goto out;\n        }\n        saved_state = json_tokener_state_finish;\n        state = json_tokener_state_eatws;\n        goto redo_char;\n      }\n      break;\n\n    case json_tokener_state_array_after_sep:\n    case json_tokener_state_array:\n      if(c == ']') {\n        if (state == json_tokener_state_array_after_sep &&\n            (tok->flags & JSON_TOKENER_STRICT))\n        {\n            tok->err = json_tokener_error_parse_unexpected;\n            goto out;\n        }\n    saved_state = json_tokener_state_finish;\n    state = json_tokener_state_eatws;\n      } else {\n    if(tok->depth >= tok->max_depth-1) {\n      tok->err = json_tokener_error_depth;\n      goto out;\n    }\n    state = json_tokener_state_array_add;\n    tok->depth++;\n    json_tokener_reset_level(tok, tok->depth);\n    goto redo_char;\n      }\n      break;\n\n    case json_tokener_state_array_add:\n      json_object_array_add(current, obj);\n      saved_state = json_tokener_state_array_sep;\n      state = json_tokener_state_eatws;\n      goto redo_char;\n\n    case json_tokener_state_array_sep:\n      if(c == ']') {\n    saved_state = json_tokener_state_finish;\n    state = json_tokener_state_eatws;\n      } else if(c == ',') {\n    saved_state = json_tokener_state_array_after_sep;\n    state = json_tokener_state_eatws;\n      } else {\n    tok->err = json_tokener_error_parse_array;\n    goto out;\n      }\n      break;\n\n    case json_tokener_state_object_field_start:\n    case json_tokener_state_object_field_start_after_sep:\n      if(c == '}') {\n        if (state == json_tokener_state_object_field_start_after_sep &&\n            (tok->flags & JSON_TOKENER_STRICT))\n        {\n            tok->err = json_tokener_error_parse_unexpected;\n            goto out;\n        }\n    saved_state = json_tokener_state_finish;\n    state = json_tokener_state_eatws;\n      } else if (c == '\"' || c == '\\'') {\n    tok->quote_char = c;\n    printbuf_reset(tok->pb);\n    state = json_tokener_state_object_field;\n      } else {\n    tok->err = json_tokener_error_parse_object_key_name;\n    goto out;\n      }\n      break;\n\n    case json_tokener_state_object_field:\n      {\n    /* Advance until we change state */\n    const char *case_start = str;\n    while(1) {\n      if(c == tok->quote_char) {\n        printbuf_memappend_fast(tok->pb, case_start, str-case_start);\n        obj_field_name = strdup(tok->pb->buf);\n        saved_state = json_tokener_state_object_field_end;\n        state = json_tokener_state_eatws;\n        break;\n      } else if(c == '\\\\') {\n        printbuf_memappend_fast(tok->pb, case_start, str-case_start);\n        saved_state = json_tokener_state_object_field;\n        state = json_tokener_state_string_escape;\n        break;\n      }\n      if (!ADVANCE_CHAR(str, tok) || !PEEK_CHAR(c, tok)) {\n        printbuf_memappend_fast(tok->pb, case_start, str-case_start);\n        goto out;\n      }\n    }\n      }\n      break;\n\n    case json_tokener_state_object_field_end:\n      if(c == ':') {\n    saved_state = json_tokener_state_object_value;\n    state = json_tokener_state_eatws;\n      } else {\n    tok->err = json_tokener_error_parse_object_key_sep;\n    goto out;\n      }\n      break;\n\n    case json_tokener_state_object_value:\n      if(tok->depth >= tok->max_depth-1) {\n    tok->err = json_tokener_error_depth;\n    goto out;\n      }\n      state = json_tokener_state_object_value_add;\n      tok->depth++;\n      json_tokener_reset_level(tok, tok->depth);\n      goto redo_char;\n\n    case json_tokener_state_object_value_add:\n      json_object_object_add(current, obj_field_name, obj);\n      free(obj_field_name);\n      obj_field_name = NULL;\n      saved_state = json_tokener_state_object_sep;\n      state = json_tokener_state_eatws;\n      goto redo_char;\n\n    case json_tokener_state_object_sep:\n      if(c == '}') {\n    saved_state = json_tokener_state_finish;\n    state = json_tokener_state_eatws;\n      } else if(c == ',') {\n    saved_state = json_tokener_state_object_field_start_after_sep;\n    state = json_tokener_state_eatws;\n      } else {\n    tok->err = json_tokener_error_parse_object_value_sep;\n    goto out;\n      }\n      break;\n\n    }\n    if (!ADVANCE_CHAR(str, tok))\n      goto out;\n  } /* while(POP_CHAR) */\n\n out:\n  if (c &&\n     (state == json_tokener_state_finish) &&\n     (tok->depth == 0) &&\n     (tok->flags & JSON_TOKENER_STRICT)) {\n      /* unexpected char after JSON data */\n      tok->err = json_tokener_error_parse_unexpected;\n  }\n  if (!c) { /* We hit an eof char (0) */\n    if(state != json_tokener_state_finish &&\n       saved_state != json_tokener_state_finish)\n      tok->err = json_tokener_error_parse_eof;\n  }\n\n#ifdef HAVE_SETLOCALE\n  setlocale(LC_NUMERIC, oldlocale);\n  if (oldlocale) free(oldlocale);\n#endif\n\n  if (tok->err == json_tokener_success)\n  {\n    json_object *ret = json_object_get(current);\n    int ii;\n\n    /* Partially reset, so we parse additional objects on subsequent calls. */\n    for(ii = tok->depth; ii >= 0; ii--)\n      json_tokener_reset_level(tok, ii);\n    return ret;\n  }\n\n  MC_DEBUG(\"json_tokener_parse_ex: error %s at offset %d\\n\",\n       json_tokener_errors[tok->err], tok->char_offset);\n  return NULL;\n}\n\nvoid json_tokener_set_flags(struct json_tokener *tok, int flags)\n{\n    tok->flags = flags;\n}\n"
  },
  {
    "path": "third_party/phlib/jsonc/json_tokener.h",
    "content": "/*\n * $Id: json_tokener.h,v 1.10 2006/07/25 03:24:50 mclark Exp $\n *\n * Copyright (c) 2004, 2005 Metaparadigm Pte. Ltd.\n * Michael Clark <michael@metaparadigm.com>\n *\n * This library is free software; you can redistribute it and/or modify\n * it under the terms of the MIT license. See COPYING for details.\n *\n */\n\n#ifndef _json_tokener_h_\n#define _json_tokener_h_\n\n#include <stddef.h>\n#include \"json_object.h\"\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\nenum json_tokener_error {\n  json_tokener_success,\n  json_tokener_continue,\n  json_tokener_error_depth,\n  json_tokener_error_parse_eof,\n  json_tokener_error_parse_unexpected,\n  json_tokener_error_parse_null,\n  json_tokener_error_parse_boolean,\n  json_tokener_error_parse_number,\n  json_tokener_error_parse_array,\n  json_tokener_error_parse_object_key_name,\n  json_tokener_error_parse_object_key_sep,\n  json_tokener_error_parse_object_value_sep,\n  json_tokener_error_parse_string,\n  json_tokener_error_parse_comment,\n  json_tokener_error_size\n};\n\nenum json_tokener_state {\n  json_tokener_state_eatws,\n  json_tokener_state_start,\n  json_tokener_state_finish,\n  json_tokener_state_null,\n  json_tokener_state_comment_start,\n  json_tokener_state_comment,\n  json_tokener_state_comment_eol,\n  json_tokener_state_comment_end,\n  json_tokener_state_string,\n  json_tokener_state_string_escape,\n  json_tokener_state_escape_unicode,\n  json_tokener_state_boolean,\n  json_tokener_state_number,\n  json_tokener_state_array,\n  json_tokener_state_array_add,\n  json_tokener_state_array_sep,\n  json_tokener_state_object_field_start,\n  json_tokener_state_object_field,\n  json_tokener_state_object_field_end,\n  json_tokener_state_object_value,\n  json_tokener_state_object_value_add,\n  json_tokener_state_object_sep,\n  json_tokener_state_array_after_sep,\n  json_tokener_state_object_field_start_after_sep,\n  json_tokener_state_inf\n};\n\nstruct json_tokener_srec\n{\n  enum json_tokener_state state, saved_state;\n  struct json_object *obj;\n  struct json_object *current;\n  char *obj_field_name;\n};\n\n#define JSON_TOKENER_DEFAULT_DEPTH 32\n\nstruct json_tokener\n{\n  char *str;\n  struct printbuf *pb;\n  int max_depth, depth, is_double, st_pos, char_offset;\n  enum json_tokener_error err;\n  unsigned int ucs_char;\n  char quote_char;\n  struct json_tokener_srec *stack;\n  int flags;\n};\n\n/**\n * Be strict when parsing JSON input.  Use caution with\n * this flag as what is considered valid may become more\n * restrictive from one release to the next, causing your\n * code to fail on previously working input.\n *\n * This flag is not set by default.\n *\n * @see json_tokener_set_flags()\n */\n#define JSON_TOKENER_STRICT  0x01\n\n/**\n * Given an error previously returned by json_tokener_get_error(),\n * return a human readable description of the error.\n *\n * @return a generic error message is returned if an invalid error value is provided.\n */\nconst char *json_tokener_error_desc(enum json_tokener_error jerr);\n\n/**\n * Retrieve the error caused by the last call to json_tokener_parse_ex(),\n * or json_tokener_success if there is no error.\n *\n * When parsing a JSON string in pieces, if the tokener is in the middle\n * of parsing this will return json_tokener_continue.\n *\n * See also json_tokener_error_desc().\n */\nenum json_tokener_error json_tokener_get_error(struct json_tokener *tok);\n\nextern struct json_tokener* json_tokener_new(void);\nextern struct json_tokener* json_tokener_new_ex(int depth);\nextern void json_tokener_free(struct json_tokener *tok);\nextern void json_tokener_reset(struct json_tokener *tok);\nextern struct json_object* json_tokener_parse(const char *str);\nextern struct json_object* json_tokener_parse_verbose(const char *str, enum json_tokener_error *error);\n\n/**\n * Set flags that control how parsing will be done.\n */\nextern void json_tokener_set_flags(struct json_tokener *tok, int flags);\n\n/** \n * Parse a string and return a non-NULL json_object if a valid JSON value\n * is found.  The string does not need to be a JSON object or array;\n * it can also be a string, number or boolean value.\n *\n * A partial JSON string can be parsed.  If the parsing is incomplete,\n * NULL will be returned and json_tokener_get_error() will be return \n * json_tokener_continue.\n * json_tokener_parse_ex() can then be called with additional bytes in str\n * to continue the parsing.  \n *\n * If json_tokener_parse_ex() returns NULL and the error anything other than\n * json_tokener_continue, a fatal error has occurred and parsing must be\n * halted.  Then tok object must not be re-used until json_tokener_reset() is\n * called.\n *\n * When a valid JSON value is parsed, a non-NULL json_object will be\n * returned.  Also, json_tokener_get_error() will return json_tokener_success.\n * Be sure to check the type with json_object_is_type() or\n * json_object_get_type() before using the object.\n *\n * @b XXX this shouldn't use internal fields:\n * Trailing characters after the parsed value do not automatically cause an \n * error.  It is up to the caller to decide whether to treat this as an\n * error or to handle the additional characters, perhaps by parsing another\n * json value starting from that point.\n *\n * Extra characters can be detected by comparing the tok->char_offset against\n * the length of the last len parameter passed in.\n *\n * The tokener does \\b not maintain an internal buffer so the caller is\n * responsible for calling json_tokener_parse_ex with an appropriate str\n * parameter starting with the extra characters.\n *\n * This interface is presently not 64-bit clean due to the int len argument\n * so the function limits the maximum string size to INT32_MAX (2GB).\n * If the function is called with len == -1 then strlen is called to check\n * the string length is less than INT32_MAX (2GB)\n *\n * Example:\n * @code\njson_object *jobj = NULL;\nconst char *mystring = NULL;\nint stringlen = 0;\nenum json_tokener_error jerr;\ndo {\n\tmystring = ...  // get JSON string, e.g. read from file, etc...\n\tstringlen = strlen(mystring);\n\tjobj = json_tokener_parse_ex(tok, mystring, stringlen);\n} while ((jerr = json_tokener_get_error(tok)) == json_tokener_continue);\nif (jerr != json_tokener_success)\n{\n\tfprintf(stderr, \"Error: %s\\n\", json_tokener_error_desc(jerr));\n\t// Handle errors, as appropriate for your application.\n}\nif (tok->char_offset < stringlen) // XXX shouldn't access internal fields\n{\n\t// Handle extra characters after parsed object as desired.\n\t// e.g. issue an error, parse another object from that point, etc...\n}\n// Success, use jobj here.\n\n@endcode\n *\n * @param tok a json_tokener previously allocated with json_tokener_new()\n * @param str an string with any valid JSON expression, or portion of.  This does not need to be null terminated.\n * @param len the length of str\n */\nextern struct json_object* json_tokener_parse_ex(struct json_tokener *tok,\n\t\t\t\t\t\t const char *str, int len);\n\n#ifdef __cplusplus\n}\n#endif\n\n#endif\n"
  },
  {
    "path": "third_party/phlib/jsonc/json_util.c",
    "content": "/*\n * $Id: json_util.c,v 1.4 2006/01/30 23:07:57 mclark Exp $\n *\n * Copyright (c) 2004, 2005 Metaparadigm Pte. Ltd.\n * Michael Clark <michael@metaparadigm.com>\n *\n * This library is free software; you can redistribute it and/or modify\n * it under the terms of the MIT license. See COPYING for details.\n *\n */\n\n#include \"..\\include\\phbase.h\"\n#include \"..\\include\\phnative.h\"\n\n#include \"config.h\"\n#undef realloc\n\n#include <stdio.h>\n#include <stdlib.h>\n#include <stddef.h>\n#include <limits.h>\n#include <string.h>\n#include <errno.h>\n#include <ctype.h>\n\n#ifdef HAVE_SYS_TYPES_H\n#include <sys/types.h>\n#endif /* HAVE_SYS_TYPES_H */\n\n#ifdef HAVE_SYS_STAT_H\n#include <sys/stat.h>\n#endif /* HAVE_SYS_STAT_H */\n\n#ifdef HAVE_FCNTL_H\n#include <fcntl.h>\n#endif /* HAVE_FCNTL_H */\n\n#ifdef HAVE_UNISTD_H\n# include <unistd.h>\n#endif /* HAVE_UNISTD_H */\n\n#ifdef _WIN32\n# define WIN32_LEAN_AND_MEAN\n# include <windows.h>\n# include <io.h>\n#endif /* defined(_WIN32) */\n\n#if !defined(HAVE_OPEN) && defined(_WIN32)\n# define open _open\n#endif\n\n#if !defined(HAVE_SNPRINTF) && defined(_MSC_VER)\n  /* MSC has the version as _snprintf */\n# define snprintf _snprintf\n#elif !defined(HAVE_SNPRINTF)\n# error You do not have snprintf on your system.\n#endif /* HAVE_SNPRINTF */\n\n#include \"bits.h\"\n#include \"debug.h\"\n#include \"printbuf.h\"\n#include \"json_inttypes.h\"\n#include \"json_object.h\"\n#include \"json_tokener.h\"\n#include \"json_util.h\"\n\nstatic int sscanf_is_broken = 0;\nstatic int sscanf_is_broken_testdone = 0;\nstatic void sscanf_is_broken_test(void);\n\nstruct json_object* json_object_from_file(wchar_t *filename)\n{\n    NTSTATUS status;\n    HANDLE fileHandle;\n    IO_STATUS_BLOCK isb;\n    struct json_object *obj = NULL;\n\n    status = PhCreateFileWin32(\n        &fileHandle,\n        filename,\n        FILE_GENERIC_WRITE,\n        FILE_ATTRIBUTE_NORMAL,\n        FILE_SHARE_READ,\n        FILE_OPEN,\n        FILE_NON_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT\n        );\n\n    if (NT_SUCCESS(status))\n    {\n        PSTR data;\n        ULONG allocatedLength;\n        ULONG dataLength;\n        ULONG returnLength;\n        BYTE buffer[PAGE_SIZE];\n\n        allocatedLength = sizeof(buffer);\n        data = (PSTR)PhAllocate(allocatedLength);\n        dataLength = 0;\n\n        memset(data, 0, allocatedLength);\n\n        while (NT_SUCCESS(NtReadFile(fileHandle, NULL, NULL, NULL, &isb, buffer, PAGE_SIZE, NULL, NULL)))\n        {\n            returnLength = (ULONG)isb.Information;\n\n            if (returnLength == 0)\n                break;\n\n            if (allocatedLength < dataLength + returnLength)\n            {\n                allocatedLength *= 2;\n                data = (PSTR)PhReAllocate(data, allocatedLength);\n            }\n\n            memcpy(data + dataLength, buffer, returnLength);\n\n            dataLength += returnLength;\n        }\n\n        if (allocatedLength < dataLength + 1)\n        {\n            allocatedLength++;\n            data = (PSTR)PhReAllocate(data, allocatedLength);\n        }\n\n        data[dataLength] = 0;\n\n        obj = json_tokener_parse(data);\n\n        PhFree(data);\n    }\n\n    return obj;\n}\n\n/* extended \"format and write to file\" function */\n\nint json_object_to_file_ext(wchar_t *filename, struct json_object *obj, int flags)\n{\n    NTSTATUS status;\n    HANDLE fileHandle;\n    IO_STATUS_BLOCK isb;\n    PSTR json_str;\n   \n    if (!(json_str = json_object_to_json_string_ext(obj, flags)))\n        return -1;\n\n    status = PhCreateFileWin32(\n        &fileHandle,\n        filename,\n        FILE_GENERIC_WRITE,\n        FILE_ATTRIBUTE_NORMAL,\n        FILE_SHARE_READ,\n        FILE_OVERWRITE_IF,\n        FILE_NON_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT\n        );\n\n    if (!NT_SUCCESS(status))\n        return -1;\n\n    status = NtWriteFile(\n        fileHandle, \n        NULL, \n        NULL, \n        NULL,\n        &isb, \n        json_str, \n        (ULONG)strlen(json_str),\n        NULL, \n        NULL\n        );\n\n    if (!NT_SUCCESS(status))\n    {\n        NtClose(fileHandle);\n        return -1;\n    }\n\n    NtClose(fileHandle);\n    return 0;\n}\n\n// backwards compatible \"format and write to file\" function\n\nint json_object_to_file(wchar_t *FileName, struct json_object *obj)\n{\n    return json_object_to_file_ext(FileName, obj, JSON_C_TO_STRING_PRETTY);\n}\n\nint json_parse_double(const char *buf, double *retval)\n{\n  return (sscanf_s(buf, \"%lf\", retval)==1 ? 0 : 1);\n}\n\n/*\n * Not all implementations of sscanf actually work properly.\n * Check whether the one we're currently using does, and if\n * it's broken, enable the workaround code.\n */\nstatic void sscanf_is_broken_test()\n{\n    int64_t num64;\n    int ret_errno, is_int64_min, ret_errno2, is_int64_max;\n\n    sscanf_s(\" -01234567890123456789012345\", \"%\" SCNd64, &num64);\n    ret_errno = errno;\n    is_int64_min = (num64 == INT64_MIN);\n\n    sscanf_s(\" 01234567890123456789012345\", \"%\" SCNd64, &num64);\n    ret_errno2 = errno;\n    is_int64_max = (num64 == INT64_MAX);\n\n    if (ret_errno != ERANGE || !is_int64_min ||\n        ret_errno2 != ERANGE || !is_int64_max)\n    {\n        MC_DEBUG(\"sscanf_is_broken_test failed, enabling workaround code\\n\");\n        sscanf_is_broken = 1;\n    }\n}\n\nint json_parse_int64(const char *buf, int64_t *retval)\n{\n    int64_t num64;\n    const char *buf_sig_digits;\n    int orig_has_neg;\n    int saved_errno;\n\n    if (!sscanf_is_broken_testdone)\n    {\n        sscanf_is_broken_test();\n        sscanf_is_broken_testdone = 1;\n    }\n\n    // Skip leading spaces\n    while (isspace((int)*buf) && *buf)\n        buf++;\n\n    errno = 0; // sscanf won't always set errno, so initialize\n\n    if (sscanf_s(buf, \"%\" SCNd64, &num64) != 1)\n    {\n        MC_DEBUG(\"Failed to parse, sscanf != 1\\n\");\n        return 1;\n    }\n\n    saved_errno = errno;\n    buf_sig_digits = buf;\n    orig_has_neg = 0;\n    if (*buf_sig_digits == '-')\n    {\n        buf_sig_digits++;\n        orig_has_neg = 1;\n    }\n\n    // Not all sscanf implementations actually work\n    if (sscanf_is_broken && saved_errno != ERANGE)\n    {\n        char buf_cmp[100];\n        char *buf_cmp_start = buf_cmp;\n        int recheck_has_neg = 0;\n        int buf_cmp_len;\n\n        // Skip leading zeros, but keep at least one digit\n        while (buf_sig_digits[0] == '0' && buf_sig_digits[1] != '\\0')\n            buf_sig_digits++;\n        if (num64 == 0) // assume all sscanf impl's will parse -0 to 0\n            orig_has_neg = 0; // \"-0\" is the same as just plain \"0\"\n\n        _snprintf_s(buf_cmp_start, sizeof(buf_cmp), _TRUNCATE, \"%\" PRId64, num64);\n        if (*buf_cmp_start == '-')\n        {\n            recheck_has_neg = 1;\n            buf_cmp_start++;\n        }\n        // No need to skip leading spaces or zeros here.\n\n        buf_cmp_len = (int)strlen(buf_cmp_start);\n        /**\n         * If the sign is different, or\n         * some of the digits are different, or\n         * there is another digit present in the original string\n         * then we have NOT successfully parsed the value.\n         */\n        if (orig_has_neg != recheck_has_neg ||\n            strncmp(buf_sig_digits, buf_cmp_start, strlen(buf_cmp_start)) != 0 ||\n            ((int)strlen(buf_sig_digits) != buf_cmp_len &&\n             isdigit((int)buf_sig_digits[buf_cmp_len])\n            )\n           )\n        {\n            saved_errno = ERANGE;\n        }\n    }\n\n    // Not all sscanf impl's set the value properly when out of range.\n    // Always do this, even for properly functioning implementations,\n    // since it shouldn't slow things down much.\n    if (saved_errno == ERANGE)\n    {\n        if (orig_has_neg)\n            num64 = INT64_MIN;\n        else\n            num64 = INT64_MAX;\n    }\n    *retval = num64;\n    return 0;\n}\n\n#ifndef HAVE_REALLOC\nvoid* rpl_realloc(void* p, size_t n)\n{\n    if (n == 0)\n        n = 1;\n    if (p == 0)\n        return malloc(n);\n    return realloc(p, n);\n}\n#endif\n\n#define NELEM(a)        (sizeof(a) / sizeof(a[0]))\nstatic const char* json_type_name[] = {\n  /* If you change this, be sure to update the enum json_type definition too */\n  \"null\",\n  \"boolean\",\n  \"double\",\n  \"int\",\n  \"object\",\n  \"array\",\n  \"string\",\n};\n\nconst char *json_type_to_name(enum json_type o_type)\n{\n    int o_type_int = (int)o_type;\n    if (o_type_int < 0 || o_type_int >= (int)NELEM(json_type_name))\n    {\n        MC_ERROR(\"json_type_to_name: type %d is out of range [0,%d]\\n\", o_type, NELEM(json_type_name));\n        return NULL;\n    }\n    return json_type_name[o_type];\n}\n\n"
  },
  {
    "path": "third_party/phlib/jsonc/json_util.h",
    "content": "/*\n * $Id: json_util.h,v 1.4 2006/01/30 23:07:57 mclark Exp $\n *\n * Copyright (c) 2004, 2005 Metaparadigm Pte. Ltd.\n * Michael Clark <michael@metaparadigm.com>\n *\n * This library is free software; you can redistribute it and/or modify\n * it under the terms of the MIT license. See COPYING for details.\n *\n */\n\n#ifndef _json_util_h_\n#define _json_util_h_\n\n#include \"json_object.h\"\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\n#define JSON_FILE_BUF_SIZE 4096\n\n/* utility functions */\nextern struct json_object* json_object_from_file(wchar_t *filename);\nextern int json_object_to_file(wchar_t *FileName, struct json_object *obj);\nextern int json_object_to_file_ext(wchar_t *FileName, struct json_object *obj, int flags);\nextern int json_parse_int64(const char *buf, int64_t *retval);\nextern int json_parse_double(const char *buf, double *retval);\n\n\n/**\n * Return a string describing the type of the object.\n * e.g. \"int\", or \"object\", etc...\n */\nextern const char *json_type_to_name(enum json_type o_type);\n\n#ifdef __cplusplus\n}\n#endif\n\n#endif\n"
  },
  {
    "path": "third_party/phlib/jsonc/libjson.c",
    "content": "\n/* dummy source file for compatibility purposes */\n\n#if defined(HAVE_CDEFS_H)\n#include <sys/cdefs.h>\n#endif\n\n#ifndef __warn_references\n\n#if defined(__GNUC__)  && defined (HAS_GNU_WARNING_LONG)\n\n#define __warn_references(sym,msg)                  \\\n  __asm__(\".section .gnu\" #sym \",\\n\\t.ascii \\\"\" msg \"\\\"\\n\\t.text\");\n\n#else\n#define __warn_references(sym,msg)    /* nothing */\n#endif\n\n#endif \n\n#include \"json_object.h\"\n\n__warn_references(json_object_get, \"Warning: please link against libjson-c instead of libjson\");\n\n/*        __asm__(\".section .gnu.warning.\" __STRING(sym)  \\\n            \" ; .ascii \\\"\" msg \"\\\" ; .text\") */\n"
  },
  {
    "path": "third_party/phlib/jsonc/linkhash.c",
    "content": "/*\n * $Id: linkhash.c,v 1.4 2006/01/26 02:16:28 mclark Exp $\n *\n * Copyright (c) 2004, 2005 Metaparadigm Pte. Ltd.\n * Michael Clark <michael@metaparadigm.com>\n * Copyright (c) 2009 Hewlett-Packard Development Company, L.P.\n *\n * This library is free software; you can redistribute it and/or modify\n * it under the terms of the MIT license. See COPYING for details.\n *\n */\n\n#include <stdio.h>\n#include <string.h>\n#include <stdlib.h>\n#include <stdarg.h>\n#include <stddef.h>\n#include <limits.h>\n\n#include <Windows.h>\n\n#ifdef HAVE_ENDIAN_H\n# include <endian.h>    /* attempt to define endianness */\n#endif\n\n#include \"random_seed.h\"\n#include \"linkhash.h\"\n\nvoid lh_abort(const char *msg, ...)\n{\n    va_list ap;\n    va_start(ap, msg);\n    vprintf(msg, ap);\n    va_end(ap);\n    exit(1);\n}\n\nunsigned long lh_ptr_hash(const void *k)\n{\n    /* CAW: refactored to be 64bit nice */\n    return (unsigned long)((((ptrdiff_t)k * LH_PRIME) >> 4) & ULONG_MAX);\n}\n\nint lh_ptr_equal(const void *k1, const void *k2)\n{\n    return (k1 == k2);\n}\n\n/* \n * hashlittle from lookup3.c, by Bob Jenkins, May 2006, Public Domain.\n * http://burtleburtle.net/bob/c/lookup3.c\n * minor modifications to make functions static so no symbols are exported\n * minor mofifications to compile with -Werror\n */\n\n/*\n-------------------------------------------------------------------------------\nlookup3.c, by Bob Jenkins, May 2006, Public Domain.\n\nThese are functions for producing 32-bit hashes for hash table lookup.\nhashword(), hashlittle(), hashlittle2(), hashbig(), mix(), and final() \nare externally useful functions.  Routines to test the hash are included \nif SELF_TEST is defined.  You can use this free for any purpose.  It's in\nthe public domain.  It has no warranty.\n\nYou probably want to use hashlittle().  hashlittle() and hashbig()\nhash byte arrays.  hashlittle() is is faster than hashbig() on\nlittle-endian machines.  Intel and AMD are little-endian machines.\nOn second thought, you probably want hashlittle2(), which is identical to\nhashlittle() except it returns two 32-bit hashes for the price of one.  \nYou could implement hashbig2() if you wanted but I haven't bothered here.\n\nIf you want to find a hash of, say, exactly 7 integers, do\n  a = i1;  b = i2;  c = i3;\n  mix(a,b,c);\n  a += i4; b += i5; c += i6;\n  mix(a,b,c);\n  a += i7;\n  final(a,b,c);\nthen use c as the hash value.  If you have a variable length array of\n4-byte integers to hash, use hashword().  If you have a byte array (like\na character string), use hashlittle().  If you have several byte arrays, or\na mix of things, see the comments above hashlittle().  \n\nWhy is this so big?  I read 12 bytes at a time into 3 4-byte integers, \nthen mix those integers.  This is fast (you can do a lot more thorough\nmixing with 12*3 instructions on 3 integers than you can with 3 instructions\non 1 byte), but shoehorning those bytes into integers efficiently is messy.\n-------------------------------------------------------------------------------\n*/\n\n/*\n * My best guess at if you are big-endian or little-endian.  This may\n * need adjustment.\n */\n#if (defined(__BYTE_ORDER) && defined(__LITTLE_ENDIAN) && \\\n     __BYTE_ORDER == __LITTLE_ENDIAN) || \\\n    (defined(i386) || defined(__i386__) || defined(__i486__) || \\\n     defined(__i586__) || defined(__i686__) || defined(vax) || defined(MIPSEL))\n# define HASH_LITTLE_ENDIAN 1\n# define HASH_BIG_ENDIAN 0\n#elif (defined(__BYTE_ORDER) && defined(__BIG_ENDIAN) && \\\n       __BYTE_ORDER == __BIG_ENDIAN) || \\\n      (defined(sparc) || defined(POWERPC) || defined(mc68000) || defined(sel))\n# define HASH_LITTLE_ENDIAN 0\n# define HASH_BIG_ENDIAN 1\n#else\n# define HASH_LITTLE_ENDIAN 0\n# define HASH_BIG_ENDIAN 0\n#endif\n\n#define hashsize(n) ((uint32_t)1<<(n))\n#define hashmask(n) (hashsize(n)-1)\n#define rot(x,k) (((x)<<(k)) | ((x)>>(32-(k))))\n\n/*\n-------------------------------------------------------------------------------\nmix -- mix 3 32-bit values reversibly.\n\nThis is reversible, so any information in (a,b,c) before mix() is\nstill in (a,b,c) after mix().\n\nIf four pairs of (a,b,c) inputs are run through mix(), or through\nmix() in reverse, there are at least 32 bits of the output that\nare sometimes the same for one pair and different for another pair.\nThis was tested for:\n* pairs that differed by one bit, by two bits, in any combination\n  of top bits of (a,b,c), or in any combination of bottom bits of\n  (a,b,c).\n* \"differ\" is defined as +, -, ^, or ~^.  For + and -, I transformed\n  the output delta to a Gray code (a^(a>>1)) so a string of 1's (as\n  is commonly produced by subtraction) look like a single 1-bit\n  difference.\n* the base values were pseudorandom, all zero but one bit set, or \n  all zero plus a counter that starts at zero.\n\nSome k values for my \"a-=c; a^=rot(c,k); c+=b;\" arrangement that\nsatisfy this are\n    4  6  8 16 19  4\n    9 15  3 18 27 15\n   14  9  3  7 17  3\nWell, \"9 15 3 18 27 15\" didn't quite get 32 bits diffing\nfor \"differ\" defined as + with a one-bit base and a two-bit delta.  I\nused http://burtleburtle.net/bob/hash/avalanche.html to choose \nthe operations, constants, and arrangements of the variables.\n\nThis does not achieve avalanche.  There are input bits of (a,b,c)\nthat fail to affect some output bits of (a,b,c), especially of a.  The\nmost thoroughly mixed value is c, but it doesn't really even achieve\navalanche in c.\n\nThis allows some parallelism.  Read-after-writes are good at doubling\nthe number of bits affected, so the goal of mixing pulls in the opposite\ndirection as the goal of parallelism.  I did what I could.  Rotates\nseem to cost as much as shifts on every machine I could lay my hands\non, and rotates are much kinder to the top and bottom bits, so I used\nrotates.\n-------------------------------------------------------------------------------\n*/\n#define mix(a,b,c) \\\n{ \\\n  a -= c;  a ^= rot(c, 4);  c += b; \\\n  b -= a;  b ^= rot(a, 6);  a += c; \\\n  c -= b;  c ^= rot(b, 8);  b += a; \\\n  a -= c;  a ^= rot(c,16);  c += b; \\\n  b -= a;  b ^= rot(a,19);  a += c; \\\n  c -= b;  c ^= rot(b, 4);  b += a; \\\n}\n\n/*\n-------------------------------------------------------------------------------\nfinal -- final mixing of 3 32-bit values (a,b,c) into c\n\nPairs of (a,b,c) values differing in only a few bits will usually\nproduce values of c that look totally different.  This was tested for\n* pairs that differed by one bit, by two bits, in any combination\n  of top bits of (a,b,c), or in any combination of bottom bits of\n  (a,b,c).\n* \"differ\" is defined as +, -, ^, or ~^.  For + and -, I transformed\n  the output delta to a Gray code (a^(a>>1)) so a string of 1's (as\n  is commonly produced by subtraction) look like a single 1-bit\n  difference.\n* the base values were pseudorandom, all zero but one bit set, or \n  all zero plus a counter that starts at zero.\n\nThese constants passed:\n 14 11 25 16 4 14 24\n 12 14 25 16 4 14 24\nand these came close:\n  4  8 15 26 3 22 24\n 10  8 15 26 3 22 24\n 11  8 15 26 3 22 24\n-------------------------------------------------------------------------------\n*/\n#define final(a,b,c) \\\n{ \\\n  c ^= b; c -= rot(b,14); \\\n  a ^= c; a -= rot(c,11); \\\n  b ^= a; b -= rot(a,25); \\\n  c ^= b; c -= rot(b,16); \\\n  a ^= c; a -= rot(c,4);  \\\n  b ^= a; b -= rot(a,14); \\\n  c ^= b; c -= rot(b,24); \\\n}\n\n\n/*\n-------------------------------------------------------------------------------\nhashlittle() -- hash a variable-length key into a 32-bit value\n  k       : the key (the unaligned variable-length array of bytes)\n  length  : the length of the key, counting by bytes\n  initval : can be any 4-byte value\nReturns a 32-bit value.  Every bit of the key affects every bit of\nthe return value.  Two keys differing by one or two bits will have\ntotally different hash values.\n\nThe best hash table sizes are powers of 2.  There is no need to do\nmod a prime (mod is sooo slow!).  If you need less than 32 bits,\nuse a bitmask.  For example, if you need only 10 bits, do\n  h = (h & hashmask(10));\nIn which case, the hash table should have hashsize(10) elements.\n\nIf you are hashing n strings (uint8_t **)k, do it like this:\n  for (i=0, h=0; i<n; ++i) h = hashlittle( k[i], len[i], h);\n\nBy Bob Jenkins, 2006.  bob_jenkins@burtleburtle.net.  You may use this\ncode any way you wish, private, educational, or commercial.  It's free.\n\nUse for hash table lookup, or anything where one collision in 2^^32 is\nacceptable.  Do NOT use for cryptographic purposes.\n-------------------------------------------------------------------------------\n*/\n\nstatic uint32_t hashlittle( const void *key, size_t length, uint32_t initval)\n{\n  uint32_t a,b,c;                                          /* internal state */\n  union { const void *ptr; size_t i; } u;     /* needed for Mac Powerbook G4 */\n\n  /* Set up the internal state */\n  a = b = c = 0xdeadbeef + ((uint32_t)length) + initval;\n\n  u.ptr = key;\n  if (HASH_LITTLE_ENDIAN && ((u.i & 0x3) == 0)) {\n    const uint32_t *k = (const uint32_t *)key;         /* read 32-bit chunks */\n\n    /*------ all but last block: aligned reads and affect 32 bits of (a,b,c) */\n    while (length > 12)\n    {\n      a += k[0];\n      b += k[1];\n      c += k[2];\n      mix(a,b,c);\n      length -= 12;\n      k += 3;\n    }\n\n    /*----------------------------- handle the last (probably partial) block */\n    /* \n     * \"k[2]&0xffffff\" actually reads beyond the end of the string, but\n     * then masks off the part it's not allowed to read.  Because the\n     * string is aligned, the masked-off tail is in the same word as the\n     * rest of the string.  Every machine with memory protection I've seen\n     * does it on word boundaries, so is OK with this.  But VALGRIND will\n     * still catch it and complain.  The masking trick does make the hash\n     * noticably faster for short strings (like English words).\n     */\n#ifndef VALGRIND\n\n    switch(length)\n    {\n    case 12: c+=k[2]; b+=k[1]; a+=k[0]; break;\n    case 11: c+=k[2]&0xffffff; b+=k[1]; a+=k[0]; break;\n    case 10: c+=k[2]&0xffff; b+=k[1]; a+=k[0]; break;\n    case 9 : c+=k[2]&0xff; b+=k[1]; a+=k[0]; break;\n    case 8 : b+=k[1]; a+=k[0]; break;\n    case 7 : b+=k[1]&0xffffff; a+=k[0]; break;\n    case 6 : b+=k[1]&0xffff; a+=k[0]; break;\n    case 5 : b+=k[1]&0xff; a+=k[0]; break;\n    case 4 : a+=k[0]; break;\n    case 3 : a+=k[0]&0xffffff; break;\n    case 2 : a+=k[0]&0xffff; break;\n    case 1 : a+=k[0]&0xff; break;\n    case 0 : return c;              /* zero length strings require no mixing */\n    }\n\n#else /* make valgrind happy */\n\n    const uint8_t  *k8 = (const uint8_t *)k;\n    switch(length)\n    {\n    case 12: c+=k[2]; b+=k[1]; a+=k[0]; break;\n    case 11: c+=((uint32_t)k8[10])<<16;  /* fall through */\n    case 10: c+=((uint32_t)k8[9])<<8;    /* fall through */\n    case 9 : c+=k8[8];                   /* fall through */\n    case 8 : b+=k[1]; a+=k[0]; break;\n    case 7 : b+=((uint32_t)k8[6])<<16;   /* fall through */\n    case 6 : b+=((uint32_t)k8[5])<<8;    /* fall through */\n    case 5 : b+=k8[4];                   /* fall through */\n    case 4 : a+=k[0]; break;\n    case 3 : a+=((uint32_t)k8[2])<<16;   /* fall through */\n    case 2 : a+=((uint32_t)k8[1])<<8;    /* fall through */\n    case 1 : a+=k8[0]; break;\n    case 0 : return c;\n    }\n\n#endif /* !valgrind */\n\n  } else if (HASH_LITTLE_ENDIAN && ((u.i & 0x1) == 0)) {\n    const uint16_t *k = (const uint16_t *)key;         /* read 16-bit chunks */\n    const uint8_t  *k8;\n\n    /*--------------- all but last block: aligned reads and different mixing */\n    while (length > 12)\n    {\n      a += k[0] + (((uint32_t)k[1])<<16);\n      b += k[2] + (((uint32_t)k[3])<<16);\n      c += k[4] + (((uint32_t)k[5])<<16);\n      mix(a,b,c);\n      length -= 12;\n      k += 6;\n    }\n\n    /*----------------------------- handle the last (probably partial) block */\n    k8 = (const uint8_t *)k;\n    switch(length)\n    {\n    case 12: c+=k[4]+(((uint32_t)k[5])<<16);\n             b+=k[2]+(((uint32_t)k[3])<<16);\n             a+=k[0]+(((uint32_t)k[1])<<16);\n             break;\n    case 11: c+=((uint32_t)k8[10])<<16;     /* fall through */\n    case 10: c+=k[4];\n             b+=k[2]+(((uint32_t)k[3])<<16);\n             a+=k[0]+(((uint32_t)k[1])<<16);\n             break;\n    case 9 : c+=k8[8];                      /* fall through */\n    case 8 : b+=k[2]+(((uint32_t)k[3])<<16);\n             a+=k[0]+(((uint32_t)k[1])<<16);\n             break;\n    case 7 : b+=((uint32_t)k8[6])<<16;      /* fall through */\n    case 6 : b+=k[2];\n             a+=k[0]+(((uint32_t)k[1])<<16);\n             break;\n    case 5 : b+=k8[4];                      /* fall through */\n    case 4 : a+=k[0]+(((uint32_t)k[1])<<16);\n             break;\n    case 3 : a+=((uint32_t)k8[2])<<16;      /* fall through */\n    case 2 : a+=k[0];\n             break;\n    case 1 : a+=k8[0];\n             break;\n    case 0 : return c;                     /* zero length requires no mixing */\n    }\n\n  } else {                        /* need to read the key one byte at a time */\n    const uint8_t *k = (const uint8_t *)key;\n\n    /*--------------- all but the last block: affect some 32 bits of (a,b,c) */\n    while (length > 12)\n    {\n      a += k[0];\n      a += ((uint32_t)k[1])<<8;\n      a += ((uint32_t)k[2])<<16;\n      a += ((uint32_t)k[3])<<24;\n      b += k[4];\n      b += ((uint32_t)k[5])<<8;\n      b += ((uint32_t)k[6])<<16;\n      b += ((uint32_t)k[7])<<24;\n      c += k[8];\n      c += ((uint32_t)k[9])<<8;\n      c += ((uint32_t)k[10])<<16;\n      c += ((uint32_t)k[11])<<24;\n      mix(a,b,c);\n      length -= 12;\n      k += 12;\n    }\n\n    /*-------------------------------- last block: affect all 32 bits of (c) */\n    switch(length)                   /* all the case statements fall through */\n    {\n    case 12: c+=((uint32_t)k[11])<<24;\n    case 11: c+=((uint32_t)k[10])<<16;\n    case 10: c+=((uint32_t)k[9])<<8;\n    case 9 : c+=k[8];\n    case 8 : b+=((uint32_t)k[7])<<24;\n    case 7 : b+=((uint32_t)k[6])<<16;\n    case 6 : b+=((uint32_t)k[5])<<8;\n    case 5 : b+=k[4];\n    case 4 : a+=((uint32_t)k[3])<<24;\n    case 3 : a+=((uint32_t)k[2])<<16;\n    case 2 : a+=((uint32_t)k[1])<<8;\n    case 1 : a+=k[0];\n             break;\n    case 0 : return c;\n    }\n  }\n\n  final(a,b,c);\n  return c;\n}\n\nunsigned long lh_char_hash(const void *k)\n{\n    static volatile int random_seed = -1;\n\n    if (random_seed == -1) {\n        int seed;\n        /* we can't use -1 as it is the unitialized sentinel */\n        while ((seed = json_c_get_random_seed()) == -1);\n#if defined __GNUC__\n        __sync_val_compare_and_swap(&random_seed, -1, seed);\n#elif defined _MSC_VER\n        InterlockedCompareExchange(&random_seed, seed, -1);\n#else\n#warning \"racy random seed initializtion if used by multiple threads\"\n        random_seed = seed; /* potentially racy */\n#endif\n    }\n\n    return hashlittle((const char*)k, strlen((const char*)k), random_seed); \n}\n\nint lh_char_equal(const void *k1, const void *k2)\n{\n    return (strcmp((const char*)k1, (const char*)k2) == 0);\n}\n\nstruct lh_table* lh_table_new(int size, const char *name,\n                  lh_entry_free_fn *free_fn,\n                  lh_hash_fn *hash_fn,\n                  lh_equal_fn *equal_fn)\n{\n    int i;\n    struct lh_table *t;\n\n    t = (struct lh_table*)calloc(1, sizeof(struct lh_table));\n    if(!t) lh_abort(\"lh_table_new: calloc failed\\n\");\n    t->count = 0;\n    t->size = size;\n    t->name = name;\n    t->table = (struct lh_entry*)calloc(size, sizeof(struct lh_entry));\n    if(!t->table) lh_abort(\"lh_table_new: calloc failed\\n\");\n    t->free_fn = free_fn;\n    t->hash_fn = hash_fn;\n    t->equal_fn = equal_fn;\n    for(i = 0; i < size; i++) t->table[i].k = LH_EMPTY;\n    return t;\n}\n\nstruct lh_table* lh_kchar_table_new(int size, const char *name,\n                    lh_entry_free_fn *free_fn)\n{\n    return lh_table_new(size, name, free_fn, lh_char_hash, lh_char_equal);\n}\n\nstruct lh_table* lh_kptr_table_new(int size, const char *name,\n                   lh_entry_free_fn *free_fn)\n{\n    return lh_table_new(size, name, free_fn, lh_ptr_hash, lh_ptr_equal);\n}\n\nvoid lh_table_resize(struct lh_table *t, int new_size)\n{\n    struct lh_table *new_t;\n    struct lh_entry *ent;\n\n    new_t = lh_table_new(new_size, t->name, NULL, t->hash_fn, t->equal_fn);\n    ent = t->head;\n    while(ent) {\n        lh_table_insert(new_t, ent->k, ent->v);\n        ent = ent->next;\n    }\n    free(t->table);\n    t->table = new_t->table;\n    t->size = new_size;\n    t->head = new_t->head;\n    t->tail = new_t->tail;\n    t->resizes++;\n    free(new_t);\n}\n\nvoid lh_table_free(struct lh_table *t)\n{\n    struct lh_entry *c;\n    for(c = t->head; c != NULL; c = c->next) {\n        if(t->free_fn) {\n            t->free_fn(c);\n        }\n    }\n    free(t->table);\n    free(t);\n}\n\n\nint lh_table_insert(struct lh_table *t, void *k, const void *v)\n{\n    unsigned long h, n;\n\n    t->inserts++;\n    if(t->count >= t->size * LH_LOAD_FACTOR) lh_table_resize(t, t->size * 2);\n\n    h = t->hash_fn(k);\n    n = h % t->size;\n\n    while( 1 ) {\n        if(t->table[n].k == LH_EMPTY || t->table[n].k == LH_FREED) break;\n        t->collisions++;\n        if ((int)++n == t->size) n = 0;\n    }\n\n    t->table[n].k = k;\n    t->table[n].v = v;\n    t->count++;\n\n    if(t->head == NULL) {\n        t->head = t->tail = &t->table[n];\n        t->table[n].next = t->table[n].prev = NULL;\n    } else {\n        t->tail->next = &t->table[n];\n        t->table[n].prev = t->tail;\n        t->table[n].next = NULL;\n        t->tail = &t->table[n];\n    }\n\n    return 0;\n}\n\n\nstruct lh_entry* lh_table_lookup_entry(struct lh_table *t, const void *k)\n{\n    unsigned long h = t->hash_fn(k);\n    unsigned long n = h % t->size;\n    int count = 0;\n\n    t->lookups++;\n    while( count < t->size ) {\n        if(t->table[n].k == LH_EMPTY) return NULL;\n        if(t->table[n].k != LH_FREED &&\n           t->equal_fn(t->table[n].k, k)) return &t->table[n];\n        if ((int)++n == t->size) n = 0;\n        count++;\n    }\n    return NULL;\n}\n\n\nconst void* lh_table_lookup(struct lh_table *t, const void *k)\n{\n    void *result;\n    lh_table_lookup_ex(t, k, &result);\n    return result;\n}\n\njson_bool lh_table_lookup_ex(struct lh_table* t, const void* k, void **v)\n{\n    struct lh_entry *e = lh_table_lookup_entry(t, k);\n    if (e != NULL) {\n        if (v != NULL) *v = (void *)e->v;\n        return TRUE; /* key found */\n    }\n    if (v != NULL) *v = NULL;\n    return FALSE; /* key not found */\n}\n\nint lh_table_delete_entry(struct lh_table *t, struct lh_entry *e)\n{\n    ptrdiff_t n = (ptrdiff_t)(e - t->table); /* CAW: fixed to be 64bit nice, still need the crazy negative case... */\n\n    /* CAW: this is bad, really bad, maybe stack goes other direction on this machine... */\n    if(n < 0) { return -2; }\n\n    if(t->table[n].k == LH_EMPTY || t->table[n].k == LH_FREED) return -1;\n    t->count--;\n    if(t->free_fn) t->free_fn(e);\n    t->table[n].v = NULL;\n    t->table[n].k = LH_FREED;\n    if(t->tail == &t->table[n] && t->head == &t->table[n]) {\n        t->head = t->tail = NULL;\n    } else if (t->head == &t->table[n]) {\n        t->head->next->prev = NULL;\n        t->head = t->head->next;\n    } else if (t->tail == &t->table[n]) {\n        t->tail->prev->next = NULL;\n        t->tail = t->tail->prev;\n    } else {\n        t->table[n].prev->next = t->table[n].next;\n        t->table[n].next->prev = t->table[n].prev;\n    }\n    t->table[n].next = t->table[n].prev = NULL;\n    return 0;\n}\n\n\nint lh_table_delete(struct lh_table *t, const void *k)\n{\n    struct lh_entry *e = lh_table_lookup_entry(t, k);\n    if(!e) return -1;\n    return lh_table_delete_entry(t, e);\n}\n\nint lh_table_length(struct lh_table *t)\n{\n    return t->count;\n}\n"
  },
  {
    "path": "third_party/phlib/jsonc/linkhash.h",
    "content": "/*\n * $Id: linkhash.h,v 1.6 2006/01/30 23:07:57 mclark Exp $\n *\n * Copyright (c) 2004, 2005 Metaparadigm Pte. Ltd.\n * Michael Clark <michael@metaparadigm.com>\n * Copyright (c) 2009 Hewlett-Packard Development Company, L.P.\n *\n * This library is free software; you can redistribute it and/or modify\n * it under the terms of the MIT license. See COPYING for details.\n *\n */\n \n#ifndef _linkhash_h_\n#define _linkhash_h_\n\n#include \"json_object.h\"\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\n/**\n * golden prime used in hash functions\n */\n#define LH_PRIME 0x9e370001UL\n\n/**\n * The fraction of filled hash buckets until an insert will cause the table\n * to be resized.  \n * This can range from just above 0 up to 1.0.\n */\n#define LH_LOAD_FACTOR 0.66\n\n/**\n * sentinel pointer value for empty slots\n */\n#define LH_EMPTY (void*)-1\n\n/**\n * sentinel pointer value for freed slots\n */\n#define LH_FREED (void*)-2\n\nstruct lh_entry;\n\n/**\n * callback function prototypes\n */\ntypedef void (lh_entry_free_fn) (struct lh_entry *e);\n/**\n * callback function prototypes\n */\ntypedef unsigned long (lh_hash_fn) (const void *k);\n/**\n * callback function prototypes\n */\ntypedef int (lh_equal_fn) (const void *k1, const void *k2);\n\n/**\n * An entry in the hash table\n */\nstruct lh_entry {\n\t/**\n\t * The key.\n\t */\n\tvoid *k;\n\t/**\n\t * The value.\n\t */\n\tconst void *v;\n\t/**\n\t * The next entry\n\t */\n\tstruct lh_entry *next;\n\t/**\n\t * The previous entry.\n\t */\n\tstruct lh_entry *prev;\n};\n\n\n/**\n * The hash table structure.\n */\nstruct lh_table {\n\t/**\n\t * Size of our hash.\n\t */\n\tint size;\n\t/**\n\t * Numbers of entries.\n\t */\n\tint count;\n\n\t/**\n\t * Number of collisions.\n\t */\n\tint collisions;\n\n\t/**\n\t * Number of resizes.\n\t */\n\tint resizes;\n\n\t/**\n\t * Number of lookups.\n\t */\n\tint lookups;\n\n\t/**\n\t * Number of inserts.\n\t */\n\tint inserts;\n\n\t/**\n\t * Number of deletes.\n\t */\n\tint deletes;\n\n\t/**\n\t * Name of the hash table.\n\t */\n\tconst char *name;\n\n\t/**\n\t * The first entry.\n\t */\n\tstruct lh_entry *head;\n\n\t/**\n\t * The last entry.\n\t */\n\tstruct lh_entry *tail;\n\n\tstruct lh_entry *table;\n\n\t/**\n\t * A pointer onto the function responsible for freeing an entry.\n\t */\n\tlh_entry_free_fn *free_fn;\n\tlh_hash_fn *hash_fn;\n\tlh_equal_fn *equal_fn;\n};\n\n\n/**\n * Pre-defined hash and equality functions\n */\nextern unsigned long lh_ptr_hash(const void *k);\nextern int lh_ptr_equal(const void *k1, const void *k2);\n\nextern unsigned long lh_char_hash(const void *k);\nextern int lh_char_equal(const void *k1, const void *k2);\n\n\n/**\n * Convenience list iterator.\n */\n#define lh_foreach(table, entry) \\\nfor(entry = table->head; entry; entry = entry->next)\n\n/**\n * lh_foreach_safe allows calling of deletion routine while iterating.\n */\n#define lh_foreach_safe(table, entry, tmp) \\\nfor(entry = table->head; entry && ((tmp = entry->next) || 1); entry = tmp)\n\n\n\n/**\n * Create a new linkhash table.\n * @param size initial table size. The table is automatically resized\n * although this incurs a performance penalty.\n * @param name the table name.\n * @param free_fn callback function used to free memory for entries\n * when lh_table_free or lh_table_delete is called.\n * If NULL is provided, then memory for keys and values\n * must be freed by the caller.\n * @param hash_fn  function used to hash keys. 2 standard ones are defined:\n * lh_ptr_hash and lh_char_hash for hashing pointer values\n * and C strings respectively.\n * @param equal_fn comparison function to compare keys. 2 standard ones defined:\n * lh_ptr_hash and lh_char_hash for comparing pointer values\n * and C strings respectively.\n * @return a pointer onto the linkhash table.\n */\nextern struct lh_table* lh_table_new(int size, const char *name,\n\t\t\t\t     lh_entry_free_fn *free_fn,\n\t\t\t\t     lh_hash_fn *hash_fn,\n\t\t\t\t     lh_equal_fn *equal_fn);\n\n/**\n * Convenience function to create a new linkhash\n * table with char keys.\n * @param size initial table size.\n * @param name table name.\n * @param free_fn callback function used to free memory for entries.\n * @return a pointer onto the linkhash table.\n */\nextern struct lh_table* lh_kchar_table_new(int size, const char *name,\n\t\t\t\t\t   lh_entry_free_fn *free_fn);\n\n\n/**\n * Convenience function to create a new linkhash\n * table with ptr keys.\n * @param size initial table size.\n * @param name table name.\n * @param free_fn callback function used to free memory for entries.\n * @return a pointer onto the linkhash table.\n */\nextern struct lh_table* lh_kptr_table_new(int size, const char *name,\n\t\t\t\t\t  lh_entry_free_fn *free_fn);\n\n\n/**\n * Free a linkhash table.\n * If a callback free function is provided then it is called for all\n * entries in the table.\n * @param t table to free.\n */\nextern void lh_table_free(struct lh_table *t);\n\n\n/**\n * Insert a record into the table.\n * @param t the table to insert into.\n * @param k a pointer to the key to insert.\n * @param v a pointer to the value to insert.\n */\nextern int lh_table_insert(struct lh_table *t, void *k, const void *v);\n\n\n/**\n * Lookup a record into the table.\n * @param t the table to lookup\n * @param k a pointer to the key to lookup\n * @return a pointer to the record structure of the value or NULL if it does not exist.\n */\nextern struct lh_entry* lh_table_lookup_entry(struct lh_table *t, const void *k);\n\n/**\n * Lookup a record into the table\n * @param t the table to lookup\n * @param k a pointer to the key to lookup\n * @return a pointer to the found value or NULL if it does not exist.\n * @deprecated Use lh_table_lookup_ex instead.\n */\nTHIS_FUNCTION_IS_DEPRECATED(extern const void* lh_table_lookup(struct lh_table *t, const void *k));\n\n/**\n * Lookup a record in the table\n * @param t the table to lookup\n * @param k a pointer to the key to lookup\n * @param v a pointer to a where to store the found value (set to NULL if it doesn't exist).\n * @return whether or not the key was found\n */\nextern json_bool lh_table_lookup_ex(struct lh_table *t, const void *k, void **v);\n\n/**\n * Delete a record from the table.\n * If a callback free function is provided then it is called for the\n * for the item being deleted.\n * @param t the table to delete from.\n * @param e a pointer to the entry to delete.\n * @return 0 if the item was deleted.\n * @return -1 if it was not found.\n */\nextern int lh_table_delete_entry(struct lh_table *t, struct lh_entry *e);\n\n\n/**\n * Delete a record from the table.\n * If a callback free function is provided then it is called for the\n * for the item being deleted.\n * @param t the table to delete from.\n * @param k a pointer to the key to delete.\n * @return 0 if the item was deleted.\n * @return -1 if it was not found.\n */\nextern int lh_table_delete(struct lh_table *t, const void *k);\n\nextern int lh_table_length(struct lh_table *t);\n\nvoid lh_abort(const char *msg, ...);\nvoid lh_table_resize(struct lh_table *t, int new_size);\n\n#ifdef __cplusplus\n}\n#endif\n\n#endif\n"
  },
  {
    "path": "third_party/phlib/jsonc/math_compat.h",
    "content": "#ifndef __math_compat_h\n#define __math_compat_h\n\n/* Define isnan and isinf on Windows/MSVC */\n\n#ifndef HAVE_DECL_ISNAN\n# ifdef HAVE_DECL__ISNAN\n#include <float.h>\n#define isnan(x) _isnan(x)\n# endif\n#endif\n\n#ifndef HAVE_DECL_ISINF\n# ifdef HAVE_DECL__FINITE\n#include <float.h>\n#define isinf(x) (!_finite(x))\n# endif\n#endif\n\n#ifndef HAVE_DECL_NAN\n#error This platform does not have nan()\n#endif\n\n#ifndef HAVE_DECL_INFINITY\n#error This platform does not have INFINITY\n#endif\n\n#endif\n"
  },
  {
    "path": "third_party/phlib/jsonc/printbuf.c",
    "content": "/*\n * $Id: printbuf.c,v 1.5 2006/01/26 02:16:28 mclark Exp $\n *\n * Copyright (c) 2004, 2005 Metaparadigm Pte. Ltd.\n * Michael Clark <michael@metaparadigm.com>\n *\n * This library is free software; you can redistribute it and/or modify\n * it under the terms of the MIT license. See COPYING for details.\n *\n *\n * Copyright (c) 2008-2009 Yahoo! Inc.  All rights reserved.\n * The copyrights to the contents of this file are licensed under the MIT License\n * (http://www.opensource.org/licenses/mit-license.php)\n */\n\n#include \"config.h\"\n\n#include <stdio.h>\n#include <stdlib.h>\n#include <string.h>\n\n#ifdef HAVE_STDARG_H\n# include <stdarg.h>\n#else /* !HAVE_STDARG_H */\n# error Not enough var arg support!\n#endif /* HAVE_STDARG_H */\n\n#include \"bits.h\"\n#include \"debug.h\"\n#include \"printbuf.h\"\n\nstatic int printbuf_extend(struct printbuf *p, size_t min_size);\n\nstruct printbuf* printbuf_new(void)\n{\n  struct printbuf *p;\n\n  p = (struct printbuf*)calloc(1, sizeof(struct printbuf));\n  if(!p) return NULL;\n  p->size = 32;\n  p->bpos = 0;\n  if(!(p->buf = (char*)malloc(p->size))) {\n    free(p);\n    return NULL;\n  }\n  return p;\n}\n\n\n/**\n * Extend the buffer p so it has a size of at least min_size.\n *\n * If the current size is large enough, nothing is changed.\n *\n * Note: this does not check the available space!  The caller\n *  is responsible for performing those calculations.\n */\nstatic int printbuf_extend(struct printbuf *p, size_t min_size)\n{\n    char *t;\n    size_t new_size;\n\n    if (p->size >= min_size)\n        return 0;\n\n    new_size = json_max(p->size * 2, min_size + 8);\n#ifdef PRINTBUF_DEBUG\n    MC_DEBUG(\"printbuf_memappend: realloc \"\n      \"bpos=%d min_size=%d old_size=%d new_size=%d\\n\",\n      p->bpos, min_size, p->size, new_size);\n#endif /* PRINTBUF_DEBUG */\n    if(!(t = (char*)realloc(p->buf, new_size)))\n        return -1;\n    p->size = new_size;\n    p->buf = t;\n    return 0;\n}\n\nsize_t printbuf_memappend(struct printbuf *p, const char *buf, size_t size)\n{\n  if (p->size <= p->bpos + size + 1) {\n    if (printbuf_extend(p, p->bpos + size + 1) < 0)\n      return -1;\n  }\n  memcpy(p->buf + p->bpos, buf, size);\n  p->bpos += size;\n  p->buf[p->bpos]= '\\0';\n  return size;\n}\n\nint printbuf_memset(struct printbuf *pb, size_t offset, int charvalue, size_t len)\n{\n    size_t size_needed;\n\n    if (offset == -1)\n        offset = pb->bpos;\n    size_needed = offset + len;\n    if (pb->size < size_needed)\n    {\n        if (printbuf_extend(pb, size_needed) < 0)\n            return -1;\n    }\n\n    memset(pb->buf + offset, charvalue, len);\n    if (pb->bpos < size_needed)\n        pb->bpos = size_needed;\n\n    return 0;\n}\n\n#if !defined(HAVE_VSNPRINTF) && defined(_MSC_VER)\n# define vsnprintf _vsnprintf\n#elif !defined(HAVE_VSNPRINTF) /* !HAVE_VSNPRINTF */\n# error Need vsnprintf!\n#endif /* !HAVE_VSNPRINTF && defined(_WIN32) */\n\n#if !defined(HAVE_VASPRINTF)\n/* CAW: compliant version of vasprintf */\nstatic int vasprintf(char **buf, const char *fmt, va_list ap)\n{\n#ifndef _WIN32\n    static char _T_emptybuffer = '\\0';\n#endif /* !defined(_WIN32) */\n    int chars;\n    char *b;\n\n    if(!buf) { return -1; }\n\n#ifdef _WIN32\n    chars = _vscprintf(fmt, ap)+1;\n#else /* !defined(_WIN32) */\n    /* CAW: RAWR! We have to hope to god here that vsnprintf doesn't overwrite\n       our buffer like on some 64bit sun systems.... but hey, its time to move on */\n    chars = vsnprintf(&_T_emptybuffer, 0, fmt, ap)+1;\n    if(chars < 0) { chars *= -1; } /* CAW: old glibc versions have this problem */\n#endif /* defined(_WIN32) */\n\n    b = (char*)malloc(sizeof(char) * chars);\n    if(!b) { return -1; }\n\n    if ((chars = vsprintf_s(b, sizeof(char), fmt, ap)) < 0)\n    {\n        free(b);\n    } \n    else \n    {\n        *buf = b;\n    }\n\n    return chars;\n}\n#endif /* !HAVE_VASPRINTF */\n\nint sprintbuf(struct printbuf *p, const char *msg, ...)\n{\n  va_list ap;\n  char *t;\n  int size;\n  char buf[128];\n\n  /* user stack buffer first */\n  va_start(ap, msg);\n  size = _vsnprintf_s(buf, sizeof(buf), _TRUNCATE, msg, ap);\n  va_end(ap);\n  /* if string is greater than stack buffer, then use dynamic string\n     with vasprintf.  Note: some implementation of vsnprintf return -1\n     if output is truncated whereas some return the number of bytes that\n     would have been written - this code handles both cases. */\n  if(size == -1 || size > 127) {\n    va_start(ap, msg);\n    if((size = vasprintf(&t, msg, ap)) < 0) { va_end(ap); return -1; }\n    va_end(ap);\n    printbuf_memappend(p, t, size);\n    free(t);\n    return size;\n  } else {\n    printbuf_memappend(p, buf, size);\n    return size;\n  }\n}\n\nvoid printbuf_reset(struct printbuf *p)\n{\n  p->buf[0] = '\\0';\n  p->bpos = 0;\n}\n\nvoid printbuf_free(struct printbuf *p)\n{\n  if(p) {\n    free(p->buf);\n    free(p);\n  }\n}\n"
  },
  {
    "path": "third_party/phlib/jsonc/printbuf.h",
    "content": "/*\n * $Id: printbuf.h,v 1.4 2006/01/26 02:16:28 mclark Exp $\n *\n * Copyright (c) 2004, 2005 Metaparadigm Pte. Ltd.\n * Michael Clark <michael@metaparadigm.com>\n *\n * This library is free software; you can redistribute it and/or modify\n * it under the terms of the MIT license. See COPYING for details.\n *\n *\n * Copyright (c) 2008-2009 Yahoo! Inc.  All rights reserved.\n * The copyrights to the contents of this file are licensed under the MIT License\n * (http://www.opensource.org/licenses/mit-license.php)\n */\n\n#ifndef _printbuf_h_\n#define _printbuf_h_\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\nstruct printbuf {\n  char *buf;\n  size_t bpos;\n  size_t size;\n};\n\nextern struct printbuf*\nprintbuf_new(void);\n\n/* As an optimization, printbuf_memappend_fast is defined as a macro\n * that handles copying data if the buffer is large enough; otherwise\n * it invokes printbuf_memappend_real() which performs the heavy\n * lifting of realloc()ing the buffer and copying data.\n * Your code should not use printbuf_memappend directly--use\n * printbuf_memappend_fast instead.\n */\nextern size_t printbuf_memappend(struct printbuf *p, const char *buf, size_t size);\n\n__inline void printbuf_memappend_fast(struct printbuf *p, const char *bufptr, size_t bufsize)\n{\n    if ((p->size - p->bpos) > bufsize)\n    {\n        memcpy(p->buf + p->bpos, (bufptr), bufsize);\n        p->bpos += (int)bufsize;\n        p->buf[p->bpos] = '\\0';\n    }\n    else\n    {\n        printbuf_memappend(p, (bufptr), bufsize);\n    }\n}\n\n#define printbuf_length(p) ((p)->bpos)\n\n/**\n * Set len bytes of the buffer to charvalue, starting at offset offset.\n * Similar to calling memset(x, charvalue, len);\n *\n * The memory allocated for the buffer is extended as necessary.\n *\n * If offset is -1, this starts at the end of the current data in the buffer.\n */\nextern int\nprintbuf_memset(struct printbuf *pb, size_t offset, int charvalue, size_t len);\n\nextern int\nsprintbuf(struct printbuf *p, const char *msg, ...);\n\nextern void\nprintbuf_reset(struct printbuf *p);\n\nextern void\nprintbuf_free(struct printbuf *p);\n\n#ifdef __cplusplus\n}\n#endif\n\n#endif\n"
  },
  {
    "path": "third_party/phlib/jsonc/random_seed.c",
    "content": "/*\n * random_seed.c\n *\n * Copyright (c) 2013 Metaparadigm Pte. Ltd.\n * Michael Clark <michael@metaparadigm.com>\n *\n * This library is free software; you can redistribute it and/or modify\n * it under the terms of the MIT license. See COPYING for details.\n *\n */\n\n#include <stdio.h>\n#include \"config.h\"\n\n#define DEBUG_SEED(s)\n\n\n#if defined ENABLE_RDRAND\n\n/* cpuid */\n\n#if defined __GNUC__ && (defined __i386__ || defined __x86_64__)\n#define HAS_X86_CPUID 1\n\nstatic void do_cpuid(int regs[], int h)\n{\n    __asm__ __volatile__(\n#if defined __x86_64__\n                         \"pushq %%rbx;\\n\"\n#else\n                         \"pushl %%ebx;\\n\"\n#endif\n                         \"cpuid;\\n\"\n#if defined __x86_64__\n                         \"popq %%rbx;\\n\"\n#else\n                         \"popl %%ebx;\\n\"\n#endif\n                         : \"=a\"(regs[0]), [ebx] \"=r\"(regs[1]), \"=c\"(regs[2]), \"=d\"(regs[3])\n                         : \"a\"(h));\n}\n\n#elif defined _MSC_VER\n\n#define HAS_X86_CPUID 1\n#define do_cpuid __cpuid\n\n#endif\n\n/* has_rdrand */\n\n#if HAS_X86_CPUID\n\nstatic int has_rdrand()\n{\n    // CPUID.01H:ECX.RDRAND[bit 30] == 1\n    int regs[4];\n    do_cpuid(regs, 1);\n    return (regs[2] & (1 << 30)) != 0;\n}\n\n#endif\n\n/* get_rdrand_seed - GCC x86 and X64 */\n\n#if defined __GNUC__ && (defined __i386__ || defined __x86_64__)\n\n#define HAVE_RDRAND 1\n\nstatic int get_rdrand_seed()\n{\n    DEBUG_SEED(\"get_rdrand_seed\");\n    int _eax;\n    // rdrand eax\n    __asm__ __volatile__(\"1: .byte 0x0F\\n\"\n                         \"   .byte 0xC7\\n\"\n                         \"   .byte 0xF0\\n\"\n                         \"   jnc 1b;\\n\"\n                         : \"=a\" (_eax));\n    return _eax;\n}\n\n#endif\n\n#if defined _MSC_VER\n\n#if _MSC_VER >= 1700\n#define HAVE_RDRAND 1\n\n/* get_rdrand_seed - Visual Studio 2012 and above */\n\nstatic int get_rdrand_seed()\n{\n    DEBUG_SEED(\"get_rdrand_seed\");\n    int r;\n    while (_rdrand32_step(&r) == 0);\n    return r;\n}\n\n#elif defined _M_IX86\n#define HAVE_RDRAND 1\n\n/* get_rdrand_seed - Visual Studio 2010 and below - x86 only */\n\nstatic int get_rdrand_seed()\n{\n    DEBUG_SEED(\"get_rdrand_seed\");\n    int _eax;\nretry:\n    // rdrand eax\n    __asm _emit 0x0F __asm _emit 0xC7 __asm _emit 0xF0\n    __asm jnc retry\n    __asm mov _eax, eax\n    return _eax;\n}\n\n#endif\n#endif\n\n#endif /* defined ENABLE_RDRAND */\n\n\n/* has_dev_urandom */\n\n#if defined (__APPLE__) || defined(__unix__) || defined(__linux__)\n\n#include <string.h>\n#include <fcntl.h>\n#include <unistd.h>\n#include <errno.h>\n#include <stdlib.h>\n#include <sys/stat.h>\n\n#define HAVE_DEV_RANDOM 1\n\nstatic const char *dev_random_file = \"/dev/urandom\";\n\nstatic int has_dev_urandom()\n{\n    struct stat buf;\n    if (stat(dev_random_file, &buf)) {\n        return 0;\n    }\n    return ((buf.st_mode & S_IFCHR) != 0);\n}\n\n\n/* get_dev_random_seed */\n\nstatic int get_dev_random_seed()\n{\n    DEBUG_SEED(\"get_dev_random_seed\");\n    \n    int fd = open(dev_random_file, O_RDONLY);\n    if (fd < 0) {\n        fprintf(stderr, \"error opening %s: %s\", dev_random_file, strerror(errno));\n        exit(1);\n    }\n    \n    int r;\n    ssize_t nread = read(fd, &r, sizeof(r));\n    if (nread != sizeof(r)) {\n        fprintf(stderr, \"error read %s: %s\", dev_random_file, strerror(errno));\n        exit(1);\n    }\n    else if (nread != sizeof(r)) {\n        fprintf(stderr, \"error short read %s\", dev_random_file);\n        exit(1);\n    }\n    close(fd);\n    return r;\n}\n\n#endif\n\n\n/* get_cryptgenrandom_seed */\n\n#ifdef _WIN32\n\n#define HAVE_CRYPTGENRANDOM 1\n\n#include <windows.h>\n\nstatic int get_cryptgenrandom_seed()\n{\n    DEBUG_SEED(\"get_cryptgenrandom_seed\");\n    \n    HCRYPTPROV hProvider = 0;\n    int r;\n    \n    if (!CryptAcquireContextW(&hProvider, 0, 0, PROV_RSA_FULL, CRYPT_VERIFYCONTEXT | CRYPT_SILENT)) \n    {\n        fprintf(stderr, \"error CryptAcquireContextW\");\n        exit(1);\n    }\n    \n    if (!CryptGenRandom(hProvider, sizeof(r), (BYTE*)&r)) \n    {\n        fprintf(stderr, \"error CryptGenRandom\");\n        exit(1);\n    }\n    \n    CryptReleaseContext(hProvider, 0);\n    \n    return r;\n}\n\n#endif\n\n\n/* get_time_seed */\n\n#include <time.h>\n\nstatic int get_time_seed()\n{\n    DEBUG_SEED(\"get_time_seed\");\n    \n    return (int)time(NULL) * 433494437;\n}\n\n\n/* json_c_get_random_seed */\n\nint json_c_get_random_seed()\n{\n#if HAVE_RDRAND\n    if (has_rdrand()) return get_rdrand_seed();\n#endif\n#if HAVE_DEV_RANDOM\n    if (has_dev_urandom()) return get_dev_random_seed();\n#endif\n#if HAVE_CRYPTGENRANDOM\n    return get_cryptgenrandom_seed();\n#endif\n    return get_time_seed();\n}\n"
  },
  {
    "path": "third_party/phlib/jsonc/random_seed.h",
    "content": "/*\n * random_seed.h\n *\n * Copyright (c) 2013 Metaparadigm Pte. Ltd.\n * Michael Clark <michael@metaparadigm.com>\n *\n * This library is free software; you can redistribute it and/or modify\n * it under the terms of the MIT license. See COPYING for details.\n *\n */\n\n#ifndef seed_h\n#define seed_h\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\nextern int json_c_get_random_seed();\n\n#ifdef __cplusplus\n}\n#endif\n\n#endif\n"
  },
  {
    "path": "third_party/phlib/kph.c",
    "content": "/*\n * Process Hacker -\n *   KProcessHacker API\n *\n * Copyright (C) 2009-2016 wj32\n *\n * This file is part of Process Hacker.\n *\n * Process Hacker is free software; you can redistribute it and/or modify\n * it under the terms of the GNU General Public License as published by\n * the Free Software Foundation, either version 3 of the License, or\n * (at your option) any later version.\n *\n * Process Hacker is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n * GNU General Public License for more details.\n *\n * You should have received a copy of the GNU General Public License\n * along with Process Hacker.  If not, see <http://www.gnu.org/licenses/>.\n */\n\n#include <ph.h>\n#include <kphuser.h>\n#include <kphuserp.h>\n\nHANDLE PhKphHandle = NULL;\nBOOLEAN PhKphVerified = FALSE;\nKPH_KEY PhKphL1Key = 0;\n\nNTSTATUS KphConnect(\n    _In_opt_ PWSTR DeviceName\n    )\n{\n    NTSTATUS status;\n    HANDLE kphHandle;\n    UNICODE_STRING objectName;\n    OBJECT_ATTRIBUTES objectAttributes;\n    IO_STATUS_BLOCK isb;\n    OBJECT_HANDLE_FLAG_INFORMATION handleFlagInfo;\n\n    if (PhKphHandle)\n        return STATUS_ADDRESS_ALREADY_EXISTS;\n\n    if (DeviceName)\n        RtlInitUnicodeString(&objectName, DeviceName);\n    else\n        RtlInitUnicodeString(&objectName, KPH_DEVICE_NAME);\n\n    InitializeObjectAttributes(\n        &objectAttributes,\n        &objectName,\n        OBJ_CASE_INSENSITIVE,\n        NULL,\n        NULL\n        );\n\n    status = NtOpenFile(\n        &kphHandle,\n        FILE_GENERIC_READ | FILE_GENERIC_WRITE,\n        &objectAttributes,\n        &isb,\n        FILE_SHARE_READ | FILE_SHARE_WRITE,\n        FILE_NON_DIRECTORY_FILE\n        );\n\n    if (NT_SUCCESS(status))\n    {\n        // Protect the handle from being closed.\n\n        handleFlagInfo.Inherit = FALSE;\n        handleFlagInfo.ProtectFromClose = TRUE;\n\n        NtSetInformationObject(\n            kphHandle,\n            ObjectHandleFlagInformation,\n            &handleFlagInfo,\n            sizeof(OBJECT_HANDLE_FLAG_INFORMATION)\n            );\n\n        PhKphHandle = kphHandle;\n        PhKphVerified = FALSE;\n        PhKphL1Key = 0;\n    }\n\n    return status;\n}\n\nNTSTATUS KphConnect2(\n    _In_opt_ PWSTR DeviceName,\n    _In_ PWSTR FileName\n    )\n{\n    return KphConnect2Ex(DeviceName, FileName, NULL);\n}\n\nNTSTATUS KphConnect2Ex(\n    _In_opt_ PWSTR DeviceName,\n    _In_ PWSTR FileName,\n    _In_opt_ PKPH_PARAMETERS Parameters\n    )\n{\n    NTSTATUS status;\n    WCHAR fullDeviceName[256];\n    PH_FORMAT format[2];\n    SC_HANDLE scmHandle;\n    SC_HANDLE serviceHandle;\n    BOOLEAN started = FALSE;\n    BOOLEAN created = FALSE;\n\n    if (!DeviceName)\n        DeviceName = KPH_DEVICE_SHORT_NAME;\n\n    PhInitFormatS(&format[0], L\"\\\\Device\\\\\");\n    PhInitFormatS(&format[1], DeviceName);\n\n    if (!PhFormatToBuffer(format, 2, fullDeviceName, sizeof(fullDeviceName), NULL))\n        return STATUS_NAME_TOO_LONG;\n\n    // Try to open the device.\n    status = KphConnect(fullDeviceName);\n\n    if (NT_SUCCESS(status) || status == STATUS_ADDRESS_ALREADY_EXISTS)\n        return status;\n\n    if (\n        status != STATUS_NO_SUCH_DEVICE &&\n        status != STATUS_NO_SUCH_FILE &&\n        status != STATUS_OBJECT_NAME_NOT_FOUND &&\n        status != STATUS_OBJECT_PATH_NOT_FOUND\n        )\n        return status;\n\n    // Load the driver, and try again.\n\n    // Try to start the service, if it exists.\n\n    scmHandle = OpenSCManager(NULL, NULL, SC_MANAGER_CONNECT);\n\n    if (scmHandle)\n    {\n        serviceHandle = OpenService(scmHandle, DeviceName, SERVICE_START);\n\n        if (serviceHandle)\n        {\n            if (StartService(serviceHandle, 0, NULL))\n                started = TRUE;\n\n            CloseServiceHandle(serviceHandle);\n        }\n\n        CloseServiceHandle(scmHandle);\n    }\n\n    if (!started && RtlDoesFileExists_U(FileName))\n    {\n        // Try to create the service.\n\n        scmHandle = OpenSCManager(NULL, NULL, SC_MANAGER_CREATE_SERVICE);\n\n        if (scmHandle)\n        {\n            serviceHandle = CreateService(\n                scmHandle,\n                DeviceName,\n                DeviceName,\n                SERVICE_ALL_ACCESS,\n                SERVICE_KERNEL_DRIVER,\n                SERVICE_DEMAND_START,\n                SERVICE_ERROR_IGNORE,\n                FileName,\n                NULL,\n                NULL,\n                NULL,\n                NULL,\n                L\"\"\n                );\n\n            if (serviceHandle)\n            {\n                created = TRUE;\n\n                KphSetServiceSecurity(serviceHandle);\n\n                // Set parameters if the caller supplied them. Note that we fail the entire function\n                // if this fails, because failing to set parameters like SecurityLevel may result in\n                // security vulnerabilities.\n                if (Parameters)\n                {\n                    status = KphSetParameters(DeviceName, Parameters);\n\n                    if (!NT_SUCCESS(status))\n                    {\n                        // Delete the service and fail.\n                        goto CreateAndConnectEnd;\n                    }\n                }\n\n                if (StartService(serviceHandle, 0, NULL))\n                    started = TRUE;\n                else\n                    status = PhGetLastWin32ErrorAsNtStatus();\n            }\n            else\n            {\n                status = PhGetLastWin32ErrorAsNtStatus();\n            }\n\n            CloseServiceHandle(scmHandle);\n        }\n    }\n\n    if (started)\n    {\n        // Try to open the device again.\n        status = KphConnect(fullDeviceName);\n    }\n\nCreateAndConnectEnd:\n    if (created && serviceHandle)\n    {\n        // \"Delete\" the service. Since we (may) have a handle to the device, the SCM will delete the\n        // service automatically when it is stopped (upon reboot). If we don't have a handle to the\n        // device, the service will get deleted immediately, which is a good thing anyway.\n        DeleteService(serviceHandle);\n        CloseServiceHandle(serviceHandle);\n    }\n\n    return status;\n}\n\nNTSTATUS KphDisconnect(\n    VOID\n    )\n{\n    NTSTATUS status;\n    OBJECT_HANDLE_FLAG_INFORMATION handleFlagInfo;\n\n    if (!PhKphHandle)\n        return STATUS_ALREADY_DISCONNECTED;\n\n    // Unprotect the handle.\n\n    handleFlagInfo.Inherit = FALSE;\n    handleFlagInfo.ProtectFromClose = FALSE;\n\n    NtSetInformationObject(\n        PhKphHandle,\n        ObjectHandleFlagInformation,\n        &handleFlagInfo,\n        sizeof(OBJECT_HANDLE_FLAG_INFORMATION)\n        );\n\n    status = NtClose(PhKphHandle);\n    PhKphHandle = NULL;\n    PhKphVerified = FALSE;\n    PhKphL1Key = 0;\n\n    return status;\n}\n\nBOOLEAN KphIsConnected(\n    VOID\n    )\n{\n    return PhKphHandle != NULL;\n}\n\nBOOLEAN KphIsVerified(\n    VOID\n    )\n{\n    return PhKphVerified;\n}\n\nNTSTATUS KphSetParameters(\n    _In_opt_ PWSTR DeviceName,\n    _In_ PKPH_PARAMETERS Parameters\n    )\n{\n    NTSTATUS status;\n    HANDLE parametersKeyHandle = NULL;\n    PPH_STRING parametersKeyName;\n    ULONG disposition;\n    UNICODE_STRING valueName;\n\n    if (!DeviceName)\n        DeviceName = KPH_DEVICE_SHORT_NAME;\n\n    parametersKeyName = PhConcatStrings(\n        3,\n        L\"System\\\\CurrentControlSet\\\\Services\\\\\",\n        DeviceName,\n        L\"\\\\Parameters\"\n        );\n    status = PhCreateKey(\n        &parametersKeyHandle,\n        KEY_WRITE | DELETE,\n        PH_KEY_LOCAL_MACHINE,\n        &parametersKeyName->sr,\n        0,\n        0,\n        &disposition\n        );\n    PhDereferenceObject(parametersKeyName);\n\n    if (!NT_SUCCESS(status))\n        return status;\n\n    RtlInitUnicodeString(&valueName, L\"SecurityLevel\");\n    status = NtSetValueKey(parametersKeyHandle, &valueName, 0, REG_DWORD, &Parameters->SecurityLevel, sizeof(ULONG));\n\n    if (!NT_SUCCESS(status))\n        goto SetValuesEnd;\n\n    if (Parameters->CreateDynamicConfiguration)\n    {\n        KPH_DYN_CONFIGURATION configuration;\n\n        RtlInitUnicodeString(&valueName, L\"DynamicConfiguration\");\n\n        configuration.Version = KPH_DYN_CONFIGURATION_VERSION;\n        configuration.NumberOfPackages = 1;\n\n        if (NT_SUCCESS(KphInitializeDynamicPackage(&configuration.Packages[0])))\n        {\n            status = NtSetValueKey(parametersKeyHandle, &valueName, 0, REG_BINARY, &configuration, sizeof(KPH_DYN_CONFIGURATION));\n\n            if (!NT_SUCCESS(status))\n                goto SetValuesEnd;\n        }\n    }\n\n    // Put more parameters here...\n\nSetValuesEnd:\n    if (!NT_SUCCESS(status))\n    {\n        // Delete the key if we created it.\n        if (disposition == REG_CREATED_NEW_KEY)\n            NtDeleteKey(parametersKeyHandle);\n    }\n\n    NtClose(parametersKeyHandle);\n\n    return status;\n}\n\nVOID KphSetServiceSecurity(\n    _In_ SC_HANDLE ServiceHandle\n    )\n{\n    static SID_IDENTIFIER_AUTHORITY ntAuthority = SECURITY_NT_AUTHORITY;\n    PSECURITY_DESCRIPTOR securityDescriptor;\n    ULONG sdAllocationLength;\n    UCHAR administratorsSidBuffer[FIELD_OFFSET(SID, SubAuthority) + sizeof(ULONG) * 2];\n    PSID administratorsSid;\n    PACL dacl;\n\n    administratorsSid = (PSID)administratorsSidBuffer;\n    RtlInitializeSid(administratorsSid, &ntAuthority, 2);\n    *RtlSubAuthoritySid(administratorsSid, 0) = SECURITY_BUILTIN_DOMAIN_RID;\n    *RtlSubAuthoritySid(administratorsSid, 1) = DOMAIN_ALIAS_RID_ADMINS;\n\n    sdAllocationLength = SECURITY_DESCRIPTOR_MIN_LENGTH +\n        (ULONG)sizeof(ACL) +\n        (ULONG)sizeof(ACCESS_ALLOWED_ACE) +\n        RtlLengthSid(&PhSeServiceSid) +\n        (ULONG)sizeof(ACCESS_ALLOWED_ACE) +\n        RtlLengthSid(administratorsSid) +\n        (ULONG)sizeof(ACCESS_ALLOWED_ACE) +\n        RtlLengthSid(&PhSeInteractiveSid);\n\n    securityDescriptor = PhAllocate(sdAllocationLength);\n    dacl = (PACL)PTR_ADD_OFFSET(securityDescriptor, SECURITY_DESCRIPTOR_MIN_LENGTH);\n\n    RtlCreateSecurityDescriptor(securityDescriptor, SECURITY_DESCRIPTOR_REVISION);\n    RtlCreateAcl(dacl, sdAllocationLength - SECURITY_DESCRIPTOR_MIN_LENGTH, ACL_REVISION);\n    RtlAddAccessAllowedAce(dacl, ACL_REVISION, SERVICE_ALL_ACCESS, &PhSeServiceSid);\n    RtlAddAccessAllowedAce(dacl, ACL_REVISION, SERVICE_ALL_ACCESS, administratorsSid);\n    RtlAddAccessAllowedAce(dacl, ACL_REVISION, \n        SERVICE_QUERY_CONFIG |\n        SERVICE_QUERY_STATUS |\n        SERVICE_START |\n        SERVICE_STOP |\n        SERVICE_INTERROGATE |\n        DELETE,\n        &PhSeInteractiveSid\n        );\n    RtlSetDaclSecurityDescriptor(securityDescriptor, TRUE, dacl, FALSE);\n\n    SetServiceObjectSecurity(ServiceHandle, DACL_SECURITY_INFORMATION, securityDescriptor);\n\n    PhFree(securityDescriptor);\n}\n\nNTSTATUS KphInstall(\n    _In_opt_ PWSTR DeviceName,\n    _In_ PWSTR FileName\n    )\n{\n    return KphInstallEx(DeviceName, FileName, NULL);\n}\n\nNTSTATUS KphInstallEx(\n    _In_opt_ PWSTR DeviceName,\n    _In_ PWSTR FileName,\n    _In_opt_ PKPH_PARAMETERS Parameters\n    )\n{\n    NTSTATUS status = STATUS_SUCCESS;\n    SC_HANDLE scmHandle;\n    SC_HANDLE serviceHandle;\n\n    if (!DeviceName)\n        DeviceName = KPH_DEVICE_SHORT_NAME;\n\n    scmHandle = OpenSCManager(NULL, NULL, SC_MANAGER_CREATE_SERVICE);\n\n    if (!scmHandle)\n        return PhGetLastWin32ErrorAsNtStatus();\n\n    serviceHandle = CreateService(\n        scmHandle,\n        DeviceName,\n        DeviceName,\n        SERVICE_ALL_ACCESS,\n        SERVICE_KERNEL_DRIVER,\n        SERVICE_SYSTEM_START,\n        SERVICE_ERROR_IGNORE,\n        FileName,\n        NULL,\n        NULL,\n        NULL,\n        NULL,\n        L\"\"\n        );\n\n    if (serviceHandle)\n    {\n        KphSetServiceSecurity(serviceHandle);\n\n        // See KphConnect2Ex for more details.\n        if (Parameters)\n        {\n            status = KphSetParameters(DeviceName, Parameters);\n\n            if (!NT_SUCCESS(status))\n            {\n                DeleteService(serviceHandle);\n                goto CreateEnd;\n            }\n        }\n\n        if (!StartService(serviceHandle, 0, NULL))\n            status = PhGetLastWin32ErrorAsNtStatus();\n\nCreateEnd:\n        CloseServiceHandle(serviceHandle);\n    }\n    else\n    {\n        status = PhGetLastWin32ErrorAsNtStatus();\n    }\n\n    CloseServiceHandle(scmHandle);\n\n    return status;\n}\n\nNTSTATUS KphUninstall(\n    _In_opt_ PWSTR DeviceName\n    )\n{\n    NTSTATUS status = STATUS_SUCCESS;\n    SC_HANDLE scmHandle;\n    SC_HANDLE serviceHandle;\n\n    if (!DeviceName)\n        DeviceName = KPH_DEVICE_SHORT_NAME;\n\n    scmHandle = OpenSCManager(NULL, NULL, SC_MANAGER_CONNECT);\n\n    if (!scmHandle)\n        return PhGetLastWin32ErrorAsNtStatus();\n\n    serviceHandle = OpenService(scmHandle, DeviceName, SERVICE_STOP | DELETE);\n\n    if (serviceHandle)\n    {\n        SERVICE_STATUS serviceStatus;\n\n        ControlService(serviceHandle, SERVICE_CONTROL_STOP, &serviceStatus);\n\n        if (!DeleteService(serviceHandle))\n            status = PhGetLastWin32ErrorAsNtStatus();\n\n        CloseServiceHandle(serviceHandle);\n    }\n    else\n    {\n        status = PhGetLastWin32ErrorAsNtStatus();\n    }\n\n    CloseServiceHandle(scmHandle);\n\n    return status;\n}\n\nNTSTATUS KphGetFeatures(\n    _Out_ PULONG Features\n    )\n{\n    struct\n    {\n        PULONG Features;\n    } input = { Features };\n\n    return KphpDeviceIoControl(\n        KPH_GETFEATURES,\n        &input,\n        sizeof(input)\n        );\n}\n\nNTSTATUS KphVerifyClient(\n    _In_reads_bytes_(SignatureSize) PUCHAR Signature,\n    _In_ ULONG SignatureSize\n    )\n{\n    NTSTATUS status;\n    struct\n    {\n        PVOID CodeAddress;\n        PUCHAR Signature;\n        ULONG SignatureSize;\n    } input = { KphpWithKeyApcRoutine, Signature, SignatureSize };\n\n    status = KphpDeviceIoControl(\n        KPH_VERIFYCLIENT,\n        &input,\n        sizeof(input)\n        );\n\n    if (NT_SUCCESS(status))\n        PhKphVerified = TRUE;\n\n    return status;\n}\n\nNTSTATUS KphOpenProcess(\n    _Out_ PHANDLE ProcessHandle,\n    _In_ ACCESS_MASK DesiredAccess,\n    _In_ PCLIENT_ID ClientId\n    )\n{\n    KPH_OPEN_PROCESS_INPUT input = { ProcessHandle, DesiredAccess, ClientId, 0 };\n\n    if ((DesiredAccess & KPH_PROCESS_READ_ACCESS) == DesiredAccess)\n    {\n        KphpGetL1Key(&input.Key);\n        return KphpDeviceIoControl(\n            KPH_OPENPROCESS,\n            &input,\n            sizeof(input)\n            );\n    }\n    else\n    {\n        return KphpWithKey(KphKeyLevel2, KphpOpenProcessContinuation, &input);\n    }\n}\n\nNTSTATUS KphOpenProcessToken(\n    _In_ HANDLE ProcessHandle,\n    _In_ ACCESS_MASK DesiredAccess,\n    _Out_ PHANDLE TokenHandle\n    )\n{\n    KPH_OPEN_PROCESS_TOKEN_INPUT input = { ProcessHandle, DesiredAccess, TokenHandle, 0 };\n\n    if ((DesiredAccess & KPH_TOKEN_READ_ACCESS) == DesiredAccess)\n    {\n        KphpGetL1Key(&input.Key);\n        return KphpDeviceIoControl(\n            KPH_OPENPROCESSTOKEN,\n            &input,\n            sizeof(input)\n            );\n    }\n    else\n    {\n        return KphpWithKey(KphKeyLevel2, KphpOpenProcessTokenContinuation, &input);\n    }\n}\n\nNTSTATUS KphOpenProcessJob(\n    _In_ HANDLE ProcessHandle,\n    _In_ ACCESS_MASK DesiredAccess,\n    _Out_ PHANDLE JobHandle\n    )\n{\n    struct\n    {\n        HANDLE ProcessHandle;\n        ACCESS_MASK DesiredAccess;\n        PHANDLE JobHandle;\n    } input = { ProcessHandle, DesiredAccess, JobHandle };\n\n    return KphpDeviceIoControl(\n        KPH_OPENPROCESSJOB,\n        &input,\n        sizeof(input)\n        );\n}\n\nNTSTATUS KphTerminateProcess(\n    _In_ HANDLE ProcessHandle,\n    _In_ NTSTATUS ExitStatus\n    )\n{\n    NTSTATUS status;\n    KPH_TERMINATE_PROCESS_INPUT input = { ProcessHandle, ExitStatus, 0 };\n\n    status = KphpWithKey(KphKeyLevel2, KphpTerminateProcessContinuation, &input);\n\n    // Check if we're trying to terminate the current process, because kernel-mode can't do it.\n    if (status == STATUS_CANT_TERMINATE_SELF)\n    {\n        RtlExitUserProcess(ExitStatus);\n    }\n\n    return status;\n}\n\nNTSTATUS KphReadVirtualMemoryUnsafe(\n    _In_opt_ HANDLE ProcessHandle,\n    _In_ PVOID BaseAddress,\n    _Out_writes_bytes_(BufferSize) PVOID Buffer,\n    _In_ SIZE_T BufferSize,\n    _Out_opt_ PSIZE_T NumberOfBytesRead\n    )\n{\n    KPH_READ_VIRTUAL_MEMORY_UNSAFE_INPUT input = { ProcessHandle, BaseAddress, Buffer, BufferSize, NumberOfBytesRead, 0 };\n\n    return KphpWithKey(KphKeyLevel2, KphpReadVirtualMemoryUnsafeContinuation, &input);\n}\n\nNTSTATUS KphQueryInformationProcess(\n    _In_ HANDLE ProcessHandle,\n    _In_ KPH_PROCESS_INFORMATION_CLASS ProcessInformationClass,\n    _Out_writes_bytes_(ProcessInformationLength) PVOID ProcessInformation,\n    _In_ ULONG ProcessInformationLength,\n    _Out_opt_ PULONG ReturnLength\n    )\n{\n    struct\n    {\n        HANDLE ProcessHandle;\n        KPH_PROCESS_INFORMATION_CLASS ProcessInformationClass;\n        PVOID ProcessInformation;\n        ULONG ProcessInformationLength;\n        PULONG ReturnLength;\n    } input = { ProcessHandle, ProcessInformationClass, ProcessInformation, ProcessInformationLength, ReturnLength };\n\n    return KphpDeviceIoControl(\n        KPH_QUERYINFORMATIONPROCESS,\n        &input,\n        sizeof(input)\n        );\n}\n\nNTSTATUS KphSetInformationProcess(\n    _In_ HANDLE ProcessHandle,\n    _In_ KPH_PROCESS_INFORMATION_CLASS ProcessInformationClass,\n    _In_reads_bytes_(ProcessInformationLength) PVOID ProcessInformation,\n    _In_ ULONG ProcessInformationLength\n    )\n{\n    struct\n    {\n        HANDLE ProcessHandle;\n        KPH_PROCESS_INFORMATION_CLASS ProcessInformationClass;\n        PVOID ProcessInformation;\n        ULONG ProcessInformationLength;\n    } input = { ProcessHandle, ProcessInformationClass, ProcessInformation, ProcessInformationLength };\n\n    return KphpDeviceIoControl(\n        KPH_SETINFORMATIONPROCESS,\n        &input,\n        sizeof(input)\n        );\n}\n\nNTSTATUS KphOpenThread(\n    _Out_ PHANDLE ThreadHandle,\n    _In_ ACCESS_MASK DesiredAccess,\n    _In_ PCLIENT_ID ClientId\n    )\n{\n    KPH_OPEN_THREAD_INPUT input = { ThreadHandle, DesiredAccess, ClientId, 0 };\n\n    if ((DesiredAccess & KPH_THREAD_READ_ACCESS) == DesiredAccess)\n    {\n        KphpGetL1Key(&input.Key);\n        return KphpDeviceIoControl(\n            KPH_OPENTHREAD,\n            &input,\n            sizeof(input)\n            );\n    }\n    else\n    {\n        return KphpWithKey(KphKeyLevel2, KphpOpenThreadContinuation, &input);\n    }\n}\n\nNTSTATUS KphOpenThreadProcess(\n    _In_ HANDLE ThreadHandle,\n    _In_ ACCESS_MASK DesiredAccess,\n    _Out_ PHANDLE ProcessHandle\n    )\n{\n    struct\n    {\n        HANDLE ThreadHandle;\n        ACCESS_MASK DesiredAccess;\n        PHANDLE ProcessHandle;\n    } input = { ThreadHandle, DesiredAccess, ProcessHandle };\n\n    return KphpDeviceIoControl(\n        KPH_OPENTHREADPROCESS,\n        &input,\n        sizeof(input)\n        );\n}\n\nNTSTATUS KphCaptureStackBackTraceThread(\n    _In_ HANDLE ThreadHandle,\n    _In_ ULONG FramesToSkip,\n    _In_ ULONG FramesToCapture,\n    _Out_writes_(FramesToCapture) PVOID *BackTrace,\n    _Out_opt_ PULONG CapturedFrames,\n    _Out_opt_ PULONG BackTraceHash\n    )\n{\n    struct\n    {\n        HANDLE ThreadHandle;\n        ULONG FramesToSkip;\n        ULONG FramesToCapture;\n        PVOID *BackTrace;\n        PULONG CapturedFrames;\n        PULONG BackTraceHash;\n    } input = { ThreadHandle, FramesToSkip, FramesToCapture, BackTrace, CapturedFrames, BackTraceHash };\n\n    return KphpDeviceIoControl(\n        KPH_CAPTURESTACKBACKTRACETHREAD,\n        &input,\n        sizeof(input)\n        );\n}\n\nNTSTATUS KphQueryInformationThread(\n    _In_ HANDLE ThreadHandle,\n    _In_ KPH_THREAD_INFORMATION_CLASS ThreadInformationClass,\n    _Out_writes_bytes_(ThreadInformationLength) PVOID ThreadInformation,\n    _In_ ULONG ThreadInformationLength,\n    _Out_opt_ PULONG ReturnLength\n    )\n{\n    struct\n    {\n        HANDLE ThreadHandle;\n        KPH_THREAD_INFORMATION_CLASS ThreadInformationClass;\n        PVOID ThreadInformation;\n        ULONG ThreadInformationLength;\n        PULONG ReturnLength;\n    } input = { ThreadHandle, ThreadInformationClass, ThreadInformation, ThreadInformationLength, ReturnLength };\n\n    return KphpDeviceIoControl(\n        KPH_QUERYINFORMATIONTHREAD,\n        &input,\n        sizeof(input)\n        );\n}\n\nNTSTATUS KphSetInformationThread(\n    _In_ HANDLE ThreadHandle,\n    _In_ KPH_THREAD_INFORMATION_CLASS ThreadInformationClass,\n    _In_reads_bytes_(ThreadInformationLength) PVOID ThreadInformation,\n    _In_ ULONG ThreadInformationLength\n    )\n{\n    struct\n    {\n        HANDLE ThreadHandle;\n        KPH_THREAD_INFORMATION_CLASS ThreadInformationClass;\n        PVOID ThreadInformation;\n        ULONG ThreadInformationLength;\n    } input = { ThreadHandle, ThreadInformationClass, ThreadInformation, ThreadInformationLength };\n\n    return KphpDeviceIoControl(\n        KPH_SETINFORMATIONTHREAD,\n        &input,\n        sizeof(input)\n        );\n}\n\nNTSTATUS KphEnumerateProcessHandles(\n    _In_ HANDLE ProcessHandle,\n    _Out_writes_bytes_(BufferLength) PVOID Buffer,\n    _In_opt_ ULONG BufferLength,\n    _Out_opt_ PULONG ReturnLength\n    )\n{\n    struct\n    {\n        HANDLE ProcessHandle;\n        PVOID Buffer;\n        ULONG BufferLength;\n        PULONG ReturnLength;\n    } input = { ProcessHandle, Buffer, BufferLength, ReturnLength };\n\n    return KphpDeviceIoControl(\n        KPH_ENUMERATEPROCESSHANDLES,\n        &input,\n        sizeof(input)\n        );\n}\n\nNTSTATUS KphEnumerateProcessHandles2(\n    _In_ HANDLE ProcessHandle,\n    _Out_ PKPH_PROCESS_HANDLE_INFORMATION *Handles\n    )\n{\n    NTSTATUS status;\n    PVOID buffer;\n    ULONG bufferSize = 2048;\n\n    buffer = PhAllocate(bufferSize);\n\n    while (TRUE)\n    {\n        status = KphEnumerateProcessHandles(\n            ProcessHandle,\n            buffer,\n            bufferSize,\n            &bufferSize\n            );\n\n        if (status == STATUS_BUFFER_TOO_SMALL)\n        {\n            PhFree(buffer);\n            buffer = PhAllocate(bufferSize);\n        }\n        else\n        {\n            break;\n        }\n    }\n\n    if (!NT_SUCCESS(status))\n    {\n        PhFree(buffer);\n        return status;\n    }\n\n    *Handles = buffer;\n\n    return status;\n}\n\nNTSTATUS KphQueryInformationObject(\n    _In_ HANDLE ProcessHandle,\n    _In_ HANDLE Handle,\n    _In_ KPH_OBJECT_INFORMATION_CLASS ObjectInformationClass,\n    _Out_writes_bytes_(ObjectInformationLength) PVOID ObjectInformation,\n    _In_ ULONG ObjectInformationLength,\n    _Out_opt_ PULONG ReturnLength\n    )\n{\n    struct\n    {\n        HANDLE ProcessHandle;\n        HANDLE Handle;\n        KPH_OBJECT_INFORMATION_CLASS ObjectInformationClass;\n        PVOID ObjectInformation;\n        ULONG ObjectInformationLength;\n        PULONG ReturnLength;\n    } input = { ProcessHandle, Handle, ObjectInformationClass, ObjectInformation, ObjectInformationLength, ReturnLength };\n\n    return KphpDeviceIoControl(\n        KPH_QUERYINFORMATIONOBJECT,\n        &input,\n        sizeof(input)\n        );\n}\n\nNTSTATUS KphSetInformationObject(\n    _In_ HANDLE ProcessHandle,\n    _In_ HANDLE Handle,\n    _In_ KPH_OBJECT_INFORMATION_CLASS ObjectInformationClass,\n    _In_reads_bytes_(ObjectInformationLength) PVOID ObjectInformation,\n    _In_ ULONG ObjectInformationLength\n    )\n{\n    struct\n    {\n        HANDLE ProcessHandle;\n        HANDLE Handle;\n        KPH_OBJECT_INFORMATION_CLASS ObjectInformationClass;\n        PVOID ObjectInformation;\n        ULONG ObjectInformationLength;\n    } input = { ProcessHandle, Handle, ObjectInformationClass, ObjectInformation, ObjectInformationLength };\n\n    return KphpDeviceIoControl(\n        KPH_SETINFORMATIONOBJECT,\n        &input,\n        sizeof(input)\n        );\n}\n\nNTSTATUS KphOpenDriver(\n    _Out_ PHANDLE DriverHandle,\n    _In_ ACCESS_MASK DesiredAccess,\n    _In_ POBJECT_ATTRIBUTES ObjectAttributes\n    )\n{\n    struct\n    {\n        PHANDLE DriverHandle;\n        ACCESS_MASK DesiredAccess;\n        POBJECT_ATTRIBUTES ObjectAttributes;\n    } input = { DriverHandle, DesiredAccess, ObjectAttributes };\n\n    return KphpDeviceIoControl(\n        KPH_OPENDRIVER,\n        &input,\n        sizeof(input)\n        );\n}\n\nNTSTATUS KphQueryInformationDriver(\n    _In_ HANDLE DriverHandle,\n    _In_ DRIVER_INFORMATION_CLASS DriverInformationClass,\n    _Out_writes_bytes_(DriverInformationLength) PVOID DriverInformation,\n    _In_ ULONG DriverInformationLength,\n    _Out_opt_ PULONG ReturnLength\n    )\n{\n    struct\n    {\n        HANDLE DriverHandle;\n        DRIVER_INFORMATION_CLASS DriverInformationClass;\n        PVOID DriverInformation;\n        ULONG DriverInformationLength;\n        PULONG ReturnLength;\n    } input = { DriverHandle, DriverInformationClass, DriverInformation, DriverInformationLength, ReturnLength };\n\n    return KphpDeviceIoControl(\n        KPH_QUERYINFORMATIONDRIVER,\n        &input,\n        sizeof(input)\n        );\n}\n\nNTSTATUS KphpDeviceIoControl(\n    _In_ ULONG KphControlCode,\n    _In_ PVOID InBuffer,\n    _In_ ULONG InBufferLength\n    )\n{\n    IO_STATUS_BLOCK iosb;\n\n    return NtDeviceIoControlFile(\n        PhKphHandle,\n        NULL,\n        NULL,\n        NULL,\n        &iosb,\n        KphControlCode,\n        InBuffer,\n        InBufferLength,\n        NULL,\n        0\n        );\n}\n\nVOID KphpWithKeyApcRoutine(\n    _In_ PVOID ApcContext,\n    _In_ PIO_STATUS_BLOCK IoStatusBlock,\n    _In_ ULONG Reserved\n    )\n{\n    PKPHP_RETRIEVE_KEY_CONTEXT context = CONTAINING_RECORD(IoStatusBlock, KPHP_RETRIEVE_KEY_CONTEXT, Iosb);\n    KPH_KEY key = PtrToUlong(ApcContext);\n\n    if (context->Continuation != KphpGetL1KeyContinuation &&\n        context->Continuation != KphpOpenProcessContinuation &&\n        context->Continuation != KphpOpenProcessTokenContinuation &&\n        context->Continuation != KphpTerminateProcessContinuation &&\n        context->Continuation != KphpReadVirtualMemoryUnsafeContinuation &&\n        context->Continuation != KphpOpenThreadContinuation)\n    {\n        PhRaiseStatus(STATUS_ACCESS_DENIED);\n        context->Status = STATUS_ACCESS_DENIED;\n        return;\n    }\n\n    context->Status = context->Continuation(key, context->Context);\n}\n\nNTSTATUS KphpWithKey(\n    _In_ KPH_KEY_LEVEL KeyLevel,\n    _In_ PKPHP_WITH_KEY_CONTINUATION Continuation,\n    _In_ PVOID Context\n    )\n{\n    NTSTATUS status;\n    struct\n    {\n        KPH_KEY_LEVEL KeyLevel;\n    } input = { KeyLevel };\n    KPHP_RETRIEVE_KEY_CONTEXT context;\n\n    context.Continuation = Continuation;\n    context.Context = Context;\n    context.Status = STATUS_UNSUCCESSFUL;\n\n    status = NtDeviceIoControlFile(\n        PhKphHandle,\n        NULL,\n        KphpWithKeyApcRoutine,\n        NULL,\n        &context.Iosb,\n        KPH_RETRIEVEKEY,\n        &input,\n        sizeof(input),\n        NULL,\n        0\n        );\n\n    NtTestAlert();\n\n    if (!NT_SUCCESS(status))\n        return status;\n\n    return context.Status;\n}\n\nNTSTATUS KphpGetL1KeyContinuation(\n    _In_ KPH_KEY Key,\n    _In_ PVOID Context\n    )\n{\n    PKPHP_GET_L1_KEY_CONTEXT context = Context;\n\n    *context->Key = Key;\n    PhKphL1Key = Key;\n\n    return STATUS_SUCCESS;\n}\n\nNTSTATUS KphpGetL1Key(\n    _Out_ PKPH_KEY Key\n    )\n{\n    KPHP_GET_L1_KEY_CONTEXT context;\n\n    if (PhKphL1Key)\n    {\n        *Key = PhKphL1Key;\n        return STATUS_SUCCESS;\n    }\n\n    context.Key = Key;\n\n    return KphpWithKey(KphKeyLevel1, KphpGetL1KeyContinuation, &context);\n}\n\nNTSTATUS KphpOpenProcessContinuation(\n    _In_ KPH_KEY Key,\n    _In_ PVOID Context\n    )\n{\n    PKPH_OPEN_PROCESS_INPUT input = Context;\n\n    input->Key = Key;\n\n    return KphpDeviceIoControl(\n        KPH_OPENPROCESS,\n        input,\n        sizeof(*input)\n        );\n}\n\nNTSTATUS KphpOpenProcessTokenContinuation(\n    _In_ KPH_KEY Key,\n    _In_ PVOID Context\n    )\n{\n    PKPH_OPEN_PROCESS_TOKEN_INPUT input = Context;\n\n    input->Key = Key;\n\n    return KphpDeviceIoControl(\n        KPH_OPENPROCESSTOKEN,\n        input,\n        sizeof(*input)\n        );\n}\n\nNTSTATUS KphpTerminateProcessContinuation(\n    _In_ KPH_KEY Key,\n    _In_ PVOID Context\n    )\n{\n    PKPH_TERMINATE_PROCESS_INPUT input = Context;\n\n    input->Key = Key;\n\n    return KphpDeviceIoControl(\n        KPH_TERMINATEPROCESS,\n        input,\n        sizeof(*input)\n        );\n}\n\nNTSTATUS KphpReadVirtualMemoryUnsafeContinuation(\n    _In_ KPH_KEY Key,\n    _In_ PVOID Context\n    )\n{\n    PKPH_READ_VIRTUAL_MEMORY_UNSAFE_INPUT input = Context;\n\n    input->Key = Key;\n\n    return KphpDeviceIoControl(\n        KPH_READVIRTUALMEMORYUNSAFE,\n        input,\n        sizeof(*input)\n        );\n}\n\nNTSTATUS KphpOpenThreadContinuation(\n    _In_ KPH_KEY Key,\n    _In_ PVOID Context\n    )\n{\n    PKPH_OPEN_PROCESS_INPUT input = Context;\n\n    input->Key = Key;\n\n    return KphpDeviceIoControl(\n        KPH_OPENTHREAD,\n        input,\n        sizeof(*input)\n        );\n}\n"
  },
  {
    "path": "third_party/phlib/kphdata.c",
    "content": "/*\n * Process Hacker -\n *   KProcessHacker dynamic data definitions\n *\n * Copyright (C) 2011-2016 wj32\n * Copyright (C) 2017 dmex\n *\n * This file is part of Process Hacker.\n *\n * Process Hacker is free software; you can redistribute it and/or modify\n * it under the terms of the GNU General Public License as published by\n * the Free Software Foundation, either version 3 of the License, or\n * (at your option) any later version.\n *\n * Process Hacker is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n * GNU General Public License for more details.\n *\n * You should have received a copy of the GNU General Public License\n * along with Process Hacker.  If not, see <http://www.gnu.org/licenses/>.\n */\n\n#include <ph.h>\n#include <kphuser.h>\n\n#ifdef _WIN64\n\nULONG KphpGetKernelRevisionNumber(\n    VOID\n    )\n{\n    ULONG result;\n    PPH_STRING kernelFileName;\n    PVOID versionInfo;\n    VS_FIXEDFILEINFO *rootBlock;\n    ULONG rootBlockLength;\n\n    result = 0;\n    kernelFileName = PhGetKernelFileName();\n    PhMoveReference(&kernelFileName, PhGetFileName(kernelFileName));\n    versionInfo = PhGetFileVersionInfo(kernelFileName->Buffer);\n    PhDereferenceObject(kernelFileName);\n\n    if (versionInfo && VerQueryValue(versionInfo, L\"\\\\\", &rootBlock, &rootBlockLength) && rootBlockLength != 0)\n        result = rootBlock->dwFileVersionLS & 0xffff;\n\n    PhFree(versionInfo);\n\n    return result;\n}\n\nNTSTATUS KphInitializeDynamicPackage(\n    _Out_ PKPH_DYN_PACKAGE Package\n    )\n{\n    ULONG majorVersion, minorVersion, servicePack, buildNumber;\n\n    majorVersion = PhOsVersion.dwMajorVersion;\n    minorVersion = PhOsVersion.dwMinorVersion;\n    servicePack = PhOsVersion.wServicePackMajor;\n    buildNumber = PhOsVersion.dwBuildNumber;\n\n    memset(&Package->StructData, -1, sizeof(KPH_DYN_STRUCT_DATA));\n\n    Package->MajorVersion = (USHORT)majorVersion;\n    Package->MinorVersion = (USHORT)minorVersion;\n    Package->ServicePackMajor = (USHORT)servicePack;\n    Package->BuildNumber = -1;\n\n    // Windows 7, Windows Server 2008 R2\n    if (majorVersion == 6 && minorVersion == 1)\n    {\n        ULONG revisionNumber = KphpGetKernelRevisionNumber();\n\n        Package->ResultingNtVersion = PHNT_WIN7;\n\n        if (servicePack == 0)\n        {\n        }\n        else if (servicePack == 1)\n        {\n        }\n        else\n        {\n            return STATUS_NOT_SUPPORTED;\n        }\n\n        Package->StructData.EgeGuid = 0x14;\n        Package->StructData.EpObjectTable = 0x200;\n        Package->StructData.EreGuidEntry = revisionNumber >= 19160 ? 0x20 : 0x10;\n        Package->StructData.OtName = 0x10;\n        Package->StructData.OtIndex = 0x28; // now only a UCHAR, not a ULONG\n    }\n    // Windows 8, Windows Server 2012\n    else if (majorVersion == 6 && minorVersion == 2 && buildNumber == 9200)\n    {\n        Package->BuildNumber = 9200;\n        Package->ResultingNtVersion = PHNT_WIN8;\n\n        Package->StructData.EgeGuid = 0x14;\n        Package->StructData.EpObjectTable = 0x408;\n        Package->StructData.EreGuidEntry = 0x10;\n        Package->StructData.HtHandleContentionEvent = 0x30;\n        Package->StructData.OtName = 0x10;\n        Package->StructData.OtIndex = 0x28;\n        Package->StructData.ObDecodeShift = 19;\n        Package->StructData.ObAttributesShift = 20;\n    }\n    // Windows 8.1, Windows Server 2012 R2\n    else if (majorVersion == 6 && minorVersion == 3 && buildNumber == 9600)\n    {\n        ULONG revisionNumber = KphpGetKernelRevisionNumber();\n\n        Package->BuildNumber = 9600;\n        Package->ResultingNtVersion = PHNT_WINBLUE;\n\n        Package->StructData.EgeGuid = 0x18;\n        Package->StructData.EpObjectTable = 0x408;\n        Package->StructData.EreGuidEntry = revisionNumber >= 17736 ? 0x20 : 0x10;\n        Package->StructData.HtHandleContentionEvent = 0x30;\n        Package->StructData.OtName = 0x10;\n        Package->StructData.OtIndex = 0x28;\n        Package->StructData.ObDecodeShift = 16;\n        Package->StructData.ObAttributesShift = 17;\n    }\n    // Windows 10\n    else if (majorVersion == 10 && minorVersion == 0)\n    {\n        switch (buildNumber)\n        {\n        case 10240:\n            Package->BuildNumber = 10240;\n            Package->ResultingNtVersion = PHNT_THRESHOLD;\n            break;\n        case 10586:\n            Package->BuildNumber = 10586;\n            Package->ResultingNtVersion = PHNT_THRESHOLD2;\n            break;\n        case 14393:\n            Package->BuildNumber = 14393;\n            Package->ResultingNtVersion = PHNT_REDSTONE;\n            break;\n        case 15063:\n            Package->BuildNumber = 15063;\n            Package->ResultingNtVersion = PHNT_REDSTONE2;\n            break;\n        case 16299:\n            Package->BuildNumber = 16299;\n            Package->ResultingNtVersion = PHNT_REDSTONE3;\n            break;\n        default:\n            Package->BuildNumber = USHRT_MAX;\n            Package->ResultingNtVersion = PHNT_THRESHOLD;\n            break;\n        }\n\n        Package->StructData.EgeGuid = 0x18;\n        Package->StructData.EpObjectTable = 0x418;\n        Package->StructData.EreGuidEntry = 0x20;\n        Package->StructData.HtHandleContentionEvent = 0x30;\n        Package->StructData.OtName = 0x10;\n        Package->StructData.OtIndex = 0x28;\n        Package->StructData.ObDecodeShift = 16;\n        Package->StructData.ObAttributesShift = 17;\n    }\n    else\n    {\n        return STATUS_NOT_SUPPORTED;\n    }\n\n    return STATUS_SUCCESS;\n}\n\n#else\n\nNTSTATUS KphInitializeDynamicPackage(\n    _Out_ PKPH_DYN_PACKAGE Package\n    )\n{\n    ULONG majorVersion, minorVersion, servicePack, buildNumber;\n\n    majorVersion = PhOsVersion.dwMajorVersion;\n    minorVersion = PhOsVersion.dwMinorVersion;\n    servicePack = PhOsVersion.wServicePackMajor;\n    buildNumber = PhOsVersion.dwBuildNumber;\n\n    memset(&Package->StructData, -1, sizeof(KPH_DYN_STRUCT_DATA));\n\n    Package->MajorVersion = (USHORT)majorVersion;\n    Package->MinorVersion = (USHORT)minorVersion;\n    Package->ServicePackMajor = (USHORT)servicePack;\n    Package->BuildNumber = -1;\n\n    // Windows 7, Windows Server 2008 R2\n    if (majorVersion == 6 && minorVersion == 1)\n    {\n        Package->ResultingNtVersion = PHNT_WIN7;\n\n        if (servicePack == 0)\n        {\n            NOTHING;\n        }\n        else if (servicePack == 1)\n        {\n            NOTHING;\n        }\n        else\n        {\n            return STATUS_NOT_SUPPORTED;\n        }\n\n        Package->StructData.EgeGuid = 0xc;\n        Package->StructData.EpObjectTable = 0xf4;\n        Package->StructData.EreGuidEntry = 0x8;\n        Package->StructData.OtName = 0x8;\n        Package->StructData.OtIndex = 0x14; // now only a UCHAR, not a ULONG\n    }\n    // Windows 8, Windows Server 2012\n    else if (majorVersion == 6 && minorVersion == 2)\n    {\n        Package->ResultingNtVersion = PHNT_WIN8;\n\n        if (servicePack == 0)\n        {\n            NOTHING;\n        }\n        else\n        {\n            return STATUS_NOT_SUPPORTED;\n        }\n\n        Package->StructData.EgeGuid = 0xc;\n        Package->StructData.EpObjectTable = 0x150;\n        Package->StructData.EreGuidEntry = 0x8;\n        Package->StructData.OtName = 0x8;\n        Package->StructData.OtIndex = 0x14;\n    }\n    // Windows 8.1, Windows Server 2012 R2\n    else if (majorVersion == 6 && minorVersion == 3)\n    {\n        Package->ResultingNtVersion = PHNT_WINBLUE;\n\n        if (servicePack == 0)\n        {\n            NOTHING;\n        }\n        else\n        {\n            return STATUS_NOT_SUPPORTED;\n        }\n\n        Package->StructData.EgeGuid = 0xc;\n        Package->StructData.EpObjectTable = 0x150;\n        Package->StructData.EreGuidEntry = 0x8;\n        Package->StructData.OtName = 0x8;\n        Package->StructData.OtIndex = 0x14;\n    }\n    // Windows 10\n    else if (majorVersion == 10 && minorVersion == 0)\n    {\n        switch (buildNumber)\n        {\n        case 10240:\n            Package->BuildNumber = 10240;\n            Package->ResultingNtVersion = PHNT_THRESHOLD;\n            break;\n        case 10586:\n            Package->BuildNumber = 10586;\n            Package->ResultingNtVersion = PHNT_THRESHOLD2;\n            break;\n        case 14393:\n            Package->BuildNumber = 14393;\n            Package->ResultingNtVersion = PHNT_REDSTONE;\n            break;\n        case 15063:\n            Package->BuildNumber = 15063;\n            Package->ResultingNtVersion = PHNT_REDSTONE2;\n            break;\n        case 16299:\n            Package->BuildNumber = 16299;\n            Package->ResultingNtVersion = PHNT_REDSTONE3;\n            break;\n        default:\n            Package->BuildNumber = USHRT_MAX;\n            Package->ResultingNtVersion = PHNT_THRESHOLD;\n            break;\n        }\n\n        Package->StructData.EgeGuid = 0xc;\n        Package->StructData.EpObjectTable = 0x154;\n        Package->StructData.EreGuidEntry = 0x10;\n        Package->StructData.OtName = 0x8;\n        Package->StructData.OtIndex = 0x14;\n    }\n    else\n    {\n        return STATUS_NOT_SUPPORTED;\n    }\n\n    return STATUS_SUCCESS;\n}\n\n#endif\n"
  },
  {
    "path": "third_party/phlib/lsasup.c",
    "content": "/*\n * Process Hacker -\n *   LSA support functions\n *\n * Copyright (C) 2010-2011 wj32\n *\n * This file is part of Process Hacker.\n *\n * Process Hacker is free software; you can redistribute it and/or modify\n * it under the terms of the GNU General Public License as published by\n * the Free Software Foundation, either version 3 of the License, or\n * (at your option) any later version.\n *\n * Process Hacker is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n * GNU General Public License for more details.\n *\n * You should have received a copy of the GNU General Public License\n * along with Process Hacker.  If not, see <http://www.gnu.org/licenses/>.\n */\n\n/*\n * These are functions which communicate with LSA or are support functions. They replace certain\n * Win32 security-related functions such as LookupAccountName, LookupAccountSid and\n * LookupPrivilege*, which are badly designed. (LSA already allocates the return values for the\n * caller, yet the Win32 functions insist on their callers providing their own buffers.)\n */\n\n#include <ph.h>\n#include <lsasup.h>\n\nstatic LSA_HANDLE PhLookupPolicyHandle = NULL;\n\nNTSTATUS PhOpenLsaPolicy(\n    _Out_ PLSA_HANDLE PolicyHandle,\n    _In_ ACCESS_MASK DesiredAccess,\n    _In_opt_ PUNICODE_STRING SystemName\n    )\n{\n    OBJECT_ATTRIBUTES objectAttributes;\n\n    InitializeObjectAttributes(&objectAttributes, NULL, 0, NULL, NULL);\n\n    return LsaOpenPolicy(\n        SystemName,\n        &objectAttributes,\n        DesiredAccess,\n        PolicyHandle\n        );\n}\n\n/**\n * Retrieves a handle to the local LSA policy with POLICY_LOOKUP_NAMES access.\n *\n * \\remarks Do not close the handle; it is cached.\n */\nLSA_HANDLE PhGetLookupPolicyHandle(\n    VOID\n    )\n{\n    LSA_HANDLE lookupPolicyHandle;\n    LSA_HANDLE newLookupPolicyHandle;\n\n    lookupPolicyHandle = PhLookupPolicyHandle;\n\n    // If there is no cached handle, open one.\n\n    if (!lookupPolicyHandle)\n    {\n        if (NT_SUCCESS(PhOpenLsaPolicy(\n            &newLookupPolicyHandle,\n            POLICY_LOOKUP_NAMES,\n            NULL\n            )))\n        {\n            // We succeeded in opening a policy handle, and since we did not have a cached handle\n            // before, we will now store it.\n\n            lookupPolicyHandle = _InterlockedCompareExchangePointer(\n                &PhLookupPolicyHandle,\n                newLookupPolicyHandle,\n                NULL\n                );\n\n            if (!lookupPolicyHandle)\n            {\n                // Success. Use our handle.\n                lookupPolicyHandle = newLookupPolicyHandle;\n            }\n            else\n            {\n                // Someone already placed a handle in the cache. Close our handle and use their\n                // handle.\n                LsaClose(newLookupPolicyHandle);\n            }\n        }\n    }\n\n    return lookupPolicyHandle;\n}\n\n/**\n * Gets the name of a privilege from its LUID.\n *\n * \\param PrivilegeValue The LUID of a privilege.\n * \\param PrivilegeName A variable which receives a pointer to a string containing the privilege\n * name. You must free the string using PhDereferenceObject() when you no longer need it.\n */\nBOOLEAN PhLookupPrivilegeName(\n    _In_ PLUID PrivilegeValue,\n    _Out_ PPH_STRING *PrivilegeName\n    )\n{\n    NTSTATUS status;\n    PUNICODE_STRING name;\n\n    status = LsaLookupPrivilegeName(\n        PhGetLookupPolicyHandle(),\n        PrivilegeValue,\n        &name\n        );\n\n    if (!NT_SUCCESS(status))\n        return FALSE;\n\n    *PrivilegeName = PhCreateStringFromUnicodeString(name);\n    LsaFreeMemory(name);\n\n    return TRUE;\n}\n\n/**\n * Gets the display name of a privilege from its name.\n *\n * \\param PrivilegeName The name of a privilege.\n * \\param PrivilegeDisplayName A variable which receives a pointer to a string containing the\n * privilege's display name. You must free the string using PhDereferenceObject() when you no longer\n * need it.\n */\nBOOLEAN PhLookupPrivilegeDisplayName(\n    _In_ PPH_STRINGREF PrivilegeName,\n    _Out_ PPH_STRING *PrivilegeDisplayName\n    )\n{\n    NTSTATUS status;\n    UNICODE_STRING privilegeName;\n    PUNICODE_STRING displayName;\n    SHORT language;\n\n    if (!PhStringRefToUnicodeString(PrivilegeName, &privilegeName))\n        return FALSE;\n\n    status = LsaLookupPrivilegeDisplayName(\n        PhGetLookupPolicyHandle(),\n        &privilegeName,\n        &displayName,\n        &language\n        );\n\n    if (!NT_SUCCESS(status))\n        return FALSE;\n\n    *PrivilegeDisplayName = PhCreateStringFromUnicodeString(displayName);\n    LsaFreeMemory(displayName);\n\n    return TRUE;\n}\n\n/**\n * Gets the LUID of a privilege from its name.\n *\n * \\param PrivilegeName The name of a privilege.\n * \\param PrivilegeValue A variable which receives the LUID of the privilege.\n */\nBOOLEAN PhLookupPrivilegeValue(\n    _In_ PPH_STRINGREF PrivilegeName,\n    _Out_ PLUID PrivilegeValue\n    )\n{\n    UNICODE_STRING privilegeName;\n\n    if (!PhStringRefToUnicodeString(PrivilegeName, &privilegeName))\n        return FALSE;\n\n    return NT_SUCCESS(LsaLookupPrivilegeValue(\n        PhGetLookupPolicyHandle(),\n        &privilegeName,\n        PrivilegeValue\n        ));\n}\n\n/**\n * Gets information about a SID.\n *\n * \\param Sid A SID to query.\n * \\param Name A variable which receives a pointer to a string containing the SID's name. You must\n * free the string using PhDereferenceObject() when you no longer need it.\n * \\param DomainName A variable which receives a pointer to a string containing the SID's domain\n * name. You must free the string using PhDereferenceObject() when you no longer need it.\n * \\param NameUse A variable which receives the SID's usage.\n */\nNTSTATUS PhLookupSid(\n    _In_ PSID Sid,\n    _Out_opt_ PPH_STRING *Name,\n    _Out_opt_ PPH_STRING *DomainName,\n    _Out_opt_ PSID_NAME_USE NameUse\n    )\n{\n    NTSTATUS status;\n    LSA_HANDLE policyHandle;\n    PLSA_REFERENCED_DOMAIN_LIST referencedDomains;\n    PLSA_TRANSLATED_NAME names;\n\n    policyHandle = PhGetLookupPolicyHandle();\n\n    referencedDomains = NULL;\n    names = NULL;\n\n    if (NT_SUCCESS(status = LsaLookupSids(\n        policyHandle,\n        1,\n        &Sid,\n        &referencedDomains,\n        &names\n        )))\n    {\n        if (names[0].Use != SidTypeInvalid && names[0].Use != SidTypeUnknown)\n        {\n            if (Name)\n            {\n                *Name = PhCreateStringFromUnicodeString(&names[0].Name);\n            }\n\n            if (DomainName)\n            {\n                if (names[0].DomainIndex >= 0)\n                {\n                    PLSA_TRUST_INFORMATION trustInfo;\n\n                    trustInfo = &referencedDomains->Domains[names[0].DomainIndex];\n                    *DomainName = PhCreateStringFromUnicodeString(&trustInfo->Name);\n                }\n                else\n                {\n                    *DomainName = PhReferenceEmptyString();\n                }\n            }\n\n            if (NameUse)\n            {\n                *NameUse = names[0].Use;\n            }\n        }\n        else\n        {\n            status = STATUS_NONE_MAPPED;\n        }\n    }\n\n    // LsaLookupSids allocates memory even if it returns STATUS_NONE_MAPPED.\n    if (referencedDomains)\n        LsaFreeMemory(referencedDomains);\n    if (names)\n        LsaFreeMemory(names);\n\n    return status;\n}\n\n/**\n * Gets information about a name.\n *\n * \\param Name A name to query.\n * \\param Sid A variable which receives a pointer to a SID. You must free the SID using PhFree()\n * when you no longer need it.\n * \\param DomainName A variable which receives a pointer to a string containing the SID's domain\n * name. You must free the string using PhDereferenceObject() when you no longer need it.\n * \\param NameUse A variable which receives the SID's usage.\n */\nNTSTATUS PhLookupName(\n    _In_ PPH_STRINGREF Name,\n    _Out_opt_ PSID *Sid,\n    _Out_opt_ PPH_STRING *DomainName,\n    _Out_opt_ PSID_NAME_USE NameUse\n    )\n{\n    NTSTATUS status;\n    LSA_HANDLE policyHandle;\n    UNICODE_STRING name;\n    PLSA_REFERENCED_DOMAIN_LIST referencedDomains;\n    PLSA_TRANSLATED_SID2 sids;\n\n    if (!PhStringRefToUnicodeString(Name, &name))\n        return STATUS_NAME_TOO_LONG;\n\n    policyHandle = PhGetLookupPolicyHandle();\n    referencedDomains = NULL;\n    sids = NULL;\n\n    if (NT_SUCCESS(status = LsaLookupNames2(\n        policyHandle,\n        0,\n        1,\n        &name,\n        &referencedDomains,\n        &sids\n        )))\n    {\n        if (sids[0].Use != SidTypeInvalid && sids[0].Use != SidTypeUnknown)\n        {\n            if (Sid)\n            {\n                PSID sid;\n                ULONG sidLength;\n\n                sidLength = RtlLengthSid(sids[0].Sid);\n                sid = PhAllocate(sidLength);\n                memcpy(sid, sids[0].Sid, sidLength);\n\n                *Sid = sid;\n            }\n\n            if (DomainName)\n            {\n                if (sids[0].DomainIndex >= 0)\n                {\n                    PLSA_TRUST_INFORMATION trustInfo;\n\n                    trustInfo = &referencedDomains->Domains[sids[0].DomainIndex];\n                    *DomainName = PhCreateStringFromUnicodeString(&trustInfo->Name);\n                }\n                else\n                {\n                    *DomainName = PhReferenceEmptyString();\n                }\n            }\n\n            if (NameUse)\n            {\n                *NameUse = sids[0].Use;\n            }\n        }\n        else\n        {\n            status = STATUS_NONE_MAPPED;\n        }\n    }\n\n    // LsaLookupNames2 allocates memory even if it returns STATUS_NONE_MAPPED.\n    if (referencedDomains)\n        LsaFreeMemory(referencedDomains);\n    if (sids)\n        LsaFreeMemory(sids);\n\n    return status;\n}\n\n/**\n * Gets the name of a SID.\n *\n * \\param Sid A SID to query.\n * \\param IncludeDomain TRUE to include the domain name, otherwise FALSE.\n * \\param NameUse A variable which receives the SID's usage.\n *\n * \\return A pointer to a string containing the name of the SID in the following format:\n * domain\\\\name. You must free the string using PhDereferenceObject() when you no longer need it. If\n * an error occurs, the function returns NULL.\n */\nPPH_STRING PhGetSidFullName(\n    _In_ PSID Sid,\n    _In_ BOOLEAN IncludeDomain,\n    _Out_opt_ PSID_NAME_USE NameUse\n    )\n{\n    NTSTATUS status;\n    PPH_STRING fullName;\n    LSA_HANDLE policyHandle;\n    PLSA_REFERENCED_DOMAIN_LIST referencedDomains;\n    PLSA_TRANSLATED_NAME names;\n\n    policyHandle = PhGetLookupPolicyHandle();\n\n    referencedDomains = NULL;\n    names = NULL;\n\n    if (NT_SUCCESS(status = LsaLookupSids(\n        policyHandle,\n        1,\n        &Sid,\n        &referencedDomains,\n        &names\n        )))\n    {\n        if (names[0].Use != SidTypeInvalid && names[0].Use != SidTypeUnknown)\n        {\n            PWSTR domainNameBuffer;\n            ULONG domainNameLength;\n\n            if (IncludeDomain && names[0].DomainIndex >= 0)\n            {\n                PLSA_TRUST_INFORMATION trustInfo;\n\n                trustInfo = &referencedDomains->Domains[names[0].DomainIndex];\n                domainNameBuffer = trustInfo->Name.Buffer;\n                domainNameLength = trustInfo->Name.Length;\n            }\n            else\n            {\n                domainNameBuffer = NULL;\n                domainNameLength = 0;\n            }\n\n            if (domainNameBuffer && domainNameLength != 0)\n            {\n                fullName = PhCreateStringEx(NULL, domainNameLength + sizeof(WCHAR) + names[0].Name.Length);\n                memcpy(&fullName->Buffer[0], domainNameBuffer, domainNameLength);\n                fullName->Buffer[domainNameLength / sizeof(WCHAR)] = '\\\\';\n                memcpy(&fullName->Buffer[domainNameLength / sizeof(WCHAR) + 1], names[0].Name.Buffer, names[0].Name.Length);\n            }\n            else\n            {\n                fullName = PhCreateStringFromUnicodeString(&names[0].Name);\n            }\n\n            if (NameUse)\n            {\n                *NameUse = names[0].Use;\n            }\n        }\n        else\n        {\n            fullName = NULL;\n        }\n    }\n    else\n    {\n        fullName = NULL;\n    }\n\n    if (referencedDomains)\n        LsaFreeMemory(referencedDomains);\n    if (names)\n        LsaFreeMemory(names);\n\n    return fullName;\n}\n\n/**\n * Gets a SDDL string representation of a SID.\n *\n * \\param Sid A SID to query.\n *\n * \\return A pointer to a string containing the SDDL representation of the SID. You must free the\n * string using PhDereferenceObject() when you no longer need it. If an error occurs, the function\n * returns NULL.\n */\nPPH_STRING PhSidToStringSid(\n    _In_ PSID Sid\n    )\n{\n    PPH_STRING string;\n    UNICODE_STRING us;\n\n    string = PhCreateStringEx(NULL, SECURITY_MAX_SID_STRING_CHARACTERS * sizeof(WCHAR));\n    PhStringRefToUnicodeString(&string->sr, &us);\n\n    if (NT_SUCCESS(RtlConvertSidToUnicodeString(\n        &us,\n        Sid,\n        FALSE\n        )))\n    {\n        string->Length = us.Length;\n        string->Buffer[us.Length / sizeof(WCHAR)] = 0;\n\n        return string;\n    }\n    else\n    {\n        return NULL;\n    }\n}\n"
  },
  {
    "path": "third_party/phlib/mapexlf.c",
    "content": "/*\n * Process Hacker -\n *   ELF library support\n *\n * Copyright (C) 2017 dmex\n *\n * This file is part of Process Hacker.\n *\n * Process Hacker is free software; you can redistribute it and/or modify\n * it under the terms of the GNU General Public License as published by\n * the Free Software Foundation, either version 3 of the License, or\n * (at your option) any later version.\n *\n * Process Hacker is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n * GNU General Public License for more details.\n *\n * You should have received a copy of the GNU General Public License\n * along with Process Hacker.  If not, see <http://www.gnu.org/licenses/>.\n */\n\n#include <ph.h>\n#include <mapimg.h>\n\nNTSTATUS PhInitializeMappedWslImage(\n    _Out_ PPH_MAPPED_IMAGE MappedWslImage,\n    _In_ PVOID ViewBase,\n    _In_ SIZE_T Size\n    )\n{\n    MappedWslImage->ViewBase = ViewBase;\n    MappedWslImage->Size = Size;\n    MappedWslImage->Header = (PELF_IMAGE_HEADER)ViewBase;\n\n    __try\n    {\n        PhProbeAddress(\n            MappedWslImage->Header, \n            sizeof(ELF_IMAGE_HEADER), \n            MappedWslImage->ViewBase, \n            MappedWslImage->Size,\n            1\n            );\n    }\n    __except (EXCEPTION_EXECUTE_HANDLER)\n    {\n        return GetExceptionCode();\n    }\n\n    // Check the magic number.\n\n    if (!RtlEqualMemory(MappedWslImage->Header->e_ident, ELFMAG, sizeof(ELFMAG)))\n        return STATUS_FAIL_CHECK;\n\n    // Check the class type.\n\n    if (MappedWslImage->Header->e_ident[EI_CLASS] == ELFCLASS64)\n    {\n        MappedWslImage->Headers64 = PTR_ADD_OFFSET(MappedWslImage->Header, sizeof(ELF_IMAGE_HEADER));\n\n        __try\n        {\n            PhProbeAddress(\n                MappedWslImage->Headers64, \n                sizeof(ELF64_IMAGE_SECTION_HEADER), \n                MappedWslImage->ViewBase, \n                MappedWslImage->Size, \n                1\n                );\n        }\n        __except (EXCEPTION_EXECUTE_HANDLER)\n        {\n            return GetExceptionCode();\n        }\n    }\n    else\n    {\n        // TODO: Add 32bit ELF support.\n        return STATUS_IMAGE_SUBSYSTEM_NOT_PRESENT;\n    }\n\n    if (MappedWslImage->Headers64->e_phentsize != sizeof(ELF64_IMAGE_SEGMENT_HEADER))\n        return STATUS_FAIL_CHECK;\n    if (MappedWslImage->Headers64->e_shentsize != sizeof(ELF64_IMAGE_SECTION_HEADER))\n        return STATUS_FAIL_CHECK;\n\n    return STATUS_SUCCESS;\n}\n\nPELF64_IMAGE_SEGMENT_HEADER PhGetMappedWslImageSegment(\n    _In_ PPH_MAPPED_IMAGE MappedWslImage,\n    _In_ USHORT Index\n    )\n{\n    return IMAGE_ELF64_SEGMENT_BY_INDEX(IMAGE_FIRST_ELF64_SEGMENT(MappedWslImage), Index);\n}\n\nPELF64_IMAGE_SEGMENT_HEADER PhGetWslImageSegmentByType(\n    _In_ PPH_MAPPED_IMAGE MappedWslImage,\n    _In_opt_ USHORT Type\n    )\n{\n    PELF64_IMAGE_SEGMENT_HEADER segmentHeader;\n    USHORT i;\n\n    segmentHeader = IMAGE_FIRST_ELF64_SEGMENT(MappedWslImage);\n\n    for (i = 0; i < MappedWslImage->Headers64->e_phnum; i++)\n    {\n        if (segmentHeader[i].p_type == Type)\n            return segmentHeader;\n    }\n\n    return NULL;\n}\n\nPVOID PhGetMappedWslImageSectionData(\n    _In_ PPH_MAPPED_IMAGE MappedWslImage,\n    _In_opt_ PSTR Name,\n    _In_opt_ USHORT Index\n    )\n{\n    if (Name)\n    {\n        PELF64_IMAGE_SECTION_HEADER sectionHeader;\n        PELF64_IMAGE_SECTION_HEADER stringSection;\n        PELF64_IMAGE_SECTION_HEADER section;\n        PVOID stringTable;\n        USHORT i;\n\n        sectionHeader = IMAGE_FIRST_ELF64_SECTION(MappedWslImage);\n        stringSection = IMAGE_ELF64_SECTION_BY_INDEX(sectionHeader, MappedWslImage->Headers64->e_shstrndx);\n        stringTable = PTR_ADD_OFFSET(MappedWslImage->Header, stringSection->sh_offset);\n\n        for (i = 0; i < MappedWslImage->Headers64->e_shnum; i++)\n        {\n            section = IMAGE_ELF64_SECTION_BY_INDEX(sectionHeader, i);\n\n            if (strcmp(Name, PTR_ADD_OFFSET(stringTable, section->sh_name)) == 0)\n            {\n                return PTR_ADD_OFFSET(MappedWslImage->Header, section->sh_offset);\n            }\n        }\n\n        return NULL;\n    }\n    else\n    {\n        PELF64_IMAGE_SECTION_HEADER sectionHeader;\n        PELF64_IMAGE_SECTION_HEADER section;\n\n        sectionHeader = IMAGE_FIRST_ELF64_SECTION(MappedWslImage);\n        section = IMAGE_ELF64_SECTION_BY_INDEX(sectionHeader, Index);\n\n        return PTR_ADD_OFFSET(MappedWslImage->Header, section->sh_offset);\n    }\n}\n\nPVOID PhGetMappedWslImageSectionDataByType(\n    _In_ PPH_MAPPED_IMAGE MappedWslImage,\n    _In_ UINT32 Type\n    )\n{\n    PELF64_IMAGE_SECTION_HEADER sectionHeader;\n    PELF64_IMAGE_SECTION_HEADER section;\n    USHORT i;\n\n    sectionHeader = IMAGE_FIRST_ELF64_SECTION(MappedWslImage);\n\n    for (i = 0; i < MappedWslImage->Headers64->e_shnum; i++)\n    {\n        section = IMAGE_ELF64_SECTION_BY_INDEX(sectionHeader, i);\n\n        if (section->sh_type == Type)\n        {\n            return PTR_ADD_OFFSET(MappedWslImage->Header, section->sh_offset);\n        }\n    }\n\n    return NULL;\n}\n\nPELF64_IMAGE_SECTION_HEADER PhGetMappedWslImageSectionByIndex(\n    _In_ PPH_MAPPED_IMAGE MappedWslImage,\n    _In_ USHORT Index\n    )\n{\n    return IMAGE_ELF64_SECTION_BY_INDEX(IMAGE_FIRST_ELF64_SECTION(MappedWslImage), Index);\n}\n\nPELF64_IMAGE_SECTION_HEADER PhGetMappedWslImageSectionByType(\n    _In_ PPH_MAPPED_IMAGE MappedWslImage,\n    _In_ UINT32 Type\n    )\n{\n    PELF64_IMAGE_SECTION_HEADER sectionHeader;\n    PELF64_IMAGE_SECTION_HEADER section;\n    USHORT i;\n\n    sectionHeader = IMAGE_FIRST_ELF64_SECTION(MappedWslImage);\n\n    for (i = 0; i < MappedWslImage->Headers64->e_shnum; i++)\n    {\n        section = IMAGE_ELF64_SECTION_BY_INDEX(sectionHeader, i);\n\n        if (section->sh_type == Type)\n            return section;\n    }\n\n    return NULL;\n}\n\n// TODO: Check this is actually correct.\n// https://stackoverflow.com/questions/18296276/base-address-of-elf\nULONG64 PhGetMappedWslImageBaseAddress(\n    _In_ PPH_MAPPED_IMAGE MappedWslImage\n    )\n{\n    ULONG64 baseAddress = MAXULONG64;\n    PELF64_IMAGE_SEGMENT_HEADER segment;\n    USHORT i;\n\n    segment = IMAGE_FIRST_ELF64_SEGMENT(MappedWslImage);\n\n    for (i = 0; i < MappedWslImage->Headers64->e_phnum; i++)\n    {\n        if (segment[i].p_type == PT_LOAD)\n        {\n            if (segment[i].p_paddr < baseAddress)\n                baseAddress = segment[i].p_paddr;\n        }\n    }\n\n    if (baseAddress == MAXULONG64)\n        baseAddress = 0;\n\n    return baseAddress;\n}\n\nBOOLEAN PhGetMappedWslImageSections(\n    _In_ PPH_MAPPED_IMAGE MappedWslImage,\n    _Out_ USHORT *NumberOfSections,\n    _Out_ PPH_ELF_IMAGE_SECTION *ImageSections\n    )\n{\n    USHORT count;\n    USHORT i;\n    PPH_ELF_IMAGE_SECTION sections;\n    PELF64_IMAGE_SECTION_HEADER sectionHeader;\n    PELF64_IMAGE_SECTION_HEADER stringSection;\n    PVOID stringTableAddress;\n\n    count = MappedWslImage->Headers64->e_shnum;\n    sections = PhAllocate(sizeof(PH_ELF_IMAGE_SECTION) * count);\n    memset(sections, 0, sizeof(PH_ELF_IMAGE_SECTION) * count);\n\n    // Get the first section.\n    sectionHeader = IMAGE_FIRST_ELF64_SECTION(MappedWslImage);\n\n    // Get the string section.\n    stringSection = IMAGE_ELF64_SECTION_BY_INDEX(sectionHeader, MappedWslImage->Headers64->e_shstrndx);\n\n    // Get the string table (The string table is an array of null terminated strings).\n    stringTableAddress = PTR_ADD_OFFSET(MappedWslImage->Header, stringSection->sh_offset);\n                                                                                  \n    // Enumerate the sections.\n    for (i = 0; i < count; i++)\n    {\n        sections[i].Type = sectionHeader[i].sh_type;\n        sections[i].Flags = sectionHeader[i].sh_flags;\n        sections[i].Address = sectionHeader[i].sh_addr;\n        sections[i].Offset = sectionHeader[i].sh_offset;\n        sections[i].Size = sectionHeader[i].sh_size;\n\n        if (sectionHeader[i].sh_name)\n        {\n            // Get the section name from the ELF string table and convert to unicode.\n            PhCopyStringZFromBytes(\n                PTR_ADD_OFFSET(stringTableAddress, sectionHeader[i].sh_name),\n                -1,\n                sections[i].Name,\n                sizeof(sections[i].Name),\n                NULL\n                );\n        }\n    }\n\n    *NumberOfSections = count;\n    *ImageSections = sections;\n\n    return TRUE;\n}\n\ntypedef struct _PH_ELF_VERSION_RECORD\n{\n    USHORT Version;\n    PSTR Name;\n    PSTR FileName;\n} PH_ELF_VERSION_RECORD, *PPH_ELF_VERSION_RECORD;\n\nstatic PPH_LIST PhpParseMappedWslImageVersionRecords(\n    _In_ PPH_MAPPED_IMAGE MappedWslImage,\n    _In_ PVOID SymbolStringTable\n    )\n{\n    PPH_LIST recordsList;\n    PELF_VERSION_NEED version;\n\n    if (!(version = PhGetMappedWslImageSectionDataByType(MappedWslImage, SHT_SUNW_verneed)))\n        return NULL;\n\n    recordsList = PhCreateList(10);\n\n    while (TRUE)\n    {\n        PELF_VERSION_AUX versionAux = PTR_ADD_OFFSET(version, version->vn_aux);\n\n        while (TRUE)\n        {\n            PPH_ELF_VERSION_RECORD versionInfo;\n\n            versionInfo = PhAllocate(sizeof(PH_ELF_VERSION_RECORD));\n            memset(versionInfo, 0, sizeof(PH_ELF_VERSION_RECORD));\n            versionInfo->Version = versionAux->vna_other;\n            versionInfo->Name = PTR_ADD_OFFSET(SymbolStringTable, versionAux->vna_name);\n            versionInfo->FileName = PTR_ADD_OFFSET(SymbolStringTable, version->vn_file);\n\n            PhAddItemList(recordsList, versionInfo);\n\n            if (versionAux->vna_next == 0)\n                break;\n\n            versionAux = PTR_ADD_OFFSET(versionAux, versionAux->vna_next);\n        }\n\n        if (version->vn_next == 0)\n            break;\n\n        version = PTR_ADD_OFFSET(version, version->vn_next);\n    }\n\n    return recordsList;\n}\n\nstatic VOID PhpFreeMappedWslImageVersionRecords(\n    _In_ PPH_LIST RecordsList\n    )\n{\n    for (ULONG i = 0; i < RecordsList->Count; i++)\n        PhFree(RecordsList->Items[i]);\n\n    PhDereferenceObject(RecordsList);\n}\n\nstatic PSTR PhpFindWslImageVersionRecordName(\n    _In_ PPH_LIST VersionRecordList,\n    _In_ USHORT VersionIndex\n    )\n{\n    // Note: 'ldconfig -v' and 'ldconfig -p' can be used to locate the path from the FileName.\n    for (ULONG i = 0; i < VersionRecordList->Count; i++)\n    {\n        PPH_ELF_VERSION_RECORD versionInfo = VersionRecordList->Items[i];\n\n        if (versionInfo->Version == VersionIndex)\n            return versionInfo->FileName;\n    }\n\n    return NULL;\n}\n\n// TODO: Optimize this function.\nBOOLEAN PhGetMappedWslImageSymbols(\n    _In_ PPH_MAPPED_IMAGE MappedWslImage,\n    _Out_ PPH_LIST *ImageSymbols\n    )\n{\n    PELF64_IMAGE_SECTION_HEADER section;\n    PPH_LIST symbols = PhCreateList(2000);\n\n    if (section = PhGetMappedWslImageSectionByType(MappedWslImage, SHT_SYMTAB))\n    {\n        // TODO: Need to find a WSL binary with a symbol table.\n        // SHT_SYMTAB should be parsed idential to SHT_DYNSYM?\n    }\n    \n    if (section = PhGetMappedWslImageSectionByType(MappedWslImage, SHT_DYNSYM))\n    {\n        ULONGLONG count;\n        ULONGLONG i;\n        PELF_IMAGE_SYMBOL_ENTRY entry;\n        PVOID stringTable;\n        PELF_VERSION_TABLE versionTable;\n        PPH_LIST versionRecords;\n\n        if (section->sh_entsize != sizeof(ELF_IMAGE_SYMBOL_ENTRY))\n            return FALSE;\n\n        count = section->sh_size / sizeof(ELF_IMAGE_SYMBOL_ENTRY);\n        entry = PTR_ADD_OFFSET(MappedWslImage->Header, section->sh_offset);\n        stringTable = PhGetMappedWslImageSectionData(MappedWslImage, NULL, section->sh_link);\n\n        versionTable = PhGetMappedWslImageSectionDataByType(MappedWslImage, SHT_SUNW_versym);\n        versionRecords = PhpParseMappedWslImageVersionRecords(MappedWslImage, stringTable);\n\n        for (i = 1; i < count; i++)\n        {\n            if (entry[i].st_shndx == SHN_UNDEF)\n            {\n                PPH_ELF_IMAGE_SYMBOL_ENTRY import;\n\n                import = PhAllocate(sizeof(PH_ELF_IMAGE_SYMBOL_ENTRY));\n                memset(import, 0, sizeof(PH_ELF_IMAGE_SYMBOL_ENTRY));\n\n                import->ImportSymbol = TRUE;\n                import->Address = entry[i].st_value;\n                import->Size = entry[i].st_size;\n                import->TypeInfo = entry[i].st_info;\n\n                // function name\n                PhCopyStringZFromBytes(\n                    PTR_ADD_OFFSET(stringTable, entry[i].st_name),\n                    -1,\n                    import->Name,\n                    sizeof(import->Name),\n                    NULL\n                    );\n\n                // import library name\n                if (versionTable && versionRecords)\n                {\n                    PSTR moduleName;\n\n                    if (moduleName = PhpFindWslImageVersionRecordName(versionRecords, versionTable[i].vs_vers))\n                    {\n                        PhCopyStringZFromBytes(\n                            moduleName,\n                            -1,\n                            import->Module,\n                            sizeof(import->Module),\n                            NULL\n                            );\n                    }\n                }\n\n                PhAddItemList(symbols, import);\n            }\n            else if (entry[i].st_shndx != SHN_UNDEF && entry[i].st_value != 0)\n            {\n                PPH_ELF_IMAGE_SYMBOL_ENTRY export;\n\n                if (ELF_ST_TYPE(entry[i].st_info) == STT_SECTION) // Ignore section symbol types.\n                    continue;\n\n                export = PhAllocate(sizeof(PH_ELF_IMAGE_SYMBOL_ENTRY));\n                memset(export, 0, sizeof(PH_ELF_IMAGE_SYMBOL_ENTRY));\n\n                export->ExportSymbol = TRUE;\n                export->Address = entry[i].st_value;\n                export->Size = entry[i].st_size;\n                export->TypeInfo = entry[i].st_info;\n\n                // function name\n                PhCopyStringZFromBytes(\n                    PTR_ADD_OFFSET(stringTable, entry[i].st_name),\n                    -1,\n                    export->Name,\n                    sizeof(export->Name),\n                    NULL\n                    );\n\n                PhAddItemList(symbols, export);\n            }\n            else\n            {   \n                PPH_ELF_IMAGE_SYMBOL_ENTRY export;\n\n                export = PhAllocate(sizeof(PH_ELF_IMAGE_SYMBOL_ENTRY));\n                memset(export, 0, sizeof(PH_ELF_IMAGE_SYMBOL_ENTRY));\n\n                export->UnknownSymbol = TRUE;\n                export->Address = entry[i].st_value;\n                export->Size = entry[i].st_size;\n                export->TypeInfo = entry[i].st_info;\n\n                // function name\n                PhCopyStringZFromBytes(\n                    PTR_ADD_OFFSET(stringTable, entry[i].st_name),\n                    -1,\n                    export->Name,\n                    sizeof(export->Name),\n                    NULL\n                    );\n\n                PhAddItemList(symbols, export);\n            }\n        }\n\n        if (versionRecords)\n            PhpFreeMappedWslImageVersionRecords(versionRecords);\n    }\n\n    *ImageSymbols = symbols;\n\n    return TRUE;\n}\n\nVOID PhFreeMappedWslImageSymbols(\n    _In_ PPH_LIST ImageSymbols\n    )\n{\n    for (ULONG i = 0; i < ImageSymbols->Count; i++)\n        PhFree(ImageSymbols->Items[i]);\n\n    PhDereferenceObject(ImageSymbols);\n}"
  },
  {
    "path": "third_party/phlib/mapimg.c",
    "content": "/*\n * Process Hacker -\n *   mapped image\n *\n * Copyright (C) 2010 wj32\n * Copyright (C) 2017 dmex\n *\n * This file is part of Process Hacker.\n *\n * Process Hacker is free software; you can redistribute it and/or modify\n * it under the terms of the GNU General Public License as published by\n * the Free Software Foundation, either version 3 of the License, or\n * (at your option) any later version.\n *\n * Process Hacker is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n * GNU General Public License for more details.\n *\n * You should have received a copy of the GNU General Public License\n * along with Process Hacker.  If not, see <http://www.gnu.org/licenses/>.\n */\n\n/*\n * This file contains functions to load and retrieve information for image files (exe, dll). The\n * file format for image files is explained in the PE/COFF specification located at:\n *\n * http://www.microsoft.com/whdc/system/platform/firmware/PECOFF.mspx\n */\n\n#include <ph.h>\n#include <mapimg.h>\n\nVOID PhpMappedImageProbe(\n    _In_ PPH_MAPPED_IMAGE MappedImage,\n    _In_ PVOID Address,\n    _In_ SIZE_T Length\n    );\n\nULONG PhpLookupMappedImageExportName(\n    _In_ PPH_MAPPED_IMAGE_EXPORTS Exports,\n    _In_ PSTR Name\n    );\n\nNTSTATUS PhInitializeMappedImage(\n    _Out_ PPH_MAPPED_IMAGE MappedImage,\n    _In_ PVOID ViewBase,\n    _In_ SIZE_T Size\n    )\n{\n    PIMAGE_DOS_HEADER dosHeader;\n    ULONG ntHeadersOffset;\n\n    MappedImage->ViewBase = ViewBase;\n    MappedImage->Size = Size;\n\n    dosHeader = (PIMAGE_DOS_HEADER)ViewBase;\n\n    __try\n    {\n        PhpMappedImageProbe(MappedImage, dosHeader, sizeof(IMAGE_DOS_HEADER));\n    }\n    __except (EXCEPTION_EXECUTE_HANDLER)\n    {\n        return GetExceptionCode();\n    }\n\n    // Check the initial MZ.\n\n    if (dosHeader->e_magic != IMAGE_DOS_SIGNATURE)\n        return STATUS_INVALID_IMAGE_NOT_MZ;\n\n    // Get a pointer to the NT headers and probe it.\n\n    ntHeadersOffset = (ULONG)dosHeader->e_lfanew;\n\n    if (ntHeadersOffset == 0)\n        return STATUS_INVALID_IMAGE_FORMAT;\n    if (ntHeadersOffset >= 0x10000000 || ntHeadersOffset >= Size)\n        return STATUS_INVALID_IMAGE_FORMAT;\n\n    MappedImage->NtHeaders = (PIMAGE_NT_HEADERS)PTR_ADD_OFFSET(ViewBase, ntHeadersOffset);\n\n    __try\n    {\n        PhpMappedImageProbe(\n            MappedImage,\n            MappedImage->NtHeaders,\n            FIELD_OFFSET(IMAGE_NT_HEADERS, OptionalHeader)\n            );\n        PhpMappedImageProbe(\n            MappedImage,\n            MappedImage->NtHeaders,\n            FIELD_OFFSET(IMAGE_NT_HEADERS, OptionalHeader) +\n            MappedImage->NtHeaders->FileHeader.SizeOfOptionalHeader +\n            MappedImage->NtHeaders->FileHeader.NumberOfSections * sizeof(IMAGE_SECTION_HEADER)\n            );\n    }\n    __except (EXCEPTION_EXECUTE_HANDLER)\n    {\n        return GetExceptionCode();\n    }\n\n    // Check the signature and verify the magic.\n\n    if (MappedImage->NtHeaders->Signature != IMAGE_NT_SIGNATURE)\n        return STATUS_INVALID_IMAGE_FORMAT;\n\n    MappedImage->Magic = MappedImage->NtHeaders->OptionalHeader.Magic;\n\n    if (\n        MappedImage->Magic != IMAGE_NT_OPTIONAL_HDR32_MAGIC &&\n        MappedImage->Magic != IMAGE_NT_OPTIONAL_HDR64_MAGIC\n        )\n        return STATUS_INVALID_IMAGE_FORMAT;\n\n    // Get a pointer to the first section.\n\n    MappedImage->NumberOfSections = MappedImage->NtHeaders->FileHeader.NumberOfSections;\n    MappedImage->Sections = IMAGE_FIRST_SECTION(MappedImage->NtHeaders);\n\n    return STATUS_SUCCESS;\n}\n\nNTSTATUS PhLoadMappedImage(\n    _In_opt_ PWSTR FileName,\n    _In_opt_ HANDLE FileHandle,\n    _In_ BOOLEAN ReadOnly,\n    _Out_ PPH_MAPPED_IMAGE MappedImage\n    )\n{\n    NTSTATUS status;\n    PVOID viewBase;\n    SIZE_T size;\n\n    status = PhMapViewOfEntireFile(\n        FileName,\n        FileHandle,\n        ReadOnly,\n        &viewBase,\n        &size\n        );\n\n    if (NT_SUCCESS(status))\n    {\n        status = PhInitializeMappedImage(\n            MappedImage,\n            viewBase,\n            size\n            );\n\n        if (!NT_SUCCESS(status))\n        {\n            PhUnloadMappedImage(MappedImage);\n        }\n    }\n\n    return status;\n}\n\nNTSTATUS PhLoadMappedImageEx(\n    _In_opt_ PWSTR FileName,\n    _In_opt_ HANDLE FileHandle,\n    _In_ BOOLEAN ReadOnly,\n    _Out_ PPH_MAPPED_IMAGE MappedImage\n    )\n{\n    NTSTATUS status;\n    PVOID viewBase;\n    SIZE_T size;\n\n    status = PhMapViewOfEntireFile(\n        FileName,\n        FileHandle,\n        ReadOnly,\n        &viewBase,\n        &size\n        );\n\n    if (NT_SUCCESS(status))\n    {\n        PUSHORT imageHeaderSignature = viewBase;\n\n        __try\n        {\n            PhProbeAddress(imageHeaderSignature, sizeof(USHORT), viewBase, size, 1);\n        }\n        __except (EXCEPTION_EXECUTE_HANDLER)\n        {\n            return GetExceptionCode();\n        }\n\n        MappedImage->Signature = *imageHeaderSignature;\n\n        switch (MappedImage->Signature)\n        {\n        case IMAGE_DOS_SIGNATURE:\n            {\n                status = PhInitializeMappedImage(\n                    MappedImage,\n                    viewBase,\n                    size\n                    );\n            }\n            break;\n        case IMAGE_ELF_SIGNATURE:\n            {\n                status = PhInitializeMappedWslImage(\n                    MappedImage,\n                    viewBase,\n                    size\n                    );\n            }\n            break;\n        }\n    }\n\n    return status;\n}\n\nNTSTATUS PhUnloadMappedImage(\n    _Inout_ PPH_MAPPED_IMAGE MappedImage\n    )\n{\n    return NtUnmapViewOfSection(\n        NtCurrentProcess(),\n        MappedImage->ViewBase\n        );\n}\n\nNTSTATUS PhMapViewOfEntireFile(\n    _In_opt_ PWSTR FileName,\n    _In_opt_ HANDLE FileHandle,\n    _In_ BOOLEAN ReadOnly,\n    _Out_ PVOID *ViewBase,\n    _Out_ PSIZE_T Size\n    )\n{\n    NTSTATUS status;\n    BOOLEAN openedFile = FALSE;\n    LARGE_INTEGER size;\n    HANDLE sectionHandle = NULL;\n    SIZE_T viewSize;\n    PVOID viewBase;\n\n    if (!FileName && !FileHandle)\n        return STATUS_INVALID_PARAMETER_MIX;\n\n    // Open the file if we weren't supplied a file handle.\n    if (!FileHandle)\n    {\n        status = PhCreateFileWin32(\n            &FileHandle,\n            FileName,\n            ((FILE_READ_ATTRIBUTES | FILE_READ_DATA) |\n            (!ReadOnly ? (FILE_APPEND_DATA | FILE_WRITE_ATTRIBUTES | FILE_WRITE_DATA) : 0)) | SYNCHRONIZE,\n            0,\n            FILE_SHARE_READ,\n            FILE_OPEN,\n            FILE_NON_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT\n            );\n\n        if (!NT_SUCCESS(status))\n            return status;\n\n        openedFile = TRUE;\n    }\n\n    // Get the file size and create the section.\n\n    status = PhGetFileSize(FileHandle, &size);\n\n    if (!NT_SUCCESS(status))\n        goto CleanupExit;\n\n    status = NtCreateSection(\n        &sectionHandle,\n        SECTION_ALL_ACCESS,\n        NULL,\n        &size,\n        ReadOnly ? PAGE_READONLY : PAGE_READWRITE,\n        SEC_COMMIT,\n        FileHandle\n        );\n\n    if (!NT_SUCCESS(status))\n        goto CleanupExit;\n\n    // Map the section.\n\n    viewSize = (SIZE_T)size.QuadPart;\n    viewBase = NULL;\n\n    status = NtMapViewOfSection(\n        sectionHandle,\n        NtCurrentProcess(),\n        &viewBase,\n        0,\n        0,\n        NULL,\n        &viewSize,\n        ViewShare,\n        0,\n        ReadOnly ? PAGE_READONLY : PAGE_READWRITE\n        );\n\n    if (!NT_SUCCESS(status))\n        goto CleanupExit;\n\n    *ViewBase = viewBase;\n    *Size = (SIZE_T)size.QuadPart;\n\nCleanupExit:\n    if (sectionHandle)\n        NtClose(sectionHandle);\n    if (openedFile)\n        NtClose(FileHandle);\n\n    return status;\n}\n\nVOID PhpMappedImageProbe(\n    _In_ PPH_MAPPED_IMAGE MappedImage,\n    _In_ PVOID Address,\n    _In_ SIZE_T Length\n    )\n{\n    PhProbeAddress(Address, Length, MappedImage->ViewBase, MappedImage->Size, 1);\n}\n\nPIMAGE_SECTION_HEADER PhMappedImageRvaToSection(\n    _In_ PPH_MAPPED_IMAGE MappedImage,\n    _In_ ULONG Rva\n    )\n{\n    ULONG i;\n\n    for (i = 0; i < MappedImage->NumberOfSections; i++)\n    {\n        if (\n            (Rva >= MappedImage->Sections[i].VirtualAddress) &&\n            (Rva < MappedImage->Sections[i].VirtualAddress + MappedImage->Sections[i].SizeOfRawData)\n            )\n        {\n            return &MappedImage->Sections[i];\n        }\n    }\n\n    return NULL;\n}\n\nPVOID PhMappedImageRvaToVa(\n    _In_ PPH_MAPPED_IMAGE MappedImage,\n    _In_ ULONG Rva,\n    _Out_opt_ PIMAGE_SECTION_HEADER *Section\n    )\n{\n    PIMAGE_SECTION_HEADER section;\n\n    section = PhMappedImageRvaToSection(MappedImage, Rva);\n\n    if (!section)\n        return NULL;\n\n    if (Section)\n        *Section = section;\n\n    return PTR_ADD_OFFSET(\n        MappedImage->ViewBase, \n        (Rva - section->VirtualAddress) +\n        section->PointerToRawData\n        );\n}\n\n_Must_inspect_result_\n_Ret_maybenull_\nPVOID PhMappedImageVaToVa(\n\t_In_ PPH_MAPPED_IMAGE MappedImage,\n\t_In_ ULONG Va,\n\t_Out_opt_ PIMAGE_SECTION_HEADER* Section\n)\n{\n\tULONG rva;\n\tPIMAGE_SECTION_HEADER section;\n\n\tif (MappedImage->Magic == IMAGE_NT_OPTIONAL_HDR32_MAGIC)\n\t{\n\t\trva = PtrToUlong(PTR_SUB_OFFSET(Va, MappedImage->NtHeaders32->OptionalHeader.ImageBase));\n\t}\n\telse if (MappedImage->Magic == IMAGE_NT_OPTIONAL_HDR64_MAGIC)\n\t{\n\t\trva = PtrToUlong(PTR_SUB_OFFSET(Va, MappedImage->NtHeaders->OptionalHeader.ImageBase));\n\t}\n\telse\n\t{\n\t\treturn NULL;\n\t}\n\n\tsection = PhMappedImageRvaToSection(MappedImage, rva);\n\n\tif (!section)\n\t\treturn NULL;\n\n\tif (Section)\n\t\t* Section = section;\n\n\treturn PTR_ADD_OFFSET(MappedImage->ViewBase, PTR_ADD_OFFSET(\n\t\tPTR_SUB_OFFSET(rva, section->VirtualAddress),\n\t\tsection->PointerToRawData\n\t));\n}\n\nBOOLEAN PhGetMappedImageSectionName(\n    _In_ PIMAGE_SECTION_HEADER Section,\n    _Out_writes_opt_z_(Count) PWSTR Buffer,\n    _In_ ULONG Count,\n    _Out_opt_ PULONG ReturnCount\n    )\n{\n    BOOLEAN result;\n    SIZE_T returnCount;\n\n    result = PhCopyStringZFromBytes(\n        Section->Name,\n        IMAGE_SIZEOF_SHORT_NAME,\n        Buffer,\n        Count,\n        &returnCount\n        );\n\n    if (ReturnCount)\n        *ReturnCount = (ULONG)returnCount;\n\n    return result;\n}\n\nNTSTATUS PhGetMappedImageDataEntry(\n    _In_ PPH_MAPPED_IMAGE MappedImage,\n    _In_ ULONG Index,\n    _Out_ PIMAGE_DATA_DIRECTORY *Entry\n    )\n{\n    if (MappedImage->Magic == IMAGE_NT_OPTIONAL_HDR32_MAGIC)\n    {\n        PIMAGE_OPTIONAL_HEADER32 optionalHeader;\n\n        optionalHeader = (PIMAGE_OPTIONAL_HEADER32)&MappedImage->NtHeaders->OptionalHeader;\n\n        if (Index >= optionalHeader->NumberOfRvaAndSizes)\n            return STATUS_INVALID_PARAMETER_2;\n\n        *Entry = &optionalHeader->DataDirectory[Index];\n    }\n    else if (MappedImage->Magic == IMAGE_NT_OPTIONAL_HDR64_MAGIC)\n    {\n        PIMAGE_OPTIONAL_HEADER64 optionalHeader;\n\n        optionalHeader = (PIMAGE_OPTIONAL_HEADER64)&MappedImage->NtHeaders->OptionalHeader;\n\n        if (Index >= optionalHeader->NumberOfRvaAndSizes)\n            return STATUS_INVALID_PARAMETER_2;\n\n        *Entry = &optionalHeader->DataDirectory[Index];\n    }\n    else\n    {\n        return STATUS_INVALID_PARAMETER;\n    }\n\n    return STATUS_SUCCESS;\n}\n\nFORCEINLINE NTSTATUS PhpGetMappedImageLoadConfig(\n    _In_ PPH_MAPPED_IMAGE MappedImage,\n    _In_ USHORT Magic,\n    _In_ ULONG ProbeLength,\n    _Out_ PVOID *LoadConfig\n    )\n{\n    NTSTATUS status;\n    PIMAGE_DATA_DIRECTORY entry;\n    PVOID loadConfig;\n\n    if (MappedImage->Magic != Magic)\n        return STATUS_INVALID_PARAMETER;\n\n    status = PhGetMappedImageDataEntry(MappedImage, IMAGE_DIRECTORY_ENTRY_LOAD_CONFIG, &entry);\n\n    if (!NT_SUCCESS(status))\n        return status;\n\n    loadConfig = PhMappedImageRvaToVa(MappedImage, entry->VirtualAddress, NULL);\n\n    if (!loadConfig)\n        return STATUS_INVALID_PARAMETER;\n\n    __try\n    {\n        PhpMappedImageProbe(MappedImage, loadConfig, ProbeLength);\n    }\n    __except (EXCEPTION_EXECUTE_HANDLER)\n    {\n        return GetExceptionCode();\n    }\n\n    *LoadConfig = loadConfig;\n\n    return STATUS_SUCCESS;\n}\n\nNTSTATUS PhGetMappedImageLoadConfig32(\n    _In_ PPH_MAPPED_IMAGE MappedImage,\n    _Out_ PIMAGE_LOAD_CONFIG_DIRECTORY32 *LoadConfig\n    )\n{\n    return PhpGetMappedImageLoadConfig(\n        MappedImage,\n        IMAGE_NT_OPTIONAL_HDR32_MAGIC,\n        sizeof(IMAGE_LOAD_CONFIG_DIRECTORY32),\n        LoadConfig\n        );\n}\n\nNTSTATUS PhGetMappedImageLoadConfig64(\n    _In_ PPH_MAPPED_IMAGE MappedImage,\n    _Out_ PIMAGE_LOAD_CONFIG_DIRECTORY64 *LoadConfig\n    )\n{\n    return PhpGetMappedImageLoadConfig(\n        MappedImage,\n        IMAGE_NT_OPTIONAL_HDR64_MAGIC,\n        sizeof(IMAGE_LOAD_CONFIG_DIRECTORY64),\n        LoadConfig\n        );\n}\n\nNTSTATUS PhLoadRemoteMappedImage(\n    _In_ HANDLE ProcessHandle,\n    _In_ PVOID ViewBase,\n    _Out_ PPH_REMOTE_MAPPED_IMAGE RemoteMappedImage\n    )\n{\n    NTSTATUS status;\n    IMAGE_DOS_HEADER dosHeader;\n    ULONG ntHeadersOffset;\n    IMAGE_NT_HEADERS32 ntHeaders;\n    ULONG ntHeadersSize;\n\n    RemoteMappedImage->ViewBase = ViewBase;\n\n    status = NtReadVirtualMemory(\n        ProcessHandle,\n        ViewBase,\n        &dosHeader,\n        sizeof(IMAGE_DOS_HEADER),\n        NULL\n        );\n\n    if (!NT_SUCCESS(status))\n        return status;\n\n    // Check the initial MZ.\n\n    if (dosHeader.e_magic != IMAGE_DOS_SIGNATURE)\n        return STATUS_INVALID_IMAGE_NOT_MZ;\n\n    // Get a pointer to the NT headers and read it in for some basic information.\n\n    ntHeadersOffset = (ULONG)dosHeader.e_lfanew;\n\n    if (ntHeadersOffset == 0 || ntHeadersOffset >= 0x10000000)\n        return STATUS_INVALID_IMAGE_FORMAT;\n\n    status = NtReadVirtualMemory(\n        ProcessHandle,\n        PTR_ADD_OFFSET(ViewBase, ntHeadersOffset),\n        &ntHeaders,\n        sizeof(IMAGE_NT_HEADERS32),\n        NULL\n        );\n\n    if (!NT_SUCCESS(status))\n        return status;\n\n    // Check the signature and verify the magic.\n\n    if (ntHeaders.Signature != IMAGE_NT_SIGNATURE)\n        return STATUS_INVALID_IMAGE_FORMAT;\n\n    RemoteMappedImage->Magic = ntHeaders.OptionalHeader.Magic;\n\n    if (\n        RemoteMappedImage->Magic != IMAGE_NT_OPTIONAL_HDR32_MAGIC &&\n        RemoteMappedImage->Magic != IMAGE_NT_OPTIONAL_HDR64_MAGIC\n        )\n        return STATUS_INVALID_IMAGE_FORMAT;\n\n    // Get the real size and read in the whole thing.\n\n    RemoteMappedImage->NumberOfSections = ntHeaders.FileHeader.NumberOfSections;\n    ntHeadersSize = FIELD_OFFSET(IMAGE_NT_HEADERS, OptionalHeader) +\n        ntHeaders.FileHeader.SizeOfOptionalHeader +\n        RemoteMappedImage->NumberOfSections * sizeof(IMAGE_SECTION_HEADER);\n\n    if (ntHeadersSize > 1024 * 1024) // 1 MB\n        return STATUS_INVALID_IMAGE_FORMAT;\n\n    RemoteMappedImage->NtHeaders = PhAllocate(ntHeadersSize);\n\n    status = NtReadVirtualMemory(\n        ProcessHandle,\n        PTR_ADD_OFFSET(ViewBase, ntHeadersOffset),\n        RemoteMappedImage->NtHeaders,\n        ntHeadersSize,\n        NULL\n        );\n\n    if (!NT_SUCCESS(status))\n    {\n        PhFree(RemoteMappedImage->NtHeaders);\n        return status;\n    }\n\n    RemoteMappedImage->Sections = IMAGE_FIRST_SECTION(RemoteMappedImage->NtHeaders);\n\n    return STATUS_SUCCESS;\n}\n\nNTSTATUS PhUnloadRemoteMappedImage(\n    _Inout_ PPH_REMOTE_MAPPED_IMAGE RemoteMappedImage\n    )\n{\n    PhFree(RemoteMappedImage->NtHeaders);\n\n    return STATUS_SUCCESS;\n}\n\nNTSTATUS PhGetMappedImageExports(\n    _Out_ PPH_MAPPED_IMAGE_EXPORTS Exports,\n    _In_ PPH_MAPPED_IMAGE MappedImage\n    )\n{\n    NTSTATUS status;\n    PIMAGE_EXPORT_DIRECTORY exportDirectory;\n\n    Exports->MappedImage = MappedImage;\n\n    // Get a pointer to the export directory.\n\n    status = PhGetMappedImageDataEntry(\n        MappedImage,\n        IMAGE_DIRECTORY_ENTRY_EXPORT,\n        &Exports->DataDirectory\n        );\n\n    if (!NT_SUCCESS(status))\n        return status;\n\n    exportDirectory = PhMappedImageRvaToVa(\n        MappedImage,\n        Exports->DataDirectory->VirtualAddress,\n        NULL\n        );\n\n    if (!exportDirectory)\n        return STATUS_INVALID_PARAMETER;\n\n    __try\n    {\n        PhpMappedImageProbe(MappedImage, exportDirectory, sizeof(IMAGE_EXPORT_DIRECTORY));\n    }\n    __except (EXCEPTION_EXECUTE_HANDLER)\n    {\n        return GetExceptionCode();\n    }\n\n    Exports->ExportDirectory = exportDirectory;\n    Exports->NumberOfEntries = exportDirectory->NumberOfFunctions;\n\n    // Get pointers to the various tables and probe them.\n\n    Exports->AddressTable = (PULONG)PhMappedImageRvaToVa(\n        MappedImage,\n        exportDirectory->AddressOfFunctions,\n        NULL\n        );\n    Exports->NamePointerTable = (PULONG)PhMappedImageRvaToVa(\n        MappedImage,\n        exportDirectory->AddressOfNames,\n        NULL\n        );\n    Exports->OrdinalTable = (PUSHORT)PhMappedImageRvaToVa(\n        MappedImage,\n        exportDirectory->AddressOfNameOrdinals,\n        NULL\n        );\n\t\n\t// Exports exist but no AddressTable => ERROR\n\tif (!Exports->AddressTable)\n\t{\n\t\treturn STATUS_INVALID_PARAMETER;\n\t}\n\n\t// Exports by name exist but no NamePointerTable => ERROR\n    if ( exportDirectory->NumberOfNames && !Exports->NamePointerTable )\n\t{\n\t\treturn STATUS_INVALID_PARAMETER;\n\t}\n\n\t// Exports by ordinal exist but no OrdinalTable => ERROR\n\tif ( exportDirectory->NumberOfNames && !Exports->OrdinalTable)\n\t{\n\t\treturn STATUS_INVALID_PARAMETER;\n\t}\n\n    __try\n    {\n        PhpMappedImageProbe(\n            MappedImage,\n            Exports->AddressTable,\n            exportDirectory->NumberOfFunctions * sizeof(ULONG)\n            );\n        PhpMappedImageProbe(\n            MappedImage,\n            Exports->NamePointerTable,\n            exportDirectory->NumberOfNames * sizeof(ULONG)\n            );\n        PhpMappedImageProbe(\n            MappedImage,\n            Exports->OrdinalTable,  // ordinal list for named exports\n            exportDirectory->NumberOfNames * sizeof(USHORT)\n            );\n    }\n    __except (EXCEPTION_EXECUTE_HANDLER)\n    {\n        return GetExceptionCode();\n    }\n\n    // The ordinal and name tables are parallel.\n    // Getting an index into the name table (e.g. by doing a binary\n    // search) and indexing into the ordinal table will produce the\n    // ordinal for that name, *unbiased* (unlike in the specification).\n    // The unbiased ordinal is an index into the address table.\n\n    return STATUS_SUCCESS;\n}\n\nNTSTATUS PhGetMappedImageExportEntry(\n    _In_ PPH_MAPPED_IMAGE_EXPORTS Exports,\n    _In_ ULONG Index,\n    _Out_ PPH_MAPPED_IMAGE_EXPORT_ENTRY Entry\n    )\n{\n    ULONG nameIndex = 0;\n    BOOLEAN exportByName = FALSE;\n    PSTR name;\n\n    if (Index >= Exports->ExportDirectory->NumberOfFunctions)\n        return STATUS_PROCEDURE_NOT_FOUND;\n\n    Entry->Ordinal = (USHORT)Index + (USHORT)Exports->ExportDirectory->Base;\n\n    // look into named exports ordinal list.\n    for (nameIndex = 0; nameIndex < Exports->ExportDirectory->NumberOfNames; nameIndex++)\n    {\n        if (Index == Exports->OrdinalTable[nameIndex])\n        {\n            exportByName = TRUE;\n            break;\n        }\n    }\n\n\n    if (exportByName)\n    {\n        name = PhMappedImageRvaToVa(\n            Exports->MappedImage,\n            Exports->NamePointerTable[nameIndex],\n            NULL\n            );\n\n        if (!name)\n            return STATUS_INVALID_PARAMETER;\n\n        // TODO: Probe the name.\n\n        Entry->Name = name;\n    }\n    else\n    {\n        Entry->Name = NULL;\n    }\n\n    return STATUS_SUCCESS;\n}\n\nNTSTATUS PhGetMappedImageExportFunction(\n    _In_ PPH_MAPPED_IMAGE_EXPORTS Exports,\n    _In_opt_ PSTR Name,\n    _In_opt_ USHORT Ordinal,\n    _Out_ PPH_MAPPED_IMAGE_EXPORT_FUNCTION Function\n    )\n{\n    ULONG rva;\n\n    if (Name)\n    {\n        ULONG index;\n\n        index = PhpLookupMappedImageExportName(Exports, Name);\n\n        if (index == -1)\n            return STATUS_PROCEDURE_NOT_FOUND;\n\n        Ordinal = Exports->OrdinalTable[index] + (USHORT)Exports->ExportDirectory->Base;\n    }\n\n    Ordinal -= (USHORT)Exports->ExportDirectory->Base;\n\n    if (Ordinal >= Exports->ExportDirectory->NumberOfFunctions)\n        return STATUS_PROCEDURE_NOT_FOUND;\n\n    rva = Exports->AddressTable[Ordinal];\n\t// A non-exported by name ordinal export cannot apparently have a NULL rva\n\tif (!Name && !rva)\n\t{\n\t\treturn STATUS_PROCEDURE_NOT_FOUND;\n\t}\n\n    if (\n        (rva >= Exports->DataDirectory->VirtualAddress) &&\n        (rva < Exports->DataDirectory->VirtualAddress + Exports->DataDirectory->Size)\n        )\n    {\n        // This is a forwarder RVA.\n\n        Function->ForwardedName = PhMappedImageRvaToVa(\n            Exports->MappedImage,\n            rva,\n            NULL\n            );\n\n        if (!Function->ForwardedName)\n            return STATUS_INVALID_PARAMETER;\n\n        // TODO: Probe the name.\n\n        Function->Function = NULL;\n    }\n    else\n    {\n        Function->Function = UlongToPtr(rva);\n        Function->ForwardedName = NULL;\n    }\n\n    return STATUS_SUCCESS;\n}\n\nNTSTATUS PhGetMappedImageExportFunctionRemote(\n    _In_ PPH_MAPPED_IMAGE_EXPORTS Exports,\n    _In_opt_ PSTR Name,\n    _In_opt_ USHORT Ordinal,\n    _In_ PVOID RemoteBase,\n    _Out_ PVOID *Function\n    )\n{\n    ULONG rva;\n\n    if (Name)\n    {\n        ULONG index;\n\n        index = PhpLookupMappedImageExportName(Exports, Name);\n\n        if (index == -1)\n            return STATUS_PROCEDURE_NOT_FOUND;\n\n        Ordinal = Exports->OrdinalTable[index] + (USHORT)Exports->ExportDirectory->Base;\n    }\n\n    Ordinal -= (USHORT)Exports->ExportDirectory->Base;\n\n    if (Ordinal >= Exports->ExportDirectory->NumberOfFunctions)\n        return STATUS_PROCEDURE_NOT_FOUND;\n\n    rva = Exports->AddressTable[Ordinal];\n\n    if (\n        (rva >= Exports->DataDirectory->VirtualAddress) &&\n        (rva < Exports->DataDirectory->VirtualAddress + Exports->DataDirectory->Size)\n        )\n    {\n        // This is a forwarder RVA. Not supported for remote lookup.\n        return STATUS_NOT_SUPPORTED;\n    }\n    else\n    {\n        *Function = PTR_ADD_OFFSET(RemoteBase, rva);\n    }\n\n    return STATUS_SUCCESS;\n}\n\nULONG PhpLookupMappedImageExportName(\n    _In_ PPH_MAPPED_IMAGE_EXPORTS Exports,\n    _In_ PSTR Name\n    )\n{\n    LONG low;\n    LONG high;\n    LONG i;\n\n    if (Exports->ExportDirectory->NumberOfNames == 0)\n        return -1;\n\n    low = 0;\n    high = Exports->ExportDirectory->NumberOfNames - 1;\n\n    do\n    {\n        PSTR name;\n        INT comparison;\n\n        i = (low + high) / 2;\n\n        name = PhMappedImageRvaToVa(\n            Exports->MappedImage,\n            Exports->NamePointerTable[i],\n            NULL\n            );\n\n        if (!name)\n            return -1;\n\n        // TODO: Probe the name.\n\n        comparison = strcmp(Name, name);\n\n        if (comparison == 0)\n            return i;\n        else if (comparison < 0)\n            high = i - 1;\n        else\n            low = i + 1;\n    } while (low <= high);\n\n    return -1;\n}\n\nNTSTATUS PhGetMappedImageImports(\n    _Out_ PPH_MAPPED_IMAGE_IMPORTS Imports,\n    _In_ PPH_MAPPED_IMAGE MappedImage\n    )\n{\n    NTSTATUS status;\n    PIMAGE_DATA_DIRECTORY dataDirectory;\n    PIMAGE_IMPORT_DESCRIPTOR descriptor;\n    ULONG i;\n\n    Imports->MappedImage = MappedImage;\n    Imports->Flags = 0;\n\n    status = PhGetMappedImageDataEntry(\n        MappedImage,\n        IMAGE_DIRECTORY_ENTRY_IMPORT,\n        &dataDirectory\n        );\n\n    if (!NT_SUCCESS(status))\n        return status;\n\n    descriptor = PhMappedImageRvaToVa(\n        MappedImage,\n        dataDirectory->VirtualAddress,\n        NULL\n        );\n\n    if (!descriptor)\n        return STATUS_INVALID_PARAMETER;\n\n    Imports->DescriptorTable = descriptor;\n\n    // Do a scan to determine how many import descriptors there are.\n\n    i = 0;\n\n    __try\n    {\n        while (TRUE)\n        {\n            PhpMappedImageProbe(MappedImage, descriptor, sizeof(IMAGE_IMPORT_DESCRIPTOR));\n\n            if (descriptor->OriginalFirstThunk == 0 && descriptor->FirstThunk == 0)\n                break;\n\n            descriptor++;\n            i++;\n        }\n    }\n    __except (EXCEPTION_EXECUTE_HANDLER)\n    {\n        return GetExceptionCode();\n    }\n\n    Imports->NumberOfDlls = i;\n\n    return STATUS_SUCCESS;\n}\n\nNTSTATUS PhGetMappedImageImportDll(\n    _In_ PPH_MAPPED_IMAGE_IMPORTS Imports,\n    _In_ ULONG Index,\n    _Out_ PPH_MAPPED_IMAGE_IMPORT_DLL ImportDll\n    )\n{\n    ULONG i;\n\n    if (Index >= Imports->NumberOfDlls)\n        return STATUS_INVALID_PARAMETER_2;\n\n    ImportDll->MappedImage = Imports->MappedImage;\n    ImportDll->Flags = Imports->Flags;\n\n\tif (!(ImportDll->Flags & PH_MAPPED_IMAGE_DELAY_IMPORTS))\n\t{\n\t\tImportDll->Descriptor = &Imports->DescriptorTable[Index];\n\n\t\tImportDll->Name = PhMappedImageRvaToVa(\n\t\t\tImportDll->MappedImage,\n\t\t\tImportDll->Descriptor->Name,\n\t\t\tNULL\n\t\t);\n\n\t\tif (!ImportDll->Name)\n\t\t\treturn STATUS_INVALID_PARAMETER;\n\n\t\t// TODO: Probe the name.\n\n\t\tif (ImportDll->Descriptor->OriginalFirstThunk)\n\t\t{\n\t\t\tImportDll->LookupTable = PhMappedImageRvaToVa(\n\t\t\t\tImportDll->MappedImage,\n\t\t\t\tImportDll->Descriptor->OriginalFirstThunk,\n\t\t\t\tNULL\n\t\t\t);\n\t\t}\n\t\telse\n\t\t{\n\t\t\tImportDll->LookupTable = PhMappedImageRvaToVa(\n\t\t\t\tImportDll->MappedImage,\n\t\t\t\tImportDll->Descriptor->FirstThunk,\n\t\t\t\tNULL\n\t\t\t);\n\t\t}\n\t}\n\telse\n\t{\n\t\tImportDll->DelayDescriptor = &Imports->DelayDescriptorTable[Index];\n\n\t\t// Backwards compatible support for legacy V1 delay imports. (dmex)\n\t\tif (ImportDll->DelayDescriptor->Attributes.RvaBased == 0)\n\t\t{\n\t\t\tImportDll->Flags |= PH_MAPPED_IMAGE_DELAY_IMPORTS_V1;\n\t\t}\n\n\t\tif (!(ImportDll->Flags & PH_MAPPED_IMAGE_DELAY_IMPORTS_V1))\n\t\t{\n\t\t\tImportDll->Name = PhMappedImageRvaToVa(\n\t\t\t\tImportDll->MappedImage,\n\t\t\t\tImportDll->DelayDescriptor->DllNameRVA,\n\t\t\t\tNULL\n\t\t\t);\n\t\t}\n\t\telse\n\t\t{\n\t\t\tImportDll->Name = PhMappedImageVaToVa(\n\t\t\t\tImportDll->MappedImage,\n\t\t\t\tImportDll->DelayDescriptor->DllNameRVA,\n\t\t\t\tNULL\n\t\t\t);\n\t\t}\n\n\t\tif (!ImportDll->Name)\n\t\t\treturn STATUS_INVALID_PARAMETER;\n\n\t\t// TODO: Probe the name.\n\n\t\tif (!(ImportDll->Flags & PH_MAPPED_IMAGE_DELAY_IMPORTS_V1))\n\t\t{\n\t\t\tImportDll->LookupTable = PhMappedImageRvaToVa(\n\t\t\t\tImportDll->MappedImage,\n\t\t\t\tImportDll->DelayDescriptor->ImportNameTableRVA,\n\t\t\t\tNULL\n\t\t\t);\n\t\t}\n\t\telse\n\t\t{\n\t\t\tImportDll->LookupTable = PhMappedImageVaToVa(\n\t\t\t\tImportDll->MappedImage,\n\t\t\t\tImportDll->DelayDescriptor->ImportNameTableRVA,\n\t\t\t\tNULL\n\t\t\t);\n\t\t}\n\t}\n\n    if (!ImportDll->LookupTable)\n        return STATUS_INVALID_PARAMETER;\n\n    // Do a scan to determine how many entries there are.\n\n    i = 0;\n\n    if (ImportDll->MappedImage->Magic == IMAGE_NT_OPTIONAL_HDR32_MAGIC)\n    {\n        PIMAGE_THUNK_DATA32 entry;\n\n        entry = (PIMAGE_THUNK_DATA32)ImportDll->LookupTable;\n\n        __try\n        {\n            while (TRUE)\n            {\n                PhpMappedImageProbe(ImportDll->MappedImage, entry, sizeof(IMAGE_THUNK_DATA32));\n\n                if (entry->u1.AddressOfData == 0)\n                    break;\n\n                entry++;\n                i++;\n            }\n        }\n        __except (EXCEPTION_EXECUTE_HANDLER)\n        {\n            return GetExceptionCode();\n        }\n    }\n    else if (ImportDll->MappedImage->Magic == IMAGE_NT_OPTIONAL_HDR64_MAGIC)\n    {\n        PIMAGE_THUNK_DATA64 entry;\n\n        entry = (PIMAGE_THUNK_DATA64)ImportDll->LookupTable;\n\n        __try\n        {\n            while (TRUE)\n            {\n                PhpMappedImageProbe(ImportDll->MappedImage, entry, sizeof(IMAGE_THUNK_DATA64));\n\n                if (entry->u1.AddressOfData == 0)\n                    break;\n\n                entry++;\n                i++;\n            }\n        }\n        __except (EXCEPTION_EXECUTE_HANDLER)\n        {\n            return GetExceptionCode();\n        }\n    }\n    else\n    {\n        return STATUS_INVALID_PARAMETER;\n    }\n\n    ImportDll->NumberOfEntries = i;\n\n    return STATUS_SUCCESS;\n}\n\nNTSTATUS PhGetMappedImageImportEntry(\n    _In_ PPH_MAPPED_IMAGE_IMPORT_DLL ImportDll,\n    _In_ ULONG Index,\n    _Out_ PPH_MAPPED_IMAGE_IMPORT_ENTRY Entry\n    )\n{\n    PIMAGE_IMPORT_BY_NAME importByName;\n\n    if (Index >= ImportDll->NumberOfEntries)\n        return STATUS_INVALID_PARAMETER_2;\n\n    if (ImportDll->MappedImage->Magic == IMAGE_NT_OPTIONAL_HDR32_MAGIC)\n    {\n        IMAGE_THUNK_DATA32 entry;\n\n        entry = ((PIMAGE_THUNK_DATA32)ImportDll->LookupTable)[Index];\n\n        // Is this entry using an ordinal?\n        if (IMAGE_SNAP_BY_ORDINAL32(entry.u1.Ordinal))\n        {\n            Entry->Name = NULL;\n            Entry->Ordinal = IMAGE_ORDINAL32(entry.u1.Ordinal);\n\n            return STATUS_SUCCESS;\n        }\n        else\n        {\n\t\t\tif (!(ImportDll->Flags & PH_MAPPED_IMAGE_DELAY_IMPORTS_V1))\n\t\t\t{\n\t\t\t\timportByName = PhMappedImageRvaToVa(\n\t\t\t\t\tImportDll->MappedImage,\n\t\t\t\t\tentry.u1.AddressOfData,\n\t\t\t\t\tNULL\n\t\t\t\t);\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\timportByName = PhMappedImageVaToVa(\n\t\t\t\t\tImportDll->MappedImage,\n\t\t\t\t\tentry.u1.AddressOfData,\n\t\t\t\t\tNULL\n\t\t\t\t);\n\t\t\t}\n        }\n    }\n    else if (ImportDll->MappedImage->Magic == IMAGE_NT_OPTIONAL_HDR64_MAGIC)\n    {\n        IMAGE_THUNK_DATA64 entry;\n\n        entry = ((PIMAGE_THUNK_DATA64)ImportDll->LookupTable)[Index];\n\n        // Is this entry using an ordinal?\n        if (IMAGE_SNAP_BY_ORDINAL64(entry.u1.Ordinal))\n        {\n            Entry->Name = NULL;\n            Entry->Ordinal = IMAGE_ORDINAL64(entry.u1.Ordinal);\n\n            return STATUS_SUCCESS;\n        }\n        else\n        {\n\t\t\tif (!(ImportDll->Flags & PH_MAPPED_IMAGE_DELAY_IMPORTS_V1))\n\t\t\t{\n\t\t\t\timportByName = PhMappedImageRvaToVa(\n\t\t\t\t\tImportDll->MappedImage,\n\t\t\t\t\t(ULONG)entry.u1.AddressOfData,\n\t\t\t\t\tNULL\n\t\t\t\t);\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\timportByName = PhMappedImageVaToVa(\n\t\t\t\t\tImportDll->MappedImage,\n\t\t\t\t\t(ULONG)entry.u1.AddressOfData,\n\t\t\t\t\tNULL\n\t\t\t\t);\n\t\t\t}\n        }\n    }\n    else\n    {\n        return STATUS_INVALID_PARAMETER;\n    }\n\n    if (!importByName)\n        return STATUS_INVALID_PARAMETER;\n\n    __try\n    {\n        PhpMappedImageProbe(ImportDll->MappedImage, importByName, sizeof(IMAGE_IMPORT_BY_NAME));\n    }\n    __except (EXCEPTION_EXECUTE_HANDLER)\n    {\n        return GetExceptionCode();\n    }\n\n    Entry->Name = (PSTR)importByName->Name;\n    Entry->NameHint = importByName->Hint;\n\n    // TODO: Probe the name.\n\n    return STATUS_SUCCESS;\n}\n\nNTSTATUS PhGetMappedImageDelayImports(\n    _Out_ PPH_MAPPED_IMAGE_IMPORTS Imports,\n    _In_ PPH_MAPPED_IMAGE MappedImage\n    )\n{\n    NTSTATUS status;\n    PIMAGE_DATA_DIRECTORY dataDirectory;\n    PIMAGE_DELAYLOAD_DESCRIPTOR descriptor;\n    ULONG i;\n\n    Imports->MappedImage = MappedImage;\n    Imports->Flags = PH_MAPPED_IMAGE_DELAY_IMPORTS;\n\n    status = PhGetMappedImageDataEntry(\n        MappedImage,\n        IMAGE_DIRECTORY_ENTRY_DELAY_IMPORT,\n        &dataDirectory\n        );\n\n    if (!NT_SUCCESS(status))\n        return status;\n\n    descriptor = PhMappedImageRvaToVa(\n        MappedImage,\n        dataDirectory->VirtualAddress,\n        NULL\n        );\n\n    if (!descriptor)\n        return STATUS_INVALID_PARAMETER;\n\n    Imports->DelayDescriptorTable = descriptor;\n\n    // Do a scan to determine how many import descriptors there are.\n\n    i = 0;\n\n    __try\n    {\n        while (TRUE)\n        {\n            PhpMappedImageProbe(MappedImage, descriptor, sizeof(PIMAGE_DELAYLOAD_DESCRIPTOR));\n\n            if (descriptor->ImportAddressTableRVA == 0 && descriptor->ImportNameTableRVA == 0)\n                break;\n\n            descriptor++;\n            i++;\n        }\n    }\n    __except (EXCEPTION_EXECUTE_HANDLER)\n    {\n        return GetExceptionCode();\n    }\n\n    Imports->NumberOfDlls = i;\n\n    return STATUS_SUCCESS;\n}\n\nUSHORT PhCheckSum(\n    _In_ ULONG Sum,\n    _In_reads_(Count) PUSHORT Buffer,\n    _In_ ULONG Count\n    )\n{\n    while (Count--)\n    {\n        Sum += *Buffer++;\n        Sum = (Sum >> 16) + (Sum & 0xffff);\n    }\n\n    Sum = (Sum >> 16) + Sum;\n\n    return (USHORT)Sum;\n}\n\nULONG PhCheckSumMappedImage(\n    _In_ PPH_MAPPED_IMAGE MappedImage\n    )\n{\n    ULONG checkSum;\n    USHORT partialSum;\n    PUSHORT adjust;\n\n    partialSum = PhCheckSum(0, (PUSHORT)MappedImage->ViewBase, (ULONG)(MappedImage->Size + 1) / 2);\n\n    // This is actually the same for 32-bit and 64-bit executables.\n    adjust = (PUSHORT)&MappedImage->NtHeaders->OptionalHeader.CheckSum;\n\n    // Subtract the existing check sum (with carry).\n    partialSum -= partialSum < adjust[0];\n    partialSum -= adjust[0];\n    partialSum -= partialSum < adjust[1];\n    partialSum -= adjust[1];\n\n    checkSum = partialSum + (ULONG)MappedImage->Size;\n\n    return checkSum;\n}\n\nNTSTATUS PhGetMappedImageCfg64(\n    _Out_ PPH_MAPPED_IMAGE_CFG CfgConfig,\n    _In_ PPH_MAPPED_IMAGE MappedImage\n    )\n{\n    NTSTATUS status;\n    PIMAGE_LOAD_CONFIG_DIRECTORY64 config64;\n\n    if (!NT_SUCCESS(status = PhGetMappedImageLoadConfig64(MappedImage, &config64)))\n        return status;\n\n    // Not every load configuration defines CFG characteristics\n    if (!RTL_CONTAINS_FIELD(config64, config64->Size, GuardFlags))\n        return STATUS_INVALID_VIEW_SIZE;\n\n    CfgConfig->MappedImage = MappedImage;\n    CfgConfig->EntrySize = sizeof(FIELD_OFFSET(IMAGE_CFG_ENTRY, Rva)) +\n        (ULONG)((config64->GuardFlags & IMAGE_GUARD_CF_FUNCTION_TABLE_SIZE_MASK) >> IMAGE_GUARD_CF_FUNCTION_TABLE_SIZE_SHIFT);\n    CfgConfig->CfgInstrumented = !!(config64->GuardFlags & IMAGE_GUARD_CF_INSTRUMENTED);\n    CfgConfig->WriteIntegrityChecks = !!(config64->GuardFlags & IMAGE_GUARD_CFW_INSTRUMENTED);\n    CfgConfig->CfgFunctionTablePresent = !!(config64->GuardFlags & IMAGE_GUARD_CF_FUNCTION_TABLE_PRESENT);\n    CfgConfig->SecurityCookieUnused = !!(config64->GuardFlags & IMAGE_GUARD_SECURITY_COOKIE_UNUSED);\n    CfgConfig->ProtectDelayLoadedIat = !!(config64->GuardFlags & IMAGE_GUARD_PROTECT_DELAYLOAD_IAT);\n    CfgConfig->DelayLoadInDidatSection = !!(config64->GuardFlags & IMAGE_GUARD_DELAYLOAD_IAT_IN_ITS_OWN_SECTION);\n    CfgConfig->EnableExportSuppression = !!(config64->GuardFlags & IMAGE_GUARD_CF_ENABLE_EXPORT_SUPPRESSION);\n    CfgConfig->HasExportSuppressionInfos = !!(config64->GuardFlags & IMAGE_GUARD_CF_EXPORT_SUPPRESSION_INFO_PRESENT);\n    CfgConfig->CfgLongJumpTablePresent = !!(config64->GuardFlags & IMAGE_GUARD_CF_LONGJUMP_TABLE_PRESENT);\n\n    CfgConfig->NumberOfGuardFunctionEntries = config64->GuardCFFunctionCount;\n    CfgConfig->GuardFunctionTable = PhMappedImageRvaToVa(\n        MappedImage,\n        (ULONG)(config64->GuardCFFunctionTable - MappedImage->NtHeaders->OptionalHeader.ImageBase),\n        NULL\n        );\n\n    if (CfgConfig->GuardFunctionTable && CfgConfig->NumberOfGuardFunctionEntries)\n    {\n        __try\n        {\n            PhpMappedImageProbe(\n                MappedImage,\n                CfgConfig->GuardFunctionTable,\n                (SIZE_T)(CfgConfig->EntrySize * CfgConfig->NumberOfGuardFunctionEntries)\n                );\n        }\n        __except (EXCEPTION_EXECUTE_HANDLER)\n        {\n            return GetExceptionCode();\n        }\n    }\n\n    CfgConfig->NumberOfGuardAdressIatEntries = 0;\n    CfgConfig->GuardAdressIatTable = 0;\n\n    if (RTL_CONTAINS_FIELD(config64, config64->Size, GuardAddressTakenIatEntryTable))\n    {\n        CfgConfig->NumberOfGuardAdressIatEntries = config64->GuardAddressTakenIatEntryCount;\n        CfgConfig->GuardAdressIatTable = PhMappedImageRvaToVa(\n            MappedImage,\n            (ULONG)(config64->GuardAddressTakenIatEntryTable - MappedImage->NtHeaders->OptionalHeader.ImageBase),\n            NULL\n            );\n\n        if (CfgConfig->GuardAdressIatTable && CfgConfig->NumberOfGuardAdressIatEntries)\n        {\n            __try\n            {\n                PhpMappedImageProbe(\n                    MappedImage,\n                    CfgConfig->GuardAdressIatTable,\n                    (SIZE_T)(CfgConfig->EntrySize * CfgConfig->NumberOfGuardAdressIatEntries)\n                    );\n            }\n            __except (EXCEPTION_EXECUTE_HANDLER)\n            {\n                return GetExceptionCode();\n            }\n        }\n    }\n\n    CfgConfig->NumberOfGuardLongJumpEntries = 0;\n    CfgConfig->GuardLongJumpTable = 0;\n\n    if (RTL_CONTAINS_FIELD(config64, config64->Size, GuardLongJumpTargetTable))\n    {\n        CfgConfig->NumberOfGuardLongJumpEntries = config64->GuardLongJumpTargetCount;\n        CfgConfig->GuardLongJumpTable = PhMappedImageRvaToVa(\n            MappedImage,\n            (ULONG)(config64->GuardLongJumpTargetTable - MappedImage->NtHeaders->OptionalHeader.ImageBase),\n            NULL\n            );\n\n        if (CfgConfig->GuardLongJumpTable && CfgConfig->NumberOfGuardLongJumpEntries)\n        {\n            __try\n            {\n                PhpMappedImageProbe(\n                    MappedImage,\n                    CfgConfig->GuardLongJumpTable,\n                    (SIZE_T)(CfgConfig->EntrySize * CfgConfig->NumberOfGuardLongJumpEntries)\n                    );\n            }\n            __except (EXCEPTION_EXECUTE_HANDLER)\n            {\n                return GetExceptionCode();\n            }\n        }\n    }\n\n    return STATUS_SUCCESS;\n}\n\nNTSTATUS PhGetMappedImageCfg32(\n    _Out_ PPH_MAPPED_IMAGE_CFG CfgConfig,\n    _In_ PPH_MAPPED_IMAGE MappedImage\n    )\n{\n    NTSTATUS status;\n    PIMAGE_LOAD_CONFIG_DIRECTORY32 config32;\n\n    if (!NT_SUCCESS(status = PhGetMappedImageLoadConfig32(MappedImage, &config32)))\n        return status;\n    \n    // Not every load configuration defines CFG characteristics\n    if (!RTL_CONTAINS_FIELD(config32, config32->Size, GuardFlags))\n        return STATUS_INVALID_VIEW_SIZE;\n\n    CfgConfig->MappedImage = MappedImage;\n    CfgConfig->EntrySize = sizeof(FIELD_OFFSET(IMAGE_CFG_ENTRY, Rva)) +\n        (ULONG)((config32->GuardFlags & IMAGE_GUARD_CF_FUNCTION_TABLE_SIZE_MASK) >> IMAGE_GUARD_CF_FUNCTION_TABLE_SIZE_SHIFT);\n    CfgConfig->CfgInstrumented = !!(config32->GuardFlags & IMAGE_GUARD_CF_INSTRUMENTED);\n    CfgConfig->WriteIntegrityChecks = !!(config32->GuardFlags & IMAGE_GUARD_CFW_INSTRUMENTED);\n    CfgConfig->CfgFunctionTablePresent = !!(config32->GuardFlags & IMAGE_GUARD_CF_FUNCTION_TABLE_PRESENT);\n    CfgConfig->SecurityCookieUnused = !!(config32->GuardFlags & IMAGE_GUARD_SECURITY_COOKIE_UNUSED);\n    CfgConfig->ProtectDelayLoadedIat = !!(config32->GuardFlags & IMAGE_GUARD_PROTECT_DELAYLOAD_IAT);\n    CfgConfig->DelayLoadInDidatSection = !!(config32->GuardFlags & IMAGE_GUARD_DELAYLOAD_IAT_IN_ITS_OWN_SECTION);\n    CfgConfig->EnableExportSuppression = !!(config32->GuardFlags & IMAGE_GUARD_CF_ENABLE_EXPORT_SUPPRESSION);\n    CfgConfig->HasExportSuppressionInfos = !!(config32->GuardFlags & IMAGE_GUARD_CF_EXPORT_SUPPRESSION_INFO_PRESENT);\n    CfgConfig->CfgLongJumpTablePresent = !!(config32->GuardFlags & IMAGE_GUARD_CF_LONGJUMP_TABLE_PRESENT);\n\n    CfgConfig->NumberOfGuardFunctionEntries = config32->GuardCFFunctionCount;\n    CfgConfig->GuardFunctionTable = PhMappedImageRvaToVa(\n        MappedImage,\n        config32->GuardCFFunctionTable - MappedImage->NtHeaders32->OptionalHeader.ImageBase,\n        NULL\n        );\n    \n    if (CfgConfig->GuardFunctionTable && CfgConfig->NumberOfGuardFunctionEntries)\n    {\n        __try\n        {\n            PhpMappedImageProbe(\n                MappedImage,\n                CfgConfig->GuardFunctionTable,\n                (SIZE_T)(CfgConfig->EntrySize * CfgConfig->NumberOfGuardFunctionEntries)\n                );\n        }\n        __except (EXCEPTION_EXECUTE_HANDLER)\n        {\n            return GetExceptionCode();\n        }\n    }\n\n    CfgConfig->NumberOfGuardAdressIatEntries = 0;\n    CfgConfig->GuardAdressIatTable = 0;\n\n    if (RTL_CONTAINS_FIELD(config32, config32->Size, GuardAddressTakenIatEntryTable))\n    {\n        CfgConfig->NumberOfGuardAdressIatEntries = config32->GuardAddressTakenIatEntryCount;\n        CfgConfig->GuardAdressIatTable = PhMappedImageRvaToVa(\n            MappedImage,\n            config32->GuardAddressTakenIatEntryTable - MappedImage->NtHeaders32->OptionalHeader.ImageBase,\n            NULL\n            );\n\n        if (CfgConfig->GuardAdressIatTable && CfgConfig->NumberOfGuardAdressIatEntries)\n        {\n            __try\n            {\n                PhpMappedImageProbe(\n                    MappedImage,\n                    CfgConfig->GuardAdressIatTable,\n                    (SIZE_T)(CfgConfig->EntrySize * CfgConfig->NumberOfGuardAdressIatEntries)\n                    );\n            }\n            __except (EXCEPTION_EXECUTE_HANDLER)\n            {\n                return GetExceptionCode();\n            }\n        }\n    }\n\n    CfgConfig->NumberOfGuardLongJumpEntries = 0;\n    CfgConfig->GuardLongJumpTable = 0;\n\n    if (RTL_CONTAINS_FIELD(config32, config32->Size, GuardLongJumpTargetTable))\n    {\n        CfgConfig->NumberOfGuardLongJumpEntries = config32->GuardLongJumpTargetCount;\n        CfgConfig->GuardLongJumpTable = PhMappedImageRvaToVa(\n            MappedImage,\n            config32->GuardLongJumpTargetTable - MappedImage->NtHeaders32->OptionalHeader.ImageBase,\n            NULL\n            );\n\n        if (CfgConfig->GuardLongJumpTable && CfgConfig->NumberOfGuardLongJumpEntries)\n        {\n            __try\n            {\n                PhpMappedImageProbe(\n                    MappedImage,\n                    CfgConfig->GuardLongJumpTable,\n                    (SIZE_T)(CfgConfig->EntrySize * CfgConfig->NumberOfGuardLongJumpEntries)\n                    );\n            }\n            __except (EXCEPTION_EXECUTE_HANDLER)\n            {\n                return GetExceptionCode();\n            }\n        }\n    }\n\n    return STATUS_SUCCESS;\n}\n\nNTSTATUS PhGetMappedImageCfg(\n    _Out_ PPH_MAPPED_IMAGE_CFG CfgConfig,\n    _In_ PPH_MAPPED_IMAGE MappedImage\n    )\n{\n    if (MappedImage->Magic == IMAGE_NT_OPTIONAL_HDR32_MAGIC)\n    {\n        return PhGetMappedImageCfg32(CfgConfig, MappedImage);\n    }\n    else\n    {\n        return PhGetMappedImageCfg64(CfgConfig, MappedImage);\n    }\n}\n\nNTSTATUS PhGetMappedImageCfgEntry(\n    _In_ PPH_MAPPED_IMAGE_CFG CfgConfig,\n    _In_ ULONGLONG Index,\n    _In_ CFG_ENTRY_TYPE Type,\n    _Out_ PIMAGE_CFG_ENTRY Entry\n    )\n{\n    PULONGLONG guardTable;\n    ULONGLONG numberofGuardEntries;\n    PIMAGE_CFG_ENTRY cfgMappedEntry;\n\n    switch (Type)\n    {\n    case ControlFlowGuardFunction:\n        {\n            guardTable = CfgConfig->GuardFunctionTable;\n            numberofGuardEntries = CfgConfig->NumberOfGuardFunctionEntries;\n        }\n        break;\n    case ControlFlowGuardtakenIatEntry:\n        {\n            guardTable = CfgConfig->GuardAdressIatTable;\n            numberofGuardEntries = CfgConfig->NumberOfGuardAdressIatEntries;\n        }\n        break;\n    case ControlFlowGuardLongJump:\n        {\n            guardTable = CfgConfig->GuardLongJumpTable;\n            numberofGuardEntries = CfgConfig->NumberOfGuardLongJumpEntries;\n        }\n        break;\n    default:\n        return STATUS_INVALID_PARAMETER_3;\n    }\n\n    if (!guardTable || Index >= numberofGuardEntries)\n        return STATUS_PROCEDURE_NOT_FOUND;\n\n    cfgMappedEntry = (PIMAGE_CFG_ENTRY)PTR_ADD_OFFSET(guardTable, Index * CfgConfig->EntrySize);\n\n    Entry->Rva = cfgMappedEntry->Rva;\n\n    // Optional header after the rva entry\n    if (CfgConfig->EntrySize > sizeof(FIELD_OFFSET(IMAGE_CFG_ENTRY, Rva)))\n    {\n        Entry->SuppressedCall = cfgMappedEntry->SuppressedCall;\n        Entry->Reserved = cfgMappedEntry->Reserved;\n    }\n\n    return STATUS_SUCCESS;\n}\n\nNTSTATUS PhGetMappedImageResources(\n    _Out_ PPH_MAPPED_IMAGE_RESOURCES Resources,\n    _In_ PPH_MAPPED_IMAGE MappedImage\n    )\n{\n    NTSTATUS status;\n    PIMAGE_RESOURCE_DIRECTORY resourceDirectory;\n    PIMAGE_RESOURCE_DIRECTORY nameDirectory;\n    PIMAGE_RESOURCE_DIRECTORY languageDirectory;\n    PIMAGE_RESOURCE_DIRECTORY_ENTRY resourceType;\n    PIMAGE_RESOURCE_DIRECTORY_ENTRY resourceName;\n    PIMAGE_RESOURCE_DIRECTORY_ENTRY resourceLanguage;\n    ULONG resourceCount = 0;\n    ULONG resourceIndex = 0;\n    ULONG resourceTypeCount;\n    ULONG resourceNameCount;\n    ULONG resourceLanguageCount;\n\n    // Get a pointer to the resource directory.\n\n    status = PhGetMappedImageDataEntry(\n        MappedImage,\n        IMAGE_DIRECTORY_ENTRY_RESOURCE,\n        &Resources->DataDirectory\n        );\n\n    if (!NT_SUCCESS(status))\n        return status;\n\n    resourceDirectory = PhMappedImageRvaToVa(\n        MappedImage,\n        Resources->DataDirectory->VirtualAddress,\n        NULL\n        );\n\n    if (!resourceDirectory)\n        return STATUS_INVALID_PARAMETER;\n\n    __try\n    {\n        PhpMappedImageProbe(MappedImage, resourceDirectory, sizeof(IMAGE_RESOURCE_DIRECTORY));\n    }\n    __except (EXCEPTION_EXECUTE_HANDLER)\n    {\n        return GetExceptionCode();\n    }\n\n    Resources->ResourceDirectory = resourceDirectory;\n\n    // NOTE: We can't use LdrEnumResources here because we're using an image mapped with SEC_COMMIT.\n\n    // Do a scan to determine how many resources there are.\n\n    resourceType = PTR_ADD_OFFSET(resourceDirectory, sizeof(IMAGE_RESOURCE_DIRECTORY));\n    resourceTypeCount = resourceDirectory->NumberOfNamedEntries + resourceDirectory->NumberOfIdEntries;\n\n    for (ULONG i = 0; i < resourceTypeCount; ++i, ++resourceType)\n    {\n        if (!resourceType->DataIsDirectory)\n            return STATUS_RESOURCE_TYPE_NOT_FOUND;\n\n        nameDirectory = PTR_ADD_OFFSET(resourceDirectory, resourceType->OffsetToDirectory);\n        resourceName = PTR_ADD_OFFSET(nameDirectory, sizeof(IMAGE_RESOURCE_DIRECTORY));\n        resourceNameCount = nameDirectory->NumberOfNamedEntries + nameDirectory->NumberOfIdEntries;\n\n        for (ULONG j = 0; j < resourceNameCount; ++j, ++resourceName)\n        {\n            if (!resourceName->DataIsDirectory)\n                return STATUS_RESOURCE_NAME_NOT_FOUND;\n\n            languageDirectory = PTR_ADD_OFFSET(resourceDirectory, resourceName->OffsetToDirectory);\n            resourceLanguage = PTR_ADD_OFFSET(languageDirectory, sizeof(IMAGE_RESOURCE_DIRECTORY));\n            resourceLanguageCount = languageDirectory->NumberOfNamedEntries + languageDirectory->NumberOfIdEntries;\n\n            for (ULONG k = 0; k < resourceLanguageCount; ++k, ++resourceLanguage)\n            {\n                if (resourceLanguage->DataIsDirectory)\n                    return STATUS_RESOURCE_DATA_NOT_FOUND;\n\n                resourceCount++;\n            }\n        }\n    }\n\n    if (resourceCount == 0)\n        return STATUS_INVALID_IMAGE_FORMAT;\n\n    // Allocate the number of resources.\n\n    Resources->NumberOfEntries = resourceCount;\n    Resources->ResourceEntries = PhAllocate(sizeof(PH_IMAGE_RESOURCE_ENTRY) * resourceCount);\n    memset(Resources->ResourceEntries, 0, sizeof(PH_IMAGE_RESOURCE_ENTRY) * resourceCount);\n\n    // Enumerate the resources adding them into our buffer.\n\n    resourceType = PTR_ADD_OFFSET(resourceDirectory, sizeof(IMAGE_RESOURCE_DIRECTORY));\n    resourceTypeCount = resourceDirectory->NumberOfNamedEntries + resourceDirectory->NumberOfIdEntries;\n\n    for (ULONG i = 0; i < resourceTypeCount; ++i, ++resourceType)\n    {\n        if (!resourceType->DataIsDirectory)\n            goto CleanupExit;\n\n        nameDirectory = PTR_ADD_OFFSET(resourceDirectory, resourceType->OffsetToDirectory);\n        resourceName = PTR_ADD_OFFSET(nameDirectory, sizeof(IMAGE_RESOURCE_DIRECTORY));\n        resourceNameCount = nameDirectory->NumberOfNamedEntries + nameDirectory->NumberOfIdEntries;\n\n        for (ULONG j = 0; j < resourceNameCount; ++j, ++resourceName)\n        {\n            if (!resourceName->DataIsDirectory)\n                goto CleanupExit;\n\n            languageDirectory = PTR_ADD_OFFSET(resourceDirectory, resourceName->OffsetToDirectory);\n            resourceLanguage = PTR_ADD_OFFSET(languageDirectory, sizeof(IMAGE_RESOURCE_DIRECTORY));\n            resourceLanguageCount = languageDirectory->NumberOfNamedEntries + languageDirectory->NumberOfIdEntries;\n\n            for (ULONG k = 0; k < resourceLanguageCount; ++k, ++resourceLanguage)\n            {\n                PIMAGE_RESOURCE_DATA_ENTRY resourceData;\n\n                if (resourceLanguage->DataIsDirectory)\n                    goto CleanupExit;\n\n                resourceData = PTR_ADD_OFFSET(resourceDirectory, resourceLanguage->OffsetToData);\n\n                Resources->ResourceEntries[resourceIndex].Type = NAME_FROM_RESOURCE_ENTRY(resourceDirectory, resourceType);\n                Resources->ResourceEntries[resourceIndex].Name = NAME_FROM_RESOURCE_ENTRY(resourceDirectory, resourceName);\n                Resources->ResourceEntries[resourceIndex].Language = NAME_FROM_RESOURCE_ENTRY(resourceDirectory, resourceLanguage);\n\t\t\t\tResources->ResourceEntries[resourceIndex].Data = PhMappedImageRvaToVa(MappedImage, resourceData->OffsetToData, NULL);\n                Resources->ResourceEntries[resourceIndex++].Size = resourceData->Size;\n            }\n        }\n    }\n\nCleanupExit:\n    return status;\n}\n    "
  },
  {
    "path": "third_party/phlib/maplib.c",
    "content": "/*\n * Process Hacker -\n *   mapped library\n *\n * Copyright (C) 2010 wj32\n *\n * This file is part of Process Hacker.\n *\n * Process Hacker is free software; you can redistribute it and/or modify\n * it under the terms of the GNU General Public License as published by\n * the Free Software Foundation, either version 3 of the License, or\n * (at your option) any later version.\n *\n * Process Hacker is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n * GNU General Public License for more details.\n *\n * You should have received a copy of the GNU General Public License\n * along with Process Hacker.  If not, see <http://www.gnu.org/licenses/>.\n */\n\n/*\n * This file contains functions to load and retrieve information for library/archive files (lib).\n * The file format for archive files is explained in the PE/COFF specification located at:\n *\n * http://www.microsoft.com/whdc/system/platform/firmware/PECOFF.mspx\n */\n\n#include <ph.h>\n#include <mapimg.h>\n\nVOID PhpMappedArchiveProbe(\n    _In_ PPH_MAPPED_ARCHIVE MappedArchive,\n    _In_ PVOID Address,\n    _In_ SIZE_T Length\n    );\n\nNTSTATUS PhpGetMappedArchiveMemberFromHeader(\n    _In_ PPH_MAPPED_ARCHIVE MappedArchive,\n    _In_ PIMAGE_ARCHIVE_MEMBER_HEADER Header,\n    _Out_ PPH_MAPPED_ARCHIVE_MEMBER Member\n    );\n\nNTSTATUS PhInitializeMappedArchive(\n    _Out_ PPH_MAPPED_ARCHIVE MappedArchive,\n    _In_ PVOID ViewBase,\n    _In_ SIZE_T Size\n    )\n{\n    NTSTATUS status;\n    PVOID start;\n\n    start = ViewBase;\n\n    memset(MappedArchive, 0, sizeof(PH_MAPPED_ARCHIVE));\n    MappedArchive->ViewBase = ViewBase;\n    MappedArchive->Size = Size;\n\n    __try\n    {\n        // Verify the file signature.\n\n        PhpMappedArchiveProbe(MappedArchive, start, IMAGE_ARCHIVE_START_SIZE);\n\n        if (memcmp(start, IMAGE_ARCHIVE_START, IMAGE_ARCHIVE_START_SIZE) != 0)\n            PhRaiseStatus(STATUS_INVALID_IMAGE_FORMAT);\n    }\n    __except (EXCEPTION_EXECUTE_HANDLER)\n    {\n        return GetExceptionCode();\n    }\n\n    // Get the members.\n    // Note: the names are checked.\n\n    // First linker member\n\n    status = PhpGetMappedArchiveMemberFromHeader(\n        MappedArchive,\n        PTR_ADD_OFFSET(start, IMAGE_ARCHIVE_START_SIZE),\n        &MappedArchive->FirstLinkerMember\n        );\n\n    if (!NT_SUCCESS(status))\n        return status;\n\n    if (MappedArchive->FirstLinkerMember.Type != LinkerArchiveMemberType)\n        return STATUS_INVALID_PARAMETER;\n\n    MappedArchive->FirstStandardMember = &MappedArchive->FirstLinkerMember;\n\n    // Second linker member\n\n    status = PhGetNextMappedArchiveMember(\n        &MappedArchive->FirstLinkerMember,\n        &MappedArchive->SecondLinkerMember\n        );\n\n    if (!NT_SUCCESS(status))\n        return status;\n\n    if (MappedArchive->SecondLinkerMember.Type != LinkerArchiveMemberType)\n        return STATUS_INVALID_PARAMETER;\n\n    // Longnames member\n    // This member doesn't seem to be mandatory, contrary to the specification.\n    // So we'll check if it's actually a longnames member, and if not, ignore it.\n\n    status = PhGetNextMappedArchiveMember(\n        &MappedArchive->SecondLinkerMember,\n        &MappedArchive->LongnamesMember\n        );\n\n    if (\n        NT_SUCCESS(status) &&\n        MappedArchive->LongnamesMember.Type == LongnamesArchiveMemberType\n        )\n    {\n        MappedArchive->HasLongnamesMember = TRUE;\n        MappedArchive->LastStandardMember = &MappedArchive->LongnamesMember;\n    }\n    else\n    {\n        MappedArchive->LastStandardMember = &MappedArchive->SecondLinkerMember;\n    }\n\n    return STATUS_SUCCESS;\n}\n\nNTSTATUS PhLoadMappedArchive(\n    _In_opt_ PWSTR FileName,\n    _In_opt_ HANDLE FileHandle,\n    _In_ BOOLEAN ReadOnly,\n    _Out_ PPH_MAPPED_ARCHIVE MappedArchive\n    )\n{\n    NTSTATUS status;\n\n    status = PhMapViewOfEntireFile(\n        FileName,\n        FileHandle,\n        ReadOnly,\n        &MappedArchive->ViewBase,\n        &MappedArchive->Size\n        );\n\n    if (NT_SUCCESS(status))\n    {\n        status = PhInitializeMappedArchive(\n            MappedArchive,\n            MappedArchive->ViewBase,\n            MappedArchive->Size\n            );\n\n        if (!NT_SUCCESS(status))\n        {\n            NtUnmapViewOfSection(NtCurrentProcess(), MappedArchive->ViewBase);\n        }\n    }\n\n    return status;\n}\n\nNTSTATUS PhUnloadMappedArchive(\n    _Inout_ PPH_MAPPED_ARCHIVE MappedArchive\n    )\n{\n    return NtUnmapViewOfSection(\n        NtCurrentProcess(),\n        MappedArchive->ViewBase\n        );\n}\n\nVOID PhpMappedArchiveProbe(\n    _In_ PPH_MAPPED_ARCHIVE MappedArchive,\n    _In_ PVOID Address,\n    _In_ SIZE_T Length\n    )\n{\n    PhProbeAddress(Address, Length, MappedArchive->ViewBase, MappedArchive->Size, 1);\n}\n\n/**\n * Gets the next archive member.\n *\n * \\param Member An archive member structure.\n * \\param NextMember A variable which receives a structure describing the next archive member. This\n * pointer may be the same as the pointer specified in \\a Member.\n */\nNTSTATUS PhGetNextMappedArchiveMember(\n    _In_ PPH_MAPPED_ARCHIVE_MEMBER Member,\n    _Out_ PPH_MAPPED_ARCHIVE_MEMBER NextMember\n    )\n{\n    PIMAGE_ARCHIVE_MEMBER_HEADER nextHeader;\n\n    nextHeader = (PIMAGE_ARCHIVE_MEMBER_HEADER)PTR_ADD_OFFSET(\n        Member->Data,\n        Member->Size\n        );\n\n    // 2 byte alignment.\n    if ((ULONG_PTR)nextHeader & 0x1)\n        nextHeader = (PIMAGE_ARCHIVE_MEMBER_HEADER)PTR_ADD_OFFSET(nextHeader, 1);\n\n    return PhpGetMappedArchiveMemberFromHeader(\n        Member->MappedArchive,\n        nextHeader,\n        NextMember\n        );\n}\n\nNTSTATUS PhpGetMappedArchiveMemberFromHeader(\n    _In_ PPH_MAPPED_ARCHIVE MappedArchive,\n    _In_ PIMAGE_ARCHIVE_MEMBER_HEADER Header,\n    _Out_ PPH_MAPPED_ARCHIVE_MEMBER Member\n    )\n{\n    WCHAR integerString[11];\n    ULONG64 size;\n    PH_STRINGREF string;\n    PWSTR digit;\n    PSTR slash;\n\n    if ((ULONG_PTR)Header >= (ULONG_PTR)MappedArchive->ViewBase + MappedArchive->Size)\n        return STATUS_NO_MORE_ENTRIES;\n\n    __try\n    {\n        PhpMappedArchiveProbe(MappedArchive, Header, sizeof(IMAGE_ARCHIVE_MEMBER_HEADER));\n    }\n    __except (EXCEPTION_EXECUTE_HANDLER)\n    {\n        return GetExceptionCode();\n    }\n\n    Member->MappedArchive = MappedArchive;\n    Member->Header = Header;\n    Member->Data = PTR_ADD_OFFSET(Header, sizeof(IMAGE_ARCHIVE_MEMBER_HEADER));\n    Member->Type = NormalArchiveMemberType;\n\n    // Read the size string, terminate it after the last digit and parse it.\n\n    if (!PhCopyStringZFromBytes(Header->Size, 10, integerString, 11, NULL))\n        return STATUS_INVALID_PARAMETER;\n\n    string.Buffer = integerString;\n    string.Length = 0;\n    digit = string.Buffer;\n\n    while (iswdigit(*digit++))\n        string.Length += sizeof(WCHAR);\n\n    if (!PhStringToInteger64(&string, 10, &size))\n        return STATUS_INVALID_PARAMETER;\n\n    Member->Size = (ULONG)size;\n\n    __try\n    {\n        PhpMappedArchiveProbe(MappedArchive, Member->Data, Member->Size);\n    }\n    __except (EXCEPTION_EXECUTE_HANDLER)\n    {\n        return GetExceptionCode();\n    }\n\n    // Parse the name.\n\n    if (!PhCopyBytesZ(Header->Name, 16, Member->NameBuffer, 20, NULL))\n        return STATUS_INVALID_PARAMETER;\n\n    Member->Name = Member->NameBuffer;\n\n    slash = strchr(Member->NameBuffer, '/');\n\n    if (!slash)\n        return STATUS_INVALID_PARAMETER;\n\n    // Special names:\n    // * If the slash is the first character, then this is a linker member.\n    // * If there is a slash after the slash which is a first character, then this is the longnames\n    //   member.\n    // * If there are digits after the slash, then the real name is stored in the longnames member.\n\n    if (slash == Member->NameBuffer)\n    {\n        if (Member->NameBuffer[1] == '/')\n        {\n            // Longnames member. Set the name to \"/\".\n            Member->NameBuffer[0] = '/';\n            Member->NameBuffer[1] = 0;\n\n            Member->Type = LongnamesArchiveMemberType;\n        }\n        else\n        {\n            // Linker member. Set the name to \"\".\n            Member->NameBuffer[0] = 0;\n\n            Member->Type = LinkerArchiveMemberType;\n        }\n    }\n    else\n    {\n        if (isdigit(slash[1]))\n        {\n            PSTR digita;\n            ULONG64 offset64;\n            ULONG offset;\n\n            // The name is stored in the longnames member.\n            // Note: we make sure we have the longnames member first.\n\n            if (!MappedArchive->LongnamesMember.Header)\n                return STATUS_INVALID_PARAMETER;\n\n            // Find the last digit and null terminate the string there.\n\n            digita = slash + 2;\n\n            while (isdigit(*digita))\n                digita++;\n\n            *digita = 0;\n\n            // Parse the offset and make sure it lies within the longnames member.\n\n            if (!PhCopyStringZFromBytes(slash + 1, -1, integerString, 11, NULL))\n                return STATUS_INVALID_PARAMETER;\n            PhInitializeStringRefLongHint(&string, integerString);\n            if (!PhStringToInteger64(&string, 10, &offset64))\n                return STATUS_INVALID_PARAMETER;\n\n            offset = (ULONG)offset64;\n\n            if (offset >= MappedArchive->LongnamesMember.Size)\n                return STATUS_INVALID_PARAMETER;\n\n            // TODO: Probe the name.\n            Member->Name = (PSTR)PTR_ADD_OFFSET(MappedArchive->LongnamesMember.Data, offset);\n        }\n        else\n        {\n            // Null terminate the string.\n            slash[0] = 0;\n        }\n    }\n\n    return STATUS_SUCCESS;\n}\n\nBOOLEAN PhIsMappedArchiveMemberShortFormat(\n    _In_ PPH_MAPPED_ARCHIVE_MEMBER Member\n    )\n{\n    PIMAGE_FILE_HEADER header;\n\n    header = (PIMAGE_FILE_HEADER)Member->Data;\n\n    return header->Machine != IMAGE_FILE_MACHINE_UNKNOWN;\n}\n\nNTSTATUS PhGetMappedArchiveImportEntry(\n    _In_ PPH_MAPPED_ARCHIVE_MEMBER Member,\n    _Out_ PPH_MAPPED_ARCHIVE_IMPORT_ENTRY Entry\n    )\n{\n    IMPORT_OBJECT_HEADER *importHeader;\n\n    importHeader = (IMPORT_OBJECT_HEADER *)Member->Data;\n\n    if (\n        importHeader->Sig1 != IMAGE_FILE_MACHINE_UNKNOWN ||\n        importHeader->Sig2 != IMPORT_OBJECT_HDR_SIG2\n        )\n        return STATUS_INVALID_PARAMETER;\n\n    Entry->Type = (BYTE)importHeader->Type;\n    Entry->NameType = (BYTE)importHeader->NameType;\n    Entry->Machine = importHeader->Machine;\n\n    // TODO: Probe the name.\n    Entry->Name = (PSTR)PTR_ADD_OFFSET(importHeader, sizeof(IMPORT_OBJECT_HEADER));\n    Entry->DllName = (PSTR)PTR_ADD_OFFSET(Entry->Name, strlen(Entry->Name) + 1);\n\n    // Ordinal/NameHint are union'ed, so these statements are exactly the same.\n    // It's there in case this changes in the future.\n    if (Entry->NameType == IMPORT_OBJECT_ORDINAL)\n    {\n        Entry->Ordinal = importHeader->Ordinal;\n    }\n    else\n    {\n        Entry->NameHint = importHeader->Hint;\n    }\n\n    return STATUS_SUCCESS;\n}\n"
  },
  {
    "path": "third_party/phlib/md5.c",
    "content": "/*\n * MD5 hash implementation and interface functions\n * Copyright (c) 2003-2005, Jouni Malinen <jkmaline@cc.hut.fi>\n *\n * This program is free software; you can redistribute it and/or modify\n * it under the terms of the GNU General Public License version 2 as\n * published by the Free Software Foundation.\n */\n\n/* This code was modified for Process Hacker. */\n\n#include <phbase.h>\n#include \"md5.h\"\n\nvoid MD5Transform(ULONG buf[4], ULONG in[16]);\n\n/*\n * Start MD5 accumulation.  Set bit count to 0 and buffer to mysterious\n * initialization constants.\n */\nVOID MD5Init(\n    _Out_ MD5_CTX *Context\n    )\n{\n    Context->buf[0] = 0x67452301;\n    Context->buf[1] = 0xefcdab89;\n    Context->buf[2] = 0x98badcfe;\n    Context->buf[3] = 0x10325476;\n\n    Context->i[0] = 0;\n    Context->i[1] = 0;\n}\n\n/*\n * Update context to reflect the concatenation of another buffer full\n * of bytes.\n */\nVOID MD5Update(\n    _Inout_ MD5_CTX *Context,\n    _In_reads_bytes_(Length) UCHAR *Input,\n    _In_ ULONG Length\n    )\n{\n    ULONG t;\n\n    /* Update bitcount */\n\n    t = Context->i[0];\n    if ((Context->i[0] = t + ((ULONG) Length << 3)) < t)\n    Context->i[1]++;        /* Carry from low to high */\n    Context->i[1] += Length >> 29;\n\n    t = (t >> 3) & 0x3f;    /* Bytes already in shsInfo->data */\n\n    /* Handle any leading odd-sized chunks */\n\n    if (t) {\n    unsigned char *p = (unsigned char *) Context->in + t;\n\n    t = 64 - t;\n    if (Length < t) {\n        memcpy(p, Input, Length);\n        return;\n    }\n    memcpy(p, Input, t);\n    MD5Transform(Context->buf, (ULONG *) Context->in);\n    Input += t;\n    Length -= t;\n    }\n    /* Process data in 64-byte chunks */\n\n    while (Length >= 64) {\n    memcpy(Context->in, Input, 64);\n    MD5Transform(Context->buf, (ULONG *) Context->in);\n    Input += 64;\n    Length -= 64;\n    }\n\n    /* Handle any remaining bytes of data. */\n\n    memcpy(Context->in, Input, Length);\n}\n\n/*\n * Final wrapup - pad to 64-byte boundary with the bit pattern\n * 1 0* (64-bit count of bits processed, MSB-first)\n */\nVOID MD5Final(\n    _Inout_ MD5_CTX *Context\n    )\n{\n    unsigned int count;\n    unsigned char *p;\n\n    /* Compute number of bytes mod 64 */\n    count = (Context->i[0] >> 3) & 0x3F;\n\n    /* Set the first char of padding to 0x80.  This is safe since there is\n       always at least one byte free */\n    p = Context->in + count;\n    *p++ = 0x80;\n\n    /* Bytes of padding needed to make 64 bytes */\n    count = 64 - 1 - count;\n\n    /* Pad out to 56 mod 64 */\n    if (count < 8) {\n    /* Two lots of padding:  Pad the first block to 64 bytes */\n    memset(p, 0, count);\n    MD5Transform(Context->buf, (ULONG *) Context->in);\n\n    /* Now fill the next block with 56 bytes */\n    memset(Context->in, 0, 56);\n    } else {\n    /* Pad block to 56 bytes */\n    memset(p, 0, count - 8);\n    }\n\n    /* Append length in bits and transform */\n    ((ULONG *) Context->in)[14] = Context->i[0];\n    ((ULONG *) Context->in)[15] = Context->i[1];\n\n    MD5Transform(Context->buf, (ULONG *) Context->in);\n    memcpy(Context->digest, Context->buf, 16);\n}\n\n/* The four core functions - F1 is optimized somewhat */\n\n/* #define F1(x, y, z) (x & y | ~x & z) */\n#define F1(x, y, z) (z ^ (x & (y ^ z)))\n#define F2(x, y, z) F1(z, x, y)\n#define F3(x, y, z) (x ^ y ^ z)\n#define F4(x, y, z) (y ^ (x | ~z))\n\n/* This is the central step in the MD5 algorithm. */\n#define MD5STEP(f, w, x, y, z, data, s) \\\n    ( w += f(x, y, z) + data,  w = _rotl(w, s),  w += x )\n\n/*\n * The core of the MD5 algorithm, this alters an existing MD5 hash to\n * reflect the addition of 16 longwords of new data.  MD5Update blocks\n * the data and converts bytes into longwords for this routine.\n */\nvoid MD5Transform(ULONG buf[4], ULONG in[16])\n{\n    register ULONG a, b, c, d;\n\n    a = buf[0];\n    b = buf[1];\n    c = buf[2];\n    d = buf[3];\n\n    MD5STEP(F1, a, b, c, d, in[0] + 0xd76aa478, 7);\n    MD5STEP(F1, d, a, b, c, in[1] + 0xe8c7b756, 12);\n    MD5STEP(F1, c, d, a, b, in[2] + 0x242070db, 17);\n    MD5STEP(F1, b, c, d, a, in[3] + 0xc1bdceee, 22);\n    MD5STEP(F1, a, b, c, d, in[4] + 0xf57c0faf, 7);\n    MD5STEP(F1, d, a, b, c, in[5] + 0x4787c62a, 12);\n    MD5STEP(F1, c, d, a, b, in[6] + 0xa8304613, 17);\n    MD5STEP(F1, b, c, d, a, in[7] + 0xfd469501, 22);\n    MD5STEP(F1, a, b, c, d, in[8] + 0x698098d8, 7);\n    MD5STEP(F1, d, a, b, c, in[9] + 0x8b44f7af, 12);\n    MD5STEP(F1, c, d, a, b, in[10] + 0xffff5bb1, 17);\n    MD5STEP(F1, b, c, d, a, in[11] + 0x895cd7be, 22);\n    MD5STEP(F1, a, b, c, d, in[12] + 0x6b901122, 7);\n    MD5STEP(F1, d, a, b, c, in[13] + 0xfd987193, 12);\n    MD5STEP(F1, c, d, a, b, in[14] + 0xa679438e, 17);\n    MD5STEP(F1, b, c, d, a, in[15] + 0x49b40821, 22);\n\n    MD5STEP(F2, a, b, c, d, in[1] + 0xf61e2562, 5);\n    MD5STEP(F2, d, a, b, c, in[6] + 0xc040b340, 9);\n    MD5STEP(F2, c, d, a, b, in[11] + 0x265e5a51, 14);\n    MD5STEP(F2, b, c, d, a, in[0] + 0xe9b6c7aa, 20);\n    MD5STEP(F2, a, b, c, d, in[5] + 0xd62f105d, 5);\n    MD5STEP(F2, d, a, b, c, in[10] + 0x02441453, 9);\n    MD5STEP(F2, c, d, a, b, in[15] + 0xd8a1e681, 14);\n    MD5STEP(F2, b, c, d, a, in[4] + 0xe7d3fbc8, 20);\n    MD5STEP(F2, a, b, c, d, in[9] + 0x21e1cde6, 5);\n    MD5STEP(F2, d, a, b, c, in[14] + 0xc33707d6, 9);\n    MD5STEP(F2, c, d, a, b, in[3] + 0xf4d50d87, 14);\n    MD5STEP(F2, b, c, d, a, in[8] + 0x455a14ed, 20);\n    MD5STEP(F2, a, b, c, d, in[13] + 0xa9e3e905, 5);\n    MD5STEP(F2, d, a, b, c, in[2] + 0xfcefa3f8, 9);\n    MD5STEP(F2, c, d, a, b, in[7] + 0x676f02d9, 14);\n    MD5STEP(F2, b, c, d, a, in[12] + 0x8d2a4c8a, 20);\n\n    MD5STEP(F3, a, b, c, d, in[5] + 0xfffa3942, 4);\n    MD5STEP(F3, d, a, b, c, in[8] + 0x8771f681, 11);\n    MD5STEP(F3, c, d, a, b, in[11] + 0x6d9d6122, 16);\n    MD5STEP(F3, b, c, d, a, in[14] + 0xfde5380c, 23);\n    MD5STEP(F3, a, b, c, d, in[1] + 0xa4beea44, 4);\n    MD5STEP(F3, d, a, b, c, in[4] + 0x4bdecfa9, 11);\n    MD5STEP(F3, c, d, a, b, in[7] + 0xf6bb4b60, 16);\n    MD5STEP(F3, b, c, d, a, in[10] + 0xbebfbc70, 23);\n    MD5STEP(F3, a, b, c, d, in[13] + 0x289b7ec6, 4);\n    MD5STEP(F3, d, a, b, c, in[0] + 0xeaa127fa, 11);\n    MD5STEP(F3, c, d, a, b, in[3] + 0xd4ef3085, 16);\n    MD5STEP(F3, b, c, d, a, in[6] + 0x04881d05, 23);\n    MD5STEP(F3, a, b, c, d, in[9] + 0xd9d4d039, 4);\n    MD5STEP(F3, d, a, b, c, in[12] + 0xe6db99e5, 11);\n    MD5STEP(F3, c, d, a, b, in[15] + 0x1fa27cf8, 16);\n    MD5STEP(F3, b, c, d, a, in[2] + 0xc4ac5665, 23);\n\n    MD5STEP(F4, a, b, c, d, in[0] + 0xf4292244, 6);\n    MD5STEP(F4, d, a, b, c, in[7] + 0x432aff97, 10);\n    MD5STEP(F4, c, d, a, b, in[14] + 0xab9423a7, 15);\n    MD5STEP(F4, b, c, d, a, in[5] + 0xfc93a039, 21);\n    MD5STEP(F4, a, b, c, d, in[12] + 0x655b59c3, 6);\n    MD5STEP(F4, d, a, b, c, in[3] + 0x8f0ccc92, 10);\n    MD5STEP(F4, c, d, a, b, in[10] + 0xffeff47d, 15);\n    MD5STEP(F4, b, c, d, a, in[1] + 0x85845dd1, 21);\n    MD5STEP(F4, a, b, c, d, in[8] + 0x6fa87e4f, 6);\n    MD5STEP(F4, d, a, b, c, in[15] + 0xfe2ce6e0, 10);\n    MD5STEP(F4, c, d, a, b, in[6] + 0xa3014314, 15);\n    MD5STEP(F4, b, c, d, a, in[13] + 0x4e0811a1, 21);\n    MD5STEP(F4, a, b, c, d, in[4] + 0xf7537e82, 6);\n    MD5STEP(F4, d, a, b, c, in[11] + 0xbd3af235, 10);\n    MD5STEP(F4, c, d, a, b, in[2] + 0x2ad7d2bb, 15);\n    MD5STEP(F4, b, c, d, a, in[9] + 0xeb86d391, 21);\n\n    buf[0] += a;\n    buf[1] += b;\n    buf[2] += c;\n    buf[3] += d;\n}\n"
  },
  {
    "path": "third_party/phlib/md5.h",
    "content": "#ifndef _MD5_H\n#define _MD5_H\n\ntypedef struct\n{\n    ULONG i[2];\n    ULONG buf[4];\n    UCHAR in[64];\n    UCHAR digest[16];\n} MD5_CTX;\n\nVOID MD5Init(\n    _Out_ MD5_CTX *Context\n    );\n\nVOID MD5Update(\n    _Inout_ MD5_CTX *Context,\n    _In_reads_bytes_(Length) UCHAR *Input,\n    _In_ ULONG Length\n    );\n\nVOID MD5Final(\n    _Inout_ MD5_CTX *Context\n    );\n\n#endif\n"
  },
  {
    "path": "third_party/phlib/mxml/COPYING",
    "content": "\t\t\t   Mini-XML License\n\t\t\t  September 18, 2010\n\n\nThe Mini-XML library and included programs are provided under the\nterms of the GNU Library General Public License version 2 (LGPL2)\nwith the following exceptions:\n\n  1. Static linking of applications to the Mini-XML library\ndoes not constitute a derivative work and does not require\nthe author to provide source code for the application, use\nthe shared Mini-XML libraries, or link their applications\nagainst a user-supplied version of Mini-XML.\n\nIf you link the application to a modified version of\nMini-XML, then the changes to Mini-XML must be provided\nunder the terms of the LGPL2 in sections 1, 2, and 4.\n\n  2. You do not have to provide a copy of the Mini-XML license\nwith programs that are linked to the Mini-XML library, nor\ndo you have to identify the Mini-XML license in your\nprogram or documentation as required by section 6 of the\nLGPL2.\n\n\n\f\t\t  GNU LIBRARY GENERAL PUBLIC LICENSE\n\t\t\t Version 2, June 1991\n\n\t  Copyright (C) 1991 Free Software Foundation, Inc.\n       59 Temple Place, Suite 330, Boston, MA  02111-1307  USA\n\n     Everyone is permitted to copy and distribute verbatim copies\n      of this license document, but changing it is not allowed.\n\n    [This is the first released version of the library GPL.  It is\n   numbered 2 because it goes with version 2 of the ordinary GPL.]\n\n\t\t\t       Preamble\n\n  The licenses for most software are designed to take away your\nfreedom to share and change it.  By contrast, the GNU General Public\nLicenses are intended to guarantee your freedom to share and change\nfree software--to make sure the software is free for all its users.\n\n  This license, the Library General Public License, applies to some\nspecially designated Free Software Foundation software, and to any\nother libraries whose authors decide to use it.  You can use it for\nyour libraries, too.\n\n  When we speak of free software, we are referring to freedom, not\nprice.  Our General Public Licenses are designed to make sure that you\nhave the freedom to distribute copies of free software (and charge for\nthis service if you wish), that you receive source code or can get it\nif you want it, that you can change the software or use pieces of it\nin new free programs; and that you know you can do these things.\n\n  To protect your rights, we need to make restrictions that forbid\nanyone to deny you these rights or to ask you to surrender the rights.\nThese restrictions translate to certain responsibilities for you if\nyou distribute copies of the library, or if you modify it.\n\n  For example, if you distribute copies of the library, whether gratis\nor for a fee, you must give the recipients all the rights that we gave\nyou.  You must make sure that they, too, receive or can get the source\ncode.  If you link a program with the library, you must provide\ncomplete object files to the recipients so that they can relink them\nwith the library, after making changes to the library and recompiling\nit.  And you must show them these terms so they know their rights.\n\n  Our method of protecting your rights has two steps: (1) copyright\nthe library, and (2) offer you this license which gives you legal\npermission to copy, distribute and/or modify the library.\n\n  Also, for each distributor's protection, we want to make certain\nthat everyone understands that there is no warranty for this free\nlibrary.  If the library is modified by someone else and passed on, we\nwant its recipients to know that what they have is not the original\nversion, so that any problems introduced by others will not reflect on\nthe original authors' reputations.\n\f\n  Finally, any free program is threatened constantly by software\npatents.  We wish to avoid the danger that companies distributing free\nsoftware will individually obtain patent licenses, thus in effect\ntransforming the program into proprietary software.  To prevent this,\nwe have made it clear that any patent must be licensed for everyone's\nfree use or not licensed at all.\n\n  Most GNU software, including some libraries, is covered by the ordinary\nGNU General Public License, which was designed for utility programs.  This\nlicense, the GNU Library General Public License, applies to certain\ndesignated libraries.  This license is quite different from the ordinary\none; be sure to read it in full, and don't assume that anything in it is\nthe same as in the ordinary license.\n\n  The reason we have a separate public license for some libraries is that\nthey blur the distinction we usually make between modifying or adding to a\nprogram and simply using it.  Linking a program with a library, without\nchanging the library, is in some sense simply using the library, and is\nanalogous to running a utility program or application program.  However, in\na textual and legal sense, the linked executable is a combined work, a\nderivative of the original library, and the ordinary General Public License\ntreats it as such.\n\n  Because of this blurred distinction, using the ordinary General\nPublic License for libraries did not effectively promote software\nsharing, because most developers did not use the libraries.  We\nconcluded that weaker conditions might promote sharing better.\n\n  However, unrestricted linking of non-free programs would deprive the\nusers of those programs of all benefit from the free status of the\nlibraries themselves.  This Library General Public License is intended to\npermit developers of non-free programs to use free libraries, while\npreserving your freedom as a user of such programs to change the free\nlibraries that are incorporated in them.  (We have not seen how to achieve\nthis as regards changes in header files, but we have achieved it as regards\nchanges in the actual functions of the Library.)  The hope is that this\nwill lead to faster development of free libraries.\n\n  The precise terms and conditions for copying, distribution and\nmodification follow.  Pay close attention to the difference between a\n\"work based on the library\" and a \"work that uses the library\".  The\nformer contains code derived from the library, while the latter only\nworks together with the library.\n\n  Note that it is possible for a library to be covered by the ordinary\nGeneral Public License rather than by this special one.\n\f\n\t\t  GNU LIBRARY GENERAL PUBLIC LICENSE\n   TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION\n\n  0. This License Agreement applies to any software library which\ncontains a notice placed by the copyright holder or other authorized\nparty saying it may be distributed under the terms of this Library\nGeneral Public License (also called \"this License\").  Each licensee is\naddressed as \"you\".\n\n  A \"library\" means a collection of software functions and/or data\nprepared so as to be conveniently linked with application programs\n(which use some of those functions and data) to form executables.\n\n  The \"Library\", below, refers to any such software library or work\nwhich has been distributed under these terms.  A \"work based on the\nLibrary\" means either the Library or any derivative work under\ncopyright law: that is to say, a work containing the Library or a\nportion of it, either verbatim or with modifications and/or translated\nstraightforwardly into another language.  (Hereinafter, translation is\nincluded without limitation in the term \"modification\".)\n\n  \"Source code\" for a work means the preferred form of the work for\nmaking modifications to it.  For a library, complete source code means\nall the source code for all modules it contains, plus any associated\ninterface definition files, plus the scripts used to control compilation\nand installation of the library.\n\n  Activities other than copying, distribution and modification are not\ncovered by this License; they are outside its scope.  The act of\nrunning a program using the Library is not restricted, and output from\nsuch a program is covered only if its contents constitute a work based\non the Library (independent of the use of the Library in a tool for\nwriting it).  Whether that is true depends on what the Library does\nand what the program that uses the Library does.\n\n  1. You may copy and distribute verbatim copies of the Library's\ncomplete source code as you receive it, in any medium, provided that\nyou conspicuously and appropriately publish on each copy an\nappropriate copyright notice and disclaimer of warranty; keep intact\nall the notices that refer to this License and to the absence of any\nwarranty; and distribute a copy of this License along with the\nLibrary.\n\n  You may charge a fee for the physical act of transferring a copy,\nand you may at your option offer warranty protection in exchange for a\nfee.\n\f\n  2. You may modify your copy or copies of the Library or any portion\nof it, thus forming a work based on the Library, and copy and\ndistribute such modifications or work under the terms of Section 1\nabove, provided that you also meet all of these conditions:\n\n    a) The modified work must itself be a software library.\n\n    b) You must cause the files modified to carry prominent notices\n    stating that you changed the files and the date of any change.\n\n    c) You must cause the whole of the work to be licensed at no\n    charge to all third parties under the terms of this License.\n\n    d) If a facility in the modified Library refers to a function or a\n    table of data to be supplied by an application program that uses\n    the facility, other than as an argument passed when the facility\n    is invoked, then you must make a good faith effort to ensure that,\n    in the event an application does not supply such function or\n    table, the facility still operates, and performs whatever part of\n    its purpose remains meaningful.\n\n    (For example, a function in a library to compute square roots has\n    a purpose that is entirely well-defined independent of the\n    application.  Therefore, Subsection 2d requires that any\n    application-supplied function or table used by this function must\n    be optional: if the application does not supply it, the square\n    root function must still compute square roots.)\n\nThese requirements apply to the modified work as a whole.  If\nidentifiable sections of that work are not derived from the Library,\nand can be reasonably considered independent and separate works in\nthemselves, then this License, and its terms, do not apply to those\nsections when you distribute them as separate works.  But when you\ndistribute the same sections as part of a whole which is a work based\non the Library, the distribution of the whole must be on the terms of\nthis License, whose permissions for other licensees extend to the\nentire whole, and thus to each and every part regardless of who wrote\nit.\n\nThus, it is not the intent of this section to claim rights or contest\nyour rights to work written entirely by you; rather, the intent is to\nexercise the right to control the distribution of derivative or\ncollective works based on the Library.\n\nIn addition, mere aggregation of another work not based on the Library\nwith the Library (or with a work based on the Library) on a volume of\na storage or distribution medium does not bring the other work under\nthe scope of this License.\n\n  3. You may opt to apply the terms of the ordinary GNU General Public\nLicense instead of this License to a given copy of the Library.  To do\nthis, you must alter all the notices that refer to this License, so\nthat they refer to the ordinary GNU General Public License, version 2,\ninstead of to this License.  (If a newer version than version 2 of the\nordinary GNU General Public License has appeared, then you can specify\nthat version instead if you wish.)  Do not make any other change in\nthese notices.\n\f\n  Once this change is made in a given copy, it is irreversible for\nthat copy, so the ordinary GNU General Public License applies to all\nsubsequent copies and derivative works made from that copy.\n\n  This option is useful when you wish to copy part of the code of\nthe Library into a program that is not a library.\n\n  4. You may copy and distribute the Library (or a portion or\nderivative of it, under Section 2) in object code or executable form\nunder the terms of Sections 1 and 2 above provided that you accompany\nit with the complete corresponding machine-readable source code, which\nmust be distributed under the terms of Sections 1 and 2 above on a\nmedium customarily used for software interchange.\n\n  If distribution of object code is made by offering access to copy\nfrom a designated place, then offering equivalent access to copy the\nsource code from the same place satisfies the requirement to\ndistribute the source code, even though third parties are not\ncompelled to copy the source along with the object code.\n\n  5. A program that contains no derivative of any portion of the\nLibrary, but is designed to work with the Library by being compiled or\nlinked with it, is called a \"work that uses the Library\".  Such a\nwork, in isolation, is not a derivative work of the Library, and\ntherefore falls outside the scope of this License.\n\n  However, linking a \"work that uses the Library\" with the Library\ncreates an executable that is a derivative of the Library (because it\ncontains portions of the Library), rather than a \"work that uses the\nlibrary\".  The executable is therefore covered by this License.\nSection 6 states terms for distribution of such executables.\n\n  When a \"work that uses the Library\" uses material from a header file\nthat is part of the Library, the object code for the work may be a\nderivative work of the Library even though the source code is not.\nWhether this is true is especially significant if the work can be\nlinked without the Library, or if the work is itself a library.  The\nthreshold for this to be true is not precisely defined by law.\n\n  If such an object file uses only numerical parameters, data\nstructure layouts and accessors, and small macros and small inline\nfunctions (ten lines or less in length), then the use of the object\nfile is unrestricted, regardless of whether it is legally a derivative\nwork.  (Executables containing this object code plus portions of the\nLibrary will still fall under Section 6.)\n\n  Otherwise, if the work is a derivative of the Library, you may\ndistribute the object code for the work under the terms of Section 6.\nAny executables containing that work also fall under Section 6,\nwhether or not they are linked directly with the Library itself.\n\f\n  6. As an exception to the Sections above, you may also compile or\nlink a \"work that uses the Library\" with the Library to produce a\nwork containing portions of the Library, and distribute that work\nunder terms of your choice, provided that the terms permit\nmodification of the work for the customer's own use and reverse\nengineering for debugging such modifications.\n\n  You must give prominent notice with each copy of the work that the\nLibrary is used in it and that the Library and its use are covered by\nthis License.  You must supply a copy of this License.  If the work\nduring execution displays copyright notices, you must include the\ncopyright notice for the Library among them, as well as a reference\ndirecting the user to the copy of this License.  Also, you must do one\nof these things:\n\n    a) Accompany the work with the complete corresponding\n    machine-readable source code for the Library including whatever\n    changes were used in the work (which must be distributed under\n    Sections 1 and 2 above); and, if the work is an executable linked\n    with the Library, with the complete machine-readable \"work that\n    uses the Library\", as object code and/or source code, so that the\n    user can modify the Library and then relink to produce a modified\n    executable containing the modified Library.  (It is understood\n    that the user who changes the contents of definitions files in the\n    Library will not necessarily be able to recompile the application\n    to use the modified definitions.)\n\n    b) Accompany the work with a written offer, valid for at\n    least three years, to give the same user the materials\n    specified in Subsection 6a, above, for a charge no more\n    than the cost of performing this distribution.\n\n    c) If distribution of the work is made by offering access to copy\n    from a designated place, offer equivalent access to copy the above\n    specified materials from the same place.\n\n    d) Verify that the user has already received a copy of these\n    materials or that you have already sent this user a copy.\n\n  For an executable, the required form of the \"work that uses the\nLibrary\" must include any data and utility programs needed for\nreproducing the executable from it.  However, as a special exception,\nthe source code distributed need not include anything that is normally\ndistributed (in either source or binary form) with the major\ncomponents (compiler, kernel, and so on) of the operating system on\nwhich the executable runs, unless that component itself accompanies\nthe executable.\n\n  It may happen that this requirement contradicts the license\nrestrictions of other proprietary libraries that do not normally\naccompany the operating system.  Such a contradiction means you cannot\nuse both them and the Library together in an executable that you\ndistribute.\n\f\n  7. You may place library facilities that are a work based on the\nLibrary side-by-side in a single library together with other library\nfacilities not covered by this License, and distribute such a combined\nlibrary, provided that the separate distribution of the work based on\nthe Library and of the other library facilities is otherwise\npermitted, and provided that you do these two things:\n\n    a) Accompany the combined library with a copy of the same work\n    based on the Library, uncombined with any other library\n    facilities.  This must be distributed under the terms of the\n    Sections above.\n\n    b) Give prominent notice with the combined library of the fact\n    that part of it is a work based on the Library, and explaining\n    where to find the accompanying uncombined form of the same work.\n\n  8. You may not copy, modify, sublicense, link with, or distribute\nthe Library except as expressly provided under this License.  Any\nattempt otherwise to copy, modify, sublicense, link with, or\ndistribute the Library is void, and will automatically terminate your\nrights under this License.  However, parties who have received copies,\nor rights, from you under this License will not have their licenses\nterminated so long as such parties remain in full compliance.\n\n  9. You are not required to accept this License, since you have not\nsigned it.  However, nothing else grants you permission to modify or\ndistribute the Library or its derivative works.  These actions are\nprohibited by law if you do not accept this License.  Therefore, by\nmodifying or distributing the Library (or any work based on the\nLibrary), you indicate your acceptance of this License to do so, and\nall its terms and conditions for copying, distributing or modifying\nthe Library or works based on it.\n\n  10. Each time you redistribute the Library (or any work based on the\nLibrary), the recipient automatically receives a license from the\noriginal licensor to copy, distribute, link with or modify the Library\nsubject to these terms and conditions.  You may not impose any further\nrestrictions on the recipients' exercise of the rights granted herein.\nYou are not responsible for enforcing compliance by third parties to\nthis License.\n\f\n  11. If, as a consequence of a court judgment or allegation of patent\ninfringement or for any other reason (not limited to patent issues),\nconditions are imposed on you (whether by court order, agreement or\notherwise) that contradict the conditions of this License, they do not\nexcuse you from the conditions of this License.  If you cannot\ndistribute so as to satisfy simultaneously your obligations under this\nLicense and any other pertinent obligations, then as a consequence you\nmay not distribute the Library at all.  For example, if a patent\nlicense would not permit royalty-free redistribution of the Library by\nall those who receive copies directly or indirectly through you, then\nthe only way you could satisfy both it and this License would be to\nrefrain entirely from distribution of the Library.\n\nIf any portion of this section is held invalid or unenforceable under any\nparticular circumstance, the balance of the section is intended to apply,\nand the section as a whole is intended to apply in other circumstances.\n\nIt is not the purpose of this section to induce you to infringe any\npatents or other property right claims or to contest validity of any\nsuch claims; this section has the sole purpose of protecting the\nintegrity of the free software distribution system which is\nimplemented by public license practices.  Many people have made\ngenerous contributions to the wide range of software distributed\nthrough that system in reliance on consistent application of that\nsystem; it is up to the author/donor to decide if he or she is willing\nto distribute software through any other system and a licensee cannot\nimpose that choice.\n\nThis section is intended to make thoroughly clear what is believed to\nbe a consequence of the rest of this License.\n\n  12. If the distribution and/or use of the Library is restricted in\ncertain countries either by patents or by copyrighted interfaces, the\noriginal copyright holder who places the Library under this License may add\nan explicit geographical distribution limitation excluding those countries,\nso that distribution is permitted only in or among countries not thus\nexcluded.  In such case, this License incorporates the limitation as if\nwritten in the body of this License.\n\n  13. The Free Software Foundation may publish revised and/or new\nversions of the Library General Public License from time to time.\nSuch new versions will be similar in spirit to the present version,\nbut may differ in detail to address new problems or concerns.\n\nEach version is given a distinguishing version number.  If the Library\nspecifies a version number of this License which applies to it and\n\"any later version\", you have the option of following the terms and\nconditions either of that version or of any later version published by\nthe Free Software Foundation.  If the Library does not specify a\nlicense version number, you may choose any version ever published by\nthe Free Software Foundation.\n\f\n  14. If you wish to incorporate parts of the Library into other free\nprograms whose distribution conditions are incompatible with these,\nwrite to the author to ask for permission.  For software which is\ncopyrighted by the Free Software Foundation, write to the Free\nSoftware Foundation; we sometimes make exceptions for this.  Our\ndecision will be guided by the two goals of preserving the free status\nof all derivatives of our free software and of promoting the sharing\nand reuse of software generally.\n\n\t\t\t    NO WARRANTY\n\n  15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO\nWARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW.\nEXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR\nOTHER PARTIES PROVIDE THE LIBRARY \"AS IS\" WITHOUT WARRANTY OF ANY\nKIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE\nIMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR\nPURPOSE.  THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE\nLIBRARY IS WITH YOU.  SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME\nTHE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.\n\n  16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN\nWRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY\nAND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU\nFOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR\nCONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE\nLIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING\nRENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A\nFAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF\nSUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH\nDAMAGES.\n\n\t\t     END OF TERMS AND CONDITIONS\n\f\n     Appendix: How to Apply These Terms to Your New Libraries\n\n  If you develop a new library, and you want it to be of the greatest\npossible use to the public, we recommend making it free software that\neveryone can redistribute and change.  You can do so by permitting\nredistribution under these terms (or, alternatively, under the terms of the\nordinary General Public License).\n\n  To apply these terms, attach the following notices to the library.  It is\nsafest to attach them to the start of each source file to most effectively\nconvey the exclusion of warranty; and each file should have at least the\n\"copyright\" line and a pointer to where the full notice is found.\n\n    <one line to give the library's name and a brief idea of what it does.>\n    Copyright (C) <year>  <name of author>\n\n    This library is free software; you can redistribute it and/or\n    modify it under the terms of the GNU Library General Public\n    License as published by the Free Software Foundation; either\n    version 2 of the License, or (at your option) any later version.\n\n    This library is distributed in the hope that it will be useful,\n    but WITHOUT ANY WARRANTY; without even the implied warranty of\n    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n    Library General Public License for more details.\n\n    You should have received a copy of the GNU Library General Public\n    License along with this library; if not, write to the Free\n    Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.\n\nAlso add information on how to contact you by electronic and paper mail.\n\nYou should also get your employer (if you work as a programmer) or your\nschool, if any, to sign a \"copyright disclaimer\" for the library, if\nnecessary.  Here is a sample; alter the names:\n\n  Yoyodyne, Inc., hereby disclaims all copyright interest in the\n  library `Frob' (a library for tweaking knobs) written by James Random Hacker.\n\n  <signature of Ty Coon>, 1 April 1990\n  Ty Coon, President of Vice\n\nThat's all there is to it!\n"
  },
  {
    "path": "third_party/phlib/mxml/config.h",
    "content": "/*\n * \"$Id: config.h 451 2014-01-04 21:50:06Z msweet $\"\n *\n * Configuration file for Mini-XML, a small XML-like file parsing library.\n *\n * Copyright 2003-2014 by Michael R Sweet.\n *\n * These coded instructions, statements, and computer programs are the\n * property of Michael R Sweet and are protected by Federal copyright\n * law.  Distribution and use rights are outlined in the file \"COPYING\"\n * which should have been included with this file.  If this file is\n * missing or damaged, see the license at:\n *\n *     http://www.msweet.org/projects.php/Mini-XML\n */\n\n/*\n * Include necessary headers...\n */\n\n#include <stdio.h>\n#include <stdlib.h>\n#include <string.h>\n#include <stdarg.h>\n#include <ctype.h>\n\n\n/*\n * Version number...\n */\n\n#define MXML_VERSION \"Mini-XML v2.10\"\n\n\n/*\n * Inline function support...\n */\n\n#define inline __inline\n\n\n/*\n * Long long support...\n */\n\n#define HAVE_LONG_LONG 1\n\n\n/*\n * Do we have the snprintf() and vsnprintf() functions?\n */\n\n#define HAVE_SNPRINTF 1\n#define HAVE_VSNPRINTF 1\n\n\n/*\n * Do we have the strXXX() functions?\n */\n\n#define HAVE_STRDUP 1\n\n\n/*\n * Do we have threading support?\n */\n\n#undef HAVE_PTHREAD_H\n\n\n/*\n * Define prototypes for string functions as needed...\n */\n\n#  ifndef HAVE_STRDUP\nextern char\t*_mxml_strdup(const char *);\n#    define strdup _mxml_strdup\n#  endif /* !HAVE_STRDUP */\n\nextern char\t*_mxml_strdupf(const char *, ...);\nextern char\t*_mxml_vstrdupf(const char *, va_list);\n\n#  ifndef HAVE_SNPRINTF\nextern int\t_mxml_snprintf(char *, size_t, const char *, ...);\n#    define snprintf _mxml_snprintf\n#  endif /* !HAVE_SNPRINTF */\n\n#  ifndef HAVE_VSNPRINTF\nextern int\t_mxml_vsnprintf(char *, size_t, const char *, va_list);\n#    define vsnprintf _mxml_vsnprintf\n#  endif /* !HAVE_VSNPRINTF */\n\n/*\n * End of \"$Id: config.h 451 2014-01-04 21:50:06Z msweet $\".\n */\n"
  },
  {
    "path": "third_party/phlib/mxml/mxml-attr.c",
    "content": "/*\n * \"$Id: mxml-attr.c 451 2014-01-04 21:50:06Z msweet $\"\n *\n * Attribute support code for Mini-XML, a small XML-like file parsing library.\n *\n * Copyright 2003-2014 by Michael R Sweet.\n *\n * These coded instructions, statements, and computer programs are the\n * property of Michael R Sweet and are protected by Federal copyright\n * law.  Distribution and use rights are outlined in the file \"COPYING\"\n * which should have been included with this file.  If this file is\n * missing or damaged, see the license at:\n *\n *     http://www.msweet.org/projects.php/Mini-XML\n */\n\n/*\n * Include necessary headers...\n */\n\n#include <phbase.h>\n#include \"config.h\"\n#include \"mxml.h\"\n\n\n/*\n * Local functions...\n */\n\nstatic int\tmxml_set_attr(mxml_node_t *node, const char *name,\n                      char *value);\n\n\n/*\n * 'mxmlElementDeleteAttr()' - Delete an attribute.\n *\n * @since Mini-XML 2.4@\n */\n\nvoid\nmxmlElementDeleteAttr(mxml_node_t *node,/* I - Element */\n                      const char  *name)/* I - Attribute name */\n{\n  int\t\ti;\t\t\t/* Looping var */\n  mxml_attr_t\t*attr;\t\t\t/* Cirrent attribute */\n\n\n#if DEBUG > 1\n  fprintf(stderr, \"mxmlElementDeleteAttr(node=%p, name=\\\"%s\\\")\\n\",\n          node, name ? name : \"(null)\");\n#endif /* DEBUG */\n\n /*\n  * Range check input...\n  */\n\n  if (!node || node->type != MXML_ELEMENT || !name)\n    return;\n\n /*\n  * Look for the attribute...\n  */\n\n  for (i = node->value.element.num_attrs, attr = node->value.element.attrs;\n       i > 0;\n       i --, attr ++)\n  {\n#if DEBUG > 1\n    printf(\"    %s=\\\"%s\\\"\\n\", attr->name, attr->value);\n#endif /* DEBUG */\n\n    if (!strcmp(attr->name, name))\n    {\n     /*\n      * Delete this attribute...\n      */\n\n      PhFree(attr->name);\n      PhFree(attr->value);\n\n      i --;\n      if (i > 0)\n        memmove(attr, attr + 1, i * sizeof(mxml_attr_t));\n\n      node->value.element.num_attrs --;\n\n      if (node->value.element.num_attrs == 0)\n        PhFree(node->value.element.attrs);\n      return;\n    }\n  }\n}\n\n\n/*\n * 'mxmlElementGetAttr()' - Get an attribute.\n *\n * This function returns NULL if the node is not an element or the\n * named attribute does not exist.\n */\n\nconst char *\t\t\t\t/* O - Attribute value or NULL */\nmxmlElementGetAttr(mxml_node_t *node,\t/* I - Element node */\n                   const char  *name)\t/* I - Name of attribute */\n{\n  int\t\ti;\t\t\t/* Looping var */\n  mxml_attr_t\t*attr;\t\t\t/* Cirrent attribute */\n\n\n#if DEBUG > 1\n  fprintf(stderr, \"mxmlElementGetAttr(node=%p, name=\\\"%s\\\")\\n\",\n          node, name ? name : \"(null)\");\n#endif /* DEBUG */\n\n /*\n  * Range check input...\n  */\n\n  if (!node || node->type != MXML_ELEMENT || !name)\n    return (NULL);\n\n /*\n  * Look for the attribute...\n  */\n\n  for (i = node->value.element.num_attrs, attr = node->value.element.attrs;\n       i > 0;\n       i --, attr ++)\n  {\n#if DEBUG > 1\n    printf(\"    %s=\\\"%s\\\"\\n\", attr->name, attr->value);\n#endif /* DEBUG */\n\n    if (!strcmp(attr->name, name))\n    {\n#if DEBUG > 1\n      printf(\"    Returning \\\"%s\\\"!\\n\", attr->value);\n#endif /* DEBUG */\n      return (attr->value);\n    }\n  }\n\n /*\n  * Didn't find attribute, so return NULL...\n  */\n\n#if DEBUG > 1\n  puts(\"    Returning NULL!\\n\");\n#endif /* DEBUG */\n\n  return (NULL);\n}\n\n\n/*\n * 'mxmlElementSetAttr()' - Set an attribute.\n *\n * If the named attribute already exists, the value of the attribute\n * is replaced by the new string value. The string value is copied\n * into the element node. This function does nothing if the node is\n * not an element.\n */\n\nvoid\nmxmlElementSetAttr(mxml_node_t *node,\t/* I - Element node */\n                   const char  *name,\t/* I - Name of attribute */\n                   const char  *value)\t/* I - Attribute value */\n{\n  char\t*valuec;\t\t\t/* Copy of value */\n\n\n#if DEBUG > 1\n  fprintf(stderr, \"mxmlElementSetAttr(node=%p, name=\\\"%s\\\", value=\\\"%s\\\")\\n\",\n          node, name ? name : \"(null)\", value ? value : \"(null)\");\n#endif /* DEBUG */\n\n /*\n  * Range check input...\n  */\n\n  if (!node || node->type != MXML_ELEMENT || !name)\n    return;\n\n  if (value)\n    valuec = PhDuplicateBytesZSafe((char *)value);\n  else\n    valuec = NULL;\n\n  if (mxml_set_attr(node, name, valuec))\n    PhFree(valuec);\n}\n\n\n/*\n * 'mxmlElementSetAttrf()' - Set an attribute with a formatted value.\n *\n * If the named attribute already exists, the value of the attribute\n * is replaced by the new formatted string. The formatted string value is\n * copied into the element node. This function does nothing if the node\n * is not an element.\n *\n * @since Mini-XML 2.3@\n */\n\nvoid\nmxmlElementSetAttrf(mxml_node_t *node,\t/* I - Element node */\n                    const char  *name,\t/* I - Name of attribute */\n                    const char  *format,/* I - Printf-style attribute value */\n            ...)\t\t/* I - Additional arguments as needed */\n{\n  va_list\tap;\t\t\t/* Argument pointer */\n  char\t\t*value;\t\t\t/* Value */\n\n\n#if DEBUG > 1\n  fprintf(stderr,\n          \"mxmlElementSetAttrf(node=%p, name=\\\"%s\\\", format=\\\"%s\\\", ...)\\n\",\n          node, name ? name : \"(null)\", format ? format : \"(null)\");\n#endif /* DEBUG */\n\n /*\n  * Range check input...\n  */\n\n  if (!node || node->type != MXML_ELEMENT || !name || !format)\n    return;\n\n /*\n  * Format the value...\n  */\n\n  va_start(ap, format);\n  value = _mxml_vstrdupf(format, ap);\n  va_end(ap);\n\n  if (!value)\n    mxml_error(\"Unable to allocate memory for attribute '%s' in element %s!\",\n               name, node->value.element.name);\n  else if (mxml_set_attr(node, name, value))\n    PhFree(value);\n}\n\n\n/*\n * 'mxml_set_attr()' - Set or add an attribute name/value pair.\n */\n\nstatic int\t\t\t\t/* O - 0 on success, -1 on failure */\nmxml_set_attr(mxml_node_t *node,\t/* I - Element node */\n              const char  *name,\t/* I - Attribute name */\n              char        *value)\t/* I - Attribute value */\n{\n  int\t\ti;\t\t\t/* Looping var */\n  mxml_attr_t\t*attr;\t\t\t/* New attribute */\n\n\n /*\n  * Look for the attribute...\n  */\n\n  for (i = node->value.element.num_attrs, attr = node->value.element.attrs;\n       i > 0;\n       i --, attr ++)\n    if (!strcmp(attr->name, name))\n    {\n     /*\n      * Free the old value as needed...\n      */\n\n      if (attr->value)\n        PhFree(attr->value);\n\n      attr->value = value;\n\n      return (0);\n    }\n\n /*\n  * Add a new attribute...\n  */\n\n  if (node->value.element.num_attrs == 0)\n    attr = PhAllocateSafe(sizeof(mxml_attr_t));\n  else\n    attr = PhReAllocateSafe(node->value.element.attrs,\n                   (node->value.element.num_attrs + 1) * sizeof(mxml_attr_t));\n\n  if (!attr)\n  {\n    mxml_error(\"Unable to allocate memory for attribute '%s' in element %s!\",\n               name, node->value.element.name);\n    return (-1);\n  }\n\n  node->value.element.attrs = attr;\n  attr += node->value.element.num_attrs;\n\n  if ((attr->name = PhDuplicateBytesZSafe((char *)name)) == NULL)\n  {\n    mxml_error(\"Unable to allocate memory for attribute '%s' in element %s!\",\n               name, node->value.element.name);\n    return (-1);\n  }\n\n  attr->value = value;\n\n  node->value.element.num_attrs ++;\n\n  return (0);\n}\n\n\n/*\n * End of \"$Id: mxml-attr.c 451 2014-01-04 21:50:06Z msweet $\".\n */\n"
  },
  {
    "path": "third_party/phlib/mxml/mxml-entity.c",
    "content": "/*\n * \"$Id: mxml-entity.c 451 2014-01-04 21:50:06Z msweet $\"\n *\n * Character entity support code for Mini-XML, a small XML-like\n * file parsing library.\n *\n * Copyright 2003-2014 by Michael R Sweet.\n *\n * These coded instructions, statements, and computer programs are the\n * property of Michael R Sweet and are protected by Federal copyright\n * law.  Distribution and use rights are outlined in the file \"COPYING\"\n * which should have been included with this file.  If this file is\n * missing or damaged, see the license at:\n *\n *     http://www.msweet.org/projects.php/Mini-XML\n */\n\n/*\n * Include necessary headers...\n */\n\n#include \"mxml-private.h\"\n\n\n/*\n * 'mxmlEntityAddCallback()' - Add a callback to convert entities to Unicode.\n */\n\nint\t\t\t\t\t/* O - 0 on success, -1 on failure */\nmxmlEntityAddCallback(\n    mxml_entity_cb_t cb)\t\t/* I - Callback function to add */\n{\n  _mxml_global_t *global = _mxml_global();\n                    /* Global data */\n\n\n  if (global->num_entity_cbs < (int)(sizeof(global->entity_cbs) / sizeof(global->entity_cbs[0])))\n  {\n    global->entity_cbs[global->num_entity_cbs] = cb;\n    global->num_entity_cbs ++;\n\n    return (0);\n  }\n  else\n  {\n    mxml_error(\"Unable to add entity callback!\");\n\n    return (-1);\n  }\n}\n\n\n/*\n * 'mxmlEntityGetName()' - Get the name that corresponds to the character value.\n *\n * If val does not need to be represented by a named entity, NULL is returned.\n */\n\nconst char *\t\t\t\t/* O - Entity name or NULL */\nmxmlEntityGetName(int val)\t\t/* I - Character value */\n{\n  switch (val)\n  {\n    case '&' :\n        return (\"amp\");\n\n    case '<' :\n        return (\"lt\");\n\n    case '>' :\n        return (\"gt\");\n\n    case '\\\"' :\n        return (\"quot\");\n\n    default :\n        return (NULL);\n  }\n}\n\n\n/*\n * 'mxmlEntityGetValue()' - Get the character corresponding to a named entity.\n *\n * The entity name can also be a numeric constant. -1 is returned if the\n * name is not known.\n */\n\nint\t\t\t\t\t/* O - Character value or -1 on error */\nmxmlEntityGetValue(const char *name)\t/* I - Entity name */\n{\n  int\t\ti;\t\t\t/* Looping var */\n  int\t\tch;\t\t\t/* Character value */\n  _mxml_global_t *global = _mxml_global();\n                    /* Global data */\n\n\n  for (i = 0; i < global->num_entity_cbs; i ++)\n    if ((ch = (global->entity_cbs[i])(name)) >= 0)\n      return (ch);\n\n  return (-1);\n}\n\n\n/*\n * 'mxmlEntityRemoveCallback()' - Remove a callback.\n */\n\nvoid\nmxmlEntityRemoveCallback(\n    mxml_entity_cb_t cb)\t\t/* I - Callback function to remove */\n{\n  int\t\ti;\t\t\t/* Looping var */\n  _mxml_global_t *global = _mxml_global();\n                    /* Global data */\n\n\n  for (i = 0; i < global->num_entity_cbs; i ++)\n    if (cb == global->entity_cbs[i])\n    {\n     /*\n      * Remove the callback...\n      */\n\n      global->num_entity_cbs --;\n\n      if (i < global->num_entity_cbs)\n        memmove(global->entity_cbs + i, global->entity_cbs + i + 1,\n            (global->num_entity_cbs - i) * sizeof(global->entity_cbs[0]));\n\n      return;\n    }\n}\n\n\n/*\n * '_mxml_entity_cb()' - Lookup standard (X)HTML entities.\n */\n\nint\t\t\t\t\t/* O - Unicode value or -1 */\n_mxml_entity_cb(const char *name)\t/* I - Entity name */\n{\n  int\tdiff,\t\t\t\t/* Difference between names */\n    current,\t\t\t/* Current entity in search */\n    first,\t\t\t\t/* First entity in search */\n    last;\t\t\t\t/* Last entity in search */\n  static const struct\n  {\n    const char\t*name;\t\t\t/* Entity name */\n    int\t\tval;\t\t\t/* Character value */\n  }\tentities[] =\n  {\n    { \"AElig\",\t\t198 },\n    { \"Aacute\",\t\t193 },\n    { \"Acirc\",\t\t194 },\n    { \"Agrave\",\t\t192 },\n    { \"Alpha\",\t\t913 },\n    { \"Aring\",\t\t197 },\n    { \"Atilde\",\t\t195 },\n    { \"Auml\",\t\t196 },\n    { \"Beta\",\t\t914 },\n    { \"Ccedil\",\t\t199 },\n    { \"Chi\",\t\t935 },\n    { \"Dagger\",\t\t8225 },\n    { \"Delta\",\t\t916 },\n    { \"Dstrok\",\t\t208 },\n    { \"ETH\",\t\t208 },\n    { \"Eacute\",\t\t201 },\n    { \"Ecirc\",\t\t202 },\n    { \"Egrave\",\t\t200 },\n    { \"Epsilon\",\t917 },\n    { \"Eta\",\t\t919 },\n    { \"Euml\",\t\t203 },\n    { \"Gamma\",\t\t915 },\n    { \"Iacute\",\t\t205 },\n    { \"Icirc\",\t\t206 },\n    { \"Igrave\",\t\t204 },\n    { \"Iota\",\t\t921 },\n    { \"Iuml\",\t\t207 },\n    { \"Kappa\",\t\t922 },\n    { \"Lambda\",\t\t923 },\n    { \"Mu\",\t\t924 },\n    { \"Ntilde\",\t\t209 },\n    { \"Nu\",\t\t925 },\n    { \"OElig\",\t\t338 },\n    { \"Oacute\",\t\t211 },\n    { \"Ocirc\",\t\t212 },\n    { \"Ograve\",\t\t210 },\n    { \"Omega\",\t\t937 },\n    { \"Omicron\",\t927 },\n    { \"Oslash\",\t\t216 },\n    { \"Otilde\",\t\t213 },\n    { \"Ouml\",\t\t214 },\n    { \"Phi\",\t\t934 },\n    { \"Pi\",\t\t928 },\n    { \"Prime\",\t\t8243 },\n    { \"Psi\",\t\t936 },\n    { \"Rho\",\t\t929 },\n    { \"Scaron\",\t\t352 },\n    { \"Sigma\",\t\t931 },\n    { \"THORN\",\t\t222 },\n    { \"Tau\",\t\t932 },\n    { \"Theta\",\t\t920 },\n    { \"Uacute\",\t\t218 },\n    { \"Ucirc\",\t\t219 },\n    { \"Ugrave\",\t\t217 },\n    { \"Upsilon\",\t933 },\n    { \"Uuml\",\t\t220 },\n    { \"Xi\",\t\t926 },\n    { \"Yacute\",\t\t221 },\n    { \"Yuml\",\t\t376 },\n    { \"Zeta\",\t\t918 },\n    { \"aacute\",\t\t225 },\n    { \"acirc\",\t\t226 },\n    { \"acute\",\t\t180 },\n    { \"aelig\",\t\t230 },\n    { \"agrave\",\t\t224 },\n    { \"alefsym\",\t8501 },\n    { \"alpha\",\t\t945 },\n    { \"amp\",\t\t'&' },\n    { \"and\",\t\t8743 },\n    { \"ang\",\t\t8736 },\n    { \"apos\",           '\\'' },\n    { \"aring\",\t\t229 },\n    { \"asymp\",\t\t8776 },\n    { \"atilde\",\t\t227 },\n    { \"auml\",\t\t228 },\n    { \"bdquo\",\t\t8222 },\n    { \"beta\",\t\t946 },\n    { \"brkbar\",\t\t166 },\n    { \"brvbar\",\t\t166 },\n    { \"bull\",\t\t8226 },\n    { \"cap\",\t\t8745 },\n    { \"ccedil\",\t\t231 },\n    { \"cedil\",\t\t184 },\n    { \"cent\",\t\t162 },\n    { \"chi\",\t\t967 },\n    { \"circ\",\t\t710 },\n    { \"clubs\",\t\t9827 },\n    { \"cong\",\t\t8773 },\n    { \"copy\",\t\t169 },\n    { \"crarr\",\t\t8629 },\n    { \"cup\",\t\t8746 },\n    { \"curren\",\t\t164 },\n    { \"dArr\",\t\t8659 },\n    { \"dagger\",\t\t8224 },\n    { \"darr\",\t\t8595 },\n    { \"deg\",\t\t176 },\n    { \"delta\",\t\t948 },\n    { \"diams\",\t\t9830 },\n    { \"die\",\t\t168 },\n    { \"divide\",\t\t247 },\n    { \"eacute\",\t\t233 },\n    { \"ecirc\",\t\t234 },\n    { \"egrave\",\t\t232 },\n    { \"empty\",\t\t8709 },\n    { \"emsp\",\t\t8195 },\n    { \"ensp\",\t\t8194 },\n    { \"epsilon\",\t949 },\n    { \"equiv\",\t\t8801 },\n    { \"eta\",\t\t951 },\n    { \"eth\",\t\t240 },\n    { \"euml\",\t\t235 },\n    { \"euro\",\t\t8364 },\n    { \"exist\",\t\t8707 },\n    { \"fnof\",\t\t402 },\n    { \"forall\",\t\t8704 },\n    { \"frac12\",\t\t189 },\n    { \"frac14\",\t\t188 },\n    { \"frac34\",\t\t190 },\n    { \"frasl\",\t\t8260 },\n    { \"gamma\",\t\t947 },\n    { \"ge\",\t\t8805 },\n    { \"gt\",\t\t'>' },\n    { \"hArr\",\t\t8660 },\n    { \"harr\",\t\t8596 },\n    { \"hearts\",\t\t9829 },\n    { \"hellip\",\t\t8230 },\n    { \"hibar\",\t\t175 },\n    { \"iacute\",\t\t237 },\n    { \"icirc\",\t\t238 },\n    { \"iexcl\",\t\t161 },\n    { \"igrave\",\t\t236 },\n    { \"image\",\t\t8465 },\n    { \"infin\",\t\t8734 },\n    { \"int\",\t\t8747 },\n    { \"iota\",\t\t953 },\n    { \"iquest\",\t\t191 },\n    { \"isin\",\t\t8712 },\n    { \"iuml\",\t\t239 },\n    { \"kappa\",\t\t954 },\n    { \"lArr\",\t\t8656 },\n    { \"lambda\",\t\t955 },\n    { \"lang\",\t\t9001 },\n    { \"laquo\",\t\t171 },\n    { \"larr\",\t\t8592 },\n    { \"lceil\",\t\t8968 },\n    { \"ldquo\",\t\t8220 },\n    { \"le\",\t\t8804 },\n    { \"lfloor\",\t\t8970 },\n    { \"lowast\",\t\t8727 },\n    { \"loz\",\t\t9674 },\n    { \"lrm\",\t\t8206 },\n    { \"lsaquo\",\t\t8249 },\n    { \"lsquo\",\t\t8216 },\n    { \"lt\",\t\t'<' },\n    { \"macr\",\t\t175 },\n    { \"mdash\",\t\t8212 },\n    { \"micro\",\t\t181 },\n    { \"middot\",\t\t183 },\n    { \"minus\",\t\t8722 },\n    { \"mu\",\t\t956 },\n    { \"nabla\",\t\t8711 },\n    { \"nbsp\",\t\t160 },\n    { \"ndash\",\t\t8211 },\n    { \"ne\",\t\t8800 },\n    { \"ni\",\t\t8715 },\n    { \"not\",\t\t172 },\n    { \"notin\",\t\t8713 },\n    { \"nsub\",\t\t8836 },\n    { \"ntilde\",\t\t241 },\n    { \"nu\",\t\t957 },\n    { \"oacute\",\t\t243 },\n    { \"ocirc\",\t\t244 },\n    { \"oelig\",\t\t339 },\n    { \"ograve\",\t\t242 },\n    { \"oline\",\t\t8254 },\n    { \"omega\",\t\t969 },\n    { \"omicron\",\t959 },\n    { \"oplus\",\t\t8853 },\n    { \"or\",\t\t8744 },\n    { \"ordf\",\t\t170 },\n    { \"ordm\",\t\t186 },\n    { \"oslash\",\t\t248 },\n    { \"otilde\",\t\t245 },\n    { \"otimes\",\t\t8855 },\n    { \"ouml\",\t\t246 },\n    { \"para\",\t\t182 },\n    { \"part\",\t\t8706 },\n    { \"permil\",\t\t8240 },\n    { \"perp\",\t\t8869 },\n    { \"phi\",\t\t966 },\n    { \"pi\",\t\t960 },\n    { \"piv\",\t\t982 },\n    { \"plusmn\",\t\t177 },\n    { \"pound\",\t\t163 },\n    { \"prime\",\t\t8242 },\n    { \"prod\",\t\t8719 },\n    { \"prop\",\t\t8733 },\n    { \"psi\",\t\t968 },\n    { \"quot\",\t\t'\\\"' },\n    { \"rArr\",\t\t8658 },\n    { \"radic\",\t\t8730 },\n    { \"rang\",\t\t9002 },\n    { \"raquo\",\t\t187 },\n    { \"rarr\",\t\t8594 },\n    { \"rceil\",\t\t8969 },\n    { \"rdquo\",\t\t8221 },\n    { \"real\",\t\t8476 },\n    { \"reg\",\t\t174 },\n    { \"rfloor\",\t\t8971 },\n    { \"rho\",\t\t961 },\n    { \"rlm\",\t\t8207 },\n    { \"rsaquo\",\t\t8250 },\n    { \"rsquo\",\t\t8217 },\n    { \"sbquo\",\t\t8218 },\n    { \"scaron\",\t\t353 },\n    { \"sdot\",\t\t8901 },\n    { \"sect\",\t\t167 },\n    { \"shy\",\t\t173 },\n    { \"sigma\",\t\t963 },\n    { \"sigmaf\",\t\t962 },\n    { \"sim\",\t\t8764 },\n    { \"spades\",\t\t9824 },\n    { \"sub\",\t\t8834 },\n    { \"sube\",\t\t8838 },\n    { \"sum\",\t\t8721 },\n    { \"sup\",\t\t8835 },\n    { \"sup1\",\t\t185 },\n    { \"sup2\",\t\t178 },\n    { \"sup3\",\t\t179 },\n    { \"supe\",\t\t8839 },\n    { \"szlig\",\t\t223 },\n    { \"tau\",\t\t964 },\n    { \"there4\",\t\t8756 },\n    { \"theta\",\t\t952 },\n    { \"thetasym\",\t977 },\n    { \"thinsp\",\t\t8201 },\n    { \"thorn\",\t\t254 },\n    { \"tilde\",\t\t732 },\n    { \"times\",\t\t215 },\n    { \"trade\",\t\t8482 },\n    { \"uArr\",\t\t8657 },\n    { \"uacute\",\t\t250 },\n    { \"uarr\",\t\t8593 },\n    { \"ucirc\",\t\t251 },\n    { \"ugrave\",\t\t249 },\n    { \"uml\",\t\t168 },\n    { \"upsih\",\t\t978 },\n    { \"upsilon\",\t965 },\n    { \"uuml\",\t\t252 },\n    { \"weierp\",\t\t8472 },\n    { \"xi\",\t\t958 },\n    { \"yacute\",\t\t253 },\n    { \"yen\",\t\t165 },\n    { \"yuml\",\t\t255 },\n    { \"zeta\",\t\t950 },\n    { \"zwj\",\t\t8205 },\n    { \"zwnj\",\t\t8204 }\n  };\n\n\n /*\n  * Do a binary search for the named entity...\n  */\n\n  first = 0;\n  last  = (int)(sizeof(entities) / sizeof(entities[0]) - 1);\n\n  while ((last - first) > 1)\n  {\n    current = (first + last) / 2;\n\n    if ((diff = strcmp(name, entities[current].name)) == 0)\n      return (entities[current].val);\n    else if (diff < 0)\n      last = current;\n    else\n      first = current;\n  }\n\n /*\n  * If we get here, there is a small chance that there is still\n  * a match; check first and last...\n  */\n\n  if (!strcmp(name, entities[first].name))\n    return (entities[first].val);\n  else if (!strcmp(name, entities[last].name))\n    return (entities[last].val);\n  else\n    return (-1);\n}\n\n\n/*\n * End of \"$Id: mxml-entity.c 451 2014-01-04 21:50:06Z msweet $\".\n */\n"
  },
  {
    "path": "third_party/phlib/mxml/mxml-file.c",
    "content": "/*\n * \"$Id: mxml-file.c 467 2016-06-13 00:51:16Z msweet $\"\n *\n * File loading code for Mini-XML, a small XML-like file parsing library.\n *\n * Copyright 2003-2016 by Michael R Sweet.\n *\n * These coded instructions, statements, and computer programs are the\n * property of Michael R Sweet and are protected by Federal copyright\n * law.  Distribution and use rights are outlined in the file \"COPYING\"\n * which should have been included with this file.  If this file is\n * missing or damaged, see the license at:\n *\n *     http://www.msweet.org/projects.php/Mini-XML\n */\n\n/*\n * Include necessary headers...\n */\n\n#include <phbase.h>\n#ifndef WIN32\n#  include <unistd.h>\n#endif /* !WIN32 */\n#include \"mxml-private.h\"\n\n\n/*\n * Character encoding...\n */\n\n#define ENCODE_UTF8\t0\t\t/* UTF-8 */\n#define ENCODE_UTF16BE\t1\t\t/* UTF-16 Big-Endian */\n#define ENCODE_UTF16LE\t2\t\t/* UTF-16 Little-Endian */\n\n\n/*\n * Macro to test for a bad XML character...\n */\n\n#define mxml_bad_char(ch) ((ch) < ' ' && (ch) != '\\n' && (ch) != '\\r' && (ch) != '\\t')\n\n\n/*\n * Types and structures...\n */\n\ntypedef int (*_mxml_getc_cb_t)(void *, int *);\ntypedef int (*_mxml_putc_cb_t)(int, void *);\n\ntypedef struct _mxml_fdbuf_s\t\t/**** File descriptor buffer ****/\n{\n  HANDLE\t\tfd;\t\t\t/* File descriptor */\n  unsigned char\t*current,\t\t/* Current position in buffer */\n        *end,\t\t\t/* End of buffer */\n        buffer[8192];\t\t/* Character buffer */\n} _mxml_fdbuf_t;\n\n\n/*\n * Local functions...\n */\n\nstatic int\t\tmxml_add_char(int ch, char **ptr, char **buffer,\n                          int *bufsize);\nstatic int\t\tmxml_fd_getc(void *p, int *encoding);\nstatic int\t\tmxml_fd_putc(int ch, void *p);\nstatic int\t\tmxml_fd_read(_mxml_fdbuf_t *buf);\nstatic int\t\tmxml_fd_write(_mxml_fdbuf_t *buf);\nstatic int\t\tmxml_file_getc(void *p, int *encoding);\nstatic int\t\tmxml_file_putc(int ch, void *p);\nstatic int\t\tmxml_get_entity(mxml_node_t *parent, void *p,\n                            int *encoding,\n                    _mxml_getc_cb_t getc_cb);\nstatic inline int\tmxml_isspace(int ch)\n            {\n              return (ch == ' ' || ch == '\\t' || ch == '\\r' ||\n                      ch == '\\n');\n            }\nstatic mxml_node_t\t*mxml_load_data(mxml_node_t *top, void *p,\n                            mxml_load_cb_t cb,\n                            _mxml_getc_cb_t getc_cb,\n                                        mxml_sax_cb_t sax_cb, void *sax_data);\nstatic int\t\tmxml_parse_element(mxml_node_t *node, void *p,\n                               int *encoding,\n                       _mxml_getc_cb_t getc_cb);\nstatic int\t\tmxml_string_getc(void *p, int *encoding);\nstatic int\t\tmxml_string_putc(int ch, void *p);\nstatic int\t\tmxml_write_name(const char *s, void *p,\n                    _mxml_putc_cb_t putc_cb);\nstatic int\t\tmxml_write_node(mxml_node_t *node, void *p,\n                            mxml_save_cb_t cb, int col,\n                    _mxml_putc_cb_t putc_cb,\n                    _mxml_global_t *global);\nstatic int\t\tmxml_write_string(const char *s, void *p,\n                      _mxml_putc_cb_t putc_cb);\nstatic int\t\tmxml_write_ws(mxml_node_t *node, void *p,\n                          mxml_save_cb_t cb, int ws,\n                      int col, _mxml_putc_cb_t putc_cb);\n\n\n/*\n * 'mxmlLoadFd()' - Load a file descriptor into an XML node tree.\n *\n * The nodes in the specified file are added to the specified top node.\n * If no top node is provided, the XML file MUST be well-formed with a\n * single parent node like <?xml> for the entire file. The callback\n * function returns the value type that should be used for child nodes.\n * If MXML_NO_CALLBACK is specified then all child nodes will be either\n * MXML_ELEMENT or MXML_TEXT nodes.\n *\n * The constants MXML_INTEGER_CALLBACK, MXML_OPAQUE_CALLBACK,\n * MXML_REAL_CALLBACK, and MXML_TEXT_CALLBACK are defined for loading\n * child nodes of the specified type.\n */\n\nmxml_node_t *\t\t\t\t/* O - First node or NULL if the file could not be read. */\nmxmlLoadFd(mxml_node_t    *top,\t\t/* I - Top node */\n           HANDLE         fd,\t\t/* I - File descriptor to read from */\n           mxml_load_cb_t cb)\t\t/* I - Callback function or MXML_NO_CALLBACK */\n{\n  _mxml_fdbuf_t\tbuf;\t\t\t/* File descriptor buffer */\n\n\n /*\n  * Initialize the file descriptor buffer...\n  */\n\n  buf.fd      = fd;\n  buf.current = buf.buffer;\n  buf.end     = buf.buffer;\n\n /*\n  * Read the XML data...\n  */\n\n  return (mxml_load_data(top, &buf, cb, mxml_fd_getc, MXML_NO_CALLBACK, NULL));\n}\n\n\n/*\n * 'mxmlLoadFile()' - Load a file into an XML node tree.\n *\n * The nodes in the specified file are added to the specified top node.\n * If no top node is provided, the XML file MUST be well-formed with a\n * single parent node like <?xml> for the entire file. The callback\n * function returns the value type that should be used for child nodes.\n * If MXML_NO_CALLBACK is specified then all child nodes will be either\n * MXML_ELEMENT or MXML_TEXT nodes.\n *\n * The constants MXML_INTEGER_CALLBACK, MXML_OPAQUE_CALLBACK,\n * MXML_REAL_CALLBACK, and MXML_TEXT_CALLBACK are defined for loading\n * child nodes of the specified type.\n */\n\nmxml_node_t *\t\t\t\t/* O - First node or NULL if the file could not be read. */\nmxmlLoadFile(mxml_node_t    *top,\t/* I - Top node */\n             FILE           *fp,\t/* I - File to read from */\n             mxml_load_cb_t cb)\t\t/* I - Callback function or MXML_NO_CALLBACK */\n{\n /*\n  * Read the XML data...\n  */\n\n  return (mxml_load_data(top, fp, cb, mxml_file_getc, MXML_NO_CALLBACK, NULL));\n}\n\n\n/*\n * 'mxmlLoadString()' - Load a string into an XML node tree.\n *\n * The nodes in the specified string are added to the specified top node.\n * If no top node is provided, the XML string MUST be well-formed with a\n * single parent node like <?xml> for the entire string. The callback\n * function returns the value type that should be used for child nodes.\n * If MXML_NO_CALLBACK is specified then all child nodes will be either\n * MXML_ELEMENT or MXML_TEXT nodes.\n *\n * The constants MXML_INTEGER_CALLBACK, MXML_OPAQUE_CALLBACK,\n * MXML_REAL_CALLBACK, and MXML_TEXT_CALLBACK are defined for loading\n * child nodes of the specified type.\n */\n\nmxml_node_t *\t\t\t\t/* O - First node or NULL if the string has errors. */\nmxmlLoadString(mxml_node_t    *top,\t/* I - Top node */\n               const char     *s,\t/* I - String to load */\n               mxml_load_cb_t cb)\t/* I - Callback function or MXML_NO_CALLBACK */\n{\n /*\n  * Read the XML data...\n  */\n\n  return (mxml_load_data(top, (void *)&s, cb, mxml_string_getc, MXML_NO_CALLBACK,\n                         NULL));\n}\n\n\n/*\n * 'mxmlSaveAllocString()' - Save an XML tree to an allocated string.\n *\n * This function returns a pointer to a string containing the textual\n * representation of the XML node tree.  The string should be freed\n * using the free() function when you are done with it.  NULL is returned\n * if the node would produce an empty string or if the string cannot be\n * allocated.\n *\n * The callback argument specifies a function that returns a whitespace\n * string or NULL before and after each element. If MXML_NO_CALLBACK\n * is specified, whitespace will only be added before MXML_TEXT nodes\n * with leading whitespace and before attribute names inside opening\n * element tags.\n */\n\nchar *\t\t\t\t\t/* O - Allocated string or NULL */\nmxmlSaveAllocString(\n    mxml_node_t    *node,\t\t/* I - Node to write */\n    mxml_save_cb_t cb)\t\t\t/* I - Whitespace callback or MXML_NO_CALLBACK */\n{\n  int\tbytes;\t\t\t\t/* Required bytes */\n  char\tbuffer[8192];\t\t\t/* Temporary buffer */\n  char\t*s;\t\t\t\t/* Allocated string */\n\n\n /*\n  * Write the node to the temporary buffer...\n  */\n\n  bytes = mxmlSaveString(node, buffer, sizeof(buffer), cb);\n\n  if (bytes <= 0)\n    return (NULL);\n\n  if (bytes < (int)(sizeof(buffer) - 1))\n  {\n   /*\n    * Node fit inside the buffer, so just duplicate that string and\n    * return...\n    */\n\n    return (PhDuplicateBytesZSafe(buffer));\n  }\n\n /*\n  * Allocate a buffer of the required size and save the node to the\n  * new buffer...\n  */\n\n  if ((s = PhAllocateSafe(bytes + 1)) == NULL)\n    return (NULL);\n\n  mxmlSaveString(node, s, bytes + 1, cb);\n\n /*\n  * Return the allocated string...\n  */\n\n  return (s);\n}\n\n\n/*\n * 'mxmlSaveFd()' - Save an XML tree to a file descriptor.\n *\n * The callback argument specifies a function that returns a whitespace\n * string or NULL before and after each element. If MXML_NO_CALLBACK\n * is specified, whitespace will only be added before MXML_TEXT nodes\n * with leading whitespace and before attribute names inside opening\n * element tags.\n */\n\nint\t\t\t\t\t/* O - 0 on success, -1 on error. */\nmxmlSaveFd(mxml_node_t    *node,\t/* I - Node to write */\n           HANDLE         fd,\t\t/* I - File descriptor to write to */\n       mxml_save_cb_t cb)\t\t/* I - Whitespace callback or MXML_NO_CALLBACK */\n{\n  int\t\tcol;\t\t\t/* Final column */\n  _mxml_fdbuf_t\tbuf;\t\t\t/* File descriptor buffer */\n  _mxml_global_t *global = _mxml_global();\n                    /* Global data */\n\n\n /*\n  * Initialize the file descriptor buffer...\n  */\n\n  buf.fd      = fd;\n  buf.current = buf.buffer;\n  buf.end     = buf.buffer + sizeof(buf.buffer);\n\n /*\n  * Write the node...\n  */\n\n  if ((col = mxml_write_node(node, &buf, cb, 0, mxml_fd_putc, global)) < 0)\n    return (-1);\n\n  if (col > 0)\n    if (mxml_fd_putc('\\n', &buf) < 0)\n      return (-1);\n\n /*\n  * Flush and return...\n  */\n\n  return (mxml_fd_write(&buf));\n}\n\n\n/*\n * 'mxmlSaveFile()' - Save an XML tree to a file.\n *\n * The callback argument specifies a function that returns a whitespace\n * string or NULL before and after each element. If MXML_NO_CALLBACK\n * is specified, whitespace will only be added before MXML_TEXT nodes\n * with leading whitespace and before attribute names inside opening\n * element tags.\n */\n\nint\t\t\t\t\t/* O - 0 on success, -1 on error. */\nmxmlSaveFile(mxml_node_t    *node,\t/* I - Node to write */\n             FILE           *fp,\t/* I - File to write to */\n         mxml_save_cb_t cb)\t\t/* I - Whitespace callback or MXML_NO_CALLBACK */\n{\n  int\tcol;\t\t\t\t/* Final column */\n  _mxml_global_t *global = _mxml_global();\n                    /* Global data */\n\n\n /*\n  * Write the node...\n  */\n\n  if ((col = mxml_write_node(node, fp, cb, 0, mxml_file_putc, global)) < 0)\n    return (-1);\n\n  if (col > 0)\n    if (putc('\\n', fp) < 0)\n      return (-1);\n\n /*\n  * Return 0 (success)...\n  */\n\n  return (0);\n}\n\n\n/*\n * 'mxmlSaveString()' - Save an XML node tree to a string.\n *\n * This function returns the total number of bytes that would be\n * required for the string but only copies (bufsize - 1) characters\n * into the specified buffer.\n *\n * The callback argument specifies a function that returns a whitespace\n * string or NULL before and after each element. If MXML_NO_CALLBACK\n * is specified, whitespace will only be added before MXML_TEXT nodes\n * with leading whitespace and before attribute names inside opening\n * element tags.\n */\n\nint\t\t\t\t\t/* O - Size of string */\nmxmlSaveString(mxml_node_t    *node,\t/* I - Node to write */\n               char           *buffer,\t/* I - String buffer */\n               int            bufsize,\t/* I - Size of string buffer */\n               mxml_save_cb_t cb)\t/* I - Whitespace callback or MXML_NO_CALLBACK */\n{\n  int\tcol;\t\t\t\t/* Final column */\n  char\t*ptr[2];\t\t\t/* Pointers for putc_cb */\n  _mxml_global_t *global = _mxml_global();\n                    /* Global data */\n\n\n /*\n  * Write the node...\n  */\n\n  ptr[0] = buffer;\n  ptr[1] = buffer + bufsize;\n\n  if ((col = mxml_write_node(node, ptr, cb, 0, mxml_string_putc, global)) < 0)\n    return (-1);\n\n  if (col > 0)\n    mxml_string_putc('\\n', ptr);\n\n /*\n  * Nul-terminate the buffer...\n  */\n\n  if (ptr[0] >= ptr[1])\n    buffer[bufsize - 1] = '\\0';\n  else\n    ptr[0][0] = '\\0';\n\n /*\n  * Return the number of characters...\n  */\n\n  return (int)(ptr[0] - buffer);\n}\n\n\n/*\n * 'mxmlSAXLoadFd()' - Load a file descriptor into an XML node tree\n *                     using a SAX callback.\n *\n * The nodes in the specified file are added to the specified top node.\n * If no top node is provided, the XML file MUST be well-formed with a\n * single parent node like <?xml> for the entire file. The callback\n * function returns the value type that should be used for child nodes.\n * If MXML_NO_CALLBACK is specified then all child nodes will be either\n * MXML_ELEMENT or MXML_TEXT nodes.\n *\n * The constants MXML_INTEGER_CALLBACK, MXML_OPAQUE_CALLBACK,\n * MXML_REAL_CALLBACK, and MXML_TEXT_CALLBACK are defined for loading\n * child nodes of the specified type.\n *\n * The SAX callback must call mxmlRetain() for any nodes that need to\n * be kept for later use. Otherwise, nodes are deleted when the parent\n * node is closed or after each data, comment, CDATA, or directive node.\n *\n * @since Mini-XML 2.3@\n */\n\nmxml_node_t *\t\t\t\t/* O - First node or NULL if the file could not be read. */\nmxmlSAXLoadFd(mxml_node_t    *top,\t/* I - Top node */\n              HANDLE         fd,\t/* I - File descriptor to read from */\n              mxml_load_cb_t cb,\t/* I - Callback function or MXML_NO_CALLBACK */\n              mxml_sax_cb_t  sax_cb,\t/* I - SAX callback or MXML_NO_CALLBACK */\n              void           *sax_data)\t/* I - SAX user data */\n{\n  _mxml_fdbuf_t\tbuf;\t\t\t/* File descriptor buffer */\n\n\n /*\n  * Initialize the file descriptor buffer...\n  */\n\n  buf.fd      = fd;\n  buf.current = buf.buffer;\n  buf.end     = buf.buffer;\n\n /*\n  * Read the XML data...\n  */\n\n  return (mxml_load_data(top, &buf, cb, mxml_fd_getc, sax_cb, sax_data));\n}\n\n\n/*\n * 'mxmlSAXLoadFile()' - Load a file into an XML node tree\n *                       using a SAX callback.\n *\n * The nodes in the specified file are added to the specified top node.\n * If no top node is provided, the XML file MUST be well-formed with a\n * single parent node like <?xml> for the entire file. The callback\n * function returns the value type that should be used for child nodes.\n * If MXML_NO_CALLBACK is specified then all child nodes will be either\n * MXML_ELEMENT or MXML_TEXT nodes.\n *\n * The constants MXML_INTEGER_CALLBACK, MXML_OPAQUE_CALLBACK,\n * MXML_REAL_CALLBACK, and MXML_TEXT_CALLBACK are defined for loading\n * child nodes of the specified type.\n *\n * The SAX callback must call mxmlRetain() for any nodes that need to\n * be kept for later use. Otherwise, nodes are deleted when the parent\n * node is closed or after each data, comment, CDATA, or directive node.\n *\n * @since Mini-XML 2.3@\n */\n\nmxml_node_t *\t\t\t\t/* O - First node or NULL if the file could not be read. */\nmxmlSAXLoadFile(\n    mxml_node_t    *top,\t\t/* I - Top node */\n    FILE           *fp,\t\t\t/* I - File to read from */\n    mxml_load_cb_t cb,\t\t\t/* I - Callback function or MXML_NO_CALLBACK */\n    mxml_sax_cb_t  sax_cb,\t\t/* I - SAX callback or MXML_NO_CALLBACK */\n    void           *sax_data)\t\t/* I - SAX user data */\n{\n /*\n  * Read the XML data...\n  */\n\n  return (mxml_load_data(top, fp, cb, mxml_file_getc, sax_cb, sax_data));\n}\n\n\n/*\n * 'mxmlSAXLoadString()' - Load a string into an XML node tree\n *                         using a SAX callback.\n *\n * The nodes in the specified string are added to the specified top node.\n * If no top node is provided, the XML string MUST be well-formed with a\n * single parent node like <?xml> for the entire string. The callback\n * function returns the value type that should be used for child nodes.\n * If MXML_NO_CALLBACK is specified then all child nodes will be either\n * MXML_ELEMENT or MXML_TEXT nodes.\n *\n * The constants MXML_INTEGER_CALLBACK, MXML_OPAQUE_CALLBACK,\n * MXML_REAL_CALLBACK, and MXML_TEXT_CALLBACK are defined for loading\n * child nodes of the specified type.\n *\n * The SAX callback must call mxmlRetain() for any nodes that need to\n * be kept for later use. Otherwise, nodes are deleted when the parent\n * node is closed or after each data, comment, CDATA, or directive node.\n *\n * @since Mini-XML 2.3@\n */\n\nmxml_node_t *\t\t\t\t/* O - First node or NULL if the string has errors. */\nmxmlSAXLoadString(\n    mxml_node_t    *top,\t\t/* I - Top node */\n    const char     *s,\t\t\t/* I - String to load */\n    mxml_load_cb_t cb,\t\t\t/* I - Callback function or MXML_NO_CALLBACK */\n    mxml_sax_cb_t  sax_cb,\t\t/* I - SAX callback or MXML_NO_CALLBACK */\n    void           *sax_data)\t\t/* I - SAX user data */\n{\n /*\n  * Read the XML data...\n  */\n\n  return (mxml_load_data(top, (void *)&s, cb, mxml_string_getc, sax_cb, sax_data));\n}\n\n\n/*\n * 'mxmlSetCustomHandlers()' - Set the handling functions for custom data.\n *\n * The load function accepts a node pointer and a data string and must\n * return 0 on success and non-zero on error.\n *\n * The save function accepts a node pointer and must return a malloc'd\n * string on success and NULL on error.\n *\n */\n\nvoid\nmxmlSetCustomHandlers(\n    mxml_custom_load_cb_t load,\t\t/* I - Load function */\n    mxml_custom_save_cb_t save)\t\t/* I - Save function */\n{\n  _mxml_global_t *global = _mxml_global();\n                    /* Global data */\n\n\n  global->custom_load_cb = load;\n  global->custom_save_cb = save;\n}\n\n\n/*\n * 'mxmlSetErrorCallback()' - Set the error message callback.\n */\n\nvoid\nmxmlSetErrorCallback(mxml_error_cb_t cb)/* I - Error callback function */\n{\n  _mxml_global_t *global = _mxml_global();\n                    /* Global data */\n\n\n  global->error_cb = cb;\n}\n\n\n/*\n * 'mxmlSetWrapMargin()' - Set the wrap margin when saving XML data.\n *\n * Wrapping is disabled when \"column\" is 0.\n *\n * @since Mini-XML 2.3@\n */\n\nvoid\nmxmlSetWrapMargin(int column)\t\t/* I - Column for wrapping, 0 to disable wrapping */\n{\n  _mxml_global_t *global = _mxml_global();\n                    /* Global data */\n\n\n  global->wrap = column;\n}\n\n\n/*\n * 'mxml_add_char()' - Add a character to a buffer, expanding as needed.\n */\n\nstatic int\t\t\t\t/* O  - 0 on success, -1 on error */\nmxml_add_char(int  ch,\t\t\t/* I  - Character to add */\n              char **bufptr,\t\t/* IO - Current position in buffer */\n          char **buffer,\t\t/* IO - Current buffer */\n          int  *bufsize)\t\t/* IO - Current buffer size */\n{\n  char\t*newbuffer;\t\t\t/* New buffer value */\n\n\n  if (*bufptr >= (*buffer + *bufsize - 4))\n  {\n   /*\n    * Increase the size of the buffer...\n    */\n\n    if (*bufsize < 1024)\n      (*bufsize) *= 2;\n    else\n      (*bufsize) += 1024;\n\n    if ((newbuffer = PhReAllocateSafe(*buffer, *bufsize)) == NULL)\n    {\n      PhFree(*buffer);\n\n      mxml_error(\"Unable to expand string buffer to %d bytes!\", *bufsize);\n\n      return (-1);\n    }\n\n    *bufptr = newbuffer + (*bufptr - *buffer);\n    *buffer = newbuffer;\n  }\n\n  if (ch < 0x80)\n  {\n   /*\n    * Single byte ASCII...\n    */\n\n    *(*bufptr)++ = ch;\n  }\n  else if (ch < 0x800)\n  {\n   /*\n    * Two-byte UTF-8...\n    */\n\n    *(*bufptr)++ = 0xc0 | (ch >> 6);\n    *(*bufptr)++ = 0x80 | (ch & 0x3f);\n  }\n  else if (ch < 0x10000)\n  {\n   /*\n    * Three-byte UTF-8...\n    */\n\n    *(*bufptr)++ = 0xe0 | (ch >> 12);\n    *(*bufptr)++ = 0x80 | ((ch >> 6) & 0x3f);\n    *(*bufptr)++ = 0x80 | (ch & 0x3f);\n  }\n  else\n  {\n   /*\n    * Four-byte UTF-8...\n    */\n\n    *(*bufptr)++ = 0xf0 | (ch >> 18);\n    *(*bufptr)++ = 0x80 | ((ch >> 12) & 0x3f);\n    *(*bufptr)++ = 0x80 | ((ch >> 6) & 0x3f);\n    *(*bufptr)++ = 0x80 | (ch & 0x3f);\n  }\n\n  return (0);\n}\n\n\n/*\n * 'mxml_fd_getc()' - Read a character from a file descriptor.\n */\n\nstatic int\t\t\t\t/* O  - Character or EOF */\nmxml_fd_getc(void *p,\t\t\t/* I  - File descriptor buffer */\n             int  *encoding)\t\t/* IO - Encoding */\n{\n  _mxml_fdbuf_t\t*buf;\t\t\t/* File descriptor buffer */\n  int\t\tch,\t\t\t/* Current character */\n        temp;\t\t\t/* Temporary character */\n\n\n /*\n  * Grab the next character in the buffer...\n  */\n\n  buf = (_mxml_fdbuf_t *)p;\n\n  if (buf->current >= buf->end)\n    if (mxml_fd_read(buf) < 0)\n      return (EOF);\n\n  ch = *(buf->current)++;\n\n  switch (*encoding)\n  {\n    case ENCODE_UTF8 :\n       /*\n    * Got a UTF-8 character; convert UTF-8 to Unicode and return...\n    */\n\n    if (!(ch & 0x80))\n    {\n#if DEBUG > 1\n          printf(\"mxml_fd_getc: %c (0x%04x)\\n\", ch < ' ' ? '.' : ch, ch);\n#endif /* DEBUG > 1 */\n\n      if (mxml_bad_char(ch))\n      {\n        mxml_error(\"Bad control character 0x%02x not allowed by XML standard!\",\n                   ch);\n        return (EOF);\n      }\n\n      return (ch);\n        }\n    else if (ch == 0xfe)\n    {\n     /*\n      * UTF-16 big-endian BOM?\n      */\n\n      if (buf->current >= buf->end)\n        if (mxml_fd_read(buf) < 0)\n          return (EOF);\n\n      ch = *(buf->current)++;\n\n      if (ch != 0xff)\n        return (EOF);\n\n      *encoding = ENCODE_UTF16BE;\n\n      return (mxml_fd_getc(p, encoding));\n    }\n    else if (ch == 0xff)\n    {\n     /*\n      * UTF-16 little-endian BOM?\n      */\n\n      if (buf->current >= buf->end)\n        if (mxml_fd_read(buf) < 0)\n          return (EOF);\n\n      ch = *(buf->current)++;\n\n      if (ch != 0xfe)\n        return (EOF);\n\n      *encoding = ENCODE_UTF16LE;\n\n      return (mxml_fd_getc(p, encoding));\n    }\n    else if ((ch & 0xe0) == 0xc0)\n    {\n     /*\n      * Two-byte value...\n      */\n\n      if (buf->current >= buf->end)\n        if (mxml_fd_read(buf) < 0)\n          return (EOF);\n\n      temp = *(buf->current)++;\n\n      if ((temp & 0xc0) != 0x80)\n        return (EOF);\n\n      ch = ((ch & 0x1f) << 6) | (temp & 0x3f);\n\n      if (ch < 0x80)\n      {\n        mxml_error(\"Invalid UTF-8 sequence for character 0x%04x!\", ch);\n        return (EOF);\n      }\n    }\n    else if ((ch & 0xf0) == 0xe0)\n    {\n     /*\n      * Three-byte value...\n      */\n\n      if (buf->current >= buf->end)\n        if (mxml_fd_read(buf) < 0)\n          return (EOF);\n\n      temp = *(buf->current)++;\n\n      if ((temp & 0xc0) != 0x80)\n        return (EOF);\n\n      ch = ((ch & 0x0f) << 6) | (temp & 0x3f);\n\n      if (buf->current >= buf->end)\n        if (mxml_fd_read(buf) < 0)\n          return (EOF);\n\n      temp = *(buf->current)++;\n\n      if ((temp & 0xc0) != 0x80)\n        return (EOF);\n\n      ch = (ch << 6) | (temp & 0x3f);\n\n      if (ch < 0x800)\n      {\n        mxml_error(\"Invalid UTF-8 sequence for character 0x%04x!\", ch);\n        return (EOF);\n      }\n\n         /*\n      * Ignore (strip) Byte Order Mark (BOM)...\n      */\n\n      if (ch == 0xfeff)\n        return (mxml_fd_getc(p, encoding));\n    }\n    else if ((ch & 0xf8) == 0xf0)\n    {\n     /*\n      * Four-byte value...\n      */\n\n      if (buf->current >= buf->end)\n        if (mxml_fd_read(buf) < 0)\n          return (EOF);\n\n      temp = *(buf->current)++;\n\n      if ((temp & 0xc0) != 0x80)\n        return (EOF);\n\n      ch = ((ch & 0x07) << 6) | (temp & 0x3f);\n\n      if (buf->current >= buf->end)\n        if (mxml_fd_read(buf) < 0)\n          return (EOF);\n\n      temp = *(buf->current)++;\n\n      if ((temp & 0xc0) != 0x80)\n        return (EOF);\n\n      ch = (ch << 6) | (temp & 0x3f);\n\n      if (buf->current >= buf->end)\n        if (mxml_fd_read(buf) < 0)\n          return (EOF);\n\n      temp = *(buf->current)++;\n\n      if ((temp & 0xc0) != 0x80)\n        return (EOF);\n\n      ch = (ch << 6) | (temp & 0x3f);\n\n      if (ch < 0x10000)\n      {\n        mxml_error(\"Invalid UTF-8 sequence for character 0x%04x!\", ch);\n        return (EOF);\n      }\n    }\n    else\n      return (EOF);\n    break;\n\n    case ENCODE_UTF16BE :\n       /*\n        * Read UTF-16 big-endian char...\n    */\n\n    if (buf->current >= buf->end)\n      if (mxml_fd_read(buf) < 0)\n        return (EOF);\n\n    temp = *(buf->current)++;\n\n    ch = (ch << 8) | temp;\n\n    if (mxml_bad_char(ch))\n    {\n      mxml_error(\"Bad control character 0x%02x not allowed by XML standard!\",\n                 ch);\n      return (EOF);\n    }\n        else if (ch >= 0xd800 && ch <= 0xdbff)\n    {\n     /*\n      * Multi-word UTF-16 char...\n      */\n\n          int lch;\n\n      if (buf->current >= buf->end)\n        if (mxml_fd_read(buf) < 0)\n          return (EOF);\n\n      lch = *(buf->current)++;\n\n      if (buf->current >= buf->end)\n        if (mxml_fd_read(buf) < 0)\n          return (EOF);\n\n      temp = *(buf->current)++;\n\n      lch = (lch << 8) | temp;\n\n          if (lch < 0xdc00 || lch >= 0xdfff)\n        return (EOF);\n\n          ch = (((ch & 0x3ff) << 10) | (lch & 0x3ff)) + 0x10000;\n    }\n    break;\n\n    case ENCODE_UTF16LE :\n       /*\n        * Read UTF-16 little-endian char...\n    */\n\n    if (buf->current >= buf->end)\n      if (mxml_fd_read(buf) < 0)\n        return (EOF);\n\n    temp = *(buf->current)++;\n\n    ch |= (temp << 8);\n\n        if (mxml_bad_char(ch))\n    {\n      mxml_error(\"Bad control character 0x%02x not allowed by XML standard!\",\n                 ch);\n      return (EOF);\n    }\n        else if (ch >= 0xd800 && ch <= 0xdbff)\n    {\n     /*\n      * Multi-word UTF-16 char...\n      */\n\n          int lch;\n\n      if (buf->current >= buf->end)\n        if (mxml_fd_read(buf) < 0)\n          return (EOF);\n\n      lch = *(buf->current)++;\n\n      if (buf->current >= buf->end)\n        if (mxml_fd_read(buf) < 0)\n          return (EOF);\n\n      temp = *(buf->current)++;\n\n      lch |= (temp << 8);\n\n          if (lch < 0xdc00 || lch >= 0xdfff)\n        return (EOF);\n\n          ch = (((ch & 0x3ff) << 10) | (lch & 0x3ff)) + 0x10000;\n    }\n    break;\n  }\n\n#if DEBUG > 1\n  printf(\"mxml_fd_getc: %c (0x%04x)\\n\", ch < ' ' ? '.' : ch, ch);\n#endif /* DEBUG > 1 */\n\n  return (ch);\n}\n\n\n/*\n * 'mxml_fd_putc()' - Write a character to a file descriptor.\n */\n\nstatic int\t\t\t\t/* O - 0 on success, -1 on error */\nmxml_fd_putc(int  ch,\t\t\t/* I - Character */\n             void *p)\t\t\t/* I - File descriptor buffer */\n{\n  _mxml_fdbuf_t\t*buf;\t\t\t/* File descriptor buffer */\n\n\n /*\n  * Flush the write buffer as needed...\n  */\n\n  buf = (_mxml_fdbuf_t *)p;\n\n  if (buf->current >= buf->end)\n    if (mxml_fd_write(buf) < 0)\n      return (-1);\n\n  *(buf->current)++ = ch;\n\n /*\n  * Return successfully...\n  */\n\n  return (0);\n}\n\n\n/*\n * 'mxml_fd_read()' - Read a buffer of data from a file descriptor.\n */\n /* wj32: modified to use file handles */\n\nstatic int\t\t\t\t/* O - 0 on success, -1 on error */\nmxml_fd_read(_mxml_fdbuf_t *buf)\t\t/* I - File descriptor buffer */\n{\n    IO_STATUS_BLOCK isb;\n\n    if (!buf)\n        return -1;\n\n    if (!NT_SUCCESS(NtReadFile(buf->fd, NULL, NULL, NULL, &isb, buf->buffer, sizeof(buf->buffer), NULL, NULL)))\n        return -1;\n\n    if (isb.Information == 0) // check bytes read\n        return -1;\n\n    buf->current = buf->buffer;\n    buf->end = buf->buffer + isb.Information;\n\n    return 0;\n}\n\n\n/*\n * 'mxml_fd_write()' - Write a buffer of data to a file descriptor.\n */\n /* wj32: modified to use file handles */\n\nstatic int\t\t\t\t/* O - 0 on success, -1 on error */\nmxml_fd_write(_mxml_fdbuf_t *buf)\t/* I - File descriptor buffer */\n{\n    IO_STATUS_BLOCK isb;\n\n    if (!buf)\n        return 1;\n\n    if (buf->current == buf->buffer)\n        return 0;\n\n    if (!NT_SUCCESS(NtWriteFile(buf->fd, NULL, NULL, NULL, &isb, buf->buffer, (ULONG)(buf->current - buf->buffer), NULL, NULL)))\n        return -1;\n\n    buf->current = buf->buffer;\n\n    return 0;\n}\n\n\n/*\n * 'mxml_file_getc()' - Get a character from a file.\n */\n\nstatic int\t\t\t\t/* O  - Character or EOF */\nmxml_file_getc(void *p,\t\t\t/* I  - Pointer to file */\n               int  *encoding)\t\t/* IO - Encoding */\n{\n  int\tch,\t\t\t\t/* Character from file */\n    temp;\t\t\t\t/* Temporary character */\n  FILE\t*fp;\t\t\t\t/* Pointer to file */\n\n\n /*\n  * Read a character from the file and see if it is EOF or ASCII...\n  */\n\n  fp = (FILE *)p;\n  ch = getc(fp);\n\n  if (ch == EOF)\n    return (EOF);\n\n  switch (*encoding)\n  {\n    case ENCODE_UTF8 :\n       /*\n    * Got a UTF-8 character; convert UTF-8 to Unicode and return...\n    */\n\n    if (!(ch & 0x80))\n    {\n      if (mxml_bad_char(ch))\n      {\n        mxml_error(\"Bad control character 0x%02x not allowed by XML standard!\",\n                   ch);\n        return (EOF);\n      }\n\n#if DEBUG > 1\n          printf(\"mxml_file_getc: %c (0x%04x)\\n\", ch < ' ' ? '.' : ch, ch);\n#endif /* DEBUG > 1 */\n\n      return (ch);\n        }\n    else if (ch == 0xfe)\n    {\n     /*\n      * UTF-16 big-endian BOM?\n      */\n\n          ch = getc(fp);\n      if (ch != 0xff)\n        return (EOF);\n\n      *encoding = ENCODE_UTF16BE;\n\n      return (mxml_file_getc(p, encoding));\n    }\n    else if (ch == 0xff)\n    {\n     /*\n      * UTF-16 little-endian BOM?\n      */\n\n          ch = getc(fp);\n      if (ch != 0xfe)\n        return (EOF);\n\n      *encoding = ENCODE_UTF16LE;\n\n      return (mxml_file_getc(p, encoding));\n    }\n    else if ((ch & 0xe0) == 0xc0)\n    {\n     /*\n      * Two-byte value...\n      */\n\n      if ((temp = getc(fp)) == EOF || (temp & 0xc0) != 0x80)\n        return (EOF);\n\n      ch = ((ch & 0x1f) << 6) | (temp & 0x3f);\n\n      if (ch < 0x80)\n      {\n        mxml_error(\"Invalid UTF-8 sequence for character 0x%04x!\", ch);\n        return (EOF);\n      }\n    }\n    else if ((ch & 0xf0) == 0xe0)\n    {\n     /*\n      * Three-byte value...\n      */\n\n      if ((temp = getc(fp)) == EOF || (temp & 0xc0) != 0x80)\n        return (EOF);\n\n      ch = ((ch & 0x0f) << 6) | (temp & 0x3f);\n\n      if ((temp = getc(fp)) == EOF || (temp & 0xc0) != 0x80)\n        return (EOF);\n\n      ch = (ch << 6) | (temp & 0x3f);\n\n      if (ch < 0x800)\n      {\n        mxml_error(\"Invalid UTF-8 sequence for character 0x%04x!\", ch);\n        return (EOF);\n      }\n\n         /*\n      * Ignore (strip) Byte Order Mark (BOM)...\n      */\n\n      if (ch == 0xfeff)\n        return (mxml_file_getc(p, encoding));\n    }\n    else if ((ch & 0xf8) == 0xf0)\n    {\n     /*\n      * Four-byte value...\n      */\n\n      if ((temp = getc(fp)) == EOF || (temp & 0xc0) != 0x80)\n        return (EOF);\n\n      ch = ((ch & 0x07) << 6) | (temp & 0x3f);\n\n      if ((temp = getc(fp)) == EOF || (temp & 0xc0) != 0x80)\n        return (EOF);\n\n      ch = (ch << 6) | (temp & 0x3f);\n\n      if ((temp = getc(fp)) == EOF || (temp & 0xc0) != 0x80)\n        return (EOF);\n\n      ch = (ch << 6) | (temp & 0x3f);\n\n      if (ch < 0x10000)\n      {\n        mxml_error(\"Invalid UTF-8 sequence for character 0x%04x!\", ch);\n        return (EOF);\n      }\n    }\n    else\n      return (EOF);\n    break;\n\n    case ENCODE_UTF16BE :\n       /*\n        * Read UTF-16 big-endian char...\n    */\n\n    ch = (ch << 8) | getc(fp);\n\n    if (mxml_bad_char(ch))\n    {\n      mxml_error(\"Bad control character 0x%02x not allowed by XML standard!\",\n                 ch);\n      return (EOF);\n    }\n        else if (ch >= 0xd800 && ch <= 0xdbff)\n    {\n     /*\n      * Multi-word UTF-16 char...\n      */\n\n          int lch = getc(fp);\n          lch = (lch << 8) | getc(fp);\n\n          if (lch < 0xdc00 || lch >= 0xdfff)\n        return (EOF);\n\n          ch = (((ch & 0x3ff) << 10) | (lch & 0x3ff)) + 0x10000;\n    }\n    break;\n\n    case ENCODE_UTF16LE :\n       /*\n        * Read UTF-16 little-endian char...\n    */\n\n    ch |= (getc(fp) << 8);\n\n        if (mxml_bad_char(ch))\n    {\n      mxml_error(\"Bad control character 0x%02x not allowed by XML standard!\",\n                 ch);\n      return (EOF);\n    }\n        else if (ch >= 0xd800 && ch <= 0xdbff)\n    {\n     /*\n      * Multi-word UTF-16 char...\n      */\n\n          int lch = getc(fp);\n          lch |= (getc(fp) << 8);\n\n          if (lch < 0xdc00 || lch >= 0xdfff)\n        return (EOF);\n\n          ch = (((ch & 0x3ff) << 10) | (lch & 0x3ff)) + 0x10000;\n    }\n    break;\n  }\n\n#if DEBUG > 1\n  printf(\"mxml_file_getc: %c (0x%04x)\\n\", ch < ' ' ? '.' : ch, ch);\n#endif /* DEBUG > 1 */\n\n  return (ch);\n}\n\n\n/*\n * 'mxml_file_putc()' - Write a character to a file.\n */\n\nstatic int\t\t\t\t/* O - 0 on success, -1 on failure */\nmxml_file_putc(int  ch,\t\t\t/* I - Character to write */\n               void *p)\t\t\t/* I - Pointer to file */\n{\n  return (putc(ch, (FILE *)p) == EOF ? -1 : 0);\n}\n\n\n/*\n * 'mxml_get_entity()' - Get the character corresponding to an entity...\n */\n\nstatic int\t\t\t\t/* O  - Character value or EOF on error */\nmxml_get_entity(mxml_node_t *parent,\t/* I  - Parent node */\n        void        *p,\t\t/* I  - Pointer to source */\n        int         *encoding,\t/* IO - Character encoding */\n                int         (*getc_cb)(void *, int *))\n                    /* I  - Get character function */\n{\n  int\tch;\t\t\t\t/* Current character */\n  char\tentity[64],\t\t\t/* Entity string */\n    *entptr;\t\t\t/* Pointer into entity */\n\n\n  entptr = entity;\n\n  while ((ch = (*getc_cb)(p, encoding)) != EOF)\n    if (ch > 126 || (!isalnum(ch) && ch != '#'))\n      break;\n    else if (entptr < (entity + sizeof(entity) - 1))\n      *entptr++ = ch;\n    else\n    {\n      mxml_error(\"Entity name too long under parent <%s>!\",\n             parent ? parent->value.element.name : \"null\");\n      break;\n    }\n\n  *entptr = '\\0';\n\n  if (ch != ';')\n  {\n    mxml_error(\"Character entity \\\"%s\\\" not terminated under parent <%s>!\",\n           entity, parent ? parent->value.element.name : \"null\");\n    return (EOF);\n  }\n\n  if (entity[0] == '#')\n  {\n    if (entity[1] == 'x')\n      ch = strtol(entity + 2, NULL, 16);\n    else\n      ch = strtol(entity + 1, NULL, 10);\n  }\n  else if ((ch = mxmlEntityGetValue(entity)) < 0)\n    mxml_error(\"Entity name \\\"%s;\\\" not supported under parent <%s>!\",\n           entity, parent ? parent->value.element.name : \"null\");\n\n  if (mxml_bad_char(ch))\n  {\n    mxml_error(\"Bad control character 0x%02x under parent <%s> not allowed by XML standard!\",\n               ch, parent ? parent->value.element.name : \"null\");\n    return (EOF);\n  }\n\n  return (ch);\n}\n\n\n/*\n * 'mxml_load_data()' - Load data into an XML node tree.\n */\n\nstatic mxml_node_t *\t\t\t/* O - First node or NULL if the file could not be read. */\nmxml_load_data(\n    mxml_node_t     *top,\t\t/* I - Top node */\n    void            *p,\t\t\t/* I - Pointer to data */\n    mxml_load_cb_t  cb,\t\t\t/* I - Callback function or MXML_NO_CALLBACK */\n    _mxml_getc_cb_t getc_cb,\t\t/* I - Read function */\n    mxml_sax_cb_t   sax_cb,\t\t/* I - SAX callback or MXML_NO_CALLBACK */\n    void            *sax_data)\t\t/* I - SAX user data */\n{\n  mxml_node_t\t*node,\t\t\t/* Current node */\n        *first,\t\t\t/* First node added */\n        *parent;\t\t/* Current parent node */\n  int\t\tch,\t\t\t/* Character from file */\n        whitespace;\t\t/* Non-zero if whitespace seen */\n  char\t\t*buffer,\t\t/* String buffer */\n        *bufptr;\t\t/* Pointer into buffer */\n  int\t\tbufsize;\t\t/* Size of buffer */\n  mxml_type_t\ttype;\t\t\t/* Current node type */\n  int\t\tencoding;\t\t/* Character encoding */\n  _mxml_global_t *global = _mxml_global();\n                    /* Global data */\n  static const char * const types[] =\t/* Type strings... */\n        {\n          \"MXML_ELEMENT\",\t/* XML element with attributes */\n          \"MXML_INTEGER\",\t/* Integer value */\n          \"MXML_OPAQUE\",\t/* Opaque string */\n          \"MXML_REAL\",\t\t/* Real value */\n          \"MXML_TEXT\",\t\t/* Text fragment */\n          \"MXML_CUSTOM\"\t\t/* Custom data */\n        };\n\n\n /*\n  * Read elements and other nodes from the file...\n  */\n\n  if ((buffer = PhAllocateSafe(64)) == NULL)\n  {\n    mxml_error(\"Unable to allocate string buffer!\");\n    return (NULL);\n  }\n\n  bufsize    = 64;\n  bufptr     = buffer;\n  parent     = top;\n  first      = NULL;\n  whitespace = 0;\n  encoding   = ENCODE_UTF8;\n\n  if (cb && parent)\n    type = (*cb)(parent);\n  else if (parent)\n    type = MXML_TEXT;\n  else\n    type = MXML_IGNORE;\n\n  while ((ch = (*getc_cb)(p, &encoding)) != EOF)\n  {\n    if ((ch == '<' ||\n         (mxml_isspace(ch) && type != MXML_OPAQUE && type != MXML_CUSTOM)) &&\n        bufptr > buffer)\n    {\n     /*\n      * Add a new value node...\n      */\n\n      *bufptr = '\\0';\n\n      switch (type)\n      {\n    case MXML_INTEGER :\n            node = mxmlNewInteger(parent, strtol(buffer, &bufptr, 0));\n        break;\n\n    case MXML_OPAQUE :\n            node = mxmlNewOpaque(parent, buffer);\n        break;\n\n    case MXML_REAL :\n            node = mxmlNewReal(parent, strtod(buffer, &bufptr));\n        break;\n\n    case MXML_TEXT :\n            node = mxmlNewText(parent, whitespace, buffer);\n        break;\n\n    case MXML_CUSTOM :\n        if (global->custom_load_cb)\n        {\n         /*\n          * Use the callback to fill in the custom data...\n          */\n\n              node = mxmlNewCustom(parent, NULL, NULL);\n\n          if ((*global->custom_load_cb)(node, buffer))\n          {\n            mxml_error(\"Bad custom value '%s' in parent <%s>!\",\n                   buffer, parent ? parent->value.element.name : \"null\");\n        mxmlDelete(node);\n        node = NULL;\n          }\n          break;\n        }\n\n        default : /* Ignore... */\n        node = NULL;\n        break;\n      }\n\n      if (*bufptr)\n      {\n       /*\n        * Bad integer/real number value...\n    */\n\n        mxml_error(\"Bad %s value '%s' in parent <%s>!\",\n               type == MXML_INTEGER ? \"integer\" : \"real\", buffer,\n           parent ? parent->value.element.name : \"null\");\n    break;\n      }\n\n      bufptr     = buffer;\n      whitespace = mxml_isspace(ch) && type == MXML_TEXT;\n\n      if (!node && type != MXML_IGNORE)\n      {\n       /*\n    * Print error and return...\n    */\n\n    mxml_error(\"Unable to add value node of type %s to parent <%s>!\",\n               types[type], parent ? parent->value.element.name : \"null\");\n    goto error;\n      }\n\n      if (sax_cb)\n      {\n        (*sax_cb)(node, MXML_SAX_DATA, sax_data);\n\n        if (!mxmlRelease(node))\n          node = NULL;\n      }\n\n      if (!first && node)\n        first = node;\n    }\n    else if (mxml_isspace(ch) && type == MXML_TEXT)\n      whitespace = 1;\n\n   /*\n    * Add lone whitespace node if we have an element and existing\n    * whitespace...\n    */\n\n    if (ch == '<' && whitespace && type == MXML_TEXT)\n    {\n      if (parent)\n      {\n    node = mxmlNewText(parent, whitespace, \"\");\n\n    if (sax_cb)\n    {\n      (*sax_cb)(node, MXML_SAX_DATA, sax_data);\n\n      if (!mxmlRelease(node))\n        node = NULL;\n    }\n\n    if (!first && node)\n      first = node;\n      }\n\n      whitespace = 0;\n    }\n\n    if (ch == '<')\n    {\n     /*\n      * Start of open/close tag...\n      */\n\n      bufptr = buffer;\n\n      while ((ch = (*getc_cb)(p, &encoding)) != EOF)\n        if (mxml_isspace(ch) || ch == '>' || (ch == '/' && bufptr > buffer))\n      break;\n    else if (ch == '<')\n    {\n      mxml_error(\"Bare < in element!\");\n      goto error;\n    }\n    else if (ch == '&')\n    {\n      if ((ch = mxml_get_entity(parent, p, &encoding, getc_cb)) == EOF)\n        goto error;\n\n      if (mxml_add_char(ch, &bufptr, &buffer, &bufsize))\n        goto error;\n    }\n    else if (ch < '0' && ch != '!' && ch != '-' && ch != '.' && ch != '/')\n      goto error;\n    else if (mxml_add_char(ch, &bufptr, &buffer, &bufsize))\n      goto error;\n    else if (((bufptr - buffer) == 1 && buffer[0] == '?') ||\n             ((bufptr - buffer) == 3 && !strncmp(buffer, \"!--\", 3)) ||\n             ((bufptr - buffer) == 8 && !strncmp(buffer, \"![CDATA[\", 8)))\n      break;\n\n      *bufptr = '\\0';\n\n      if (!strcmp(buffer, \"!--\"))\n      {\n       /*\n        * Gather rest of comment...\n    */\n\n    while ((ch = (*getc_cb)(p, &encoding)) != EOF)\n    {\n      if (ch == '>' && bufptr > (buffer + 4) &&\n          bufptr[-3] != '-' && bufptr[-2] == '-' && bufptr[-1] == '-')\n        break;\n      else if (mxml_add_char(ch, &bufptr, &buffer, &bufsize))\n        goto error;\n    }\n\n       /*\n        * Error out if we didn't get the whole comment...\n    */\n\n        if (ch != '>')\n    {\n     /*\n      * Print error and return...\n      */\n\n      mxml_error(\"Early EOF in comment node!\");\n      goto error;\n    }\n\n\n       /*\n        * Otherwise add this as an element under the current parent...\n    */\n\n    *bufptr = '\\0';\n\n        if (!parent && first)\n    {\n     /*\n      * There can only be one root element!\n      */\n\n      mxml_error(\"<%s> cannot be a second root node after <%s>\",\n                 buffer, first->value.element.name);\n          goto error;\n    }\n\n    if ((node = mxmlNewElement(parent, buffer)) == NULL)\n    {\n     /*\n      * Just print error for now...\n      */\n\n      mxml_error(\"Unable to add comment node to parent <%s>!\",\n                 parent ? parent->value.element.name : \"null\");\n      break;\n    }\n\n        if (sax_cb)\n        {\n          (*sax_cb)(node, MXML_SAX_COMMENT, sax_data);\n\n          if (!mxmlRelease(node))\n            node = NULL;\n        }\n\n    if (node && !first)\n      first = node;\n      }\n      else if (!strcmp(buffer, \"![CDATA[\"))\n      {\n       /*\n        * Gather CDATA section...\n    */\n\n    while ((ch = (*getc_cb)(p, &encoding)) != EOF)\n    {\n      if (ch == '>' && !strncmp(bufptr - 2, \"]]\", 2))\n        break;\n      else if (mxml_add_char(ch, &bufptr, &buffer, &bufsize))\n        goto error;\n    }\n\n       /*\n        * Error out if we didn't get the whole comment...\n    */\n\n        if (ch != '>')\n    {\n     /*\n      * Print error and return...\n      */\n\n      mxml_error(\"Early EOF in CDATA node!\");\n      goto error;\n    }\n\n\n       /*\n        * Otherwise add this as an element under the current parent...\n    */\n\n    *bufptr = '\\0';\n\n        if (!parent && first)\n    {\n     /*\n      * There can only be one root element!\n      */\n\n      mxml_error(\"<%s> cannot be a second root node after <%s>\",\n                 buffer, first->value.element.name);\n          goto error;\n    }\n\n    if ((node = mxmlNewElement(parent, buffer)) == NULL)\n    {\n     /*\n      * Print error and return...\n      */\n\n      mxml_error(\"Unable to add CDATA node to parent <%s>!\",\n                 parent ? parent->value.element.name : \"null\");\n      goto error;\n    }\n\n        if (sax_cb)\n        {\n          (*sax_cb)(node, MXML_SAX_CDATA, sax_data);\n\n          if (!mxmlRelease(node))\n            node = NULL;\n        }\n\n    if (node && !first)\n      first = node;\n      }\n      else if (buffer[0] == '?')\n      {\n       /*\n        * Gather rest of processing instruction...\n    */\n\n    while ((ch = (*getc_cb)(p, &encoding)) != EOF)\n    {\n      if (ch == '>' && bufptr > buffer && bufptr[-1] == '?')\n        break;\n      else if (mxml_add_char(ch, &bufptr, &buffer, &bufsize))\n        goto error;\n    }\n\n       /*\n        * Error out if we didn't get the whole processing instruction...\n    */\n\n        if (ch != '>')\n    {\n     /*\n      * Print error and return...\n      */\n\n      mxml_error(\"Early EOF in processing instruction node!\");\n      goto error;\n    }\n\n       /*\n        * Otherwise add this as an element under the current parent...\n    */\n\n    *bufptr = '\\0';\n\n        if (!parent && first)\n    {\n     /*\n      * There can only be one root element!\n      */\n\n      mxml_error(\"<%s> cannot be a second root node after <%s>\",\n                 buffer, first->value.element.name);\n          goto error;\n    }\n\n    if ((node = mxmlNewElement(parent, buffer)) == NULL)\n    {\n     /*\n      * Print error and return...\n      */\n\n      mxml_error(\"Unable to add processing instruction node to parent <%s>!\",\n                 parent ? parent->value.element.name : \"null\");\n      goto error;\n    }\n\n        if (sax_cb)\n        {\n          (*sax_cb)(node, MXML_SAX_DIRECTIVE, sax_data);\n\n          if (!mxmlRelease(node))\n            node = NULL;\n        }\n\n        if (node)\n    {\n      if (!first)\n            first = node;\n\n      if (!parent)\n      {\n        parent = node;\n\n        if (cb)\n          type = (*cb)(parent);\n        else\n          type = MXML_TEXT;\n      }\n    }\n      }\n      else if (buffer[0] == '!')\n      {\n       /*\n        * Gather rest of declaration...\n    */\n\n    do\n    {\n      if (ch == '>')\n        break;\n      else\n      {\n            if (ch == '&')\n          if ((ch = mxml_get_entity(parent, p, &encoding, getc_cb)) == EOF)\n        goto error;\n\n        if (mxml_add_char(ch, &bufptr, &buffer, &bufsize))\n          goto error;\n      }\n    }\n        while ((ch = (*getc_cb)(p, &encoding)) != EOF);\n\n       /*\n        * Error out if we didn't get the whole declaration...\n    */\n\n        if (ch != '>')\n    {\n     /*\n      * Print error and return...\n      */\n\n      mxml_error(\"Early EOF in declaration node!\");\n      goto error;\n    }\n\n       /*\n        * Otherwise add this as an element under the current parent...\n    */\n\n    *bufptr = '\\0';\n\n        if (!parent && first)\n    {\n     /*\n      * There can only be one root element!\n      */\n\n      mxml_error(\"<%s> cannot be a second root node after <%s>\",\n                 buffer, first->value.element.name);\n          goto error;\n    }\n\n    if ((node = mxmlNewElement(parent, buffer)) == NULL)\n    {\n     /*\n      * Print error and return...\n      */\n\n      mxml_error(\"Unable to add declaration node to parent <%s>!\",\n                 parent ? parent->value.element.name : \"null\");\n      goto error;\n    }\n\n        if (sax_cb)\n        {\n          (*sax_cb)(node, MXML_SAX_DIRECTIVE, sax_data);\n\n          if (!mxmlRelease(node))\n            node = NULL;\n        }\n\n        if (node)\n    {\n      if (!first)\n            first = node;\n\n      if (!parent)\n      {\n        parent = node;\n\n        if (cb)\n          type = (*cb)(parent);\n        else\n          type = MXML_TEXT;\n      }\n    }\n      }\n      else if (buffer[0] == '/')\n      {\n       /*\n        * Handle close tag...\n    */\n\n        if (!parent || strcmp(buffer + 1, parent->value.element.name))\n    {\n     /*\n      * Close tag doesn't match tree; print an error for now...\n      */\n\n      mxml_error(\"Mismatched close tag <%s> under parent <%s>!\",\n                 buffer, parent ? parent->value.element.name : \"(null)\");\n          goto error;\n    }\n\n       /*\n        * Keep reading until we see >...\n    */\n\n        while (ch != '>' && ch != EOF)\n      ch = (*getc_cb)(p, &encoding);\n\n        node   = parent;\n        parent = parent->parent;\n\n        if (sax_cb)\n        {\n          (*sax_cb)(node, MXML_SAX_ELEMENT_CLOSE, sax_data);\n\n          if (!mxmlRelease(node) && first == node)\n        first = NULL;\n        }\n\n       /*\n    * Ascend into the parent and set the value type as needed...\n    */\n\n    if (cb && parent)\n      type = (*cb)(parent);\n      }\n      else\n      {\n       /*\n        * Handle open tag...\n    */\n\n        if (!parent && first)\n    {\n     /*\n      * There can only be one root element!\n      */\n\n      mxml_error(\"<%s> cannot be a second root node after <%s>\",\n                 buffer, first->value.element.name);\n          goto error;\n    }\n\n        if ((node = mxmlNewElement(parent, buffer)) == NULL)\n    {\n     /*\n      * Just print error for now...\n      */\n\n      mxml_error(\"Unable to add element node to parent <%s>!\",\n                 parent ? parent->value.element.name : \"null\");\n      goto error;\n    }\n\n        if (mxml_isspace(ch))\n        {\n      if ((ch = mxml_parse_element(node, p, &encoding, getc_cb)) == EOF)\n        goto error;\n        }\n        else if (ch == '/')\n    {\n      if ((ch = (*getc_cb)(p, &encoding)) != '>')\n      {\n        mxml_error(\"Expected > but got '%c' instead for element <%s/>!\",\n                   ch, buffer);\n            mxmlDelete(node);\n            goto error;\n      }\n\n      ch = '/';\n    }\n\n        if (sax_cb)\n          (*sax_cb)(node, MXML_SAX_ELEMENT_OPEN, sax_data);\n\n        if (!first)\n      first = node;\n\n    if (ch == EOF)\n      break;\n\n        if (ch != '/')\n    {\n     /*\n      * Descend into this node, setting the value type as needed...\n      */\n\n      parent = node;\n\n      if (cb && parent)\n        type = (*cb)(parent);\n      else\n        type = MXML_TEXT;\n    }\n        else if (sax_cb)\n        {\n          (*sax_cb)(node, MXML_SAX_ELEMENT_CLOSE, sax_data);\n\n          if (!mxmlRelease(node) && first == node)\n            first = NULL;\n        }\n      }\n\n      bufptr  = buffer;\n    }\n    else if (ch == '&')\n    {\n     /*\n      * Add character entity to current buffer...\n      */\n\n      if ((ch = mxml_get_entity(parent, p, &encoding, getc_cb)) == EOF)\n    goto error;\n\n      if (mxml_add_char(ch, &bufptr, &buffer, &bufsize))\n    goto error;\n    }\n    else if (type == MXML_OPAQUE || type == MXML_CUSTOM || !mxml_isspace(ch))\n    {\n     /*\n      * Add character to current buffer...\n      */\n\n      if (mxml_add_char(ch, &bufptr, &buffer, &bufsize))\n    goto error;\n    }\n  }\n\n /*\n  * Free the string buffer - we don't need it anymore...\n  */\n\n  PhFree(buffer);\n\n /*\n  * Find the top element and return it...\n  */\n\n  if (parent)\n  {\n    node = parent;\n\n    while (parent != top && parent->parent)\n      parent = parent->parent;\n\n    if (node != parent)\n    {\n      mxml_error(\"Missing close tag </%s> under parent <%s>!\",\n             node->value.element.name,\n         node->parent ? node->parent->value.element.name : \"(null)\");\n\n      mxmlDelete(first);\n\n      return (NULL);\n    }\n  }\n\n  if (parent)\n    return (parent);\n  else\n    return (first);\n\n /*\n  * Common error return...\n  */\n\nerror:\n\n  mxmlDelete(first);\n\n  PhFree(buffer);\n\n  return (NULL);\n}\n\n\n/*\n * 'mxml_parse_element()' - Parse an element for any attributes...\n */\n\nstatic int\t\t\t\t/* O  - Terminating character */\nmxml_parse_element(\n    mxml_node_t     *node,\t\t/* I  - Element node */\n    void            *p,\t\t\t/* I  - Data to read from */\n    int             *encoding,\t\t/* IO - Encoding */\n    _mxml_getc_cb_t getc_cb)\t\t/* I  - Data callback */\n{\n  int\tch,\t\t\t\t/* Current character in file */\n    quote;\t\t\t\t/* Quoting character */\n  char\t*name,\t\t\t\t/* Attribute name */\n    *value,\t\t\t\t/* Attribute value */\n    *ptr;\t\t\t\t/* Pointer into name/value */\n  int\tnamesize,\t\t\t/* Size of name string */\n    valsize;\t\t\t/* Size of value string */\n\n\n /*\n  * Initialize the name and value buffers...\n  */\n\n  if ((name = PhAllocateSafe(64)) == NULL)\n  {\n    mxml_error(\"Unable to allocate memory for name!\");\n    return (EOF);\n  }\n\n  namesize = 64;\n\n  if ((value = PhAllocateSafe(64)) == NULL)\n  {\n    PhFree(name);\n    mxml_error(\"Unable to allocate memory for value!\");\n    return (EOF);\n  }\n\n  valsize = 64;\n\n /*\n  * Loop until we hit a >, /, ?, or EOF...\n  */\n\n  while ((ch = (*getc_cb)(p, encoding)) != EOF)\n  {\n#if DEBUG > 1\n    fprintf(stderr, \"parse_element: ch='%c'\\n\", ch);\n#endif /* DEBUG > 1 */\n\n   /*\n    * Skip leading whitespace...\n    */\n\n    if (mxml_isspace(ch))\n      continue;\n\n   /*\n    * Stop at /, ?, or >...\n    */\n\n    if (ch == '/' || ch == '?')\n    {\n     /*\n      * Grab the > character and print an error if it isn't there...\n      */\n\n      quote = (*getc_cb)(p, encoding);\n\n      if (quote != '>')\n      {\n        mxml_error(\"Expected '>' after '%c' for element %s, but got '%c'!\",\n               ch, node->value.element.name, quote);\n        goto error;\n      }\n\n      break;\n    }\n    else if (ch == '<')\n    {\n      mxml_error(\"Bare < in element %s!\", node->value.element.name);\n      goto error;\n    }\n    else if (ch == '>')\n      break;\n\n   /*\n    * Read the attribute name...\n    */\n\n    name[0] = ch;\n    ptr     = name + 1;\n\n    if (ch == '\\\"' || ch == '\\'')\n    {\n     /*\n      * Name is in quotes, so get a quoted string...\n      */\n\n      quote = ch;\n\n      while ((ch = (*getc_cb)(p, encoding)) != EOF)\n      {\n        if (ch == '&')\n      if ((ch = mxml_get_entity(node, p, encoding, getc_cb)) == EOF)\n        goto error;\n\n    if (mxml_add_char(ch, &ptr, &name, &namesize))\n      goto error;\n\n    if (ch == quote)\n          break;\n      }\n    }\n    else\n    {\n     /*\n      * Grab an normal, non-quoted name...\n      */\n\n      while ((ch = (*getc_cb)(p, encoding)) != EOF)\n    if (mxml_isspace(ch) || ch == '=' || ch == '/' || ch == '>' ||\n        ch == '?')\n          break;\n    else\n    {\n          if (ch == '&')\n        if ((ch = mxml_get_entity(node, p, encoding, getc_cb)) == EOF)\n          goto error;\n\n      if (mxml_add_char(ch, &ptr, &name, &namesize))\n        goto error;\n    }\n    }\n\n    *ptr = '\\0';\n\n    if (mxmlElementGetAttr(node, name))\n      goto error;\n\n    while (ch != EOF && mxml_isspace(ch))\n      ch = (*getc_cb)(p, encoding);\n\n    if (ch == '=')\n    {\n     /*\n      * Read the attribute value...\n      */\n\n      while ((ch = (*getc_cb)(p, encoding)) != EOF && mxml_isspace(ch));\n\n      if (ch == EOF)\n      {\n        mxml_error(\"Missing value for attribute '%s' in element %s!\",\n               name, node->value.element.name);\n        goto error;\n      }\n\n      if (ch == '\\'' || ch == '\\\"')\n      {\n       /*\n        * Read quoted value...\n    */\n\n        quote = ch;\n    ptr   = value;\n\n        while ((ch = (*getc_cb)(p, encoding)) != EOF)\n      if (ch == quote)\n        break;\n      else\n      {\n        if (ch == '&')\n          if ((ch = mxml_get_entity(node, p, encoding, getc_cb)) == EOF)\n            goto error;\n\n        if (mxml_add_char(ch, &ptr, &value, &valsize))\n          goto error;\n      }\n\n        *ptr = '\\0';\n      }\n      else\n      {\n       /*\n        * Read unquoted value...\n    */\n\n    value[0] = ch;\n    ptr      = value + 1;\n\n    while ((ch = (*getc_cb)(p, encoding)) != EOF)\n      if (mxml_isspace(ch) || ch == '=' || ch == '/' || ch == '>')\n            break;\n      else\n      {\n        if (ch == '&')\n          if ((ch = mxml_get_entity(node, p, encoding, getc_cb)) == EOF)\n            goto error;\n\n        if (mxml_add_char(ch, &ptr, &value, &valsize))\n          goto error;\n      }\n\n        *ptr = '\\0';\n      }\n\n     /*\n      * Set the attribute with the given string value...\n      */\n\n      mxmlElementSetAttr(node, name, value);\n    }\n    else\n    {\n      mxml_error(\"Missing value for attribute '%s' in element %s!\",\n             name, node->value.element.name);\n      goto error;\n    }\n\n   /*\n    * Check the end character...\n    */\n\n    if (ch == '/' || ch == '?')\n    {\n     /*\n      * Grab the > character and print an error if it isn't there...\n      */\n\n      quote = (*getc_cb)(p, encoding);\n\n      if (quote != '>')\n      {\n        mxml_error(\"Expected '>' after '%c' for element %s, but got '%c'!\",\n               ch, node->value.element.name, quote);\n        ch = EOF;\n      }\n\n      break;\n    }\n    else if (ch == '>')\n      break;\n  }\n\n /*\n  * Free the name and value buffers and return...\n  */\n\n  PhFree(name);\n  PhFree(value);\n\n  return (ch);\n\n /*\n  * Common error return point...\n  */\n\nerror:\n\n  PhFree(name);\n  PhFree(value);\n\n  return (EOF);\n}\n\n\n/*\n * 'mxml_string_getc()' - Get a character from a string.\n */\n\nstatic int\t\t\t\t/* O  - Character or EOF */\nmxml_string_getc(void *p,\t\t/* I  - Pointer to file */\n                 int  *encoding)\t/* IO - Encoding */\n{\n  int\t\tch;\t\t\t/* Character */\n  const char\t**s;\t\t\t/* Pointer to string pointer */\n\n\n  s = (const char **)p;\n\n  if ((ch = (*s)[0] & 255) != 0 || *encoding == ENCODE_UTF16LE)\n  {\n   /*\n    * Got character; convert UTF-8 to integer and return...\n    */\n\n    (*s)++;\n\n    switch (*encoding)\n    {\n      case ENCODE_UTF8 :\n      if (!(ch & 0x80))\n      {\n#if DEBUG > 1\n            printf(\"mxml_string_getc: %c (0x%04x)\\n\", ch < ' ' ? '.' : ch, ch);\n#endif /* DEBUG > 1 */\n\n        if (mxml_bad_char(ch))\n        {\n          mxml_error(\"Bad control character 0x%02x not allowed by XML standard!\",\n                 ch);\n          return (EOF);\n        }\n\n        return (ch);\n          }\n      else if (ch == 0xfe)\n      {\n       /*\n        * UTF-16 big-endian BOM?\n        */\n\n            if (((*s)[0] & 255) != 0xff)\n          return (EOF);\n\n        *encoding = ENCODE_UTF16BE;\n        (*s)++;\n\n        return (mxml_string_getc(p, encoding));\n      }\n      else if (ch == 0xff)\n      {\n       /*\n        * UTF-16 little-endian BOM?\n        */\n\n            if (((*s)[0] & 255) != 0xfe)\n          return (EOF);\n\n        *encoding = ENCODE_UTF16LE;\n        (*s)++;\n\n        return (mxml_string_getc(p, encoding));\n      }\n      else if ((ch & 0xe0) == 0xc0)\n      {\n       /*\n        * Two-byte value...\n        */\n\n        if (((*s)[0] & 0xc0) != 0x80)\n              return (EOF);\n\n        ch = ((ch & 0x1f) << 6) | ((*s)[0] & 0x3f);\n\n        (*s)++;\n\n        if (ch < 0x80)\n        {\n          mxml_error(\"Invalid UTF-8 sequence for character 0x%04x!\", ch);\n          return (EOF);\n        }\n\n#if DEBUG > 1\n            printf(\"mxml_string_getc: %c (0x%04x)\\n\", ch < ' ' ? '.' : ch, ch);\n#endif /* DEBUG > 1 */\n\n        return (ch);\n      }\n      else if ((ch & 0xf0) == 0xe0)\n      {\n       /*\n        * Three-byte value...\n        */\n\n        if (((*s)[0] & 0xc0) != 0x80 ||\n            ((*s)[1] & 0xc0) != 0x80)\n              return (EOF);\n\n        ch = ((((ch & 0x0f) << 6) | ((*s)[0] & 0x3f)) << 6) | ((*s)[1] & 0x3f);\n\n        (*s) += 2;\n\n        if (ch < 0x800)\n        {\n          mxml_error(\"Invalid UTF-8 sequence for character 0x%04x!\", ch);\n          return (EOF);\n        }\n\n       /*\n        * Ignore (strip) Byte Order Mark (BOM)...\n        */\n\n        if (ch == 0xfeff)\n          return (mxml_string_getc(p, encoding));\n\n#if DEBUG > 1\n            printf(\"mxml_string_getc: %c (0x%04x)\\n\", ch < ' ' ? '.' : ch, ch);\n#endif /* DEBUG > 1 */\n\n        return (ch);\n      }\n      else if ((ch & 0xf8) == 0xf0)\n      {\n       /*\n        * Four-byte value...\n        */\n\n        if (((*s)[0] & 0xc0) != 0x80 ||\n            ((*s)[1] & 0xc0) != 0x80 ||\n            ((*s)[2] & 0xc0) != 0x80)\n              return (EOF);\n\n        ch = ((((((ch & 0x07) << 6) | ((*s)[0] & 0x3f)) << 6) |\n               ((*s)[1] & 0x3f)) << 6) | ((*s)[2] & 0x3f);\n\n        (*s) += 3;\n\n        if (ch < 0x10000)\n        {\n          mxml_error(\"Invalid UTF-8 sequence for character 0x%04x!\", ch);\n          return (EOF);\n        }\n\n#if DEBUG > 1\n            printf(\"mxml_string_getc: %c (0x%04x)\\n\", ch < ' ' ? '.' : ch, ch);\n#endif /* DEBUG > 1 */\n\n        return (ch);\n      }\n      else\n        return (EOF);\n\n      case ENCODE_UTF16BE :\n     /*\n          * Read UTF-16 big-endian char...\n      */\n\n      ch = (ch << 8) | ((*s)[0] & 255);\n      (*s) ++;\n\n          if (mxml_bad_char(ch))\n      {\n        mxml_error(\"Bad control character 0x%02x not allowed by XML standard!\",\n                   ch);\n        return (EOF);\n      }\n          else if (ch >= 0xd800 && ch <= 0xdbff)\n      {\n       /*\n        * Multi-word UTF-16 char...\n        */\n\n            int lch;\t\t\t/* Lower word */\n\n\n            if (!(*s)[0])\n          return (EOF);\n\n            lch = (((*s)[0] & 255) << 8) | ((*s)[1] & 255);\n        (*s) += 2;\n\n            if (lch < 0xdc00 || lch >= 0xdfff)\n          return (EOF);\n\n            ch = (((ch & 0x3ff) << 10) | (lch & 0x3ff)) + 0x10000;\n      }\n\n#if DEBUG > 1\n          printf(\"mxml_string_getc: %c (0x%04x)\\n\", ch < ' ' ? '.' : ch, ch);\n#endif /* DEBUG > 1 */\n\n      return (ch);\n\n      case ENCODE_UTF16LE :\n     /*\n          * Read UTF-16 little-endian char...\n      */\n\n      ch = ch | (((*s)[0] & 255) << 8);\n\n      if (!ch)\n      {\n        (*s) --;\n        return (EOF);\n      }\n\n      (*s) ++;\n\n          if (mxml_bad_char(ch))\n      {\n        mxml_error(\"Bad control character 0x%02x not allowed by XML standard!\",\n                   ch);\n        return (EOF);\n      }\n          else if (ch >= 0xd800 && ch <= 0xdbff)\n      {\n       /*\n        * Multi-word UTF-16 char...\n        */\n\n            int lch;\t\t\t/* Lower word */\n\n\n            if (!(*s)[1])\n          return (EOF);\n\n            lch = (((*s)[1] & 255) << 8) | ((*s)[0] & 255);\n        (*s) += 2;\n\n            if (lch < 0xdc00 || lch >= 0xdfff)\n          return (EOF);\n\n            ch = (((ch & 0x3ff) << 10) | (lch & 0x3ff)) + 0x10000;\n      }\n\n#if DEBUG > 1\n          printf(\"mxml_string_getc: %c (0x%04x)\\n\", ch < ' ' ? '.' : ch, ch);\n#endif /* DEBUG > 1 */\n\n      return (ch);\n    }\n  }\n\n  return (EOF);\n}\n\n\n/*\n * 'mxml_string_putc()' - Write a character to a string.\n */\n\nstatic int\t\t\t\t/* O - 0 on success, -1 on failure */\nmxml_string_putc(int  ch,\t\t/* I - Character to write */\n                 void *p)\t\t/* I - Pointer to string pointers */\n{\n  char\t**pp;\t\t\t\t/* Pointer to string pointers */\n\n\n  pp = (char **)p;\n\n  if (pp[0] < pp[1])\n    pp[0][0] = ch;\n\n  pp[0] ++;\n\n  return (0);\n}\n\n\n/*\n * 'mxml_write_name()' - Write a name string.\n */\n\nstatic int\t\t\t\t/* O - 0 on success, -1 on failure */\nmxml_write_name(const char *s,\t\t/* I - Name to write */\n                void       *p,\t\t/* I - Write pointer */\n        int        (*putc_cb)(int, void *))\n                    /* I - Write callback */\n{\n  char\t\tquote;\t\t\t/* Quote character */\n  const char\t*name;\t\t\t/* Entity name */\n\n\n  if (*s == '\\\"' || *s == '\\'')\n  {\n   /*\n    * Write a quoted name string...\n    */\n\n    if ((*putc_cb)(*s, p) < 0)\n      return (-1);\n\n    quote = *s++;\n\n    while (*s && *s != quote)\n    {\n      if ((name = mxmlEntityGetName(*s)) != NULL)\n      {\n    if ((*putc_cb)('&', p) < 0)\n          return (-1);\n\n        while (*name)\n    {\n      if ((*putc_cb)(*name, p) < 0)\n            return (-1);\n\n          name ++;\n    }\n\n    if ((*putc_cb)(';', p) < 0)\n          return (-1);\n      }\n      else if ((*putc_cb)(*s, p) < 0)\n    return (-1);\n\n      s ++;\n    }\n\n   /*\n    * Write the end quote...\n    */\n\n    if ((*putc_cb)(quote, p) < 0)\n      return (-1);\n  }\n  else\n  {\n   /*\n    * Write a non-quoted name string...\n    */\n\n    while (*s)\n    {\n      if ((*putc_cb)(*s, p) < 0)\n    return (-1);\n\n      s ++;\n    }\n  }\n\n  return (0);\n}\n\n\n/*\n * 'mxml_write_node()' - Save an XML node to a file.\n */\n\nstatic int\t\t\t\t/* O - Column or -1 on error */\nmxml_write_node(mxml_node_t     *node,\t/* I - Node to write */\n                void            *p,\t/* I - File to write to */\n            mxml_save_cb_t  cb,\t/* I - Whitespace callback */\n        int             col,\t/* I - Current column */\n        _mxml_putc_cb_t putc_cb,/* I - Output callback */\n        _mxml_global_t  *global)/* I - Global data */\n{\n  mxml_node_t\t*current,\t\t/* Current node */\n        *next;\t\t\t/* Next node */\n  int\t\ti,\t\t\t/* Looping var */\n        width;\t\t\t/* Width of attr + value */\n  mxml_attr_t\t*attr;\t\t\t/* Current attribute */\n  char\t\ts[255];\t\t\t/* Temporary string */\n\n\n /*\n  * Loop through this node and all of its children...\n  */\n\n  for (current = node; current; current = next)\n  {\n   /*\n    * Print the node value...\n    */\n\n    switch (current->type)\n    {\n      case MXML_ELEMENT :\n      col = mxml_write_ws(current, p, cb, MXML_WS_BEFORE_OPEN, col, putc_cb);\n\n      if ((*putc_cb)('<', p) < 0)\n        return (-1);\n      if (current->value.element.name[0] == '?' ||\n          !strncmp(current->value.element.name, \"!--\", 3) ||\n          !strncmp(current->value.element.name, \"![CDATA[\", 8))\n      {\n       /*\n        * Comments, CDATA, and processing instructions do not\n        * use character entities.\n        */\n\n        const char\t*ptr;\t\t/* Pointer into name */\n\n        for (ptr = current->value.element.name; *ptr; ptr ++)\n          if ((*putc_cb)(*ptr, p) < 0)\n        return (-1);\n      }\n      else if (mxml_write_name(current->value.element.name, p, putc_cb) < 0)\n        return (-1);\n\n      col += (int)strlen(current->value.element.name) + 1;\n\n      for (i = current->value.element.num_attrs, attr = current->value.element.attrs;\n           i > 0;\n           i --, attr ++)\n      {\n        width = (int)strlen(attr->name);\n\n        if (attr->value)\n          width += (int)strlen(attr->value) + 3;\n\n        if (global->wrap > 0 && (col + width) > global->wrap)\n        {\n          if ((*putc_cb)('\\n', p) < 0)\n        return (-1);\n\n          col = 0;\n        }\n        else\n        {\n          if ((*putc_cb)(' ', p) < 0)\n        return (-1);\n\n          col ++;\n        }\n\n        if (mxml_write_name(attr->name, p, putc_cb) < 0)\n          return (-1);\n\n        if (attr->value)\n        {\n          if ((*putc_cb)('=', p) < 0)\n        return (-1);\n          if ((*putc_cb)('\\\"', p) < 0)\n        return (-1);\n          if (mxml_write_string(attr->value, p, putc_cb) < 0)\n        return (-1);\n          if ((*putc_cb)('\\\"', p) < 0)\n        return (-1);\n        }\n\n        col += width;\n      }\n\n      if (current->child)\n      {\n       /*\n        * Write children...\n        */\n\n        if ((*putc_cb)('>', p) < 0)\n          return (-1);\n        else\n          col ++;\n\n        col = mxml_write_ws(current, p, cb, MXML_WS_AFTER_OPEN, col, putc_cb);\n      }\n      else if (current->value.element.name[0] == '!' ||\n           current->value.element.name[0] == '?')\n      {\n       /*\n        * The ? and ! elements are special-cases...\n        */\n\n        if ((*putc_cb)('>', p) < 0)\n          return (-1);\n        else\n          col ++;\n\n        col = mxml_write_ws(current, p, cb, MXML_WS_AFTER_OPEN, col, putc_cb);\n      }\n      else\n      {\n        if ((*putc_cb)(' ', p) < 0)\n          return (-1);\n        if ((*putc_cb)('/', p) < 0)\n          return (-1);\n        if ((*putc_cb)('>', p) < 0)\n          return (-1);\n\n        col += 3;\n\n        col = mxml_write_ws(current, p, cb, MXML_WS_AFTER_OPEN, col, putc_cb);\n      }\n      break;\n\n      case MXML_INTEGER :\n      if (current->prev)\n      {\n        if (global->wrap > 0 && col > global->wrap)\n        {\n          if ((*putc_cb)('\\n', p) < 0)\n        return (-1);\n\n          col = 0;\n        }\n        else if ((*putc_cb)(' ', p) < 0)\n          return (-1);\n        else\n          col ++;\n      }\n\n      sprintf(s, \"%d\", current->value.integer);\n      if (mxml_write_string(s, p, putc_cb) < 0)\n        return (-1);\n\n      col += (int)strlen(s);\n      break;\n\n      case MXML_OPAQUE :\n      if (mxml_write_string(current->value.opaque, p, putc_cb) < 0)\n        return (-1);\n\n      col += (int)strlen(current->value.opaque);\n      break;\n\n      case MXML_REAL :\n      if (current->prev)\n      {\n        if (global->wrap > 0 && col > global->wrap)\n        {\n          if ((*putc_cb)('\\n', p) < 0)\n        return (-1);\n\n          col = 0;\n        }\n        else if ((*putc_cb)(' ', p) < 0)\n          return (-1);\n        else\n          col ++;\n      }\n\n      sprintf(s, \"%f\", current->value.real);\n      if (mxml_write_string(s, p, putc_cb) < 0)\n        return (-1);\n\n      col += (int)strlen(s);\n      break;\n\n      case MXML_TEXT :\n      if (current->value.text.whitespace && col > 0)\n      {\n        if (global->wrap > 0 && col > global->wrap)\n        {\n          if ((*putc_cb)('\\n', p) < 0)\n        return (-1);\n\n          col = 0;\n        }\n        else if ((*putc_cb)(' ', p) < 0)\n          return (-1);\n        else\n          col ++;\n      }\n\n      if (mxml_write_string(current->value.text.string, p, putc_cb) < 0)\n        return (-1);\n\n      col += (int)strlen(current->value.text.string);\n      break;\n\n      case MXML_CUSTOM :\n      if (global->custom_save_cb)\n      {\n        char\t*data;\t\t/* Custom data string */\n        const char\t*newline;\t/* Last newline in string */\n\n\n        if ((data = (*global->custom_save_cb)(node)) == NULL)\n          return (-1);\n\n        if (mxml_write_string(data, p, putc_cb) < 0)\n          return (-1);\n\n        if ((newline = strrchr(data, '\\n')) == NULL)\n          col += (int)strlen(data);\n        else\n          col = (int)strlen(newline);\n\n        PhFree(data);\n        break;\n      }\n\n      default : /* Should never happen */\n      return (-1);\n    }\n\n   /*\n    * Figure out the next node...\n    */\n\n    if ((next = current->child) == NULL)\n    {\n      while ((next = current->next) == NULL)\n      {\n        if (current == node)\n          break;\n\n       /*\n    * The ? and ! elements are special-cases and have no end tags...\n    */\n\n    current = current->parent;\n\n    if (current->value.element.name[0] != '!' &&\n        current->value.element.name[0] != '?')\n    {\n      col = mxml_write_ws(current, p, cb, MXML_WS_BEFORE_CLOSE, col, putc_cb);\n\n      if ((*putc_cb)('<', p) < 0)\n        return (-1);\n      if ((*putc_cb)('/', p) < 0)\n        return (-1);\n      if (mxml_write_string(current->value.element.name, p, putc_cb) < 0)\n        return (-1);\n      if ((*putc_cb)('>', p) < 0)\n        return (-1);\n\n      col += (int)strlen(current->value.element.name) + 3;\n\n      col = mxml_write_ws(current, p, cb, MXML_WS_AFTER_CLOSE, col, putc_cb);\n    }\n      }\n    }\n  }\n\n  return (col);\n}\n\n\n/*\n * 'mxml_write_string()' - Write a string, escaping & and < as needed.\n */\n\nstatic int\t\t\t\t/* O - 0 on success, -1 on failure */\nmxml_write_string(\n    const char      *s,\t\t\t/* I - String to write */\n    void            *p,\t\t\t/* I - Write pointer */\n    _mxml_putc_cb_t putc_cb)\t\t/* I - Write callback */\n{\n  const char\t*name;\t\t\t/* Entity name, if any */\n\n\n  while (*s)\n  {\n    if ((name = mxmlEntityGetName(*s)) != NULL)\n    {\n      if ((*putc_cb)('&', p) < 0)\n        return (-1);\n\n      while (*name)\n      {\n    if ((*putc_cb)(*name, p) < 0)\n          return (-1);\n        name ++;\n      }\n\n      if ((*putc_cb)(';', p) < 0)\n        return (-1);\n    }\n    else if ((*putc_cb)(*s, p) < 0)\n      return (-1);\n\n    s ++;\n  }\n\n  return (0);\n}\n\n\n/*\n * 'mxml_write_ws()' - Do whitespace callback...\n */\n\nstatic int\t\t\t\t/* O - New column */\nmxml_write_ws(mxml_node_t     *node,\t/* I - Current node */\n              void            *p,\t/* I - Write pointer */\n              mxml_save_cb_t  cb,\t/* I - Callback function */\n          int             ws,\t/* I - Where value */\n          int             col,\t/* I - Current column */\n              _mxml_putc_cb_t putc_cb)\t/* I - Write callback */\n{\n  const char\t*s;\t\t\t/* Whitespace string */\n\n\n  if (cb && (s = (*cb)(node, ws)) != NULL)\n  {\n    while (*s)\n    {\n      if ((*putc_cb)(*s, p) < 0)\n    return (-1);\n      else if (*s == '\\n')\n    col = 0;\n      else if (*s == '\\t')\n      {\n    col += MXML_TAB;\n    col = col - (col % MXML_TAB);\n      }\n      else\n    col ++;\n\n      s ++;\n    }\n  }\n\n  return (col);\n}\n\n\n/*\n * End of \"$Id: mxml-file.c 467 2016-06-13 00:51:16Z msweet $\".\n */\n"
  },
  {
    "path": "third_party/phlib/mxml/mxml-get.c",
    "content": "/*\n * \"$Id: mxml-get.c 451 2014-01-04 21:50:06Z msweet $\"\n *\n * Node get functions for Mini-XML, a small XML-like file parsing library.\n *\n * Copyright 2014 by Michael R Sweet.\n *\n * These coded instructions, statements, and computer programs are the\n * property of Michael R Sweet and are protected by Federal copyright\n * law.  Distribution and use rights are outlined in the file \"COPYING\"\n * which should have been included with this file.  If this file is\n * missing or damaged, see the license at:\n *\n *     http://www.msweet.org/projects.php/Mini-XML\n */\n\n/*\n * Include necessary headers...\n */\n\n#include \"config.h\"\n#include \"mxml.h\"\n\n\n/*\n * 'mxmlGetCDATA()' - Get the value for a CDATA node.\n *\n * @code NULL@ is returned if the node is not a CDATA element.\n *\n * @since Mini-XML 2.7@\n */\n\nconst char *\t\t\t\t/* O - CDATA value or NULL */\nmxmlGetCDATA(mxml_node_t *node)\t\t/* I - Node to get */\n{\n /*\n  * Range check input...\n  */\n\n  if (!node || node->type != MXML_ELEMENT ||\n      strncmp(node->value.element.name, \"![CDATA[\", 8))\n    return (NULL);\n\n /*\n  * Return the text following the CDATA declaration...\n  */\n\n  return (node->value.element.name + 8);\n}\n\n\n/*\n * 'mxmlGetCustom()' - Get the value for a custom node.\n *\n * @code NULL@ is returned if the node (or its first child) is not a custom\n * value node.\n *\n * @since Mini-XML 2.7@\n */\n\nconst void *\t\t\t\t/* O - Custom value or NULL */\nmxmlGetCustom(mxml_node_t *node)\t/* I - Node to get */\n{\n /*\n  * Range check input...\n  */\n\n  if (!node)\n    return (NULL);\n\n /*\n  * Return the integer value...\n  */\n\n  if (node->type == MXML_CUSTOM)\n    return (node->value.custom.data);\n  else if (node->type == MXML_ELEMENT &&\n           node->child &&\n\t   node->child->type == MXML_CUSTOM)\n    return (node->child->value.custom.data);\n  else\n    return (NULL);\n}\n\n\n/*\n * 'mxmlGetElement()' - Get the name for an element node.\n *\n * @code NULL@ is returned if the node is not an element node.\n *\n * @since Mini-XML 2.7@\n */\n\nconst char *\t\t\t\t/* O - Element name or NULL */\nmxmlGetElement(mxml_node_t *node)\t/* I - Node to get */\n{\n /*\n  * Range check input...\n  */\n\n  if (!node || node->type != MXML_ELEMENT)\n    return (NULL);\n\n /*\n  * Return the element name...\n  */\n\n  return (node->value.element.name);\n}\n\n\n/*\n * 'mxmlGetFirstChild()' - Get the first child of an element node.\n *\n * @code NULL@ is returned if the node is not an element node or if the node\n * has no children.\n *\n * @since Mini-XML 2.7@\n */\n\nmxml_node_t *\t\t\t\t/* O - First child or NULL */\nmxmlGetFirstChild(mxml_node_t *node)\t/* I - Node to get */\n{\n /*\n  * Range check input...\n  */\n\n  if (!node || node->type != MXML_ELEMENT)\n    return (NULL);\n\n /*\n  * Return the first child node...\n  */\n\n  return (node->child);\n}\n\n\n/*\n * 'mxmlGetInteger()' - Get the integer value from the specified node or its\n *                      first child.\n *\n * 0 is returned if the node (or its first child) is not an integer value node.\n *\n * @since Mini-XML 2.7@\n */\n\nint\t\t\t\t\t/* O - Integer value or 0 */\nmxmlGetInteger(mxml_node_t *node)\t/* I - Node to get */\n{\n /*\n  * Range check input...\n  */\n\n  if (!node)\n    return (0);\n\n /*\n  * Return the integer value...\n  */\n\n  if (node->type == MXML_INTEGER)\n    return (node->value.integer);\n  else if (node->type == MXML_ELEMENT &&\n           node->child &&\n\t   node->child->type == MXML_INTEGER)\n    return (node->child->value.integer);\n  else\n    return (0);\n}\n\n\n/*\n * 'mxmlGetLastChild()' - Get the last child of an element node.\n *\n * @code NULL@ is returned if the node is not an element node or if the node\n * has no children.\n *\n * @since Mini-XML 2.7@\n */\n\nmxml_node_t *\t\t\t\t/* O - Last child or NULL */\nmxmlGetLastChild(mxml_node_t *node)\t/* I - Node to get */\n{\n /*\n  * Range check input...\n  */\n\n  if (!node || node->type != MXML_ELEMENT)\n    return (NULL);\n\n /*\n  * Return the node type...\n  */\n\n  return (node->last_child);\n}\n\n\n/*\n * 'mxmlGetNextSibling()' - Get the next node for the current parent.\n *\n * @code NULL@ is returned if this is the last child for the current parent.\n *\n * @since Mini-XML 2.7@\n */\n\nmxml_node_t *\nmxmlGetNextSibling(mxml_node_t *node)\t/* I - Node to get */\n{\n /*\n  * Range check input...\n  */\n\n  if (!node)\n    return (NULL);\n\n /*\n  * Return the node type...\n  */\n\n  return (node->next);\n}\n\n\n/*\n * 'mxmlGetOpaque()' - Get an opaque string value for a node or its first child.\n *\n * @code NULL@ is returned if the node (or its first child) is not an opaque\n * value node.\n *\n * @since Mini-XML 2.7@\n */\n\nconst char *\t\t\t\t/* O - Opaque string or NULL */\nmxmlGetOpaque(mxml_node_t *node)\t/* I - Node to get */\n{\n /*\n  * Range check input...\n  */\n\n  if (!node)\n    return (NULL);\n\n /*\n  * Return the integer value...\n  */\n\n  if (node->type == MXML_OPAQUE)\n    return (node->value.opaque);\n  else if (node->type == MXML_ELEMENT &&\n           node->child &&\n\t   node->child->type == MXML_OPAQUE)\n    return (node->child->value.opaque);\n  else\n    return (NULL);\n}\n\n\n/*\n * 'mxmlGetParent()' - Get the parent node.\n *\n * @code NULL@ is returned for a root node.\n *\n * @since Mini-XML 2.7@\n */\n\nmxml_node_t *\t\t\t\t/* O - Parent node or NULL */\nmxmlGetParent(mxml_node_t *node)\t/* I - Node to get */\n{\n /*\n  * Range check input...\n  */\n\n  if (!node)\n    return (NULL);\n\n /*\n  * Return the node type...\n  */\n\n  return (node->parent);\n}\n\n\n/*\n * 'mxmlGetPrevSibling()' - Get the previous node for the current parent.\n *\n * @code NULL@ is returned if this is the first child for the current parent.\n *\n * @since Mini-XML 2.7@\n */\n\nmxml_node_t *\t\t\t\t/* O - Previous node or NULL */\nmxmlGetPrevSibling(mxml_node_t *node)\t/* I - Node to get */\n{\n /*\n  * Range check input...\n  */\n\n  if (!node)\n    return (NULL);\n\n /*\n  * Return the node type...\n  */\n\n  return (node->prev);\n}\n\n\n/*\n * 'mxmlGetReal()' - Get the real value for a node or its first child.\n *\n * 0.0 is returned if the node (or its first child) is not a real value node.\n *\n * @since Mini-XML 2.7@\n */\n\ndouble\t\t\t\t\t/* O - Real value or 0.0 */\nmxmlGetReal(mxml_node_t *node)\t\t/* I - Node to get */\n{\n /*\n  * Range check input...\n  */\n\n  if (!node)\n    return (0.0);\n\n /*\n  * Return the integer value...\n  */\n\n  if (node->type == MXML_REAL)\n    return (node->value.real);\n  else if (node->type == MXML_ELEMENT &&\n           node->child &&\n\t   node->child->type == MXML_REAL)\n    return (node->child->value.real);\n  else\n    return (0.0);\n}\n\n\n/*\n * 'mxmlGetText()' - Get the text value for a node or its first child.\n *\n * @code NULL@ is returned if the node (or its first child) is not a text node.\n * The \"whitespace\" argument can be NULL.\n *\n * @since Mini-XML 2.7@\n */\n\nconst char *\t\t\t\t/* O - Text string or NULL */\nmxmlGetText(mxml_node_t *node,\t\t/* I - Node to get */\n            int         *whitespace)\t/* O - 1 if string is preceded by whitespace, 0 otherwise */\n{\n /*\n  * Range check input...\n  */\n\n  if (!node)\n  {\n    if (whitespace)\n      *whitespace = 0;\n\n    return (NULL);\n  }\n\n /*\n  * Return the integer value...\n  */\n\n  if (node->type == MXML_TEXT)\n  {\n    if (whitespace)\n      *whitespace = node->value.text.whitespace;\n\n    return (node->value.text.string);\n  }\n  else if (node->type == MXML_ELEMENT &&\n           node->child &&\n\t   node->child->type == MXML_TEXT)\n  {\n    if (whitespace)\n      *whitespace = node->child->value.text.whitespace;\n\n    return (node->child->value.text.string);\n  }\n  else\n  {\n    if (whitespace)\n      *whitespace = 0;\n\n    return (NULL);\n  }\n}\n\n\n/*\n * 'mxmlGetType()' - Get the node type.\n *\n * @code MXML_IGNORE@ is returned if \"node\" is @code NULL@.\n *\n * @since Mini-XML 2.7@\n */\n\nmxml_type_t\t\t\t\t/* O - Type of node */\nmxmlGetType(mxml_node_t *node)\t\t/* I - Node to get */\n{\n /*\n  * Range check input...\n  */\n\n  if (!node)\n    return (MXML_IGNORE);\n\n /*\n  * Return the node type...\n  */\n\n  return (node->type);\n}\n\n\n/*\n * 'mxmlGetUserData()' - Get the user data pointer for a node.\n *\n * @since Mini-XML 2.7@\n */\n\nvoid *\t\t\t\t\t/* O - User data pointer */\nmxmlGetUserData(mxml_node_t *node)\t/* I - Node to get */\n{\n /*\n  * Range check input...\n  */\n\n  if (!node)\n    return (NULL);\n\n /*\n  * Return the user data pointer...\n  */\n\n  return (node->user_data);\n}\n\n\n/*\n * End of \"$Id: mxml-get.c 451 2014-01-04 21:50:06Z msweet $\".\n */\n"
  },
  {
    "path": "third_party/phlib/mxml/mxml-index.c",
    "content": "/*\n * \"$Id: mxml-index.c 451 2014-01-04 21:50:06Z msweet $\"\n *\n * Index support code for Mini-XML, a small XML-like file parsing library.\n *\n * Copyright 2003-2014 by Michael R Sweet.\n *\n * These coded instructions, statements, and computer programs are the\n * property of Michael R Sweet and are protected by Federal copyright\n * law.  Distribution and use rights are outlined in the file \"COPYING\"\n * which should have been included with this file.  If this file is\n * missing or damaged, see the license at:\n *\n *     http://www.msweet.org/projects.php/Mini-XML\n */\n\n/*\n * Include necessary headers...\n */\n\n#include <phbase.h>\n#include \"config.h\"\n#include \"mxml.h\"\n\n\n/*\n * Sort functions...\n */\n\nstatic int\tindex_compare(mxml_index_t *ind, mxml_node_t *first,\n                      mxml_node_t *second);\nstatic int\tindex_find(mxml_index_t *ind, const char *element,\n                   const char *value, mxml_node_t *node);\nstatic void\tindex_sort(mxml_index_t *ind, int left, int right);\n\n\n/*\n * 'mxmlIndexDelete()' - Delete an index.\n */\n\nvoid\nmxmlIndexDelete(mxml_index_t *ind)\t/* I - Index to delete */\n{\n /*\n  * Range check input..\n  */\n\n  if (!ind)\n    return;\n\n /*\n  * Free memory...\n  */\n\n  if (ind->attr)\n    PhFree(ind->attr);\n\n  if (ind->alloc_nodes)\n    PhFree(ind->nodes);\n\n  PhFree(ind);\n}\n\n\n/*\n * 'mxmlIndexEnum()' - Return the next node in the index.\n *\n * Nodes are returned in the sorted order of the index.\n */\n\nmxml_node_t *\t\t\t\t/* O - Next node or NULL if there is none */\nmxmlIndexEnum(mxml_index_t *ind)\t/* I - Index to enumerate */\n{\n /*\n  * Range check input...\n  */\n\n  if (!ind)\n    return (NULL);\n\n /*\n  * Return the next node...\n  */\n\n  if (ind->cur_node < ind->num_nodes)\n    return (ind->nodes[ind->cur_node ++]);\n  else\n    return (NULL);\n}\n\n\n/*\n * 'mxmlIndexFind()' - Find the next matching node.\n *\n * You should call mxmlIndexReset() prior to using this function for\n * the first time with a particular set of \"element\" and \"value\"\n * strings. Passing NULL for both \"element\" and \"value\" is equivalent\n * to calling mxmlIndexEnum().\n */\n\nmxml_node_t *\t\t\t\t/* O - Node or NULL if none found */\nmxmlIndexFind(mxml_index_t *ind,\t/* I - Index to search */\n              const char   *element,\t/* I - Element name to find, if any */\n          const char   *value)\t/* I - Attribute value, if any */\n{\n  int\t\tdiff,\t\t\t/* Difference between names */\n        current,\t\t/* Current entity in search */\n        first,\t\t\t/* First entity in search */\n        last;\t\t\t/* Last entity in search */\n\n\n#if DEBUG > 1\n  printf(\"mxmlIndexFind(ind=%p, element=\\\"%s\\\", value=\\\"%s\\\")\\n\",\n         ind, element ? element : \"(null)\", value ? value : \"(null)\");\n#endif /* DEBUG */\n\n /*\n  * Range check input...\n  */\n\n  if (!ind || (!ind->attr && value))\n  {\n#if DEBUG > 1\n    puts(\"    returning NULL...\");\n    printf(\"    ind->attr=\\\"%s\\\"\\n\", ind->attr ? ind->attr : \"(null)\");\n#endif /* DEBUG */\n\n    return (NULL);\n  }\n\n /*\n  * If both element and value are NULL, just enumerate the nodes in the\n  * index...\n  */\n\n  if (!element && !value)\n    return (mxmlIndexEnum(ind));\n\n /*\n  * If there are no nodes in the index, return NULL...\n  */\n\n  if (!ind->num_nodes)\n  {\n#if DEBUG > 1\n    puts(\"    returning NULL...\");\n    puts(\"    no nodes!\");\n#endif /* DEBUG */\n\n    return (NULL);\n  }\n\n /*\n  * If cur_node == 0, then find the first matching node...\n  */\n\n  if (ind->cur_node == 0)\n  {\n   /*\n    * Find the first node using a modified binary search algorithm...\n    */\n\n    first = 0;\n    last  = ind->num_nodes - 1;\n\n#if DEBUG > 1\n    printf(\"    find first time, num_nodes=%d...\\n\", ind->num_nodes);\n#endif /* DEBUG */\n\n    while ((last - first) > 1)\n    {\n      current = (first + last) / 2;\n\n#if DEBUG > 1\n      printf(\"    first=%d, last=%d, current=%d\\n\", first, last, current);\n#endif /* DEBUG */\n\n      if ((diff = index_find(ind, element, value, ind->nodes[current])) == 0)\n      {\n       /*\n        * Found a match, move back to find the first...\n    */\n\n#if DEBUG > 1\n        puts(\"    match!\");\n#endif /* DEBUG */\n\n        while (current > 0 &&\n           !index_find(ind, element, value, ind->nodes[current - 1]))\n      current --;\n\n#if DEBUG > 1\n        printf(\"    returning first match=%d\\n\", current);\n#endif /* DEBUG */\n\n       /*\n        * Return the first match and save the index to the next...\n    */\n\n        ind->cur_node = current + 1;\n\n    return (ind->nodes[current]);\n      }\n      else if (diff < 0)\n    last = current;\n      else\n    first = current;\n\n#if DEBUG > 1\n      printf(\"    diff=%d\\n\", diff);\n#endif /* DEBUG */\n    }\n\n   /*\n    * If we get this far, then we found exactly 0 or 1 matches...\n    */\n\n    for (current = first; current <= last; current ++)\n      if (!index_find(ind, element, value, ind->nodes[current]))\n      {\n       /*\n    * Found exactly one (or possibly two) match...\n    */\n\n#if DEBUG > 1\n    printf(\"    returning only match %d...\\n\", current);\n#endif /* DEBUG */\n\n    ind->cur_node = current + 1;\n\n    return (ind->nodes[current]);\n      }\n\n   /*\n    * No matches...\n    */\n\n    ind->cur_node = ind->num_nodes;\n\n#if DEBUG > 1\n    puts(\"    returning NULL...\");\n#endif /* DEBUG */\n\n    return (NULL);\n  }\n  else if (ind->cur_node < ind->num_nodes &&\n           !index_find(ind, element, value, ind->nodes[ind->cur_node]))\n  {\n   /*\n    * Return the next matching node...\n    */\n\n#if DEBUG > 1\n    printf(\"    returning next match %d...\\n\", ind->cur_node);\n#endif /* DEBUG */\n\n    return (ind->nodes[ind->cur_node ++]);\n  }\n\n /*\n  * If we get this far, then we have no matches...\n  */\n\n  ind->cur_node = ind->num_nodes;\n\n#if DEBUG > 1\n  puts(\"    returning NULL...\");\n#endif /* DEBUG */\n\n  return (NULL);\n}\n\n\n/*\n * 'mxmlIndexGetCount()' - Get the number of nodes in an index.\n *\n * @since Mini-XML 2.7@\n */\n\nint\t\t\t\t\t/* I - Number of nodes in index */\nmxmlIndexGetCount(mxml_index_t *ind)\t/* I - Index of nodes */\n{\n /*\n  * Range check input...\n  */\n\n  if (!ind)\n    return (0);\n\n /*\n  * Return the number of nodes in the index...\n  */\n\n  return (ind->num_nodes);\n}\n\n\n/*\n * 'mxmlIndexNew()' - Create a new index.\n *\n * The index will contain all nodes that contain the named element and/or\n * attribute. If both \"element\" and \"attr\" are NULL, then the index will\n * contain a sorted list of the elements in the node tree.  Nodes are\n * sorted by element name and optionally by attribute value if the \"attr\"\n * argument is not NULL.\n */\n\nmxml_index_t *\t\t\t\t/* O - New index */\nmxmlIndexNew(mxml_node_t *node,\t\t/* I - XML node tree */\n             const char  *element,\t/* I - Element to index or NULL for all */\n             const char  *attr)\t\t/* I - Attribute to index or NULL for none */\n{\n  mxml_index_t\t*ind;\t\t\t/* New index */\n  mxml_node_t\t*current,\t\t/* Current node in index */\n        **temp;\t\t\t/* Temporary node pointer array */\n\n\n /*\n  * Range check input...\n  */\n\n#if DEBUG > 1\n  printf(\"mxmlIndexNew(node=%p, element=\\\"%s\\\", attr=\\\"%s\\\")\\n\",\n         node, element ? element : \"(null)\", attr ? attr : \"(null)\");\n#endif /* DEBUG */\n\n  if (!node)\n    return (NULL);\n\n /*\n  * Create a new index...\n  */\n\n  if ((ind = PhAllocateExSafe(sizeof(mxml_index_t), HEAP_ZERO_MEMORY)) == NULL)\n  {\n    mxml_error(\"Unable to allocate %d bytes for index - %s\",\n               sizeof(mxml_index_t), strerror(errno));\n    return (NULL);\n  }\n\n  if (attr)\n    ind->attr = PhDuplicateBytesZSafe((char *)attr);\n\n  if (!element && !attr)\n    current = node;\n  else\n    current = mxmlFindElement(node, node, element, attr, NULL, MXML_DESCEND);\n\n  while (current)\n  {\n    if (ind->num_nodes >= ind->alloc_nodes)\n    {\n      if (!ind->alloc_nodes)\n        temp = PhAllocateSafe(64 * sizeof(mxml_node_t *));\n      else\n        temp = PhReAllocateSafe(ind->nodes, (ind->alloc_nodes + 64) * sizeof(mxml_node_t *));\n\n      if (!temp)\n      {\n       /*\n        * Unable to allocate memory for the index, so abort...\n    */\n\n        mxml_error(\"Unable to allocate %d bytes for index: %s\",\n               (ind->alloc_nodes + 64) * sizeof(mxml_node_t *),\n           strerror(errno));\n\n        mxmlIndexDelete(ind);\n    return (NULL);\n      }\n\n      ind->nodes       = temp;\n      ind->alloc_nodes += 64;\n    }\n\n    ind->nodes[ind->num_nodes ++] = current;\n\n    current = mxmlFindElement(current, node, element, attr, NULL, MXML_DESCEND);\n  }\n\n /*\n  * Sort nodes based upon the search criteria...\n  */\n\n#if DEBUG > 1\n  {\n    int i;\t\t\t\t/* Looping var */\n\n\n    printf(\"%d node(s) in index.\\n\\n\", ind->num_nodes);\n\n    if (attr)\n    {\n      printf(\"Node      Address   Element         %s\\n\", attr);\n      puts(\"--------  --------  --------------  ------------------------------\");\n\n      for (i = 0; i < ind->num_nodes; i ++)\n    printf(\"%8d  %-8p  %-14.14s  %s\\n\", i, ind->nodes[i],\n           ind->nodes[i]->value.element.name,\n           mxmlElementGetAttr(ind->nodes[i], attr));\n    }\n    else\n    {\n      puts(\"Node      Address   Element\");\n      puts(\"--------  --------  --------------\");\n\n      for (i = 0; i < ind->num_nodes; i ++)\n    printf(\"%8d  %-8p  %s\\n\", i, ind->nodes[i],\n           ind->nodes[i]->value.element.name);\n    }\n\n    putchar('\\n');\n  }\n#endif /* DEBUG */\n\n  if (ind->num_nodes > 1)\n    index_sort(ind, 0, ind->num_nodes - 1);\n\n#if DEBUG > 1\n  {\n    int i;\t\t\t\t/* Looping var */\n\n\n    puts(\"After sorting:\\n\");\n\n    if (attr)\n    {\n      printf(\"Node      Address   Element         %s\\n\", attr);\n      puts(\"--------  --------  --------------  ------------------------------\");\n\n      for (i = 0; i < ind->num_nodes; i ++)\n    printf(\"%8d  %-8p  %-14.14s  %s\\n\", i, ind->nodes[i],\n           ind->nodes[i]->value.element.name,\n           mxmlElementGetAttr(ind->nodes[i], attr));\n    }\n    else\n    {\n      puts(\"Node      Address   Element\");\n      puts(\"--------  --------  --------------\");\n\n      for (i = 0; i < ind->num_nodes; i ++)\n    printf(\"%8d  %-8p  %s\\n\", i, ind->nodes[i],\n           ind->nodes[i]->value.element.name);\n    }\n\n    putchar('\\n');\n  }\n#endif /* DEBUG */\n\n /*\n  * Return the new index...\n  */\n\n  return (ind);\n}\n\n\n/*\n * 'mxmlIndexReset()' - Reset the enumeration/find pointer in the index and\n *                      return the first node in the index.\n *\n * This function should be called prior to using mxmlIndexEnum() or\n * mxmlIndexFind() for the first time.\n */\n\nmxml_node_t *\t\t\t\t/* O - First node or NULL if there is none */\nmxmlIndexReset(mxml_index_t *ind)\t/* I - Index to reset */\n{\n#if DEBUG > 1\n  printf(\"mxmlIndexReset(ind=%p)\\n\", ind);\n#endif /* DEBUG */\n\n /*\n  * Range check input...\n  */\n\n  if (!ind)\n    return (NULL);\n\n /*\n  * Set the index to the first element...\n  */\n\n  ind->cur_node = 0;\n\n /*\n  * Return the first node...\n  */\n\n  if (ind->num_nodes)\n    return (ind->nodes[0]);\n  else\n    return (NULL);\n}\n\n\n/*\n * 'index_compare()' - Compare two nodes.\n */\n\nstatic int\t\t\t\t/* O - Result of comparison */\nindex_compare(mxml_index_t *ind,\t/* I - Index */\n              mxml_node_t  *first,\t/* I - First node */\n              mxml_node_t  *second)\t/* I - Second node */\n{\n  int\tdiff;\t\t\t\t/* Difference */\n\n\n /*\n  * Check the element name...\n  */\n\n  if ((diff = strcmp(first->value.element.name,\n                     second->value.element.name)) != 0)\n    return (diff);\n\n /*\n  * Check the attribute value...\n  */\n\n  if (ind->attr)\n  {\n    if ((diff = strcmp(mxmlElementGetAttr(first, ind->attr),\n                       mxmlElementGetAttr(second, ind->attr))) != 0)\n      return (diff);\n  }\n\n /*\n  * No difference, return 0...\n  */\n\n  return (0);\n}\n\n\n/*\n * 'index_find()' - Compare a node with index values.\n */\n\nstatic int\t\t\t\t/* O - Result of comparison */\nindex_find(mxml_index_t *ind,\t\t/* I - Index */\n           const char   *element,\t/* I - Element name or NULL */\n       const char   *value,\t\t/* I - Attribute value or NULL */\n           mxml_node_t  *node)\t\t/* I - Node */\n{\n  int\tdiff;\t\t\t\t/* Difference */\n\n\n /*\n  * Check the element name...\n  */\n\n  if (element)\n  {\n    if ((diff = strcmp(element, node->value.element.name)) != 0)\n      return (diff);\n  }\n\n /*\n  * Check the attribute value...\n  */\n\n  if (value)\n  {\n    if ((diff = strcmp(value, mxmlElementGetAttr(node, ind->attr))) != 0)\n      return (diff);\n  }\n\n /*\n  * No difference, return 0...\n  */\n\n  return (0);\n}\n\n\n/*\n * 'index_sort()' - Sort the nodes in the index...\n *\n * This function implements the classic quicksort algorithm...\n */\n\nstatic void\nindex_sort(mxml_index_t *ind,\t\t/* I - Index to sort */\n           int          left,\t\t/* I - Left node in partition */\n       int          right)\t\t/* I - Right node in partition */\n{\n  mxml_node_t\t*pivot,\t\t\t/* Pivot node */\n        *temp;\t\t\t/* Swap node */\n  int\t\ttempl,\t\t\t/* Temporary left node */\n        tempr;\t\t\t/* Temporary right node */\n\n\n /*\n  * Loop until we have sorted all the way to the right...\n  */\n\n  do\n  {\n   /*\n    * Sort the pivot in the current partition...\n    */\n\n    pivot = ind->nodes[left];\n\n    for (templ = left, tempr = right; templ < tempr;)\n    {\n     /*\n      * Move left while left node <= pivot node...\n      */\n\n      while ((templ < right) &&\n             index_compare(ind, ind->nodes[templ], pivot) <= 0)\n    templ ++;\n\n     /*\n      * Move right while right node > pivot node...\n      */\n\n      while ((tempr > left) &&\n             index_compare(ind, ind->nodes[tempr], pivot) > 0)\n    tempr --;\n\n     /*\n      * Swap nodes if needed...\n      */\n\n      if (templ < tempr)\n      {\n    temp              = ind->nodes[templ];\n    ind->nodes[templ] = ind->nodes[tempr];\n    ind->nodes[tempr] = temp;\n      }\n    }\n\n   /*\n    * When we get here, the right (tempr) node is the new position for the\n    * pivot node...\n    */\n\n    if (index_compare(ind, pivot, ind->nodes[tempr]) > 0)\n    {\n      ind->nodes[left]  = ind->nodes[tempr];\n      ind->nodes[tempr] = pivot;\n    }\n\n   /*\n    * Recursively sort the left partition as needed...\n    */\n\n    if (left < (tempr - 1))\n      index_sort(ind, left, tempr - 1);\n  }\n  while (right > (left = tempr + 1));\n}\n\n\n/*\n * End of \"$Id: mxml-index.c 451 2014-01-04 21:50:06Z msweet $\".\n */\n"
  },
  {
    "path": "third_party/phlib/mxml/mxml-node.c",
    "content": "/*\n * \"$Id: mxml-node.c 462 2016-06-11 20:51:49Z msweet $\"\n *\n * Node support code for Mini-XML, a small XML-like file parsing library.\n *\n * Copyright 2003-2016 by Michael R Sweet.\n *\n * These coded instructions, statements, and computer programs are the\n * property of Michael R Sweet and are protected by Federal copyright\n * law.  Distribution and use rights are outlined in the file \"COPYING\"\n * which should have been included with this file.  If this file is\n * missing or damaged, see the license at:\n *\n *     http://www.msweet.org/projects.php/Mini-XML\n */\n\n/*\n * Include necessary headers...\n */\n\n#include <phbase.h>\n#include \"config.h\"\n#include \"mxml.h\"\n\n\n/*\n * Local functions...\n */\n\nstatic void\t\tmxml_free(mxml_node_t *node);\nstatic mxml_node_t\t*mxml_new(mxml_node_t *parent, mxml_type_t type);\n\n\n/*\n * 'mxmlAdd()' - Add a node to a tree.\n *\n * Adds the specified node to the parent. If the child argument is not\n * NULL, puts the new node before or after the specified child depending\n * on the value of the where argument. If the child argument is NULL,\n * puts the new node at the beginning of the child list (MXML_ADD_BEFORE)\n * or at the end of the child list (MXML_ADD_AFTER). The constant\n * MXML_ADD_TO_PARENT can be used to specify a NULL child pointer.\n */\n\nvoid\nmxmlAdd(mxml_node_t *parent,\t\t/* I - Parent node */\n        int         where,\t\t/* I - Where to add, MXML_ADD_BEFORE or MXML_ADD_AFTER */\n        mxml_node_t *child,\t\t/* I - Child node for where or MXML_ADD_TO_PARENT */\n    mxml_node_t *node)\t\t/* I - Node to add */\n{\n#if DEBUG > 1\n  fprintf(stderr, \"mxmlAdd(parent=%p, where=%d, child=%p, node=%p)\\n\", parent,\n          where, child, node);\n#endif /* DEBUG */\n\n /*\n  * Range check input...\n  */\n\n  if (!parent || !node)\n    return;\n\n#if DEBUG > 1\n  fprintf(stderr, \"    BEFORE: node->parent=%p\\n\", node->parent);\n  if (parent)\n  {\n    fprintf(stderr, \"    BEFORE: parent->child=%p\\n\", parent->child);\n    fprintf(stderr, \"    BEFORE: parent->last_child=%p\\n\", parent->last_child);\n    fprintf(stderr, \"    BEFORE: parent->prev=%p\\n\", parent->prev);\n    fprintf(stderr, \"    BEFORE: parent->next=%p\\n\", parent->next);\n  }\n#endif /* DEBUG > 1 */\n\n /*\n  * Remove the node from any existing parent...\n  */\n\n  if (node->parent)\n    mxmlRemove(node);\n\n /*\n  * Reset pointers...\n  */\n\n  node->parent = parent;\n\n  switch (where)\n  {\n    case MXML_ADD_BEFORE :\n        if (!child || child == parent->child || child->parent != parent)\n    {\n     /*\n      * Insert as first node under parent...\n      */\n\n      node->next = parent->child;\n\n      if (parent->child)\n        parent->child->prev = node;\n      else\n        parent->last_child = node;\n\n      parent->child = node;\n    }\n    else\n    {\n     /*\n      * Insert node before this child...\n      */\n\n      node->next = child;\n      node->prev = child->prev;\n\n      if (child->prev)\n        child->prev->next = node;\n      else\n        parent->child = node;\n\n      child->prev = node;\n    }\n        break;\n\n    case MXML_ADD_AFTER :\n        if (!child || child == parent->last_child || child->parent != parent)\n    {\n     /*\n      * Insert as last node under parent...\n      */\n\n      node->parent = parent;\n      node->prev   = parent->last_child;\n\n      if (parent->last_child)\n        parent->last_child->next = node;\n      else\n        parent->child = node;\n\n      parent->last_child = node;\n        }\n    else\n    {\n     /*\n      * Insert node after this child...\n      */\n\n      node->prev = child;\n      node->next = child->next;\n\n      if (child->next)\n        child->next->prev = node;\n      else\n        parent->last_child = node;\n\n      child->next = node;\n    }\n        break;\n  }\n\n#if DEBUG > 1\n  fprintf(stderr, \"    AFTER: node->parent=%p\\n\", node->parent);\n  if (parent)\n  {\n    fprintf(stderr, \"    AFTER: parent->child=%p\\n\", parent->child);\n    fprintf(stderr, \"    AFTER: parent->last_child=%p\\n\", parent->last_child);\n    fprintf(stderr, \"    AFTER: parent->prev=%p\\n\", parent->prev);\n    fprintf(stderr, \"    AFTER: parent->next=%p\\n\", parent->next);\n  }\n#endif /* DEBUG > 1 */\n}\n\n\n/*\n * 'mxmlDelete()' - Delete a node and all of its children.\n *\n * If the specified node has a parent, this function first removes the\n * node from its parent using the mxmlRemove() function.\n */\n\nvoid\nmxmlDelete(mxml_node_t *node)\t\t/* I - Node to delete */\n{\n  mxml_node_t\t*current,\t\t/* Current node */\n        *next;\t\t\t/* Next node */\n\n\n#if DEBUG > 1\n  fprintf(stderr, \"mxmlDelete(node=%p)\\n\", node);\n#endif /* DEBUG */\n\n /*\n  * Range check input...\n  */\n\n  if (!node)\n    return;\n\n /*\n  * Remove the node from its parent, if any...\n  */\n\n  mxmlRemove(node);\n\n /*\n  * Delete children...\n  */\n\n  for (current = node->child; current; current = next)\n  {\n   /*\n    * Get the next node...\n    */\n\n    if ((next = current->child) != NULL)\n    {\n     /*\n      * Free parent nodes after child nodes have been freed...\n      */\n\n      current->child = NULL;\n      continue;\n    }\n\n    if ((next = current->next) == NULL)\n    {\n      mxml_node_t *temp = current->parent;\n                    /* Pointer to parent node */\n\n      if (temp == node)\n      {\n       /*\n        * Got back to the top node...\n        */\n\n        next = NULL;\n      }\n      else if ((next = temp->next) == NULL)\n      {\n    if ((next = temp->parent) == node)\n      next = NULL;\n      }\n    }\n\n    mxml_free(current);\n  }\n\n /*\n  * Then free the memory used by this node...\n  */\n\n  mxml_free(node);\n}\n\n\n/*\n * 'mxmlGetRefCount()' - Get the current reference (use) count for a node.\n *\n * The initial reference count of new nodes is 1. Use the @link mxmlRetain@\n * and @link mxmlRelease@ functions to increment and decrement a node's\n * reference count.\n *\n * @since Mini-XML 2.7@.\n */\n\nint\t\t\t\t\t/* O - Reference count */\nmxmlGetRefCount(mxml_node_t *node)\t/* I - Node */\n{\n /*\n  * Range check input...\n  */\n\n  if (!node)\n    return (0);\n\n /*\n  * Return the reference count...\n  */\n\n  return (node->ref_count);\n}\n\n\n/*\n * 'mxmlNewCDATA()' - Create a new CDATA node.\n *\n * The new CDATA node is added to the end of the specified parent's child\n * list. The constant MXML_NO_PARENT can be used to specify that the new\n * CDATA node has no parent. The data string must be nul-terminated and\n * is copied into the new node. CDATA nodes use the MXML_ELEMENT type.\n *\n * @since Mini-XML 2.3@\n */\n\nmxml_node_t *\t\t\t\t/* O - New node */\nmxmlNewCDATA(mxml_node_t *parent,\t/* I - Parent node or MXML_NO_PARENT */\n         const char  *data)\t\t/* I - Data string */\n{\n  mxml_node_t\t*node;\t\t\t/* New node */\n\n\n#if DEBUG > 1\n  fprintf(stderr, \"mxmlNewCDATA(parent=%p, data=\\\"%s\\\")\\n\",\n          parent, data ? data : \"(null)\");\n#endif /* DEBUG */\n\n /*\n  * Range check input...\n  */\n\n  if (!data)\n    return (NULL);\n\n /*\n  * Create the node and set the name value...\n  */\n\n  if ((node = mxml_new(parent, MXML_ELEMENT)) != NULL)\n    node->value.element.name = _mxml_strdupf(\"![CDATA[%s]]\", data);\n\n  return (node);\n}\n\n\n/*\n * 'mxmlNewCustom()' - Create a new custom data node.\n *\n * The new custom node is added to the end of the specified parent's child\n * list. The constant MXML_NO_PARENT can be used to specify that the new\n * element node has no parent. NULL can be passed when the data in the\n * node is not dynamically allocated or is separately managed.\n *\n * @since Mini-XML 2.1@\n */\n\nmxml_node_t *\t\t\t\t/* O - New node */\nmxmlNewCustom(\n    mxml_node_t              *parent,\t/* I - Parent node or MXML_NO_PARENT */\n    void                     *data,\t/* I - Pointer to data */\n    mxml_custom_destroy_cb_t destroy)\t/* I - Function to destroy data */\n{\n  mxml_node_t\t*node;\t\t\t/* New node */\n\n\n#if DEBUG > 1\n  fprintf(stderr, \"mxmlNewCustom(parent=%p, data=%p, destroy=%p)\\n\", parent,\n          data, destroy);\n#endif /* DEBUG */\n\n /*\n  * Create the node and set the value...\n  */\n\n  if ((node = mxml_new(parent, MXML_CUSTOM)) != NULL)\n  {\n    node->value.custom.data    = data;\n    node->value.custom.destroy = destroy;\n  }\n\n  return (node);\n}\n\n\n/*\n * 'mxmlNewElement()' - Create a new element node.\n *\n * The new element node is added to the end of the specified parent's child\n * list. The constant MXML_NO_PARENT can be used to specify that the new\n * element node has no parent.\n */\n\nmxml_node_t *\t\t\t\t/* O - New node */\nmxmlNewElement(mxml_node_t *parent,\t/* I - Parent node or MXML_NO_PARENT */\n               const char  *name)\t/* I - Name of element */\n{\n  mxml_node_t\t*node;\t\t\t/* New node */\n\n\n#if DEBUG > 1\n  fprintf(stderr, \"mxmlNewElement(parent=%p, name=\\\"%s\\\")\\n\", parent,\n          name ? name : \"(null)\");\n#endif /* DEBUG */\n\n /*\n  * Range check input...\n  */\n\n  if (!name)\n    return (NULL);\n\n /*\n  * Create the node and set the element name...\n  */\n\n  if ((node = mxml_new(parent, MXML_ELEMENT)) != NULL)\n    node->value.element.name = PhDuplicateBytesZSafe((char *)name);\n\n  return (node);\n}\n\n\n/*\n * 'mxmlNewInteger()' - Create a new integer node.\n *\n * The new integer node is added to the end of the specified parent's child\n * list. The constant MXML_NO_PARENT can be used to specify that the new\n * integer node has no parent.\n */\n\nmxml_node_t *\t\t\t\t/* O - New node */\nmxmlNewInteger(mxml_node_t *parent,\t/* I - Parent node or MXML_NO_PARENT */\n               int         integer)\t/* I - Integer value */\n{\n  mxml_node_t\t*node;\t\t\t/* New node */\n\n\n#if DEBUG > 1\n  fprintf(stderr, \"mxmlNewInteger(parent=%p, integer=%d)\\n\", parent, integer);\n#endif /* DEBUG */\n\n /*\n  * Create the node and set the element name...\n  */\n\n  if ((node = mxml_new(parent, MXML_INTEGER)) != NULL)\n    node->value.integer = integer;\n\n  return (node);\n}\n\n\n/*\n * 'mxmlNewOpaque()' - Create a new opaque string.\n *\n * The new opaque node is added to the end of the specified parent's child\n * list. The constant MXML_NO_PARENT can be used to specify that the new\n * opaque node has no parent. The opaque string must be nul-terminated and\n * is copied into the new node.\n */\n\nmxml_node_t *\t\t\t\t/* O - New node */\nmxmlNewOpaque(mxml_node_t *parent,\t/* I - Parent node or MXML_NO_PARENT */\n              const char  *opaque)\t/* I - Opaque string */\n{\n  mxml_node_t\t*node;\t\t\t/* New node */\n\n\n#if DEBUG > 1\n  fprintf(stderr, \"mxmlNewOpaque(parent=%p, opaque=\\\"%s\\\")\\n\", parent,\n          opaque ? opaque : \"(null)\");\n#endif /* DEBUG */\n\n /*\n  * Range check input...\n  */\n\n  if (!opaque)\n    return (NULL);\n\n /*\n  * Create the node and set the element name...\n  */\n\n  if ((node = mxml_new(parent, MXML_OPAQUE)) != NULL)\n    node->value.opaque = PhDuplicateBytesZSafe((char *)opaque);\n\n  return (node);\n}\n\n\n/*\n * 'mxmlNewReal()' - Create a new real number node.\n *\n * The new real number node is added to the end of the specified parent's\n * child list. The constant MXML_NO_PARENT can be used to specify that\n * the new real number node has no parent.\n */\n\nmxml_node_t *\t\t\t\t/* O - New node */\nmxmlNewReal(mxml_node_t *parent,\t/* I - Parent node or MXML_NO_PARENT */\n            double      real)\t\t/* I - Real number value */\n{\n  mxml_node_t\t*node;\t\t\t/* New node */\n\n\n#if DEBUG > 1\n  fprintf(stderr, \"mxmlNewReal(parent=%p, real=%g)\\n\", parent, real);\n#endif /* DEBUG */\n\n /*\n  * Create the node and set the element name...\n  */\n\n  if ((node = mxml_new(parent, MXML_REAL)) != NULL)\n    node->value.real = real;\n\n  return (node);\n}\n\n\n/*\n * 'mxmlNewText()' - Create a new text fragment node.\n *\n * The new text node is added to the end of the specified parent's child\n * list. The constant MXML_NO_PARENT can be used to specify that the new\n * text node has no parent. The whitespace parameter is used to specify\n * whether leading whitespace is present before the node. The text\n * string must be nul-terminated and is copied into the new node.\n */\n\nmxml_node_t *\t\t\t\t/* O - New node */\nmxmlNewText(mxml_node_t *parent,\t/* I - Parent node or MXML_NO_PARENT */\n            int         whitespace,\t/* I - 1 = leading whitespace, 0 = no whitespace */\n        const char  *string)\t/* I - String */\n{\n  mxml_node_t\t*node;\t\t\t/* New node */\n\n\n#if DEBUG > 1\n  fprintf(stderr, \"mxmlNewText(parent=%p, whitespace=%d, string=\\\"%s\\\")\\n\",\n          parent, whitespace, string ? string : \"(null)\");\n#endif /* DEBUG */\n\n /*\n  * Range check input...\n  */\n\n  if (!string)\n    return (NULL);\n\n /*\n  * Create the node and set the text value...\n  */\n\n  if ((node = mxml_new(parent, MXML_TEXT)) != NULL)\n  {\n    node->value.text.whitespace = whitespace;\n    node->value.text.string     = PhDuplicateBytesZSafe((char *)string);\n  }\n\n  return (node);\n}\n\n\n/*\n * 'mxmlNewTextf()' - Create a new formatted text fragment node.\n *\n * The new text node is added to the end of the specified parent's child\n * list. The constant MXML_NO_PARENT can be used to specify that the new\n * text node has no parent. The whitespace parameter is used to specify\n * whether leading whitespace is present before the node. The format\n * string must be nul-terminated and is formatted into the new node.\n */\n\nmxml_node_t *\t\t\t\t/* O - New node */\nmxmlNewTextf(mxml_node_t *parent,\t/* I - Parent node or MXML_NO_PARENT */\n             int         whitespace,\t/* I - 1 = leading whitespace, 0 = no whitespace */\n         const char  *format,\t/* I - Printf-style frmat string */\n         ...)\t\t\t/* I - Additional args as needed */\n{\n  mxml_node_t\t*node;\t\t\t/* New node */\n  va_list\tap;\t\t\t/* Pointer to arguments */\n\n\n#if DEBUG > 1\n  fprintf(stderr, \"mxmlNewTextf(parent=%p, whitespace=%d, format=\\\"%s\\\", ...)\\n\",\n          parent, whitespace, format ? format : \"(null)\");\n#endif /* DEBUG */\n\n /*\n  * Range check input...\n  */\n\n  if (!format)\n    return (NULL);\n\n /*\n  * Create the node and set the text value...\n  */\n\n  if ((node = mxml_new(parent, MXML_TEXT)) != NULL)\n  {\n    va_start(ap, format);\n\n    node->value.text.whitespace = whitespace;\n    node->value.text.string     = _mxml_vstrdupf(format, ap);\n\n    va_end(ap);\n  }\n\n  return (node);\n}\n\n\n/*\n * 'mxmlRemove()' - Remove a node from its parent.\n *\n * Does not free memory used by the node - use mxmlDelete() for that.\n * This function does nothing if the node has no parent.\n */\n\nvoid\nmxmlRemove(mxml_node_t *node)\t\t/* I - Node to remove */\n{\n#if DEBUG > 1\n  fprintf(stderr, \"mxmlRemove(node=%p)\\n\", node);\n#endif /* DEBUG */\n\n /*\n  * Range check input...\n  */\n\n  if (!node || !node->parent)\n    return;\n\n /*\n  * Remove from parent...\n  */\n\n#if DEBUG > 1\n  fprintf(stderr, \"    BEFORE: node->parent=%p\\n\", node->parent);\n  if (node->parent)\n  {\n    fprintf(stderr, \"    BEFORE: node->parent->child=%p\\n\", node->parent->child);\n    fprintf(stderr, \"    BEFORE: node->parent->last_child=%p\\n\", node->parent->last_child);\n  }\n  fprintf(stderr, \"    BEFORE: node->child=%p\\n\", node->child);\n  fprintf(stderr, \"    BEFORE: node->last_child=%p\\n\", node->last_child);\n  fprintf(stderr, \"    BEFORE: node->prev=%p\\n\", node->prev);\n  fprintf(stderr, \"    BEFORE: node->next=%p\\n\", node->next);\n#endif /* DEBUG > 1 */\n\n  if (node->prev)\n    node->prev->next = node->next;\n  else\n    node->parent->child = node->next;\n\n  if (node->next)\n    node->next->prev = node->prev;\n  else\n    node->parent->last_child = node->prev;\n\n  node->parent = NULL;\n  node->prev   = NULL;\n  node->next   = NULL;\n\n#if DEBUG > 1\n  fprintf(stderr, \"    AFTER: node->parent=%p\\n\", node->parent);\n  if (node->parent)\n  {\n    fprintf(stderr, \"    AFTER: node->parent->child=%p\\n\", node->parent->child);\n    fprintf(stderr, \"    AFTER: node->parent->last_child=%p\\n\", node->parent->last_child);\n  }\n  fprintf(stderr, \"    AFTER: node->child=%p\\n\", node->child);\n  fprintf(stderr, \"    AFTER: node->last_child=%p\\n\", node->last_child);\n  fprintf(stderr, \"    AFTER: node->prev=%p\\n\", node->prev);\n  fprintf(stderr, \"    AFTER: node->next=%p\\n\", node->next);\n#endif /* DEBUG > 1 */\n}\n\n\n/*\n * 'mxmlNewXML()' - Create a new XML document tree.\n *\n * The \"version\" argument specifies the version number to put in the\n * ?xml element node. If NULL, version 1.0 is assumed.\n *\n * @since Mini-XML 2.3@\n */\n\nmxml_node_t *\t\t\t\t/* O - New ?xml node */\nmxmlNewXML(const char *version)\t\t/* I - Version number to use */\n{\n  char\telement[1024];\t\t\t/* Element text */\n\n\n  snprintf(element, sizeof(element), \"?xml version=\\\"%s\\\" encoding=\\\"utf-8\\\"?\",\n           version ? version : \"1.0\");\n\n  return (mxmlNewElement(NULL, element));\n}\n\n\n/*\n * 'mxmlRelease()' - Release a node.\n *\n * When the reference count reaches zero, the node (and any children)\n * is deleted via mxmlDelete().\n *\n * @since Mini-XML 2.3@\n */\n\nint\t\t\t\t\t/* O - New reference count */\nmxmlRelease(mxml_node_t *node)\t\t/* I - Node */\n{\n  if (node)\n  {\n    if ((-- node->ref_count) <= 0)\n    {\n      mxmlDelete(node);\n      return (0);\n    }\n    else\n      return (node->ref_count);\n  }\n  else\n    return (-1);\n}\n\n\n/*\n * 'mxmlRetain()' - Retain a node.\n *\n * @since Mini-XML 2.3@\n */\n\nint\t\t\t\t\t/* O - New reference count */\nmxmlRetain(mxml_node_t *node)\t\t/* I - Node */\n{\n  if (node)\n    return (++ node->ref_count);\n  else\n    return (-1);\n}\n\n\n/*\n * 'mxml_free()' - Free the memory used by a node.\n *\n * Note: Does not free child nodes, does not remove from parent.\n */\n\nstatic void\nmxml_free(mxml_node_t *node)\t\t/* I - Node */\n{\n  int\ti;\t\t\t\t/* Looping var */\n\n\n  switch (node->type)\n  {\n    case MXML_ELEMENT :\n        if (node->value.element.name)\n      PhFree(node->value.element.name);\n\n    if (node->value.element.num_attrs)\n    {\n      for (i = 0; i < node->value.element.num_attrs; i ++)\n      {\n        if (node->value.element.attrs[i].name)\n          PhFree(node->value.element.attrs[i].name);\n        if (node->value.element.attrs[i].value)\n          PhFree(node->value.element.attrs[i].value);\n      }\n\n          PhFree(node->value.element.attrs);\n    }\n        break;\n    case MXML_INTEGER :\n       /* Nothing to do */\n        break;\n    case MXML_OPAQUE :\n        if (node->value.opaque)\n      PhFree(node->value.opaque);\n        break;\n    case MXML_REAL :\n       /* Nothing to do */\n        break;\n    case MXML_TEXT :\n        if (node->value.text.string)\n      PhFree(node->value.text.string);\n        break;\n    case MXML_CUSTOM :\n        if (node->value.custom.data &&\n        node->value.custom.destroy)\n      (*(node->value.custom.destroy))(node->value.custom.data);\n    break;\n    default :\n        break;\n  }\n\n /*\n  * Free this node...\n  */\n\n  PhFree(node);\n}\n\n\n/*\n * 'mxml_new()' - Create a new node.\n */\n\nstatic mxml_node_t *\t\t\t/* O - New node */\nmxml_new(mxml_node_t *parent,\t\t/* I - Parent node */\n         mxml_type_t type)\t\t/* I - Node type */\n{\n  mxml_node_t\t*node;\t\t\t/* New node */\n\n\n#if DEBUG > 1\n  fprintf(stderr, \"mxml_new(parent=%p, type=%d)\\n\", parent, type);\n#endif /* DEBUG > 1 */\n\n /*\n  * Allocate memory for the node...\n  */\n\n  if ((node = PhAllocateExSafe(sizeof(mxml_node_t), HEAP_ZERO_MEMORY)) == NULL)\n  {\n#if DEBUG > 1\n    fputs(\"    returning NULL\\n\", stderr);\n#endif /* DEBUG > 1 */\n\n    return (NULL);\n  }\n\n#if DEBUG > 1\n  fprintf(stderr, \"    returning %p\\n\", node);\n#endif /* DEBUG > 1 */\n\n /*\n  * Set the node type...\n  */\n\n  node->type      = type;\n  node->ref_count = 1;\n\n /*\n  * Add to the parent if present...\n  */\n\n  if (parent)\n    mxmlAdd(parent, MXML_ADD_AFTER, MXML_ADD_TO_PARENT, node);\n\n /*\n  * Return the new node...\n  */\n\n  return (node);\n}\n\n\n/*\n * End of \"$Id: mxml-node.c 462 2016-06-11 20:51:49Z msweet $\".\n */\n"
  },
  {
    "path": "third_party/phlib/mxml/mxml-private.c",
    "content": "/*\n * \"$Id: mxml-private.c 451 2014-01-04 21:50:06Z msweet $\"\n *\n * Private functions for Mini-XML, a small XML-like file parsing library.\n *\n * Copyright 2003-2014 by Michael R Sweet.\n *\n * These coded instructions, statements, and computer programs are the\n * property of Michael R Sweet and are protected by Federal copyright\n * law.  Distribution and use rights are outlined in the file \"COPYING\"\n * which should have been included with this file.  If this file is\n * missing or damaged, see the license at:\n *\n *     http://www.msweet.org/projects.php/Mini-XML\n */\n\n/*\n * Include necessary headers...\n */\n\n#include \"mxml-private.h\"\n\n\n/*\n * Some crazy people think that unloading a shared object is a good or safe\n * thing to do.  Unfortunately, most objects are simply *not* safe to unload\n * and bad things *will* happen.\n *\n * The following mess of conditional code allows us to provide a destructor\n * function in Mini-XML for our thread-global storage so that it can possibly\n * be unloaded safely, although since there is no standard way to do so I\n * can't even provide any guarantees that you can do it safely on all platforms.\n *\n * This code currently supports AIX, HP-UX, Linux, Mac OS X, Solaris, and\n * Windows.  It might work on the BSDs and IRIX, but I haven't tested that.\n */\n\n#if defined(__sun) || defined(_AIX)\n#  pragma fini(_mxml_fini)\n#  define _MXML_FINI _mxml_fini\n#elif defined(__hpux)\n#  pragma FINI _mxml_fini\n#  define _MXML_FINI _mxml_fini\n#elif defined(__GNUC__) /* Linux and Mac OS X */\n#  define _MXML_FINI __attribute((destructor)) _mxml_fini\n#else\n#  define _MXML_FINI _fini\n#endif /* __sun */\n\n\n/*\n * 'mxml_error()' - Display an error message.\n */\n\nvoid\nmxml_error(const char *format,\t\t/* I - Printf-style format string */\n           ...)\t\t\t\t/* I - Additional arguments as needed */\n{\n  va_list\tap;\t\t\t/* Pointer to arguments */\n  char\t\ts[1024];\t\t/* Message string */\n  _mxml_global_t *global = _mxml_global();\n                    /* Global data */\n\n\n /*\n  * Range check input...\n  */\n\n  if (!format)\n    return;\n\n /*\n  * Format the error message string...\n  */\n\n  va_start(ap, format);\n\n  vsnprintf(s, sizeof(s), format, ap);\n\n  va_end(ap);\n\n /*\n  * And then display the error message...\n  */\n\n  if (global->error_cb)\n    (*global->error_cb)(s);\n  else\n    fprintf(stderr, \"mxml: %s\\n\", s);\n}\n\n\n/*\n * 'mxml_ignore_cb()' - Default callback for ignored values.\n */\n\nmxml_type_t\t\t\t\t/* O - Node type */\nmxml_ignore_cb(mxml_node_t *node)\t/* I - Current node */\n{\n  (void)node;\n\n  return (MXML_IGNORE);\n}\n\n\n/*\n * 'mxml_integer_cb()' - Default callback for integer values.\n */\n\nmxml_type_t\t\t\t\t/* O - Node type */\nmxml_integer_cb(mxml_node_t *node)\t/* I - Current node */\n{\n  (void)node;\n\n  return (MXML_INTEGER);\n}\n\n\n/*\n * 'mxml_opaque_cb()' - Default callback for opaque values.\n */\n\nmxml_type_t\t\t\t\t/* O - Node type */\nmxml_opaque_cb(mxml_node_t *node)\t/* I - Current node */\n{\n  (void)node;\n\n  return (MXML_OPAQUE);\n}\n\n\n/*\n * 'mxml_real_cb()' - Default callback for real number values.\n */\n\nmxml_type_t\t\t\t\t/* O - Node type */\nmxml_real_cb(mxml_node_t *node)\t\t/* I - Current node */\n{\n  (void)node;\n\n  return (MXML_REAL);\n}\n\n\n#ifdef HAVE_PTHREAD_H\t\t\t/**** POSIX threading ****/\n#  include <pthread.h>\n\nstatic pthread_key_t\t_mxml_key = -1;\t/* Thread local storage key */\nstatic pthread_once_t\t_mxml_key_once = PTHREAD_ONCE_INIT;\n                    /* One-time initialization object */\nstatic void\t\t_mxml_init(void);\nstatic void\t\t_mxml_destructor(void *g);\n\n\n/*\n * '_mxml_destructor()' - Free memory used for globals...\n */\n\nstatic void\n_mxml_destructor(void *g)\t\t/* I - Global data */\n{\n  free(g);\n}\n\n\n/*\n * '_mxml_fini()' - Clean up when unloaded.\n */\n\nstatic void\n_MXML_FINI(void)\n{\n  _mxml_global_t\t*global;\t/* Global data */\n\n\n  if (_mxml_key != -1)\n  {\n    if ((global = (_mxml_global_t *)pthread_getspecific(_mxml_key)) != NULL)\n      _mxml_destructor(global);\n\n    pthread_key_delete(_mxml_key);\n    _mxml_key = -1;\n  }\n}\n\n\n/*\n * '_mxml_global()' - Get global data.\n */\n\n_mxml_global_t *\t\t\t/* O - Global data */\n_mxml_global(void)\n{\n  _mxml_global_t\t*global;\t/* Global data */\n\n\n  pthread_once(&_mxml_key_once, _mxml_init);\n\n  if ((global = (_mxml_global_t *)pthread_getspecific(_mxml_key)) == NULL)\n  {\n    global = (_mxml_global_t *)calloc(1, sizeof(_mxml_global_t));\n    pthread_setspecific(_mxml_key, global);\n\n    global->num_entity_cbs = 1;\n    global->entity_cbs[0]  = _mxml_entity_cb;\n    global->wrap           = 72;\n  }\n\n  return (global);\n}\n\n\n/*\n * '_mxml_init()' - Initialize global data...\n */\n\nstatic void\n_mxml_init(void)\n{\n  pthread_key_create(&_mxml_key, _mxml_destructor);\n}\n\n\n#elif defined(WIN32) && defined(MXML1_EXPORTS) /**** WIN32 threading ****/\n#  include <windows.h>\n\nstatic DWORD _mxml_tls_index;\t\t/* Index for global storage */\n\n\n/*\n * 'DllMain()' - Main entry for library.\n */\n\nBOOL WINAPI\t\t\t\t/* O - Success/failure */\nDllMain(HINSTANCE hinst,\t\t/* I - DLL module handle */\n        DWORD     reason,\t\t/* I - Reason */\n        LPVOID    reserved)\t\t/* I - Unused */\n{\n  _mxml_global_t\t*global;\t/* Global data */\n\n\n  (void)hinst;\n  (void)reserved;\n\n  switch (reason)\n  {\n    case DLL_PROCESS_ATTACH :\t\t/* Called on library initialization */\n        if ((_mxml_tls_index = TlsAlloc()) == TLS_OUT_OF_INDEXES)\n          return (FALSE);\n        break;\n\n    case DLL_THREAD_DETACH :\t\t/* Called when a thread terminates */\n        if ((global = (_mxml_global_t *)TlsGetValue(_mxml_tls_index)) != NULL)\n          free(global);\n        break;\n\n    case DLL_PROCESS_DETACH :\t\t/* Called when library is unloaded */\n        if ((global = (_mxml_global_t *)TlsGetValue(_mxml_tls_index)) != NULL)\n          free(global);\n\n        TlsFree(_mxml_tls_index);\n        break;\n\n    default:\n        break;\n  }\n\n  return (TRUE);\n}\n\n\n/*\n * '_mxml_global()' - Get global data.\n */\n\n_mxml_global_t *\t\t\t/* O - Global data */\n_mxml_global(void)\n{\n  _mxml_global_t\t*global;\t/* Global data */\n\n\n  if ((global = (_mxml_global_t *)TlsGetValue(_mxml_tls_index)) == NULL)\n  {\n    global = (_mxml_global_t *)calloc(1, sizeof(_mxml_global_t));\n\n    global->num_entity_cbs = 1;\n    global->entity_cbs[0]  = _mxml_entity_cb;\n    global->wrap           = 72;\n\n    TlsSetValue(_mxml_tls_index, (LPVOID)global);\n  }\n\n  return (global);\n}\n\n\n#else\t\t\t\t\t/**** No threading ****/\n/*\n * '_mxml_global()' - Get global data.\n */\n\n_mxml_global_t *\t\t\t/* O - Global data */\n_mxml_global(void)\n{\n  static _mxml_global_t\tglobal =\t/* Global data */\n  {\n    NULL,\t\t\t\t/* error_cb */\n    1,\t\t\t\t\t/* num_entity_cbs */\n    { _mxml_entity_cb },\t\t/* entity_cbs */\n    72,\t\t\t\t\t/* wrap */\n    NULL,\t\t\t\t/* custom_load_cb */\n    NULL\t\t\t\t/* custom_save_cb */\n  };\n\n\n  return (&global);\n}\n#endif /* HAVE_PTHREAD_H */\n\n\n/*\n * End of \"$Id: mxml-private.c 451 2014-01-04 21:50:06Z msweet $\".\n */\n"
  },
  {
    "path": "third_party/phlib/mxml/mxml-private.h",
    "content": "/*\n * \"$Id: mxml-private.h 451 2014-01-04 21:50:06Z msweet $\"\n *\n * Private definitions for Mini-XML, a small XML-like file parsing library.\n *\n * Copyright 2003-2014 by Michael R Sweet.\n *\n * These coded instructions, statements, and computer programs are the\n * property of Michael R Sweet and are protected by Federal copyright\n * law.  Distribution and use rights are outlined in the file \"COPYING\"\n * which should have been included with this file.  If this file is\n * missing or damaged, see the license at:\n *\n *     http://www.msweet.org/projects.php/Mini-XML\n */\n\n/*\n * Include necessary headers...\n */\n\n#include \"config.h\"\n#include \"mxml.h\"\n\n\n/*\n * Global, per-thread data...\n */\n\ntypedef struct _mxml_global_s\n{\n  void\t(*error_cb)(const char *);\n  int\tnum_entity_cbs;\n  int\t(*entity_cbs[100])(const char *name);\n  int\twrap;\n  mxml_custom_load_cb_t\tcustom_load_cb;\n  mxml_custom_save_cb_t\tcustom_save_cb;\n} _mxml_global_t;\n\n\n/*\n * Functions...\n */\n\nextern _mxml_global_t\t*_mxml_global(void);\nextern int\t\t_mxml_entity_cb(const char *name);\n\n\n/*\n * End of \"$Id: mxml-private.h 451 2014-01-04 21:50:06Z msweet $\".\n */\n"
  },
  {
    "path": "third_party/phlib/mxml/mxml-search.c",
    "content": "/*\n * \"$Id: mxml-search.c 451 2014-01-04 21:50:06Z msweet $\"\n *\n * Search/navigation functions for Mini-XML, a small XML-like file\n * parsing library.\n *\n * Copyright 2003-2014 by Michael R Sweet.\n *\n * These coded instructions, statements, and computer programs are the\n * property of Michael R Sweet and are protected by Federal copyright\n * law.  Distribution and use rights are outlined in the file \"COPYING\"\n * which should have been included with this file.  If this file is\n * missing or damaged, see the license at:\n *\n *     http://www.msweet.org/projects.php/Mini-XML\n */\n\n/*\n * Include necessary headers...\n */\n\n#include \"config.h\"\n#include \"mxml.h\"\n\n\n/*\n * 'mxmlFindElement()' - Find the named element.\n *\n * The search is constrained by the name, attribute name, and value; any\n * NULL names or values are treated as wildcards, so different kinds of\n * searches can be implemented by looking for all elements of a given name\n * or all elements with a specific attribute. The descend argument determines\n * whether the search descends into child nodes; normally you will use\n * MXML_DESCEND_FIRST for the initial search and MXML_NO_DESCEND to find\n * additional direct descendents of the node. The top node argument\n * constrains the search to a particular node's children.\n */\n\nmxml_node_t *\t\t\t\t/* O - Element node or NULL */\nmxmlFindElement(mxml_node_t *node,\t/* I - Current node */\n                mxml_node_t *top,\t/* I - Top node */\n                const char  *name,\t/* I - Element name or NULL for any */\n        const char  *attr,\t/* I - Attribute name, or NULL for none */\n        const char  *value,\t/* I - Attribute value, or NULL for any */\n        int         descend)\t/* I - Descend into tree - MXML_DESCEND, MXML_NO_DESCEND, or MXML_DESCEND_FIRST */\n{\n  const char\t*temp;\t\t\t/* Current attribute value */\n\n\n /*\n  * Range check input...\n  */\n\n  if (!node || !top || (!attr && value))\n    return (NULL);\n\n /*\n  * Start with the next node...\n  */\n\n  node = mxmlWalkNext(node, top, descend);\n\n /*\n  * Loop until we find a matching element...\n  */\n\n  while (node != NULL)\n  {\n   /*\n    * See if this node matches...\n    */\n\n    if (node->type == MXML_ELEMENT &&\n        node->value.element.name &&\n    (!name || !strcmp(node->value.element.name, name)))\n    {\n     /*\n      * See if we need to check for an attribute...\n      */\n\n      if (!attr)\n        return (node);\t\t\t/* No attribute search, return it... */\n\n     /*\n      * Check for the attribute...\n      */\n\n      if ((temp = mxmlElementGetAttr(node, attr)) != NULL)\n      {\n       /*\n        * OK, we have the attribute, does it match?\n    */\n\n    if (!value || !strcmp(value, temp))\n      return (node);\t\t/* Yes, return it... */\n      }\n    }\n\n   /*\n    * No match, move on to the next node...\n    */\n\n    if (descend == MXML_DESCEND)\n      node = mxmlWalkNext(node, top, MXML_DESCEND);\n    else\n      node = node->next;\n  }\n\n  return (NULL);\n}\n\n\n/*\n * 'mxmlFindPath()' - Find a node with the given path.\n *\n * The \"path\" is a slash-separated list of element names. The name \"*\" is\n * considered a wildcard for one or more levels of elements.  For example,\n * \"foo/one/two\", \"bar/two/one\", \"*\\/one\", and so forth.\n *\n * The first child node of the found node is returned if the given node has\n * children and the first child is a value node.\n *\n * @since Mini-XML 2.7@\n */\n\nmxml_node_t *\t\t\t\t/* O - Found node or NULL */\nmxmlFindPath(mxml_node_t *top,\t\t/* I - Top node */\n         const char  *path)\t\t/* I - Path to element */\n{\n  mxml_node_t\t*node;\t\t\t/* Current node */\n  char\t\telement[256];\t\t/* Current element name */\n  const char\t*pathsep;\t\t/* Separator in path */\n  int\t\tdescend;\t\t/* mxmlFindElement option */\n\n\n /*\n  * Range check input...\n  */\n\n  if (!top || !path || !*path)\n    return (NULL);\n\n /*\n  * Search each element in the path...\n  */\n\n  node = top;\n  while (*path)\n  {\n   /*\n    * Handle wildcards...\n    */\n\n    if (!strncmp(path, \"*/\", 2))\n    {\n      path += 2;\n      descend = MXML_DESCEND;\n    }\n    else\n      descend = MXML_DESCEND_FIRST;\n\n   /*\n    * Get the next element in the path...\n    */\n\n    if ((pathsep = strchr(path, '/')) == NULL)\n      pathsep = path + strlen(path);\n\n    if (pathsep == path || (pathsep - path) >= sizeof(element))\n      return (NULL);\n\n    memcpy(element, path, pathsep - path);\n    element[pathsep - path] = '\\0';\n\n    if (*pathsep)\n      path = pathsep + 1;\n    else\n      path = pathsep;\n\n   /*\n    * Search for the element...\n    */\n\n    if ((node = mxmlFindElement(node, node, element, NULL, NULL,\n                                descend)) == NULL)\n      return (NULL);\n  }\n\n /*\n  * If we get this far, return the node or its first child...\n  */\n\n  if (node->child && node->child->type != MXML_ELEMENT)\n    return (node->child);\n  else\n    return (node);\n}\n\n\n/*\n * 'mxmlWalkNext()' - Walk to the next logical node in the tree.\n *\n * The descend argument controls whether the first child is considered\n * to be the next node. The top node argument constrains the walk to\n * the node's children.\n */\n\nmxml_node_t *\t\t\t\t/* O - Next node or NULL */\nmxmlWalkNext(mxml_node_t *node,\t\t/* I - Current node */\n             mxml_node_t *top,\t\t/* I - Top node */\n             int         descend)\t/* I - Descend into tree - MXML_DESCEND, MXML_NO_DESCEND, or MXML_DESCEND_FIRST */\n{\n  if (!node)\n    return (NULL);\n  else if (node->child && descend)\n    return (node->child);\n  else if (node == top)\n    return (NULL);\n  else if (node->next)\n    return (node->next);\n  else if (node->parent && node->parent != top)\n  {\n    node = node->parent;\n\n    while (!node->next)\n      if (node->parent == top || !node->parent)\n        return (NULL);\n      else\n        node = node->parent;\n\n    return (node->next);\n  }\n  else\n    return (NULL);\n}\n\n\n/*\n * 'mxmlWalkPrev()' - Walk to the previous logical node in the tree.\n *\n * The descend argument controls whether the previous node's last child\n * is considered to be the previous node. The top node argument constrains\n * the walk to the node's children.\n */\n\nmxml_node_t *\t\t\t\t/* O - Previous node or NULL */\nmxmlWalkPrev(mxml_node_t *node,\t\t/* I - Current node */\n             mxml_node_t *top,\t\t/* I - Top node */\n             int         descend)\t/* I - Descend into tree - MXML_DESCEND, MXML_NO_DESCEND, or MXML_DESCEND_FIRST */\n{\n  if (!node || node == top)\n    return (NULL);\n  else if (node->prev)\n  {\n    if (node->prev->last_child && descend)\n    {\n     /*\n      * Find the last child under the previous node...\n      */\n\n      node = node->prev->last_child;\n\n      while (node->last_child)\n        node = node->last_child;\n\n      return (node);\n    }\n    else\n      return (node->prev);\n  }\n  else if (node->parent != top)\n    return (node->parent);\n  else\n    return (NULL);\n}\n\n\n/*\n * End of \"$Id: mxml-search.c 451 2014-01-04 21:50:06Z msweet $\".\n */\n"
  },
  {
    "path": "third_party/phlib/mxml/mxml-set.c",
    "content": "/*\n * \"$Id: mxml-set.c 451 2014-01-04 21:50:06Z msweet $\"\n *\n * Node set functions for Mini-XML, a small XML-like file parsing library.\n *\n * Copyright 2003-2014 by Michael R Sweet.\n *\n * These coded instructions, statements, and computer programs are the\n * property of Michael R Sweet and are protected by Federal copyright\n * law.  Distribution and use rights are outlined in the file \"COPYING\"\n * which should have been included with this file.  If this file is\n * missing or damaged, see the license at:\n *\n *     http://www.msweet.org/projects.php/Mini-XML\n */\n\n/*\n * Include necessary headers...\n */\n\n#include <phbase.h>\n#include \"config.h\"\n#include \"mxml.h\"\n\n\n/*\n * 'mxmlSetCDATA()' - Set the element name of a CDATA node.\n *\n * The node is not changed if it (or its first child) is not a CDATA element node.\n *\n * @since Mini-XML 2.3@\n */\n\nint\t\t\t\t\t/* O - 0 on success, -1 on failure */\nmxmlSetCDATA(mxml_node_t *node,\t\t/* I - Node to set */\n             const char  *data)\t\t/* I - New data string */\n{\n /*\n  * Range check input...\n  */\n\n  if (node && node->type == MXML_ELEMENT &&\n      strncmp(node->value.element.name, \"![CDATA[\", 8) &&\n      node->child && node->child->type == MXML_ELEMENT &&\n      !strncmp(node->child->value.element.name, \"![CDATA[\", 8))\n    node = node->child;\n\n  if (!node || node->type != MXML_ELEMENT || !data ||\n      strncmp(node->value.element.name, \"![CDATA[\", 8))\n    return (-1);\n\n /*\n  * Free any old element value and set the new value...\n  */\n\n  if (node->value.element.name)\n    PhFree(node->value.element.name);\n\n  node->value.element.name = _mxml_strdupf(\"![CDATA[%s]]\", data);\n\n  return (0);\n}\n\n\n/*\n * 'mxmlSetCustom()' - Set the data and destructor of a custom data node.\n *\n * The node is not changed if it (or its first child) is not a custom node.\n *\n * @since Mini-XML 2.1@\n */\n\nint\t\t\t\t\t/* O - 0 on success, -1 on failure */\nmxmlSetCustom(\n    mxml_node_t              *node,\t/* I - Node to set */\n    void                     *data,\t/* I - New data pointer */\n    mxml_custom_destroy_cb_t destroy)\t/* I - New destructor function */\n{\n /*\n  * Range check input...\n  */\n\n  if (node && node->type == MXML_ELEMENT &&\n      node->child && node->child->type == MXML_CUSTOM)\n    node = node->child;\n\n  if (!node || node->type != MXML_CUSTOM)\n    return (-1);\n\n /*\n  * Free any old element value and set the new value...\n  */\n\n  if (node->value.custom.data && node->value.custom.destroy)\n    (*(node->value.custom.destroy))(node->value.custom.data);\n\n  node->value.custom.data    = data;\n  node->value.custom.destroy = destroy;\n\n  return (0);\n}\n\n\n/*\n * 'mxmlSetElement()' - Set the name of an element node.\n *\n * The node is not changed if it is not an element node.\n */\n\nint\t\t\t\t\t/* O - 0 on success, -1 on failure */\nmxmlSetElement(mxml_node_t *node,\t/* I - Node to set */\n               const char  *name)\t/* I - New name string */\n{\n /*\n  * Range check input...\n  */\n\n  if (!node || node->type != MXML_ELEMENT || !name)\n    return (-1);\n\n /*\n  * Free any old element value and set the new value...\n  */\n\n  if (node->value.element.name)\n    PhFree(node->value.element.name);\n\n  node->value.element.name = PhDuplicateBytesZSafe((char *)name);\n\n  return (0);\n}\n\n\n/*\n * 'mxmlSetInteger()' - Set the value of an integer node.\n *\n * The node is not changed if it (or its first child) is not an integer node.\n */\n\nint\t\t\t\t\t/* O - 0 on success, -1 on failure */\nmxmlSetInteger(mxml_node_t *node,\t/* I - Node to set */\n               int         integer)\t/* I - Integer value */\n{\n /*\n  * Range check input...\n  */\n\n  if (node && node->type == MXML_ELEMENT &&\n      node->child && node->child->type == MXML_INTEGER)\n    node = node->child;\n\n  if (!node || node->type != MXML_INTEGER)\n    return (-1);\n\n /*\n  * Set the new value and return...\n  */\n\n  node->value.integer = integer;\n\n  return (0);\n}\n\n\n/*\n * 'mxmlSetOpaque()' - Set the value of an opaque node.\n *\n * The node is not changed if it (or its first child) is not an opaque node.\n */\n\nint\t\t\t\t\t/* O - 0 on success, -1 on failure */\nmxmlSetOpaque(mxml_node_t *node,\t/* I - Node to set */\n              const char  *opaque)\t/* I - Opaque string */\n{\n /*\n  * Range check input...\n  */\n\n  if (node && node->type == MXML_ELEMENT &&\n      node->child && node->child->type == MXML_OPAQUE)\n    node = node->child;\n\n  if (!node || node->type != MXML_OPAQUE || !opaque)\n    return (-1);\n\n /*\n  * Free any old opaque value and set the new value...\n  */\n\n  if (node->value.opaque)\n    PhFree(node->value.opaque);\n\n  node->value.opaque = PhDuplicateBytesZSafe((char *)opaque);\n\n  return (0);\n}\n\n\n/*\n * 'mxmlSetReal()' - Set the value of a real number node.\n *\n * The node is not changed if it (or its first child) is not a real number node.\n */\n\nint\t\t\t\t\t/* O - 0 on success, -1 on failure */\nmxmlSetReal(mxml_node_t *node,\t\t/* I - Node to set */\n            double      real)\t\t/* I - Real number value */\n{\n /*\n  * Range check input...\n  */\n\n  if (node && node->type == MXML_ELEMENT &&\n      node->child && node->child->type == MXML_REAL)\n    node = node->child;\n\n  if (!node || node->type != MXML_REAL)\n    return (-1);\n\n /*\n  * Set the new value and return...\n  */\n\n  node->value.real = real;\n\n  return (0);\n}\n\n\n/*\n * 'mxmlSetText()' - Set the value of a text node.\n *\n * The node is not changed if it (or its first child) is not a text node.\n */\n\nint\t\t\t\t\t/* O - 0 on success, -1 on failure */\nmxmlSetText(mxml_node_t *node,\t\t/* I - Node to set */\n            int         whitespace,\t/* I - 1 = leading whitespace, 0 = no whitespace */\n        const char  *string)\t/* I - String */\n{\n /*\n  * Range check input...\n  */\n\n  if (node && node->type == MXML_ELEMENT &&\n      node->child && node->child->type == MXML_TEXT)\n    node = node->child;\n\n  if (!node || node->type != MXML_TEXT || !string)\n    return (-1);\n\n /*\n  * Free any old string value and set the new value...\n  */\n\n  if (node->value.text.string)\n    PhFree(node->value.text.string);\n\n  node->value.text.whitespace = whitespace;\n  node->value.text.string     = PhDuplicateBytesZSafe((char *)string);\n\n  return (0);\n}\n\n\n/*\n * 'mxmlSetTextf()' - Set the value of a text node to a formatted string.\n *\n * The node is not changed if it (or its first child) is not a text node.\n */\n\nint\t\t\t\t\t/* O - 0 on success, -1 on failure */\nmxmlSetTextf(mxml_node_t *node,\t\t/* I - Node to set */\n             int         whitespace,\t/* I - 1 = leading whitespace, 0 = no whitespace */\n             const char  *format,\t/* I - Printf-style format string */\n         ...)\t\t\t/* I - Additional arguments as needed */\n{\n  va_list\tap;\t\t\t/* Pointer to arguments */\n\n\n /*\n  * Range check input...\n  */\n\n  if (node && node->type == MXML_ELEMENT &&\n      node->child && node->child->type == MXML_TEXT)\n    node = node->child;\n\n  if (!node || node->type != MXML_TEXT || !format)\n    return (-1);\n\n /*\n  * Free any old string value and set the new value...\n  */\n\n  if (node->value.text.string)\n    PhFree(node->value.text.string);\n\n  va_start(ap, format);\n\n  node->value.text.whitespace = whitespace;\n  node->value.text.string     = _mxml_strdupf(format, ap);\n\n  va_end(ap);\n\n  return (0);\n}\n\n\n/*\n * 'mxmlSetUserData()' - Set the user data pointer for a node.\n *\n * @since Mini-XML 2.7@\n */\n\nint\t\t\t\t\t/* O - 0 on success, -1 on failure */\nmxmlSetUserData(mxml_node_t *node,\t/* I - Node to set */\n                void        *data)\t/* I - User data pointer */\n{\n /*\n  * Range check input...\n  */\n\n  if (!node)\n    return (-1);\n\n /*\n  * Set the user data pointer and return...\n  */\n\n  node->user_data = data;\n  return (0);\n}\n\n\n/*\n * End of \"$Id: mxml-set.c 451 2014-01-04 21:50:06Z msweet $\".\n */\n"
  },
  {
    "path": "third_party/phlib/mxml/mxml-string.c",
    "content": "/*\n * \"$Id: mxml-string.c 454 2014-01-05 03:25:07Z msweet $\"\n *\n * String functions for Mini-XML, a small XML-like file parsing library.\n *\n * Copyright 2003-2014 by Michael R Sweet.\n *\n * These coded instructions, statements, and computer programs are the\n * property of Michael R Sweet and are protected by Federal copyright\n * law.  Distribution and use rights are outlined in the file \"COPYING\"\n * which should have been included with this file.  If this file is\n * missing or damaged, see the license at:\n *\n *     http://www.msweet.org/projects.php/Mini-XML\n */\n\n/*\n * Include necessary headers...\n */\n\n#include <phbase.h>\n#include \"config.h\"\n\n\n/*\n * The va_copy macro is part of C99, but many compilers don't implement it.\n * Provide a \"direct assignment\" implmentation when va_copy isn't defined...\n */\n\n#ifndef va_copy\n#  ifdef __va_copy\n#    define va_copy(dst,src) __va_copy(dst,src)\n#  else\n#    define va_copy(dst,src) memcpy(&dst, src, sizeof(va_list))\n#  endif /* __va_copy */\n#endif /* va_copy */\n\n\n#ifndef HAVE_SNPRINTF\n/*\n * '_mxml_snprintf()' - Format a string.\n */\n\nint\t\t\t\t\t/* O - Number of bytes formatted */\n_mxml_snprintf(char       *buffer,\t/* I - Output buffer */\n               size_t     bufsize,\t/* I - Size of output buffer */\n           const char *format,\t/* I - Printf-style format string */\n           ...)\t\t\t/* I - Additional arguments as needed */\n{\n  va_list\tap;\t\t\t/* Argument list */\n  int\t\tbytes;\t\t\t/* Number of bytes formatted */\n\n\n  va_start(ap, format);\n  bytes = vsnprintf(buffer, bufsize, format, ap);\n  va_end(ap);\n\n  return (bytes);\n}\n#endif /* !HAVE_SNPRINTF */\n\n\n/*\n * '_mxml_strdup()' - Duplicate a string.\n */\n\n#ifndef HAVE_STRDUP\nchar *\t\t\t\t\t/* O - New string pointer */\n_mxml_strdup(const char *s)\t\t/* I - String to duplicate */\n{\n  char\t*t;\t\t\t\t/* New string pointer */\n\n\n  if (s == NULL)\n    return (NULL);\n\n  if ((t = malloc(strlen(s) + 1)) == NULL)\n    return (NULL);\n\n  return (strcpy(t, s));\n}\n#endif /* !HAVE_STRDUP */\n\n\n/*\n * '_mxml_strdupf()' - Format and duplicate a string.\n */\n\nchar *\t\t\t\t\t/* O - New string pointer */\n_mxml_strdupf(const char *format,\t/* I - Printf-style format string */\n              ...)\t\t\t/* I - Additional arguments as needed */\n{\n  va_list\tap;\t\t\t/* Pointer to additional arguments */\n  char\t\t*s;\t\t\t/* Pointer to formatted string */\n\n\n /*\n  * Get a pointer to the additional arguments, format the string,\n  * and return it...\n  */\n\n  va_start(ap, format);\n  s = _mxml_vstrdupf(format, ap);\n  va_end(ap);\n\n  return (s);\n}\n\n\n#ifndef HAVE_VSNPRINTF\n/*\n * '_mxml_vsnprintf()' - Format a string into a fixed size buffer.\n */\n\nint\t\t\t\t\t/* O - Number of bytes formatted */\n_mxml_vsnprintf(char       *buffer,\t/* O - Output buffer */\n                size_t     bufsize,\t/* O - Size of output buffer */\n        const char *format,\t/* I - Printf-style format string */\n        va_list    ap)\t\t/* I - Pointer to additional arguments */\n{\n  char\t\t*bufptr,\t\t/* Pointer to position in buffer */\n        *bufend,\t\t/* Pointer to end of buffer */\n        sign,\t\t\t/* Sign of format width */\n        size,\t\t\t/* Size character (h, l, L) */\n        type;\t\t\t/* Format type character */\n  int\t\twidth,\t\t\t/* Width of field */\n        prec;\t\t\t/* Number of characters of precision */\n  char\t\ttformat[100],\t\t/* Temporary format string for sprintf() */\n        *tptr,\t\t\t/* Pointer into temporary format */\n        temp[1024];\t\t/* Buffer for formatted numbers */\n  char\t\t*s;\t\t\t/* Pointer to string */\n  int\t\tslen;\t\t\t/* Length of string */\n  int\t\tbytes;\t\t\t/* Total number of bytes needed */\n\n\n /*\n  * Loop through the format string, formatting as needed...\n  */\n\n  bufptr = buffer;\n  bufend = buffer + bufsize - 1;\n  bytes  = 0;\n\n  while (*format)\n  {\n    if (*format == '%')\n    {\n      tptr = tformat;\n      *tptr++ = *format++;\n\n      if (*format == '%')\n      {\n        if (bufptr && bufptr < bufend)\n          *bufptr++ = *format;\n        bytes ++;\n        format ++;\n    continue;\n      }\n      else if (strchr(\" -+#\\'\", *format))\n      {\n        *tptr++ = *format;\n        sign = *format++;\n      }\n      else\n        sign = 0;\n\n      if (*format == '*')\n      {\n       /*\n        * Get width from argument...\n    */\n\n    format ++;\n    width = va_arg(ap, int);\n\n    snprintf(tptr, sizeof(tformat) - (tptr - tformat), \"%d\", width);\n    tptr += strlen(tptr);\n      }\n      else\n      {\n    width = 0;\n\n    while (isdigit(*format & 255))\n    {\n      if (tptr < (tformat + sizeof(tformat) - 1))\n        *tptr++ = *format;\n\n      width = width * 10 + *format++ - '0';\n    }\n      }\n\n      if (*format == '.')\n      {\n    if (tptr < (tformat + sizeof(tformat) - 1))\n      *tptr++ = *format;\n\n        format ++;\n\n        if (*format == '*')\n    {\n         /*\n      * Get precision from argument...\n      */\n\n      format ++;\n      prec = va_arg(ap, int);\n\n      snprintf(tptr, sizeof(tformat) - (tptr - tformat), \"%d\", prec);\n      tptr += strlen(tptr);\n    }\n    else\n    {\n      prec = 0;\n\n      while (isdigit(*format & 255))\n      {\n        if (tptr < (tformat + sizeof(tformat) - 1))\n          *tptr++ = *format;\n\n        prec = prec * 10 + *format++ - '0';\n      }\n    }\n      }\n      else\n        prec = -1;\n\n      if (*format == 'l' && format[1] == 'l')\n      {\n        size = 'L';\n\n    if (tptr < (tformat + sizeof(tformat) - 2))\n    {\n      *tptr++ = 'l';\n      *tptr++ = 'l';\n    }\n\n    format += 2;\n      }\n      else if (*format == 'h' || *format == 'l' || *format == 'L')\n      {\n    if (tptr < (tformat + sizeof(tformat) - 1))\n      *tptr++ = *format;\n\n        size = *format++;\n      }\n\n      if (!*format)\n        break;\n\n      if (tptr < (tformat + sizeof(tformat) - 1))\n        *tptr++ = *format;\n\n      type  = *format++;\n      *tptr = '\\0';\n\n      switch (type)\n      {\n    case 'E' : /* Floating point formats */\n    case 'G' :\n    case 'e' :\n    case 'f' :\n    case 'g' :\n        if ((width + 2) > sizeof(temp))\n          break;\n\n        sprintf(temp, tformat, va_arg(ap, double));\n\n            bytes += strlen(temp);\n\n            if (bufptr)\n        {\n          if ((bufptr + strlen(temp)) > bufend)\n          {\n        strncpy(bufptr, temp, (size_t)(bufend - bufptr));\n        bufptr = bufend;\n          }\n          else\n          {\n        strcpy(bufptr, temp);\n        bufptr += strlen(temp);\n          }\n        }\n        break;\n\n        case 'B' : /* Integer formats */\n    case 'X' :\n    case 'b' :\n        case 'd' :\n    case 'i' :\n    case 'o' :\n    case 'u' :\n    case 'x' :\n        if ((width + 2) > sizeof(temp))\n          break;\n\n#ifdef HAVE_LONG_LONG\n        if (size == 'L')\n          sprintf(temp, tformat, va_arg(ap, long long));\n        else\n#endif /* HAVE_LONG_LONG */\n        sprintf(temp, tformat, va_arg(ap, int));\n\n            bytes += strlen(temp);\n\n        if (bufptr)\n        {\n          if ((bufptr + strlen(temp)) > bufend)\n          {\n        strncpy(bufptr, temp, (size_t)(bufend - bufptr));\n        bufptr = bufend;\n          }\n          else\n          {\n        strcpy(bufptr, temp);\n        bufptr += strlen(temp);\n          }\n        }\n        break;\n\n    case 'p' : /* Pointer value */\n        if ((width + 2) > sizeof(temp))\n          break;\n\n        sprintf(temp, tformat, va_arg(ap, void *));\n\n            bytes += strlen(temp);\n\n        if (bufptr)\n        {\n          if ((bufptr + strlen(temp)) > bufend)\n          {\n        strncpy(bufptr, temp, (size_t)(bufend - bufptr));\n        bufptr = bufend;\n          }\n          else\n          {\n        strcpy(bufptr, temp);\n        bufptr += strlen(temp);\n          }\n        }\n        break;\n\n        case 'c' : /* Character or character array */\n        bytes += width;\n\n        if (bufptr)\n        {\n          if (width <= 1)\n            *bufptr++ = va_arg(ap, int);\n          else\n          {\n        if ((bufptr + width) > bufend)\n          width = bufend - bufptr;\n\n        memcpy(bufptr, va_arg(ap, char *), (size_t)width);\n        bufptr += width;\n          }\n        }\n        break;\n\n    case 's' : /* String */\n        if ((s = va_arg(ap, char *)) == NULL)\n          s = \"(null)\";\n\n        slen = strlen(s);\n        if (slen > width && prec != width)\n          width = slen;\n\n            bytes += width;\n\n        if (bufptr)\n        {\n          if ((bufptr + width) > bufend)\n            width = bufend - bufptr;\n\n              if (slen > width)\n            slen = width;\n\n          if (sign == '-')\n          {\n        strncpy(bufptr, s, (size_t)slen);\n        memset(bufptr + slen, ' ', (size_t)(width - slen));\n          }\n          else\n          {\n        memset(bufptr, ' ', (size_t)(width - slen));\n        strncpy(bufptr + width - slen, s, (size_t)slen);\n          }\n\n          bufptr += width;\n        }\n        break;\n\n    case 'n' : /* Output number of chars so far */\n        *(va_arg(ap, int *)) = bytes;\n        break;\n      }\n    }\n    else\n    {\n      bytes ++;\n\n      if (bufptr && bufptr < bufend)\n        *bufptr++ = *format;\n\n      format ++;\n    }\n  }\n\n /*\n  * Nul-terminate the string and return the number of characters needed.\n  */\n\n  *bufptr = '\\0';\n\n  return (bytes);\n}\n#endif /* !HAVE_VSNPRINTF */\n\n\n/*\n * '_mxml_vstrdupf()' - Format and duplicate a string.\n */\n\nchar *\t\t\t\t\t/* O - New string pointer */\n_mxml_vstrdupf(const char *format,\t/* I - Printf-style format string */\n               va_list    ap)\t\t/* I - Pointer to additional arguments */\n{\n  int\t\tbytes;\t\t\t/* Number of bytes required */\n  char\t\t*buffer,\t\t/* String buffer */\n        temp[256];\t\t/* Small buffer for first vsnprintf */\n  va_list\tapcopy;\t\t\t/* Copy of argument list */\n\n\n /*\n  * First format with a tiny buffer; this will tell us how many bytes are\n  * needed...\n  */\n\n  va_copy(apcopy, ap);\n  bytes = vsnprintf(temp, sizeof(temp), format, apcopy);\n\n  if (bytes < sizeof(temp))\n  {\n   /*\n    * Hey, the formatted string fits in the tiny buffer, so just dup that...\n    */\n\n    return (PhDuplicateBytesZSafe(temp));\n  }\n\n /*\n  * Allocate memory for the whole thing and reformat to the new, larger\n  * buffer...\n  */\n\n  if ((buffer = PhAllocateExSafe(bytes + 1, HEAP_ZERO_MEMORY)) != NULL)\n    vsnprintf(buffer, bytes + 1, format, ap);\n\n /*\n  * Return the new string...\n  */\n\n  return (buffer);\n}\n\n\n/*\n * End of \"$Id: mxml-string.c 454 2014-01-05 03:25:07Z msweet $\".\n */\n"
  },
  {
    "path": "third_party/phlib/mxml/mxml.h",
    "content": "/*\n * \"$Id: mxml.h 464 2016-06-12 21:16:14Z msweet $\"\n *\n * Header file for Mini-XML, a small XML-like file parsing library.\n *\n * Copyright 2003-2016 by Michael R Sweet.\n *\n * These coded instructions, statements, and computer programs are the\n * property of Michael R Sweet and are protected by Federal copyright\n * law.  Distribution and use rights are outlined in the file \"COPYING\"\n * which should have been included with this file.  If this file is\n * missing or damaged, see the license at:\n *\n *     http://www.msweet.org/projects.php/Mini-XML\n */\n\n/*\n * Prevent multiple inclusion...\n */\n\n#ifndef _mxml_h_\n#  define _mxml_h_\n\n/*\n * Include necessary headers...\n */\n\n#  include <stdio.h>\n#  include <stdlib.h>\n#  include <string.h>\n#  include <ctype.h>\n#  include <errno.h>\n#  include <windows.h>\n\n#ifdef _PHAPP_\n#define PHMXMLAPI __declspec(dllexport)\n#else\n#define PHMXMLAPI\n#endif\n\n/*\n * Constants...\n */\n\n#  define MXML_MAJOR_VERSION\t2\t/* Major version number */\n#  define MXML_MINOR_VERSION\t10\t/* Minor version number */\n\n#  define MXML_TAB\t\t8\t/* Tabs every N columns */\n\n#  define MXML_NO_CALLBACK\t0\t/* Don't use a type callback */\n#  define MXML_INTEGER_CALLBACK\tmxml_integer_cb\n\t\t\t\t\t/* Treat all data as integers */\n#  define MXML_OPAQUE_CALLBACK\tmxml_opaque_cb\n\t\t\t\t\t/* Treat all data as opaque */\n#  define MXML_REAL_CALLBACK\tmxml_real_cb\n\t\t\t\t\t/* Treat all data as real numbers */\n#  define MXML_TEXT_CALLBACK\t0\t/* Treat all data as text */\n#  define MXML_IGNORE_CALLBACK\tmxml_ignore_cb\n\t\t\t\t\t/* Ignore all non-element content */\n\n#  define MXML_NO_PARENT\t0\t/* No parent for the node */\n\n#  define MXML_DESCEND\t\t1\t/* Descend when finding/walking */\n#  define MXML_NO_DESCEND\t0\t/* Don't descend when finding/walking */\n#  define MXML_DESCEND_FIRST\t-1\t/* Descend for first find */\n\n#  define MXML_WS_BEFORE_OPEN\t0\t/* Callback for before open tag */\n#  define MXML_WS_AFTER_OPEN\t1\t/* Callback for after open tag */\n#  define MXML_WS_BEFORE_CLOSE\t2\t/* Callback for before close tag */\n#  define MXML_WS_AFTER_CLOSE\t3\t/* Callback for after close tag */\n\n#  define MXML_ADD_BEFORE\t0\t/* Add node before specified node */\n#  define MXML_ADD_AFTER\t1\t/* Add node after specified node */\n#  define MXML_ADD_TO_PARENT\tNULL\t/* Add node relative to parent */\n\n\n/*\n * Data types...\n */\n\ntypedef enum mxml_sax_event_e\t\t/**** SAX event type. ****/\n{\n  MXML_SAX_CDATA,\t\t\t/* CDATA node */\n  MXML_SAX_COMMENT,\t\t\t/* Comment node */\n  MXML_SAX_DATA,\t\t\t/* Data node */\n  MXML_SAX_DIRECTIVE,\t\t\t/* Processing directive node */\n  MXML_SAX_ELEMENT_CLOSE,\t\t/* Element closed */\n  MXML_SAX_ELEMENT_OPEN\t\t\t/* Element opened */\n} mxml_sax_event_t;\n\ntypedef enum mxml_type_e\t\t/**** The XML node type. ****/\n{\n  MXML_IGNORE = -1,\t\t\t/* Ignore/throw away node @since Mini-XML 2.3@ */\n  MXML_ELEMENT,\t\t\t\t/* XML element with attributes */\n  MXML_INTEGER,\t\t\t\t/* Integer value */\n  MXML_OPAQUE,\t\t\t\t/* Opaque string */\n  MXML_REAL,\t\t\t\t/* Real value */\n  MXML_TEXT,\t\t\t\t/* Text fragment */\n  MXML_CUSTOM\t\t\t\t/* Custom data @since Mini-XML 2.1@ */\n} mxml_type_t;\n\ntypedef void (*mxml_custom_destroy_cb_t)(void *);\n\t\t\t\t\t/**** Custom data destructor ****/\n\ntypedef void (*mxml_error_cb_t)(const char *);\n\t\t\t\t\t/**** Error callback function ****/\n\ntypedef struct mxml_attr_s\t\t/**** An XML element attribute value. @private@ ****/\n{\n  char\t\t\t*name;\t\t/* Attribute name */\n  char\t\t\t*value;\t\t/* Attribute value */\n} mxml_attr_t;\n\ntypedef struct mxml_element_s\t\t/**** An XML element value. @private@ ****/\n{\n  char\t\t\t*name;\t\t/* Name of element */\n  int\t\t\tnum_attrs;\t/* Number of attributes */\n  mxml_attr_t\t\t*attrs;\t\t/* Attributes */\n} mxml_element_t;\n\ntypedef struct mxml_text_s\t\t/**** An XML text value. @private@ ****/\n{\n  int\t\t\twhitespace;\t/* Leading whitespace? */\n  char\t\t\t*string;\t/* Fragment string */\n} mxml_text_t;\n\ntypedef struct mxml_custom_s\t\t/**** An XML custom value. @private@ ****/\n{\n  void\t\t\t*data;\t\t/* Pointer to (allocated) custom data */\n  mxml_custom_destroy_cb_t destroy;\t/* Pointer to destructor function */\n} mxml_custom_t;\n\ntypedef union mxml_value_u\t\t/**** An XML node value. @private@ ****/\n{\n  mxml_element_t\telement;\t/* Element */\n  int\t\t\tinteger;\t/* Integer number */\n  char\t\t\t*opaque;\t/* Opaque string */\n  double\t\treal;\t\t/* Real number */\n  mxml_text_t\t\ttext;\t\t/* Text fragment */\n  mxml_custom_t\t\tcustom;\t\t/* Custom data @since Mini-XML 2.1@ */\n} mxml_value_t;\n\nstruct mxml_node_s\t\t\t/**** An XML node. @private@ ****/\n{\n  mxml_type_t\t\ttype;\t\t/* Node type */\n  struct mxml_node_s\t*next;\t\t/* Next node under same parent */\n  struct mxml_node_s\t*prev;\t\t/* Previous node under same parent */\n  struct mxml_node_s\t*parent;\t/* Parent node */\n  struct mxml_node_s\t*child;\t\t/* First child node */\n  struct mxml_node_s\t*last_child;\t/* Last child node */\n  mxml_value_t\t\tvalue;\t\t/* Node value */\n  int\t\t\tref_count;\t/* Use count */\n  void\t\t\t*user_data;\t/* User data */\n};\n\ntypedef struct mxml_node_s mxml_node_t;\t/**** An XML node. ****/\n\nstruct mxml_index_s\t\t\t /**** An XML node index. @private@ ****/\n{\n  char\t\t\t*attr;\t\t/* Attribute used for indexing or NULL */\n  int\t\t\tnum_nodes;\t/* Number of nodes in index */\n  int\t\t\talloc_nodes;\t/* Allocated nodes in index */\n  int\t\t\tcur_node;\t/* Current node */\n  mxml_node_t\t\t**nodes;\t/* Node array */\n};\n\ntypedef struct mxml_index_s mxml_index_t;\n\t\t\t\t\t/**** An XML node index. ****/\n\ntypedef int (*mxml_custom_load_cb_t)(mxml_node_t *, const char *);\n\t\t\t\t\t/**** Custom data load callback function ****/\n\ntypedef char *(*mxml_custom_save_cb_t)(mxml_node_t *);\n\t\t\t\t\t/**** Custom data save callback function ****/\n\ntypedef int (*mxml_entity_cb_t)(const char *);\n\t\t\t\t\t/**** Entity callback function */\n\ntypedef mxml_type_t (*mxml_load_cb_t)(mxml_node_t *);\n\t\t\t\t\t/**** Load callback function ****/\n\ntypedef const char *(*mxml_save_cb_t)(mxml_node_t *, int);\n\t\t\t\t\t/**** Save callback function ****/\n\ntypedef void (*mxml_sax_cb_t)(mxml_node_t *, mxml_sax_event_t, void *);\n\t\t\t\t\t/**** SAX callback function ****/\n\n\n/*\n * C++ support...\n */\n\n#  ifdef __cplusplus\nextern \"C\" {\n#  endif /* __cplusplus */\n\n/*\n * Prototypes...\n */\n\nPHMXMLAPI extern void\t\tmxmlAdd(mxml_node_t *parent, int where,\n\t\t\t        mxml_node_t *child, mxml_node_t *node);\nPHMXMLAPI extern void\t\tmxmlDelete(mxml_node_t *node);\nPHMXMLAPI extern void\t\tmxmlElementDeleteAttr(mxml_node_t *node,\n\t\t\t                      const char *name);\nPHMXMLAPI extern const char\t*mxmlElementGetAttr(mxml_node_t *node, const char *name);\nPHMXMLAPI extern void\t\tmxmlElementSetAttr(mxml_node_t *node, const char *name,\n\t\t\t                   const char *value);\nextern void\t\tmxmlElementSetAttrf(mxml_node_t *node, const char *name,\n\t\t\t                    const char *format, ...)\n#    ifdef __GNUC__\n__attribute__ ((__format__ (__printf__, 3, 4)))\n#    endif /* __GNUC__ */\n;\nextern int\t\tmxmlEntityAddCallback(mxml_entity_cb_t cb);\nextern const char\t*mxmlEntityGetName(int val);\nextern int\t\tmxmlEntityGetValue(const char *name);\nextern void\t\tmxmlEntityRemoveCallback(mxml_entity_cb_t cb);\nPHMXMLAPI extern mxml_node_t\t*mxmlFindElement(mxml_node_t *node, mxml_node_t *top,\n\t\t\t                 const char *name, const char *attr,\n\t\t\t\t\t const char *value, int descend);\nextern mxml_node_t\t*mxmlFindPath(mxml_node_t *node, const char *path);\nextern const char\t*mxmlGetCDATA(mxml_node_t *node);\nextern const void\t*mxmlGetCustom(mxml_node_t *node);\nextern const char\t*mxmlGetElement(mxml_node_t *node);\nextern mxml_node_t\t*mxmlGetFirstChild(mxml_node_t *node);\nextern int\t\tmxmlGetInteger(mxml_node_t *node);\nextern mxml_node_t\t*mxmlGetLastChild(mxml_node_t *node);\nextern mxml_node_t\t*mxmlGetNextSibling(mxml_node_t *node);\nextern const char\t*mxmlGetOpaque(mxml_node_t *node);\nextern mxml_node_t\t*mxmlGetParent(mxml_node_t *node);\nextern mxml_node_t\t*mxmlGetPrevSibling(mxml_node_t *node);\nextern double\t\tmxmlGetReal(mxml_node_t *node);\nextern int\t\tmxmlGetRefCount(mxml_node_t *node);\nextern const char\t*mxmlGetText(mxml_node_t *node, int *whitespace);\nextern mxml_type_t\tmxmlGetType(mxml_node_t *node);\nextern void\t\t*mxmlGetUserData(mxml_node_t *node);\nextern void\t\tmxmlIndexDelete(mxml_index_t *ind);\nextern mxml_node_t\t*mxmlIndexEnum(mxml_index_t *ind);\nextern mxml_node_t\t*mxmlIndexFind(mxml_index_t *ind,\n\t\t\t               const char *element,\n\t\t\t               const char *value);\nextern int\t\tmxmlIndexGetCount(mxml_index_t *ind);\nextern mxml_index_t\t*mxmlIndexNew(mxml_node_t *node, const char *element,\n\t\t\t              const char *attr);\nextern mxml_node_t\t*mxmlIndexReset(mxml_index_t *ind);\nPHMXMLAPI extern mxml_node_t\t*mxmlLoadFd(mxml_node_t *top, HANDLE fd,\n\t\t\t            mxml_type_t (*cb)(mxml_node_t *));\nextern mxml_node_t\t*mxmlLoadFile(mxml_node_t *top, FILE *fp,\n\t\t\t              mxml_type_t (*cb)(mxml_node_t *));\nPHMXMLAPI extern mxml_node_t\t*mxmlLoadString(mxml_node_t *top, const char *s,\n\t\t\t                mxml_type_t (*cb)(mxml_node_t *));\nPHMXMLAPI extern mxml_node_t\t*mxmlNewCDATA(mxml_node_t *parent, const char *string);\nPHMXMLAPI extern mxml_node_t\t*mxmlNewCustom(mxml_node_t *parent, void *data,\n\t\t\t               mxml_custom_destroy_cb_t destroy);\nPHMXMLAPI extern mxml_node_t\t*mxmlNewElement(mxml_node_t *parent, const char *name);\nPHMXMLAPI extern mxml_node_t\t*mxmlNewInteger(mxml_node_t *parent, int integer);\nPHMXMLAPI extern mxml_node_t\t*mxmlNewOpaque(mxml_node_t *parent, const char *opaque);\nPHMXMLAPI extern mxml_node_t\t*mxmlNewReal(mxml_node_t *parent, double real);\nPHMXMLAPI extern mxml_node_t\t*mxmlNewText(mxml_node_t *parent, int whitespace,\n\t\t\t             const char *string);\nextern mxml_node_t\t*mxmlNewTextf(mxml_node_t *parent, int whitespace,\n\t\t\t              const char *format, ...)\n#    ifdef __GNUC__\n__attribute__ ((__format__ (__printf__, 3, 4)))\n#    endif /* __GNUC__ */\n;\nPHMXMLAPI extern mxml_node_t\t*mxmlNewXML(const char *version);\nPHMXMLAPI extern int\t\tmxmlRelease(mxml_node_t *node);\nPHMXMLAPI extern void\t\tmxmlRemove(mxml_node_t *node);\nPHMXMLAPI extern int\t\tmxmlRetain(mxml_node_t *node);\nPHMXMLAPI extern char\t\t*mxmlSaveAllocString(mxml_node_t *node,\n\t\t\t        \t     mxml_save_cb_t cb);\nPHMXMLAPI extern int\t\tmxmlSaveFd(mxml_node_t *node, HANDLE fd,\n\t\t\t           mxml_save_cb_t cb);\nextern int\t\tmxmlSaveFile(mxml_node_t *node, FILE *fp,\n\t\t\t             mxml_save_cb_t cb);\nPHMXMLAPI extern int\t\tmxmlSaveString(mxml_node_t *node, char *buffer,\n\t\t\t               int bufsize, mxml_save_cb_t cb);\nextern mxml_node_t\t*mxmlSAXLoadFd(mxml_node_t *top, HANDLE fd,\n\t\t\t               mxml_type_t (*cb)(mxml_node_t *),\n\t\t\t               mxml_sax_cb_t sax, void *sax_data);\nextern mxml_node_t\t*mxmlSAXLoadFile(mxml_node_t *top, FILE *fp,\n\t\t\t                 mxml_type_t (*cb)(mxml_node_t *),\n\t\t\t                 mxml_sax_cb_t sax, void *sax_data);\nextern mxml_node_t\t*mxmlSAXLoadString(mxml_node_t *top, const char *s,\n\t\t\t                   mxml_type_t (*cb)(mxml_node_t *),\n\t\t\t                   mxml_sax_cb_t sax, void *sax_data);\nPHMXMLAPI extern int\t\tmxmlSetCDATA(mxml_node_t *node, const char *data);\nPHMXMLAPI extern int\t\tmxmlSetCustom(mxml_node_t *node, void *data,\n\t\t\t              mxml_custom_destroy_cb_t destroy);\nPHMXMLAPI extern void\t\tmxmlSetCustomHandlers(mxml_custom_load_cb_t load,\n\t\t\t                      mxml_custom_save_cb_t save);\nPHMXMLAPI extern int\t\tmxmlSetElement(mxml_node_t *node, const char *name);\nPHMXMLAPI extern void\t\tmxmlSetErrorCallback(mxml_error_cb_t cb);\nextern int\t\tmxmlSetInteger(mxml_node_t *node, int integer);\nPHMXMLAPI extern int\t\tmxmlSetOpaque(mxml_node_t *node, const char *opaque);\nextern int\t\tmxmlSetReal(mxml_node_t *node, double real);\nPHMXMLAPI extern int\t\tmxmlSetText(mxml_node_t *node, int whitespace,\n\t\t\t            const char *string);\nextern int\t\tmxmlSetTextf(mxml_node_t *node, int whitespace,\n\t\t\t             const char *format, ...)\n#    ifdef __GNUC__\n__attribute__ ((__format__ (__printf__, 3, 4)))\n#    endif /* __GNUC__ */\n;\nPHMXMLAPI extern int\t\tmxmlSetUserData(mxml_node_t *node, void *data);\nextern void\t\tmxmlSetWrapMargin(int column);\nPHMXMLAPI extern mxml_node_t\t*mxmlWalkNext(mxml_node_t *node, mxml_node_t *top,\n\t\t\t              int descend);\nPHMXMLAPI extern mxml_node_t\t*mxmlWalkPrev(mxml_node_t *node, mxml_node_t *top,\n\t\t\t              int descend);\n\n\n/*\n * Semi-private functions...\n */\n\nextern void\t\tmxml_error(const char *format, ...);\nPHMXMLAPI extern mxml_type_t\tmxml_ignore_cb(mxml_node_t *node);\nPHMXMLAPI extern mxml_type_t\tmxml_integer_cb(mxml_node_t *node);\nPHMXMLAPI extern mxml_type_t\tmxml_opaque_cb(mxml_node_t *node);\nPHMXMLAPI extern mxml_type_t\tmxml_real_cb(mxml_node_t *node);\n\n\n/*\n * C++ support...\n */\n\n#  ifdef __cplusplus\n}\n#  endif /* __cplusplus */\n#endif /* !_mxml_h_ */\n\n\n/*\n * End of \"$Id: mxml.h 464 2016-06-12 21:16:14Z msweet $\".\n */\n"
  },
  {
    "path": "third_party/phlib/native.c",
    "content": "/*\n * Process Hacker -\n *   native wrapper and support functions\n *\n * Copyright (C) 2009-2016 wj32\n * Copyright (C) 2017 dmex\n *\n * This file is part of Process Hacker.\n *\n * Process Hacker is free software; you can redistribute it and/or modify\n * it under the terms of the GNU General Public License as published by\n * the Free Software Foundation, either version 3 of the License, or\n * (at your option) any later version.\n *\n * Process Hacker is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n * GNU General Public License for more details.\n *\n * You should have received a copy of the GNU General Public License\n * along with Process Hacker.  If not, see <http://www.gnu.org/licenses/>.\n */\n\n#include <ph.h>\n\n#include <apiimport.h>\n#include <kphuser.h>\n#include <lsasup.h>\n#include <mapimg.h>\n\n#define PH_DEVICE_PREFIX_LENGTH 64\n#define PH_DEVICE_MUP_PREFIX_MAX_COUNT 16\n\ntypedef BOOLEAN (NTAPI *PPHP_ENUM_PROCESS_MODULES_CALLBACK)(\n    _In_ HANDLE ProcessHandle,\n    _In_ PLDR_DATA_TABLE_ENTRY Entry,\n    _In_ PVOID AddressOfEntry,\n    _In_opt_ PVOID Context1,\n    _In_opt_ PVOID Context2\n    );\n\ntypedef BOOLEAN (NTAPI *PPHP_ENUM_PROCESS_MODULES32_CALLBACK)(\n    _In_ HANDLE ProcessHandle,\n    _In_ PLDR_DATA_TABLE_ENTRY32 Entry,\n    _In_ ULONG AddressOfEntry,\n    _In_opt_ PVOID Context1,\n    _In_opt_ PVOID Context2\n    );\n\nstatic PH_INITONCE PhDevicePrefixesInitOnce = PH_INITONCE_INIT;\n\nstatic UNICODE_STRING PhDevicePrefixes[26];\nstatic PH_QUEUED_LOCK PhDevicePrefixesLock = PH_QUEUED_LOCK_INIT;\n\nstatic PPH_STRING PhDeviceMupPrefixes[PH_DEVICE_MUP_PREFIX_MAX_COUNT] = { 0 };\nstatic ULONG PhDeviceMupPrefixesCount = 0;\nstatic PH_QUEUED_LOCK PhDeviceMupPrefixesLock = PH_QUEUED_LOCK_INIT;\n\nstatic PH_INITONCE PhPredefineKeyInitOnce = PH_INITONCE_INIT;\nstatic UNICODE_STRING PhPredefineKeyNames[PH_KEY_MAXIMUM_PREDEFINE] =\n{\n    RTL_CONSTANT_STRING(L\"\\\\Registry\\\\Machine\"),\n    RTL_CONSTANT_STRING(L\"\\\\Registry\\\\User\"),\n    RTL_CONSTANT_STRING(L\"\\\\Registry\\\\Machine\\\\Software\\\\Classes\"),\n    { 0, 0, NULL }\n};\nstatic HANDLE PhPredefineKeyHandles[PH_KEY_MAXIMUM_PREDEFINE] = { 0 };\n\n/**\n * Queries information about the token of the current process.\n */\nPH_TOKEN_ATTRIBUTES PhGetOwnTokenAttributes(\n    VOID\n    )\n{\n    static PH_INITONCE initOnce = PH_INITONCE_INIT;\n    static PH_TOKEN_ATTRIBUTES attributes;\n\n    if (PhBeginInitOnce(&initOnce))\n    {\n        if (NT_SUCCESS(NtOpenProcessToken(\n            NtCurrentProcess(),\n            TOKEN_QUERY,\n            &attributes.TokenHandle\n            )))\n        {\n            BOOLEAN elevated = TRUE;\n            TOKEN_ELEVATION_TYPE elevationType = TokenElevationTypeFull;\n\n            PhGetTokenIsElevated(attributes.TokenHandle, &elevated);\n            PhGetTokenElevationType(attributes.TokenHandle, &elevationType);\n\n            attributes.Elevated = elevated;\n            attributes.ElevationType = elevationType;\n        }\n\n        PhEndInitOnce(&initOnce);\n    }\n\n    return attributes;\n}\n\n/**\n * Opens a process.\n *\n * \\param ProcessHandle A variable which receives a handle to the process.\n * \\param DesiredAccess The desired access to the process.\n * \\param ProcessId The ID of the process.\n */\nNTSTATUS PhOpenProcess(\n    _Out_ PHANDLE ProcessHandle,\n    _In_ ACCESS_MASK DesiredAccess,\n    _In_ HANDLE ProcessId\n    )\n{\n    NTSTATUS status;\n    OBJECT_ATTRIBUTES objectAttributes;\n    CLIENT_ID clientId;\n\n    clientId.UniqueProcess = ProcessId;\n    clientId.UniqueThread = NULL;\n\n    if (KphIsVerified() && (DesiredAccess & KPH_PROCESS_READ_ACCESS) == DesiredAccess)\n    {\n        status = KphOpenProcess(\n            ProcessHandle,\n            DesiredAccess,\n            &clientId\n            );\n    }\n    else\n    {\n        InitializeObjectAttributes(&objectAttributes, NULL, 0, NULL, NULL);\n        status = NtOpenProcess(\n            ProcessHandle,\n            DesiredAccess,\n            &objectAttributes,\n            &clientId\n            );\n\n        if (status == STATUS_ACCESS_DENIED && KphIsVerified())\n        {\n            status = KphOpenProcess(\n                ProcessHandle,\n                DesiredAccess,\n                &clientId\n                );\n        }\n    }\n\n    return status;\n}\n\n/** Limited API for untrusted/external code. */\nNTSTATUS PhOpenProcessPublic(\n    _Out_ PHANDLE ProcessHandle,\n    _In_ ACCESS_MASK DesiredAccess,\n    _In_ HANDLE ProcessId\n    )\n{\n    OBJECT_ATTRIBUTES objectAttributes;\n    CLIENT_ID clientId;\n\n    InitializeObjectAttributes(&objectAttributes, NULL, 0, NULL, NULL);\n    clientId.UniqueProcess = ProcessId;\n    clientId.UniqueThread = NULL;\n\n    return NtOpenProcess(\n        ProcessHandle,\n        DesiredAccess,\n        &objectAttributes,\n        &clientId\n        );\n}\n\n/**\n * Opens a thread.\n *\n * \\param ThreadHandle A variable which receives a handle to the thread.\n * \\param DesiredAccess The desired access to the thread.\n * \\param ThreadId The ID of the thread.\n */\nNTSTATUS PhOpenThread(\n    _Out_ PHANDLE ThreadHandle,\n    _In_ ACCESS_MASK DesiredAccess,\n    _In_ HANDLE ThreadId\n    )\n{\n    NTSTATUS status;\n    OBJECT_ATTRIBUTES objectAttributes;\n    CLIENT_ID clientId;\n\n    clientId.UniqueProcess = NULL;\n    clientId.UniqueThread = ThreadId;\n\n    if (KphIsVerified() && (DesiredAccess & KPH_THREAD_READ_ACCESS) == DesiredAccess)\n    {\n        status = KphOpenThread(\n            ThreadHandle,\n            DesiredAccess,\n            &clientId\n            );\n    }\n    else\n    {\n        InitializeObjectAttributes(&objectAttributes, NULL, 0, NULL, NULL);\n        status = NtOpenThread(\n            ThreadHandle,\n            DesiredAccess,\n            &objectAttributes,\n            &clientId\n            );\n\n        if (status == STATUS_ACCESS_DENIED && KphIsVerified())\n        {\n            status = KphOpenThread(\n                ThreadHandle,\n                DesiredAccess,\n                &clientId\n                );\n        }\n    }\n\n    return status;\n}\n\n/** Limited API for untrusted/external code. */\nNTSTATUS PhOpenThreadPublic(\n    _Out_ PHANDLE ThreadHandle,\n    _In_ ACCESS_MASK DesiredAccess,\n    _In_ HANDLE ThreadId\n    )\n{\n    OBJECT_ATTRIBUTES objectAttributes;\n    CLIENT_ID clientId;\n\n    clientId.UniqueProcess = NULL;\n    clientId.UniqueThread = ThreadId;\n\n    InitializeObjectAttributes(&objectAttributes, NULL, 0, NULL, NULL);\n\n    return NtOpenThread(\n        ThreadHandle,\n        DesiredAccess,\n        &objectAttributes,\n        &clientId\n        );\n}\n\nNTSTATUS PhOpenThreadProcess(\n    _In_ HANDLE ThreadHandle,\n    _In_ ACCESS_MASK DesiredAccess,\n    _Out_ PHANDLE ProcessHandle\n    )\n{\n    if (KphIsConnected())\n    {\n        return KphOpenThreadProcess(\n            ThreadHandle,\n            DesiredAccess,\n            ProcessHandle\n            );\n    }\n    else\n    {\n        NTSTATUS status;\n        THREAD_BASIC_INFORMATION basicInfo;\n\n        if (!NT_SUCCESS(status = PhGetThreadBasicInformation(\n            ThreadHandle,\n            &basicInfo\n            )))\n            return status;\n\n        return PhOpenProcess(\n            ProcessHandle,\n            DesiredAccess,\n            basicInfo.ClientId.UniqueProcess\n            );\n    }\n}\n\n/**\n * Opens a process token.\n *\n * \\param ProcessHandle A handle to a process.\n * \\param DesiredAccess The desired access to the token.\n * \\param TokenHandle A variable which receives a handle to the token.\n */\nNTSTATUS PhOpenProcessToken(\n    _In_ HANDLE ProcessHandle,\n    _In_ ACCESS_MASK DesiredAccess,\n    _Out_ PHANDLE TokenHandle\n    )\n{\n    NTSTATUS status;\n\n    if (KphIsVerified() && (DesiredAccess & KPH_TOKEN_READ_ACCESS) == DesiredAccess)\n    {\n        status = KphOpenProcessToken(\n            ProcessHandle,\n            DesiredAccess,\n            TokenHandle\n            );\n    }\n    else\n    {\n        status = NtOpenProcessToken(\n            ProcessHandle,\n            DesiredAccess,\n            TokenHandle\n            );\n\n        if (status == STATUS_ACCESS_DENIED && KphIsVerified())\n        {\n            status = KphOpenProcessToken(\n                ProcessHandle,\n                DesiredAccess,\n                TokenHandle\n                );\n        }\n    }\n\n    return status;\n}\n\nNTSTATUS PhGetObjectSecurity(\n    _In_ HANDLE Handle,\n    _In_ SECURITY_INFORMATION SecurityInformation,\n    _Out_ PSECURITY_DESCRIPTOR *SecurityDescriptor\n    )\n{\n    NTSTATUS status;\n    ULONG bufferSize;\n    PVOID buffer;\n\n    bufferSize = 0x100;\n    buffer = PhAllocate(bufferSize);\n    // This is required (especially for File objects) because some drivers don't seem to handle\n    // QuerySecurity properly.\n    memset(buffer, 0, bufferSize);\n\n    status = NtQuerySecurityObject(\n        Handle,\n        SecurityInformation,\n        buffer,\n        bufferSize,\n        &bufferSize\n        );\n\n    if (status == STATUS_BUFFER_TOO_SMALL)\n    {\n        PhFree(buffer);\n        buffer = PhAllocate(bufferSize);\n        memset(buffer, 0, bufferSize);\n\n        status = NtQuerySecurityObject(\n            Handle,\n            SecurityInformation,\n            buffer,\n            bufferSize,\n            &bufferSize\n            );\n    }\n\n    if (!NT_SUCCESS(status))\n    {\n        PhFree(buffer);\n        return status;\n    }\n\n    *SecurityDescriptor = (PSECURITY_DESCRIPTOR)buffer;\n\n    return status;\n}\n\nNTSTATUS PhSetObjectSecurity(\n    _In_ HANDLE Handle,\n    _In_ SECURITY_INFORMATION SecurityInformation,\n    _In_ PSECURITY_DESCRIPTOR SecurityDescriptor\n    )\n{\n    return NtSetSecurityObject(\n        Handle,\n        SecurityInformation,\n        SecurityDescriptor\n        );\n}\n\n/**\n * Terminates a process.\n *\n * \\param ProcessHandle A handle to a process. The handle must have PROCESS_TERMINATE access.\n * \\param ExitStatus A status value that indicates why the process is being terminated.\n */\nNTSTATUS PhTerminateProcess(\n    _In_ HANDLE ProcessHandle,\n    _In_ NTSTATUS ExitStatus\n    )\n{\n    NTSTATUS status;\n\n    if (KphIsVerified())\n    {\n        status = KphTerminateProcess(\n            ProcessHandle,\n            ExitStatus\n            );\n\n        if (status != STATUS_NOT_SUPPORTED)\n            return status;\n    }\n\n    return NtTerminateProcess(\n        ProcessHandle,\n        ExitStatus\n        );\n}\n\n/** Limited API for untrusted/external code. */\nNTSTATUS PhTerminateProcessPublic(\n    _In_ HANDLE ProcessHandle,\n    _In_ NTSTATUS ExitStatus\n    )\n{\n    return NtTerminateProcess(\n        ProcessHandle,\n        ExitStatus\n        );\n}\n\n/**\n * Queries variable-sized information for a process. The function allocates a buffer to contain the\n * information.\n *\n * \\param ProcessHandle A handle to a process. The access required depends on the information class\n * specified.\n * \\param ProcessInformationClass The information class to retrieve.\n * \\param Buffer A variable which receives a pointer to a buffer containing the information. You\n * must free the buffer using PhFree() when you no longer need it.\n */\nNTSTATUS PhpQueryProcessVariableSize(\n    _In_ HANDLE ProcessHandle,\n    _In_ PROCESSINFOCLASS ProcessInformationClass,\n    _Out_ PVOID *Buffer\n    )\n{\n    NTSTATUS status;\n    PVOID buffer;\n    ULONG returnLength = 0;\n\n    status = NtQueryInformationProcess(\n        ProcessHandle,\n        ProcessInformationClass,\n        NULL,\n        0,\n        &returnLength\n        );\n\n    if (status != STATUS_BUFFER_OVERFLOW && status != STATUS_BUFFER_TOO_SMALL && status != STATUS_INFO_LENGTH_MISMATCH)\n        return status;\n\n    buffer = PhAllocate(returnLength);\n    status = NtQueryInformationProcess(\n        ProcessHandle,\n        ProcessInformationClass,\n        buffer,\n        returnLength,\n        &returnLength\n        );\n\n    if (NT_SUCCESS(status))\n    {\n        *Buffer = buffer;\n    }\n    else\n    {\n        PhFree(buffer);\n    }\n\n    return status;\n}\n\n/**\n * Gets the file name of the process' image.\n *\n * \\param ProcessHandle A handle to a process. The handle must have\n * PROCESS_QUERY_LIMITED_INFORMATION access.\n * \\param FileName A variable which receives a pointer to a string containing the file name. You\n * must free the string using PhDereferenceObject() when you no longer need it.\n */\nNTSTATUS PhGetProcessImageFileName(\n    _In_ HANDLE ProcessHandle,\n    _Out_ PPH_STRING *FileName\n    )\n{\n    NTSTATUS status;\n    PUNICODE_STRING fileName;\n\n    status = PhpQueryProcessVariableSize(\n        ProcessHandle,\n        ProcessImageFileName,\n        &fileName\n        );\n\n    if (!NT_SUCCESS(status))\n        return status;\n\n    *FileName = PhCreateStringFromUnicodeString(fileName);\n    PhFree(fileName);\n\n    return status;\n}\n\n/**\n * Gets the Win32 file name of the process' image.\n *\n * \\param ProcessHandle A handle to a process. The handle must have\n * PROCESS_QUERY_LIMITED_INFORMATION access.\n * \\param FileName A variable which receives a pointer to a string containing the file name. You\n * must free the string using PhDereferenceObject() when you no longer need it.\n *\n * \\remarks This function is only available on Windows Vista and above.\n */\nNTSTATUS PhGetProcessImageFileNameWin32(\n    _In_ HANDLE ProcessHandle,\n    _Out_ PPH_STRING *FileName\n    )\n{\n    NTSTATUS status;\n    PUNICODE_STRING fileName;\n\n    status = PhpQueryProcessVariableSize(\n        ProcessHandle,\n        ProcessImageFileNameWin32,\n        &fileName\n        );\n\n    if (!NT_SUCCESS(status))\n        return status;\n\n    *FileName = PhCreateStringFromUnicodeString(fileName);\n    PhFree(fileName);\n\n    return status;\n}\n\n/**\n * Gets a string stored in a process' parameters structure.\n *\n * \\param ProcessHandle A handle to a process. The handle must have\n * PROCESS_QUERY_LIMITED_INFORMATION and PROCESS_VM_READ access.\n * \\param Offset The string to retrieve.\n * \\param String A variable which receives a pointer to the requested string. You must free the\n * string using PhDereferenceObject() when you no longer need it.\n *\n * \\retval STATUS_INVALID_PARAMETER_2 An invalid value was specified in the Offset parameter.\n */\nNTSTATUS PhGetProcessPebString(\n    _In_ HANDLE ProcessHandle,\n    _In_ PH_PEB_OFFSET Offset,\n    _Out_ PPH_STRING *String\n    )\n{\n    NTSTATUS status;\n    PPH_STRING string;\n    ULONG offset;\n\n#define PEB_OFFSET_CASE(Enum, Field) \\\n    case Enum: offset = FIELD_OFFSET(RTL_USER_PROCESS_PARAMETERS, Field); break; \\\n    case Enum | PhpoWow64: offset = FIELD_OFFSET(RTL_USER_PROCESS_PARAMETERS32, Field); break\n\n    switch (Offset)\n    {\n        PEB_OFFSET_CASE(PhpoCurrentDirectory, CurrentDirectory);\n        PEB_OFFSET_CASE(PhpoDllPath, DllPath);\n        PEB_OFFSET_CASE(PhpoImagePathName, ImagePathName);\n        PEB_OFFSET_CASE(PhpoCommandLine, CommandLine);\n        PEB_OFFSET_CASE(PhpoWindowTitle, WindowTitle);\n        PEB_OFFSET_CASE(PhpoDesktopInfo, DesktopInfo);\n        PEB_OFFSET_CASE(PhpoShellInfo, ShellInfo);\n        PEB_OFFSET_CASE(PhpoRuntimeData, RuntimeData);\n    default:\n        return STATUS_INVALID_PARAMETER_2;\n    }\n\n    if (!(Offset & PhpoWow64))\n    {\n        PROCESS_BASIC_INFORMATION basicInfo;\n        PVOID processParameters;\n        UNICODE_STRING unicodeString;\n\n        // Get the PEB address.\n        if (!NT_SUCCESS(status = PhGetProcessBasicInformation(ProcessHandle, &basicInfo)))\n            return status;\n\n        // Read the address of the process parameters.\n        if (!NT_SUCCESS(status = NtReadVirtualMemory(\n            ProcessHandle,\n            PTR_ADD_OFFSET(basicInfo.PebBaseAddress, FIELD_OFFSET(PEB, ProcessParameters)),\n            &processParameters,\n            sizeof(PVOID),\n            NULL\n            )))\n            return status;\n\n        // Read the string structure.\n        if (!NT_SUCCESS(status = NtReadVirtualMemory(\n            ProcessHandle,\n            PTR_ADD_OFFSET(processParameters, offset),\n            &unicodeString,\n            sizeof(UNICODE_STRING),\n            NULL\n            )))\n            return status;\n\n        string = PhCreateStringEx(NULL, unicodeString.Length);\n\n        // Read the string contents.\n        if (!NT_SUCCESS(status = NtReadVirtualMemory(\n            ProcessHandle,\n            unicodeString.Buffer,\n            string->Buffer,\n            string->Length,\n            NULL\n            )))\n        {\n            PhDereferenceObject(string);\n            return status;\n        }\n    }\n    else\n    {\n        PVOID peb32;\n        ULONG processParameters32;\n        UNICODE_STRING32 unicodeString32;\n\n        if (!NT_SUCCESS(status = PhGetProcessPeb32(ProcessHandle, &peb32)))\n            return status;\n\n        if (!NT_SUCCESS(status = NtReadVirtualMemory(\n            ProcessHandle,\n            PTR_ADD_OFFSET(peb32, FIELD_OFFSET(PEB32, ProcessParameters)),\n            &processParameters32,\n            sizeof(ULONG),\n            NULL\n            )))\n            return status;\n\n        if (!NT_SUCCESS(status = NtReadVirtualMemory(\n            ProcessHandle,\n            PTR_ADD_OFFSET(processParameters32, offset),\n            &unicodeString32,\n            sizeof(UNICODE_STRING32),\n            NULL\n            )))\n            return status;\n\n        string = PhCreateStringEx(NULL, unicodeString32.Length);\n\n        // Read the string contents.\n        if (!NT_SUCCESS(status = NtReadVirtualMemory(\n            ProcessHandle,\n            UlongToPtr(unicodeString32.Buffer),\n            string->Buffer,\n            string->Length,\n            NULL\n            )))\n        {\n            PhDereferenceObject(string);\n            return status;\n        }\n    }\n\n    *String = string;\n\n    return status;\n}\n\n/**\n * Gets a process' command line.\n *\n * \\param ProcessHandle A handle to a process. The handle must have\n * PROCESS_QUERY_LIMITED_INFORMATION. Before Windows 8.1, the handle must also have PROCESS_VM_READ\n * access.\n * \\param String A variable which receives a pointer to a string containing the command line. You\n * must free the string using PhDereferenceObject() when you no longer need it.\n */\nNTSTATUS PhGetProcessCommandLine(\n    _In_ HANDLE ProcessHandle,\n    _Out_ PPH_STRING *CommandLine\n    )\n{\n    NTSTATUS status;\n\n    if (WindowsVersion >= WINDOWS_8_1)\n    {\n        PUNICODE_STRING commandLine;\n\n        status = PhpQueryProcessVariableSize(\n            ProcessHandle,\n            ProcessCommandLineInformation,\n            &commandLine\n            );\n\n        if (NT_SUCCESS(status))\n        {\n            *CommandLine = PhCreateStringFromUnicodeString(commandLine);\n            PhFree(commandLine);\n\n            return status;\n        }\n    }\n\n    return PhGetProcessPebString(ProcessHandle, PhpoCommandLine, CommandLine);\n}\n\n/**\n * Gets the window flags and window title of a process.\n *\n * \\param ProcessHandle A handle to a process. The handle must have\n * PROCESS_QUERY_LIMITED_INFORMATION. Before Windows 7 SP1, the handle must also have\n * PROCESS_VM_READ access.\n * \\param WindowFlags A variable which receives the window flags.\n * \\param WindowTitle A variable which receives a pointer to the window title. You must free the\n * string using PhDereferenceObject() when you no longer need it.\n */\nNTSTATUS PhGetProcessWindowTitle(\n    _In_ HANDLE ProcessHandle,\n    _Out_ PULONG WindowFlags,\n    _Out_ PPH_STRING *WindowTitle\n    )\n{\n    NTSTATUS status;\n#ifdef _WIN64\n    BOOLEAN isWow64 = FALSE;\n#endif\n    ULONG windowFlags;\n    PPROCESS_WINDOW_INFORMATION windowInfo;\n\n    status = PhpQueryProcessVariableSize(\n        ProcessHandle,\n        ProcessWindowInformation,\n        &windowInfo\n        );\n\n    if (NT_SUCCESS(status))\n    {\n        *WindowFlags = windowInfo->WindowFlags;\n        *WindowTitle = PhCreateStringEx(windowInfo->WindowTitle, windowInfo->WindowTitleLength);\n        PhFree(windowInfo);\n\n        return status;\n    }\n\n#ifdef _WIN64\n    PhGetProcessIsWow64(ProcessHandle, &isWow64);\n\n    if (!isWow64)\n#endif\n    {\n        PROCESS_BASIC_INFORMATION basicInfo;\n        PVOID processParameters;\n\n        // Get the PEB address.\n        if (!NT_SUCCESS(status = PhGetProcessBasicInformation(ProcessHandle, &basicInfo)))\n            return status;\n\n        // Read the address of the process parameters.\n        if (!NT_SUCCESS(status = NtReadVirtualMemory(\n            ProcessHandle,\n            PTR_ADD_OFFSET(basicInfo.PebBaseAddress, FIELD_OFFSET(PEB, ProcessParameters)),\n            &processParameters,\n            sizeof(PVOID),\n            NULL\n            )))\n            return status;\n\n        // Read the window flags.\n        if (!NT_SUCCESS(status = NtReadVirtualMemory(\n            ProcessHandle,\n            PTR_ADD_OFFSET(processParameters, FIELD_OFFSET(RTL_USER_PROCESS_PARAMETERS, WindowFlags)),\n            &windowFlags,\n            sizeof(ULONG),\n            NULL\n            )))\n            return status;\n    }\n#ifdef _WIN64\n    else\n    {\n        PVOID peb32;\n        ULONG processParameters32;\n\n        if (!NT_SUCCESS(status = PhGetProcessPeb32(ProcessHandle, &peb32)))\n            return status;\n\n        if (!NT_SUCCESS(status = NtReadVirtualMemory(\n            ProcessHandle,\n            PTR_ADD_OFFSET(peb32, FIELD_OFFSET(PEB32, ProcessParameters)),\n            &processParameters32,\n            sizeof(ULONG),\n            NULL\n            )))\n            return status;\n\n        if (!NT_SUCCESS(status = NtReadVirtualMemory(\n            ProcessHandle,\n            PTR_ADD_OFFSET(processParameters32, FIELD_OFFSET(RTL_USER_PROCESS_PARAMETERS32, WindowFlags)),\n            &windowFlags,\n            sizeof(ULONG),\n            NULL\n            )))\n            return status;\n    }\n#endif\n\n#ifdef _WIN64\n    status = PhGetProcessPebString(ProcessHandle, PhpoWindowTitle | (isWow64 ? PhpoWow64 : 0), WindowTitle);\n#else\n    status = PhGetProcessPebString(ProcessHandle, PhpoWindowTitle, WindowTitle);\n#endif\n\n    if (NT_SUCCESS(status))\n        *WindowFlags = windowFlags;\n\n    return status;\n}\n\nNTSTATUS PhGetProcessDepStatus(\n    _In_ HANDLE ProcessHandle,\n    _Out_ PULONG DepStatus\n    )\n{\n    NTSTATUS status;\n    ULONG executeFlags;\n    ULONG depStatus;\n\n    if (!NT_SUCCESS(status = PhGetProcessExecuteFlags(\n        ProcessHandle,\n        &executeFlags\n        )))\n        return status;\n\n    // Check if execution of data pages is enabled.\n    if (executeFlags & MEM_EXECUTE_OPTION_ENABLE)\n        depStatus = 0;\n    else\n        depStatus = PH_PROCESS_DEP_ENABLED;\n\n    if (executeFlags & MEM_EXECUTE_OPTION_DISABLE_THUNK_EMULATION)\n        depStatus |= PH_PROCESS_DEP_ATL_THUNK_EMULATION_DISABLED;\n    if (executeFlags & MEM_EXECUTE_OPTION_PERMANENT)\n        depStatus |= PH_PROCESS_DEP_PERMANENT;\n\n    *DepStatus = depStatus;\n\n    return status;\n}\n\n/**\n * Gets a process' environment block.\n *\n * \\param ProcessHandle A handle to a process. The handle must have PROCESS_QUERY_INFORMATION and\n * PROCESS_VM_READ access.\n * \\param Flags A combination of flags.\n * \\li \\c PH_GET_PROCESS_ENVIRONMENT_WOW64 Retrieve the environment block from the WOW64 PEB.\n * \\param Environment A variable which will receive a pointer to the environment block copied from\n * the process. You must free the block using PhFreePage() when you no longer need it.\n * \\param EnvironmentLength A variable which will receive the length of the environment block, in\n * bytes.\n */\nNTSTATUS PhGetProcessEnvironment(\n    _In_ HANDLE ProcessHandle,\n    _In_ ULONG Flags,\n    _Out_ PVOID *Environment,\n    _Out_ PULONG EnvironmentLength\n    )\n{\n    NTSTATUS status;\n    PVOID environmentRemote;\n    MEMORY_BASIC_INFORMATION mbi;\n    PVOID environment;\n    ULONG environmentLength;\n\n    if (!(Flags & PH_GET_PROCESS_ENVIRONMENT_WOW64))\n    {\n        PROCESS_BASIC_INFORMATION basicInfo;\n        PVOID processParameters;\n\n        status = PhGetProcessBasicInformation(ProcessHandle, &basicInfo);\n\n        if (!NT_SUCCESS(status))\n            return status;\n\n        if (!NT_SUCCESS(status = NtReadVirtualMemory(\n            ProcessHandle,\n            PTR_ADD_OFFSET(basicInfo.PebBaseAddress, FIELD_OFFSET(PEB, ProcessParameters)),\n            &processParameters,\n            sizeof(PVOID),\n            NULL\n            )))\n            return status;\n\n        if (!NT_SUCCESS(status = NtReadVirtualMemory(\n            ProcessHandle,\n            PTR_ADD_OFFSET(processParameters, FIELD_OFFSET(RTL_USER_PROCESS_PARAMETERS, Environment)),\n            &environmentRemote,\n            sizeof(PVOID),\n            NULL\n            )))\n            return status;\n    }\n    else\n    {\n        PVOID peb32;\n        ULONG processParameters32;\n        ULONG environmentRemote32;\n\n        status = PhGetProcessPeb32(ProcessHandle, &peb32);\n\n        if (!NT_SUCCESS(status))\n            return status;\n\n        if (!NT_SUCCESS(status = NtReadVirtualMemory(\n            ProcessHandle,\n            PTR_ADD_OFFSET(peb32, FIELD_OFFSET(PEB32, ProcessParameters)),\n            &processParameters32,\n            sizeof(ULONG),\n            NULL\n            )))\n            return status;\n\n        if (!NT_SUCCESS(status = NtReadVirtualMemory(\n            ProcessHandle,\n            PTR_ADD_OFFSET(processParameters32, FIELD_OFFSET(RTL_USER_PROCESS_PARAMETERS32, Environment)),\n            &environmentRemote32,\n            sizeof(ULONG),\n            NULL\n            )))\n            return status;\n\n        environmentRemote = UlongToPtr(environmentRemote32);\n    }\n\n    if (!NT_SUCCESS(status = NtQueryVirtualMemory(\n        ProcessHandle,\n        environmentRemote,\n        MemoryBasicInformation,\n        &mbi,\n        sizeof(MEMORY_BASIC_INFORMATION),\n        NULL\n        )))\n        return status;\n\n    environmentLength = (ULONG)(mbi.RegionSize -\n        ((ULONG_PTR)environmentRemote - (ULONG_PTR)mbi.BaseAddress));\n\n    // Read in the entire region of memory.\n\n    environment = PhAllocatePage(environmentLength, NULL);\n\n    if (!environment)\n        return STATUS_NO_MEMORY;\n\n    if (!NT_SUCCESS(status = NtReadVirtualMemory(\n        ProcessHandle,\n        environmentRemote,\n        environment,\n        environmentLength,\n        NULL\n        )))\n    {\n        PhFreePage(environment);\n        return status;\n    }\n\n    *Environment = environment;\n\n    if (EnvironmentLength)\n        *EnvironmentLength = environmentLength;\n\n    return status;\n}\n\nBOOLEAN PhEnumProcessEnvironmentVariables(\n    _In_ PVOID Environment,\n    _In_ ULONG EnvironmentLength,\n    _Inout_ PULONG EnumerationKey,\n    _Out_ PPH_ENVIRONMENT_VARIABLE Variable\n    )\n{\n    ULONG length;\n    ULONG startIndex;\n    PWCHAR name;\n    ULONG nameLength;\n    PWCHAR value;\n    ULONG valueLength;\n    PWCHAR currentChar;\n    ULONG currentIndex;\n\n    length = EnvironmentLength / sizeof(WCHAR);\n\n    currentIndex = *EnumerationKey;\n    currentChar = (PWCHAR)Environment + currentIndex;\n    startIndex = currentIndex;\n    name = currentChar;\n\n    // Find the end of the name.\n    while (TRUE)\n    {\n        if (currentIndex >= length)\n            return FALSE;\n        if (*currentChar == '=')\n            break;\n        if (*currentChar == 0)\n            return FALSE; // no more variables\n\n        currentIndex++;\n        currentChar++;\n    }\n\n    nameLength = currentIndex - startIndex;\n\n    currentIndex++;\n    currentChar++;\n    startIndex = currentIndex;\n    value = currentChar;\n\n    // Find the end of the value.\n    while (TRUE)\n    {\n        if (currentIndex >= length)\n            return FALSE;\n        if (*currentChar == 0)\n            break;\n\n        currentIndex++;\n        currentChar++;\n    }\n\n    valueLength = currentIndex - startIndex;\n\n    currentIndex++;\n    *EnumerationKey = currentIndex;\n\n    Variable->Name.Buffer = name;\n    Variable->Name.Length = nameLength * sizeof(WCHAR);\n    Variable->Value.Buffer = value;\n    Variable->Value.Length = valueLength * sizeof(WCHAR);\n\n    return TRUE;\n}\n\n/**\n * Gets the file name of a mapped section.\n *\n * \\param ProcessHandle A handle to a process. The handle must have PROCESS_QUERY_INFORMATION\n * access.\n * \\param BaseAddress The base address of the section view.\n * \\param FileName A variable which receives a pointer to a string containing the file name of the\n * section. You must free the string using PhDereferenceObject() when you no longer need it.\n */\nNTSTATUS PhGetProcessMappedFileName(\n    _In_ HANDLE ProcessHandle,\n    _In_ PVOID BaseAddress,\n    _Out_ PPH_STRING *FileName\n    )\n{\n    NTSTATUS status;\n    PVOID buffer;\n    SIZE_T bufferSize;\n    SIZE_T returnLength;\n    PUNICODE_STRING unicodeString;\n\n    bufferSize = 0x100;\n    buffer = PhAllocate(bufferSize);\n\n    status = NtQueryVirtualMemory(\n        ProcessHandle,\n        BaseAddress,\n        MemoryMappedFilenameInformation,\n        buffer,\n        bufferSize,\n        &returnLength\n        );\n\n    if (status == STATUS_BUFFER_OVERFLOW)\n    {\n        PhFree(buffer);\n        bufferSize = returnLength;\n        buffer = PhAllocate(bufferSize);\n\n        status = NtQueryVirtualMemory(\n            ProcessHandle,\n            BaseAddress,\n            MemoryMappedFilenameInformation,\n            buffer,\n            bufferSize,\n            &returnLength\n            );\n    }\n\n    if (!NT_SUCCESS(status))\n    {\n        PhFree(buffer);\n        return status;\n    }\n\n    unicodeString = (PUNICODE_STRING)buffer;\n    *FileName = PhCreateStringFromUnicodeString(unicodeString);\n    PhFree(buffer);\n\n    return status;\n}\n\n/**\n * Gets working set information for a process.\n *\n * \\param ProcessHandle A handle to a process. The handle must have PROCESS_QUERY_INFORMATION\n * access.\n * \\param WorkingSetInformation A variable which receives a pointer to the information. You must\n * free the buffer using PhFree() when you no longer need it.\n */\nNTSTATUS PhGetProcessWorkingSetInformation(\n    _In_ HANDLE ProcessHandle,\n    _Out_ PMEMORY_WORKING_SET_INFORMATION *WorkingSetInformation\n    )\n{\n    NTSTATUS status;\n    PVOID buffer;\n    SIZE_T bufferSize;\n\n    bufferSize = 0x8000;\n    buffer = PhAllocate(bufferSize);\n\n    while ((status = NtQueryVirtualMemory(\n        ProcessHandle,\n        NULL,\n        MemoryWorkingSetInformation,\n        buffer,\n        bufferSize,\n        NULL\n        )) == STATUS_INFO_LENGTH_MISMATCH)\n    {\n        PhFree(buffer);\n        bufferSize *= 2;\n\n        // Fail if we're resizing the buffer to something very large.\n        if (bufferSize > PH_LARGE_BUFFER_SIZE)\n            return STATUS_INSUFFICIENT_RESOURCES;\n\n        buffer = PhAllocate(bufferSize);\n    }\n\n    if (!NT_SUCCESS(status))\n    {\n        PhFree(buffer);\n        return status;\n    }\n\n    *WorkingSetInformation = (PMEMORY_WORKING_SET_INFORMATION)buffer;\n\n    return status;\n}\n\n/**\n * Gets working set counters for a process.\n *\n * \\param ProcessHandle A handle to a process. The handle must have PROCESS_QUERY_INFORMATION\n * access.\n * \\param WsCounters A variable which receives the counters.\n */\nNTSTATUS PhGetProcessWsCounters(\n    _In_ HANDLE ProcessHandle,\n    _Out_ PPH_PROCESS_WS_COUNTERS WsCounters\n    )\n{\n    NTSTATUS status;\n    PMEMORY_WORKING_SET_INFORMATION wsInfo;\n    PH_PROCESS_WS_COUNTERS wsCounters;\n    ULONG_PTR i;\n\n    if (!NT_SUCCESS(status = PhGetProcessWorkingSetInformation(\n        ProcessHandle,\n        &wsInfo\n        )))\n        return status;\n\n    memset(&wsCounters, 0, sizeof(PH_PROCESS_WS_COUNTERS));\n\n    for (i = 0; i < wsInfo->NumberOfEntries; i++)\n    {\n        wsCounters.NumberOfPages++;\n\n        if (wsInfo->WorkingSetInfo[i].ShareCount > 1)\n            wsCounters.NumberOfSharedPages++;\n        if (wsInfo->WorkingSetInfo[i].ShareCount == 0)\n            wsCounters.NumberOfPrivatePages++;\n        if (wsInfo->WorkingSetInfo[i].Shared)\n            wsCounters.NumberOfShareablePages++;\n    }\n\n    PhFree(wsInfo);\n\n    *WsCounters = wsCounters;\n\n    return status;\n}\n\n/**\n * Causes a process to unload a DLL.\n *\n * \\param ProcessHandle A handle to a process. The handle must have\n * PROCESS_QUERY_LIMITED_INFORMATION, PROCESS_CREATE_THREAD, PROCESS_VM_OPERATION, PROCESS_VM_READ\n * and PROCESS_VM_WRITE access.\n * \\param BaseAddress The base address of the DLL to unload.\n * \\param Timeout The timeout, in milliseconds, for the process to unload the DLL.\n */\nNTSTATUS PhUnloadDllProcess(\n    _In_ HANDLE ProcessHandle,\n    _In_ PVOID BaseAddress,\n    _In_opt_ PLARGE_INTEGER Timeout\n    )\n{\n#ifdef _WIN64\n    static PVOID ldrUnloadDll32 = NULL;\n#endif\n\n    NTSTATUS status;\n#ifdef _WIN64\n    BOOLEAN isWow64 = FALSE;\n    BOOLEAN isModule32 = FALSE;\n#endif\n    HANDLE threadHandle;\n    THREAD_BASIC_INFORMATION basicInfo;\n    PVOID threadStart;\n\n#ifdef _WIN64\n    PhGetProcessIsWow64(ProcessHandle, &isWow64);\n#endif\n\n    // No point trying to set the load count on Windows 8 and higher, because NT now uses a DAG of\n    // loader nodes.\n    if (WindowsVersion < WINDOWS_8)\n    {\n        status = PhSetProcessModuleLoadCount(\n            ProcessHandle,\n            BaseAddress,\n            1\n            );\n\n#ifdef _WIN64\n        if (isWow64 && status == STATUS_DLL_NOT_FOUND)\n        {\n            // The DLL might be 32-bit.\n            status = PhSetProcessModuleLoadCount32(\n                ProcessHandle,\n                BaseAddress,\n                1\n                );\n\n            if (NT_SUCCESS(status))\n                isModule32 = TRUE;\n        }\n#endif\n\n        if (!NT_SUCCESS(status))\n            return status;\n    }\n\n#ifdef _WIN64\n    if (!isModule32)\n    {\n#endif\n        threadStart = PhGetModuleProcAddress(L\"ntdll.dll\", \"LdrUnloadDll\");\n#ifdef _WIN64\n    }\n    else\n    {\n        threadStart = ldrUnloadDll32;\n\n        if (!threadStart)\n        {\n            PPH_STRING ntdll32FileName;\n\n            ntdll32FileName = PhConcatStrings2(USER_SHARED_DATA->NtSystemRoot, L\"\\\\SysWow64\\\\ntdll.dll\");\n            status = PhGetProcedureAddressRemote(\n                ProcessHandle,\n                ntdll32FileName->Buffer,\n                \"LdrUnloadDll\",\n                0,\n                &ldrUnloadDll32,\n                NULL\n                );\n            PhDereferenceObject(ntdll32FileName);\n\n            if (!NT_SUCCESS(status))\n                return status;\n\n            threadStart = ldrUnloadDll32;\n        }\n    }\n#endif\n\n    status = RtlCreateUserThread(\n        ProcessHandle,\n        NULL,\n        FALSE,\n        0,\n        0,\n        0,\n        (PUSER_THREAD_START_ROUTINE)threadStart,\n        BaseAddress,\n        &threadHandle,\n        NULL\n        );\n\n    if (!NT_SUCCESS(status))\n        return status;\n\n    status = NtWaitForSingleObject(threadHandle, FALSE, Timeout);\n\n    if (status == STATUS_WAIT_0)\n    {\n        status = PhGetThreadBasicInformation(threadHandle, &basicInfo);\n\n        if (NT_SUCCESS(status))\n            status = basicInfo.ExitStatus;\n    }\n\n    NtClose(threadHandle);\n\n    return status;\n}\n\n// Contributed by dmex\n/**\n * Sets an environment variable in a process.\n *\n * \\param ProcessHandle A handle to a process. The handle must have\n * PROCESS_QUERY_LIMITED_INFORMATION, PROCESS_CREATE_THREAD, PROCESS_VM_OPERATION, PROCESS_VM_READ\n * and PROCESS_VM_WRITE access.\n * \\param Name The name of the environment variable to set.\n * \\param Value The new value of the environment variable. If this parameter is NULL, the\n * environment variable is deleted.\n * \\param Timeout The timeout, in milliseconds, for the process to set the environment variable.\n */\nNTSTATUS PhSetEnvironmentVariableRemote(\n    _In_ HANDLE ProcessHandle,\n    _In_ PPH_STRINGREF Name,\n    _In_opt_ PPH_STRINGREF Value,\n    _In_opt_ PLARGE_INTEGER Timeout\n    )\n{\n    NTSTATUS status;\n#ifdef _WIN64\n    BOOLEAN isWow64;\n#endif\n    PPH_STRING ntdllFileName = NULL;\n    PPH_STRING kernel32FileName = NULL;\n    PVOID nameBaseAddress = NULL;\n    PVOID valueBaseAddress = NULL;\n    SIZE_T nameAllocationSize = 0;\n    SIZE_T valueAllocationSize = 0;\n    PVOID rtlExitUserThread = NULL;\n    PVOID setEnvironmentVariableW = NULL;\n    HANDLE threadHandle = NULL;\n\n    nameAllocationSize = Name->Length + sizeof(WCHAR);\n\n    if (Value)\n        valueAllocationSize = Value->Length + sizeof(WCHAR);\n\n#ifdef _WIN64\n    if (!NT_SUCCESS(status = PhGetProcessIsWow64(ProcessHandle, &isWow64)))\n        goto CleanupExit;\n\n    if (isWow64)\n    {\n        ntdllFileName = PhConcatStrings2(USER_SHARED_DATA->NtSystemRoot, L\"\\\\SysWow64\\\\ntdll.dll\");\n        kernel32FileName = PhConcatStrings2(USER_SHARED_DATA->NtSystemRoot, L\"\\\\SysWow64\\\\kernel32.dll\");\n    }\n    else\n    {\n#endif\n        ntdllFileName = PhConcatStrings2(USER_SHARED_DATA->NtSystemRoot, L\"\\\\System32\\\\ntdll.dll\");\n        kernel32FileName = PhConcatStrings2(USER_SHARED_DATA->NtSystemRoot, L\"\\\\System32\\\\kernel32.dll\");\n#ifdef _WIN64\n    }\n#endif\n\n    if (!NT_SUCCESS(status = PhGetProcedureAddressRemote(\n        ProcessHandle,\n        ntdllFileName->Buffer,\n        \"RtlExitUserThread\",\n        0,\n        &rtlExitUserThread,\n        NULL\n        )))\n    {\n        goto CleanupExit;\n    }\n    if (!NT_SUCCESS(status = PhGetProcedureAddressRemote(\n        ProcessHandle,\n        kernel32FileName->Buffer,\n        \"SetEnvironmentVariableW\",\n        0,\n        &setEnvironmentVariableW,\n        NULL\n        )))\n    {\n        goto CleanupExit;\n    }\n    if (!NT_SUCCESS(status = NtAllocateVirtualMemory(\n        ProcessHandle,\n        &nameBaseAddress,\n        0,\n        &nameAllocationSize,\n        MEM_COMMIT,\n        PAGE_READWRITE\n        )))\n    {\n        goto CleanupExit;\n    }\n    if (!NT_SUCCESS(status = NtWriteVirtualMemory(\n        ProcessHandle,\n        nameBaseAddress,\n        Name->Buffer,\n        Name->Length,\n        NULL\n        )))\n    {\n        goto CleanupExit;\n    }\n\n    if (Value)\n    {\n        if (!NT_SUCCESS(status = NtAllocateVirtualMemory(\n            ProcessHandle,\n            &valueBaseAddress,\n            0,\n            &valueAllocationSize,\n            MEM_COMMIT,\n            PAGE_READWRITE\n            )))\n        {\n            goto CleanupExit;\n        }\n        if (!NT_SUCCESS(status = NtWriteVirtualMemory(\n            ProcessHandle,\n            valueBaseAddress,\n            Value->Buffer,\n            Value->Length,\n            NULL\n            )))\n        {\n            goto CleanupExit;\n        }\n    }\n\n    if (!NT_SUCCESS(status = RtlCreateUserThread(\n        ProcessHandle,\n        NULL,\n        TRUE,\n        0,\n        0,\n        0,\n        (PUSER_THREAD_START_ROUTINE)rtlExitUserThread,\n        NULL,\n        &threadHandle,\n        NULL\n        )))\n    {\n        goto CleanupExit;\n    }\n\n#ifdef _WIN64\n    if (isWow64)\n    {\n        // NtQueueApcThread doesn't work for WOW64 processes - we need to use RtlQueueApcWow64Thread\n        // instead.\n        if (!NT_SUCCESS(status = RtlQueueApcWow64Thread(\n            threadHandle,\n            setEnvironmentVariableW,\n            nameBaseAddress,\n            valueBaseAddress,\n            NULL\n            )))\n        {\n            goto CleanupExit;\n        }\n    }\n    else\n    {\n#endif\n        if (!NT_SUCCESS(status = NtQueueApcThread(\n            threadHandle,\n            setEnvironmentVariableW,\n            nameBaseAddress,\n            valueBaseAddress,\n            NULL\n            )))\n        {\n            goto CleanupExit;\n        }\n#ifdef _WIN64\n    }\n#endif\n\n    // This causes our APC to be executed.\n    NtResumeThread(threadHandle, NULL);\n    status = NtWaitForSingleObject(threadHandle, FALSE, Timeout);\n\nCleanupExit:\n    if (threadHandle)\n        NtClose(threadHandle);\n    if (nameBaseAddress)\n    {\n        nameAllocationSize = 0;\n        NtFreeVirtualMemory(\n            ProcessHandle,\n            &nameBaseAddress,\n            &nameAllocationSize,\n            MEM_RELEASE\n            );\n    }\n    if (valueBaseAddress)\n    {\n        valueAllocationSize = 0;\n        NtFreeVirtualMemory(\n            ProcessHandle,\n            &valueBaseAddress,\n            &valueAllocationSize,\n            MEM_RELEASE\n            );\n    }\n    PhClearReference(&ntdllFileName);\n    PhClearReference(&kernel32FileName);\n\n    return status;\n}\n\nNTSTATUS PhGetJobProcessIdList(\n    _In_ HANDLE JobHandle,\n    _Out_ PJOBOBJECT_BASIC_PROCESS_ID_LIST *ProcessIdList\n    )\n{\n    NTSTATUS status;\n    PVOID buffer;\n    ULONG bufferSize;\n\n    bufferSize = 0x100;\n    buffer = PhAllocate(bufferSize);\n\n    status = NtQueryInformationJobObject(\n        JobHandle,\n        JobObjectBasicProcessIdList,\n        buffer,\n        bufferSize,\n        &bufferSize\n        );\n\n    if (status == STATUS_BUFFER_OVERFLOW)\n    {\n        PhFree(buffer);\n        buffer = PhAllocate(bufferSize);\n\n        status = NtQueryInformationJobObject(\n            JobHandle,\n            JobObjectBasicProcessIdList,\n            buffer,\n            bufferSize,\n            NULL\n            );\n    }\n\n    if (!NT_SUCCESS(status))\n    {\n        PhFree(buffer);\n        return status;\n    }\n\n    *ProcessIdList = (PJOBOBJECT_BASIC_PROCESS_ID_LIST)buffer;\n\n    return status;\n}\n\n/**\n * Queries variable-sized information for a token. The function allocates a buffer to contain the\n * information.\n *\n * \\param TokenHandle A handle to a token. The access required depends on the information class\n * specified.\n * \\param TokenInformationClass The information class to retrieve.\n * \\param Buffer A variable which receives a pointer to a buffer containing the information. You\n * must free the buffer using PhFree() when you no longer need it.\n */\nNTSTATUS PhpQueryTokenVariableSize(\n    _In_ HANDLE TokenHandle,\n    _In_ TOKEN_INFORMATION_CLASS TokenInformationClass,\n    _Out_ PVOID *Buffer\n    )\n{\n    NTSTATUS status;\n    PVOID buffer;\n    ULONG returnLength = 0;\n\n    NtQueryInformationToken(\n        TokenHandle,\n        TokenInformationClass,\n        NULL,\n        0,\n        &returnLength\n        );\n    buffer = PhAllocate(returnLength);\n    status = NtQueryInformationToken(\n        TokenHandle,\n        TokenInformationClass,\n        buffer,\n        returnLength,\n        &returnLength\n        );\n\n    if (NT_SUCCESS(status))\n    {\n        *Buffer = buffer;\n    }\n    else\n    {\n        PhFree(buffer);\n    }\n\n    return status;\n}\n\n/**\n * Queries variable-sized information for a token. The function allocates a buffer to contain the\n * information.\n *\n * \\param TokenHandle A handle to a token. The access required depends on the information class\n * specified.\n * \\param TokenInformationClass The information class to retrieve.\n * \\param Buffer A variable which receives a pointer to a buffer containing the information. You\n * must free the buffer using PhFree() when you no longer need it.\n */\nNTSTATUS PhQueryTokenVariableSize(\n    _In_ HANDLE TokenHandle,\n    _In_ TOKEN_INFORMATION_CLASS TokenInformationClass,\n    _Out_ PVOID *Buffer\n    )\n{\n    return PhpQueryTokenVariableSize(\n        TokenHandle,\n        TokenInformationClass,\n        Buffer\n        );\n}\n\n/**\n * Gets a token's user.\n *\n * \\param TokenHandle A handle to a token. The handle must have TOKEN_QUERY access.\n * \\param User A variable which receives a pointer to a structure containing the token's user. You\n * must free the structure using PhFree() when you no longer need it.\n */\nNTSTATUS PhGetTokenUser(\n    _In_ HANDLE TokenHandle,\n    _Out_ PTOKEN_USER *User\n    )\n{\n    return PhpQueryTokenVariableSize(\n        TokenHandle,\n        TokenUser,\n        User\n        );\n}\n\n/**\n * Gets a token's owner.\n *\n * \\param TokenHandle A handle to a token. The handle must have TOKEN_QUERY access.\n * \\param Owner A variable which receives a pointer to a structure containing the token's owner. You\n * must free the structure using PhFree() when you no longer need it.\n */\nNTSTATUS PhGetTokenOwner(\n    _In_ HANDLE TokenHandle,\n    _Out_ PTOKEN_OWNER *Owner\n    )\n{\n    return PhpQueryTokenVariableSize(\n        TokenHandle,\n        TokenOwner,\n        Owner\n        );\n}\n\n/**\n * Gets a token's primary group.\n *\n * \\param TokenHandle A handle to a token. The handle must have TOKEN_QUERY access.\n * \\param PrimaryGroup A variable which receives a pointer to a structure containing the token's\n * primary group. You must free the structure using PhFree() when you no longer need it.\n */\nNTSTATUS PhGetTokenPrimaryGroup(\n    _In_ HANDLE TokenHandle,\n    _Out_ PTOKEN_PRIMARY_GROUP *PrimaryGroup\n    )\n{\n    return PhpQueryTokenVariableSize(\n        TokenHandle,\n        TokenPrimaryGroup,\n        PrimaryGroup\n        );\n}\n\n/**\n * Gets a token's groups.\n *\n * \\param TokenHandle A handle to a token. The handle must have TOKEN_QUERY access.\n * \\param Groups A variable which receives a pointer to a structure containing the token's groups.\n * You must free the structure using PhFree() when you no longer need it.\n */\nNTSTATUS PhGetTokenGroups(\n    _In_ HANDLE TokenHandle,\n    _Out_ PTOKEN_GROUPS *Groups\n    )\n{\n    return PhpQueryTokenVariableSize(\n        TokenHandle,\n        TokenGroups,\n        Groups\n        );\n}\n\n/**\n * Get a token's restricted SIDs.\n *\n * \\param TokenHandle A handle to a token. The handle must have TOKEN_QUERY access.\n * \\param RestrictedSids A variable which receives a pointer to a structure containing the token's restricted SIDs.\n * You must free the structure using PhFree() when you no longer need it.\n */\nNTSTATUS PhGetTokenRestrictedSids(\n    _In_ HANDLE TokenHandle,\n    _Out_ PTOKEN_GROUPS* RestrictedSids\n)\n{\n    return PhpQueryTokenVariableSize(\n        TokenHandle,\n        TokenRestrictedSids,\n        RestrictedSids\n        );\n}\n\n/**\n * Gets a token's privileges.\n *\n * \\param TokenHandle A handle to a token. The handle must have TOKEN_QUERY access.\n * \\param Privileges A variable which receives a pointer to a structure containing the token's\n * privileges. You must free the structure using PhFree() when you no longer need it.\n */\nNTSTATUS PhGetTokenPrivileges(\n    _In_ HANDLE TokenHandle,\n    _Out_ PTOKEN_PRIVILEGES *Privileges\n    )\n{\n    return PhpQueryTokenVariableSize(\n        TokenHandle,\n        TokenPrivileges,\n        Privileges\n        );\n}\n\nNTSTATUS PhSetTokenSessionId(\n    _In_ HANDLE TokenHandle,\n    _In_ ULONG SessionId\n    )\n{\n    return NtSetInformationToken(\n        TokenHandle,\n        TokenSessionId,\n        &SessionId,\n        sizeof(ULONG)\n        );\n}\n\n/**\n * Modifies a token privilege.\n *\n * \\param TokenHandle A handle to a token. The handle must have TOKEN_ADJUST_PRIVILEGES access.\n * \\param PrivilegeName The name of the privilege to modify. If this parameter is NULL, you must\n * specify a LUID in the \\a PrivilegeLuid parameter.\n * \\param PrivilegeLuid The LUID of the privilege to modify. If this parameter is NULL, you must\n * specify a name in the \\a PrivilegeName parameter.\n * \\param Attributes The new attributes of the privilege.\n */\nBOOLEAN PhSetTokenPrivilege(\n    _In_ HANDLE TokenHandle,\n    _In_opt_ PWSTR PrivilegeName,\n    _In_opt_ PLUID PrivilegeLuid,\n    _In_ ULONG Attributes\n    )\n{\n    NTSTATUS status;\n    TOKEN_PRIVILEGES privileges;\n\n    privileges.PrivilegeCount = 1;\n    privileges.Privileges[0].Attributes = Attributes;\n\n    if (PrivilegeLuid)\n    {\n        privileges.Privileges[0].Luid = *PrivilegeLuid;\n    }\n    else if (PrivilegeName)\n    {\n        PH_STRINGREF privilegeName;\n\n        PhInitializeStringRef(&privilegeName, PrivilegeName);\n\n        if (!PhLookupPrivilegeValue(\n            &privilegeName,\n            &privileges.Privileges[0].Luid\n            ))\n            return FALSE;\n    }\n    else\n    {\n        return FALSE;\n    }\n\n    if (!NT_SUCCESS(status = NtAdjustPrivilegesToken(\n        TokenHandle,\n        FALSE,\n        &privileges,\n        0,\n        NULL,\n        NULL\n        )))\n        return FALSE;\n\n    if (status == STATUS_NOT_ALL_ASSIGNED)\n        return FALSE;\n\n    return TRUE;\n}\n\nBOOLEAN PhSetTokenPrivilege2(\n    _In_ HANDLE TokenHandle,\n    _In_ LONG Privilege,\n    _In_ ULONG Attributes\n    )\n{\n    LUID privilegeLuid;\n\n    privilegeLuid = RtlConvertLongToLuid(Privilege);\n\n    return PhSetTokenPrivilege(TokenHandle, NULL, &privilegeLuid, Attributes);\n}\n\n/**\n * Sets whether virtualization is enabled for a token.\n *\n * \\param TokenHandle A handle to a token. The handle must have TOKEN_WRITE access.\n * \\param IsVirtualizationEnabled A boolean indicating whether virtualization is to be enabled for\n * the token.\n */\nNTSTATUS PhSetTokenIsVirtualizationEnabled(\n    _In_ HANDLE TokenHandle,\n    _In_ BOOLEAN IsVirtualizationEnabled\n    )\n{\n    ULONG virtualizationEnabled;\n\n    virtualizationEnabled = IsVirtualizationEnabled;\n\n    return NtSetInformationToken(\n        TokenHandle,\n        TokenVirtualizationEnabled,\n        &virtualizationEnabled,\n        sizeof(ULONG)\n        );\n}\n\n/**\n * Gets a token's integrity level.\n *\n * \\param TokenHandle A handle to a token. The handle must have TOKEN_QUERY access.\n * \\param IntegrityLevel A variable which receives the integrity level of the token.\n * \\param IntegrityString A variable which receives a pointer to a string containing a string\n * representation of the integrity level.\n */\nNTSTATUS PhGetTokenIntegrityLevel(\n    _In_ HANDLE TokenHandle,\n    _Out_opt_ PMANDATORY_LEVEL IntegrityLevel,\n    _Out_opt_ PWSTR *IntegrityString\n    )\n{\n    NTSTATUS status;\n    PTOKEN_MANDATORY_LABEL mandatoryLabel;\n    ULONG subAuthority;\n    MANDATORY_LEVEL integrityLevel;\n    PWSTR integrityString;\n\n    status = PhpQueryTokenVariableSize(TokenHandle, TokenIntegrityLevel, &mandatoryLabel);\n\n    if (!NT_SUCCESS(status))\n        return status;\n\n    subAuthority = *RtlSubAuthoritySid(mandatoryLabel->Label.Sid, 0);\n    PhFree(mandatoryLabel);\n\n    switch (subAuthority)\n    {\n    case SECURITY_MANDATORY_UNTRUSTED_RID:\n        integrityLevel = MandatoryLevelUntrusted;\n        integrityString = L\"Untrusted\";\n        break;\n    case SECURITY_MANDATORY_LOW_RID:\n        integrityLevel = MandatoryLevelLow;\n        integrityString = L\"Low\";\n        break;\n    case SECURITY_MANDATORY_MEDIUM_RID:\n        integrityLevel = MandatoryLevelMedium;\n        integrityString = L\"Medium\";\n        break;\n    case SECURITY_MANDATORY_HIGH_RID:\n        integrityLevel = MandatoryLevelHigh;\n        integrityString = L\"High\";\n        break;\n    case SECURITY_MANDATORY_SYSTEM_RID:\n        integrityLevel = MandatoryLevelSystem;\n        integrityString = L\"System\";\n        break;\n    case SECURITY_MANDATORY_PROTECTED_PROCESS_RID:\n        integrityLevel = MandatoryLevelSecureProcess;\n        integrityString = L\"Protected\";\n        break;\n    default:\n        return STATUS_UNSUCCESSFUL;\n    }\n\n    if (IntegrityLevel)\n        *IntegrityLevel = integrityLevel;\n    if (IntegrityString)\n        *IntegrityString = integrityString;\n\n    return status;\n}\n\nNTSTATUS PhpQueryFileVariableSize(\n    _In_ HANDLE FileHandle,\n    _In_ FILE_INFORMATION_CLASS FileInformationClass,\n    _Out_ PVOID *Buffer\n    )\n{\n    NTSTATUS status;\n    IO_STATUS_BLOCK isb;\n    PVOID buffer;\n    ULONG bufferSize = 0x200;\n\n    buffer = PhAllocate(bufferSize);\n\n    while (TRUE)\n    {\n        status = NtQueryInformationFile(\n            FileHandle,\n            &isb,\n            buffer,\n            bufferSize,\n            FileInformationClass\n            );\n\n        if (status == STATUS_BUFFER_OVERFLOW || status == STATUS_BUFFER_TOO_SMALL || status == STATUS_INFO_LENGTH_MISMATCH)\n        {\n            PhFree(buffer);\n            bufferSize *= 2;\n            buffer = PhAllocate(bufferSize);\n        }\n        else\n        {\n            break;\n        }\n    }\n\n    if (NT_SUCCESS(status))\n    {\n        *Buffer = buffer;\n    }\n    else\n    {\n        PhFree(buffer);\n    }\n\n    return status;\n}\n\nNTSTATUS PhGetFileSize(\n    _In_ HANDLE FileHandle,\n    _Out_ PLARGE_INTEGER Size\n    )\n{\n    NTSTATUS status;\n    FILE_STANDARD_INFORMATION standardInfo;\n    IO_STATUS_BLOCK isb;\n\n    status = NtQueryInformationFile(\n        FileHandle,\n        &isb,\n        &standardInfo,\n        sizeof(FILE_STANDARD_INFORMATION),\n        FileStandardInformation\n        );\n\n    if (!NT_SUCCESS(status))\n        return status;\n\n    *Size = standardInfo.EndOfFile;\n\n    return status;\n}\n\nNTSTATUS PhSetFileSize(\n    _In_ HANDLE FileHandle,\n    _In_ PLARGE_INTEGER Size\n    )\n{\n    FILE_END_OF_FILE_INFORMATION endOfFileInfo;\n    IO_STATUS_BLOCK isb;\n\n    endOfFileInfo.EndOfFile = *Size;\n\n    return NtSetInformationFile(\n        FileHandle,\n        &isb,\n        &endOfFileInfo,\n        sizeof(FILE_END_OF_FILE_INFORMATION),\n        FileEndOfFileInformation\n        );\n}\n\nNTSTATUS PhpQueryTransactionManagerVariableSize(\n    _In_ HANDLE TransactionManagerHandle,\n    _In_ TRANSACTIONMANAGER_INFORMATION_CLASS TransactionManagerInformationClass,\n    _Out_ PVOID *Buffer\n    )\n{\n    NTSTATUS status;\n    PVOID buffer;\n    ULONG bufferSize = 0x100;\n\n    if (!NtQueryInformationTransactionManager_Import())\n        return STATUS_NOT_SUPPORTED;\n\n    buffer = PhAllocate(bufferSize);\n\n    while (TRUE)\n    {\n        status = NtQueryInformationTransactionManager_Import()(\n            TransactionManagerHandle,\n            TransactionManagerInformationClass,\n            buffer,\n            bufferSize,\n            NULL\n            );\n\n        if (status == STATUS_BUFFER_OVERFLOW)\n        {\n            PhFree(buffer);\n            bufferSize *= 2;\n\n            if (bufferSize > 1 * 1024 * 1024)\n                return STATUS_INSUFFICIENT_RESOURCES;\n\n            buffer = PhAllocate(bufferSize);\n        }\n        else\n        {\n            break;\n        }\n    }\n\n    if (NT_SUCCESS(status))\n    {\n        *Buffer = buffer;\n    }\n    else\n    {\n        PhFree(buffer);\n    }\n\n    return status;\n}\n\nNTSTATUS PhGetTransactionManagerBasicInformation(\n    _In_ HANDLE TransactionManagerHandle,\n    _Out_ PTRANSACTIONMANAGER_BASIC_INFORMATION BasicInformation\n    )\n{\n    if (NtQueryInformationTransactionManager_Import())\n    {\n        return NtQueryInformationTransactionManager_Import()(\n            TransactionManagerHandle,\n            TransactionManagerBasicInformation,\n            BasicInformation,\n            sizeof(TRANSACTIONMANAGER_BASIC_INFORMATION),\n            NULL\n            );\n    }\n    else\n    {\n        return STATUS_NOT_SUPPORTED;\n    }\n}\n\nNTSTATUS PhGetTransactionManagerLogFileName(\n    _In_ HANDLE TransactionManagerHandle,\n    _Out_ PPH_STRING *LogFileName\n    )\n{\n    NTSTATUS status;\n    PTRANSACTIONMANAGER_LOGPATH_INFORMATION logPathInfo;\n\n    status = PhpQueryTransactionManagerVariableSize(\n        TransactionManagerHandle,\n        TransactionManagerLogPathInformation,\n        &logPathInfo\n        );\n\n    if (!NT_SUCCESS(status))\n        return status;\n\n    *LogFileName = PhCreateStringEx(\n        logPathInfo->LogPath,\n        logPathInfo->LogPathLength\n        );\n    PhFree(logPathInfo);\n\n    return status;\n}\n\nNTSTATUS PhpQueryTransactionVariableSize(\n    _In_ HANDLE TransactionHandle,\n    _In_ TRANSACTION_INFORMATION_CLASS TransactionInformationClass,\n    _Out_ PVOID *Buffer\n    )\n{\n    NTSTATUS status;\n    PVOID buffer;\n    ULONG bufferSize = 0x100;\n\n    if (!NtQueryInformationTransaction_Import())\n        return STATUS_NOT_SUPPORTED;\n\n    buffer = PhAllocate(bufferSize);\n\n    while (TRUE)\n    {\n        status = NtQueryInformationTransaction_Import()(\n            TransactionHandle,\n            TransactionInformationClass,\n            buffer,\n            bufferSize,\n            NULL\n            );\n\n        if (status == STATUS_BUFFER_OVERFLOW)\n        {\n            PhFree(buffer);\n            bufferSize *= 2;\n\n            if (bufferSize > 1 * 1024 * 1024)\n                return STATUS_INSUFFICIENT_RESOURCES;\n\n            buffer = PhAllocate(bufferSize);\n        }\n        else\n        {\n            break;\n        }\n    }\n\n    if (NT_SUCCESS(status))\n    {\n        *Buffer = buffer;\n    }\n    else\n    {\n        PhFree(buffer);\n    }\n\n    return status;\n}\n\nNTSTATUS PhGetTransactionBasicInformation(\n    _In_ HANDLE TransactionHandle,\n    _Out_ PTRANSACTION_BASIC_INFORMATION BasicInformation\n    )\n{\n    if (NtQueryInformationTransaction_Import())\n    {\n        return NtQueryInformationTransaction_Import()(\n            TransactionHandle,\n            TransactionBasicInformation,\n            BasicInformation,\n            sizeof(TRANSACTION_BASIC_INFORMATION),\n            NULL\n            );\n    }\n    else\n    {\n        return STATUS_NOT_SUPPORTED;\n    }\n}\n\nNTSTATUS PhGetTransactionPropertiesInformation(\n    _In_ HANDLE TransactionHandle,\n    _Out_opt_ PLARGE_INTEGER Timeout,\n    _Out_opt_ TRANSACTION_OUTCOME *Outcome,\n    _Out_opt_ PPH_STRING *Description\n    )\n{\n    NTSTATUS status;\n    PTRANSACTION_PROPERTIES_INFORMATION propertiesInfo;\n\n    status = PhpQueryTransactionVariableSize(\n        TransactionHandle,\n        TransactionPropertiesInformation,\n        &propertiesInfo\n        );\n\n    if (!NT_SUCCESS(status))\n        return status;\n\n    if (Timeout)\n    {\n        *Timeout = propertiesInfo->Timeout;\n    }\n\n    if (Outcome)\n    {\n        *Outcome = propertiesInfo->Outcome;\n    }\n\n    if (Description)\n    {\n        *Description = PhCreateStringEx(\n            propertiesInfo->Description,\n            propertiesInfo->DescriptionLength\n            );\n    }\n\n    PhFree(propertiesInfo);\n\n    return status;\n}\n\nNTSTATUS PhpQueryResourceManagerVariableSize(\n    _In_ HANDLE ResourceManagerHandle,\n    _In_ RESOURCEMANAGER_INFORMATION_CLASS ResourceManagerInformationClass,\n    _Out_ PVOID *Buffer\n    )\n{\n    NTSTATUS status;\n    PVOID buffer;\n    ULONG bufferSize = 0x100;\n\n    if (!NtQueryInformationResourceManager_Import())\n        return STATUS_NOT_SUPPORTED;\n\n    buffer = PhAllocate(bufferSize);\n\n    while (TRUE)\n    {\n        status = NtQueryInformationResourceManager_Import()(\n            ResourceManagerHandle,\n            ResourceManagerInformationClass,\n            buffer,\n            bufferSize,\n            NULL\n            );\n\n        if (status == STATUS_BUFFER_OVERFLOW)\n        {\n            PhFree(buffer);\n            bufferSize *= 2;\n\n            if (bufferSize > 1 * 1024 * 1024)\n                return STATUS_INSUFFICIENT_RESOURCES;\n\n            buffer = PhAllocate(bufferSize);\n        }\n        else\n        {\n            break;\n        }\n    }\n\n    if (NT_SUCCESS(status))\n    {\n        *Buffer = buffer;\n    }\n    else\n    {\n        PhFree(buffer);\n    }\n\n    return status;\n}\n\nNTSTATUS PhGetResourceManagerBasicInformation(\n    _In_ HANDLE ResourceManagerHandle,\n    _Out_opt_ PGUID Guid,\n    _Out_opt_ PPH_STRING *Description\n    )\n{\n    NTSTATUS status;\n    PRESOURCEMANAGER_BASIC_INFORMATION basicInfo;\n\n    status = PhpQueryResourceManagerVariableSize(\n        ResourceManagerHandle,\n        ResourceManagerBasicInformation,\n        &basicInfo\n        );\n\n    if (!NT_SUCCESS(status))\n        return status;\n\n    if (Guid)\n    {\n        *Guid = basicInfo->ResourceManagerId;\n    }\n\n    if (Description)\n    {\n        *Description = PhCreateStringEx(\n            basicInfo->Description,\n            basicInfo->DescriptionLength\n            );\n    }\n\n    PhFree(basicInfo);\n\n    return status;\n}\n\nNTSTATUS PhGetEnlistmentBasicInformation(\n    _In_ HANDLE EnlistmentHandle,\n    _Out_ PENLISTMENT_BASIC_INFORMATION BasicInformation\n    )\n{\n    if (NtQueryInformationEnlistment_Import())\n    {\n        return NtQueryInformationEnlistment_Import()(\n            EnlistmentHandle,\n            EnlistmentBasicInformation,\n            BasicInformation,\n            sizeof(ENLISTMENT_BASIC_INFORMATION),\n            NULL\n            );\n    }\n    else\n    {\n        return STATUS_NOT_SUPPORTED;\n    }\n}\n\ntypedef struct _OPEN_DRIVER_BY_BASE_ADDRESS_CONTEXT\n{\n    NTSTATUS Status;\n    PVOID BaseAddress;\n    HANDLE DriverHandle;\n} OPEN_DRIVER_BY_BASE_ADDRESS_CONTEXT, *POPEN_DRIVER_BY_BASE_ADDRESS_CONTEXT;\n\nBOOLEAN NTAPI PhpOpenDriverByBaseAddressCallback(\n    _In_ PPH_STRINGREF Name,\n    _In_ PPH_STRINGREF TypeName,\n    _In_opt_ PVOID Context\n    )\n{\n    static PH_STRINGREF driverDirectoryName = PH_STRINGREF_INIT(L\"\\\\Driver\\\\\");\n\n    NTSTATUS status;\n    POPEN_DRIVER_BY_BASE_ADDRESS_CONTEXT context = Context;\n    PPH_STRING driverName;\n    UNICODE_STRING driverNameUs;\n    OBJECT_ATTRIBUTES objectAttributes;\n    HANDLE driverHandle;\n    DRIVER_BASIC_INFORMATION basicInfo;\n\n    driverName = PhConcatStringRef2(&driverDirectoryName, Name);\n\n    if (!PhStringRefToUnicodeString(&driverName->sr, &driverNameUs))\n    {\n        PhDereferenceObject(driverName);\n        return TRUE;\n    }\n\n    InitializeObjectAttributes(\n        &objectAttributes,\n        &driverNameUs,\n        0,\n        NULL,\n        NULL\n        );\n\n    status = KphOpenDriver(&driverHandle, SYNCHRONIZE, &objectAttributes);\n    PhDereferenceObject(driverName);\n\n    if (!NT_SUCCESS(status))\n        return TRUE;\n\n    status = KphQueryInformationDriver(\n        driverHandle,\n        DriverBasicInformation,\n        &basicInfo,\n        sizeof(DRIVER_BASIC_INFORMATION),\n        NULL\n        );\n\n    if (NT_SUCCESS(status))\n    {\n        if (basicInfo.DriverStart == context->BaseAddress)\n        {\n            context->Status = STATUS_SUCCESS;\n            context->DriverHandle = driverHandle;\n\n            return FALSE;\n        }\n    }\n\n    NtClose(driverHandle);\n\n    return TRUE;\n}\n\n/**\n * Opens a driver object using a base address.\n *\n * \\param DriverHandle A variable which receives a handle to the driver object.\n * \\param BaseAddress The base address of the driver to open.\n *\n * \\retval STATUS_OBJECT_NAME_NOT_FOUND The driver could not be found.\n *\n * \\remarks This function requires a valid KProcessHacker handle.\n */\nNTSTATUS PhOpenDriverByBaseAddress(\n    _Out_ PHANDLE DriverHandle,\n    _In_ PVOID BaseAddress\n    )\n{\n    NTSTATUS status;\n    UNICODE_STRING driverDirectoryName;\n    OBJECT_ATTRIBUTES objectAttributes;\n    HANDLE driverDirectoryHandle;\n    OPEN_DRIVER_BY_BASE_ADDRESS_CONTEXT context;\n\n    RtlInitUnicodeString(\n        &driverDirectoryName,\n        L\"\\\\Driver\"\n        );\n    InitializeObjectAttributes(\n        &objectAttributes,\n        &driverDirectoryName,\n        0,\n        NULL,\n        NULL\n        );\n\n    if (!NT_SUCCESS(status = NtOpenDirectoryObject(\n        &driverDirectoryHandle,\n        DIRECTORY_QUERY,\n        &objectAttributes\n        )))\n        return status;\n\n    context.Status = STATUS_OBJECT_NAME_NOT_FOUND;\n    context.BaseAddress = BaseAddress;\n\n    status = PhEnumDirectoryObjects(\n        driverDirectoryHandle,\n        PhpOpenDriverByBaseAddressCallback,\n        &context\n        );\n    NtClose(driverDirectoryHandle);\n\n    if (!NT_SUCCESS(status) && !NT_SUCCESS(context.Status))\n        return status;\n\n    if (NT_SUCCESS(context.Status))\n    {\n        *DriverHandle = context.DriverHandle;\n    }\n\n    return context.Status;\n}\n\n/**\n * Queries variable-sized information for a driver. The function allocates a buffer to contain the\n * information.\n *\n * \\param DriverHandle A handle to a driver. The access required depends on the information class\n * specified.\n * \\param DriverInformationClass The information class to retrieve.\n * \\param Buffer A variable which receives a pointer to a buffer containing the information. You\n * must free the buffer using PhFree() when you no longer need it.\n *\n * \\remarks This function requires a valid KProcessHacker handle.\n */\nNTSTATUS PhpQueryDriverVariableSize(\n    _In_ HANDLE DriverHandle,\n    _In_ DRIVER_INFORMATION_CLASS DriverInformationClass,\n    _Out_ PVOID *Buffer\n    )\n{\n    NTSTATUS status;\n    PVOID buffer;\n    ULONG returnLength = 0;\n\n    KphQueryInformationDriver(\n        DriverHandle,\n        DriverInformationClass,\n        NULL,\n        0,\n        &returnLength\n        );\n    buffer = PhAllocate(returnLength);\n    status = KphQueryInformationDriver(\n        DriverHandle,\n        DriverInformationClass,\n        buffer,\n        returnLength,\n        &returnLength\n        );\n\n    if (NT_SUCCESS(status))\n    {\n        *Buffer = buffer;\n    }\n    else\n    {\n        PhFree(buffer);\n    }\n\n    return status;\n}\n\n/**\n * Gets the object name of a driver.\n *\n * \\param DriverHandle A handle to a driver.\n * \\param Name A variable which receives a pointer to a string containing the object name. You must\n * free the string using PhDereferenceObject() when you no longer need it.\n *\n * \\remarks This function requires a valid KProcessHacker handle.\n */\nNTSTATUS PhGetDriverName(\n    _In_ HANDLE DriverHandle,\n    _Out_ PPH_STRING *Name\n    )\n{\n    NTSTATUS status;\n    PUNICODE_STRING unicodeString;\n\n    if (!NT_SUCCESS(status = PhpQueryDriverVariableSize(\n        DriverHandle,\n        DriverNameInformation,\n        &unicodeString\n        )))\n        return status;\n\n    *Name = PhCreateStringFromUnicodeString(unicodeString);\n    PhFree(unicodeString);\n\n    return status;\n}\n\n/**\n * Gets the service key name of a driver.\n *\n * \\param DriverHandle A handle to a driver.\n * \\param ServiceKeyName A variable which receives a pointer to a string containing the service key\n * name. You must free the string using PhDereferenceObject() when you no longer need it.\n *\n * \\remarks This function requires a valid KProcessHacker handle.\n */\nNTSTATUS PhGetDriverServiceKeyName(\n    _In_ HANDLE DriverHandle,\n    _Out_ PPH_STRING *ServiceKeyName\n    )\n{\n    NTSTATUS status;\n    PUNICODE_STRING unicodeString;\n\n    if (!NT_SUCCESS(status = PhpQueryDriverVariableSize(\n        DriverHandle,\n        DriverServiceKeyNameInformation,\n        &unicodeString\n        )))\n        return status;\n\n    *ServiceKeyName = PhCreateStringFromUnicodeString(unicodeString);\n    PhFree(unicodeString);\n\n    return status;\n}\n\nNTSTATUS PhpUnloadDriver(\n    _In_ PPH_STRING ServiceKeyName\n    )\n{\n    static PH_STRINGREF fullServicesKeyName = PH_STRINGREF_INIT(L\"\\\\Registry\\\\Machine\\\\System\\\\CurrentControlSet\\\\Services\\\\\");\n\n    NTSTATUS status;\n    PPH_STRING fullServiceKeyName;\n    UNICODE_STRING fullServiceKeyNameUs;\n    HANDLE serviceKeyHandle;\n    ULONG disposition;\n\n    fullServiceKeyName = PhConcatStringRef2(&fullServicesKeyName, &ServiceKeyName->sr);\n\n    if (!PhStringRefToUnicodeString(&fullServiceKeyName->sr, &fullServiceKeyNameUs))\n    {\n        PhDereferenceObject(fullServiceKeyName);\n        return STATUS_NAME_TOO_LONG;\n    }\n\n    if (NT_SUCCESS(status = PhCreateKey(\n        &serviceKeyHandle,\n        KEY_WRITE | DELETE,\n        NULL,\n        &fullServiceKeyName->sr,\n        0,\n        0,\n        &disposition\n        )))\n    {\n        if (disposition == REG_CREATED_NEW_KEY)\n        {\n            static UNICODE_STRING imagePath = RTL_CONSTANT_STRING(L\"\\\\SystemRoot\\\\system32\\\\drivers\\\\ntfs.sys\");\n\n            UNICODE_STRING valueName;\n            ULONG dword;\n\n            // Set up the required values.\n            dword = 1;\n            RtlInitUnicodeString(&valueName, L\"ErrorControl\");\n            NtSetValueKey(serviceKeyHandle, &valueName, 0, REG_DWORD, &dword, sizeof(ULONG));\n            RtlInitUnicodeString(&valueName, L\"Start\");\n            NtSetValueKey(serviceKeyHandle, &valueName, 0, REG_DWORD, &dword, sizeof(ULONG));\n            RtlInitUnicodeString(&valueName, L\"Type\");\n            NtSetValueKey(serviceKeyHandle, &valueName, 0, REG_DWORD, &dword, sizeof(ULONG));\n\n            // Use a bogus name.\n            RtlInitUnicodeString(&valueName, L\"ImagePath\");\n            NtSetValueKey(serviceKeyHandle, &valueName, 0, REG_SZ, imagePath.Buffer, imagePath.Length + 2);\n        }\n\n        status = NtUnloadDriver(&fullServiceKeyNameUs);\n\n        if (disposition == REG_CREATED_NEW_KEY)\n        {\n            // We added values, not subkeys, so this function will work correctly.\n            NtDeleteKey(serviceKeyHandle);\n        }\n\n        NtClose(serviceKeyHandle);\n    }\n\n    PhDereferenceObject(fullServiceKeyName);\n\n    return status;\n}\n\n/**\n * Unloads a driver.\n *\n * \\param BaseAddress The base address of the driver. This parameter can be NULL if a value is\n * specified in \\c Name.\n * \\param Name The base name of the driver. This parameter can be NULL if a value is specified in\n * \\c BaseAddress and KProcessHacker is loaded.\n *\n * \\retval STATUS_INVALID_PARAMETER_MIX Both \\c BaseAddress and \\c Name were null, or \\c Name was\n * not specified and KProcessHacker is not loaded.\n * \\retval STATUS_OBJECT_NAME_NOT_FOUND The driver could not be found.\n */\nNTSTATUS PhUnloadDriver(\n    _In_opt_ PVOID BaseAddress,\n    _In_opt_ PWSTR Name\n    )\n{\n    NTSTATUS status;\n    HANDLE driverHandle;\n    PPH_STRING serviceKeyName = NULL;\n\n    if (!BaseAddress && !Name)\n        return STATUS_INVALID_PARAMETER_MIX;\n    if (!Name && !KphIsConnected())\n        return STATUS_INVALID_PARAMETER_MIX;\n\n    // Try to get the service key name by scanning the Driver directory.\n\n    if (KphIsConnected() && BaseAddress)\n    {\n        if (NT_SUCCESS(PhOpenDriverByBaseAddress(\n            &driverHandle,\n            BaseAddress\n            )))\n        {\n            PhGetDriverServiceKeyName(driverHandle, &serviceKeyName);\n            NtClose(driverHandle);\n        }\n    }\n\n    // Use the base name if we didn't get the service key name.\n\n    if (!serviceKeyName && Name)\n    {\n        PPH_STRING name;\n\n        name = PhCreateString(Name);\n\n        // Remove the extension if it is present.\n        if (PhEndsWithString2(name, L\".sys\", TRUE))\n        {\n            serviceKeyName = PhSubstring(name, 0, name->Length / 2 - 4);\n            PhDereferenceObject(name);\n        }\n        else\n        {\n            serviceKeyName = name;\n        }\n    }\n\n    if (!serviceKeyName)\n        return STATUS_OBJECT_NAME_NOT_FOUND;\n\n    status = PhpUnloadDriver(serviceKeyName);\n    PhDereferenceObject(serviceKeyName);\n\n    return status;\n}\n\nNTSTATUS PhpEnumProcessModules(\n    _In_ HANDLE ProcessHandle,\n    _In_ PPHP_ENUM_PROCESS_MODULES_CALLBACK Callback,\n    _In_opt_ PVOID Context1,\n    _In_opt_ PVOID Context2\n    )\n{\n    NTSTATUS status;\n    PROCESS_BASIC_INFORMATION basicInfo;\n    PPEB_LDR_DATA ldr;\n    PEB_LDR_DATA pebLdrData;\n    PLIST_ENTRY startLink;\n    PLIST_ENTRY currentLink;\n    ULONG dataTableEntrySize;\n    LDR_DATA_TABLE_ENTRY currentEntry;\n    ULONG i;\n\n    // Get the PEB address.\n    status = PhGetProcessBasicInformation(ProcessHandle, &basicInfo);\n\n    if (!NT_SUCCESS(status))\n        return status;\n\n    // Read the address of the loader data.\n    status = NtReadVirtualMemory(\n        ProcessHandle,\n        PTR_ADD_OFFSET(basicInfo.PebBaseAddress, FIELD_OFFSET(PEB, Ldr)),\n        &ldr,\n        sizeof(PVOID),\n        NULL\n        );\n\n    if (!NT_SUCCESS(status))\n        return status;\n\n    // Read the loader data.\n    status = NtReadVirtualMemory(\n        ProcessHandle,\n        ldr,\n        &pebLdrData,\n        sizeof(PEB_LDR_DATA),\n        NULL\n        );\n\n    if (!NT_SUCCESS(status))\n        return status;\n\n    if (!pebLdrData.Initialized)\n        return STATUS_UNSUCCESSFUL;\n\n    if (WindowsVersion >= WINDOWS_8)\n        dataTableEntrySize = LDR_DATA_TABLE_ENTRY_SIZE_WIN8;\n    else\n        dataTableEntrySize = LDR_DATA_TABLE_ENTRY_SIZE_WIN7;\n\n    // Traverse the linked list (in load order).\n\n    i = 0;\n    startLink = PTR_ADD_OFFSET(ldr, FIELD_OFFSET(PEB_LDR_DATA, InLoadOrderModuleList));\n    currentLink = pebLdrData.InLoadOrderModuleList.Flink;\n\n    while (\n        currentLink != startLink &&\n        i <= PH_ENUM_PROCESS_MODULES_LIMIT\n        )\n    {\n        PVOID addressOfEntry;\n\n        addressOfEntry = CONTAINING_RECORD(currentLink, LDR_DATA_TABLE_ENTRY, InLoadOrderLinks);\n        status = NtReadVirtualMemory(\n            ProcessHandle,\n            addressOfEntry,\n            &currentEntry,\n            dataTableEntrySize,\n            NULL\n            );\n\n        if (!NT_SUCCESS(status))\n            return status;\n\n        // Make sure the entry is valid.\n        if (currentEntry.DllBase)\n        {\n            // Execute the callback.\n            if (!Callback(\n                ProcessHandle,\n                &currentEntry,\n                addressOfEntry,\n                Context1,\n                Context2\n                ))\n                break;\n        }\n\n        currentLink = currentEntry.InLoadOrderLinks.Flink;\n        i++;\n    }\n\n    return status;\n}\n\nBOOLEAN NTAPI PhpEnumProcessModulesCallback(\n    _In_ HANDLE ProcessHandle,\n    _In_ PLDR_DATA_TABLE_ENTRY Entry,\n    _In_ PVOID AddressOfEntry,\n    _In_opt_ PVOID Context1,\n    _In_opt_ PVOID Context2\n    )\n{\n    NTSTATUS status;\n    PPH_ENUM_PROCESS_MODULES_PARAMETERS parameters;\n    BOOLEAN cont;\n    PPH_STRING mappedFileName;\n    PWSTR fullDllNameOriginal;\n    PWSTR fullDllNameBuffer;\n    PWSTR baseDllNameOriginal;\n    PWSTR baseDllNameBuffer;\n\n    parameters = Context1;\n    mappedFileName = NULL;\n\n    if (parameters->Flags & PH_ENUM_PROCESS_MODULES_TRY_MAPPED_FILE_NAME)\n    {\n        PhGetProcessMappedFileName(ProcessHandle, Entry->DllBase, &mappedFileName);\n    }\n\n    if (mappedFileName)\n    {\n        ULONG_PTR indexOfLastBackslash;\n\n        PhStringRefToUnicodeString(&mappedFileName->sr, &Entry->FullDllName);\n        indexOfLastBackslash = PhFindLastCharInString(mappedFileName, 0, '\\\\');\n\n        if (indexOfLastBackslash != -1)\n        {\n            Entry->BaseDllName.Buffer = Entry->FullDllName.Buffer + indexOfLastBackslash + 1;\n            Entry->BaseDllName.Length = Entry->FullDllName.Length - (USHORT)indexOfLastBackslash * 2 - 2;\n            Entry->BaseDllName.MaximumLength = Entry->BaseDllName.Length;\n        }\n        else\n        {\n            Entry->BaseDllName = Entry->FullDllName;\n        }\n    }\n    else\n    {\n        // Read the full DLL name string and add a null terminator.\n\n        fullDllNameOriginal = Entry->FullDllName.Buffer;\n        fullDllNameBuffer = PhAllocate(Entry->FullDllName.Length + 2);\n        Entry->FullDllName.Buffer = fullDllNameBuffer;\n\n        if (NT_SUCCESS(status = NtReadVirtualMemory(\n            ProcessHandle,\n            fullDllNameOriginal,\n            fullDllNameBuffer,\n            Entry->FullDllName.Length,\n            NULL\n            )))\n        {\n            fullDllNameBuffer[Entry->FullDllName.Length / 2] = 0;\n        }\n        else\n        {\n            fullDllNameBuffer[0] = 0;\n            Entry->FullDllName.Length = 0;\n        }\n\n        baseDllNameOriginal = Entry->BaseDllName.Buffer;\n\n        // Try to use the buffer we just read in.\n        if (\n            NT_SUCCESS(status) &&\n            (ULONG_PTR)baseDllNameOriginal >= (ULONG_PTR)fullDllNameOriginal &&\n            (ULONG_PTR)baseDllNameOriginal + Entry->BaseDllName.Length >= (ULONG_PTR)baseDllNameOriginal &&\n            (ULONG_PTR)baseDllNameOriginal + Entry->BaseDllName.Length <= (ULONG_PTR)fullDllNameOriginal + Entry->FullDllName.Length\n            )\n        {\n            baseDllNameBuffer = NULL;\n\n            Entry->BaseDllName.Buffer = (PWCHAR)((ULONG_PTR)Entry->FullDllName.Buffer +\n                ((ULONG_PTR)baseDllNameOriginal - (ULONG_PTR)fullDllNameOriginal));\n        }\n        else\n        {\n            // Read the base DLL name string and add a null terminator.\n\n            baseDllNameBuffer = PhAllocate(Entry->BaseDllName.Length + 2);\n            Entry->BaseDllName.Buffer = baseDllNameBuffer;\n\n            if (NT_SUCCESS(NtReadVirtualMemory(\n                ProcessHandle,\n                baseDllNameOriginal,\n                baseDllNameBuffer,\n                Entry->BaseDllName.Length,\n                NULL\n                )))\n            {\n                baseDllNameBuffer[Entry->BaseDllName.Length / 2] = 0;\n            }\n            else\n            {\n                baseDllNameBuffer[0] = 0;\n                Entry->BaseDllName.Length = 0;\n            }\n        }\n    }\n\n    if (WindowsVersion >= WINDOWS_8)\n    {\n        LDR_DDAG_NODE ldrDagNode = { 0 };\n\n        if (NT_SUCCESS(NtReadVirtualMemory(\n            ProcessHandle,\n            Entry->DdagNode,\n            &ldrDagNode,\n            sizeof(LDR_DDAG_NODE),\n            NULL\n            )))\n        {\n            // HACK: Fixup the module load count.\n            // Temp fix until PhpModuleQueryWorker can be used for 'Stage2'. \n            Entry->ObsoleteLoadCount = (USHORT)ldrDagNode.LoadCount;\n        }\n    }\n\n    // Execute the callback.\n    cont = parameters->Callback(Entry, parameters->Context);\n\n    if (mappedFileName)\n    {\n        PhDereferenceObject(mappedFileName);\n    }\n    else\n    {\n        PhFree(fullDllNameBuffer);\n\n        if (baseDllNameBuffer)\n            PhFree(baseDllNameBuffer);\n    }\n\n    return cont;\n}\n\n/**\n * Enumerates the modules loaded by a process.\n *\n * \\param ProcessHandle A handle to a process. The handle must have\n * PROCESS_QUERY_LIMITED_INFORMATION and PROCESS_VM_READ access.\n * \\param Callback A callback function which is executed for each process module.\n * \\param Context A user-defined value to pass to the callback function.\n */\nNTSTATUS PhEnumProcessModules(\n    _In_ HANDLE ProcessHandle,\n    _In_ PPH_ENUM_PROCESS_MODULES_CALLBACK Callback,\n    _In_opt_ PVOID Context\n    )\n{\n    PH_ENUM_PROCESS_MODULES_PARAMETERS parameters;\n\n    parameters.Callback = Callback;\n    parameters.Context = Context;\n    parameters.Flags = 0;\n\n    return PhEnumProcessModulesEx(ProcessHandle, &parameters);\n}\n\n/**\n * Enumerates the modules loaded by a process.\n *\n * \\param ProcessHandle A handle to a process. The handle must have\n * PROCESS_QUERY_LIMITED_INFORMATION and PROCESS_VM_READ access. If\n * \\c PH_ENUM_PROCESS_MODULES_TRY_MAPPED_FILE_NAME is specified in \\a Parameters, the handle should\n * have PROCESS_QUERY_INFORMATION access.\n * \\param Parameters The enumeration parameters.\n */\nNTSTATUS PhEnumProcessModulesEx(\n    _In_ HANDLE ProcessHandle,\n    _In_ PPH_ENUM_PROCESS_MODULES_PARAMETERS Parameters\n    )\n{\n    return PhpEnumProcessModules(\n        ProcessHandle,\n        PhpEnumProcessModulesCallback,\n        Parameters,\n        NULL\n        );\n}\n\ntypedef struct _SET_PROCESS_MODULE_LOAD_COUNT_CONTEXT\n{\n    NTSTATUS Status;\n    PVOID BaseAddress;\n    ULONG LoadCount;\n} SET_PROCESS_MODULE_LOAD_COUNT_CONTEXT, *PSET_PROCESS_MODULE_LOAD_COUNT_CONTEXT;\n\nBOOLEAN NTAPI PhpSetProcessModuleLoadCountCallback(\n    _In_ HANDLE ProcessHandle,\n    _In_ PLDR_DATA_TABLE_ENTRY Entry,\n    _In_ PVOID AddressOfEntry,\n    _In_opt_ PVOID Context1,\n    _In_opt_ PVOID Context2\n    )\n{\n    PSET_PROCESS_MODULE_LOAD_COUNT_CONTEXT context = Context1;\n\n    if (Entry->DllBase == context->BaseAddress)\n    {\n        context->Status = NtWriteVirtualMemory(\n            ProcessHandle,\n            PTR_ADD_OFFSET(AddressOfEntry, FIELD_OFFSET(LDR_DATA_TABLE_ENTRY, ObsoleteLoadCount)),\n            &context->LoadCount,\n            sizeof(USHORT),\n            NULL\n            );\n\n        return FALSE;\n    }\n\n    return TRUE;\n}\n\n/**\n * Sets the load count of a process module.\n *\n * \\param ProcessHandle A handle to a process. The handle must have\n * PROCESS_QUERY_LIMITED_INFORMATION, PROCESS_VM_READ and PROCESS_VM_WRITE access.\n * \\param BaseAddress The base address of a module.\n * \\param LoadCount The new load count of the module.\n *\n * \\retval STATUS_DLL_NOT_FOUND The module was not found.\n */\nNTSTATUS PhSetProcessModuleLoadCount(\n    _In_ HANDLE ProcessHandle,\n    _In_ PVOID BaseAddress,\n    _In_ ULONG LoadCount\n    )\n{\n    NTSTATUS status;\n    SET_PROCESS_MODULE_LOAD_COUNT_CONTEXT context;\n\n    context.Status = STATUS_DLL_NOT_FOUND;\n    context.BaseAddress = BaseAddress;\n    context.LoadCount = LoadCount;\n\n    status = PhpEnumProcessModules(\n        ProcessHandle,\n        PhpSetProcessModuleLoadCountCallback,\n        &context,\n        NULL\n        );\n\n    if (!NT_SUCCESS(status))\n        return status;\n\n    return context.Status;\n}\n\nNTSTATUS PhpEnumProcessModules32(\n    _In_ HANDLE ProcessHandle,\n    _In_ PPHP_ENUM_PROCESS_MODULES32_CALLBACK Callback,\n    _In_opt_ PVOID Context1,\n    _In_opt_ PVOID Context2\n    )\n{\n    NTSTATUS status;\n    PPEB32 peb;\n    ULONG ldr; // PEB_LDR_DATA32 *32\n    PEB_LDR_DATA32 pebLdrData;\n    ULONG startLink; // LIST_ENTRY32 *32\n    ULONG currentLink; // LIST_ENTRY32 *32\n    ULONG dataTableEntrySize;\n    LDR_DATA_TABLE_ENTRY32 currentEntry;\n    ULONG i;\n\n    // Get the 32-bit PEB address.\n    status = PhGetProcessPeb32(ProcessHandle, &peb);\n\n    if (!NT_SUCCESS(status))\n        return status;\n\n    if (!peb)\n        return STATUS_NOT_SUPPORTED; // not a WOW64 process\n\n    // Read the address of the loader data.\n    status = NtReadVirtualMemory(\n        ProcessHandle,\n        PTR_ADD_OFFSET(peb, FIELD_OFFSET(PEB32, Ldr)),\n        &ldr,\n        sizeof(ULONG),\n        NULL\n        );\n\n    if (!NT_SUCCESS(status))\n        return status;\n\n    // Read the loader data.\n    status = NtReadVirtualMemory(\n        ProcessHandle,\n        UlongToPtr(ldr),\n        &pebLdrData,\n        sizeof(PEB_LDR_DATA32),\n        NULL\n        );\n\n    if (!NT_SUCCESS(status))\n        return status;\n\n    if (!pebLdrData.Initialized)\n        return STATUS_UNSUCCESSFUL;\n\n    if (WindowsVersion >= WINDOWS_8)\n        dataTableEntrySize = LDR_DATA_TABLE_ENTRY_SIZE_WIN8_32;\n    else\n        dataTableEntrySize = LDR_DATA_TABLE_ENTRY_SIZE_WIN7_32;\n\n    // Traverse the linked list (in load order).\n\n    i = 0;\n    startLink = (ULONG)(ldr + FIELD_OFFSET(PEB_LDR_DATA32, InLoadOrderModuleList));\n    currentLink = pebLdrData.InLoadOrderModuleList.Flink;\n\n    while (\n        currentLink != startLink &&\n        i <= PH_ENUM_PROCESS_MODULES_LIMIT\n        )\n    {\n        ULONG addressOfEntry;\n\n        addressOfEntry = PtrToUlong(CONTAINING_RECORD(UlongToPtr(currentLink), LDR_DATA_TABLE_ENTRY32, InLoadOrderLinks));\n        status = NtReadVirtualMemory(\n            ProcessHandle,\n            UlongToPtr(addressOfEntry),\n            &currentEntry,\n            dataTableEntrySize,\n            NULL\n            );\n\n        if (!NT_SUCCESS(status))\n            return status;\n\n        // Make sure the entry is valid.\n        if (currentEntry.DllBase)\n        {\n            // Execute the callback.\n            if (!Callback(\n                ProcessHandle,\n                &currentEntry,\n                addressOfEntry,\n                Context1,\n                Context2\n                ))\n                break;\n        }\n\n        currentLink = currentEntry.InLoadOrderLinks.Flink;\n        i++;\n    }\n\n    return status;\n}\n\nBOOLEAN NTAPI PhpEnumProcessModules32Callback(\n    _In_ HANDLE ProcessHandle,\n    _In_ PLDR_DATA_TABLE_ENTRY32 Entry,\n    _In_ ULONG AddressOfEntry,\n    _In_opt_ PVOID Context1,\n    _In_opt_ PVOID Context2\n    )\n{\n    static PH_STRINGREF system32String = PH_STRINGREF_INIT(L\"\\\\system32\\\\\");\n\n    PPH_ENUM_PROCESS_MODULES_PARAMETERS parameters;\n    BOOLEAN cont;\n    LDR_DATA_TABLE_ENTRY nativeEntry;\n    PPH_STRING mappedFileName;\n    PWSTR baseDllNameBuffer;\n    PWSTR fullDllNameBuffer;\n    PH_STRINGREF fullDllName;\n    PH_STRINGREF systemRootString;\n\n    parameters = Context1;\n\n    // Convert the 32-bit entry to a native-sized entry.\n\n    memset(&nativeEntry, 0, sizeof(LDR_DATA_TABLE_ENTRY));\n    nativeEntry.DllBase = UlongToPtr(Entry->DllBase);\n    nativeEntry.EntryPoint = UlongToPtr(Entry->EntryPoint);\n    nativeEntry.SizeOfImage = Entry->SizeOfImage;\n    UStr32ToUStr(&nativeEntry.FullDllName, &Entry->FullDllName);\n    UStr32ToUStr(&nativeEntry.BaseDllName, &Entry->BaseDllName);\n    nativeEntry.Flags = Entry->Flags;\n    nativeEntry.ObsoleteLoadCount = Entry->ObsoleteLoadCount;\n    nativeEntry.TlsIndex = Entry->TlsIndex;\n    nativeEntry.TimeDateStamp = Entry->TimeDateStamp;\n    nativeEntry.OriginalBase = Entry->OriginalBase;\n    nativeEntry.LoadTime = Entry->LoadTime;\n    nativeEntry.BaseNameHashValue = Entry->BaseNameHashValue;\n    nativeEntry.LoadReason = Entry->LoadReason;\n\n    mappedFileName = NULL;\n\n    if (parameters->Flags & PH_ENUM_PROCESS_MODULES_TRY_MAPPED_FILE_NAME)\n    {\n        PhGetProcessMappedFileName(ProcessHandle, nativeEntry.DllBase, &mappedFileName);\n    }\n\n    if (mappedFileName)\n    {\n        ULONG_PTR indexOfLastBackslash;\n\n        PhStringRefToUnicodeString(&mappedFileName->sr, &nativeEntry.FullDllName);\n        indexOfLastBackslash = PhFindLastCharInString(mappedFileName, 0, '\\\\');\n\n        if (indexOfLastBackslash != -1)\n        {\n            nativeEntry.BaseDllName.Buffer = nativeEntry.FullDllName.Buffer + indexOfLastBackslash + 1;\n            nativeEntry.BaseDllName.Length = nativeEntry.FullDllName.Length - (USHORT)indexOfLastBackslash * 2 - 2;\n            nativeEntry.BaseDllName.MaximumLength = nativeEntry.BaseDllName.Length;\n        }\n        else\n        {\n            nativeEntry.BaseDllName = nativeEntry.FullDllName;\n        }\n    }\n    else\n    {\n        // Read the base DLL name string and add a null terminator.\n\n        baseDllNameBuffer = PhAllocate(nativeEntry.BaseDllName.Length + 2);\n\n        if (NT_SUCCESS(NtReadVirtualMemory(\n            ProcessHandle,\n            nativeEntry.BaseDllName.Buffer,\n            baseDllNameBuffer,\n            nativeEntry.BaseDllName.Length,\n            NULL\n            )))\n        {\n            baseDllNameBuffer[nativeEntry.BaseDllName.Length / 2] = 0;\n        }\n        else\n        {\n            baseDllNameBuffer[0] = 0;\n            nativeEntry.BaseDllName.Length = 0;\n        }\n\n        nativeEntry.BaseDllName.Buffer = baseDllNameBuffer;\n\n        // Read the full DLL name string and add a null terminator.\n\n        fullDllNameBuffer = PhAllocate(nativeEntry.FullDllName.Length + 2);\n\n        if (NT_SUCCESS(NtReadVirtualMemory(\n            ProcessHandle,\n            nativeEntry.FullDllName.Buffer,\n            fullDllNameBuffer,\n            nativeEntry.FullDllName.Length,\n            NULL\n            )))\n        {\n            fullDllNameBuffer[nativeEntry.FullDllName.Length / 2] = 0;\n\n            if (!(parameters->Flags & PH_ENUM_PROCESS_MODULES_DONT_RESOLVE_WOW64_FS))\n            {\n                // WOW64 file system redirection - convert \"system32\" to \"SysWOW64\".\n                if (!(nativeEntry.FullDllName.Length & 1)) // validate the string length\n                {\n                    fullDllName.Buffer = fullDllNameBuffer;\n                    fullDllName.Length = nativeEntry.FullDllName.Length;\n\n                    PhGetSystemRoot(&systemRootString);\n\n                    if (PhStartsWithStringRef(&fullDllName, &systemRootString, TRUE))\n                    {\n                        PhSkipStringRef(&fullDllName, systemRootString.Length);\n\n                        if (PhStartsWithStringRef(&fullDllName, &system32String, TRUE))\n                        {\n                            fullDllName.Buffer[1] = 'S';\n                            fullDllName.Buffer[4] = 'W';\n                            fullDllName.Buffer[5] = 'O';\n                            fullDllName.Buffer[6] = 'W';\n                            fullDllName.Buffer[7] = '6';\n                            fullDllName.Buffer[8] = '4';\n                        }\n                    }\n                }\n            }\n        }\n        else\n        {\n            fullDllNameBuffer[0] = 0;\n            nativeEntry.FullDllName.Length = 0;\n        }\n\n        nativeEntry.FullDllName.Buffer = fullDllNameBuffer;\n    }\n\n    if (WindowsVersion >= WINDOWS_8)\n    {\n        LDR_DDAG_NODE32 ldrDagNode32 = { 0 };\n\n        if (NT_SUCCESS(NtReadVirtualMemory(\n            ProcessHandle,\n            UlongToPtr(Entry->DdagNode),\n            &ldrDagNode32,\n            sizeof(LDR_DDAG_NODE32),\n            NULL\n            )))\n        {\n            // HACK: Fixup the module load count.\n            // Temp fix until PhpModuleQueryWorker can be used for 'Stage2'. \n            nativeEntry.ObsoleteLoadCount = (USHORT)ldrDagNode32.LoadCount;\n        }\n    }\n\n    // Execute the callback.\n    cont = parameters->Callback(&nativeEntry, parameters->Context);\n\n    if (mappedFileName)\n    {\n        PhDereferenceObject(mappedFileName);\n    }\n    else\n    {\n        PhFree(baseDllNameBuffer);\n        PhFree(fullDllNameBuffer);\n    }\n\n    return cont;\n}\n\n/**\n * Enumerates the 32-bit modules loaded by a process.\n *\n * \\param ProcessHandle A handle to a process. The handle must have\n * PROCESS_QUERY_LIMITED_INFORMATION and PROCESS_VM_READ access.\n * \\param Callback A callback function which is executed for each process module.\n * \\param Context A user-defined value to pass to the callback function.\n *\n * \\retval STATUS_NOT_SUPPORTED The process is not running under WOW64.\n *\n * \\remarks Do not use this function under a 32-bit environment.\n */\nNTSTATUS PhEnumProcessModules32(\n    _In_ HANDLE ProcessHandle,\n    _In_ PPH_ENUM_PROCESS_MODULES_CALLBACK Callback,\n    _In_opt_ PVOID Context\n    )\n{\n    PH_ENUM_PROCESS_MODULES_PARAMETERS parameters;\n\n    parameters.Callback = Callback;\n    parameters.Context = Context;\n    parameters.Flags = 0;\n\n    return PhEnumProcessModules32Ex(ProcessHandle, &parameters);\n}\n\n/**\n * Enumerates the 32-bit modules loaded by a process.\n *\n * \\param ProcessHandle A handle to a process. The handle must have\n * PROCESS_QUERY_LIMITED_INFORMATION and PROCESS_VM_READ access. If\n * \\c PH_ENUM_PROCESS_MODULES_TRY_MAPPED_FILE_NAME is specified in \\a Parameters, the handle should\n * have PROCESS_QUERY_INFORMATION access.\n * \\param Parameters The enumeration parameters.\n *\n * \\retval STATUS_NOT_SUPPORTED The process is not running under WOW64.\n *\n * \\remarks Do not use this function under a 32-bit environment.\n */\nNTSTATUS PhEnumProcessModules32Ex(\n    _In_ HANDLE ProcessHandle,\n    _In_ PPH_ENUM_PROCESS_MODULES_PARAMETERS Parameters\n    )\n{\n    return PhpEnumProcessModules32(\n        ProcessHandle,\n        PhpEnumProcessModules32Callback,\n        Parameters,\n        NULL\n        );\n}\n\nBOOLEAN NTAPI PhpSetProcessModuleLoadCount32Callback(\n    _In_ HANDLE ProcessHandle,\n    _In_ PLDR_DATA_TABLE_ENTRY32 Entry,\n    _In_ ULONG AddressOfEntry,\n    _In_opt_ PVOID Context1,\n    _In_opt_ PVOID Context2\n    )\n{\n    PSET_PROCESS_MODULE_LOAD_COUNT_CONTEXT context = Context1;\n\n    if (UlongToPtr(Entry->DllBase) == context->BaseAddress)\n    {\n        context->Status = NtWriteVirtualMemory(\n            ProcessHandle,\n            UlongToPtr(AddressOfEntry + FIELD_OFFSET(LDR_DATA_TABLE_ENTRY32, ObsoleteLoadCount)),\n            &context->LoadCount,\n            sizeof(USHORT),\n            NULL\n            );\n\n        return FALSE;\n    }\n\n    return TRUE;\n}\n\n/**\n * Sets the load count of a 32-bit process module.\n *\n * \\param ProcessHandle A handle to a process. The handle must have\n * PROCESS_QUERY_LIMITED_INFORMATION, PROCESS_VM_READ and PROCESS_VM_WRITE access.\n * \\param BaseAddress The base address of a module.\n * \\param LoadCount The new load count of the module.\n *\n * \\retval STATUS_DLL_NOT_FOUND The module was not found.\n * \\retval STATUS_NOT_SUPPORTED The process is not running under WOW64.\n *\n * \\remarks Do not use this function under a 32-bit environment.\n */\nNTSTATUS PhSetProcessModuleLoadCount32(\n    _In_ HANDLE ProcessHandle,\n    _In_ PVOID BaseAddress,\n    _In_ ULONG LoadCount\n    )\n{\n    NTSTATUS status;\n    SET_PROCESS_MODULE_LOAD_COUNT_CONTEXT context;\n\n    context.Status = STATUS_DLL_NOT_FOUND;\n    context.BaseAddress = BaseAddress;\n    context.LoadCount = LoadCount;\n\n    status = PhpEnumProcessModules32(\n        ProcessHandle,\n        PhpSetProcessModuleLoadCount32Callback,\n        &context,\n        NULL\n        );\n\n    if (!NT_SUCCESS(status))\n        return status;\n\n    return context.Status;\n}\n\ntypedef struct _GET_PROCEDURE_ADDRESS_REMOTE_CONTEXT\n{\n    PH_STRINGREF FileName;\n    PVOID DllBase;\n} GET_PROCEDURE_ADDRESS_REMOTE_CONTEXT, *PGET_PROCEDURE_ADDRESS_REMOTE_CONTEXT;\n\nstatic BOOLEAN PhpGetProcedureAddressRemoteCallback(\n    _In_ PLDR_DATA_TABLE_ENTRY Module,\n    _In_opt_ PVOID Context\n    )\n{\n    PGET_PROCEDURE_ADDRESS_REMOTE_CONTEXT context = Context;\n    PH_STRINGREF fullDllName;\n\n    PhUnicodeStringToStringRef(&Module->FullDllName, &fullDllName);\n\n    if (PhEqualStringRef(&fullDllName, &context->FileName, TRUE))\n    {\n        context->DllBase = Module->DllBase;\n        return FALSE;\n    }\n\n    return TRUE;\n}\n\n/**\n * Gets the address of a procedure in a process.\n *\n * \\param ProcessHandle A handle to a process. The handle must have\n * PROCESS_QUERY_LIMITED_INFORMATION and PROCESS_VM_READ access.\n * \\param FileName The file name of the DLL containing the procedure.\n * \\param ProcedureName The name of the procedure.\n * \\param ProcedureNumber The ordinal of the procedure.\n * \\param ProcedureAddress A variable which receives the address of the procedure in the address\n * space of the process.\n * \\param DllBase A variable which receives the base address of the DLL containing the procedure.\n */\nNTSTATUS PhGetProcedureAddressRemote(\n    _In_ HANDLE ProcessHandle,\n    _In_ PWSTR FileName,\n    _In_opt_ PSTR ProcedureName,\n    _In_opt_ ULONG ProcedureNumber,\n    _Out_ PVOID *ProcedureAddress,\n    _Out_opt_ PVOID *DllBase\n    )\n{\n    NTSTATUS status;\n    PH_MAPPED_IMAGE mappedImage;\n    PH_MAPPED_IMAGE_EXPORTS exports;\n    GET_PROCEDURE_ADDRESS_REMOTE_CONTEXT context;\n\n    if (!NT_SUCCESS(status = PhLoadMappedImage(FileName, NULL, TRUE, &mappedImage)))\n        return status;\n\n    PhInitializeStringRef(&context.FileName, FileName);\n    context.DllBase = NULL;\n\n    if (mappedImage.Magic == IMAGE_NT_OPTIONAL_HDR32_MAGIC)\n    {\n#ifdef _WIN64\n        status = PhEnumProcessModules32(ProcessHandle, PhpGetProcedureAddressRemoteCallback, &context);\n#else\n        status = PhEnumProcessModules(ProcessHandle, PhpGetProcedureAddressRemoteCallback, &context);\n#endif\n    }\n    else\n    {\n#ifdef _WIN64\n        status = PhEnumProcessModules(ProcessHandle, PhpGetProcedureAddressRemoteCallback, &context);\n#else\n        status = STATUS_NOT_SUPPORTED;\n#endif\n    }\n\n    if (!NT_SUCCESS(status))\n        goto CleanupExit;\n\n    if (!NT_SUCCESS(status = PhGetMappedImageExports(&exports, &mappedImage)))\n        goto CleanupExit;\n\n    status = PhGetMappedImageExportFunctionRemote(\n        &exports,\n        ProcedureName,\n        (USHORT)ProcedureNumber,\n        context.DllBase,\n        ProcedureAddress\n        );\n\n    if (NT_SUCCESS(status))\n    {\n        if (DllBase)\n            *DllBase = context.DllBase;\n    }\n\nCleanupExit:\n    PhUnloadMappedImage(&mappedImage);\n\n    return status;\n}\n\n/**\n * Enumerates the modules loaded by the kernel.\n *\n * \\param Modules A variable which receives a pointer to a structure containing information about\n * the kernel modules. You must free the structure using PhFree() when you no longer need it.\n */\nNTSTATUS PhEnumKernelModules(\n    _Out_ PRTL_PROCESS_MODULES *Modules\n    )\n{\n    NTSTATUS status;\n    PVOID buffer;\n    ULONG bufferSize = 2048;\n\n    buffer = PhAllocate(bufferSize);\n\n    status = NtQuerySystemInformation(\n        SystemModuleInformation,\n        buffer,\n        bufferSize,\n        &bufferSize\n        );\n\n    if (status == STATUS_INFO_LENGTH_MISMATCH)\n    {\n        PhFree(buffer);\n        buffer = PhAllocate(bufferSize);\n\n        status = NtQuerySystemInformation(\n            SystemModuleInformation,\n            buffer,\n            bufferSize,\n            &bufferSize\n            );\n    }\n\n    if (!NT_SUCCESS(status))\n        return status;\n\n    *Modules = buffer;\n\n    return status;\n}\n\n/**\n * Enumerates the modules loaded by the kernel.\n *\n * \\param Modules A variable which receives a pointer to a structure containing information about\n * the kernel modules. You must free the structure using PhFree() when you no longer need it.\n */\nNTSTATUS PhEnumKernelModulesEx(\n    _Out_ PRTL_PROCESS_MODULE_INFORMATION_EX *Modules\n    )\n{\n    NTSTATUS status;\n    PVOID buffer;\n    ULONG bufferSize = 2048;\n\n    buffer = PhAllocate(bufferSize);\n\n    status = NtQuerySystemInformation(\n        SystemModuleInformationEx,\n        buffer,\n        bufferSize,\n        &bufferSize\n        );\n\n    if (status == STATUS_INFO_LENGTH_MISMATCH)\n    {\n        PhFree(buffer);\n        buffer = PhAllocate(bufferSize);\n\n        status = NtQuerySystemInformation(\n            SystemModuleInformationEx,\n            buffer,\n            bufferSize,\n            &bufferSize\n            );\n    }\n\n    if (!NT_SUCCESS(status))\n        return status;\n\n    *Modules = buffer;\n\n    return status;\n}\n\n/**\n * Gets the file name of the kernel image.\n *\n * \\return A pointer to a string containing the kernel image file name. You must free the string\n * using PhDereferenceObject() when you no longer need it.\n */\nPPH_STRING PhGetKernelFileName(\n    VOID\n    )\n{\n    PRTL_PROCESS_MODULES modules;\n    PPH_STRING fileName = NULL;\n\n    if (!NT_SUCCESS(PhEnumKernelModules(&modules)))\n        return NULL;\n\n    if (modules->NumberOfModules >= 1)\n    {\n        fileName = PhConvertMultiByteToUtf16(modules->Modules[0].FullPathName);\n    }\n\n    PhFree(modules);\n\n    return fileName;\n}\n\n/**\n * Enumerates the running processes.\n *\n * \\param Processes A variable which receives a pointer to a buffer containing process information.\n * You must free the buffer using PhFree() when you no longer need it.\n *\n * \\remarks You can use the \\ref PH_FIRST_PROCESS and \\ref PH_NEXT_PROCESS macros to process the\n * information contained in the buffer.\n */\nNTSTATUS PhEnumProcesses(\n    _Out_ PVOID *Processes\n    )\n{\n    return PhEnumProcessesEx(Processes, SystemProcessInformation);\n}\n\n/**\n * Enumerates the running processes.\n *\n * \\param Processes A variable which receives a pointer to a buffer containing process information.\n * You must free the buffer using PhFree() when you no longer need it.\n *\n * \\remarks You can use the \\ref PH_FIRST_PROCESS and \\ref PH_NEXT_PROCESS macros to process the\n * information contained in the buffer.\n */\nNTSTATUS PhEnumProcessesEx(\n    _Out_ PVOID *Processes,\n    _In_ SYSTEM_INFORMATION_CLASS SystemInformationClass\n    )\n{\n    static ULONG initialBufferSize[3] = { 0x4000, 0x4000, 0x4000 };\n    NTSTATUS status;\n    ULONG classIndex;\n    PVOID buffer;\n    ULONG bufferSize;\n\n    switch (SystemInformationClass)\n    {\n    case SystemProcessInformation:\n        classIndex = 0;\n        break;\n    case SystemExtendedProcessInformation:\n        classIndex = 1;\n        break;\n    case SystemFullProcessInformation:\n        classIndex = 2;\n        break;\n    default:\n        return STATUS_INVALID_INFO_CLASS;\n    }\n\n    bufferSize = initialBufferSize[classIndex];\n    buffer = PhAllocate(bufferSize);\n\n    while (TRUE)\n    {\n        status = NtQuerySystemInformation(\n            SystemInformationClass,\n            buffer,\n            bufferSize,\n            &bufferSize\n            );\n\n        if (status == STATUS_BUFFER_TOO_SMALL || status == STATUS_INFO_LENGTH_MISMATCH)\n        {\n            PhFree(buffer);\n            buffer = PhAllocate(bufferSize);\n        }\n        else\n        {\n            break;\n        }\n    }\n\n    if (!NT_SUCCESS(status))\n    {\n        PhFree(buffer);\n        return status;\n    }\n\n    if (bufferSize <= 0x100000) initialBufferSize[classIndex] = bufferSize;\n    *Processes = buffer;\n\n    return status;\n}\n\n/**\n * Enumerates the running processes for a session.\n *\n * \\param Processes A variable which receives a pointer to a buffer containing process information.\n * You must free the buffer using PhFree() when you no longer need it.\n * \\param SessionId A session ID.\n *\n * \\remarks You can use the \\ref PH_FIRST_PROCESS and \\ref PH_NEXT_PROCESS macros to process the\n * information contained in the buffer.\n */\nNTSTATUS PhEnumProcessesForSession(\n    _Out_ PVOID *Processes,\n    _In_ ULONG SessionId\n    )\n{\n    static ULONG initialBufferSize = 0x4000;\n    NTSTATUS status;\n    SYSTEM_SESSION_PROCESS_INFORMATION sessionProcessInfo;\n    PVOID buffer;\n    ULONG bufferSize;\n\n    bufferSize = initialBufferSize;\n    buffer = PhAllocate(bufferSize);\n\n    sessionProcessInfo.SessionId = SessionId;\n\n    while (TRUE)\n    {\n        sessionProcessInfo.SizeOfBuf = bufferSize;\n        sessionProcessInfo.Buffer = buffer;\n\n        status = NtQuerySystemInformation(\n            SystemSessionProcessInformation,\n            &sessionProcessInfo,\n            sizeof(SYSTEM_SESSION_PROCESS_INFORMATION),\n            &bufferSize // size of the inner buffer gets returned\n            );\n\n        if (status == STATUS_BUFFER_TOO_SMALL || status == STATUS_INFO_LENGTH_MISMATCH)\n        {\n            PhFree(buffer);\n            buffer = PhAllocate(bufferSize);\n        }\n        else\n        {\n            break;\n        }\n    }\n\n    if (!NT_SUCCESS(status))\n    {\n        PhFree(buffer);\n        return status;\n    }\n\n    if (bufferSize <= 0x100000) initialBufferSize = bufferSize;\n    *Processes = buffer;\n\n    return status;\n}\n\n/**\n * Finds the process information structure for a specific process.\n *\n * \\param Processes A pointer to a buffer returned by PhEnumProcesses().\n * \\param ProcessId The ID of the process.\n *\n * \\return A pointer to the process information structure for the specified process, or NULL if the\n * structure could not be found.\n */\nPSYSTEM_PROCESS_INFORMATION PhFindProcessInformation(\n    _In_ PVOID Processes,\n    _In_ HANDLE ProcessId\n    )\n{\n    PSYSTEM_PROCESS_INFORMATION process;\n\n    process = PH_FIRST_PROCESS(Processes);\n\n    do\n    {\n        if (process->UniqueProcessId == ProcessId)\n            return process;\n    } while (process = PH_NEXT_PROCESS(process));\n\n    return NULL;\n}\n\n/**\n * Finds the process information structure for a specific process.\n *\n * \\param Processes A pointer to a buffer returned by PhEnumProcesses().\n * \\param ImageName The image name to search for.\n *\n * \\return A pointer to the process information structure for the specified process, or NULL if the\n * structure could not be found.\n */\nPSYSTEM_PROCESS_INFORMATION PhFindProcessInformationByImageName(\n    _In_ PVOID Processes,\n    _In_ PPH_STRINGREF ImageName\n    )\n{\n    PSYSTEM_PROCESS_INFORMATION process;\n    PH_STRINGREF processImageName;\n\n    process = PH_FIRST_PROCESS(Processes);\n\n    do\n    {\n        PhUnicodeStringToStringRef(&process->ImageName, &processImageName);\n\n        if (PhEqualStringRef(&processImageName, ImageName, TRUE))\n            return process;\n    } while (process = PH_NEXT_PROCESS(process));\n\n    return NULL;\n}\n\n/**\n * Enumerates all open handles.\n *\n * \\param Handles A variable which receives a pointer to a structure containing information about\n * all opened handles. You must free the structure using PhFree() when you no longer need it.\n *\n * \\retval STATUS_INSUFFICIENT_RESOURCES The handle information returned by the kernel is too large.\n */\nNTSTATUS PhEnumHandles(\n    _Out_ PSYSTEM_HANDLE_INFORMATION *Handles\n    )\n{\n    static ULONG initialBufferSize = 0x4000;\n    NTSTATUS status;\n    PVOID buffer;\n    ULONG bufferSize;\n\n    bufferSize = initialBufferSize;\n    buffer = PhAllocate(bufferSize);\n\n    while ((status = NtQuerySystemInformation(\n        SystemHandleInformation,\n        buffer,\n        bufferSize,\n        NULL\n        )) == STATUS_INFO_LENGTH_MISMATCH)\n    {\n        PhFree(buffer);\n        bufferSize *= 2;\n\n        // Fail if we're resizing the buffer to something very large.\n        if (bufferSize > PH_LARGE_BUFFER_SIZE)\n            return STATUS_INSUFFICIENT_RESOURCES;\n\n        buffer = PhAllocate(bufferSize);\n    }\n\n    if (!NT_SUCCESS(status))\n    {\n        PhFree(buffer);\n        return status;\n    }\n\n    if (bufferSize <= 0x100000) initialBufferSize = bufferSize;\n    *Handles = (PSYSTEM_HANDLE_INFORMATION)buffer;\n\n    return status;\n}\n\n/**\n * Enumerates all open handles.\n *\n * \\param Handles A variable which receives a pointer to a structure containing information about\n * all opened handles. You must free the structure using PhFree() when you no longer need it.\n *\n * \\retval STATUS_INSUFFICIENT_RESOURCES The handle information returned by the kernel is too large.\n *\n * \\remarks This function is only available starting with Windows XP.\n */\nNTSTATUS PhEnumHandlesEx(\n    _Out_ PSYSTEM_HANDLE_INFORMATION_EX *Handles\n    )\n{\n    static ULONG initialBufferSize = 0x10000;\n    NTSTATUS status;\n    PVOID buffer;\n    ULONG bufferSize;\n\n    bufferSize = initialBufferSize;\n    buffer = PhAllocate(bufferSize);\n\n    while ((status = NtQuerySystemInformation(\n        SystemExtendedHandleInformation,\n        buffer,\n        bufferSize,\n        NULL\n        )) == STATUS_INFO_LENGTH_MISMATCH)\n    {\n        PhFree(buffer);\n        bufferSize *= 2;\n\n        // Fail if we're resizing the buffer to something very large.\n        if (bufferSize > PH_LARGE_BUFFER_SIZE)\n            return STATUS_INSUFFICIENT_RESOURCES;\n\n        buffer = PhAllocate(bufferSize);\n    }\n\n    if (!NT_SUCCESS(status))\n    {\n        PhFree(buffer);\n        return status;\n    }\n\n    if (bufferSize <= 0x200000) initialBufferSize = bufferSize;\n    *Handles = (PSYSTEM_HANDLE_INFORMATION_EX)buffer;\n\n    return status;\n}\n\n/**\n * Enumerates all open handles.\n *\n * \\param ProcessHandle A handle to the process. The handle must have PROCESS_QUERY_INFORMATION access.\n * \\param Handles A variable which receives a pointer to a structure containing information about\n * handles opened by the process. You must free the structure using PhFree() when you no longer need it.\n *\n * \\retval STATUS_INSUFFICIENT_RESOURCES The handle information returned by the kernel is too large.\n *\n * \\remarks This function is only available starting with Windows 8.\n */\nNTSTATUS PhEnumHandlesEx2(\n    _In_ HANDLE ProcessHandle,\n    _Out_ PPROCESS_HANDLE_SNAPSHOT_INFORMATION *Handles\n    )\n{\n    NTSTATUS status;\n    PVOID buffer;\n    ULONG bufferSize;\n    ULONG returnLength = 0;\n    ULONG attempts = 0;\n\n    bufferSize = 0x8000;\n    buffer = PhAllocate(bufferSize);\n    memset(buffer, 0, bufferSize);\n\n    status = NtQueryInformationProcess(\n        ProcessHandle,\n        ProcessHandleInformation,\n        buffer,\n        bufferSize,\n        &returnLength\n        );\n\n    while (status == STATUS_INFO_LENGTH_MISMATCH && attempts < 8)\n    {\n        PhFree(buffer);\n        bufferSize = returnLength;\n        buffer = PhAllocate(bufferSize);\n        memset(buffer, 0, bufferSize);\n\n        status = NtQueryInformationProcess(\n            ProcessHandle,\n            ProcessHandleInformation,\n            buffer,\n            bufferSize,\n            &returnLength\n            );\n        attempts++;\n    }\n\n    if (NT_SUCCESS(status))\n        *Handles = buffer;\n    else\n        PhFree(buffer);\n\n    return status;\n}\n\n/**\n * Enumerates all pagefiles.\n *\n * \\param Pagefiles A variable which receives a pointer to a buffer containing information about all\n * active pagefiles. You must free the structure using PhFree() when you no longer need it.\n *\n * \\retval STATUS_INSUFFICIENT_RESOURCES The handle information returned by the kernel is too large.\n */\nNTSTATUS PhEnumPagefiles(\n    _Out_ PVOID *Pagefiles\n    )\n{\n    NTSTATUS status;\n    PVOID buffer;\n    ULONG bufferSize = 0x200;\n\n    buffer = PhAllocate(bufferSize);\n\n    while ((status = NtQuerySystemInformation(\n        SystemPageFileInformation,\n        buffer,\n        bufferSize,\n        NULL\n        )) == STATUS_INFO_LENGTH_MISMATCH)\n    {\n        PhFree(buffer);\n        bufferSize *= 2;\n\n        // Fail if we're resizing the buffer to something very large.\n        if (bufferSize > PH_LARGE_BUFFER_SIZE)\n            return STATUS_INSUFFICIENT_RESOURCES;\n\n        buffer = PhAllocate(bufferSize);\n    }\n\n    if (!NT_SUCCESS(status))\n    {\n        PhFree(buffer);\n        return status;\n    }\n\n    *Pagefiles = buffer;\n\n    return status;\n}\n\n/**\n * Gets the file name of a process' image.\n *\n * \\param ProcessId The ID of the process.\n * \\param FileName A variable which receives a pointer to a string containing the file name. You\n * must free the string using PhDereferenceObject() when you no longer need it.\n *\n * \\remarks This function only works on Windows Vista and above. There does not appear to be any\n * access checking performed by the kernel for this.\n */\nNTSTATUS PhGetProcessImageFileNameByProcessId(\n    _In_ HANDLE ProcessId,\n    _Out_ PPH_STRING *FileName\n    )\n{\n    NTSTATUS status;\n    PVOID buffer;\n    ULONG bufferSize = 0x100;\n    SYSTEM_PROCESS_ID_INFORMATION processIdInfo;\n\n    buffer = PhAllocate(bufferSize);\n\n    processIdInfo.ProcessId = ProcessId;\n    processIdInfo.ImageName.Length = 0;\n    processIdInfo.ImageName.MaximumLength = (USHORT)bufferSize;\n    processIdInfo.ImageName.Buffer = buffer;\n\n    status = NtQuerySystemInformation(\n        SystemProcessIdInformation,\n        &processIdInfo,\n        sizeof(SYSTEM_PROCESS_ID_INFORMATION),\n        NULL\n        );\n\n    if (status == STATUS_INFO_LENGTH_MISMATCH)\n    {\n        // Required length is stored in MaximumLength.\n\n        PhFree(buffer);\n        buffer = PhAllocate(processIdInfo.ImageName.MaximumLength);\n        processIdInfo.ImageName.Buffer = buffer;\n\n        status = NtQuerySystemInformation(\n            SystemProcessIdInformation,\n            &processIdInfo,\n            sizeof(SYSTEM_PROCESS_ID_INFORMATION),\n            NULL\n            );\n    }\n\n    if (!NT_SUCCESS(status))\n    {\n        PhFree(buffer);\n        return status;\n    }\n\n    *FileName = PhCreateStringFromUnicodeString(&processIdInfo.ImageName);\n    PhFree(buffer);\n\n    return status;\n}\n\n/**\n * Determines if a process is managed.\n *\n * \\param ProcessId The ID of the process.\n * \\param IsDotNet A variable which receives a boolean indicating whether the process is managed.\n */\nNTSTATUS PhGetProcessIsDotNet(\n    _In_ HANDLE ProcessId,\n    _Out_ PBOOLEAN IsDotNet\n    )\n{\n    return PhGetProcessIsDotNetEx(ProcessId, NULL, 0, IsDotNet, NULL);\n}\n\nBOOLEAN NTAPI PhpIsDotNetEnumProcessModulesCallback(\n    _In_ PLDR_DATA_TABLE_ENTRY Module,\n    _In_opt_ PVOID Context\n    )\n{\n    static UNICODE_STRING clrString = RTL_CONSTANT_STRING(L\"clr.dll\");\n    static UNICODE_STRING mscorwksString = RTL_CONSTANT_STRING(L\"mscorwks.dll\");\n    static UNICODE_STRING mscorsvrString = RTL_CONSTANT_STRING(L\"mscorsvr.dll\");\n    static UNICODE_STRING mscorlibString = RTL_CONSTANT_STRING(L\"mscorlib.dll\");\n    static UNICODE_STRING mscorlibNiString = RTL_CONSTANT_STRING(L\"mscorlib.ni.dll\");\n    static UNICODE_STRING clrjitString = RTL_CONSTANT_STRING(L\"clrjit.dll\");\n    static UNICODE_STRING frameworkString = RTL_CONSTANT_STRING(L\"\\\\Microsoft.NET\\\\Framework\\\\\");\n    static UNICODE_STRING framework64String = RTL_CONSTANT_STRING(L\"\\\\Microsoft.NET\\\\Framework64\\\\\");\n\n    if (\n        RtlEqualUnicodeString(&Module->BaseDllName, &clrString, TRUE) ||\n        RtlEqualUnicodeString(&Module->BaseDllName, &mscorwksString, TRUE) ||\n        RtlEqualUnicodeString(&Module->BaseDllName, &mscorsvrString, TRUE)\n        )\n    {\n        UNICODE_STRING fileName;\n        PH_STRINGREF systemRootSr;\n        UNICODE_STRING systemRoot;\n        PUNICODE_STRING frameworkPart;\n\n#ifdef _WIN64\n        if (*(PULONG)Context & PH_CLR_PROCESS_IS_WOW64)\n        {\n#endif\n            frameworkPart = &frameworkString;\n#ifdef _WIN64\n        }\n        else\n        {\n            frameworkPart = &framework64String;\n        }\n#endif\n\n        fileName = Module->FullDllName;\n        PhGetSystemRoot(&systemRootSr);\n        PhStringRefToUnicodeString(&systemRootSr, &systemRoot);\n\n        if (RtlPrefixUnicodeString(&systemRoot, &fileName, TRUE))\n        {\n            fileName.Buffer = (PWCHAR)PTR_ADD_OFFSET(fileName.Buffer, systemRoot.Length);\n            fileName.Length -= systemRoot.Length;\n\n            if (RtlPrefixUnicodeString(frameworkPart, &fileName, TRUE))\n            {\n                fileName.Buffer = (PWCHAR)PTR_ADD_OFFSET(fileName.Buffer, frameworkPart->Length);\n                fileName.Length -= frameworkPart->Length;\n\n                if (fileName.Length >= 4 * sizeof(WCHAR)) // vx.x\n                {\n                    if (fileName.Buffer[1] == '1')\n                    {\n                        if (fileName.Buffer[3] == '0')\n                            *(PULONG)Context |= PH_CLR_VERSION_1_0;\n                        else if (fileName.Buffer[3] == '1')\n                            *(PULONG)Context |= PH_CLR_VERSION_1_1;\n                    }\n                    else if (fileName.Buffer[1] == '2')\n                    {\n                        *(PULONG)Context |= PH_CLR_VERSION_2_0;\n                    }\n                    else if (fileName.Buffer[1] >= '4' && fileName.Buffer[1] <= '9')\n                    {\n                        *(PULONG)Context |= PH_CLR_VERSION_4_ABOVE;\n                    }\n                }\n            }\n        }\n    }\n    else if (\n        RtlEqualUnicodeString(&Module->BaseDllName, &mscorlibString, TRUE) ||\n        RtlEqualUnicodeString(&Module->BaseDllName, &mscorlibNiString, TRUE)\n        )\n    {\n        *(PULONG)Context |= PH_CLR_MSCORLIB_PRESENT;\n    }\n    else if (RtlEqualUnicodeString(&Module->BaseDllName, &clrjitString, TRUE))\n    {\n        *(PULONG)Context |= PH_CLR_JIT_PRESENT;\n    }\n\n    return TRUE;\n}\n\n/**\n * Determines if a process is managed.\n *\n * \\param ProcessId The ID of the process.\n * \\param ProcessHandle An optional handle to the process. The handle must have\n * PROCESS_QUERY_LIMITED_INFORMATION and PROCESS_VM_READ access.\n * \\param InFlags A combination of flags.\n * \\li \\c PH_CLR_USE_SECTION_CHECK Checks for the existence of related section objects to determine\n * whether the process is managed.\n * \\li \\c PH_CLR_NO_WOW64_CHECK Instead of a separate query, uses the presence of the\n * \\c PH_CLR_KNOWN_IS_WOW64 flag to determine whether the process is running under WOW64.\n * \\li \\c PH_CLR_KNOWN_IS_WOW64 When \\c PH_CLR_NO_WOW64_CHECK is specified, indicates that the\n * process is managed.\n * \\param IsDotNet A variable which receives a boolean indicating whether the process is managed.\n * \\param Flags A variable which receives additional flags.\n */\nNTSTATUS PhGetProcessIsDotNetEx(\n    _In_ HANDLE ProcessId,\n    _In_opt_ HANDLE ProcessHandle,\n    _In_ ULONG InFlags,\n    _Out_opt_ PBOOLEAN IsDotNet,\n    _Out_opt_ PULONG Flags\n    )\n{\n    if (InFlags & PH_CLR_USE_SECTION_CHECK)\n    {\n        NTSTATUS status;\n        HANDLE sectionHandle;\n        OBJECT_ATTRIBUTES objectAttributes;\n        PPH_STRING sectionName;\n        UNICODE_STRING sectionNameUs;\n        PH_FORMAT format[2];\n\n        // Most .NET processes have a handle open to a section named\n        // \\BaseNamedObjects\\Cor_Private_IPCBlock(_v4)_<ProcessId>. This is the same object used by\n        // the ICorPublish::GetProcess function. Instead of calling that function, we simply check\n        // for the existence of that section object. This means:\n        // * Better performance.\n        // * No need for admin rights to get .NET status of processes owned by other users.\n\n        PhInitFormatIU(&format[1], (ULONG_PTR)ProcessId);\n\n        // Version 4 section object\n\n        PhInitFormatS(&format[0], L\"\\\\BaseNamedObjects\\\\Cor_Private_IPCBlock_v4_\");\n        sectionName = PhFormat(format, 2, 96);\n        PhStringRefToUnicodeString(&sectionName->sr, &sectionNameUs);\n\n        InitializeObjectAttributes(\n            &objectAttributes,\n            &sectionNameUs,\n            OBJ_CASE_INSENSITIVE,\n            NULL,\n            NULL\n            );\n        status = NtOpenSection(\n            &sectionHandle,\n            SECTION_QUERY,\n            &objectAttributes\n            );\n        PhDereferenceObject(sectionName);\n\n        if (NT_SUCCESS(status) || status == STATUS_ACCESS_DENIED)\n        {\n            if (NT_SUCCESS(status))\n                NtClose(sectionHandle);\n\n            if (IsDotNet)\n                *IsDotNet = TRUE;\n\n            if (Flags)\n                *Flags = PH_CLR_VERSION_4_ABOVE;\n\n            return STATUS_SUCCESS;\n        }\n\n        // Version 2 section object\n\n        PhInitFormatS(&format[0], L\"\\\\BaseNamedObjects\\\\Cor_Private_IPCBlock_\");\n        sectionName = PhFormat(format, 2, 90);\n        PhStringRefToUnicodeString(&sectionName->sr, &sectionNameUs);\n\n        InitializeObjectAttributes(\n            &objectAttributes,\n            &sectionNameUs,\n            OBJ_CASE_INSENSITIVE,\n            NULL,\n            NULL\n            );\n        status = NtOpenSection(\n            &sectionHandle,\n            SECTION_QUERY,\n            &objectAttributes\n            );\n        PhDereferenceObject(sectionName);\n\n        if (NT_SUCCESS(status) || status == STATUS_ACCESS_DENIED)\n        {\n            if (NT_SUCCESS(status))\n                NtClose(sectionHandle);\n\n            if (IsDotNet)\n                *IsDotNet = TRUE;\n\n            if (Flags)\n                *Flags = PH_CLR_VERSION_2_0;\n\n            return STATUS_SUCCESS;\n        }\n\n        return status;\n    }\n    else\n    {\n        NTSTATUS status;\n        HANDLE processHandle = NULL;\n        ULONG flags = 0;\n#ifdef _WIN64\n        BOOLEAN isWow64;\n#endif\n\n        if (!ProcessHandle)\n        {\n            if (!NT_SUCCESS(status = PhOpenProcess(&processHandle, ProcessQueryAccess | PROCESS_VM_READ, ProcessId)))\n                return status;\n\n            ProcessHandle = processHandle;\n        }\n\n#ifdef _WIN64\n        if (InFlags & PH_CLR_NO_WOW64_CHECK)\n        {\n            isWow64 = !!(InFlags & PH_CLR_KNOWN_IS_WOW64);\n        }\n        else\n        {\n            isWow64 = FALSE;\n            PhGetProcessIsWow64(ProcessHandle, &isWow64);\n        }\n\n        if (isWow64)\n        {\n            flags |= PH_CLR_PROCESS_IS_WOW64;\n            status = PhEnumProcessModules32(ProcessHandle, PhpIsDotNetEnumProcessModulesCallback, &flags);\n        }\n        else\n        {\n#endif\n            status = PhEnumProcessModules(ProcessHandle, PhpIsDotNetEnumProcessModulesCallback, &flags);\n#ifdef _WIN64\n        }\n#endif\n\n        if (processHandle)\n            NtClose(processHandle);\n\n        if (IsDotNet)\n            *IsDotNet = (flags & PH_CLR_VERSION_MASK) && (flags & (PH_CLR_MSCORLIB_PRESENT | PH_CLR_JIT_PRESENT));\n\n        if (Flags)\n            *Flags = flags;\n\n        return status;\n    }\n}\n\n/**\n * Enumerates the objects in a directory object.\n *\n * \\param DirectoryHandle A handle to a directory. The handle must have DIRECTORY_QUERY access.\n * \\param Callback A callback function which is executed for each object.\n * \\param Context A user-defined value to pass to the callback function.\n */\nNTSTATUS PhEnumDirectoryObjects(\n    _In_ HANDLE DirectoryHandle,\n    _In_ PPH_ENUM_DIRECTORY_OBJECTS Callback,\n    _In_opt_ PVOID Context\n    )\n{\n    NTSTATUS status;\n    ULONG context = 0;\n    BOOLEAN firstTime = TRUE;\n    ULONG bufferSize;\n    POBJECT_DIRECTORY_INFORMATION buffer;\n    ULONG i;\n    BOOLEAN cont;\n\n    bufferSize = 0x200;\n    buffer = PhAllocate(bufferSize);\n\n    while (TRUE)\n    {\n        // Get a batch of entries.\n\n        while ((status = NtQueryDirectoryObject(\n            DirectoryHandle,\n            buffer,\n            bufferSize,\n            FALSE,\n            firstTime,\n            &context,\n            NULL\n            )) == STATUS_MORE_ENTRIES)\n        {\n            // Check if we have at least one entry. If not, we'll double the buffer size and try\n            // again.\n            if (buffer[0].Name.Buffer)\n                break;\n\n            // Make sure we don't use too much memory.\n            if (bufferSize > PH_LARGE_BUFFER_SIZE)\n            {\n                PhFree(buffer);\n                return STATUS_INSUFFICIENT_RESOURCES;\n            }\n\n            PhFree(buffer);\n            bufferSize *= 2;\n            buffer = PhAllocate(bufferSize);\n        }\n\n        if (!NT_SUCCESS(status))\n        {\n            PhFree(buffer);\n            return status;\n        }\n\n        // Read the batch and execute the callback function for each object.\n\n        i = 0;\n        cont = TRUE;\n\n        while (TRUE)\n        {\n            POBJECT_DIRECTORY_INFORMATION info;\n            PH_STRINGREF name;\n            PH_STRINGREF typeName;\n\n            info = &buffer[i];\n\n            if (!info->Name.Buffer)\n                break;\n\n            PhUnicodeStringToStringRef(&info->Name, &name);\n            PhUnicodeStringToStringRef(&info->TypeName, &typeName);\n\n            cont = Callback(&name, &typeName, Context);\n\n            if (!cont)\n                break;\n\n            i++;\n        }\n\n        if (!cont)\n            break;\n\n        if (status != STATUS_MORE_ENTRIES)\n            break;\n\n        firstTime = FALSE;\n    }\n\n    PhFree(buffer);\n\n    return STATUS_SUCCESS;\n}\n\nNTSTATUS PhEnumDirectoryFile(\n    _In_ HANDLE FileHandle,\n    _In_opt_ PUNICODE_STRING SearchPattern,\n    _In_ PPH_ENUM_DIRECTORY_FILE Callback,\n    _In_opt_ PVOID Context\n    )\n{\n    NTSTATUS status;\n    IO_STATUS_BLOCK isb;\n    BOOLEAN firstTime = TRUE;\n    PVOID buffer;\n    ULONG bufferSize = 0x400;\n    ULONG i;\n    BOOLEAN cont;\n\n    buffer = PhAllocate(bufferSize);\n\n    while (TRUE)\n    {\n        // Query the directory, doubling the buffer each time NtQueryDirectoryFile fails.\n        while (TRUE)\n        {\n            status = NtQueryDirectoryFile(\n                FileHandle,\n                NULL,\n                NULL,\n                NULL,\n                &isb,\n                buffer,\n                bufferSize,\n                FileDirectoryInformation,\n                FALSE,\n                SearchPattern,\n                firstTime\n                );\n\n            // Our ISB is on the stack, so we have to wait for the operation to complete before\n            // continuing.\n            if (status == STATUS_PENDING)\n            {\n                status = NtWaitForSingleObject(FileHandle, FALSE, NULL);\n\n                if (NT_SUCCESS(status))\n                    status = isb.Status;\n            }\n\n            if (status == STATUS_BUFFER_OVERFLOW || status == STATUS_INFO_LENGTH_MISMATCH)\n            {\n                PhFree(buffer);\n                bufferSize *= 2;\n                buffer = PhAllocate(bufferSize);\n            }\n            else\n            {\n                break;\n            }\n        }\n\n        // If we don't have any entries to read, exit.\n        if (status == STATUS_NO_MORE_FILES)\n        {\n            status = STATUS_SUCCESS;\n            break;\n        }\n\n        if (!NT_SUCCESS(status))\n            break;\n\n        // Read the batch and execute the callback function for each file.\n\n        i = 0;\n        cont = TRUE;\n\n        while (TRUE)\n        {\n            PFILE_DIRECTORY_INFORMATION information;\n\n            information = (PFILE_DIRECTORY_INFORMATION)PTR_ADD_OFFSET(buffer, i);\n\n            if (!Callback(\n                information,\n                Context\n                ))\n            {\n                cont = FALSE;\n                break;\n            }\n\n            if (information->NextEntryOffset != 0)\n                i += information->NextEntryOffset;\n            else\n                break;\n        }\n\n        if (!cont)\n            break;\n\n        firstTime = FALSE;\n    }\n\n    PhFree(buffer);\n\n    return status;\n}\n\nNTSTATUS PhEnumFileStreams(\n    _In_ HANDLE FileHandle,\n    _Out_ PVOID *Streams\n    )\n{\n    return PhpQueryFileVariableSize(\n        FileHandle,\n        FileStreamInformation,\n        Streams\n        );\n}\n\n/**\n * Initializes the device prefixes module.\n */\nVOID PhpInitializeDevicePrefixes(\n    VOID\n    )\n{\n    ULONG i;\n    PUCHAR buffer;\n\n    // Allocate one buffer for all 26 prefixes to reduce overhead.\n    buffer = PhAllocate(PH_DEVICE_PREFIX_LENGTH * sizeof(WCHAR) * 26);\n\n    for (i = 0; i < 26; i++)\n    {\n        PhDevicePrefixes[i].Length = 0;\n        PhDevicePrefixes[i].MaximumLength = PH_DEVICE_PREFIX_LENGTH * sizeof(WCHAR);\n        PhDevicePrefixes[i].Buffer = (PWCHAR)buffer;\n        buffer += PH_DEVICE_PREFIX_LENGTH * sizeof(WCHAR);\n    }\n}\n\nVOID PhUpdateMupDevicePrefixes(\n    VOID\n    )\n{\n    static PH_STRINGREF orderKeyName = PH_STRINGREF_INIT(L\"System\\\\CurrentControlSet\\\\Control\\\\NetworkProvider\\\\Order\");\n    static PH_STRINGREF servicesStringPart = PH_STRINGREF_INIT(L\"System\\\\CurrentControlSet\\\\Services\\\\\");\n    static PH_STRINGREF networkProviderStringPart = PH_STRINGREF_INIT(L\"\\\\NetworkProvider\");\n\n    HANDLE orderKeyHandle;\n    PPH_STRING providerOrder = NULL;\n    ULONG i;\n    PH_STRINGREF remainingPart;\n    PH_STRINGREF part;\n\n    // The provider names are stored in the ProviderOrder value in this key:\n    // HKLM\\System\\CurrentControlSet\\Control\\NetworkProvider\\Order\n    // Each name can then be looked up, its device name in the DeviceName value in:\n    // HKLM\\System\\CurrentControlSet\\Services\\<ProviderName>\\NetworkProvider\n\n    // Note that we assume the providers only claim their device name. Some providers such as DFS\n    // claim an extra part, and are not resolved correctly here.\n\n    if (NT_SUCCESS(PhOpenKey(\n        &orderKeyHandle,\n        KEY_READ,\n        PH_KEY_LOCAL_MACHINE,\n        &orderKeyName,\n        0\n        )))\n    {\n        providerOrder = PhQueryRegistryString(orderKeyHandle, L\"ProviderOrder\");\n        NtClose(orderKeyHandle);\n    }\n\n    if (!providerOrder)\n        return;\n\n    PhAcquireQueuedLockExclusive(&PhDeviceMupPrefixesLock);\n\n    for (i = 0; i < PhDeviceMupPrefixesCount; i++)\n    {\n        PhDereferenceObject(PhDeviceMupPrefixes[i]);\n        PhDeviceMupPrefixes[i] = NULL;\n    }\n\n    PhDeviceMupPrefixesCount = 0;\n\n    PhDeviceMupPrefixes[PhDeviceMupPrefixesCount++] = PhCreateString(L\"\\\\Device\\\\Mup\");\n\n    // DFS claims an extra part of file names, which we don't handle.\n    // PhDeviceMupPrefixes[PhDeviceMupPrefixesCount++] = PhCreateString(L\"\\\\Device\\\\DfsClient\");\n\n    remainingPart = providerOrder->sr;\n\n    while (remainingPart.Length != 0)\n    {\n        PPH_STRING serviceKeyName;\n        HANDLE networkProviderKeyHandle;\n        PPH_STRING deviceName;\n\n        if (PhDeviceMupPrefixesCount == PH_DEVICE_MUP_PREFIX_MAX_COUNT)\n            break;\n\n        PhSplitStringRefAtChar(&remainingPart, ',', &part, &remainingPart);\n\n        if (part.Length != 0)\n        {\n            serviceKeyName = PhConcatStringRef3(&servicesStringPart, &part, &networkProviderStringPart);\n\n            if (NT_SUCCESS(PhOpenKey(\n                &networkProviderKeyHandle,\n                KEY_READ,\n                PH_KEY_LOCAL_MACHINE,\n                &serviceKeyName->sr,\n                0\n                )))\n            {\n                if (deviceName = PhQueryRegistryString(networkProviderKeyHandle, L\"DeviceName\"))\n                {\n                    PhDeviceMupPrefixes[PhDeviceMupPrefixesCount] = deviceName;\n                    PhDeviceMupPrefixesCount++;\n                }\n\n                NtClose(networkProviderKeyHandle);\n            }\n\n            PhDereferenceObject(serviceKeyName);\n        }\n    }\n\n    PhReleaseQueuedLockExclusive(&PhDeviceMupPrefixesLock);\n\n    PhDereferenceObject(providerOrder);\n}\n\n/**\n * Updates the DOS device names array.\n */\nVOID PhUpdateDosDevicePrefixes(\n    VOID\n    )\n{\n    WCHAR deviceNameBuffer[7] = L\"\\\\??\\\\ :\";\n#ifndef _WIN64\n    PROCESS_DEVICEMAP_INFORMATION deviceMapInfo;\n#else\n    PROCESS_DEVICEMAP_INFORMATION_EX deviceMapInfo;\n#endif\n    memset(&deviceMapInfo, 0, sizeof(deviceMapInfo));\n\n    NtQueryInformationProcess(\n        NtCurrentProcess(), \n        ProcessDeviceMap, \n        &deviceMapInfo, \n        sizeof(deviceMapInfo), \n        NULL\n        );\n\n    for (ULONG i = 0; i < 0x1A; i++)\n    {\n        HANDLE linkHandle;\n        OBJECT_ATTRIBUTES oa;\n        UNICODE_STRING deviceName;\n\n        if (deviceMapInfo.Query.DriveMap)\n        {\n            if (!(deviceMapInfo.Query.DriveMap & (0x1 << i)))\n                continue;\n        }\n\n        deviceNameBuffer[4] = (WCHAR)('A' + i);\n        deviceName.Buffer = deviceNameBuffer;\n        deviceName.Length = 6 * sizeof(WCHAR);\n\n        InitializeObjectAttributes(\n            &oa,\n            &deviceName,\n            OBJ_CASE_INSENSITIVE,\n            NULL,\n            NULL\n            );\n\n        if (NT_SUCCESS(NtOpenSymbolicLinkObject(\n            &linkHandle,\n            SYMBOLIC_LINK_QUERY,\n            &oa\n            )))\n        {\n            PhAcquireQueuedLockExclusive(&PhDevicePrefixesLock);\n\n            if (!NT_SUCCESS(NtQuerySymbolicLinkObject(\n                linkHandle,\n                &PhDevicePrefixes[i],\n                NULL\n                )))\n            {\n                PhDevicePrefixes[i].Length = 0;\n            }\n\n            PhReleaseQueuedLockExclusive(&PhDevicePrefixesLock);\n\n            NtClose(linkHandle);\n        }\n        else\n        {\n            PhDevicePrefixes[i].Length = 0;\n        }\n    }\n}\n\n/**\n * Resolves a NT path into a Win32 path.\n *\n * \\param Name A string containing the path to resolve.\n *\n * \\return A pointer to a string containing the Win32 path. You must free the string using\n * PhDereferenceObject() when you no longer need it.\n */\nPPH_STRING PhResolveDevicePrefix(\n    _In_ PPH_STRING Name\n    )\n{\n    ULONG i;\n    PPH_STRING newName = NULL;\n\n    if (PhBeginInitOnce(&PhDevicePrefixesInitOnce))\n    {\n        PhpInitializeDevicePrefixes();\n        PhUpdateDosDevicePrefixes();\n        PhUpdateMupDevicePrefixes();\n\n        PhEndInitOnce(&PhDevicePrefixesInitOnce);\n    }\n\n    // Go through the DOS devices and try to find a matching prefix.\n    for (i = 0; i < 26; i++)\n    {\n        BOOLEAN isPrefix = FALSE;\n        PH_STRINGREF prefix;\n\n        PhAcquireQueuedLockShared(&PhDevicePrefixesLock);\n\n        PhUnicodeStringToStringRef(&PhDevicePrefixes[i], &prefix);\n\n        if (prefix.Length != 0)\n        {\n            if (PhStartsWithStringRef(&Name->sr, &prefix, TRUE))\n            {\n                // To ensure we match the longest prefix, make sure the next character is a\n                // backslash or the path is equal to the prefix.\n                if (Name->Length == prefix.Length || Name->Buffer[prefix.Length / sizeof(WCHAR)] == '\\\\')\n                {\n                    isPrefix = TRUE;\n                }\n            }\n        }\n\n        PhReleaseQueuedLockShared(&PhDevicePrefixesLock);\n\n        if (isPrefix)\n        {\n            // <letter>:path\n            newName = PhCreateStringEx(NULL, 2 * sizeof(WCHAR) + Name->Length - prefix.Length);\n            newName->Buffer[0] = (WCHAR)('A' + i);\n            newName->Buffer[1] = ':';\n            memcpy(\n                &newName->Buffer[2],\n                &Name->Buffer[prefix.Length / sizeof(WCHAR)],\n                Name->Length - prefix.Length\n                );\n\n            break;\n        }\n    }\n\n    if (i == 26)\n    {\n        // Resolve network providers.\n\n        PhAcquireQueuedLockShared(&PhDeviceMupPrefixesLock);\n\n        for (i = 0; i < PhDeviceMupPrefixesCount; i++)\n        {\n            BOOLEAN isPrefix = FALSE;\n            SIZE_T prefixLength;\n\n            prefixLength = PhDeviceMupPrefixes[i]->Length;\n\n            if (prefixLength != 0)\n            {\n                if (PhStartsWithString(Name, PhDeviceMupPrefixes[i], TRUE))\n                {\n                    // To ensure we match the longest prefix, make sure the next character is a\n                    // backslash. Don't resolve if the name *is* the prefix. Otherwise, we will end\n                    // up with a useless string like \"\\\".\n                    if (Name->Length != prefixLength && Name->Buffer[prefixLength / sizeof(WCHAR)] == '\\\\')\n                    {\n                        isPrefix = TRUE;\n                    }\n                }\n            }\n\n            if (isPrefix)\n            {\n                // \\path\n                newName = PhCreateStringEx(NULL, 1 * sizeof(WCHAR) + Name->Length - prefixLength);\n                newName->Buffer[0] = '\\\\';\n                memcpy(\n                    &newName->Buffer[1],\n                    &Name->Buffer[prefixLength / sizeof(WCHAR)],\n                    Name->Length - prefixLength\n                    );\n\n                break;\n            }\n        }\n\n        PhReleaseQueuedLockShared(&PhDeviceMupPrefixesLock);\n    }\n\n    if (newName)\n        PhTrimToNullTerminatorString(newName);\n\n    return newName;\n}\n\n/**\n * Converts a file name into Win32 format.\n *\n * \\param FileName A string containing a file name.\n *\n * \\return A pointer to a string containing the Win32 file name. You must free the string using\n * PhDereferenceObject() when you no longer need it.\n *\n * \\remarks This function may convert NT object name paths to invalid ones. If the path to be\n * converted is not necessarily a file name, use PhResolveDevicePrefix().\n */\nPPH_STRING PhGetFileName(\n    _In_ PPH_STRING FileName\n    )\n{\n    PPH_STRING newFileName;\n\n    newFileName = FileName;\n\n    // \"\\??\\\" refers to \\GLOBAL??\\. Just remove it.\n    if (PhStartsWithString2(FileName, L\"\\\\??\\\\\", FALSE))\n    {\n        newFileName = PhCreateStringEx(NULL, FileName->Length - 4 * 2);\n        memcpy(newFileName->Buffer, &FileName->Buffer[4], FileName->Length - 4 * 2);\n    }\n    // \"\\SystemRoot\" means \"C:\\Windows\".\n    else if (PhStartsWithString2(FileName, L\"\\\\SystemRoot\", TRUE))\n    {\n        PH_STRINGREF systemRoot;\n\n        PhGetSystemRoot(&systemRoot);\n        newFileName = PhCreateStringEx(NULL, systemRoot.Length + FileName->Length - 11 * 2);\n        memcpy(newFileName->Buffer, systemRoot.Buffer, systemRoot.Length);\n        memcpy(PTR_ADD_OFFSET(newFileName->Buffer, systemRoot.Length), &FileName->Buffer[11], FileName->Length - 11 * 2);\n    }\n    // \"system32\\\" means \"C:\\Windows\\system32\\\".\n    else if (PhStartsWithString2(FileName, L\"system32\\\\\", TRUE))\n    {\n        PH_STRINGREF systemRoot;\n\n        PhGetSystemRoot(&systemRoot);\n        newFileName = PhCreateStringEx(NULL, systemRoot.Length + 2 + FileName->Length);\n        memcpy(newFileName->Buffer, systemRoot.Buffer, systemRoot.Length);\n        newFileName->Buffer[systemRoot.Length / 2] = '\\\\';\n        memcpy(PTR_ADD_OFFSET(newFileName->Buffer, systemRoot.Length + 2), FileName->Buffer, FileName->Length);\n    }\n    else if (FileName->Length != 0 && FileName->Buffer[0] == '\\\\')\n    {\n        PPH_STRING resolvedName;\n\n        resolvedName = PhResolveDevicePrefix(FileName);\n\n        if (resolvedName)\n        {\n            newFileName = resolvedName;\n        }\n        else\n        {\n            // We didn't find a match.\n            // If the file name starts with \"\\Windows\", prepend the system drive.\n            if (PhStartsWithString2(newFileName, L\"\\\\Windows\", TRUE))\n            {\n                newFileName = PhCreateStringEx(NULL, FileName->Length + 2 * 2);\n                newFileName->Buffer[0] = USER_SHARED_DATA->NtSystemRoot[0];\n                newFileName->Buffer[1] = ':';\n                memcpy(&newFileName->Buffer[2], FileName->Buffer, FileName->Length);\n            }\n            else\n            {\n                PhReferenceObject(newFileName);\n            }\n        }\n    }\n    else\n    {\n        // Just return the supplied file name. Note that we need to add a reference.\n        PhReferenceObject(newFileName);\n    }\n\n    return newFileName;\n}\n\ntypedef struct _ENUM_GENERIC_PROCESS_MODULES_CONTEXT\n{\n    PPH_ENUM_GENERIC_MODULES_CALLBACK Callback;\n    PVOID Context;\n    ULONG Type;\n    PPH_HASHTABLE BaseAddressHashtable;\n\n    ULONG LoadOrderIndex;\n} ENUM_GENERIC_PROCESS_MODULES_CONTEXT, *PENUM_GENERIC_PROCESS_MODULES_CONTEXT;\n\nstatic BOOLEAN EnumGenericProcessModulesCallback(\n    _In_ PLDR_DATA_TABLE_ENTRY Module,\n    _In_opt_ PVOID Context\n    )\n{\n    PENUM_GENERIC_PROCESS_MODULES_CONTEXT context;\n    PH_MODULE_INFO moduleInfo;\n    PPH_STRING fileName;\n    BOOLEAN cont;\n\n    context = (PENUM_GENERIC_PROCESS_MODULES_CONTEXT)Context;\n\n    // Check if we have a duplicate base address.\n    if (PhFindEntryHashtable(context->BaseAddressHashtable, &Module->DllBase))\n    {\n        return TRUE;\n    }\n    else\n    {\n        PhAddEntryHashtable(context->BaseAddressHashtable, &Module->DllBase);\n    }\n\n    fileName = PhCreateStringFromUnicodeString(&Module->FullDllName);\n\n    moduleInfo.Type = context->Type;\n    moduleInfo.BaseAddress = Module->DllBase;\n    moduleInfo.Size = Module->SizeOfImage;\n    moduleInfo.EntryPoint = Module->EntryPoint;\n    moduleInfo.Flags = Module->Flags;\n    moduleInfo.Name = PhCreateStringFromUnicodeString(&Module->BaseDllName);\n    moduleInfo.FileName = PhGetFileName(fileName);\n    moduleInfo.OriginalFileName = fileName;\n    moduleInfo.LoadOrderIndex = (USHORT)(context->LoadOrderIndex++);\n    moduleInfo.LoadCount = Module->ObsoleteLoadCount;\n\n    if (WindowsVersion >= WINDOWS_8)\n    {\n        moduleInfo.LoadReason = (USHORT)Module->LoadReason;\n        moduleInfo.LoadTime = Module->LoadTime;\n    }\n    else\n    {\n        moduleInfo.LoadReason = -1;\n        moduleInfo.LoadTime.QuadPart = 0;\n    }\n\n    cont = context->Callback(&moduleInfo, context->Context);\n\n    PhDereferenceObject(moduleInfo.Name);\n    PhDereferenceObject(moduleInfo.FileName);\n    PhDereferenceObject(moduleInfo.OriginalFileName);\n\n    return cont;\n}\n\nVOID PhpRtlModulesToGenericModules(\n    _In_ PRTL_PROCESS_MODULES Modules,\n    _In_ PPH_ENUM_GENERIC_MODULES_CALLBACK Callback,\n    _In_opt_ PVOID Context,\n    _In_ PPH_HASHTABLE BaseAddressHashtable\n    )\n{\n    PRTL_PROCESS_MODULE_INFORMATION module;\n    ULONG i;\n    PH_MODULE_INFO moduleInfo;\n    BOOLEAN cont;\n\n    for (i = 0; i < Modules->NumberOfModules; i++)\n    {\n        PPH_STRING fileName;\n\n        module = &Modules->Modules[i];\n\n        // Check if we have a duplicate base address.\n        if (PhFindEntryHashtable(BaseAddressHashtable, &module->ImageBase))\n        {\n            continue;\n        }\n        else\n        {\n            PhAddEntryHashtable(BaseAddressHashtable, &module->ImageBase);\n        }\n\n        fileName = PhConvertMultiByteToUtf16(module->FullPathName);\n\n        if ((ULONG_PTR)module->ImageBase <= PhSystemBasicInformation.MaximumUserModeAddress)\n            moduleInfo.Type = PH_MODULE_TYPE_MODULE;\n        else\n            moduleInfo.Type = PH_MODULE_TYPE_KERNEL_MODULE;\n\n        moduleInfo.BaseAddress = module->ImageBase;\n        moduleInfo.Size = module->ImageSize;\n        moduleInfo.EntryPoint = NULL;\n        moduleInfo.Flags = module->Flags;\n        moduleInfo.Name = PhConvertMultiByteToUtf16(&module->FullPathName[module->OffsetToFileName]);\n        moduleInfo.FileName = PhGetFileName(fileName); // convert to DOS file name\n        moduleInfo.OriginalFileName = fileName;\n        moduleInfo.LoadOrderIndex = module->LoadOrderIndex;\n        moduleInfo.LoadCount = module->LoadCount;\n        moduleInfo.LoadReason = -1;\n        moduleInfo.LoadTime.QuadPart = 0;\n\n        if (module->OffsetToFileName == 0)\n        {\n            static PH_STRINGREF driversString = PH_STRINGREF_INIT(L\"\\\\System32\\\\Drivers\\\\\");\n            PH_STRINGREF systemRoot;\n            PPH_STRING newFileName;\n\n            // We only have the file name, without a path. The driver must be in the default drivers\n            // directory.\n            PhGetSystemRoot(&systemRoot);\n            newFileName = PhConcatStringRef3(&systemRoot, &driversString, &moduleInfo.Name->sr);\n            PhDereferenceObject(moduleInfo.FileName);\n            moduleInfo.FileName = newFileName;\n        }\n\n        cont = Callback(&moduleInfo, Context);\n\n        PhDereferenceObject(moduleInfo.Name);\n        PhDereferenceObject(moduleInfo.FileName);\n        PhDereferenceObject(moduleInfo.OriginalFileName);\n\n        if (!cont)\n            break;\n    }\n}\n\nVOID PhpRtlModulesExToGenericModules(\n    _In_ PRTL_PROCESS_MODULE_INFORMATION_EX Modules,\n    _In_ PPH_ENUM_GENERIC_MODULES_CALLBACK Callback,\n    _In_opt_ PVOID Context,\n    _In_ PPH_HASHTABLE BaseAddressHashtable\n    )\n{\n    PRTL_PROCESS_MODULE_INFORMATION_EX module;\n    PH_MODULE_INFO moduleInfo;\n    BOOLEAN cont;\n\n    module = Modules;\n\n    while (module->NextOffset != 0)\n    {\n        PPH_STRING fileName;\n\n        // Check if we have a duplicate base address.\n        if (PhFindEntryHashtable(BaseAddressHashtable, &module->BaseInfo.ImageBase))\n        {\n            continue;\n        }\n        else\n        {\n            PhAddEntryHashtable(BaseAddressHashtable, &module->BaseInfo.ImageBase);\n        }\n\n        fileName = PhConvertMultiByteToUtf16(module->BaseInfo.FullPathName);\n\n        if ((ULONG_PTR)module->BaseInfo.ImageBase <= PhSystemBasicInformation.MaximumUserModeAddress)\n            moduleInfo.Type = PH_MODULE_TYPE_MODULE;\n        else\n            moduleInfo.Type = PH_MODULE_TYPE_KERNEL_MODULE;\n\n        moduleInfo.BaseAddress = module->BaseInfo.ImageBase;\n        moduleInfo.Size = module->BaseInfo.ImageSize;\n        moduleInfo.EntryPoint = NULL;\n        moduleInfo.Flags = module->BaseInfo.Flags;\n        moduleInfo.Name = PhConvertMultiByteToUtf16(&module->BaseInfo.FullPathName[module->BaseInfo.OffsetToFileName]);\n        moduleInfo.FileName = PhGetFileName(fileName); // convert to DOS file name\n        moduleInfo.LoadOrderIndex = module->BaseInfo.LoadOrderIndex;\n        moduleInfo.LoadCount = module->BaseInfo.LoadCount;\n        moduleInfo.LoadReason = -1;\n        moduleInfo.LoadTime.QuadPart = 0;\n\n        PhDereferenceObject(fileName);\n\n        cont = Callback(&moduleInfo, Context);\n\n        PhDereferenceObject(moduleInfo.Name);\n        PhDereferenceObject(moduleInfo.FileName);\n\n        if (!cont)\n            break;\n\n        module = PTR_ADD_OFFSET(module, module->NextOffset);\n    }\n}\n\nBOOLEAN PhpCallbackMappedFileOrImage(\n    _In_ PVOID AllocationBase,\n    _In_ SIZE_T AllocationSize,\n    _In_ ULONG Type,\n    _In_ PPH_STRING FileName,\n    _In_ PPH_ENUM_GENERIC_MODULES_CALLBACK Callback,\n    _In_opt_ PVOID Context,\n    _In_ PPH_HASHTABLE BaseAddressHashtable\n    )\n{\n    PH_MODULE_INFO moduleInfo;\n    BOOLEAN cont;\n\n    moduleInfo.Type = Type;\n    moduleInfo.BaseAddress = AllocationBase;\n    moduleInfo.Size = (ULONG)AllocationSize;\n    moduleInfo.EntryPoint = NULL;\n    moduleInfo.Flags = 0;\n    moduleInfo.FileName = PhGetFileName(FileName);\n    moduleInfo.OriginalFileName = FileName;\n    moduleInfo.Name = PhGetBaseName(moduleInfo.FileName);\n    moduleInfo.LoadOrderIndex = -1;\n    moduleInfo.LoadCount = -1;\n    moduleInfo.LoadReason = -1;\n    moduleInfo.LoadTime.QuadPart = 0;\n\n    cont = Callback(&moduleInfo, Context);\n\n    PhDereferenceObject(moduleInfo.FileName);\n    PhDereferenceObject(moduleInfo.OriginalFileName);\n    PhDereferenceObject(moduleInfo.Name);\n\n    return cont;\n}\n\nVOID PhpEnumGenericMappedFilesAndImages(\n    _In_ HANDLE ProcessHandle,\n    _In_ ULONG Flags,\n    _In_ PPH_ENUM_GENERIC_MODULES_CALLBACK Callback,\n    _In_opt_ PVOID Context,\n    _In_ PPH_HASHTABLE BaseAddressHashtable\n    )\n{\n    BOOLEAN querySucceeded;\n    PVOID baseAddress;\n    MEMORY_BASIC_INFORMATION basicInfo;\n\n    baseAddress = (PVOID)0;\n\n    if (!NT_SUCCESS(NtQueryVirtualMemory(\n        ProcessHandle,\n        baseAddress,\n        MemoryBasicInformation,\n        &basicInfo,\n        sizeof(MEMORY_BASIC_INFORMATION),\n        NULL\n        )))\n    {\n        return;\n    }\n\n    querySucceeded = TRUE;\n\n    while (querySucceeded)\n    {\n        PVOID allocationBase;\n        SIZE_T allocationSize;\n        ULONG type;\n        PPH_STRING fileName;\n        BOOLEAN cont;\n\n        if (basicInfo.Type == MEM_MAPPED || basicInfo.Type == MEM_IMAGE)\n        {\n            if (basicInfo.Type == MEM_MAPPED)\n                type = PH_MODULE_TYPE_MAPPED_FILE;\n            else\n                type = PH_MODULE_TYPE_MAPPED_IMAGE;\n\n            // Find the total allocation size.\n\n            allocationBase = basicInfo.AllocationBase;\n            allocationSize = 0;\n\n            do\n            {\n                baseAddress = PTR_ADD_OFFSET(baseAddress, basicInfo.RegionSize);\n                allocationSize += basicInfo.RegionSize;\n\n                if (!NT_SUCCESS(NtQueryVirtualMemory(\n                    ProcessHandle,\n                    baseAddress,\n                    MemoryBasicInformation,\n                    &basicInfo,\n                    sizeof(MEMORY_BASIC_INFORMATION),\n                    NULL\n                    )))\n                {\n                    querySucceeded = FALSE;\n                    break;\n                }\n            } while (basicInfo.AllocationBase == allocationBase);\n\n            if ((type == PH_MODULE_TYPE_MAPPED_FILE && !(Flags & PH_ENUM_GENERIC_MAPPED_FILES)) ||\n                (type == PH_MODULE_TYPE_MAPPED_IMAGE && !(Flags & PH_ENUM_GENERIC_MAPPED_IMAGES)))\n            {\n                // The user doesn't want this type of entry.\n                continue;\n            }\n\n            // Check if we have a duplicate base address.\n            if (PhFindEntryHashtable(BaseAddressHashtable, &allocationBase))\n            {\n                continue;\n            }\n\n            if (!NT_SUCCESS(PhGetProcessMappedFileName(\n                ProcessHandle,\n                allocationBase,\n                &fileName\n                )))\n            {\n                continue;\n            }\n\n            PhAddEntryHashtable(BaseAddressHashtable, &allocationBase);\n\n            cont = PhpCallbackMappedFileOrImage(\n                allocationBase,\n                allocationSize,\n                type,\n                fileName,\n                Callback,\n                Context,\n                BaseAddressHashtable\n                );\n\n            if (!cont)\n                break;\n        }\n        else\n        {\n            baseAddress = PTR_ADD_OFFSET(baseAddress, basicInfo.RegionSize);\n\n            if (!NT_SUCCESS(NtQueryVirtualMemory(\n                ProcessHandle,\n                baseAddress,\n                MemoryBasicInformation,\n                &basicInfo,\n                sizeof(MEMORY_BASIC_INFORMATION),\n                NULL\n                )))\n            {\n                querySucceeded = FALSE;\n            }\n        }\n    }\n}\n\nBOOLEAN NTAPI PhpBaseAddressHashtableEqualFunction(\n    _In_ PVOID Entry1,\n    _In_ PVOID Entry2\n    )\n{\n    return *(PVOID *)Entry1 == *(PVOID *)Entry2;\n}\n\nULONG NTAPI PhpBaseAddressHashtableHashFunction(\n    _In_ PVOID Entry\n    )\n{\n    return PhHashIntPtr((ULONG_PTR)*(PVOID *)Entry);\n}\n\n/**\n * Enumerates the modules loaded by a process.\n *\n * \\param ProcessId The ID of a process. If \\ref SYSTEM_PROCESS_ID is specified the function\n * enumerates the kernel modules.\n * \\param ProcessHandle A handle to the process.\n * \\param Flags Flags controlling the information to retrieve.\n * \\li \\c PH_ENUM_GENERIC_MAPPED_FILES Enumerate mapped files.\n * \\li \\c PH_ENUM_GENERIC_MAPPED_IMAGES Enumerate mapped images (those which are not mapped by the\n * loader).\n * \\param Callback A callback function which is executed for each module.\n * \\param Context A user-defined value to pass to the callback function.\n */\nNTSTATUS PhEnumGenericModules(\n    _In_ HANDLE ProcessId,\n    _In_opt_ HANDLE ProcessHandle,\n    _In_ ULONG Flags,\n    _In_ PPH_ENUM_GENERIC_MODULES_CALLBACK Callback,\n    _In_opt_ PVOID Context\n    )\n{\n    NTSTATUS status;\n    PPH_HASHTABLE baseAddressHashtable;\n\n    baseAddressHashtable = PhCreateHashtable(\n        sizeof(PVOID),\n        PhpBaseAddressHashtableEqualFunction,\n        PhpBaseAddressHashtableHashFunction,\n        32\n        );\n\n    if (ProcessId == SYSTEM_PROCESS_ID)\n    {\n        // Kernel modules\n\n        PVOID modules;\n\n        if (NT_SUCCESS(status = PhEnumKernelModules((PRTL_PROCESS_MODULES *)&modules)))\n        {\n            PhpRtlModulesToGenericModules(\n                modules,\n                Callback,\n                Context,\n                baseAddressHashtable\n                );\n            PhFree(modules);\n        }\n    }\n    else\n    {\n        // Process modules\n\n        BOOLEAN opened = FALSE;\n#ifdef _WIN64\n        BOOLEAN isWow64 = FALSE;\n#endif\n        ENUM_GENERIC_PROCESS_MODULES_CONTEXT context;\n        PH_ENUM_PROCESS_MODULES_PARAMETERS parameters;\n\n        if (!ProcessHandle)\n        {\n            if (!NT_SUCCESS(status = PhOpenProcess(\n                &ProcessHandle,\n                PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, // needed for enumerating mapped files\n                ProcessId\n                )))\n            {\n                if (!NT_SUCCESS(status = PhOpenProcess(\n                    &ProcessHandle,\n                    ProcessQueryAccess | PROCESS_VM_READ,\n                    ProcessId\n                    )))\n                {\n                    goto CleanupExit;\n                }\n            }\n\n            opened = TRUE;\n        }\n\n        context.Callback = Callback;\n        context.Context = Context;\n        context.Type = PH_MODULE_TYPE_MODULE;\n        context.BaseAddressHashtable = baseAddressHashtable;\n        context.LoadOrderIndex = 0;\n\n        parameters.Callback = EnumGenericProcessModulesCallback;\n        parameters.Context = &context;\n        parameters.Flags = PH_ENUM_PROCESS_MODULES_TRY_MAPPED_FILE_NAME;\n\n        status = PhEnumProcessModulesEx(\n            ProcessHandle,\n            &parameters\n            );\n\n#ifdef _WIN64\n        PhGetProcessIsWow64(ProcessHandle, &isWow64);\n\n        // 32-bit process modules\n        if (isWow64)\n        {\n            context.Callback = Callback;\n            context.Context = Context;\n            context.Type = PH_MODULE_TYPE_WOW64_MODULE;\n            context.BaseAddressHashtable = baseAddressHashtable;\n            context.LoadOrderIndex = 0;\n\n            status = PhEnumProcessModules32Ex(\n                ProcessHandle,\n                &parameters\n                );\n        }\n#endif\n\n        // Mapped files and mapped images\n        // This is done last because it provides the least amount of information.\n\n        if (Flags & (PH_ENUM_GENERIC_MAPPED_FILES | PH_ENUM_GENERIC_MAPPED_IMAGES))\n        {\n            PhpEnumGenericMappedFilesAndImages(\n                ProcessHandle,\n                Flags,\n                Callback,\n                Context,\n                baseAddressHashtable\n                );\n        }\n\n        if (opened)\n            NtClose(ProcessHandle);\n    }\n\nCleanupExit:\n    PhDereferenceObject(baseAddressHashtable);\n\n    return status;\n}\n\n/**\n * Initializes usage of predefined keys.\n */\nVOID PhpInitializePredefineKeys(\n    VOID\n    )\n{\n    static UNICODE_STRING currentUserPrefix = RTL_CONSTANT_STRING(L\"\\\\Registry\\\\User\\\\\");\n\n    NTSTATUS status;\n    HANDLE tokenHandle;\n    PTOKEN_USER tokenUser;\n    UNICODE_STRING stringSid;\n    WCHAR stringSidBuffer[SECURITY_MAX_SID_STRING_CHARACTERS];\n    PUNICODE_STRING currentUserKeyName;\n\n    // Get the string SID of the current user.\n    if (NT_SUCCESS(status = NtOpenProcessToken(NtCurrentProcess(), TOKEN_QUERY, &tokenHandle)))\n    {\n        if (NT_SUCCESS(status = PhGetTokenUser(tokenHandle, &tokenUser)))\n        {\n            stringSid.Buffer = stringSidBuffer;\n            stringSid.MaximumLength = sizeof(stringSidBuffer);\n\n            status = RtlConvertSidToUnicodeString(\n                &stringSid,\n                tokenUser->User.Sid,\n                FALSE\n                );\n\n            PhFree(tokenUser);\n        }\n\n        NtClose(tokenHandle);\n    }\n\n    // Construct the current user key name.\n    if (NT_SUCCESS(status))\n    {\n        currentUserKeyName = &PhPredefineKeyNames[PH_KEY_CURRENT_USER_NUMBER];\n        currentUserKeyName->Length = currentUserPrefix.Length + stringSid.Length;\n        currentUserKeyName->Buffer = PhAllocate(currentUserKeyName->Length + sizeof(WCHAR));\n        memcpy(currentUserKeyName->Buffer, currentUserPrefix.Buffer, currentUserPrefix.Length);\n        memcpy(&currentUserKeyName->Buffer[currentUserPrefix.Length / sizeof(WCHAR)], stringSid.Buffer, stringSid.Length);\n    }\n}\n\n/**\n * Initializes the attributes of a key object for creating/opening.\n *\n * \\param RootDirectory A handle to a root key, or one of the predefined keys. See PhCreateKey() for\n * details.\n * \\param ObjectName The path to the key.\n * \\param Attributes Additional object flags.\n * \\param ObjectAttributes The OBJECT_ATTRIBUTES structure to initialize.\n * \\param NeedsClose A variable which receives a handle that must be closed when the create/open\n * operation is finished. The variable may be set to NULL if no handle needs to be closed.\n */\nNTSTATUS PhpInitializeKeyObjectAttributes(\n    _In_opt_ HANDLE RootDirectory,\n    _In_ PUNICODE_STRING ObjectName,\n    _In_ ULONG Attributes,\n    _Out_ POBJECT_ATTRIBUTES ObjectAttributes,\n    _Out_ PHANDLE NeedsClose\n    )\n{\n    NTSTATUS status;\n    ULONG predefineIndex;\n    HANDLE predefineHandle;\n    OBJECT_ATTRIBUTES predefineObjectAttributes;\n\n    InitializeObjectAttributes(\n        ObjectAttributes,\n        ObjectName,\n        Attributes | OBJ_CASE_INSENSITIVE,\n        RootDirectory,\n        NULL\n        );\n\n    *NeedsClose = NULL;\n\n    if (RootDirectory && PH_KEY_IS_PREDEFINED(RootDirectory))\n    {\n        predefineIndex = PH_KEY_PREDEFINE_TO_NUMBER(RootDirectory);\n\n        if (predefineIndex < PH_KEY_MAXIMUM_PREDEFINE)\n        {\n            if (PhBeginInitOnce(&PhPredefineKeyInitOnce))\n            {\n                PhpInitializePredefineKeys();\n                PhEndInitOnce(&PhPredefineKeyInitOnce);\n            }\n\n            predefineHandle = PhPredefineKeyHandles[predefineIndex];\n\n            if (!predefineHandle)\n            {\n                // The predefined key has not been opened yet. Do so now.\n\n                if (!PhPredefineKeyNames[predefineIndex].Buffer) // we may have failed in getting the current user key name\n                    return STATUS_UNSUCCESSFUL;\n\n                InitializeObjectAttributes(\n                    &predefineObjectAttributes,\n                    &PhPredefineKeyNames[predefineIndex],\n                    OBJ_CASE_INSENSITIVE,\n                    NULL,\n                    NULL\n                    );\n\n                status = NtOpenKey(\n                    &predefineHandle,\n                    KEY_READ,\n                    &predefineObjectAttributes\n                    );\n\n                if (!NT_SUCCESS(status))\n                    return status;\n\n                if (_InterlockedCompareExchangePointer(\n                    &PhPredefineKeyHandles[predefineIndex],\n                    predefineHandle,\n                    NULL\n                    ) != NULL)\n                {\n                    // Someone else already opened the key and cached it. Indicate that the caller\n                    // needs to close the handle later, since it isn't shared.\n                    *NeedsClose = predefineHandle;\n                }\n            }\n\n            ObjectAttributes->RootDirectory = predefineHandle;\n        }\n    }\n\n    return STATUS_SUCCESS;\n}\n\n/**\n * Creates or opens a registry key.\n *\n * \\param KeyHandle A variable which receives a handle to the key.\n * \\param DesiredAccess The desired access to the key.\n * \\param RootDirectory A handle to a root key, or one of the following predefined keys:\n * \\li \\c PH_KEY_LOCAL_MACHINE Represents \\\\Registry\\\\Machine.\n * \\li \\c PH_KEY_USERS Represents \\\\Registry\\\\User.\n * \\li \\c PH_KEY_CLASSES_ROOT Represents \\\\Registry\\\\Machine\\\\Software\\\\Classes.\n * \\li \\c PH_KEY_CURRENT_USER Represents \\\\Registry\\\\User\\\\[SID of current user].\n * \\param ObjectName The path to the key.\n * \\param Attributes Additional object flags.\n * \\param CreateOptions The options to apply when creating or opening the key.\n * \\param Disposition A variable which receives a value indicating whether a new key was created or\n * an existing key was opened:\n * \\li \\c REG_CREATED_NEW_KEY A new key was created.\n * \\li \\c REG_OPENED_EXISTING_KEY An existing key was opened.\n */\nNTSTATUS PhCreateKey(\n    _Out_ PHANDLE KeyHandle,\n    _In_ ACCESS_MASK DesiredAccess,\n    _In_opt_ HANDLE RootDirectory,\n    _In_ PPH_STRINGREF ObjectName,\n    _In_ ULONG Attributes,\n    _In_ ULONG CreateOptions,\n    _Out_opt_ PULONG Disposition\n    )\n{\n    NTSTATUS status;\n    UNICODE_STRING objectName;\n    OBJECT_ATTRIBUTES objectAttributes;\n    HANDLE needsClose;\n\n    if (!PhStringRefToUnicodeString(ObjectName, &objectName))\n        return STATUS_NAME_TOO_LONG;\n\n    if (!NT_SUCCESS(status = PhpInitializeKeyObjectAttributes(\n        RootDirectory,\n        &objectName,\n        Attributes,\n        &objectAttributes,\n        &needsClose\n        )))\n    {\n        return status;\n    }\n\n    status = NtCreateKey(\n        KeyHandle,\n        DesiredAccess,\n        &objectAttributes,\n        0,\n        NULL,\n        CreateOptions,\n        Disposition\n        );\n\n    if (needsClose)\n        NtClose(needsClose);\n\n    return status;\n}\n\n/**\n * Opens a registry key.\n *\n * \\param KeyHandle A variable which receives a handle to the key.\n * \\param DesiredAccess The desired access to the key.\n * \\param RootDirectory A handle to a root key, or one of the predefined keys. See PhCreateKey() for\n * details.\n * \\param ObjectName The path to the key.\n * \\param Attributes Additional object flags.\n */\nNTSTATUS PhOpenKey(\n    _Out_ PHANDLE KeyHandle,\n    _In_ ACCESS_MASK DesiredAccess,\n    _In_opt_ HANDLE RootDirectory,\n    _In_ PPH_STRINGREF ObjectName,\n    _In_ ULONG Attributes\n    )\n{\n    NTSTATUS status;\n    UNICODE_STRING objectName;\n    OBJECT_ATTRIBUTES objectAttributes;\n    HANDLE needsClose;\n\n    if (!PhStringRefToUnicodeString(ObjectName, &objectName))\n        return STATUS_NAME_TOO_LONG;\n\n    if (!NT_SUCCESS(status = PhpInitializeKeyObjectAttributes(\n        RootDirectory,\n        &objectName,\n        Attributes,\n        &objectAttributes,\n        &needsClose\n        )))\n    {\n        return status;\n    }\n\n    status = NtOpenKey(\n        KeyHandle,\n        DesiredAccess,\n        &objectAttributes\n        );\n\n    if (needsClose)\n        NtClose(needsClose);\n\n    return status;\n}\n\n// rev from RegLoadAppKey\n/**\n * Loads the specified registry hive file into a private application hive.\n *\n * \\param KeyHandle A variable which receives a handle to the key.\n * \\param FileName The Win32 file name.\n * \\param DesiredAccess The desired access to the key.\n * \\param Flags Optional flags for loading the hive.\n */\nNTSTATUS PhLoadAppKey(\n    _Out_ PHANDLE KeyHandle,\n    _In_ PWSTR FileName,\n    _In_ ACCESS_MASK DesiredAccess,\n    _In_opt_ ULONG Flags\n    )\n{\n    NTSTATUS status;\n    GUID guid;\n    UNICODE_STRING fileName;\n    UNICODE_STRING objectName; \n    UNICODE_STRING guidStringUs;\n    OBJECT_ATTRIBUTES targetAttributes;\n    OBJECT_ATTRIBUTES sourceAttributes;\n    WCHAR objectNameBuffer[MAX_PATH];\n\n    RtlInitEmptyUnicodeString(&objectName, objectNameBuffer, sizeof(objectNameBuffer));\n\n    PhGenerateGuid(&guid);\n\n    if (!NT_SUCCESS(status = RtlStringFromGUID(&guid, &guidStringUs)))\n        return status;\n\n    if (!NT_SUCCESS(status = RtlAppendUnicodeToString(&objectName, L\"\\\\REGISTRY\\\\A\\\\\")))\n        goto CleanupExit;\n\n    if (!NT_SUCCESS(status = RtlAppendUnicodeStringToString(&objectName, &guidStringUs)))\n        goto CleanupExit;\n\n    if (!NT_SUCCESS(status = RtlDosPathNameToNtPathName_U_WithStatus(\n        FileName,\n        &fileName,\n        NULL,\n        NULL\n        )))\n    {\n        goto CleanupExit;\n    }\n\n    InitializeObjectAttributes(\n        &targetAttributes,\n        &objectName,\n        OBJ_CASE_INSENSITIVE,\n        NULL,\n        NULL\n        );\n\n    InitializeObjectAttributes(\n        &sourceAttributes,\n        &fileName,\n        OBJ_CASE_INSENSITIVE,\n        NULL,\n        NULL\n        );\n\n    status = NtLoadKeyEx(\n        &targetAttributes,\n        &sourceAttributes,\n        REG_APP_HIVE | Flags,\n        NULL,\n        NULL,\n        DesiredAccess,\n        KeyHandle,\n        NULL\n        );\n\n    RtlFreeUnicodeString(&fileName);\n\nCleanupExit:\n    RtlFreeUnicodeString(&guidStringUs);\n\n    return status;\n}\n\n/**\n * Gets information about a registry key.\n *\n * \\param KeyHandle A handle to the key.\n * \\param KeyInformationClass The information class to query.\n * \\param Buffer A variable which receives a pointer to a buffer containing information about the\n * registry key. You must free the buffer with PhFree() when you no longer need it.\n */\nNTSTATUS PhQueryKey(\n    _In_ HANDLE KeyHandle,\n    _In_ KEY_INFORMATION_CLASS KeyInformationClass,\n    _Out_ PVOID *Buffer\n    )\n{\n    NTSTATUS status;\n    PVOID buffer;\n    ULONG bufferSize;\n    ULONG attempts = 16;\n\n    bufferSize = 0x100;\n    buffer = PhAllocate(bufferSize);\n\n    do\n    {\n        status = NtQueryKey(\n            KeyHandle,\n            KeyInformationClass,\n            buffer,\n            bufferSize,\n            &bufferSize\n            );\n\n        if (NT_SUCCESS(status))\n            break;\n\n        if (status == STATUS_BUFFER_OVERFLOW)\n        {\n            PhFree(buffer);\n            buffer = PhAllocate(bufferSize);\n        }\n        else\n        {\n            PhFree(buffer);\n            return status;\n        }\n    } while (--attempts);\n\n    *Buffer = buffer;\n\n    return status;\n}\n\n/**\n * Gets a registry value of any type.\n *\n * \\param KeyHandle A handle to the key.\n * \\param ValueName The name of the value.\n * \\param KeyValueInformationClass The information class to query.\n * \\param Buffer A variable which receives a pointer to a buffer containing information about the\n * registry value. You must free the buffer with PhFree() when you no longer need it.\n */\nNTSTATUS PhQueryValueKey(\n    _In_ HANDLE KeyHandle,\n    _In_opt_ PPH_STRINGREF ValueName,\n    _In_ KEY_VALUE_INFORMATION_CLASS KeyValueInformationClass,\n    _Out_ PVOID *Buffer\n    )\n{\n    NTSTATUS status;\n    UNICODE_STRING valueName;\n    PVOID buffer;\n    ULONG bufferSize;\n    ULONG attempts = 16;\n\n    if (ValueName)\n    {\n        if (!PhStringRefToUnicodeString(ValueName, &valueName))\n            return STATUS_NAME_TOO_LONG;\n    }\n    else\n    {\n        RtlInitUnicodeString(&valueName, NULL);\n    }\n\n    bufferSize = 0x100;\n    buffer = PhAllocate(bufferSize);\n\n    do\n    {\n        status = NtQueryValueKey(\n            KeyHandle,\n            &valueName,\n            KeyValueInformationClass,\n            buffer,\n            bufferSize,\n            &bufferSize\n            );\n\n        if (NT_SUCCESS(status))\n            break;\n\n        if (status == STATUS_BUFFER_OVERFLOW)\n        {\n            PhFree(buffer);\n            buffer = PhAllocate(bufferSize);\n        }\n        else\n        {\n            PhFree(buffer);\n            return status;\n        }\n    } while (--attempts);\n\n    *Buffer = buffer;\n\n    return status;\n}\n\n/**\n * Creates or opens a file.\n *\n * \\param FileHandle A variable that receives the file handle.\n * \\param FileName The Win32 file name.\n * \\param DesiredAccess The desired access to the file.\n * \\param FileAttributes File attributes applied if the file is created or overwritten.\n * \\param ShareAccess The file access granted to other threads.\n * \\li \\c FILE_SHARE_READ Allows other threads to read from the file.\n * \\li \\c FILE_SHARE_WRITE Allows other threads to write to the file.\n * \\li \\c FILE_SHARE_DELETE Allows other threads to delete the file.\n * \\param CreateDisposition The action to perform if the file does or does not exist.\n * \\li \\c FILE_SUPERSEDE If the file exists, replace it. Otherwise, create the file.\n * \\li \\c FILE_CREATE If the file exists, fail. Otherwise, create the file.\n * \\li \\c FILE_OPEN If the file exists, open it. Otherwise, fail.\n * \\li \\c FILE_OPEN_IF If the file exists, open it. Otherwise, create the file.\n * \\li \\c FILE_OVERWRITE If the file exists, open and overwrite it. Otherwise, fail.\n * \\li \\c FILE_OVERWRITE_IF If the file exists, open and overwrite it. Otherwise, create the file.\n * \\param CreateOptions The options to apply when the file is opened or created.\n */\nNTSTATUS PhCreateFileWin32(\n    _Out_ PHANDLE FileHandle,\n    _In_ PWSTR FileName,\n    _In_ ACCESS_MASK DesiredAccess,\n    _In_opt_ ULONG FileAttributes,\n    _In_ ULONG ShareAccess,\n    _In_ ULONG CreateDisposition,\n    _In_ ULONG CreateOptions\n    )\n{\n    return PhCreateFileWin32Ex(\n        FileHandle,\n        FileName,\n        DesiredAccess,\n        FileAttributes,\n        ShareAccess,\n        CreateDisposition,\n        CreateOptions,\n        NULL\n        );\n}\n\n/**\n * Creates or opens a file.\n *\n * \\param FileHandle A variable that receives the file handle.\n * \\param FileName The Win32 file name.\n * \\param DesiredAccess The desired access to the file.\n * \\param FileAttributes File attributes applied if the file is created or overwritten.\n * \\param ShareAccess The file access granted to other threads.\n * \\li \\c FILE_SHARE_READ Allows other threads to read from the file.\n * \\li \\c FILE_SHARE_WRITE Allows other threads to write to the file.\n * \\li \\c FILE_SHARE_DELETE Allows other threads to delete the file.\n * \\param CreateDisposition The action to perform if the file does or does not exist.\n * \\li \\c FILE_SUPERSEDE If the file exists, replace it. Otherwise, create the file.\n * \\li \\c FILE_CREATE If the file exists, fail. Otherwise, create the file.\n * \\li \\c FILE_OPEN If the file exists, open it. Otherwise, fail.\n * \\li \\c FILE_OPEN_IF If the file exists, open it. Otherwise, create the file.\n * \\li \\c FILE_OVERWRITE If the file exists, open and overwrite it. Otherwise, fail.\n * \\li \\c FILE_OVERWRITE_IF If the file exists, open and overwrite it. Otherwise, create the file.\n * \\param CreateOptions The options to apply when the file is opened or created.\n * \\param CreateStatus A variable that receives creation information.\n * \\li \\c FILE_SUPERSEDED The file was replaced because \\c FILE_SUPERSEDE was specified in\n * \\a CreateDisposition.\n * \\li \\c FILE_OPENED The file was opened because \\c FILE_OPEN or \\c FILE_OPEN_IF was specified in\n * \\a CreateDisposition.\n * \\li \\c FILE_CREATED The file was created because \\c FILE_CREATE or \\c FILE_OPEN_IF was specified\n * in \\a CreateDisposition.\n * \\li \\c FILE_OVERWRITTEN The file was overwritten because \\c FILE_OVERWRITE or\n * \\c FILE_OVERWRITE_IF was specified in \\a CreateDisposition.\n * \\li \\c FILE_EXISTS The file was not opened because it already existed and \\c FILE_CREATE was\n * specified in \\a CreateDisposition.\n * \\li \\c FILE_DOES_NOT_EXIST The file was not opened because it did not exist and \\c FILE_OPEN or\n * \\c FILE_OVERWRITE was specified in \\a CreateDisposition.\n */\nNTSTATUS PhCreateFileWin32Ex(\n    _Out_ PHANDLE FileHandle,\n    _In_ PWSTR FileName,\n    _In_ ACCESS_MASK DesiredAccess,\n    _In_opt_ ULONG FileAttributes,\n    _In_ ULONG ShareAccess,\n    _In_ ULONG CreateDisposition,\n    _In_ ULONG CreateOptions,\n    _Out_opt_ PULONG CreateStatus\n    )\n{\n    NTSTATUS status;\n    HANDLE fileHandle;\n    UNICODE_STRING fileName;\n    OBJECT_ATTRIBUTES oa;\n    IO_STATUS_BLOCK isb;\n\n    if (!FileAttributes)\n        FileAttributes = FILE_ATTRIBUTE_NORMAL;\n\n    if (!NT_SUCCESS(status = RtlDosPathNameToNtPathName_U_WithStatus(\n        FileName,\n        &fileName,\n        NULL,\n        NULL\n        )))\n        return status;\n\n    InitializeObjectAttributes(\n        &oa,\n        &fileName,\n        OBJ_CASE_INSENSITIVE,\n        NULL,\n        NULL\n        );\n\n    status = NtCreateFile(\n        &fileHandle,\n        DesiredAccess,\n        &oa,\n        &isb,\n        NULL,\n        FileAttributes,\n        ShareAccess,\n        CreateDisposition,\n        CreateOptions,\n        NULL,\n        0\n        );\n\n    RtlFreeUnicodeString(&fileName);\n\n    if (NT_SUCCESS(status))\n    {\n        *FileHandle = fileHandle;\n    }\n\n    if (CreateStatus)\n        *CreateStatus = (ULONG)isb.Information;\n\n    return status;\n}\n\n/**\n * Queries file attributes.\n *\n * \\param FileName The Win32 file name.\n * \\param FileInformation A variable that receives the file information.\n */\nNTSTATUS PhQueryFullAttributesFileWin32(\n    _In_ PWSTR FileName,\n    _Out_ PFILE_NETWORK_OPEN_INFORMATION FileInformation\n    )\n{\n    NTSTATUS status;\n    UNICODE_STRING fileName;\n    OBJECT_ATTRIBUTES oa;\n\n    if (!NT_SUCCESS(status = RtlDosPathNameToNtPathName_U_WithStatus(\n        FileName,\n        &fileName,\n        NULL,\n        NULL\n        )))\n        return status;\n\n    InitializeObjectAttributes(\n        &oa,\n        &fileName,\n        OBJ_CASE_INSENSITIVE,\n        NULL,\n        NULL\n        );\n\n    status = NtQueryFullAttributesFile(&oa, FileInformation);\n    RtlFreeUnicodeString(&fileName);\n\n    return status;\n}\n\n/**\n * Deletes a file.\n *\n * \\param FileName The Win32 file name.\n */\nNTSTATUS PhDeleteFileWin32(\n    _In_ PWSTR FileName\n    )\n{\n    NTSTATUS status;\n    HANDLE fileHandle;\n\n    status = PhCreateFileWin32(\n        &fileHandle,\n        FileName,\n        DELETE,\n        0,\n        FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,\n        FILE_OPEN,\n        FILE_DELETE_ON_CLOSE\n        );\n\n    if (!NT_SUCCESS(status))\n        return status;\n\n    NtClose(fileHandle);\n\n    return status;\n}\n\n/**\n* Creates a directory path recursively.\n*\n* \\param DirectoryPath The Win32 directory path.\n*/\nNTSTATUS PhCreateDirectory(\n    _In_ PPH_STRING DirectoryPath\n    )\n{\n    static PH_STRINGREF directorySeparator = PH_STRINGREF_INIT(L\"\\\\\");\n    PPH_STRING directoryPath = NULL;\n    PH_STRINGREF part;\n    PH_STRINGREF remainingPart;\n\n    if (PhIsNullOrEmptyString(DirectoryPath))\n        return STATUS_FAIL_CHECK;\n\n    if (RtlDoesFileExists_U(PhGetString(DirectoryPath)))\n        return STATUS_SUCCESS;\n\n    remainingPart = PhGetStringRef(DirectoryPath);\n\n    while (remainingPart.Length != 0)\n    {\n        PhSplitStringRefAtChar(&remainingPart, '\\\\', &part, &remainingPart);\n\n        if (part.Length != 0)\n        {\n            if (PhIsNullOrEmptyString(directoryPath))\n                directoryPath = PhCreateString2(&part);\n            else\n            {\n                PPH_STRING tempPathString;\n\n                tempPathString = PhConcatStringRef3(\n                    &directoryPath->sr,\n                    &directorySeparator,\n                    &part\n                    );\n\n                // Check if the directory already exists.\n                if (!RtlDoesFileExists_U(PhGetString(tempPathString)))\n                {\n                    HANDLE directoryHandle;\n\n                    // Create the directory.\n                    if (NT_SUCCESS(PhCreateFileWin32(\n                        &directoryHandle,\n                        PhGetString(tempPathString),\n                        FILE_GENERIC_READ,\n                        FILE_ATTRIBUTE_NORMAL,\n                        FILE_SHARE_READ | FILE_SHARE_WRITE,\n                        FILE_CREATE,\n                        FILE_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT | FILE_OPEN_FOR_BACKUP_INTENT\n                        )))\n                    {\n                        NtClose(directoryHandle);\n                    }\n                }\n\n                PhMoveReference(&directoryPath, tempPathString);\n            }\n        }\n    }\n\n    if (directoryPath)\n        PhDereferenceObject(directoryPath);\n\n    if (RtlDoesFileExists_U(PhGetString(DirectoryPath)))\n        return STATUS_SUCCESS;\n    else\n        return STATUS_NOT_FOUND;\n}\n\nstatic BOOLEAN PhpDeleteDirectoryCallback(\n    _In_ PFILE_DIRECTORY_INFORMATION Information,\n    _In_opt_ PVOID Context\n    )\n{\n    static PH_STRINGREF directorySeparator = PH_STRINGREF_INIT(L\"\\\\\");\n    PPH_STRING parentDirectory = Context;\n    PPH_STRING fullName;\n    PH_STRINGREF baseName;\n\n    baseName.Buffer = Information->FileName;\n    baseName.Length = Information->FileNameLength;\n\n    if (PhEqualStringRef2(&baseName, L\".\", TRUE) || PhEqualStringRef2(&baseName, L\"..\", TRUE))\n        return TRUE;\n\n    fullName = PhConcatStringRef3(\n        &parentDirectory->sr,\n        &directorySeparator,\n        &baseName\n        );\n\n    if (Information->FileAttributes & FILE_ATTRIBUTE_DIRECTORY)\n    {\n        HANDLE directoryHandle;\n\n        if (NT_SUCCESS(PhCreateFileWin32(\n            &directoryHandle,\n            PhGetString(fullName),\n            FILE_GENERIC_READ | DELETE,\n            FILE_ATTRIBUTE_NORMAL,\n            FILE_SHARE_READ | FILE_SHARE_DELETE,\n            FILE_OPEN,\n            FILE_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT\n            )))\n        {\n            IO_STATUS_BLOCK isb;\n            FILE_DISPOSITION_INFORMATION fileInfo;\n\n            PhEnumDirectoryFile(directoryHandle, NULL, PhpDeleteDirectoryCallback, fullName);\n\n            // Delete the directory. \n            fileInfo.DeleteFile = TRUE;\n            NtSetInformationFile(\n                directoryHandle,\n                &isb,\n                &fileInfo,\n                sizeof(FILE_DISPOSITION_INFORMATION),\n                FileDispositionInformation\n                );\n\n            NtClose(directoryHandle);\n        }\n    }\n    else\n    {\n        if (Information->FileAttributes & FILE_ATTRIBUTE_READONLY)\n        {\n            HANDLE fileHandle;\n\n            if (NT_SUCCESS(PhCreateFileWin32(\n                &fileHandle,\n                PhGetString(fullName),\n                FILE_GENERIC_READ | FILE_WRITE_ATTRIBUTES,\n                FILE_ATTRIBUTE_NORMAL,\n                FILE_SHARE_WRITE,\n                FILE_OPEN,\n                FILE_NON_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT\n                )))\n            {\n                IO_STATUS_BLOCK isb;\n                FILE_BASIC_INFORMATION fileInfo;\n\n                memset(&fileInfo, 0, sizeof(FILE_BASIC_INFORMATION));\n\n                // Clear the read-only flag.\n                fileInfo.FileAttributes = Information->FileAttributes &= ~FILE_ATTRIBUTE_READONLY;\n\n                NtSetInformationFile(\n                    fileHandle,\n                    &isb,\n                    &fileInfo,\n                    sizeof(FILE_BASIC_INFORMATION),\n                    FileBasicInformation\n                    );\n\n                NtClose(fileHandle);\n            }\n        }\n\n        // Delete the file. \n        PhDeleteFileWin32(PhGetString(fullName));\n    }\n\n    PhDereferenceObject(fullName);\n    return TRUE;\n}\n\n/**\n* Deletes a directory path recursively.\n*\n* \\param DirectoryPath The Win32 directory path.\n*/\nNTSTATUS PhDeleteDirectory(\n    _In_ PPH_STRING DirectoryPath\n    )\n{\n    NTSTATUS status;\n    HANDLE directoryHandle;\n\n    status = PhCreateFileWin32(\n        &directoryHandle,\n        PhGetString(DirectoryPath),\n        FILE_GENERIC_READ | DELETE,\n        FILE_ATTRIBUTE_NORMAL,\n        FILE_SHARE_READ | FILE_SHARE_DELETE,\n        FILE_OPEN,\n        FILE_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT\n        );\n\n    if (NT_SUCCESS(status))\n    {\n        IO_STATUS_BLOCK isb;\n        FILE_DISPOSITION_INFORMATION fileInfo;\n\n        // Remove any files or folders inside the directory.\n        status = PhEnumDirectoryFile(\n            directoryHandle, \n            NULL, \n            PhpDeleteDirectoryCallback, \n            DirectoryPath\n            );\n\n        // Remove the directory. \n        fileInfo.DeleteFile = TRUE;\n        status = NtSetInformationFile(\n            directoryHandle,\n            &isb,\n            &fileInfo,\n            sizeof(FILE_DISPOSITION_INFORMATION),\n            FileDispositionInformation\n            );\n\n        NtClose(directoryHandle);\n    }\n\n    if (!RtlDoesFileExists_U(PhGetString(DirectoryPath)))\n        return STATUS_SUCCESS;\n\n    return status;\n}\n\n/**\n* Creates an anonymous pipe.\n*\n* \\param PipeReadHandle The pipe read handle.\n* \\param PipeWriteHandle The pipe write handle.\n*/\nNTSTATUS PhCreatePipe(\n    _Out_ PHANDLE PipeReadHandle,\n    _Out_ PHANDLE PipeWriteHandle\n    )\n{\n    NTSTATUS status;\n    PACL pipeAcl = NULL;\n    HANDLE pipeDirectoryHandle;\n    HANDLE pipeReadHandle;\n    HANDLE pipeWriteHandle;\n    LARGE_INTEGER pipeTimeout;\n    UNICODE_STRING pipeNameUs;\n    OBJECT_ATTRIBUTES oa;\n    IO_STATUS_BLOCK isb;\n\n    RtlInitUnicodeString(&pipeNameUs, DEVICE_NAMED_PIPE);\n    InitializeObjectAttributes(\n        &oa,\n        &pipeNameUs,\n        OBJ_CASE_INSENSITIVE,\n        NULL,\n        NULL\n        );\n\n    status = NtOpenFile(\n        &pipeDirectoryHandle,\n        GENERIC_READ | SYNCHRONIZE,\n        &oa,\n        &isb,\n        FILE_SHARE_READ | FILE_SHARE_WRITE,\n        FILE_SYNCHRONOUS_IO_NONALERT\n        );\n\n    if (!NT_SUCCESS(status))\n        return status;\n\n    RtlInitUnicodeString(&pipeNameUs, UNICODE_NULL);\n    InitializeObjectAttributes(\n        &oa,\n        &pipeNameUs,\n        OBJ_CASE_INSENSITIVE,\n        pipeDirectoryHandle,\n        NULL\n        );\n\n    if (NT_SUCCESS(RtlDefaultNpAcl(&pipeAcl)))\n    {\n        SECURITY_DESCRIPTOR securityDescriptor;\n\n        RtlCreateSecurityDescriptor(&securityDescriptor, SECURITY_DESCRIPTOR_REVISION);\n        RtlSetDaclSecurityDescriptor(&securityDescriptor, TRUE, pipeAcl, FALSE);\n\n        oa.SecurityDescriptor = &securityDescriptor;\n    }\n\n    status = NtCreateNamedPipeFile(\n        &pipeReadHandle,\n        FILE_WRITE_ATTRIBUTES | GENERIC_READ | SYNCHRONIZE,\n        &oa,\n        &isb,\n        FILE_SHARE_READ | FILE_SHARE_WRITE,\n        FILE_CREATE,\n        FILE_PIPE_INBOUND | FILE_SYNCHRONOUS_IO_NONALERT,\n        FILE_PIPE_BYTE_STREAM_TYPE,\n        FILE_PIPE_BYTE_STREAM_MODE,\n        FILE_PIPE_QUEUE_OPERATION,\n        ULONG_MAX,\n        PAGE_SIZE,\n        PAGE_SIZE,\n        PhTimeoutFromMilliseconds(&pipeTimeout, 500)\n        );\n\n    if (!NT_SUCCESS(status))\n    {\n        if (pipeAcl)\n            RtlFreeHeap(RtlProcessHeap(), 0, pipeAcl);\n\n        NtClose(pipeDirectoryHandle);\n        return status;\n    }\n\n    RtlInitUnicodeString(&pipeNameUs, UNICODE_NULL);\n    InitializeObjectAttributes(\n        &oa,\n        &pipeNameUs,\n        OBJ_CASE_INSENSITIVE,\n        pipeReadHandle,\n        NULL\n        );\n\n    status = NtOpenFile(\n        &pipeWriteHandle,\n        FILE_READ_ATTRIBUTES | GENERIC_WRITE | SYNCHRONIZE,\n        &oa,\n        &isb,\n        FILE_SHARE_READ | FILE_SHARE_WRITE,\n        FILE_NON_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT\n        );\n\n    if (NT_SUCCESS(status))\n    {\n        *PipeReadHandle = pipeReadHandle;\n        *PipeWriteHandle = pipeWriteHandle;\n    }\n\n    if (pipeAcl)\n        RtlFreeHeap(RtlProcessHeap(), 0, pipeAcl);\n\n    NtClose(pipeDirectoryHandle);\n    return status;\n}\n\n/**\n* Creates an named pipe.\n*\n* \\param PipeHandle The pipe read/write handle.\n* \\param PipeName The pipe name.\n*/\nNTSTATUS PhCreateNamedPipe(\n    _Out_ PHANDLE PipeHandle,\n    _In_ PWSTR PipeName\n    )\n{\n    NTSTATUS status;\n    PACL pipeAcl = NULL;\n    HANDLE pipeHandle;\n    PPH_STRING pipeName;\n    LARGE_INTEGER pipeTimeout;\n    UNICODE_STRING pipeNameUs;\n    OBJECT_ATTRIBUTES oa;\n    IO_STATUS_BLOCK isb;\n\n    pipeName = PhConcatStrings2(DEVICE_NAMED_PIPE, PipeName);\n    PhStringRefToUnicodeString(&pipeName->sr, &pipeNameUs);\n    PhTimeoutFromMilliseconds(&pipeTimeout, 500);\n\n    InitializeObjectAttributes(\n        &oa,\n        &pipeNameUs,\n        OBJ_CASE_INSENSITIVE,\n        NULL,\n        NULL\n        );\n\n    if (NT_SUCCESS(RtlDefaultNpAcl(&pipeAcl)))\n    {\n        SECURITY_DESCRIPTOR securityDescriptor;\n\n        RtlCreateSecurityDescriptor(&securityDescriptor, SECURITY_DESCRIPTOR_REVISION);\n        RtlSetDaclSecurityDescriptor(&securityDescriptor, TRUE, pipeAcl, FALSE);\n\n        oa.SecurityDescriptor = &securityDescriptor;\n    }\n\n    status = NtCreateNamedPipeFile(\n        &pipeHandle,\n        FILE_GENERIC_READ | FILE_GENERIC_WRITE,\n        &oa,\n        &isb,\n        FILE_SHARE_READ | FILE_SHARE_WRITE,\n        FILE_OPEN_IF,\n        FILE_PIPE_FULL_DUPLEX | FILE_SYNCHRONOUS_IO_NONALERT,\n        FILE_PIPE_MESSAGE_TYPE,\n        FILE_PIPE_MESSAGE_MODE,\n        FILE_PIPE_QUEUE_OPERATION,\n        ULONG_MAX,\n        PAGE_SIZE,\n        PAGE_SIZE,\n        &pipeTimeout\n        );\n\n    if (NT_SUCCESS(status))\n    {\n        *PipeHandle = pipeHandle;\n    }\n\n    if (pipeAcl)\n        RtlFreeHeap(RtlProcessHeap(), 0, pipeAcl);\n\n    PhDereferenceObject(pipeName);\n    return status;\n}\n\nNTSTATUS PhConnectPipe(\n    _Out_ PHANDLE PipeHandle,\n    _In_ PWSTR PipeName\n    )\n{\n    NTSTATUS status;\n    HANDLE pipeHandle;\n    PPH_STRING pipeName;\n    UNICODE_STRING pipeNameUs;\n    OBJECT_ATTRIBUTES oa;\n    IO_STATUS_BLOCK isb;\n\n    pipeName = PhConcatStrings2(DEVICE_NAMED_PIPE, PipeName);\n    PhStringRefToUnicodeString(&pipeName->sr, &pipeNameUs);\n\n    InitializeObjectAttributes(\n        &oa,\n        &pipeNameUs,\n        OBJ_CASE_INSENSITIVE,\n        NULL,\n        NULL\n        );\n\n    status = NtCreateFile(\n        &pipeHandle,\n        FILE_GENERIC_READ | FILE_GENERIC_WRITE,\n        &oa,\n        &isb,\n        NULL,\n        FILE_ATTRIBUTE_NORMAL,\n        FILE_SHARE_READ | FILE_SHARE_WRITE,\n        FILE_OPEN,\n        FILE_NON_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT,\n        NULL,\n        0\n        );\n\n    if (NT_SUCCESS(status))\n    {\n        *PipeHandle = pipeHandle;\n    }\n\n    PhDereferenceObject(pipeName);\n    return status;\n}\n\nNTSTATUS PhListenNamedPipe(\n    _In_ HANDLE PipeHandle\n    )\n{\n    NTSTATUS status;\n    IO_STATUS_BLOCK isb;\n\n    status = NtFsControlFile(\n        PipeHandle,\n        NULL,\n        NULL,\n        NULL,\n        &isb,\n        FSCTL_PIPE_LISTEN,\n        NULL,\n        0,\n        NULL,\n        0\n        );\n\n    if (status == STATUS_PENDING)\n    {\n        status = NtWaitForSingleObject(PipeHandle, FALSE, NULL);\n\n        if (NT_SUCCESS(status))\n            status = isb.Status;\n    }\n\n    return status;\n}\n\nNTSTATUS PhDisconnectNamedPipe(\n    _In_ HANDLE PipeHandle\n    )\n{\n    NTSTATUS status;\n    IO_STATUS_BLOCK isb;\n\n    status = NtFsControlFile(\n        PipeHandle,\n        NULL,\n        NULL,\n        NULL,\n        &isb,\n        FSCTL_PIPE_DISCONNECT,\n        NULL,\n        0,\n        NULL,\n        0\n        );\n\n    if (status == STATUS_PENDING)\n    {\n        status = NtWaitForSingleObject(PipeHandle, FALSE, NULL);\n\n        if (NT_SUCCESS(status))\n            status = isb.Status;\n    }\n\n    return status;\n}\n\nNTSTATUS PhPeekNamedPipe(\n    _In_ HANDLE PipeHandle,\n    _Out_writes_bytes_opt_(Length) PVOID Buffer,\n    _In_ ULONG Length,\n    _Out_opt_ PULONG NumberOfBytesRead,\n    _Out_opt_ PULONG NumberOfBytesAvailable,\n    _Out_opt_ PULONG NumberOfBytesLeftInMessage\n    )\n{\n    NTSTATUS status;\n    IO_STATUS_BLOCK isb;\n    PFILE_PIPE_PEEK_BUFFER peekBuffer;\n    ULONG peekBufferLength;\n\n    peekBufferLength = FIELD_OFFSET(FILE_PIPE_PEEK_BUFFER, Data) + Length;\n    peekBuffer = PhAllocate(peekBufferLength);\n\n    status = NtFsControlFile(\n        PipeHandle,\n        NULL,\n        NULL,\n        NULL,\n        &isb,\n        FSCTL_PIPE_PEEK,\n        NULL,\n        0,\n        peekBuffer,\n        peekBufferLength\n        );\n\n    if (status == STATUS_PENDING)\n    {\n        status = NtWaitForSingleObject(PipeHandle, FALSE, NULL);\n\n        if (NT_SUCCESS(status))\n            status = isb.Status;\n    }\n\n    // STATUS_BUFFER_OVERFLOW means that there is data remaining; this is normal.\n    if (status == STATUS_BUFFER_OVERFLOW)\n        status = STATUS_SUCCESS;\n\n    if (NT_SUCCESS(status))\n    {\n        ULONG numberOfBytesRead = 0;\n\n        if (Buffer || NumberOfBytesRead || NumberOfBytesLeftInMessage)\n            numberOfBytesRead = (ULONG)(isb.Information - FIELD_OFFSET(FILE_PIPE_PEEK_BUFFER, Data));\n\n        if (Buffer)\n            memcpy(Buffer, peekBuffer->Data, numberOfBytesRead);\n\n        if (NumberOfBytesRead)\n            *NumberOfBytesRead = numberOfBytesRead;\n\n        if (NumberOfBytesAvailable)\n            *NumberOfBytesAvailable = peekBuffer->ReadDataAvailable;\n\n        if (NumberOfBytesLeftInMessage)\n            *NumberOfBytesLeftInMessage = peekBuffer->MessageLength - numberOfBytesRead;\n    }\n\n    PhFree(peekBuffer);\n\n    return status;\n}\n\nNTSTATUS PhTransceiveNamedPipe(\n    _In_ HANDLE PipeHandle,\n    _In_reads_bytes_(InputBufferLength) PVOID InputBuffer,\n    _In_ ULONG InputBufferLength,\n    _Out_writes_bytes_(OutputBufferLength) PVOID OutputBuffer,\n    _In_ ULONG OutputBufferLength\n    )\n{\n    NTSTATUS status;\n    IO_STATUS_BLOCK isb;\n\n    status = NtFsControlFile(\n        PipeHandle,\n        NULL,\n        NULL,\n        NULL,\n        &isb,\n        FSCTL_PIPE_TRANSCEIVE,\n        InputBuffer,\n        InputBufferLength,\n        OutputBuffer,\n        OutputBufferLength\n        );\n\n    if (status == STATUS_PENDING)\n    {\n        status = NtWaitForSingleObject(PipeHandle, FALSE, NULL);\n\n        if (NT_SUCCESS(status))\n            status = isb.Status;\n    }\n\n    return status;\n}\n\nNTSTATUS PhWaitForNamedPipe(\n    _In_ PWSTR PipeName,\n    _In_opt_ ULONG Timeout\n    )\n{\n    NTSTATUS status;\n    IO_STATUS_BLOCK isb;\n    PH_STRINGREF localNpfsNameSr;\n    UNICODE_STRING localNpfsName;\n    HANDLE fileSystemHandle;\n    OBJECT_ATTRIBUTES oa;\n    PFILE_PIPE_WAIT_FOR_BUFFER waitForBuffer;\n    ULONG waitForBufferLength;\n\n    RtlInitUnicodeString(&localNpfsName, DEVICE_NAMED_PIPE);\n    InitializeObjectAttributes(\n        &oa,\n        &localNpfsName,\n        OBJ_CASE_INSENSITIVE,\n        NULL,\n        NULL\n        );\n\n    status = NtOpenFile(\n        &fileSystemHandle,\n        FILE_READ_ATTRIBUTES | SYNCHRONIZE,\n        &oa,\n        &isb,\n        FILE_SHARE_READ | FILE_SHARE_WRITE,\n        FILE_SYNCHRONOUS_IO_NONALERT\n        );\n\n    if (!NT_SUCCESS(status))\n        return status;\n\n    PhInitializeStringRefLongHint(&localNpfsNameSr, PipeName);\n    waitForBufferLength = FIELD_OFFSET(FILE_PIPE_WAIT_FOR_BUFFER, Name) + (ULONG)localNpfsNameSr.Length;\n    waitForBuffer = PhAllocate(waitForBufferLength);\n\n    if (Timeout)\n    {\n        PhTimeoutFromMilliseconds(&waitForBuffer->Timeout, Timeout);\n        waitForBuffer->TimeoutSpecified = TRUE;\n    }\n    else\n    {\n        waitForBuffer->Timeout.LowPart = 0;\n        waitForBuffer->Timeout.HighPart = MINLONG; // a very long time\n        waitForBuffer->TimeoutSpecified = TRUE;\n    }\n\n    waitForBuffer->NameLength = (ULONG)localNpfsNameSr.Length;\n    memcpy(waitForBuffer->Name, localNpfsNameSr.Buffer, localNpfsNameSr.Length);\n\n    status = NtFsControlFile(\n        fileSystemHandle,\n        NULL,\n        NULL,\n        NULL,\n        &isb,\n        FSCTL_PIPE_WAIT,\n        waitForBuffer,\n        waitForBufferLength,\n        NULL,\n        0\n        );\n\n    PhFree(waitForBuffer);\n    NtClose(fileSystemHandle);\n\n    return status;\n}\n\nNTSTATUS PhImpersonateClientOfNamedPipe(\n    _In_ HANDLE PipeHandle\n    )\n{\n    IO_STATUS_BLOCK isb;\n\n    return NtFsControlFile(\n        PipeHandle,\n        NULL,\n        NULL,\n        NULL,\n        &isb,\n        FSCTL_PIPE_IMPERSONATE,\n        NULL,\n        0,\n        NULL,\n        0\n        );\n}\n"
  },
  {
    "path": "third_party/phlib/phlib.vcxproj",
    "content": "﻿<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<Project DefaultTargets=\"Build\" ToolsVersion=\"15.0\" xmlns=\"http://schemas.microsoft.com/developer/msbuild/2003\">\n  <ItemGroup Label=\"ProjectConfigurations\">\n    <ProjectConfiguration Include=\"Appx|Win32\">\n      <Configuration>Appx</Configuration>\n      <Platform>Win32</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"Appx|x64\">\n      <Configuration>Appx</Configuration>\n      <Platform>x64</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"Debug|Win32\">\n      <Configuration>Debug</Configuration>\n      <Platform>Win32</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"Debug|x64\">\n      <Configuration>Debug</Configuration>\n      <Platform>x64</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"Release|Win32\">\n      <Configuration>Release</Configuration>\n      <Platform>Win32</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"Release|x64\">\n      <Configuration>Release</Configuration>\n      <Platform>x64</Platform>\n    </ProjectConfiguration>\n  </ItemGroup>\n  <PropertyGroup Label=\"Globals\">\n    <ProjectGuid>{477D0215-F252-41A1-874B-F27E3EA1ED17}</ProjectGuid>\n    <RootNamespace>phlib</RootNamespace>\n    <Keyword>Win32Proj</Keyword>\n    <WindowsTargetPlatformVersion>10.0</WindowsTargetPlatformVersion>\n  </PropertyGroup>\n  <Import Project=\"$(VCTargetsPath)\\Microsoft.Cpp.Default.props\" />\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Release|Win32'\" Label=\"Configuration\">\n    <ConfigurationType>StaticLibrary</ConfigurationType>\n    <CharacterSet>Unicode</CharacterSet>\n    <WholeProgramOptimization>true</WholeProgramOptimization>\n    <PlatformToolset>v142</PlatformToolset>\n    <SpectreMitigation>false</SpectreMitigation>\n  </PropertyGroup>\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Appx|Win32'\" Label=\"Configuration\">\n    <ConfigurationType>StaticLibrary</ConfigurationType>\n    <CharacterSet>Unicode</CharacterSet>\n    <WholeProgramOptimization>true</WholeProgramOptimization>\n    <PlatformToolset>v142</PlatformToolset>\n    <SpectreMitigation>false</SpectreMitigation>\n  </PropertyGroup>\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Debug|Win32'\" Label=\"Configuration\">\n    <ConfigurationType>StaticLibrary</ConfigurationType>\n    <CharacterSet>Unicode</CharacterSet>\n    <PlatformToolset>v142</PlatformToolset>\n    <SpectreMitigation>false</SpectreMitigation>\n  </PropertyGroup>\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\" Label=\"Configuration\">\n    <ConfigurationType>StaticLibrary</ConfigurationType>\n    <CharacterSet>Unicode</CharacterSet>\n    <WholeProgramOptimization>true</WholeProgramOptimization>\n    <PlatformToolset>v142</PlatformToolset>\n    <SpectreMitigation>false</SpectreMitigation>\n  </PropertyGroup>\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Appx|x64'\" Label=\"Configuration\">\n    <ConfigurationType>StaticLibrary</ConfigurationType>\n    <CharacterSet>Unicode</CharacterSet>\n    <WholeProgramOptimization>true</WholeProgramOptimization>\n    <PlatformToolset>v142</PlatformToolset>\n    <SpectreMitigation>false</SpectreMitigation>\n  </PropertyGroup>\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\" Label=\"Configuration\">\n    <ConfigurationType>StaticLibrary</ConfigurationType>\n    <CharacterSet>Unicode</CharacterSet>\n    <PlatformToolset>v142</PlatformToolset>\n    <SpectreMitigation>false</SpectreMitigation>\n  </PropertyGroup>\n  <Import Project=\"$(VCTargetsPath)\\Microsoft.Cpp.props\" />\n  <ImportGroup Label=\"ExtensionSettings\">\n  </ImportGroup>\n  <ImportGroup Condition=\"'$(Configuration)|$(Platform)'=='Release|Win32'\" Label=\"PropertySheets\">\n    <Import Project=\"$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props\" Condition=\"exists('$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props')\" Label=\"LocalAppDataPlatform\" />\n  </ImportGroup>\n  <ImportGroup Condition=\"'$(Configuration)|$(Platform)'=='Appx|Win32'\" Label=\"PropertySheets\">\n    <Import Project=\"$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props\" Condition=\"exists('$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props')\" Label=\"LocalAppDataPlatform\" />\n  </ImportGroup>\n  <ImportGroup Condition=\"'$(Configuration)|$(Platform)'=='Debug|Win32'\" Label=\"PropertySheets\">\n    <Import Project=\"$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props\" Condition=\"exists('$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props')\" Label=\"LocalAppDataPlatform\" />\n  </ImportGroup>\n  <ImportGroup Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\" Label=\"PropertySheets\">\n    <Import Project=\"$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props\" Condition=\"exists('$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props')\" Label=\"LocalAppDataPlatform\" />\n  </ImportGroup>\n  <ImportGroup Condition=\"'$(Configuration)|$(Platform)'=='Appx|x64'\" Label=\"PropertySheets\">\n    <Import Project=\"$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props\" Condition=\"exists('$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props')\" Label=\"LocalAppDataPlatform\" />\n  </ImportGroup>\n  <ImportGroup Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\" Label=\"PropertySheets\">\n    <Import Project=\"$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props\" Condition=\"exists('$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props')\" Label=\"LocalAppDataPlatform\" />\n  </ImportGroup>\n  <PropertyGroup Label=\"UserMacros\" />\n  <PropertyGroup>\n    <OutDir Condition=\"'$(Configuration)|$(Platform)'=='Debug|Win32'\">$(SolutionDir)bin\\$(Configuration)$(PlatformArchitecture)\\</OutDir>\n    <IntDir Condition=\"'$(Configuration)|$(Platform)'=='Debug|Win32'\">$(SolutionDir)obj\\$(ProjectName)\\$(Configuration)$(PlatformArchitecture)\\</IntDir>\n    <OutDir Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">$(SolutionDir)bin\\$(Configuration)$(PlatformArchitecture)\\</OutDir>\n    <IntDir Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">$(SolutionDir)obj\\$(ProjectName)\\$(Configuration)$(PlatformArchitecture)\\</IntDir>\n    <OutDir Condition=\"'$(Configuration)|$(Platform)'=='Release|Win32'\">$(SolutionDir)bin\\$(Configuration)$(PlatformArchitecture)\\</OutDir>\n    <OutDir Condition=\"'$(Configuration)|$(Platform)'=='Appx|Win32'\">$(SolutionDir)bin\\$(Configuration)$(PlatformArchitecture)\\</OutDir>\n    <IntDir Condition=\"'$(Configuration)|$(Platform)'=='Release|Win32'\">$(SolutionDir)obj\\$(ProjectName)\\$(Configuration)$(PlatformArchitecture)\\</IntDir>\n    <IntDir Condition=\"'$(Configuration)|$(Platform)'=='Appx|Win32'\">$(SolutionDir)obj\\$(ProjectName)\\$(Configuration)$(PlatformArchitecture)\\</IntDir>\n    <OutDir Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\">$(SolutionDir)bin\\$(Configuration)$(PlatformArchitecture)\\</OutDir>\n    <OutDir Condition=\"'$(Configuration)|$(Platform)'=='Appx|x64'\">$(SolutionDir)bin\\$(Configuration)$(PlatformArchitecture)\\</OutDir>\n    <IntDir Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\">$(SolutionDir)obj\\$(ProjectName)\\$(Configuration)$(PlatformArchitecture)\\</IntDir>\n    <IntDir Condition=\"'$(Configuration)|$(Platform)'=='Appx|x64'\">$(SolutionDir)obj\\$(ProjectName)\\$(Configuration)$(PlatformArchitecture)\\</IntDir>\n  </PropertyGroup>\n  <ItemDefinitionGroup Condition=\"'$(Configuration)|$(Platform)'=='Debug|Win32'\">\n    <ClCompile>\n      <Optimization>Disabled</Optimization>\n      <AdditionalIncludeDirectories>$(SolutionDir)third_party\\phnt\\include;include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>\n      <PreprocessorDefinitions>DEBUG;_PHLIB_;%(PreprocessorDefinitions)</PreprocessorDefinitions>\n      <StringPooling>true</StringPooling>\n      <BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks>\n      <RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>\n      <WarningLevel>Level3</WarningLevel>\n      <DebugInformationFormat>ProgramDatabase</DebugInformationFormat>\n      <CallingConvention>StdCall</CallingConvention>\n      <TreatWarningAsError>true</TreatWarningAsError>\n      <MultiProcessorCompilation>true</MultiProcessorCompilation>\n    </ClCompile>\n  </ItemDefinitionGroup>\n  <ItemDefinitionGroup Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">\n    <ClCompile>\n      <Optimization>Disabled</Optimization>\n      <AdditionalIncludeDirectories>$(SolutionDir)third_party\\phnt\\include;include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>\n      <PreprocessorDefinitions>DEBUG;_PHLIB_;%(PreprocessorDefinitions)</PreprocessorDefinitions>\n      <StringPooling>true</StringPooling>\n      <BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks>\n      <RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>\n      <WarningLevel>Level3</WarningLevel>\n      <DebugInformationFormat>ProgramDatabase</DebugInformationFormat>\n      <CallingConvention>StdCall</CallingConvention>\n      <TreatWarningAsError>true</TreatWarningAsError>\n      <MultiProcessorCompilation>true</MultiProcessorCompilation>\n    </ClCompile>\n  </ItemDefinitionGroup>\n  <ItemDefinitionGroup Condition=\"'$(Configuration)|$(Platform)'=='Release|Win32'\">\n    <ClCompile>\n      <Optimization>MaxSpeed</Optimization>\n      <IntrinsicFunctions>true</IntrinsicFunctions>\n      <AdditionalIncludeDirectories>$(SolutionDir)third_party\\phnt\\include;include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>\n      <PreprocessorDefinitions>WIN32;NDEBUG;_WINDOWS;_PHLIB_;%(PreprocessorDefinitions)</PreprocessorDefinitions>\n      <StringPooling>true</StringPooling>\n      <RuntimeLibrary>MultiThreaded</RuntimeLibrary>\n      <BufferSecurityCheck>false</BufferSecurityCheck>\n      <FunctionLevelLinking>true</FunctionLevelLinking>\n      <WarningLevel>Level3</WarningLevel>\n      <DebugInformationFormat>ProgramDatabase</DebugInformationFormat>\n      <CallingConvention>StdCall</CallingConvention>\n      <TreatWarningAsError>true</TreatWarningAsError>\n      <MultiProcessorCompilation>true</MultiProcessorCompilation>\n      <EnableEnhancedInstructionSet>StreamingSIMDExtensions</EnableEnhancedInstructionSet>\n    </ClCompile>\n  </ItemDefinitionGroup>\n  <ItemDefinitionGroup Condition=\"'$(Configuration)|$(Platform)'=='Appx|Win32'\">\n    <ClCompile>\n      <Optimization>MaxSpeed</Optimization>\n      <IntrinsicFunctions>true</IntrinsicFunctions>\n      <AdditionalIncludeDirectories>$(SolutionDir)third_party\\phnt\\include;include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>\n      <PreprocessorDefinitions>WIN32;NDEBUG;_WINDOWS;_PHLIB_;%(PreprocessorDefinitions)</PreprocessorDefinitions>\n      <StringPooling>true</StringPooling>\n      <RuntimeLibrary>MultiThreaded</RuntimeLibrary>\n      <BufferSecurityCheck>false</BufferSecurityCheck>\n      <FunctionLevelLinking>true</FunctionLevelLinking>\n      <WarningLevel>Level3</WarningLevel>\n      <DebugInformationFormat>ProgramDatabase</DebugInformationFormat>\n      <CallingConvention>StdCall</CallingConvention>\n      <TreatWarningAsError>true</TreatWarningAsError>\n      <MultiProcessorCompilation>true</MultiProcessorCompilation>\n      <EnableEnhancedInstructionSet>StreamingSIMDExtensions</EnableEnhancedInstructionSet>\n    </ClCompile>\n  </ItemDefinitionGroup>\n  <ItemDefinitionGroup Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\">\n    <ClCompile>\n      <Optimization>MaxSpeed</Optimization>\n      <IntrinsicFunctions>true</IntrinsicFunctions>\n      <AdditionalIncludeDirectories>$(SolutionDir)third_party\\phnt\\include;include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>\n      <PreprocessorDefinitions>WIN64;NDEBUG;_WINDOWS;_PHLIB_;%(PreprocessorDefinitions)</PreprocessorDefinitions>\n      <StringPooling>true</StringPooling>\n      <RuntimeLibrary>MultiThreaded</RuntimeLibrary>\n      <BufferSecurityCheck>false</BufferSecurityCheck>\n      <FunctionLevelLinking>true</FunctionLevelLinking>\n      <WarningLevel>Level3</WarningLevel>\n      <DebugInformationFormat>ProgramDatabase</DebugInformationFormat>\n      <CallingConvention>StdCall</CallingConvention>\n      <TreatWarningAsError>true</TreatWarningAsError>\n      <MultiProcessorCompilation>true</MultiProcessorCompilation>\n    </ClCompile>\n  </ItemDefinitionGroup>\n  <ItemDefinitionGroup Condition=\"'$(Configuration)|$(Platform)'=='Appx|x64'\">\n    <ClCompile>\n      <Optimization>MaxSpeed</Optimization>\n      <IntrinsicFunctions>true</IntrinsicFunctions>\n      <AdditionalIncludeDirectories>$(SolutionDir)third_party\\phnt\\include;include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>\n      <PreprocessorDefinitions>WIN64;NDEBUG;_WINDOWS;_PHLIB_;%(PreprocessorDefinitions)</PreprocessorDefinitions>\n      <StringPooling>true</StringPooling>\n      <RuntimeLibrary>MultiThreaded</RuntimeLibrary>\n      <BufferSecurityCheck>false</BufferSecurityCheck>\n      <FunctionLevelLinking>true</FunctionLevelLinking>\n      <WarningLevel>Level3</WarningLevel>\n      <DebugInformationFormat>ProgramDatabase</DebugInformationFormat>\n      <CallingConvention>StdCall</CallingConvention>\n      <TreatWarningAsError>true</TreatWarningAsError>\n      <MultiProcessorCompilation>true</MultiProcessorCompilation>\n    </ClCompile>\n  </ItemDefinitionGroup>\n  <ItemGroup>\n    <ClCompile Include=\"apiimport.c\" />\n    <ClCompile Include=\"appresolver.c\" />\n    <ClCompile Include=\"avltree.c\" />\n    <ClCompile Include=\"basesup.c\" />\n    <ClCompile Include=\"circbuf.c\" />\n    <ClCompile Include=\"colorbox.c\" />\n    <ClCompile Include=\"cpysave.c\" />\n    <ClCompile Include=\"data.c\" />\n    <ClCompile Include=\"dspick.c\" />\n    <ClCompile Include=\"emenu.c\" />\n    <ClCompile Include=\"error.c\" />\n    <ClCompile Include=\"extlv.c\" />\n    <ClCompile Include=\"fastlock.c\" />\n    <ClCompile Include=\"filepool.c\" />\n    <ClCompile Include=\"format.c\" />\n    <ClCompile Include=\"global.c\" />\n    <ClCompile Include=\"graph.c\" />\n    <ClCompile Include=\"guisup.c\" />\n    <ClCompile Include=\"handle.c\" />\n    <ClCompile Include=\"hexedit.c\" />\n    <ClCompile Include=\"hndlinfo.c\" />\n    <ClCompile Include=\"icotobmp.c\" />\n    <ClCompile Include=\"filestream.c\" />\n    <ClCompile Include=\"json.c\" />\n    <ClCompile Include=\"jsonc\\arraylist.c\" />\n    <ClCompile Include=\"jsonc\\debug.c\" />\n    <ClCompile Include=\"jsonc\\json_c_version.c\" />\n    <ClCompile Include=\"jsonc\\json_object.c\" />\n    <ClCompile Include=\"jsonc\\json_object_iterator.c\" />\n    <ClCompile Include=\"jsonc\\json_tokener.c\" />\n    <ClCompile Include=\"jsonc\\json_util.c\" />\n    <ClCompile Include=\"jsonc\\libjson.c\" />\n    <ClCompile Include=\"jsonc\\linkhash.c\" />\n    <ClCompile Include=\"jsonc\\printbuf.c\" />\n    <ClCompile Include=\"jsonc\\random_seed.c\" />\n    <ClCompile Include=\"kph.c\" />\n    <ClCompile Include=\"kphdata.c\" />\n    <ClCompile Include=\"lsasup.c\" />\n    <ClCompile Include=\"mapexlf.c\" />\n    <ClCompile Include=\"mapimg.c\" />\n    <ClCompile Include=\"maplib.c\" />\n    <ClCompile Include=\"md5.c\" />\n    <ClCompile Include=\"mxml\\mxml-attr.c\" />\n    <ClCompile Include=\"mxml\\mxml-entity.c\" />\n    <ClCompile Include=\"mxml\\mxml-file.c\" />\n    <ClCompile Include=\"mxml\\mxml-index.c\" />\n    <ClCompile Include=\"mxml\\mxml-node.c\" />\n    <ClCompile Include=\"mxml\\mxml-private.c\" />\n    <ClCompile Include=\"mxml\\mxml-search.c\" />\n    <ClCompile Include=\"mxml\\mxml-set.c\" />\n    <ClCompile Include=\"mxml\\mxml-string.c\" />\n    <ClCompile Include=\"native.c\" />\n    <ClCompile Include=\"provider.c\" />\n    <ClCompile Include=\"queuedlock.c\" />\n    <ClCompile Include=\"ref.c\" />\n    <ClCompile Include=\"secdata.c\" />\n    <ClCompile Include=\"secedit.c\" />\n    <ClCompile Include=\"settings.c\" />\n    <ClCompile Include=\"sha.c\" />\n    <ClCompile Include=\"sha256.c\" />\n    <ClCompile Include=\"util.c\" />\n    <ClCompile Include=\"svcsup.c\" />\n    <ClCompile Include=\"symprv.c\" />\n    <ClCompile Include=\"sync.c\" />\n    <ClCompile Include=\"treenew.c\" />\n    <ClCompile Include=\"verify.c\" />\n    <ClCompile Include=\"workqueue.c\" />\n  </ItemGroup>\n  <ItemGroup>\n    <ClInclude Include=\"include\\apiimport.h\" />\n    <ClInclude Include=\"include\\appresolver.h\" />\n    <ClInclude Include=\"include\\appresolverp.h\" />\n    <ClInclude Include=\"include\\cpysave.h\" />\n    <ClInclude Include=\"include\\exlf.h\" />\n    <ClInclude Include=\"include\\filepool.h\" />\n    <ClInclude Include=\"include\\filepoolp.h\" />\n    <ClInclude Include=\"include\\filestream.h\" />\n    <ClInclude Include=\"include\\handle.h\" />\n    <ClInclude Include=\"include\\hndlinfo.h\" />\n    <ClInclude Include=\"include\\json.h\" />\n    <ClInclude Include=\"include\\kphapi.h\" />\n    <ClInclude Include=\"include\\kphuserp.h\" />\n    <ClInclude Include=\"include\\lsasup.h\" />\n    <ClInclude Include=\"include\\mapimg.h\" />\n    <ClInclude Include=\"include\\phbasesup.h\" />\n    <ClInclude Include=\"include\\phconfig.h\" />\n    <ClInclude Include=\"include\\phdata.h\" />\n    <ClInclude Include=\"include\\phintrnl.h\" />\n    <ClInclude Include=\"include\\phnative.h\" />\n    <ClInclude Include=\"include\\phnativeinl.h\" />\n    <ClInclude Include=\"include\\circbuf.h\" />\n    <ClInclude Include=\"include\\circbuf_h.h\" />\n    <ClInclude Include=\"circbuf_i.h\" />\n    <ClInclude Include=\"include\\colorbox.h\" />\n    <ClInclude Include=\"include\\phutil.h\" />\n    <ClInclude Include=\"include\\provider.h\" />\n    <ClInclude Include=\"include\\secedit.h\" />\n    <ClInclude Include=\"include\\settings.h\" />\n    <ClInclude Include=\"include\\svcsup.h\" />\n    <ClInclude Include=\"include\\symprvp.h\" />\n    <ClInclude Include=\"include\\treenew.h\" />\n    <ClInclude Include=\"include\\treenewp.h\" />\n    <ClInclude Include=\"include\\verify.h\" />\n    <ClInclude Include=\"include\\dltmgr.h\" />\n    <ClInclude Include=\"include\\dspick.h\" />\n    <ClInclude Include=\"include\\emenu.h\" />\n    <ClInclude Include=\"include\\fastlock.h\" />\n    <ClInclude Include=\"format_i.h\" />\n    <ClInclude Include=\"include\\graph.h\" />\n    <ClInclude Include=\"include\\guisupp.h\" />\n    <ClInclude Include=\"include\\handlep.h\" />\n    <ClInclude Include=\"include\\hexedit.h\" />\n    <ClInclude Include=\"include\\hexeditp.h\" />\n    <ClInclude Include=\"include\\filestreamp.h\" />\n    <ClInclude Include=\"include\\kphuser.h\" />\n    <ClInclude Include=\"jsonc\\arraylist.h\" />\n    <ClInclude Include=\"jsonc\\bits.h\" />\n    <ClInclude Include=\"jsonc\\config.h\" />\n    <ClInclude Include=\"jsonc\\debug.h\" />\n    <ClInclude Include=\"jsonc\\json.h\" />\n    <ClInclude Include=\"jsonc\\json_config.h\" />\n    <ClInclude Include=\"jsonc\\json_c_version.h\" />\n    <ClInclude Include=\"jsonc\\json_inttypes.h\" />\n    <ClInclude Include=\"jsonc\\json_object.h\" />\n    <ClInclude Include=\"jsonc\\json_object_iterator.h\" />\n    <ClInclude Include=\"jsonc\\json_object_private.h\" />\n    <ClInclude Include=\"jsonc\\json_tokener.h\" />\n    <ClInclude Include=\"jsonc\\json_util.h\" />\n    <ClInclude Include=\"jsonc\\linkhash.h\" />\n    <ClInclude Include=\"jsonc\\math_compat.h\" />\n    <ClInclude Include=\"jsonc\\printbuf.h\" />\n    <ClInclude Include=\"jsonc\\random_seed.h\" />\n    <ClInclude Include=\"md5.h\" />\n    <ClInclude Include=\"include\\ph.h\" />\n    <ClInclude Include=\"include\\phbase.h\" />\n    <ClInclude Include=\"include\\guisup.h\" />\n    <ClInclude Include=\"include\\phnet.h\" />\n    <ClInclude Include=\"include\\phsup.h\" />\n    <ClInclude Include=\"include\\queuedlock.h\" />\n    <ClInclude Include=\"include\\ref.h\" />\n    <ClInclude Include=\"include\\refp.h\" />\n    <ClInclude Include=\"include\\seceditp.h\" />\n    <ClInclude Include=\"mxml\\config.h\" />\n    <ClInclude Include=\"mxml\\mxml-private.h\" />\n    <ClInclude Include=\"mxml\\mxml.h\" />\n    <ClInclude Include=\"sha.h\" />\n    <ClInclude Include=\"include\\symprv.h\" />\n    <ClInclude Include=\"include\\templ.h\" />\n    <ClInclude Include=\"include\\verifyp.h\" />\n    <ClInclude Include=\"include\\workqueue.h\" />\n    <ClInclude Include=\"include\\workqueuep.h\" />\n    <ClInclude Include=\"sha256.h\" />\n  </ItemGroup>\n  <Import Project=\"$(VCTargetsPath)\\Microsoft.Cpp.targets\" />\n  <ImportGroup Label=\"ExtensionTargets\">\n  </ImportGroup>\n</Project>"
  },
  {
    "path": "third_party/phlib/phlib.vcxproj.filters",
    "content": "﻿<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<Project ToolsVersion=\"4.0\" xmlns=\"http://schemas.microsoft.com/developer/msbuild/2003\">\n  <ItemGroup>\n    <Filter Include=\"Source Files\">\n      <UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier>\n      <Extensions>cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx</Extensions>\n    </Filter>\n    <Filter Include=\"Header Files\">\n      <UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier>\n      <Extensions>h;hpp;hxx;hm;inl;inc;xsd</Extensions>\n    </Filter>\n    <Filter Include=\"Mini-XML\">\n      <UniqueIdentifier>{7d0c2da2-811d-4844-9704-0c87067c7be1}</UniqueIdentifier>\n    </Filter>\n    <Filter Include=\"Mini-XML\\Headers\">\n      <UniqueIdentifier>{874b89c3-fb60-46f3-a62c-49ac88e3026d}</UniqueIdentifier>\n    </Filter>\n    <Filter Include=\"Json-C\">\n      <UniqueIdentifier>{fd6c74dc-d93e-4dd1-9a8b-5bdf525e0709}</UniqueIdentifier>\n    </Filter>\n    <Filter Include=\"Json-C\\Headers\">\n      <UniqueIdentifier>{4f0e2a3e-3009-4e13-8d38-e33c46d00044}</UniqueIdentifier>\n    </Filter>\n  </ItemGroup>\n  <ItemGroup>\n    <ClCompile Include=\"basesup.c\">\n      <Filter>Source Files</Filter>\n    </ClCompile>\n    <ClCompile Include=\"circbuf.c\">\n      <Filter>Source Files</Filter>\n    </ClCompile>\n    <ClCompile Include=\"colorbox.c\">\n      <Filter>Source Files</Filter>\n    </ClCompile>\n    <ClCompile Include=\"data.c\">\n      <Filter>Source Files</Filter>\n    </ClCompile>\n    <ClCompile Include=\"dspick.c\">\n      <Filter>Source Files</Filter>\n    </ClCompile>\n    <ClCompile Include=\"emenu.c\">\n      <Filter>Source Files</Filter>\n    </ClCompile>\n    <ClCompile Include=\"error.c\">\n      <Filter>Source Files</Filter>\n    </ClCompile>\n    <ClCompile Include=\"extlv.c\">\n      <Filter>Source Files</Filter>\n    </ClCompile>\n    <ClCompile Include=\"fastlock.c\">\n      <Filter>Source Files</Filter>\n    </ClCompile>\n    <ClCompile Include=\"format.c\">\n      <Filter>Source Files</Filter>\n    </ClCompile>\n    <ClCompile Include=\"global.c\">\n      <Filter>Source Files</Filter>\n    </ClCompile>\n    <ClCompile Include=\"graph.c\">\n      <Filter>Source Files</Filter>\n    </ClCompile>\n    <ClCompile Include=\"guisup.c\">\n      <Filter>Source Files</Filter>\n    </ClCompile>\n    <ClCompile Include=\"handle.c\">\n      <Filter>Source Files</Filter>\n    </ClCompile>\n    <ClCompile Include=\"hexedit.c\">\n      <Filter>Source Files</Filter>\n    </ClCompile>\n    <ClCompile Include=\"hndlinfo.c\">\n      <Filter>Source Files</Filter>\n    </ClCompile>\n    <ClCompile Include=\"icotobmp.c\">\n      <Filter>Source Files</Filter>\n    </ClCompile>\n    <ClCompile Include=\"kph.c\">\n      <Filter>Source Files</Filter>\n    </ClCompile>\n    <ClCompile Include=\"mapimg.c\">\n      <Filter>Source Files</Filter>\n    </ClCompile>\n    <ClCompile Include=\"maplib.c\">\n      <Filter>Source Files</Filter>\n    </ClCompile>\n    <ClCompile Include=\"md5.c\">\n      <Filter>Source Files</Filter>\n    </ClCompile>\n    <ClCompile Include=\"native.c\">\n      <Filter>Source Files</Filter>\n    </ClCompile>\n    <ClCompile Include=\"provider.c\">\n      <Filter>Source Files</Filter>\n    </ClCompile>\n    <ClCompile Include=\"queuedlock.c\">\n      <Filter>Source Files</Filter>\n    </ClCompile>\n    <ClCompile Include=\"ref.c\">\n      <Filter>Source Files</Filter>\n    </ClCompile>\n    <ClCompile Include=\"secdata.c\">\n      <Filter>Source Files</Filter>\n    </ClCompile>\n    <ClCompile Include=\"secedit.c\">\n      <Filter>Source Files</Filter>\n    </ClCompile>\n    <ClCompile Include=\"sha.c\">\n      <Filter>Source Files</Filter>\n    </ClCompile>\n    <ClCompile Include=\"svcsup.c\">\n      <Filter>Source Files</Filter>\n    </ClCompile>\n    <ClCompile Include=\"symprv.c\">\n      <Filter>Source Files</Filter>\n    </ClCompile>\n    <ClCompile Include=\"sync.c\">\n      <Filter>Source Files</Filter>\n    </ClCompile>\n    <ClCompile Include=\"verify.c\">\n      <Filter>Source Files</Filter>\n    </ClCompile>\n    <ClCompile Include=\"workqueue.c\">\n      <Filter>Source Files</Filter>\n    </ClCompile>\n    <ClCompile Include=\"cpysave.c\">\n      <Filter>Source Files</Filter>\n    </ClCompile>\n    <ClCompile Include=\"filepool.c\">\n      <Filter>Source Files</Filter>\n    </ClCompile>\n    <ClCompile Include=\"treenew.c\">\n      <Filter>Source Files</Filter>\n    </ClCompile>\n    <ClCompile Include=\"kphdata.c\">\n      <Filter>Source Files</Filter>\n    </ClCompile>\n    <ClCompile Include=\"apiimport.c\">\n      <Filter>Source Files</Filter>\n    </ClCompile>\n    <ClCompile Include=\"avltree.c\">\n      <Filter>Source Files</Filter>\n    </ClCompile>\n    <ClCompile Include=\"filestream.c\">\n      <Filter>Source Files</Filter>\n    </ClCompile>\n    <ClCompile Include=\"lsasup.c\">\n      <Filter>Source Files</Filter>\n    </ClCompile>\n    <ClCompile Include=\"util.c\">\n      <Filter>Source Files</Filter>\n    </ClCompile>\n    <ClCompile Include=\"sha256.c\">\n      <Filter>Source Files</Filter>\n    </ClCompile>\n    <ClCompile Include=\"settings.c\">\n      <Filter>Source Files</Filter>\n    </ClCompile>\n    <ClCompile Include=\"mxml\\mxml-attr.c\">\n      <Filter>Mini-XML</Filter>\n    </ClCompile>\n    <ClCompile Include=\"mxml\\mxml-entity.c\">\n      <Filter>Mini-XML</Filter>\n    </ClCompile>\n    <ClCompile Include=\"mxml\\mxml-file.c\">\n      <Filter>Mini-XML</Filter>\n    </ClCompile>\n    <ClCompile Include=\"mxml\\mxml-index.c\">\n      <Filter>Mini-XML</Filter>\n    </ClCompile>\n    <ClCompile Include=\"mxml\\mxml-node.c\">\n      <Filter>Mini-XML</Filter>\n    </ClCompile>\n    <ClCompile Include=\"mxml\\mxml-private.c\">\n      <Filter>Mini-XML</Filter>\n    </ClCompile>\n    <ClCompile Include=\"mxml\\mxml-search.c\">\n      <Filter>Mini-XML</Filter>\n    </ClCompile>\n    <ClCompile Include=\"mxml\\mxml-set.c\">\n      <Filter>Mini-XML</Filter>\n    </ClCompile>\n    <ClCompile Include=\"mxml\\mxml-string.c\">\n      <Filter>Mini-XML</Filter>\n    </ClCompile>\n    <ClCompile Include=\"jsonc\\arraylist.c\">\n      <Filter>Json-C</Filter>\n    </ClCompile>\n    <ClCompile Include=\"jsonc\\debug.c\">\n      <Filter>Json-C</Filter>\n    </ClCompile>\n    <ClCompile Include=\"json.c\">\n      <Filter>Json-C</Filter>\n    </ClCompile>\n    <ClCompile Include=\"jsonc\\json_c_version.c\">\n      <Filter>Json-C</Filter>\n    </ClCompile>\n    <ClCompile Include=\"jsonc\\json_object.c\">\n      <Filter>Json-C</Filter>\n    </ClCompile>\n    <ClCompile Include=\"jsonc\\json_object_iterator.c\">\n      <Filter>Json-C</Filter>\n    </ClCompile>\n    <ClCompile Include=\"jsonc\\json_tokener.c\">\n      <Filter>Json-C</Filter>\n    </ClCompile>\n    <ClCompile Include=\"jsonc\\json_util.c\">\n      <Filter>Json-C</Filter>\n    </ClCompile>\n    <ClCompile Include=\"jsonc\\libjson.c\">\n      <Filter>Json-C</Filter>\n    </ClCompile>\n    <ClCompile Include=\"jsonc\\linkhash.c\">\n      <Filter>Json-C</Filter>\n    </ClCompile>\n    <ClCompile Include=\"jsonc\\random_seed.c\">\n      <Filter>Json-C</Filter>\n    </ClCompile>\n    <ClCompile Include=\"jsonc\\printbuf.c\">\n      <Filter>Json-C</Filter>\n    </ClCompile>\n    <ClCompile Include=\"mapexlf.c\">\n      <Filter>Source Files</Filter>\n    </ClCompile>\n    <ClCompile Include=\"appresolver.c\">\n      <Filter>Source Files</Filter>\n    </ClCompile>\n  </ItemGroup>\n  <ItemGroup>\n    <ClInclude Include=\"include\\circbuf.h\">\n      <Filter>Header Files</Filter>\n    </ClInclude>\n    <ClInclude Include=\"include\\circbuf_h.h\">\n      <Filter>Header Files</Filter>\n    </ClInclude>\n    <ClInclude Include=\"circbuf_i.h\">\n      <Filter>Header Files</Filter>\n    </ClInclude>\n    <ClInclude Include=\"include\\colorbox.h\">\n      <Filter>Header Files</Filter>\n    </ClInclude>\n    <ClInclude Include=\"include\\dltmgr.h\">\n      <Filter>Header Files</Filter>\n    </ClInclude>\n    <ClInclude Include=\"include\\dspick.h\">\n      <Filter>Header Files</Filter>\n    </ClInclude>\n    <ClInclude Include=\"include\\emenu.h\">\n      <Filter>Header Files</Filter>\n    </ClInclude>\n    <ClInclude Include=\"include\\fastlock.h\">\n      <Filter>Header Files</Filter>\n    </ClInclude>\n    <ClInclude Include=\"format_i.h\">\n      <Filter>Header Files</Filter>\n    </ClInclude>\n    <ClInclude Include=\"include\\graph.h\">\n      <Filter>Header Files</Filter>\n    </ClInclude>\n    <ClInclude Include=\"include\\guisupp.h\">\n      <Filter>Header Files</Filter>\n    </ClInclude>\n    <ClInclude Include=\"include\\handlep.h\">\n      <Filter>Header Files</Filter>\n    </ClInclude>\n    <ClInclude Include=\"include\\hexedit.h\">\n      <Filter>Header Files</Filter>\n    </ClInclude>\n    <ClInclude Include=\"include\\hexeditp.h\">\n      <Filter>Header Files</Filter>\n    </ClInclude>\n    <ClInclude Include=\"include\\ph.h\">\n      <Filter>Header Files</Filter>\n    </ClInclude>\n    <ClInclude Include=\"include\\phbase.h\">\n      <Filter>Header Files</Filter>\n    </ClInclude>\n    <ClInclude Include=\"include\\phnet.h\">\n      <Filter>Header Files</Filter>\n    </ClInclude>\n    <ClInclude Include=\"include\\phsup.h\">\n      <Filter>Header Files</Filter>\n    </ClInclude>\n    <ClInclude Include=\"include\\queuedlock.h\">\n      <Filter>Header Files</Filter>\n    </ClInclude>\n    <ClInclude Include=\"include\\ref.h\">\n      <Filter>Header Files</Filter>\n    </ClInclude>\n    <ClInclude Include=\"include\\refp.h\">\n      <Filter>Header Files</Filter>\n    </ClInclude>\n    <ClInclude Include=\"include\\seceditp.h\">\n      <Filter>Header Files</Filter>\n    </ClInclude>\n    <ClInclude Include=\"include\\symprv.h\">\n      <Filter>Header Files</Filter>\n    </ClInclude>\n    <ClInclude Include=\"include\\templ.h\">\n      <Filter>Header Files</Filter>\n    </ClInclude>\n    <ClInclude Include=\"include\\verifyp.h\">\n      <Filter>Header Files</Filter>\n    </ClInclude>\n    <ClInclude Include=\"include\\phintrnl.h\">\n      <Filter>Header Files</Filter>\n    </ClInclude>\n    <ClInclude Include=\"include\\kphapi.h\">\n      <Filter>Header Files</Filter>\n    </ClInclude>\n    <ClInclude Include=\"include\\kphuser.h\">\n      <Filter>Header Files</Filter>\n    </ClInclude>\n    <ClInclude Include=\"include\\cpysave.h\">\n      <Filter>Header Files</Filter>\n    </ClInclude>\n    <ClInclude Include=\"include\\filepool.h\">\n      <Filter>Header Files</Filter>\n    </ClInclude>\n    <ClInclude Include=\"include\\filepoolp.h\">\n      <Filter>Header Files</Filter>\n    </ClInclude>\n    <ClInclude Include=\"include\\treenew.h\">\n      <Filter>Header Files</Filter>\n    </ClInclude>\n    <ClInclude Include=\"include\\treenewp.h\">\n      <Filter>Header Files</Filter>\n    </ClInclude>\n    <ClInclude Include=\"include\\verify.h\">\n      <Filter>Header Files</Filter>\n    </ClInclude>\n    <ClInclude Include=\"include\\secedit.h\">\n      <Filter>Header Files</Filter>\n    </ClInclude>\n    <ClInclude Include=\"include\\symprvp.h\">\n      <Filter>Header Files</Filter>\n    </ClInclude>\n    <ClInclude Include=\"include\\apiimport.h\">\n      <Filter>Header Files</Filter>\n    </ClInclude>\n    <ClInclude Include=\"include\\handle.h\">\n      <Filter>Header Files</Filter>\n    </ClInclude>\n    <ClInclude Include=\"include\\workqueue.h\">\n      <Filter>Header Files</Filter>\n    </ClInclude>\n    <ClInclude Include=\"include\\mapimg.h\">\n      <Filter>Header Files</Filter>\n    </ClInclude>\n    <ClInclude Include=\"include\\workqueuep.h\">\n      <Filter>Header Files</Filter>\n    </ClInclude>\n    <ClInclude Include=\"include\\filestreamp.h\">\n      <Filter>Header Files</Filter>\n    </ClInclude>\n    <ClInclude Include=\"include\\filestream.h\">\n      <Filter>Header Files</Filter>\n    </ClInclude>\n    <ClInclude Include=\"include\\hndlinfo.h\">\n      <Filter>Header Files</Filter>\n    </ClInclude>\n    <ClInclude Include=\"include\\provider.h\">\n      <Filter>Header Files</Filter>\n    </ClInclude>\n    <ClInclude Include=\"include\\phdata.h\">\n      <Filter>Header Files</Filter>\n    </ClInclude>\n    <ClInclude Include=\"include\\phconfig.h\">\n      <Filter>Header Files</Filter>\n    </ClInclude>\n    <ClInclude Include=\"include\\phbasesup.h\">\n      <Filter>Header Files</Filter>\n    </ClInclude>\n    <ClInclude Include=\"include\\lsasup.h\">\n      <Filter>Header Files</Filter>\n    </ClInclude>\n    <ClInclude Include=\"include\\phnativeinl.h\">\n      <Filter>Header Files</Filter>\n    </ClInclude>\n    <ClInclude Include=\"include\\phnative.h\">\n      <Filter>Header Files</Filter>\n    </ClInclude>\n    <ClInclude Include=\"include\\svcsup.h\">\n      <Filter>Header Files</Filter>\n    </ClInclude>\n    <ClInclude Include=\"include\\phutil.h\">\n      <Filter>Header Files</Filter>\n    </ClInclude>\n    <ClInclude Include=\"md5.h\">\n      <Filter>Header Files</Filter>\n    </ClInclude>\n    <ClInclude Include=\"sha.h\">\n      <Filter>Header Files</Filter>\n    </ClInclude>\n    <ClInclude Include=\"include\\guisup.h\">\n      <Filter>Header Files</Filter>\n    </ClInclude>\n    <ClInclude Include=\"include\\kphuserp.h\">\n      <Filter>Header Files</Filter>\n    </ClInclude>\n    <ClInclude Include=\"sha256.h\">\n      <Filter>Header Files</Filter>\n    </ClInclude>\n    <ClInclude Include=\"include\\settings.h\">\n      <Filter>Header Files</Filter>\n    </ClInclude>\n    <ClInclude Include=\"mxml\\config.h\">\n      <Filter>Mini-XML\\Headers</Filter>\n    </ClInclude>\n    <ClInclude Include=\"mxml\\mxml-private.h\">\n      <Filter>Mini-XML\\Headers</Filter>\n    </ClInclude>\n    <ClInclude Include=\"mxml\\mxml.h\">\n      <Filter>Mini-XML\\Headers</Filter>\n    </ClInclude>\n    <ClInclude Include=\"jsonc\\arraylist.h\">\n      <Filter>Json-C\\Headers</Filter>\n    </ClInclude>\n    <ClInclude Include=\"jsonc\\bits.h\">\n      <Filter>Json-C\\Headers</Filter>\n    </ClInclude>\n    <ClInclude Include=\"jsonc\\config.h\">\n      <Filter>Json-C\\Headers</Filter>\n    </ClInclude>\n    <ClInclude Include=\"jsonc\\debug.h\">\n      <Filter>Json-C\\Headers</Filter>\n    </ClInclude>\n    <ClInclude Include=\"jsonc\\json_c_version.h\">\n      <Filter>Json-C\\Headers</Filter>\n    </ClInclude>\n    <ClInclude Include=\"jsonc\\json_config.h\">\n      <Filter>Json-C\\Headers</Filter>\n    </ClInclude>\n    <ClInclude Include=\"jsonc\\json_inttypes.h\">\n      <Filter>Json-C\\Headers</Filter>\n    </ClInclude>\n    <ClInclude Include=\"jsonc\\json_object.h\">\n      <Filter>Json-C\\Headers</Filter>\n    </ClInclude>\n    <ClInclude Include=\"jsonc\\json_object_iterator.h\">\n      <Filter>Json-C\\Headers</Filter>\n    </ClInclude>\n    <ClInclude Include=\"jsonc\\json_object_private.h\">\n      <Filter>Json-C\\Headers</Filter>\n    </ClInclude>\n    <ClInclude Include=\"jsonc\\json_tokener.h\">\n      <Filter>Json-C\\Headers</Filter>\n    </ClInclude>\n    <ClInclude Include=\"jsonc\\json_util.h\">\n      <Filter>Json-C\\Headers</Filter>\n    </ClInclude>\n    <ClInclude Include=\"jsonc\\linkhash.h\">\n      <Filter>Json-C\\Headers</Filter>\n    </ClInclude>\n    <ClInclude Include=\"jsonc\\math_compat.h\">\n      <Filter>Json-C\\Headers</Filter>\n    </ClInclude>\n    <ClInclude Include=\"jsonc\\printbuf.h\">\n      <Filter>Json-C\\Headers</Filter>\n    </ClInclude>\n    <ClInclude Include=\"jsonc\\random_seed.h\">\n      <Filter>Json-C\\Headers</Filter>\n    </ClInclude>\n    <ClInclude Include=\"jsonc\\json.h\">\n      <Filter>Json-C\\Headers</Filter>\n    </ClInclude>\n    <ClInclude Include=\"include\\json.h\">\n      <Filter>Header Files</Filter>\n    </ClInclude>\n    <ClInclude Include=\"include\\exlf.h\">\n      <Filter>Header Files</Filter>\n    </ClInclude>\n    <ClInclude Include=\"include\\appresolver.h\">\n      <Filter>Header Files</Filter>\n    </ClInclude>\n    <ClInclude Include=\"include\\appresolverp.h\">\n      <Filter>Header Files</Filter>\n    </ClInclude>\n  </ItemGroup>\n</Project>"
  },
  {
    "path": "third_party/phlib/provider.c",
    "content": "/*\n * Process Hacker -\n *   provider system\n *\n * Copyright (C) 2009-2016 wj32\n *\n * This file is part of Process Hacker.\n *\n * Process Hacker is free software; you can redistribute it and/or modify\n * it under the terms of the GNU General Public License as published by\n * the Free Software Foundation, either version 3 of the License, or\n * (at your option) any later version.\n *\n * Process Hacker is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n * GNU General Public License for more details.\n *\n * You should have received a copy of the GNU General Public License\n * along with Process Hacker.  If not, see <http://www.gnu.org/licenses/>.\n */\n\n/*\n * Provider objects allow a function to be executed periodically. This is managed by a\n * synchronization timer object which is signaled periodically. The use of a timer object as opposed\n * to a simple sleep call means that the length of time a provider function takes to execute has no\n * effect on the interval between runs.\n *\n * In contrast to callback objects, the context passed to provider functions must be\n * reference-counted objects. This means that it is not guaranteed that the function will not be in\n * execution after the unregister operation is complete. However, the since the context object is\n * reference-counted, there are no safety issues.\n *\n * Providers can be boosted, which causes them to be run immediately ignoring the interval. This is\n * separate to the periodic runs, and does not cause the next periodic run to be missed. Providers,\n * even when boosted, always run on the same provider thread. The other option would be to have the\n * boosting thread run the provider function directly, which would involve unnecessary blocking and\n * synchronization.\n */\n\n#include <ph.h>\n#include <provider.h>\n\n#ifdef DEBUG\nPPH_LIST PhDbgProviderList;\nPH_QUEUED_LOCK PhDbgProviderListLock = PH_QUEUED_LOCK_INIT;\n#endif\n\n/**\n * Initializes a provider thread.\n *\n * \\param ProviderThread A pointer to a provider thread object.\n * \\param Interval The interval between each run, in milliseconds.\n */\nVOID PhInitializeProviderThread(\n    _Out_ PPH_PROVIDER_THREAD ProviderThread,\n    _In_ ULONG Interval\n    )\n{\n    ProviderThread->ThreadHandle = NULL;\n    ProviderThread->TimerHandle = NULL;\n    ProviderThread->Interval = Interval;\n    ProviderThread->State = ProviderThreadStopped;\n\n    PhInitializeQueuedLock(&ProviderThread->Lock);\n    InitializeListHead(&ProviderThread->ListHead);\n    ProviderThread->BoostCount = 0;\n\n#ifdef DEBUG\n    PhAcquireQueuedLockExclusive(&PhDbgProviderListLock);\n    if (!PhDbgProviderList)\n        PhDbgProviderList = PhCreateList(4);\n    PhAddItemList(PhDbgProviderList, ProviderThread);\n    PhReleaseQueuedLockExclusive(&PhDbgProviderListLock);\n#endif\n}\n\n/**\n * Frees resources used by a provider thread.\n *\n * \\param ProviderThread A pointer to a provider thread object.\n */\nVOID PhDeleteProviderThread(\n    _Inout_ PPH_PROVIDER_THREAD ProviderThread\n    )\n{\n#ifdef DEBUG\n    ULONG index;\n#endif\n    // Nothing\n\n#ifdef DEBUG\n    PhAcquireQueuedLockExclusive(&PhDbgProviderListLock);\n    if ((index = PhFindItemList(PhDbgProviderList, ProviderThread)) != -1)\n        PhRemoveItemList(PhDbgProviderList, index);\n    PhReleaseQueuedLockExclusive(&PhDbgProviderListLock);\n#endif\n}\n\nNTSTATUS NTAPI PhpProviderThreadStart(\n    _In_ PVOID Parameter\n    )\n{\n    PH_AUTO_POOL autoPool;\n    PPH_PROVIDER_THREAD providerThread = (PPH_PROVIDER_THREAD)Parameter;\n    NTSTATUS status = STATUS_SUCCESS;\n    PLIST_ENTRY listEntry;\n    PPH_PROVIDER_REGISTRATION registration;\n    PPH_PROVIDER_FUNCTION providerFunction;\n    PVOID object;\n    LIST_ENTRY tempListHead;\n\n    PhInitializeAutoPool(&autoPool);\n\n    while (providerThread->State != ProviderThreadStopping)\n    {\n        // Keep removing and executing providers from the list until there are no more. Each removed\n        // provider will be placed on the temporary list. After this is done, all providers on the\n        // temporary list will be re-added to the list again.\n        //\n        // The key to this working safely with the other functions (boost, register, unregister) is\n        // that at all times when the mutex is not acquired every single provider must be in a list\n        // (main list or the temp list).\n\n        InitializeListHead(&tempListHead);\n\n        PhAcquireQueuedLockExclusive(&providerThread->Lock);\n\n        // Main loop.\n\n        // We check the status variable for STATUS_ALERTED, which means that someone is requesting\n        // that a provider be boosted. Note that if they alert this thread while we are not waiting\n        // on the timer, when we do perform the wait it will return immediately with STATUS_ALERTED.\n\n        while (TRUE)\n        {\n            if (status == STATUS_ALERTED)\n            {\n                // Check if we have any more providers to boost. Note that this always works because\n                // boosted providers are always in front of normal providers. Therefore we will\n                // never mistakenly boost normal providers.\n\n                if (providerThread->BoostCount == 0)\n                    break;\n            }\n\n            listEntry = RemoveHeadList(&providerThread->ListHead);\n\n            if (listEntry == &providerThread->ListHead)\n                break;\n\n            registration = CONTAINING_RECORD(listEntry, PH_PROVIDER_REGISTRATION, ListEntry);\n\n            // Add the provider to the temp list.\n            InsertTailList(&tempListHead, listEntry);\n\n            if (status != STATUS_ALERTED)\n            {\n                if (!registration->Enabled || registration->Unregistering)\n                    continue;\n            }\n            else\n            {\n                // If we're boosting providers, we don't care if they are enabled or not. However,\n                // we have to make sure any providers which are being unregistered get a chance to\n                // fix the boost count.\n\n                if (registration->Unregistering)\n                {\n                    PhReleaseQueuedLockExclusive(&providerThread->Lock);\n                    PhAcquireQueuedLockExclusive(&providerThread->Lock);\n\n                    continue;\n                }\n            }\n\n            if (status == STATUS_ALERTED)\n            {\n                assert(registration->Boosting);\n                registration->Boosting = FALSE;\n                providerThread->BoostCount--;\n            }\n\n            providerFunction = registration->Function;\n            object = registration->Object;\n\n            if (object)\n                PhReferenceObject(object);\n\n            registration->RunId++;\n\n            PhReleaseQueuedLockExclusive(&providerThread->Lock);\n            providerFunction(object);\n            PhDrainAutoPool(&autoPool);\n            PhAcquireQueuedLockExclusive(&providerThread->Lock);\n\n            if (object)\n                PhDereferenceObject(object);\n        }\n\n        // Re-add the items in the temp list to the main list.\n\n        while ((listEntry = RemoveHeadList(&tempListHead)) != &tempListHead)\n        {\n            registration = CONTAINING_RECORD(listEntry, PH_PROVIDER_REGISTRATION, ListEntry);\n\n            // We must insert boosted providers at the front of the list in order to maintain the\n            // condition that boosted providers are always in front of normal providers. This occurs\n            // when the timer is signaled just before a boosting provider alerts our thread.\n            if (!registration->Boosting)\n                InsertTailList(&providerThread->ListHead, listEntry);\n            else\n                InsertHeadList(&providerThread->ListHead, listEntry);\n        }\n\n        PhReleaseQueuedLockExclusive(&providerThread->Lock);\n\n        // Perform an alertable wait so we can be woken up by someone telling us to boost providers,\n        // or to terminate.\n        status = NtWaitForSingleObject(\n            providerThread->TimerHandle,\n            TRUE,\n            NULL\n            );\n    }\n\n    PhDeleteAutoPool(&autoPool);\n\n    return STATUS_SUCCESS;\n}\n\n/**\n * Starts a provider thread.\n *\n * \\param ProviderThread A pointer to a provider thread object.\n */\nVOID PhStartProviderThread(\n    _Inout_ PPH_PROVIDER_THREAD ProviderThread\n    )\n{\n    if (ProviderThread->State != ProviderThreadStopped)\n        return;\n\n    // Create and set the timer.\n    NtCreateTimer(&ProviderThread->TimerHandle, TIMER_ALL_ACCESS, NULL, SynchronizationTimer);\n    PhSetIntervalProviderThread(ProviderThread, ProviderThread->Interval);\n\n    // Create and start the thread.\n    ProviderThread->ThreadHandle = PhCreateThread(\n        0,\n        PhpProviderThreadStart,\n        ProviderThread\n        );\n\n    ProviderThread->State = ProviderThreadRunning;\n}\n\n/**\n * Stops a provider thread.\n *\n * \\param ProviderThread A pointer to a provider thread object.\n */\nVOID PhStopProviderThread(\n    _Inout_ PPH_PROVIDER_THREAD ProviderThread\n    )\n{\n    if (ProviderThread->State != ProviderThreadRunning)\n        return;\n\n    // Signal to the thread that we are shutting down, and wait for it to exit.\n    ProviderThread->State = ProviderThreadStopping;\n    NtAlertThread(ProviderThread->ThreadHandle); // wake it up\n    NtWaitForSingleObject(ProviderThread->ThreadHandle, FALSE, NULL);\n\n    // Free resources.\n    NtClose(ProviderThread->ThreadHandle);\n    NtClose(ProviderThread->TimerHandle);\n    ProviderThread->ThreadHandle = NULL;\n    ProviderThread->TimerHandle = NULL;\n\n    ProviderThread->State = ProviderThreadStopped;\n}\n\n/**\n * Sets the run interval for a provider thread.\n *\n * \\param ProviderThread A pointer to a provider thread object.\n * \\param Interval The interval between each run, in milliseconds.\n */\nVOID PhSetIntervalProviderThread(\n    _Inout_ PPH_PROVIDER_THREAD ProviderThread,\n    _In_ ULONG Interval\n    )\n{\n    ProviderThread->Interval = Interval;\n\n    if (ProviderThread->TimerHandle)\n    {\n        LARGE_INTEGER interval;\n\n        interval.QuadPart = -(LONGLONG)Interval * PH_TIMEOUT_MS;\n        NtSetTimer(ProviderThread->TimerHandle, &interval, NULL, NULL, FALSE, Interval, NULL);\n    }\n}\n\n/**\n * Registers a provider with a provider thread.\n *\n * \\param ProviderThread A pointer to a provider thread object.\n * \\param Function The provider function.\n * \\param Object A pointer to an object to pass to the provider function. The object must be managed\n * by the reference-counting system.\n * \\param Registration A variable which receives registration information for the provider.\n *\n * \\remarks The provider is initially disabled. Call PhSetEnabledProvider() to enable it.\n */\nVOID PhRegisterProvider(\n    _Inout_ PPH_PROVIDER_THREAD ProviderThread,\n    _In_ PPH_PROVIDER_FUNCTION Function,\n    _In_opt_ PVOID Object,\n    _Out_ PPH_PROVIDER_REGISTRATION Registration\n    )\n{\n    Registration->ProviderThread = ProviderThread;\n    Registration->Function = Function;\n    Registration->Object = Object;\n    Registration->RunId = 0;\n    Registration->Enabled = FALSE;\n    Registration->Unregistering = FALSE;\n    Registration->Boosting = FALSE;\n\n    if (Object)\n        PhReferenceObject(Object);\n\n    PhAcquireQueuedLockExclusive(&ProviderThread->Lock);\n    InsertTailList(&ProviderThread->ListHead, &Registration->ListEntry);\n    PhReleaseQueuedLockExclusive(&ProviderThread->Lock);\n}\n\n/**\n * Unregisters a provider.\n *\n * \\param Registration A pointer to the registration object for a provider.\n *\n * \\remarks The provider function may still be in execution once this function returns.\n */\nVOID PhUnregisterProvider(\n    _Inout_ PPH_PROVIDER_REGISTRATION Registration\n    )\n{\n    PPH_PROVIDER_THREAD providerThread;\n\n    providerThread = Registration->ProviderThread;\n\n    Registration->Unregistering = TRUE;\n\n    // There are two possibilities for removal:\n    // 1. The provider is removed while the thread is not in the main loop. This is the normal case.\n    // 2. The provider is removed while the thread is in the main loop. In that case the provider\n    //    will be removed from the temp list and so it won't be re-added to the main list.\n\n    PhAcquireQueuedLockExclusive(&providerThread->Lock);\n\n    RemoveEntryList(&Registration->ListEntry);\n\n    // Fix the boost count.\n    if (Registration->Boosting)\n        providerThread->BoostCount--;\n\n    // The user-supplied object must be dereferenced\n    // while the mutex is held.\n    if (Registration->Object)\n        PhDereferenceObject(Registration->Object);\n\n    PhReleaseQueuedLockExclusive(&providerThread->Lock);\n}\n\n/**\n * Causes a provider to be queued for immediate execution.\n *\n * \\param Registration A pointer to the registration object for a provider.\n * \\param FutureRunId A variable which receives the run ID of the future run.\n *\n * \\return TRUE if the operation was successful; FALSE if the provider is being unregistered, the\n * provider is already being boosted, or the provider thread is not running.\n *\n * \\remarks Boosted providers will be run immediately, ignoring the run interval. Boosting will not\n * however affect the normal runs.\n */\nBOOLEAN PhBoostProvider(\n    _Inout_ PPH_PROVIDER_REGISTRATION Registration,\n    _Out_opt_ PULONG FutureRunId\n    )\n{\n    PPH_PROVIDER_THREAD providerThread;\n    ULONG futureRunId;\n\n    if (Registration->Unregistering)\n        return FALSE;\n\n    providerThread = Registration->ProviderThread;\n\n    // Simply move to the provider to the front of the list. This works even if the provider is\n    // currently in the temp list.\n\n    PhAcquireQueuedLockExclusive(&providerThread->Lock);\n\n    // Abort if the provider is already being boosted or the provider thread is stopping/stopped.\n    if (Registration->Boosting || providerThread->State != ProviderThreadRunning)\n    {\n        PhReleaseQueuedLockExclusive(&providerThread->Lock);\n        return FALSE;\n    }\n\n    RemoveEntryList(&Registration->ListEntry);\n    InsertHeadList(&providerThread->ListHead, &Registration->ListEntry);\n\n    Registration->Boosting = TRUE;\n    providerThread->BoostCount++;\n\n    futureRunId = Registration->RunId + 1;\n\n    PhReleaseQueuedLockExclusive(&providerThread->Lock);\n\n    // Wake up the thread.\n    NtAlertThread(providerThread->ThreadHandle);\n\n    if (FutureRunId)\n        *FutureRunId = futureRunId;\n\n    return TRUE;\n}\n\n/**\n * Gets the current run ID of a provider.\n *\n * \\param Registration A pointer to the registration object for a provider.\n */\nULONG PhGetRunIdProvider(\n    _In_ PPH_PROVIDER_REGISTRATION Registration\n    )\n{\n    return Registration->RunId;\n}\n\n/**\n * Gets whether a provider is enabled.\n *\n * \\param Registration A pointer to the registration object for a provider.\n */\nBOOLEAN PhGetEnabledProvider(\n    _In_ PPH_PROVIDER_REGISTRATION Registration\n    )\n{\n    return Registration->Enabled;\n}\n\n/**\n * Sets whether a provider is enabled.\n *\n * \\param Registration A pointer to the registration object for a provider.\n * \\param Enabled TRUE if the provider is enabled, otherwise FALSE.\n */\nVOID PhSetEnabledProvider(\n    _Inout_ PPH_PROVIDER_REGISTRATION Registration,\n    _In_ BOOLEAN Enabled\n    )\n{\n    Registration->Enabled = Enabled;\n}\n"
  },
  {
    "path": "third_party/phlib/queuedlock.c",
    "content": "/*\n * Process Hacker -\n *   queued lock\n *\n * Copyright (C) 2010-2016 wj32\n *\n * This file is part of Process Hacker.\n *\n * Process Hacker is free software; you can redistribute it and/or modify\n * it under the terms of the GNU General Public License as published by\n * the Free Software Foundation, either version 3 of the License, or\n * (at your option) any later version.\n *\n * Process Hacker is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n * GNU General Public License for more details.\n *\n * You should have received a copy of the GNU General Public License\n * along with Process Hacker.  If not, see <http://www.gnu.org/licenses/>.\n */\n\n/*\n * Queued lock, a.k.a. push lock (kernel-mode) or slim reader-writer lock (user-mode).\n *\n * The queued lock is:\n * * Around 10% faster than the fast lock.\n * * Only the size of a pointer.\n * * Low on resource usage (no additional kernel objects are created for blocking).\n *\n * The usual flags are used for contention-free acquire/release. When there is contention,\n * stack-based wait blocks are chained. The first wait block contains the shared owners count which\n * is decremented by shared releasers.\n *\n * Naturally these wait blocks would be chained in FILO order, but list optimization is done for two\n * purposes:\n * * Finding the last wait block (where the shared owners count is stored). This is implemented by\n *   the Last pointer.\n * * Unblocking the wait blocks in FIFO order. This is implemented by the Previous pointer.\n *\n * The optimization is incremental - each optimization run will stop at the first optimized wait\n * block. Any needed optimization is completed just before waking waiters.\n *\n * The waiters list/chain has the following restrictions:\n * * At any time wait blocks may be pushed onto the list.\n * * While waking waiters, the list may not be traversed nor optimized.\n * * When there are multiple shared owners, shared releasers may traverse the list (to find the last\n *   wait block). This is not an issue because waiters wouldn't be woken until there are no more\n *   shared owners.\n * * List optimization may be done at any time except for when someone else is waking waiters. This\n *   is controlled by the traversing bit.\n *\n * The traversing bit has the following rules:\n * * The list may be optimized only after the traversing bit is set, checking that it wasn't set\n *   already. If it was set, it would indicate that someone else is optimizing the list or waking\n *   waiters.\n * * Before waking waiters the traversing bit must be set. If it was set already, just clear the\n *   owned bit.\n * * If during list optimization the owned bit is detected to be cleared, the function begins waking\n *   waiters. This is because the owned bit is cleared when a releaser fails to set the traversing\n *   bit.\n *\n * Blocking is implemented through a process-wide keyed event. A spin count is also used before\n * blocking on the keyed event.\n *\n * Queued locks can act as condition variables, with wait, pulse and pulse all support. Waiters are\n * released in FIFO order.\n *\n * Queued locks can act as wake events. These are designed for tiny one-bit locks which share a\n * single event to block on. Spurious wake-ups are a part of normal operation.\n */\n\n#include <phbase.h>\n\n#include <fastlock.h>\n#include <phintrnl.h>\n#include <queuedlock.h>\n\nVOID FASTCALL PhpfOptimizeQueuedLockList(\n    _Inout_ PPH_QUEUED_LOCK QueuedLock,\n    _In_ ULONG_PTR Value\n    );\n\nVOID FASTCALL PhpfWakeQueuedLock(\n    _Inout_ PPH_QUEUED_LOCK QueuedLock,\n    _In_ ULONG_PTR Value\n    );\n\nVOID FASTCALL PhpfWakeQueuedLockEx(\n    _Inout_ PPH_QUEUED_LOCK QueuedLock,\n    _In_ ULONG_PTR Value,\n    _In_ BOOLEAN IgnoreOwned,\n    _In_ BOOLEAN WakeAll\n    );\n\nstatic HANDLE PhQueuedLockKeyedEventHandle;\nstatic ULONG PhQueuedLockSpinCount = 2000;\n\nBOOLEAN PhQueuedLockInitialization(\n    VOID\n    )\n{\n    if (!NT_SUCCESS(NtCreateKeyedEvent(\n        &PhQueuedLockKeyedEventHandle,\n        KEYEDEVENT_ALL_ACCESS,\n        NULL,\n        0\n        )))\n        return FALSE;\n\n    if ((ULONG)PhSystemBasicInformation.NumberOfProcessors > 1)\n        PhQueuedLockSpinCount = 4000;\n    else\n        PhQueuedLockSpinCount = 0;\n\n    return TRUE;\n}\n\n/**\n * Pushes a wait block onto a queued lock's waiters list.\n *\n * \\param QueuedLock A queued lock.\n * \\param Value The current value of the queued lock.\n * \\param Exclusive Whether the wait block is in exclusive mode.\n * \\param WaitBlock A variable which receives the resulting wait block structure.\n * \\param Optimize A variable which receives a boolean indicating whether to optimize the waiters\n * list.\n * \\param NewValue The old value of the queued lock. This value is useful only if the function\n * returns FALSE.\n * \\param CurrentValue The new value of the queued lock. This value is useful only if the function\n * returns TRUE.\n *\n * \\return TRUE if the wait block was pushed onto the waiters list, otherwise FALSE.\n *\n * \\remarks\n * \\li The function assumes the following flags are set:\n * \\ref PH_QUEUED_LOCK_OWNED.\n * \\li Do not move the wait block location after this function is called.\n * \\li The \\a Optimize boolean is a hint to call PhpfOptimizeQueuedLockList() if the function\n * succeeds. It is recommended, but not essential that this occurs.\n * \\li Call PhpBlockOnQueuedWaitBlock() to wait for the wait block to be unblocked.\n */\nFORCEINLINE BOOLEAN PhpPushQueuedWaitBlock(\n    _Inout_ PPH_QUEUED_LOCK QueuedLock,\n    _In_ ULONG_PTR Value,\n    _In_ BOOLEAN Exclusive,\n    _Out_ PPH_QUEUED_WAIT_BLOCK WaitBlock,\n    _Out_ PBOOLEAN Optimize,\n    _Out_ PULONG_PTR NewValue,\n    _Out_ PULONG_PTR CurrentValue\n    )\n{\n    ULONG_PTR newValue;\n    BOOLEAN optimize;\n\n    WaitBlock->Previous = NULL; // set later by optimization\n    optimize = FALSE;\n\n    if (Exclusive)\n        WaitBlock->Flags = PH_QUEUED_WAITER_EXCLUSIVE | PH_QUEUED_WAITER_SPINNING;\n    else\n        WaitBlock->Flags = PH_QUEUED_WAITER_SPINNING;\n\n    if (Value & PH_QUEUED_LOCK_WAITERS)\n    {\n        // We're not the first waiter.\n\n        WaitBlock->Last = NULL; // set later by optimization\n        WaitBlock->Next = PhGetQueuedLockWaitBlock(Value);\n        WaitBlock->SharedOwners = 0;\n\n        // Push our wait block onto the list.\n        // Set the traversing bit because we'll be optimizing the list.\n        newValue = ((ULONG_PTR)WaitBlock) | (Value & PH_QUEUED_LOCK_FLAGS) |\n            PH_QUEUED_LOCK_TRAVERSING;\n\n        if (!(Value & PH_QUEUED_LOCK_TRAVERSING))\n            optimize = TRUE;\n    }\n    else\n    {\n        // We're the first waiter.\n\n        WaitBlock->Last = WaitBlock; // indicate that this is the last wait block\n\n        if (Exclusive)\n        {\n            // We're the first waiter. Save the shared owners count.\n            WaitBlock->SharedOwners = (ULONG)PhGetQueuedLockSharedOwners(Value);\n\n            if (WaitBlock->SharedOwners > 1)\n            {\n                newValue = ((ULONG_PTR)WaitBlock) | PH_QUEUED_LOCK_OWNED |\n                    PH_QUEUED_LOCK_WAITERS | PH_QUEUED_LOCK_MULTIPLE_SHARED;\n            }\n            else\n            {\n                newValue = ((ULONG_PTR)WaitBlock) | PH_QUEUED_LOCK_OWNED |\n                    PH_QUEUED_LOCK_WAITERS;\n            }\n        }\n        else\n        {\n            // We're waiting in shared mode, which means there can't be any shared owners (otherwise\n            // we would've acquired the lock already).\n\n            WaitBlock->SharedOwners = 0;\n\n            newValue = ((ULONG_PTR)WaitBlock) | PH_QUEUED_LOCK_OWNED |\n                PH_QUEUED_LOCK_WAITERS;\n        }\n    }\n\n    *Optimize = optimize;\n    *CurrentValue = newValue;\n\n    newValue = (ULONG_PTR)_InterlockedCompareExchangePointer(\n        (PVOID *)&QueuedLock->Value,\n        (PVOID)newValue,\n        (PVOID)Value\n        );\n\n    *NewValue = newValue;\n\n    return newValue == Value;\n}\n\n/**\n * Finds the last wait block in the waiters list.\n *\n * \\param Value The current value of the queued lock.\n *\n * \\return A pointer to the last wait block.\n *\n * \\remarks The function assumes the following flags are set:\n * \\ref PH_QUEUED_LOCK_WAITERS,\n * \\ref PH_QUEUED_LOCK_MULTIPLE_SHARED or\n * \\ref PH_QUEUED_LOCK_TRAVERSING.\n */\nFORCEINLINE PPH_QUEUED_WAIT_BLOCK PhpFindLastQueuedWaitBlock(\n    _In_ ULONG_PTR Value\n    )\n{\n    PPH_QUEUED_WAIT_BLOCK waitBlock;\n    PPH_QUEUED_WAIT_BLOCK lastWaitBlock;\n\n    waitBlock = PhGetQueuedLockWaitBlock(Value);\n\n    // Traverse the list until we find the last wait block.\n    // The Last pointer should be set by list optimization, allowing us to skip all, if not most of\n    // the wait blocks.\n\n    while (TRUE)\n    {\n        lastWaitBlock = waitBlock->Last;\n\n        if (lastWaitBlock)\n        {\n            // Follow the Last pointer. This can mean two things: the pointer was set by list\n            // optimization, or this wait block is actually the last wait block (set when it was\n            // pushed onto the list).\n            waitBlock = lastWaitBlock;\n            break;\n        }\n\n        waitBlock = waitBlock->Next;\n    }\n\n    return waitBlock;\n}\n\n/**\n * Waits for a wait block to be unblocked.\n *\n * \\param WaitBlock A wait block.\n * \\param Spin TRUE to spin, FALSE to block immediately.\n * \\param Timeout A timeout value.\n */\n_May_raise_ FORCEINLINE NTSTATUS PhpBlockOnQueuedWaitBlock(\n    _Inout_ PPH_QUEUED_WAIT_BLOCK WaitBlock,\n    _In_ BOOLEAN Spin,\n    _In_opt_ PLARGE_INTEGER Timeout\n    )\n{\n    NTSTATUS status;\n    ULONG i;\n\n    if (Spin)\n    {\n        PHLIB_INC_STATISTIC(QlBlockSpins);\n\n        for (i = PhQueuedLockSpinCount; i != 0; i--)\n        {\n            if (!(*(volatile ULONG *)&WaitBlock->Flags & PH_QUEUED_WAITER_SPINNING))\n                return STATUS_SUCCESS;\n\n            YieldProcessor();\n        }\n    }\n\n    if (_interlockedbittestandreset((PLONG)&WaitBlock->Flags, PH_QUEUED_WAITER_SPINNING_SHIFT))\n    {\n        PHLIB_INC_STATISTIC(QlBlockWaits);\n\n        status = NtWaitForKeyedEvent(\n            PhQueuedLockKeyedEventHandle,\n            WaitBlock,\n            FALSE,\n            Timeout\n            );\n\n        // If an error occurred (timeout is not an error), raise an exception as it is nearly\n        // impossible to recover from this situation.\n        if (!NT_SUCCESS(status))\n            PhRaiseStatus(status);\n    }\n    else\n    {\n        status = STATUS_SUCCESS;\n    }\n\n    return status;\n}\n\n/**\n * Unblocks a wait block.\n *\n * \\param WaitBlock A wait block.\n *\n * \\remarks The wait block is in an undefined state after it is unblocked. Do not attempt to read\n * any values from it. All relevant information should be saved before unblocking the wait block.\n */\n_May_raise_ FORCEINLINE VOID PhpUnblockQueuedWaitBlock(\n    _Inout_ PPH_QUEUED_WAIT_BLOCK WaitBlock\n    )\n{\n    NTSTATUS status;\n\n    if (!_interlockedbittestandreset((PLONG)&WaitBlock->Flags, PH_QUEUED_WAITER_SPINNING_SHIFT))\n    {\n        if (!NT_SUCCESS(status = NtReleaseKeyedEvent(\n            PhQueuedLockKeyedEventHandle,\n            WaitBlock,\n            FALSE,\n            NULL\n            )))\n            PhRaiseStatus(status);\n    }\n}\n\n/**\n * Optimizes a queued lock waiters list.\n *\n * \\param QueuedLock A queued lock.\n * \\param Value The current value of the queued lock.\n * \\param IgnoreOwned TRUE to ignore lock state, FALSE to conduct normal checks.\n *\n * \\remarks The function assumes the following flags are set:\n * \\ref PH_QUEUED_LOCK_WAITERS, \\ref PH_QUEUED_LOCK_TRAVERSING.\n */\nFORCEINLINE VOID PhpOptimizeQueuedLockListEx(\n    _Inout_ PPH_QUEUED_LOCK QueuedLock,\n    _In_ ULONG_PTR Value,\n    _In_ BOOLEAN IgnoreOwned\n    )\n{\n    ULONG_PTR value;\n    ULONG_PTR newValue;\n    PPH_QUEUED_WAIT_BLOCK waitBlock;\n    PPH_QUEUED_WAIT_BLOCK firstWaitBlock;\n    PPH_QUEUED_WAIT_BLOCK lastWaitBlock;\n    PPH_QUEUED_WAIT_BLOCK previousWaitBlock;\n\n    value = Value;\n\n    while (TRUE)\n    {\n        assert(value & PH_QUEUED_LOCK_TRAVERSING);\n\n        if (!IgnoreOwned && !(value & PH_QUEUED_LOCK_OWNED))\n        {\n            // Someone has requested that we wake waiters.\n            PhpfWakeQueuedLock(QueuedLock, value);\n            break;\n        }\n\n        // Perform the optimization.\n\n        waitBlock = PhGetQueuedLockWaitBlock(value);\n        firstWaitBlock = waitBlock;\n\n        while (TRUE)\n        {\n            lastWaitBlock = waitBlock->Last;\n\n            if (lastWaitBlock)\n            {\n                // Save a pointer to the last wait block in the first wait block and stop\n                // optimizing.\n                //\n                // We don't need to continue setting Previous pointers because the last optimization\n                // run would have set them already.\n\n                firstWaitBlock->Last = lastWaitBlock;\n                break;\n            }\n\n            previousWaitBlock = waitBlock;\n            waitBlock = waitBlock->Next;\n            waitBlock->Previous = previousWaitBlock;\n        }\n\n        // Try to clear the traversing bit.\n\n        newValue = value - PH_QUEUED_LOCK_TRAVERSING;\n\n        if ((newValue = (ULONG_PTR)_InterlockedCompareExchangePointer(\n            (PVOID *)&QueuedLock->Value,\n            (PVOID)newValue,\n            (PVOID)value\n            )) == value)\n            break;\n\n        // Either someone pushed a wait block onto the list or someone released ownership. In either\n        // case we need to go back.\n\n        value = newValue;\n    }\n}\n\n/**\n * Optimizes a queued lock waiters list.\n *\n * \\param QueuedLock A queued lock.\n * \\param Value The current value of the queued lock.\n *\n * \\remarks The function assumes the following flags are set:\n * \\ref PH_QUEUED_LOCK_WAITERS, \\ref PH_QUEUED_LOCK_TRAVERSING.\n */\nVOID FASTCALL PhpfOptimizeQueuedLockList(\n    _Inout_ PPH_QUEUED_LOCK QueuedLock,\n    _In_ ULONG_PTR Value\n    )\n{\n    PhpOptimizeQueuedLockListEx(QueuedLock, Value, FALSE);\n}\n\n/**\n * Dequeues the appropriate number of wait blocks in a queued lock.\n *\n * \\param QueuedLock A queued lock.\n * \\param Value The current value of the queued lock.\n * \\param IgnoreOwned TRUE to ignore lock state, FALSE to conduct normal checks.\n * \\param WakeAll TRUE to remove all wait blocks, FALSE to decide based on the wait block type.\n */\nFORCEINLINE PPH_QUEUED_WAIT_BLOCK PhpPrepareToWakeQueuedLock(\n    _Inout_ PPH_QUEUED_LOCK QueuedLock,\n    _In_ ULONG_PTR Value,\n    _In_ BOOLEAN IgnoreOwned,\n    _In_ BOOLEAN WakeAll\n    )\n{\n    ULONG_PTR value;\n    ULONG_PTR newValue;\n    PPH_QUEUED_WAIT_BLOCK waitBlock;\n    PPH_QUEUED_WAIT_BLOCK firstWaitBlock;\n    PPH_QUEUED_WAIT_BLOCK lastWaitBlock;\n    PPH_QUEUED_WAIT_BLOCK previousWaitBlock;\n\n    value = Value;\n\n    while (TRUE)\n    {\n        // If there are multiple shared owners, no one is going to wake waiters since the lock would\n        // still be owned. Also if there are multiple shared owners they may be traversing the list.\n        // While that is safe when done concurrently with list optimization, we may be removing and\n        // waking waiters.\n        assert(!(value & PH_QUEUED_LOCK_MULTIPLE_SHARED));\n        assert(IgnoreOwned || (value & PH_QUEUED_LOCK_TRAVERSING));\n\n        // There's no point in waking a waiter if the lock is owned. Clear the traversing bit.\n        while (!IgnoreOwned && (value & PH_QUEUED_LOCK_OWNED))\n        {\n            newValue = value - PH_QUEUED_LOCK_TRAVERSING;\n\n            if ((newValue = (ULONG_PTR)_InterlockedCompareExchangePointer(\n                (PVOID *)&QueuedLock->Value,\n                (PVOID)newValue,\n                (PVOID)value\n                )) == value)\n                return NULL;\n\n            value = newValue;\n        }\n\n        // Finish up any needed optimization (setting the Previous pointers) while finding the last\n        // wait block.\n\n        waitBlock = PhGetQueuedLockWaitBlock(value);\n        firstWaitBlock = waitBlock;\n\n        while (TRUE)\n        {\n            lastWaitBlock = waitBlock->Last;\n\n            if (lastWaitBlock)\n            {\n                waitBlock = lastWaitBlock;\n                break;\n            }\n\n            previousWaitBlock = waitBlock;\n            waitBlock = waitBlock->Next;\n            waitBlock->Previous = previousWaitBlock;\n        }\n\n        // Unlink the relevant wait blocks and clear the traversing bit before we wake waiters.\n\n        if (\n            !WakeAll &&\n            (waitBlock->Flags & PH_QUEUED_WAITER_EXCLUSIVE) &&\n            (previousWaitBlock = waitBlock->Previous)\n            )\n        {\n            // We have an exclusive waiter and there are multiple waiters. We'll only be waking this\n            // waiter.\n\n            // Unlink the wait block from the list. Although other wait blocks may have their Last\n            // pointers set to this wait block, the algorithm to find the last wait block will stop\n            // here. Likewise the Next pointers are never followed beyond this point, so we don't\n            // need to clear those.\n            firstWaitBlock->Last = previousWaitBlock;\n\n            // Make sure we only wake this waiter.\n            waitBlock->Previous = NULL;\n\n            if (!IgnoreOwned)\n            {\n                // Clear the traversing bit.\n                _InterlockedExchangeAddPointer((PLONG_PTR)&QueuedLock->Value, -(LONG_PTR)PH_QUEUED_LOCK_TRAVERSING);\n            }\n\n            break;\n        }\n        else\n        {\n            // We're waking an exclusive waiter and there is only one waiter, or we are waking a\n            // shared waiter and possibly others.\n\n            newValue = 0;\n\n            if ((newValue = (ULONG_PTR)_InterlockedCompareExchangePointer(\n                (PVOID *)&QueuedLock->Value,\n                (PVOID)newValue,\n                (PVOID)value\n                )) == value)\n                break;\n\n            // Someone changed the lock (acquired it or pushed a wait block).\n\n            value = newValue;\n        }\n    }\n\n    return waitBlock;\n}\n\n/**\n * Wakes waiters in a queued lock.\n *\n * \\param QueuedLock A queued lock.\n * \\param Value The current value of the queued lock.\n *\n * \\remarks The function assumes the following flags are set:\n * \\ref PH_QUEUED_LOCK_WAITERS, \\ref PH_QUEUED_LOCK_TRAVERSING. The function assumes the following\n * flags are not set:\n * \\ref PH_QUEUED_LOCK_MULTIPLE_SHARED.\n */\nVOID FASTCALL PhpfWakeQueuedLock(\n    _Inout_ PPH_QUEUED_LOCK QueuedLock,\n    _In_ ULONG_PTR Value\n    )\n{\n    PPH_QUEUED_WAIT_BLOCK waitBlock;\n    PPH_QUEUED_WAIT_BLOCK previousWaitBlock;\n\n    waitBlock = PhpPrepareToWakeQueuedLock(QueuedLock, Value, FALSE, FALSE);\n\n    // Wake waiters.\n\n    while (waitBlock)\n    {\n        previousWaitBlock = waitBlock->Previous;\n        PhpUnblockQueuedWaitBlock(waitBlock);\n        waitBlock = previousWaitBlock;\n    }\n}\n\n/**\n * Wakes waiters in a queued lock.\n *\n * \\param QueuedLock A queued lock.\n * \\param Value The current value of the queued lock.\n * \\param IgnoreOwned TRUE to ignore lock state, FALSE to conduct normal checks.\n * \\param WakeAll TRUE to wake all waiters, FALSE to decide based on the wait block type.\n *\n * \\remarks The function assumes the following flags are set:\n * \\ref PH_QUEUED_LOCK_WAITERS, \\ref PH_QUEUED_LOCK_TRAVERSING. The function assumes the following\n * flags are not set:\n * \\ref PH_QUEUED_LOCK_MULTIPLE_SHARED.\n */\nVOID FASTCALL PhpfWakeQueuedLockEx(\n    _Inout_ PPH_QUEUED_LOCK QueuedLock,\n    _In_ ULONG_PTR Value,\n    _In_ BOOLEAN IgnoreOwned,\n    _In_ BOOLEAN WakeAll\n    )\n{\n    PPH_QUEUED_WAIT_BLOCK waitBlock;\n    PPH_QUEUED_WAIT_BLOCK previousWaitBlock;\n\n    waitBlock = PhpPrepareToWakeQueuedLock(QueuedLock, Value, IgnoreOwned, WakeAll);\n\n    // Wake waiters.\n\n    while (waitBlock)\n    {\n        previousWaitBlock = waitBlock->Previous;\n        PhpUnblockQueuedWaitBlock(waitBlock);\n        waitBlock = previousWaitBlock;\n    }\n}\n\n/**\n * Acquires a queued lock in exclusive mode.\n *\n * \\param QueuedLock A queued lock.\n */\nVOID FASTCALL PhfAcquireQueuedLockExclusive(\n    _Inout_ PPH_QUEUED_LOCK QueuedLock\n    )\n{\n    ULONG_PTR value;\n    ULONG_PTR newValue;\n    ULONG_PTR currentValue;\n    BOOLEAN optimize;\n    PH_QUEUED_WAIT_BLOCK waitBlock;\n\n    value = QueuedLock->Value;\n\n    while (TRUE)\n    {\n        if (!(value & PH_QUEUED_LOCK_OWNED))\n        {\n            if ((newValue = (ULONG_PTR)_InterlockedCompareExchangePointer(\n                (PVOID *)&QueuedLock->Value,\n                (PVOID)(value + PH_QUEUED_LOCK_OWNED),\n                (PVOID)value\n                )) == value)\n                break;\n        }\n        else\n        {\n            if (PhpPushQueuedWaitBlock(\n                QueuedLock,\n                value,\n                TRUE,\n                &waitBlock,\n                &optimize,\n                &newValue,\n                &currentValue\n                ))\n            {\n                if (optimize)\n                    PhpfOptimizeQueuedLockList(QueuedLock, currentValue);\n\n                PHLIB_INC_STATISTIC(QlAcquireExclusiveBlocks);\n                PhpBlockOnQueuedWaitBlock(&waitBlock, TRUE, NULL);\n            }\n        }\n\n        value = newValue;\n    }\n}\n\n/**\n * Acquires a queued lock in shared mode.\n *\n * \\param QueuedLock A queued lock.\n */\nVOID FASTCALL PhfAcquireQueuedLockShared(\n    _Inout_ PPH_QUEUED_LOCK QueuedLock\n    )\n{\n    ULONG_PTR value;\n    ULONG_PTR newValue;\n    ULONG_PTR currentValue;\n    BOOLEAN optimize;\n    PH_QUEUED_WAIT_BLOCK waitBlock;\n\n    value = QueuedLock->Value;\n\n    while (TRUE)\n    {\n        // We can't acquire if there are waiters for two reasons:\n        //\n        // We want to prioritize exclusive acquires over shared acquires. There's currently no fast,\n        // safe way of finding the last wait block and incrementing the shared owners count here.\n        if (\n            !(value & PH_QUEUED_LOCK_WAITERS) &&\n            (!(value & PH_QUEUED_LOCK_OWNED) || (PhGetQueuedLockSharedOwners(value) > 0))\n            )\n        {\n            newValue = (value + PH_QUEUED_LOCK_SHARED_INC) | PH_QUEUED_LOCK_OWNED;\n\n            if ((newValue = (ULONG_PTR)_InterlockedCompareExchangePointer(\n                (PVOID *)&QueuedLock->Value,\n                (PVOID)newValue,\n                (PVOID)value\n                )) == value)\n                break;\n        }\n        else\n        {\n            if (PhpPushQueuedWaitBlock(\n                QueuedLock,\n                value,\n                FALSE,\n                &waitBlock,\n                &optimize,\n                &newValue,\n                &currentValue\n                ))\n            {\n                if (optimize)\n                    PhpfOptimizeQueuedLockList(QueuedLock, currentValue);\n\n                PHLIB_INC_STATISTIC(QlAcquireSharedBlocks);\n                PhpBlockOnQueuedWaitBlock(&waitBlock, TRUE, NULL);\n            }\n        }\n\n        value = newValue;\n    }\n}\n\n/**\n * Releases a queued lock in exclusive mode.\n *\n * \\param QueuedLock A queued lock.\n */\nVOID FASTCALL PhfReleaseQueuedLockExclusive(\n    _Inout_ PPH_QUEUED_LOCK QueuedLock\n    )\n{\n    ULONG_PTR value;\n    ULONG_PTR newValue;\n    ULONG_PTR currentValue;\n\n    value = QueuedLock->Value;\n\n    while (TRUE)\n    {\n        assert(value & PH_QUEUED_LOCK_OWNED);\n        assert((value & PH_QUEUED_LOCK_WAITERS) || (PhGetQueuedLockSharedOwners(value) == 0));\n\n        if ((value & (PH_QUEUED_LOCK_WAITERS | PH_QUEUED_LOCK_TRAVERSING)) != PH_QUEUED_LOCK_WAITERS)\n        {\n            // There are no waiters or someone is traversing the list.\n            //\n            // If there are no waiters, we're simply releasing ownership. If someone is traversing\n            // the list, clearing the owned bit is a signal for them to wake waiters.\n\n            newValue = value - PH_QUEUED_LOCK_OWNED;\n\n            if ((newValue = (ULONG_PTR)_InterlockedCompareExchangePointer(\n                (PVOID *)&QueuedLock->Value,\n                (PVOID)newValue,\n                (PVOID)value\n                )) == value)\n                break;\n        }\n        else\n        {\n            // We need to wake waiters and no one is traversing the list.\n            // Try to set the traversing bit and wake waiters.\n\n            newValue = value - PH_QUEUED_LOCK_OWNED + PH_QUEUED_LOCK_TRAVERSING;\n            currentValue = newValue;\n\n            if ((newValue = (ULONG_PTR)_InterlockedCompareExchangePointer(\n                (PVOID *)&QueuedLock->Value,\n                (PVOID)newValue,\n                (PVOID)value\n                )) == value)\n            {\n                PhpfWakeQueuedLock(QueuedLock, currentValue);\n                break;\n            }\n        }\n\n        value = newValue;\n    }\n}\n\n/**\n * Wakes waiters in a queued lock for releasing it in exclusive mode.\n *\n * \\param QueuedLock A queued lock.\n * \\param Value The current value of the queued lock.\n *\n * \\remarks The function assumes the following flags are set:\n * \\ref PH_QUEUED_LOCK_WAITERS. The function assumes the following flags are not set:\n * \\ref PH_QUEUED_LOCK_MULTIPLE_SHARED, \\ref PH_QUEUED_LOCK_TRAVERSING.\n */\nVOID FASTCALL PhfWakeForReleaseQueuedLock(\n    _Inout_ PPH_QUEUED_LOCK QueuedLock,\n    _In_ ULONG_PTR Value\n    )\n{\n    ULONG_PTR newValue;\n\n    newValue = Value + PH_QUEUED_LOCK_TRAVERSING;\n\n    if ((ULONG_PTR)_InterlockedCompareExchangePointer(\n        (PVOID *)&QueuedLock->Value,\n        (PVOID)newValue,\n        (PVOID)Value\n        ) == Value)\n    {\n        PhpfWakeQueuedLock(QueuedLock, newValue);\n    }\n}\n\n/**\n * Releases a queued lock in shared mode.\n *\n * \\param QueuedLock A queued lock.\n */\nVOID FASTCALL PhfReleaseQueuedLockShared(\n    _Inout_ PPH_QUEUED_LOCK QueuedLock\n    )\n{\n    ULONG_PTR value;\n    ULONG_PTR newValue;\n    ULONG_PTR currentValue;\n    PPH_QUEUED_WAIT_BLOCK waitBlock;\n\n    value = QueuedLock->Value;\n\n    while (!(value & PH_QUEUED_LOCK_WAITERS))\n    {\n        assert(value & PH_QUEUED_LOCK_OWNED);\n        assert((value & PH_QUEUED_LOCK_WAITERS) || (PhGetQueuedLockSharedOwners(value) > 0));\n\n        if (PhGetQueuedLockSharedOwners(value) > 1)\n            newValue = value - PH_QUEUED_LOCK_SHARED_INC;\n        else\n            newValue = 0;\n\n        if ((newValue = (ULONG_PTR)_InterlockedCompareExchangePointer(\n            (PVOID *)&QueuedLock->Value,\n            (PVOID)newValue,\n            (PVOID)value\n            )) == value)\n            return;\n\n        value = newValue;\n    }\n\n    if (value & PH_QUEUED_LOCK_MULTIPLE_SHARED)\n    {\n        // Unfortunately we have to find the last wait block and decrement the shared owners count.\n        waitBlock = PhpFindLastQueuedWaitBlock(value);\n\n        if ((ULONG)_InterlockedDecrement((PLONG)&waitBlock->SharedOwners) > 0)\n            return;\n    }\n\n    while (TRUE)\n    {\n        if (value & PH_QUEUED_LOCK_TRAVERSING)\n        {\n            newValue = value & ~(PH_QUEUED_LOCK_OWNED | PH_QUEUED_LOCK_MULTIPLE_SHARED);\n\n            if ((newValue = (ULONG_PTR)_InterlockedCompareExchangePointer(\n                (PVOID *)&QueuedLock->Value,\n                (PVOID)newValue,\n                (PVOID)value\n                )) == value)\n                break;\n        }\n        else\n        {\n            newValue = (value & ~(PH_QUEUED_LOCK_OWNED | PH_QUEUED_LOCK_MULTIPLE_SHARED)) |\n                PH_QUEUED_LOCK_TRAVERSING;\n            currentValue = newValue;\n\n            if ((newValue = (ULONG_PTR)_InterlockedCompareExchangePointer(\n                (PVOID *)&QueuedLock->Value,\n                (PVOID)newValue,\n                (PVOID)value\n                )) == value)\n            {\n                PhpfWakeQueuedLock(QueuedLock, currentValue);\n                break;\n            }\n        }\n\n        value = newValue;\n    }\n}\n\n/**\n * Wakes one thread sleeping on a condition variable.\n *\n * \\param Condition A condition variable.\n *\n * \\remarks The associated lock must be acquired before calling the function.\n */\nVOID FASTCALL PhfPulseCondition(\n    _Inout_ PPH_CONDITION Condition\n    )\n{\n    if (Condition->Value & PH_QUEUED_LOCK_WAITERS)\n        PhpfWakeQueuedLockEx(Condition, Condition->Value, TRUE, FALSE);\n}\n\n/**\n * Wakes all threads sleeping on a condition variable.\n *\n * \\param Condition A condition variable.\n *\n * \\remarks The associated lock must be acquired before calling the function.\n */\nVOID FASTCALL PhfPulseAllCondition(\n    _Inout_ PPH_CONDITION Condition\n    )\n{\n    if (Condition->Value & PH_QUEUED_LOCK_WAITERS)\n        PhpfWakeQueuedLockEx(Condition, Condition->Value, TRUE, TRUE);\n}\n\n/**\n * Sleeps on a condition variable.\n *\n * \\param Condition A condition variable.\n * \\param Lock A queued lock to release/acquire in exclusive mode.\n * \\param Timeout Not implemented.\n *\n * \\remarks The associated lock must be acquired before calling the function.\n */\nVOID FASTCALL PhfWaitForCondition(\n    _Inout_ PPH_CONDITION Condition,\n    _Inout_ PPH_QUEUED_LOCK Lock,\n    _In_opt_ PLARGE_INTEGER Timeout\n    )\n{\n    ULONG_PTR value;\n    ULONG_PTR currentValue;\n    PH_QUEUED_WAIT_BLOCK waitBlock;\n    BOOLEAN optimize;\n\n    value = Condition->Value;\n\n    while (TRUE)\n    {\n        if (PhpPushQueuedWaitBlock(\n            Condition,\n            value,\n            TRUE,\n            &waitBlock,\n            &optimize,\n            &value,\n            &currentValue\n            ))\n        {\n            if (optimize)\n            {\n                PhpOptimizeQueuedLockListEx(Condition, currentValue, TRUE);\n            }\n\n            PhReleaseQueuedLockExclusive(Lock);\n\n            PhpBlockOnQueuedWaitBlock(&waitBlock, FALSE, NULL);\n\n            // Don't use the inline variant; it is extremely likely that the lock is still owned.\n            PhfAcquireQueuedLockExclusive(Lock);\n\n            break;\n        }\n    }\n}\n\n/**\n * Sleeps on a condition variable.\n *\n * \\param Condition A condition variable.\n * \\param Lock A pointer to a lock.\n * \\param Flags A combination of flags controlling the operation.\n * \\param Timeout Not implemented.\n */\nVOID FASTCALL PhfWaitForConditionEx(\n    _Inout_ PPH_CONDITION Condition,\n    _Inout_ PVOID Lock,\n    _In_ ULONG Flags,\n    _In_opt_ PLARGE_INTEGER Timeout\n    )\n{\n    ULONG_PTR value;\n    ULONG_PTR currentValue;\n    PH_QUEUED_WAIT_BLOCK waitBlock;\n    BOOLEAN optimize;\n\n    value = Condition->Value;\n\n    while (TRUE)\n    {\n        if (PhpPushQueuedWaitBlock(\n            Condition,\n            value,\n            TRUE,\n            &waitBlock,\n            &optimize,\n            &value,\n            &currentValue\n            ))\n        {\n            if (optimize)\n            {\n                PhpOptimizeQueuedLockListEx(Condition, currentValue, TRUE);\n            }\n\n            switch (Flags & PH_CONDITION_WAIT_LOCK_TYPE_MASK)\n            {\n            case PH_CONDITION_WAIT_QUEUED_LOCK:\n                if (!(Flags & PH_CONDITION_WAIT_SHARED))\n                    PhReleaseQueuedLockExclusive((PPH_QUEUED_LOCK)Lock);\n                else\n                    PhReleaseQueuedLockShared((PPH_QUEUED_LOCK)Lock);\n                break;\n            case PH_CONDITION_WAIT_CRITICAL_SECTION:\n                RtlLeaveCriticalSection((PRTL_CRITICAL_SECTION)Lock);\n                break;\n            case PH_CONDITION_WAIT_FAST_LOCK:\n                if (!(Flags & PH_CONDITION_WAIT_SHARED))\n                    PhReleaseFastLockExclusive((PPH_FAST_LOCK)Lock);\n                else\n                    PhReleaseFastLockShared((PPH_FAST_LOCK)Lock);\n                break;\n            }\n\n            if (!(Flags & PH_CONDITION_WAIT_SPIN))\n            {\n                PhpBlockOnQueuedWaitBlock(&waitBlock, FALSE, NULL);\n            }\n            else\n            {\n                PhpBlockOnQueuedWaitBlock(&waitBlock, TRUE, NULL);\n            }\n\n            switch (Flags & PH_CONDITION_WAIT_LOCK_TYPE_MASK)\n            {\n            case PH_CONDITION_WAIT_QUEUED_LOCK:\n                if (!(Flags & PH_CONDITION_WAIT_SHARED))\n                    PhfAcquireQueuedLockExclusive((PPH_QUEUED_LOCK)Lock);\n                else\n                    PhfAcquireQueuedLockShared((PPH_QUEUED_LOCK)Lock);\n                break;\n            case PH_CONDITION_WAIT_CRITICAL_SECTION:\n                RtlEnterCriticalSection((PRTL_CRITICAL_SECTION)Lock);\n                break;\n            case PH_CONDITION_WAIT_FAST_LOCK:\n                if (!(Flags & PH_CONDITION_WAIT_SHARED))\n                    PhAcquireFastLockExclusive((PPH_FAST_LOCK)Lock);\n                else\n                    PhAcquireFastLockShared((PPH_FAST_LOCK)Lock);\n                break;\n            }\n\n            break;\n        }\n    }\n}\n\n/**\n * Queues a wait block to a wake event.\n *\n * \\param WakeEvent A wake event.\n * \\param WaitBlock A wait block.\n *\n * \\remarks If you later determine that the wait should not occur, you must call PhfSetWakeEvent()\n * to dequeue the wait block.\n */\nVOID FASTCALL PhfQueueWakeEvent(\n    _Inout_ PPH_WAKE_EVENT WakeEvent,\n    _Out_ PPH_QUEUED_WAIT_BLOCK WaitBlock\n    )\n{\n    PPH_QUEUED_WAIT_BLOCK value;\n    PPH_QUEUED_WAIT_BLOCK newValue;\n\n    WaitBlock->Flags = PH_QUEUED_WAITER_SPINNING;\n\n    value = (PPH_QUEUED_WAIT_BLOCK)WakeEvent->Value;\n\n    while (TRUE)\n    {\n        WaitBlock->Next = value;\n\n        if ((newValue = _InterlockedCompareExchangePointer(\n            (PVOID *)&WakeEvent->Value,\n            WaitBlock,\n            value\n            )) == value)\n            break;\n\n        value = newValue;\n    }\n}\n\n/**\n * Sets a wake event, unblocking all queued wait blocks.\n *\n * \\param WakeEvent A wake event.\n * \\param WaitBlock A wait block for a cancelled wait, otherwise NULL.\n */\nVOID FASTCALL PhfSetWakeEvent(\n    _Inout_ PPH_WAKE_EVENT WakeEvent,\n    _Inout_opt_ PPH_QUEUED_WAIT_BLOCK WaitBlock\n    )\n{\n    PPH_QUEUED_WAIT_BLOCK waitBlock;\n    PPH_QUEUED_WAIT_BLOCK nextWaitBlock;\n\n    // Pop all waiters and unblock them.\n\n    waitBlock = _InterlockedExchangePointer((PVOID *)&WakeEvent->Value, NULL);\n\n    while (waitBlock)\n    {\n        nextWaitBlock = waitBlock->Next;\n        PhpUnblockQueuedWaitBlock(waitBlock);\n        waitBlock = nextWaitBlock;\n    }\n\n    if (WaitBlock)\n    {\n        // We're cancelling a wait; the thread called this function instead of PhfWaitForWakeEvent.\n        // This will remove all waiters from the list. However, we may not have popped and unblocked\n        // the cancelled wait block ourselves. Another thread may have popped all waiters but not\n        // unblocked them yet at this point:\n        //\n        // 1. This thread: calls PhfQueueWakeEvent.\n        // 2. This thread: code determines that the wait should be cancelled.\n        // 3. Other thread: calls PhfSetWakeEvent and pops our wait block off. It hasn't unblocked\n        //    any wait blocks yet.\n        // 4. This thread: calls PhfSetWakeEvent. Since all wait blocks have been popped, we don't\n        //    do anything. The caller function exits, making our wait block invalid.\n        // 5. Other thread: tries to unblock our wait block. Anything could happen, since our caller\n        //    already returned.\n        //\n        // The solution is to (always) wait for an unblock. Note that the check below for the\n        // spinning flag is not required, but it is a small optimization. If the wait block has been\n        // unblocked (i.e. the spinning flag is cleared), then there's no danger.\n\n        if (WaitBlock->Flags & PH_QUEUED_WAITER_SPINNING)\n            PhpBlockOnQueuedWaitBlock(WaitBlock, FALSE, NULL);\n    }\n}\n\n/**\n * Waits for a wake event to be set.\n *\n * \\param WakeEvent A wake event.\n * \\param WaitBlock A wait block previously queued to the wake event using PhfQueueWakeEvent().\n * \\param Spin TRUE to spin on the wake event before blocking, FALSE to block immediately.\n * \\param Timeout A timeout value.\n *\n * \\remarks Wake events are subject to spurious wakeups. You should call this function in a loop\n * which checks a predicate.\n */\nNTSTATUS FASTCALL PhfWaitForWakeEvent(\n    _Inout_ PPH_WAKE_EVENT WakeEvent,\n    _Inout_ PPH_QUEUED_WAIT_BLOCK WaitBlock,\n    _In_ BOOLEAN Spin,\n    _In_opt_ PLARGE_INTEGER Timeout\n    )\n{\n    NTSTATUS status;\n\n    status = PhpBlockOnQueuedWaitBlock(WaitBlock, Spin, Timeout);\n\n    if (status != STATUS_SUCCESS)\n    {\n        // Probably a timeout. There's no way of unlinking the wait block safely, so just wake\n        // everyone.\n        PhSetWakeEvent(WakeEvent, WaitBlock);\n    }\n\n    return status;\n}\n"
  },
  {
    "path": "third_party/phlib/ref.c",
    "content": "/*\n * Process Hacker -\n *   object manager\n *\n * Copyright (C) 2009-2016 wj32\n *\n * This file is part of Process Hacker.\n *\n * Process Hacker is free software; you can redistribute it and/or modify\n * it under the terms of the GNU General Public License as published by\n * the Free Software Foundation, either version 3 of the License, or\n * (at your option) any later version.\n *\n * Process Hacker is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n * GNU General Public License for more details.\n *\n * You should have received a copy of the GNU General Public License\n * along with Process Hacker.  If not, see <http://www.gnu.org/licenses/>.\n */\n\n#include <phbase.h>\n#include <refp.h>\n\n#include <phintrnl.h>\n#include <workqueue.h>\n\nPPH_OBJECT_TYPE PhObjectTypeObject = NULL;\nSLIST_HEADER PhObjectDeferDeleteListHead;\nPH_FREE_LIST PhObjectSmallFreeList;\nPPH_OBJECT_TYPE PhAllocType = NULL;\n\nULONG PhObjectTypeCount = 0;\nPPH_OBJECT_TYPE PhObjectTypeTable[PH_OBJECT_TYPE_TABLE_SIZE];\n\nstatic ULONG PhpAutoPoolTlsIndex;\n\n#ifdef DEBUG\nLIST_ENTRY PhDbgObjectListHead;\nPH_QUEUED_LOCK PhDbgObjectListLock = PH_QUEUED_LOCK_INIT;\nPPH_CREATE_OBJECT_HOOK PhDbgCreateObjectHook = NULL;\n#endif\n\n#define REF_STAT_UP(Name) PHLIB_INC_STATISTIC(Name)\n\n/**\n * Initializes the object manager module.\n */\nNTSTATUS PhRefInitialization(\n    VOID\n    )\n{\n    PH_OBJECT_TYPE dummyObjectType;\n\n#ifdef DEBUG\n    InitializeListHead(&PhDbgObjectListHead);\n#endif\n\n    RtlInitializeSListHead(&PhObjectDeferDeleteListHead);\n    PhInitializeFreeList(\n        &PhObjectSmallFreeList,\n        PhAddObjectHeaderSize(PH_OBJECT_SMALL_OBJECT_SIZE),\n        PH_OBJECT_SMALL_OBJECT_COUNT\n        );\n\n    // Create the fundamental object type.\n\n    memset(&dummyObjectType, 0, sizeof(PH_OBJECT_TYPE));\n    PhObjectTypeObject = &dummyObjectType; // PhCreateObject expects an object type.\n    PhObjectTypeTable[0] = &dummyObjectType; // PhCreateObject also expects PhObjectTypeTable[0] to be filled in.\n    PhObjectTypeObject = PhCreateObjectType(L\"Type\", 0, NULL);\n\n    // Now that the fundamental object type exists, fix it up.\n    PhObjectToObjectHeader(PhObjectTypeObject)->TypeIndex = PhObjectTypeObject->TypeIndex;\n    PhObjectTypeObject->NumberOfObjects = 1;\n\n    // Create the allocated memory object type.\n    PhAllocType = PhCreateObjectType(L\"Alloc\", 0, NULL);\n\n    // Reserve a slot for the auto pool.\n    PhpAutoPoolTlsIndex = TlsAlloc();\n\n    if (PhpAutoPoolTlsIndex == TLS_OUT_OF_INDEXES)\n        return STATUS_INSUFFICIENT_RESOURCES;\n\n    return STATUS_SUCCESS;\n}\n\n/**\n * Allocates a object.\n *\n * \\param ObjectSize The size of the object.\n * \\param ObjectType The type of the object.\n *\n * \\return A pointer to the newly allocated object.\n */\n_May_raise_ PVOID PhCreateObject(\n    _In_ SIZE_T ObjectSize,\n    _In_ PPH_OBJECT_TYPE ObjectType\n    )\n{\n    NTSTATUS status = STATUS_SUCCESS;\n    PPH_OBJECT_HEADER objectHeader;\n\n    // Allocate storage for the object. Note that this includes the object header followed by the\n    // object body.\n    objectHeader = PhpAllocateObject(ObjectType, ObjectSize);\n\n    // Object type statistics.\n    _InterlockedIncrement((PLONG)&ObjectType->NumberOfObjects);\n\n    // Initialize the object header.\n    objectHeader->RefCount = 1;\n    objectHeader->TypeIndex = ObjectType->TypeIndex;\n    // objectHeader->Flags is set by PhpAllocateObject.\n\n    REF_STAT_UP(RefObjectsCreated);\n\n#ifdef DEBUG\n    {\n        USHORT capturedFrames;\n\n        capturedFrames = RtlCaptureStackBackTrace(1, 16, objectHeader->StackBackTrace, NULL);\n        memset(\n            &objectHeader->StackBackTrace[capturedFrames],\n            0,\n            sizeof(objectHeader->StackBackTrace) - capturedFrames * sizeof(PVOID)\n            );\n    }\n\n    PhAcquireQueuedLockExclusive(&PhDbgObjectListLock);\n    InsertTailList(&PhDbgObjectListHead, &objectHeader->ObjectListEntry);\n    PhReleaseQueuedLockExclusive(&PhDbgObjectListLock);\n\n    {\n        PPH_CREATE_OBJECT_HOOK dbgCreateObjectHook;\n\n        dbgCreateObjectHook = PhDbgCreateObjectHook;\n\n        if (dbgCreateObjectHook)\n        {\n            dbgCreateObjectHook(\n                PhObjectHeaderToObject(objectHeader),\n                ObjectSize,\n                0,\n                ObjectType\n                );\n        }\n    }\n#endif\n\n    return PhObjectHeaderToObject(objectHeader);\n}\n\n/**\n * References the specified object.\n *\n * \\param Object A pointer to the object to reference.\n *\n * \\return The object.\n */\nPVOID PhReferenceObject(\n    _In_ PVOID Object\n    )\n{\n    PPH_OBJECT_HEADER objectHeader;\n\n    objectHeader = PhObjectToObjectHeader(Object);\n    // Increment the reference count.\n    _InterlockedIncrement(&objectHeader->RefCount);\n\n    return Object;\n}\n\n/**\n * References the specified object.\n *\n * \\param Object A pointer to the object to reference.\n * \\param RefCount The number of references to add.\n *\n * \\return The object.\n */\n_May_raise_ PVOID PhReferenceObjectEx(\n    _In_ PVOID Object,\n    _In_ LONG RefCount\n    )\n{\n    PPH_OBJECT_HEADER objectHeader;\n    LONG oldRefCount;\n\n    assert(!(RefCount < 0));\n\n    objectHeader = PhObjectToObjectHeader(Object);\n    // Increase the reference count.\n    oldRefCount = _InterlockedExchangeAdd(&objectHeader->RefCount, RefCount);\n\n    return Object;\n}\n\n/**\n * Attempts to reference an object and fails if it is being destroyed.\n *\n * \\param Object The object to reference if it is not being deleted.\n *\n * \\return The object itself if the object was referenced, NULL if it was being deleted and was not\n * referenced.\n *\n * \\remarks This function is useful if a reference to an object is held, protected by a mutex, and\n * the delete procedure of the object's type attempts to acquire the mutex. If this function is\n * called while the mutex is owned, you can avoid referencing an object that is being destroyed.\n */\nPVOID PhReferenceObjectSafe(\n    _In_ PVOID Object\n    )\n{\n    PPH_OBJECT_HEADER objectHeader;\n\n    objectHeader = PhObjectToObjectHeader(Object);\n\n    // Increase the reference count only if it positive already (atomically).\n    if (PhpInterlockedIncrementSafe(&objectHeader->RefCount))\n        return Object;\n    else\n        return NULL;\n}\n\n/**\n * Dereferences the specified object.\n * The object will be freed if its reference count reaches 0.\n *\n * \\param Object A pointer to the object to dereference.\n */\nVOID PhDereferenceObject(\n    _In_ PVOID Object\n    )\n{\n    PPH_OBJECT_HEADER objectHeader;\n    LONG newRefCount;\n\n    objectHeader = PhObjectToObjectHeader(Object);\n    // Decrement the reference count.\n    newRefCount = _InterlockedDecrement(&objectHeader->RefCount);\n    ASSUME_ASSERT(newRefCount >= 0);\n\n    // Free the object if it has 0 references.\n    if (newRefCount == 0)\n    {\n        PhpFreeObject(objectHeader);\n    }\n}\n\n/**\n * Dereferences the specified object.\n * The object will be freed in a worker thread if its reference count reaches 0.\n *\n * \\param Object A pointer to the object to dereference.\n */\nVOID PhDereferenceObjectDeferDelete(\n    _In_ PVOID Object\n    )\n{\n    PhDereferenceObjectEx(Object, 1, TRUE);\n}\n\n/**\n * Dereferences the specified object.\n * The object will be freed if its reference count reaches 0.\n *\n * \\param Object A pointer to the object to dereference.\n * \\param RefCount The number of references to remove.\n * \\param DeferDelete Whether to defer deletion of the object.\n */\n_May_raise_ VOID PhDereferenceObjectEx(\n    _In_ PVOID Object,\n    _In_ LONG RefCount,\n    _In_ BOOLEAN DeferDelete\n    )\n{\n    PPH_OBJECT_HEADER objectHeader;\n    LONG oldRefCount;\n    LONG newRefCount;\n\n    assert(!(RefCount < 0));\n\n    objectHeader = PhObjectToObjectHeader(Object);\n\n    // Decrease the reference count.\n    oldRefCount = _InterlockedExchangeAdd(&objectHeader->RefCount, -RefCount);\n    newRefCount = oldRefCount - RefCount;\n\n    // Free the object if it has 0 references.\n    if (newRefCount == 0)\n    {\n        if (DeferDelete)\n        {\n            PhpDeferDeleteObject(objectHeader);\n        }\n        else\n        {\n            // Free the object.\n            PhpFreeObject(objectHeader);\n        }\n    }\n    else if (newRefCount < 0)\n    {\n        PhRaiseStatus(STATUS_INVALID_PARAMETER);\n    }\n}\n\n/**\n * Gets an object's type.\n *\n * \\param Object A pointer to an object.\n *\n * \\return A pointer to a type object.\n */\nPPH_OBJECT_TYPE PhGetObjectType(\n    _In_ PVOID Object\n    )\n{\n    return PhObjectTypeTable[PhObjectToObjectHeader(Object)->TypeIndex];\n}\n\n/**\n * Creates an object type.\n *\n * \\param Name The name of the type.\n * \\param Flags A combination of flags affecting the behaviour of the object type.\n * \\param DeleteProcedure A callback function that is executed when an object of this type is about\n * to be freed (i.e. when its reference count is 0).\n *\n * \\return A pointer to the newly created object type.\n *\n * \\remarks Do not reference or dereference the object type once it is created.\n */\nPPH_OBJECT_TYPE PhCreateObjectType(\n    _In_ PWSTR Name,\n    _In_ ULONG Flags,\n    _In_opt_ PPH_TYPE_DELETE_PROCEDURE DeleteProcedure\n    )\n{\n    return PhCreateObjectTypeEx(\n        Name,\n        Flags,\n        DeleteProcedure,\n        NULL\n        );\n}\n\n/**\n * Creates an object type.\n *\n * \\param Name The name of the type.\n * \\param Flags A combination of flags affecting the behaviour of the object type.\n * \\param DeleteProcedure A callback function that is executed when an object of this type is about\n * to be freed (i.e. when its reference count is 0).\n * \\param Parameters A structure containing additional parameters for the object type.\n *\n * \\return A pointer to the newly created object type.\n *\n * \\remarks Do not reference or dereference the object type once it is created.\n */\nPPH_OBJECT_TYPE PhCreateObjectTypeEx(\n    _In_ PWSTR Name,\n    _In_ ULONG Flags,\n    _In_opt_ PPH_TYPE_DELETE_PROCEDURE DeleteProcedure,\n    _In_opt_ PPH_OBJECT_TYPE_PARAMETERS Parameters\n    )\n{\n    NTSTATUS status = STATUS_SUCCESS;\n    PPH_OBJECT_TYPE objectType;\n\n    // Check the flags.\n    if ((Flags & PH_OBJECT_TYPE_VALID_FLAGS) != Flags) /* Valid flag mask */\n        PhRaiseStatus(STATUS_INVALID_PARAMETER_3);\n    if ((Flags & PH_OBJECT_TYPE_USE_FREE_LIST) && !Parameters)\n        PhRaiseStatus(STATUS_INVALID_PARAMETER_MIX);\n\n    // Create the type object.\n    objectType = PhCreateObject(sizeof(PH_OBJECT_TYPE), PhObjectTypeObject);\n\n    // Initialize the type object.\n    objectType->Flags = (USHORT)Flags;\n    objectType->TypeIndex = (USHORT)_InterlockedIncrement(&PhObjectTypeCount) - 1;\n    objectType->NumberOfObjects = 0;\n    objectType->DeleteProcedure = DeleteProcedure;\n    objectType->Name = Name;\n\n    if (objectType->TypeIndex < PH_OBJECT_TYPE_TABLE_SIZE)\n        PhObjectTypeTable[objectType->TypeIndex] = objectType;\n    else\n        PhRaiseStatus(STATUS_UNSUCCESSFUL);\n\n    if (Parameters)\n    {\n        if (Flags & PH_OBJECT_TYPE_USE_FREE_LIST)\n        {\n            PhInitializeFreeList(\n                &objectType->FreeList,\n                PhAddObjectHeaderSize(Parameters->FreeListSize),\n                Parameters->FreeListCount\n                );\n        }\n    }\n\n    return objectType;\n}\n\n/**\n * Gets information about an object type.\n *\n * \\param ObjectType A pointer to an object type.\n * \\param Information A variable which receives information about the object type.\n */\nVOID PhGetObjectTypeInformation(\n    _In_ PPH_OBJECT_TYPE ObjectType,\n    _Out_ PPH_OBJECT_TYPE_INFORMATION Information\n    )\n{\n    Information->Name = ObjectType->Name;\n    Information->NumberOfObjects = ObjectType->NumberOfObjects;\n    Information->Flags = ObjectType->Flags;\n    Information->TypeIndex = ObjectType->TypeIndex;\n}\n\n/**\n * Allocates storage for an object.\n *\n * \\param ObjectType The type of the object.\n * \\param ObjectSize The size of the object, excluding the header.\n */\nPPH_OBJECT_HEADER PhpAllocateObject(\n    _In_ PPH_OBJECT_TYPE ObjectType,\n    _In_ SIZE_T ObjectSize\n    )\n{\n    PPH_OBJECT_HEADER objectHeader;\n\n    if (ObjectType->Flags & PH_OBJECT_TYPE_USE_FREE_LIST)\n    {\n        assert(ObjectType->FreeList.Size == PhAddObjectHeaderSize(ObjectSize));\n\n        objectHeader = PhAllocateFromFreeList(&ObjectType->FreeList);\n        objectHeader->Flags = PH_OBJECT_FROM_TYPE_FREE_LIST;\n        REF_STAT_UP(RefObjectsAllocatedFromTypeFreeList);\n    }\n    else if (ObjectSize <= PH_OBJECT_SMALL_OBJECT_SIZE)\n    {\n        objectHeader = PhAllocateFromFreeList(&PhObjectSmallFreeList);\n        objectHeader->Flags = PH_OBJECT_FROM_SMALL_FREE_LIST;\n        REF_STAT_UP(RefObjectsAllocatedFromSmallFreeList);\n    }\n    else\n    {\n        objectHeader = PhAllocate(PhAddObjectHeaderSize(ObjectSize));\n        objectHeader->Flags = 0;\n        REF_STAT_UP(RefObjectsAllocated);\n    }\n\n    return objectHeader;\n}\n\n/**\n * Calls the delete procedure for an object and frees its allocated storage.\n *\n * \\param ObjectHeader A pointer to the object header of an allocated object.\n */\nVOID PhpFreeObject(\n    _In_ PPH_OBJECT_HEADER ObjectHeader\n    )\n{\n    PPH_OBJECT_TYPE objectType;\n\n    objectType = PhObjectTypeTable[ObjectHeader->TypeIndex];\n\n    // Object type statistics.\n    _InterlockedDecrement(&objectType->NumberOfObjects);\n\n#ifdef DEBUG\n    PhAcquireQueuedLockExclusive(&PhDbgObjectListLock);\n    RemoveEntryList(&ObjectHeader->ObjectListEntry);\n    PhReleaseQueuedLockExclusive(&PhDbgObjectListLock);\n#endif\n\n    REF_STAT_UP(RefObjectsDestroyed);\n\n    // Call the delete procedure if we have one.\n    if (objectType->DeleteProcedure)\n    {\n        objectType->DeleteProcedure(PhObjectHeaderToObject(ObjectHeader), 0);\n    }\n\n    if (ObjectHeader->Flags & PH_OBJECT_FROM_TYPE_FREE_LIST)\n    {\n        PhFreeToFreeList(&objectType->FreeList, ObjectHeader);\n        REF_STAT_UP(RefObjectsFreedToTypeFreeList);\n    }\n    else if (ObjectHeader->Flags & PH_OBJECT_FROM_SMALL_FREE_LIST)\n    {\n        PhFreeToFreeList(&PhObjectSmallFreeList, ObjectHeader);\n        REF_STAT_UP(RefObjectsFreedToSmallFreeList);\n    }\n    else\n    {\n        PhFree(ObjectHeader);\n        REF_STAT_UP(RefObjectsFreed);\n    }\n}\n\n/**\n * Queues an object for deletion.\n *\n * \\param ObjectHeader A pointer to the object header of the object to delete.\n */\nVOID PhpDeferDeleteObject(\n    _In_ PPH_OBJECT_HEADER ObjectHeader\n    )\n{\n    PSLIST_ENTRY oldFirstEntry;\n\n    // Save TypeIndex and Flags since they get overwritten when we push the object onto the defer\n    // delete list.\n    ObjectHeader->DeferDelete = 1;\n    MemoryBarrier();\n    ObjectHeader->SavedTypeIndex = ObjectHeader->TypeIndex;\n    ObjectHeader->SavedFlags = ObjectHeader->Flags;\n\n    oldFirstEntry = RtlFirstEntrySList(&PhObjectDeferDeleteListHead);\n    RtlInterlockedPushEntrySList(&PhObjectDeferDeleteListHead, &ObjectHeader->DeferDeleteListEntry);\n    REF_STAT_UP(RefObjectsDeleteDeferred);\n\n    // Was the to-free list empty before? If so, we need to queue a work item.\n    if (!oldFirstEntry)\n    {\n        PhQueueItemWorkQueue(PhGetGlobalWorkQueue(), PhpDeferDeleteObjectRoutine, NULL);\n    }\n}\n\n/**\n * Removes and frees objects from the to-free list.\n */\nNTSTATUS PhpDeferDeleteObjectRoutine(\n    _In_ PVOID Parameter\n    )\n{\n    PSLIST_ENTRY listEntry;\n    PPH_OBJECT_HEADER objectHeader;\n\n    // Clear the list and obtain the first object to free.\n    listEntry = RtlInterlockedFlushSList(&PhObjectDeferDeleteListHead);\n\n    while (listEntry)\n    {\n        objectHeader = CONTAINING_RECORD(listEntry, PH_OBJECT_HEADER, DeferDeleteListEntry);\n        listEntry = listEntry->Next;\n\n        // Restore TypeIndex and Flags.\n        objectHeader->TypeIndex = (USHORT)objectHeader->SavedTypeIndex;\n        objectHeader->Flags = (UCHAR)objectHeader->SavedFlags;\n\n        PhpFreeObject(objectHeader);\n    }\n\n    return STATUS_SUCCESS;\n}\n\n/**\n * Creates a reference-counted memory block.\n *\n * \\param Size The number of bytes to allocate.\n *\n * \\return A pointer to the memory block.\n */\nPVOID PhCreateAlloc(\n    _In_ SIZE_T Size\n    )\n{\n    return PhCreateObject(Size, PhAllocType);\n}\n\n/**\n * Gets the current auto-dereference pool for the current thread.\n */\nFORCEINLINE PPH_AUTO_POOL PhpGetCurrentAutoPool(\n    VOID\n    )\n{\n    return (PPH_AUTO_POOL)TlsGetValue(PhpAutoPoolTlsIndex);\n}\n\n/**\n * Sets the current auto-dereference pool for the current thread.\n */\n_May_raise_ FORCEINLINE VOID PhpSetCurrentAutoPool(\n    _In_ PPH_AUTO_POOL AutoPool\n    )\n{\n    if (!TlsSetValue(PhpAutoPoolTlsIndex, AutoPool))\n        PhRaiseStatus(STATUS_UNSUCCESSFUL);\n\n#ifdef DEBUG\n    {\n        PPHP_BASE_THREAD_DBG dbg;\n\n        dbg = (PPHP_BASE_THREAD_DBG)TlsGetValue(PhDbgThreadDbgTlsIndex);\n\n        if (dbg)\n        {\n            dbg->CurrentAutoPool = AutoPool;\n        }\n    }\n#endif\n}\n\n/**\n * Initializes an auto-dereference pool and sets it as the current pool for the current thread. You\n * must call PhDeleteAutoPool() before storage for the auto-dereference pool is freed.\n *\n * \\remarks Always store auto-dereference pools in local variables, and do not share the pool with\n * any other functions.\n */\nVOID PhInitializeAutoPool(\n    _Out_ PPH_AUTO_POOL AutoPool\n    )\n{\n    AutoPool->StaticCount = 0;\n    AutoPool->DynamicCount = 0;\n    AutoPool->DynamicAllocated = 0;\n    AutoPool->DynamicObjects = NULL;\n\n    // Add the pool to the stack.\n    AutoPool->NextPool = PhpGetCurrentAutoPool();\n    PhpSetCurrentAutoPool(AutoPool);\n\n    REF_STAT_UP(RefAutoPoolsCreated);\n}\n\n/**\n * Deletes an auto-dereference pool. The function will dereference any objects currently in the\n * pool. If a pool other than the current pool is passed to the function, an exception is raised.\n *\n * \\param AutoPool The auto-dereference pool to delete.\n */\n_May_raise_ VOID PhDeleteAutoPool(\n    _Inout_ PPH_AUTO_POOL AutoPool\n    )\n{\n    PhDrainAutoPool(AutoPool);\n\n    if (PhpGetCurrentAutoPool() != AutoPool)\n        PhRaiseStatus(STATUS_UNSUCCESSFUL);\n\n    // Remove the pool from the stack.\n    PhpSetCurrentAutoPool(AutoPool->NextPool);\n\n    // Free the dynamic array if it hasn't been freed yet.\n    if (AutoPool->DynamicObjects)\n        PhFree(AutoPool->DynamicObjects);\n\n    REF_STAT_UP(RefAutoPoolsDestroyed);\n}\n\n/**\n * Dereferences and removes all objects in an auto-release pool.\n *\n * \\param AutoPool The auto-release pool to drain.\n */\nVOID PhDrainAutoPool(\n    _In_ PPH_AUTO_POOL AutoPool\n    )\n{\n    ULONG i;\n\n    for (i = 0; i < AutoPool->StaticCount; i++)\n        PhDereferenceObject(AutoPool->StaticObjects[i]);\n\n    AutoPool->StaticCount = 0;\n\n    if (AutoPool->DynamicObjects)\n    {\n        for (i = 0; i < AutoPool->DynamicCount; i++)\n        {\n            PhDereferenceObject(AutoPool->DynamicObjects[i]);\n        }\n\n        AutoPool->DynamicCount = 0;\n\n        if (AutoPool->DynamicAllocated > PH_AUTO_POOL_DYNAMIC_BIG_SIZE)\n        {\n            AutoPool->DynamicAllocated = 0;\n            PhFree(AutoPool->DynamicObjects);\n            AutoPool->DynamicObjects = NULL;\n        }\n    }\n}\n\n/**\n * Adds an object to the current auto-dereference pool for the current thread. If the current thread\n * does not have an auto-dereference pool, the function raises an exception.\n *\n * \\param Object A pointer to an object. The object will be dereferenced when the current\n * auto-dereference pool is drained or freed.\n */\n_May_raise_ PVOID PhAutoDereferenceObject(\n    _In_opt_ PVOID Object\n    )\n{\n    PPH_AUTO_POOL autoPool = PhpGetCurrentAutoPool();\n\n#ifdef DEBUG\n    // If we don't have an auto-dereference pool, we don't want to leak the object (unlike what\n    // Apple does with NSAutoreleasePool).\n    if (!autoPool)\n        PhRaiseStatus(STATUS_UNSUCCESSFUL);\n#endif\n\n    if (!Object)\n        return NULL;\n\n    // See if we can use the static array.\n    if (autoPool->StaticCount < PH_AUTO_POOL_STATIC_SIZE)\n    {\n        autoPool->StaticObjects[autoPool->StaticCount++] = Object;\n        return Object;\n    }\n\n    // Use the dynamic array.\n\n    // Allocate the array if we haven't already.\n    if (!autoPool->DynamicObjects)\n    {\n        autoPool->DynamicAllocated = 64;\n        autoPool->DynamicObjects = PhAllocate(\n            sizeof(PVOID) * autoPool->DynamicAllocated\n            );\n        REF_STAT_UP(RefAutoPoolsDynamicAllocated);\n    }\n\n    // See if we need to resize the array.\n    if (autoPool->DynamicCount == autoPool->DynamicAllocated)\n    {\n        autoPool->DynamicAllocated *= 2;\n        autoPool->DynamicObjects = PhReAllocate(\n            autoPool->DynamicObjects,\n            sizeof(PVOID) * autoPool->DynamicAllocated\n            );\n        REF_STAT_UP(RefAutoPoolsDynamicResized);\n    }\n\n    autoPool->DynamicObjects[autoPool->DynamicCount++] = Object;\n\n    return Object;\n}\n"
  },
  {
    "path": "third_party/phlib/secdata.c",
    "content": "/*\n * Process Hacker -\n *   object security data\n *\n * Copyright (C) 2010-2016 wj32\n *\n * This file is part of Process Hacker.\n *\n * Process Hacker is free software; you can redistribute it and/or modify\n * it under the terms of the GNU General Public License as published by\n * the Free Software Foundation, either version 3 of the License, or\n * (at your option) any later version.\n *\n * Process Hacker is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n * GNU General Public License for more details.\n *\n * You should have received a copy of the GNU General Public License\n * along with Process Hacker.  If not, see <http://www.gnu.org/licenses/>.\n */\n\n#include <ph.h>\n#include <secedit.h>\n\n#include <wmistr.h>\n\n#include <guisup.h>\n\n#define ACCESS_ENTRIES(Type) static PH_ACCESS_ENTRY Ph##Type##AccessEntries[] =\n#define ACCESS_ENTRY(Type, HasSynchronize) \\\n    { L#Type, Ph##Type##AccessEntries, sizeof(Ph##Type##AccessEntries), HasSynchronize }\n\ntypedef struct _PH_SPECIFIC_TYPE\n{\n    PWSTR Type;\n    PPH_ACCESS_ENTRY AccessEntries;\n    ULONG SizeOfAccessEntries;\n    BOOLEAN HasSynchronize;\n} PH_SPECIFIC_TYPE, *PPH_SPECIFIC_TYPE;\n\nACCESS_ENTRIES(Standard)\n{\n    { L\"Synchronize\", SYNCHRONIZE, FALSE, TRUE },\n    { L\"Delete\", DELETE, FALSE, TRUE },\n    { L\"Read permissions\", READ_CONTROL, FALSE, TRUE, L\"Read control\" },\n    { L\"Change permissions\", WRITE_DAC, FALSE, TRUE, L\"Write DAC\" },\n    { L\"Take ownership\", WRITE_OWNER, FALSE, TRUE, L\"Write owner\" }\n};\n\nACCESS_ENTRIES(AlpcPort)\n{\n    { L\"Full control\", PORT_ALL_ACCESS, TRUE, TRUE },\n    { L\"Connect\", PORT_CONNECT, TRUE, TRUE }\n};\n\nACCESS_ENTRIES(DebugObject)\n{\n    { L\"Full control\", DEBUG_ALL_ACCESS, TRUE, TRUE },\n    { L\"Read events\", DEBUG_READ_EVENT, TRUE, TRUE },\n    { L\"Assign processes\", DEBUG_PROCESS_ASSIGN, TRUE, TRUE },\n    { L\"Query information\", DEBUG_QUERY_INFORMATION, TRUE, TRUE },\n    { L\"Set information\", DEBUG_SET_INFORMATION, TRUE, TRUE }\n};\n\nACCESS_ENTRIES(Desktop)\n{\n    { L\"Full control\", DESKTOP_ALL_ACCESS, TRUE, TRUE },\n    { L\"Read\", DESKTOP_GENERIC_READ, TRUE, FALSE },\n    { L\"Write\", DESKTOP_GENERIC_WRITE, TRUE, FALSE },\n    { L\"Execute\", DESKTOP_GENERIC_EXECUTE, TRUE, FALSE },\n    { L\"Enumerate\", DESKTOP_ENUMERATE, FALSE, TRUE },\n    { L\"Read objects\", DESKTOP_READOBJECTS, FALSE, TRUE },\n    { L\"Playback journals\", DESKTOP_JOURNALPLAYBACK, FALSE, TRUE },\n    { L\"Write objects\", DESKTOP_WRITEOBJECTS, FALSE, TRUE },\n    { L\"Create windows\", DESKTOP_CREATEWINDOW, FALSE, TRUE },\n    { L\"Create menus\", DESKTOP_CREATEMENU, FALSE, TRUE },\n    { L\"Create window hooks\", DESKTOP_HOOKCONTROL, FALSE, TRUE },\n    { L\"Record journals\", DESKTOP_JOURNALRECORD, FALSE, TRUE },\n    { L\"Switch desktop\", DESKTOP_SWITCHDESKTOP, FALSE, TRUE }\n};\n\nACCESS_ENTRIES(Directory)\n{\n    { L\"Full control\", DIRECTORY_ALL_ACCESS, TRUE, TRUE },\n    { L\"Query\", DIRECTORY_QUERY, TRUE, TRUE},\n    { L\"Traverse\", DIRECTORY_TRAVERSE, TRUE, TRUE},\n    { L\"Create objects\", DIRECTORY_CREATE_OBJECT, TRUE, TRUE},\n    { L\"Create subdirectories\", DIRECTORY_CREATE_SUBDIRECTORY, TRUE, TRUE}\n};\n\nACCESS_ENTRIES(Event)\n{\n    { L\"Full control\", EVENT_ALL_ACCESS, TRUE, TRUE },\n    { L\"Query\", EVENT_QUERY_STATE, TRUE, TRUE },\n    { L\"Modify\", EVENT_MODIFY_STATE, TRUE, TRUE }\n};\n\nACCESS_ENTRIES(EventPair)\n{\n    { L\"Full control\", EVENT_PAIR_ALL_ACCESS, TRUE, TRUE }\n};\n\nACCESS_ENTRIES(File)\n{\n    { L\"Full control\", FILE_ALL_ACCESS, TRUE, TRUE },\n    { L\"Read & execute\", FILE_GENERIC_READ | FILE_GENERIC_EXECUTE, TRUE, FALSE },\n    { L\"Read\", FILE_GENERIC_READ, TRUE, FALSE },\n    { L\"Write\", FILE_GENERIC_WRITE, TRUE, FALSE },\n    { L\"Traverse folder / execute file\", FILE_EXECUTE, FALSE, TRUE, L\"Execute\" },\n    { L\"List folder / read data\", FILE_READ_DATA, FALSE, TRUE, L\"Read data\" },\n    { L\"Read attributes\", FILE_READ_ATTRIBUTES, FALSE, TRUE },\n    { L\"Read extended attributes\", FILE_READ_EA, FALSE, TRUE, L\"Read EA\" },\n    { L\"Create files / write data\", FILE_WRITE_DATA, FALSE, TRUE, L\"Write data\" },\n    { L\"Create folders / append data\", FILE_APPEND_DATA, FALSE, TRUE, L\"Append data\" },\n    { L\"Write attributes\", FILE_WRITE_ATTRIBUTES, FALSE, TRUE },\n    { L\"Write extended attributes\", FILE_WRITE_EA, FALSE, TRUE, L\"Write EA\" },\n    { L\"Delete subfolders and files\", FILE_DELETE_CHILD, FALSE, TRUE, L\"Delete child\" }\n};\n\nACCESS_ENTRIES(FilterConnectionPort)\n{\n    { L\"Full control\", FLT_PORT_ALL_ACCESS, TRUE, TRUE },\n    { L\"Connect\", FLT_PORT_CONNECT, TRUE, TRUE }\n};\n\nACCESS_ENTRIES(IoCompletion)\n{\n    { L\"Full control\", IO_COMPLETION_ALL_ACCESS, TRUE, TRUE },\n    { L\"Query\", IO_COMPLETION_QUERY_STATE, TRUE, TRUE },\n    { L\"Modify\", IO_COMPLETION_MODIFY_STATE, TRUE, TRUE }\n};\n\nACCESS_ENTRIES(Job)\n{\n    { L\"Full control\", JOB_OBJECT_ALL_ACCESS, TRUE, TRUE },\n    { L\"Query\", JOB_OBJECT_QUERY, TRUE, TRUE },\n    { L\"Assign processes\", JOB_OBJECT_ASSIGN_PROCESS, TRUE, TRUE },\n    { L\"Set attributes\", JOB_OBJECT_SET_ATTRIBUTES, TRUE, TRUE },\n    { L\"Set security attributes\", JOB_OBJECT_SET_SECURITY_ATTRIBUTES, TRUE, TRUE },\n    { L\"Terminate\", JOB_OBJECT_TERMINATE, TRUE, TRUE }\n};\n\nACCESS_ENTRIES(Key)\n{\n    { L\"Full control\", KEY_ALL_ACCESS, TRUE, TRUE },\n    { L\"Read\", KEY_READ, TRUE, FALSE },\n    { L\"Write\", KEY_WRITE, TRUE, FALSE },\n    { L\"Execute\", KEY_EXECUTE, TRUE, FALSE },\n    { L\"Enumerate subkeys\", KEY_ENUMERATE_SUB_KEYS, FALSE, TRUE },\n    { L\"Query values\", KEY_QUERY_VALUE, FALSE, TRUE },\n    { L\"Notify\", KEY_NOTIFY, FALSE, TRUE },\n    { L\"Set values\", KEY_SET_VALUE, FALSE, TRUE },\n    { L\"Create subkeys\", KEY_CREATE_SUB_KEY, FALSE, TRUE },\n    { L\"Create links\", KEY_CREATE_LINK, FALSE, TRUE }\n};\n\nACCESS_ENTRIES(KeyedEvent)\n{\n    { L\"Full control\", KEYEDEVENT_ALL_ACCESS, TRUE, TRUE },\n    { L\"Wait\", KEYEDEVENT_WAIT, TRUE, TRUE },\n    { L\"Wake\", KEYEDEVENT_WAKE, TRUE, TRUE }\n};\n\nACCESS_ENTRIES(LsaAccount)\n{\n    { L\"Full control\", ACCOUNT_ALL_ACCESS, TRUE, TRUE },\n    { L\"Read\", ACCOUNT_READ, TRUE, FALSE },\n    { L\"Write\", ACCOUNT_WRITE, TRUE, FALSE },\n    { L\"Execute\", ACCOUNT_EXECUTE, TRUE, FALSE },\n    { L\"View\", ACCOUNT_VIEW, FALSE, TRUE },\n    { L\"Adjust privileges\", ACCOUNT_ADJUST_PRIVILEGES, FALSE, TRUE },\n    { L\"Adjust quotas\", ACCOUNT_ADJUST_QUOTAS, FALSE, TRUE },\n    { L\"Adjust system access\", ACCOUNT_ADJUST_SYSTEM_ACCESS, FALSE, TRUE }\n};\n\nACCESS_ENTRIES(LsaPolicy)\n{\n    { L\"Full control\", POLICY_ALL_ACCESS | POLICY_NOTIFICATION, TRUE, TRUE },\n    { L\"Read\", POLICY_READ, TRUE, FALSE },\n    { L\"Write\", POLICY_WRITE, TRUE, FALSE },\n    { L\"Execute\", POLICY_EXECUTE | POLICY_NOTIFICATION, TRUE, FALSE },\n    { L\"View local information\", POLICY_VIEW_LOCAL_INFORMATION, FALSE, TRUE },\n    { L\"View audit information\", POLICY_VIEW_AUDIT_INFORMATION, FALSE, TRUE },\n    { L\"Get private information\", POLICY_GET_PRIVATE_INFORMATION, FALSE, TRUE },\n    { L\"Administer trust\", POLICY_TRUST_ADMIN, FALSE, TRUE },\n    { L\"Create account\", POLICY_CREATE_ACCOUNT, FALSE, TRUE },\n    { L\"Create secret\", POLICY_CREATE_SECRET, FALSE, TRUE },\n    { L\"Create privilege\", POLICY_CREATE_PRIVILEGE, FALSE, TRUE },\n    { L\"Set default quota limits\", POLICY_SET_DEFAULT_QUOTA_LIMITS, FALSE, TRUE },\n    { L\"Set audit requirements\", POLICY_SET_AUDIT_REQUIREMENTS, FALSE, TRUE },\n    { L\"Administer audit log\", POLICY_AUDIT_LOG_ADMIN, FALSE, TRUE },\n    { L\"Administer server\", POLICY_SERVER_ADMIN, FALSE, TRUE },\n    { L\"Lookup names\", POLICY_LOOKUP_NAMES, FALSE, TRUE },\n    { L\"Get notifications\", POLICY_NOTIFICATION, FALSE, TRUE }\n};\n\nACCESS_ENTRIES(LsaSecret)\n{\n    { L\"Full control\", SECRET_ALL_ACCESS, TRUE, TRUE },\n    { L\"Read\", SECRET_READ, TRUE, FALSE },\n    { L\"Write\", SECRET_WRITE, TRUE, FALSE },\n    { L\"Execute\", SECRET_EXECUTE, TRUE, FALSE },\n    { L\"Set value\", SECRET_SET_VALUE, FALSE, TRUE },\n    { L\"Query value\", SECRET_QUERY_VALUE, FALSE, TRUE }\n};\n\nACCESS_ENTRIES(LsaTrusted)\n{\n    { L\"Full control\", TRUSTED_ALL_ACCESS, TRUE, TRUE },\n    { L\"Read\", TRUSTED_READ, TRUE, FALSE },\n    { L\"Write\", TRUSTED_WRITE, TRUE, FALSE },\n    { L\"Execute\", TRUSTED_EXECUTE, TRUE, FALSE },\n    { L\"Query domain name\", TRUSTED_QUERY_DOMAIN_NAME, FALSE, TRUE },\n    { L\"Query controllers\", TRUSTED_QUERY_CONTROLLERS, FALSE, TRUE },\n    { L\"Set controllers\", TRUSTED_SET_CONTROLLERS, FALSE, TRUE },\n    { L\"Query POSIX\", TRUSTED_QUERY_POSIX, FALSE, TRUE },\n    { L\"Set POSIX\", TRUSTED_SET_POSIX, FALSE, TRUE },\n    { L\"Query authentication\", TRUSTED_QUERY_AUTH, FALSE, TRUE },\n    { L\"Set authentication\", TRUSTED_SET_AUTH, FALSE, TRUE }\n};\n\nACCESS_ENTRIES(Mutant)\n{\n    { L\"Full control\", MUTANT_ALL_ACCESS, TRUE, TRUE },\n    { L\"Query\", MUTANT_QUERY_STATE, TRUE, TRUE }\n};\n\nACCESS_ENTRIES(Partition)\n{\n    { L\"Full control\", MEMORY_PARTITION_ALL_ACCESS, TRUE, TRUE },\n    { L\"Query\", MEMORY_PARTITION_QUERY_ACCESS, TRUE, TRUE },\n    { L\"Modify\", MEMORY_PARTITION_MODIFY_ACCESS, TRUE, TRUE }\n};\n\nACCESS_ENTRIES(Process)\n{\n    { L\"Full control\", STANDARD_RIGHTS_REQUIRED | SYNCHRONIZE | 0xfff, TRUE, TRUE },\n    { L\"Query information\", PROCESS_QUERY_INFORMATION, TRUE, TRUE },\n    { L\"Set information\", PROCESS_SET_INFORMATION, TRUE, TRUE },\n    { L\"Set quotas\", PROCESS_SET_QUOTA, TRUE, TRUE },\n    { L\"Set session ID\", PROCESS_SET_SESSIONID, TRUE, TRUE },\n    { L\"Create threads\", PROCESS_CREATE_THREAD, TRUE, TRUE },\n    { L\"Create processes\", PROCESS_CREATE_PROCESS, TRUE, TRUE },\n    { L\"Modify memory\", PROCESS_VM_OPERATION, TRUE, TRUE, L\"VM operation\" },\n    { L\"Read memory\", PROCESS_VM_READ, TRUE, TRUE, L\"VM read\" },\n    { L\"Write memory\", PROCESS_VM_WRITE, TRUE, TRUE, L\"VM write\" },\n    { L\"Duplicate handles\", PROCESS_DUP_HANDLE, TRUE, TRUE },\n    { L\"Suspend / resume / set port\", PROCESS_SUSPEND_RESUME, TRUE, TRUE, L\"Suspend/resume\" },\n    { L\"Terminate\", PROCESS_TERMINATE, TRUE, TRUE }\n};\n\nACCESS_ENTRIES(Process60)\n{\n    { L\"Full control\", STANDARD_RIGHTS_REQUIRED | SYNCHRONIZE | 0xffff, TRUE, TRUE }, // PROCESS_ALL_ACCESS\n    { L\"Query limited information\", PROCESS_QUERY_LIMITED_INFORMATION, TRUE, TRUE },\n    { L\"Query information\", PROCESS_QUERY_INFORMATION | PROCESS_QUERY_LIMITED_INFORMATION, TRUE, TRUE },\n    { L\"Set information\", PROCESS_SET_INFORMATION, TRUE, TRUE },\n    { L\"Set limited information\", PROCESS_SET_LIMITED_INFORMATION, TRUE, TRUE },\n    { L\"Set quotas\", PROCESS_SET_QUOTA, TRUE, TRUE },\n    { L\"Set session ID\", PROCESS_SET_SESSIONID, TRUE, TRUE },\n    { L\"Create threads\", PROCESS_CREATE_THREAD, TRUE, TRUE },\n    { L\"Create processes\", PROCESS_CREATE_PROCESS, TRUE, TRUE },\n    { L\"Modify memory\", PROCESS_VM_OPERATION, TRUE, TRUE, L\"VM operation\" },\n    { L\"Read memory\", PROCESS_VM_READ, TRUE, TRUE, L\"VM read\" },\n    { L\"Write memory\", PROCESS_VM_WRITE, TRUE, TRUE, L\"VM write\" },\n    { L\"Duplicate handles\", PROCESS_DUP_HANDLE, TRUE, TRUE },\n    { L\"Suspend / resume / set port\", PROCESS_SUSPEND_RESUME, TRUE, TRUE, L\"Suspend/resume\" },\n    { L\"Terminate\", PROCESS_TERMINATE, TRUE, TRUE }\n};\n\nACCESS_ENTRIES(Profile)\n{\n    { L\"Full control\", PROFILE_ALL_ACCESS, TRUE, TRUE },\n    { L\"Control\", PROFILE_CONTROL, TRUE, TRUE }\n};\n\nACCESS_ENTRIES(SamAlias)\n{\n    { L\"Full control\", ALIAS_ALL_ACCESS, TRUE, TRUE },\n    { L\"Read\", ALIAS_READ, TRUE, FALSE },\n    { L\"Write\", ALIAS_WRITE, TRUE, FALSE },\n    { L\"Execute\", ALIAS_EXECUTE, TRUE, FALSE },\n    { L\"Read information\", ALIAS_READ_INFORMATION, FALSE, TRUE },\n    { L\"Write account\", ALIAS_WRITE_ACCOUNT, FALSE, TRUE },\n    { L\"Add member\", ALIAS_ADD_MEMBER, FALSE, TRUE },\n    { L\"Remove member\", ALIAS_REMOVE_MEMBER, FALSE, TRUE },\n    { L\"List members\", ALIAS_LIST_MEMBERS, FALSE, TRUE }\n};\n\nACCESS_ENTRIES(SamDomain)\n{\n    { L\"Full control\", DOMAIN_ALL_ACCESS, TRUE, TRUE },\n    { L\"Read\", DOMAIN_READ, TRUE, FALSE },\n    { L\"Write\", DOMAIN_WRITE, TRUE, FALSE },\n    { L\"Execute\", DOMAIN_EXECUTE, TRUE, FALSE },\n    { L\"Read password parameters\", DOMAIN_READ_PASSWORD_PARAMETERS, FALSE, TRUE },\n    { L\"Write password parameters\", DOMAIN_WRITE_PASSWORD_PARAMS, FALSE, TRUE },\n    { L\"Read other parameters\", DOMAIN_READ_OTHER_PARAMETERS, FALSE, TRUE },\n    { L\"Write other parameters\", DOMAIN_WRITE_OTHER_PARAMETERS, FALSE, TRUE },\n    { L\"Create user\", DOMAIN_CREATE_USER, FALSE, TRUE },\n    { L\"Create group\", DOMAIN_CREATE_GROUP, FALSE, TRUE },\n    { L\"Create alias\", DOMAIN_CREATE_ALIAS, FALSE, TRUE },\n    { L\"Get alias membership\", DOMAIN_GET_ALIAS_MEMBERSHIP, FALSE, TRUE },\n    { L\"List accounts\", DOMAIN_LIST_ACCOUNTS, FALSE, TRUE },\n    { L\"Lookup\", DOMAIN_LOOKUP, FALSE, TRUE },\n    { L\"Administer server\", DOMAIN_ADMINISTER_SERVER, FALSE, TRUE }\n};\n\nACCESS_ENTRIES(SamGroup)\n{\n    { L\"Full control\", GROUP_ALL_ACCESS, TRUE, TRUE },\n    { L\"Read\", GROUP_READ, TRUE, FALSE },\n    { L\"Write\", GROUP_WRITE, TRUE, FALSE },\n    { L\"Execute\", GROUP_EXECUTE, TRUE, FALSE },\n    { L\"Read information\", GROUP_READ_INFORMATION, FALSE, TRUE },\n    { L\"Write account\", GROUP_WRITE_ACCOUNT, FALSE, TRUE },\n    { L\"Add member\", GROUP_ADD_MEMBER, FALSE, TRUE },\n    { L\"Remove member\", GROUP_REMOVE_MEMBER, FALSE, TRUE },\n    { L\"List members\", GROUP_LIST_MEMBERS, FALSE, TRUE }\n};\n\nACCESS_ENTRIES(SamServer)\n{\n    { L\"Full control\", SAM_SERVER_ALL_ACCESS, TRUE, TRUE },\n    { L\"Read\", SAM_SERVER_READ, TRUE, FALSE },\n    { L\"Write\", SAM_SERVER_WRITE, TRUE, FALSE },\n    { L\"Execute\", SAM_SERVER_EXECUTE, TRUE, FALSE },\n    { L\"Connect\", SAM_SERVER_CONNECT, FALSE, TRUE },\n    { L\"Shutdown\", SAM_SERVER_SHUTDOWN, FALSE, TRUE },\n    { L\"Initialize\", SAM_SERVER_INITIALIZE, FALSE, TRUE },\n    { L\"Create domain\", SAM_SERVER_CREATE_DOMAIN, FALSE, TRUE },\n    { L\"Enumerate domains\", SAM_SERVER_ENUMERATE_DOMAINS, FALSE, TRUE },\n    { L\"Lookup domain\", SAM_SERVER_LOOKUP_DOMAIN, FALSE, TRUE }\n};\n\nACCESS_ENTRIES(SamUser)\n{\n    { L\"Full control\", USER_ALL_ACCESS, TRUE, TRUE },\n    { L\"Read\", USER_READ, TRUE, FALSE },\n    { L\"Write\", USER_WRITE, TRUE, FALSE },\n    { L\"Execute\", USER_EXECUTE, TRUE, FALSE },\n    { L\"Read general\", USER_READ_GENERAL, FALSE, TRUE },\n    { L\"Read preferences\", USER_READ_PREFERENCES, FALSE, TRUE },\n    { L\"Write preferences\", USER_WRITE_PREFERENCES, FALSE, TRUE },\n    { L\"Read logon\", USER_READ_LOGON, FALSE, TRUE },\n    { L\"Read account\", USER_READ_ACCOUNT, FALSE, TRUE },\n    { L\"Write account\", USER_WRITE_ACCOUNT, FALSE, TRUE },\n    { L\"Change password\", USER_CHANGE_PASSWORD, FALSE, TRUE },\n    { L\"Force password change\", USER_FORCE_PASSWORD_CHANGE, FALSE, TRUE },\n    { L\"List groups\", USER_LIST_GROUPS, FALSE, TRUE },\n    { L\"Read group information\", USER_READ_GROUP_INFORMATION, FALSE, TRUE },\n    { L\"Write group information\", USER_WRITE_GROUP_INFORMATION, FALSE, TRUE }\n};\n\nACCESS_ENTRIES(Section)\n{\n    { L\"Full control\", SECTION_ALL_ACCESS, TRUE, TRUE },\n    { L\"Query\", SECTION_QUERY, TRUE, TRUE },\n    { L\"Map for read\", SECTION_MAP_READ, TRUE, TRUE, L\"Map read\" },\n    { L\"Map for write\", SECTION_MAP_WRITE, TRUE, TRUE, L\"Map write\" },\n    { L\"Map for execute\", SECTION_MAP_EXECUTE, TRUE, TRUE, L\"Map execute\" },\n    { L\"Map for execute (explicit)\", SECTION_MAP_EXECUTE_EXPLICIT, TRUE, TRUE, L\"Map execute explicit\" },\n    { L\"Extend size\", SECTION_EXTEND_SIZE, TRUE, TRUE }\n};\n\nACCESS_ENTRIES(Semaphore)\n{\n    { L\"Full control\", SEMAPHORE_ALL_ACCESS, TRUE, TRUE },\n    { L\"Query\", SEMAPHORE_QUERY_STATE, TRUE, TRUE },\n    { L\"Modify\", SEMAPHORE_MODIFY_STATE, TRUE, TRUE }\n};\n\nACCESS_ENTRIES(Service)\n{\n    { L\"Full control\", SERVICE_ALL_ACCESS, TRUE, TRUE },\n    { L\"Query status\", SERVICE_QUERY_STATUS, TRUE, TRUE },\n    { L\"Query configuration\", SERVICE_QUERY_CONFIG, TRUE, TRUE },\n    { L\"Modify configuration\", SERVICE_CHANGE_CONFIG, TRUE, TRUE },\n    { L\"Enumerate dependents\", SERVICE_ENUMERATE_DEPENDENTS, TRUE, TRUE },\n    { L\"Start\", SERVICE_START, TRUE, TRUE },\n    { L\"Stop\", SERVICE_STOP, TRUE, TRUE },\n    { L\"Pause / continue\", SERVICE_PAUSE_CONTINUE, TRUE, TRUE, L\"Pause/continue\" },\n    { L\"Interrogate\", SERVICE_INTERROGATE, TRUE, TRUE },\n    { L\"User-defined control\", SERVICE_USER_DEFINED_CONTROL, TRUE, TRUE }\n};\n\nACCESS_ENTRIES(Session)\n{\n    { L\"Full control\", SESSION_ALL_ACCESS, TRUE, TRUE },\n    { L\"Query\", SESSION_QUERY_ACCESS, TRUE, TRUE },\n    { L\"Modify\", SESSION_MODIFY_ACCESS, TRUE, TRUE }\n};\n\nACCESS_ENTRIES(SymbolicLink)\n{\n    { L\"Full control\", SYMBOLIC_LINK_ALL_ACCESS, TRUE, TRUE },\n    { L\"Query\", SYMBOLIC_LINK_QUERY, TRUE, TRUE }\n};\n\nACCESS_ENTRIES(Thread)\n{\n    { L\"Full control\", STANDARD_RIGHTS_REQUIRED | SYNCHRONIZE | 0x3ff, TRUE, TRUE },\n    { L\"Query information\", THREAD_QUERY_INFORMATION, TRUE, TRUE },\n    { L\"Set information\", THREAD_SET_INFORMATION, TRUE, TRUE },\n    { L\"Get context\", THREAD_GET_CONTEXT, TRUE, TRUE },\n    { L\"Set context\", THREAD_SET_CONTEXT, TRUE, TRUE },\n    { L\"Set token\", THREAD_SET_THREAD_TOKEN, TRUE, TRUE },\n    { L\"Alert\", THREAD_ALERT, TRUE, TRUE },\n    { L\"Impersonate\", THREAD_IMPERSONATE, TRUE, TRUE },\n    { L\"Direct impersonate\", THREAD_DIRECT_IMPERSONATION, TRUE, TRUE },\n    { L\"Suspend / resume\", THREAD_SUSPEND_RESUME, TRUE, TRUE, L\"Suspend/resume\" },\n    { L\"Terminate\", THREAD_TERMINATE, TRUE, TRUE },\n};\n\nACCESS_ENTRIES(Thread60)\n{\n    { L\"Full control\", STANDARD_RIGHTS_REQUIRED | SYNCHRONIZE | 0xffff, TRUE, TRUE }, // THREAD_ALL_ACCESS\n    { L\"Query limited information\", THREAD_QUERY_LIMITED_INFORMATION, TRUE, TRUE },\n    { L\"Query information\", THREAD_QUERY_INFORMATION | THREAD_QUERY_LIMITED_INFORMATION, TRUE, TRUE },\n    { L\"Set limited information\", THREAD_SET_LIMITED_INFORMATION, TRUE, TRUE },\n    { L\"Set information\", THREAD_SET_INFORMATION | THREAD_SET_LIMITED_INFORMATION, TRUE, TRUE },\n    { L\"Get context\", THREAD_GET_CONTEXT, TRUE, TRUE },\n    { L\"Set context\", THREAD_SET_CONTEXT, TRUE, TRUE },\n    { L\"Set token\", THREAD_SET_THREAD_TOKEN, TRUE, TRUE },\n    { L\"Alert\", THREAD_ALERT, TRUE, TRUE },\n    { L\"Impersonate\", THREAD_IMPERSONATE, TRUE, TRUE },\n    { L\"Direct impersonate\", THREAD_DIRECT_IMPERSONATION, TRUE, TRUE },\n    { L\"Suspend / resume\", THREAD_SUSPEND_RESUME, TRUE, TRUE, L\"Suspend/resume\" },\n    { L\"Terminate\", THREAD_TERMINATE, TRUE, TRUE },\n};\n\nACCESS_ENTRIES(Timer)\n{\n    { L\"Full control\", TIMER_ALL_ACCESS, TRUE, TRUE },\n    { L\"Query\", TIMER_QUERY_STATE, TRUE, TRUE },\n    { L\"Modify\", TIMER_MODIFY_STATE, TRUE, TRUE }\n};\n\nACCESS_ENTRIES(TmEn)\n{\n    { L\"Full control\", ENLISTMENT_ALL_ACCESS, TRUE, TRUE },\n    { L\"Read\", ENLISTMENT_GENERIC_READ, TRUE, FALSE },\n    { L\"Write\", ENLISTMENT_GENERIC_WRITE, TRUE, FALSE },\n    { L\"Execute\", ENLISTMENT_GENERIC_EXECUTE, TRUE, FALSE },\n    { L\"Query information\", ENLISTMENT_QUERY_INFORMATION, FALSE, TRUE },\n    { L\"Set information\", ENLISTMENT_SET_INFORMATION, FALSE, TRUE },\n    { L\"Recover\", ENLISTMENT_RECOVER, FALSE, TRUE },\n    { L\"Subordinate rights\", ENLISTMENT_SUBORDINATE_RIGHTS, FALSE, TRUE },\n    { L\"Superior rights\", ENLISTMENT_SUPERIOR_RIGHTS, FALSE, TRUE }\n};\n\nACCESS_ENTRIES(TmRm)\n{\n    { L\"Full control\", RESOURCEMANAGER_ALL_ACCESS, TRUE, TRUE },\n    { L\"Read\", RESOURCEMANAGER_GENERIC_READ, TRUE, FALSE },\n    { L\"Write\", RESOURCEMANAGER_GENERIC_WRITE, TRUE, FALSE },\n    { L\"Execute\", RESOURCEMANAGER_GENERIC_EXECUTE, TRUE, FALSE },\n    { L\"Query information\", RESOURCEMANAGER_QUERY_INFORMATION, FALSE, TRUE },\n    { L\"Set information\", RESOURCEMANAGER_SET_INFORMATION, FALSE, TRUE },\n    { L\"Get notifications\", RESOURCEMANAGER_GET_NOTIFICATION, FALSE, TRUE },\n    { L\"Enlist\", RESOURCEMANAGER_ENLIST, FALSE, TRUE },\n    { L\"Recover\", RESOURCEMANAGER_RECOVER, FALSE, TRUE },\n    { L\"Register protocols\", RESOURCEMANAGER_REGISTER_PROTOCOL, FALSE, TRUE },\n    { L\"Complete propagation\", RESOURCEMANAGER_COMPLETE_PROPAGATION, FALSE, TRUE }\n};\n\nACCESS_ENTRIES(TmTm)\n{\n    { L\"Full control\", TRANSACTIONMANAGER_ALL_ACCESS, TRUE, TRUE },\n    { L\"Read\", TRANSACTIONMANAGER_GENERIC_READ, TRUE, FALSE },\n    { L\"Write\", TRANSACTIONMANAGER_GENERIC_WRITE, TRUE, FALSE },\n    { L\"Execute\", TRANSACTIONMANAGER_GENERIC_EXECUTE, TRUE, FALSE },\n    { L\"Query information\", TRANSACTIONMANAGER_QUERY_INFORMATION, FALSE, TRUE },\n    { L\"Set information\", TRANSACTIONMANAGER_SET_INFORMATION, FALSE, TRUE },\n    { L\"Recover\", TRANSACTIONMANAGER_RECOVER, FALSE, TRUE },\n    { L\"Rename\", TRANSACTIONMANAGER_RENAME, FALSE, TRUE },\n    { L\"Create resource manager\", TRANSACTIONMANAGER_CREATE_RM, FALSE, TRUE },\n    { L\"Bind transactions\", TRANSACTIONMANAGER_BIND_TRANSACTION, FALSE, TRUE }\n};\n\nACCESS_ENTRIES(TmTx)\n{\n    { L\"Full control\", TRANSACTION_ALL_ACCESS, TRUE, TRUE },\n    { L\"Read\", TRANSACTION_GENERIC_READ, TRUE, FALSE },\n    { L\"Write\", TRANSACTION_GENERIC_WRITE, TRUE, FALSE },\n    { L\"Execute\", TRANSACTION_GENERIC_EXECUTE, TRUE, FALSE },\n    { L\"Query information\", TRANSACTION_QUERY_INFORMATION, FALSE, TRUE },\n    { L\"Set information\", TRANSACTION_SET_INFORMATION, FALSE, TRUE },\n    { L\"Enlist\", TRANSACTION_ENLIST, FALSE, TRUE },\n    { L\"Commit\", TRANSACTION_COMMIT, FALSE, TRUE },\n    { L\"Rollback\", TRANSACTION_ROLLBACK, FALSE, TRUE },\n    { L\"Propagate\", TRANSACTION_PROPAGATE, FALSE, TRUE }\n};\n\nACCESS_ENTRIES(Token)\n{\n    { L\"Full control\", TOKEN_ALL_ACCESS, TRUE, TRUE },\n    { L\"Read\", TOKEN_READ, TRUE, FALSE },\n    { L\"Write\", TOKEN_WRITE, TRUE, FALSE },\n    { L\"Execute\", TOKEN_EXECUTE, TRUE, FALSE },\n    { L\"Adjust privileges\", TOKEN_ADJUST_PRIVILEGES, FALSE, TRUE },\n    { L\"Adjust groups\", TOKEN_ADJUST_GROUPS, FALSE, TRUE },\n    { L\"Adjust defaults\", TOKEN_ADJUST_DEFAULT, FALSE, TRUE },\n    { L\"Adjust session ID\", TOKEN_ADJUST_SESSIONID, FALSE, TRUE },\n    { L\"Assign as primary token\", TOKEN_ASSIGN_PRIMARY, FALSE, TRUE, L\"Assign primary\" },\n    { L\"Duplicate\", TOKEN_DUPLICATE, FALSE, TRUE },\n    { L\"Impersonate\", TOKEN_IMPERSONATE, FALSE, TRUE },\n    { L\"Query\", TOKEN_QUERY, FALSE, TRUE },\n    { L\"Query source\", TOKEN_QUERY_SOURCE, FALSE, TRUE }\n};\n\nACCESS_ENTRIES(TpWorkerFactory)\n{\n    { L\"Full control\", WORKER_FACTORY_ALL_ACCESS, TRUE, TRUE },\n    { L\"Release worker\", WORKER_FACTORY_RELEASE_WORKER, FALSE, TRUE },\n    { L\"Ready worker\", WORKER_FACTORY_READY_WORKER, FALSE, TRUE },\n    { L\"Wait\", WORKER_FACTORY_WAIT, FALSE, TRUE },\n    { L\"Set information\", WORKER_FACTORY_SET_INFORMATION, FALSE, TRUE },\n    { L\"Query information\", WORKER_FACTORY_QUERY_INFORMATION, FALSE, TRUE },\n    { L\"Shutdown\", WORKER_FACTORY_SHUTDOWN, FALSE, TRUE }\n};\n\nACCESS_ENTRIES(Type)\n{\n    { L\"Full control\", OBJECT_TYPE_ALL_ACCESS, TRUE, TRUE },\n    { L\"Create\", OBJECT_TYPE_CREATE, TRUE, TRUE }\n};\n\nACCESS_ENTRIES(WindowStation)\n{\n    { L\"Full control\", WINSTA_ALL_ACCESS | STANDARD_RIGHTS_REQUIRED, TRUE, TRUE },\n    { L\"Read\", WINSTA_GENERIC_READ, TRUE, FALSE },\n    { L\"Write\", WINSTA_GENERIC_WRITE, TRUE, FALSE },\n    { L\"Execute\", WINSTA_GENERIC_EXECUTE, TRUE, FALSE },\n    { L\"Enumerate\", WINSTA_ENUMERATE, FALSE, TRUE },\n    { L\"Enumerate desktops\", WINSTA_ENUMDESKTOPS, FALSE, TRUE },\n    { L\"Read attributes\", WINSTA_READATTRIBUTES, FALSE, TRUE },\n    { L\"Read screen\", WINSTA_READSCREEN, FALSE, TRUE },\n    { L\"Access clipboard\", WINSTA_ACCESSCLIPBOARD, FALSE, TRUE },\n    { L\"Access global atoms\", WINSTA_ACCESSGLOBALATOMS, FALSE, TRUE },\n    { L\"Create desktop\", WINSTA_CREATEDESKTOP, FALSE, TRUE },\n    { L\"Write attributes\", WINSTA_WRITEATTRIBUTES, FALSE, TRUE },\n    { L\"Exit windows\", WINSTA_EXITWINDOWS, FALSE, TRUE }\n};\n\nACCESS_ENTRIES(WmiGuid)\n{\n    { L\"Full control\", WMIGUID_ALL_ACCESS, TRUE, TRUE },\n    { L\"Read\", WMIGUID_GENERIC_READ, TRUE, FALSE },\n    { L\"Write\", WMIGUID_GENERIC_WRITE, TRUE, FALSE },\n    { L\"Execute\", WMIGUID_GENERIC_EXECUTE, TRUE, FALSE },\n    { L\"Query information\", WMIGUID_QUERY, FALSE, TRUE },\n    { L\"Set information\", WMIGUID_SET, FALSE, TRUE },\n    { L\"Get notifications\", WMIGUID_NOTIFICATION, FALSE, TRUE },\n    { L\"Read description\", WMIGUID_READ_DESCRIPTION, FALSE, TRUE },\n    { L\"Execute\", WMIGUID_EXECUTE, FALSE, TRUE },\n    { L\"Create real-time logs\", TRACELOG_CREATE_REALTIME, FALSE, TRUE, L\"Create real-time\" },\n    { L\"Create on disk logs\", TRACELOG_CREATE_ONDISK, FALSE, TRUE, L\"Create on disk\" },\n    { L\"Enable provider GUIDs\", TRACELOG_GUID_ENABLE, FALSE, TRUE, L\"Enable GUIDs\" },\n    { L\"Access kernel logger\", TRACELOG_ACCESS_KERNEL_LOGGER, FALSE, TRUE },\n    { L\"Log events\", TRACELOG_LOG_EVENT, FALSE, TRUE },\n    { L\"Access real-time events\", TRACELOG_ACCESS_REALTIME, FALSE, TRUE, L\"Access real-time\" },\n    { L\"Register provider GUIDs\", TRACELOG_REGISTER_GUIDS, FALSE, TRUE, L\"Register GUIDs\" }\n};\n\nstatic PH_SPECIFIC_TYPE PhSpecificTypes[] =\n{\n    ACCESS_ENTRY(AlpcPort, TRUE),\n    ACCESS_ENTRY(DebugObject, TRUE),\n    ACCESS_ENTRY(Desktop, FALSE),\n    ACCESS_ENTRY(Directory, FALSE),\n    ACCESS_ENTRY(Event, TRUE),\n    ACCESS_ENTRY(EventPair, TRUE),\n    ACCESS_ENTRY(File, TRUE),\n    ACCESS_ENTRY(FilterConnectionPort, FALSE),\n    ACCESS_ENTRY(IoCompletion, TRUE),\n    ACCESS_ENTRY(Job, TRUE),\n    ACCESS_ENTRY(Key, FALSE),\n    ACCESS_ENTRY(KeyedEvent, FALSE),\n    ACCESS_ENTRY(LsaAccount, FALSE),\n    ACCESS_ENTRY(LsaPolicy, FALSE),\n    ACCESS_ENTRY(LsaSecret, FALSE),\n    ACCESS_ENTRY(LsaTrusted, FALSE),\n    ACCESS_ENTRY(Mutant, TRUE),\n    ACCESS_ENTRY(Partition, TRUE),\n    ACCESS_ENTRY(Process, TRUE),\n    ACCESS_ENTRY(Process60, TRUE),\n    ACCESS_ENTRY(Profile, FALSE),\n    ACCESS_ENTRY(SamAlias, FALSE),\n    ACCESS_ENTRY(SamDomain, FALSE),\n    ACCESS_ENTRY(SamGroup, FALSE),\n    ACCESS_ENTRY(SamServer, FALSE),\n    ACCESS_ENTRY(SamUser, FALSE),\n    ACCESS_ENTRY(Section, FALSE),\n    ACCESS_ENTRY(Semaphore, TRUE),\n    ACCESS_ENTRY(Service, FALSE),\n    ACCESS_ENTRY(Session, FALSE),\n    ACCESS_ENTRY(SymbolicLink, FALSE),\n    ACCESS_ENTRY(Thread, TRUE),\n    ACCESS_ENTRY(Thread60, TRUE),\n    ACCESS_ENTRY(Timer, TRUE),\n    ACCESS_ENTRY(TmEn, FALSE),\n    ACCESS_ENTRY(TmRm, FALSE),\n    ACCESS_ENTRY(TmTm, FALSE),\n    ACCESS_ENTRY(TmTx, FALSE),\n    ACCESS_ENTRY(Token, FALSE),\n    ACCESS_ENTRY(TpWorkerFactory, FALSE),\n    ACCESS_ENTRY(Type, FALSE),\n    ACCESS_ENTRY(WindowStation, FALSE),\n    ACCESS_ENTRY(WmiGuid, TRUE)\n};\n\n/**\n * Gets access entries for an object type.\n *\n * \\param Type The name of the object type.\n * \\param AccessEntries A variable which receives an array of access entry structures. You must free\n * the buffer with PhFree() when you no longer need it.\n * \\param NumberOfAccessEntries A variable which receives the number of access entry structures\n * returned in\n * \\a AccessEntries.\n */\nBOOLEAN PhGetAccessEntries(\n    _In_ PWSTR Type,\n    _Out_ PPH_ACCESS_ENTRY *AccessEntries,\n    _Out_ PULONG NumberOfAccessEntries\n    )\n{\n    ULONG i;\n    PPH_SPECIFIC_TYPE specificType = NULL;\n    PPH_ACCESS_ENTRY accessEntries;\n\n    if (PhEqualStringZ(Type, L\"ALPC Port\", TRUE))\n    {\n        Type = L\"AlpcPort\";\n    }\n    else if (PhEqualStringZ(Type, L\"Port\", TRUE))\n    {\n        Type = L\"AlpcPort\";\n    }\n    else if (PhEqualStringZ(Type, L\"WaitablePort\", TRUE))\n    {\n        Type = L\"AlpcPort\";\n    }\n    else if (PhEqualStringZ(Type, L\"Process\", TRUE))\n    {\n        Type = L\"Process60\";\n    }\n    else if (PhEqualStringZ(Type, L\"Thread\", TRUE))\n    {\n        Type = L\"Thread60\";\n    }\n\n    // Find the specific type.\n    for (i = 0; i < sizeof(PhSpecificTypes) / sizeof(PH_SPECIFIC_TYPE); i++)\n    {\n        if (PhEqualStringZ(PhSpecificTypes[i].Type, Type, TRUE))\n        {\n            specificType = &PhSpecificTypes[i];\n            break;\n        }\n    }\n\n    if (specificType)\n    {\n        ULONG sizeOfEntries;\n\n        // Copy the specific access entries and append the standard access entries.\n\n        if (specificType->HasSynchronize)\n            sizeOfEntries = specificType->SizeOfAccessEntries + sizeof(PhStandardAccessEntries);\n        else\n            sizeOfEntries = specificType->SizeOfAccessEntries + sizeof(PhStandardAccessEntries) - sizeof(PH_ACCESS_ENTRY);\n\n        accessEntries = PhAllocate(sizeOfEntries);\n        memcpy(accessEntries, specificType->AccessEntries, specificType->SizeOfAccessEntries);\n\n        if (specificType->HasSynchronize)\n        {\n            memcpy(\n                PTR_ADD_OFFSET(accessEntries, specificType->SizeOfAccessEntries),\n                PhStandardAccessEntries,\n                sizeof(PhStandardAccessEntries)\n                );\n        }\n        else\n        {\n            memcpy(\n                PTR_ADD_OFFSET(accessEntries, specificType->SizeOfAccessEntries),\n                &PhStandardAccessEntries[1],\n                sizeof(PhStandardAccessEntries) - sizeof(PH_ACCESS_ENTRY)\n                );\n        }\n\n        *AccessEntries = accessEntries;\n        *NumberOfAccessEntries = sizeOfEntries / sizeof(PH_ACCESS_ENTRY);\n    }\n    else\n    {\n        accessEntries = PhAllocate(sizeof(PhStandardAccessEntries));\n        memcpy(accessEntries, PhStandardAccessEntries, sizeof(PhStandardAccessEntries));\n\n        *AccessEntries = accessEntries;\n        *NumberOfAccessEntries = sizeof(PhStandardAccessEntries) / sizeof(PH_ACCESS_ENTRY);\n    }\n\n    return TRUE;\n}\n\nstatic int __cdecl PhpAccessEntryCompare(\n    _In_ const void *elem1,\n    _In_ const void *elem2\n    )\n{\n    PPH_ACCESS_ENTRY entry1 = (PPH_ACCESS_ENTRY)elem1;\n    PPH_ACCESS_ENTRY entry2 = (PPH_ACCESS_ENTRY)elem2;\n\n    return intcmp(PhCountBits(entry2->Access), PhCountBits(entry1->Access));\n}\n\n/**\n * Creates a string representation of an access mask.\n *\n * \\param Access The access mask.\n * \\param AccessEntries An array of access entry structures. You can call PhGetAccessEntries() to\n * retrieve the access entry structures for a standard object type.\n * \\param NumberOfAccessEntries The number of elements in \\a AccessEntries.\n *\n * \\return The string representation of \\a Access.\n */\nPPH_STRING PhGetAccessString(\n    _In_ ACCESS_MASK Access,\n    _In_ PPH_ACCESS_ENTRY AccessEntries,\n    _In_ ULONG NumberOfAccessEntries\n    )\n{\n    PH_STRING_BUILDER stringBuilder;\n    PPH_ACCESS_ENTRY accessEntries;\n    PBOOLEAN matched;\n    ULONG i;\n    ULONG j;\n\n    PhInitializeStringBuilder(&stringBuilder, 32);\n\n    // Sort the access entries according to how many access rights they include.\n    accessEntries = PhAllocateCopy(AccessEntries, NumberOfAccessEntries * sizeof(PH_ACCESS_ENTRY));\n    qsort(accessEntries, NumberOfAccessEntries, sizeof(PH_ACCESS_ENTRY), PhpAccessEntryCompare);\n\n    matched = PhAllocate(NumberOfAccessEntries * sizeof(BOOLEAN));\n    memset(matched, 0, NumberOfAccessEntries * sizeof(BOOLEAN));\n\n    for (i = 0; i < NumberOfAccessEntries; i++)\n    {\n        // We make sure we haven't matched this access entry yet. This ensures that we won't get\n        // duplicates, e.g. FILE_GENERIC_READ includes FILE_READ_DATA, and we don't want to display\n        // both to the user.\n        if (\n            !matched[i] &&\n            ((Access & accessEntries[i].Access) == accessEntries[i].Access)\n            )\n        {\n            if (accessEntries[i].ShortName)\n                PhAppendStringBuilder2(&stringBuilder, accessEntries[i].ShortName);\n            else\n                PhAppendStringBuilder2(&stringBuilder, accessEntries[i].Name);\n\n            PhAppendStringBuilder2(&stringBuilder, L\", \");\n\n            // Disable equal or more specific entries.\n            for (j = i; j < NumberOfAccessEntries; j++)\n            {\n                if ((accessEntries[i].Access | accessEntries[j].Access) == accessEntries[i].Access)\n                    matched[j] = TRUE;\n            }\n        }\n    }\n\n    // Remove the trailing \", \".\n    if (PhEndsWithString2(stringBuilder.String, L\", \", FALSE))\n        PhRemoveEndStringBuilder(&stringBuilder, 2);\n\n    PhFree(matched);\n    PhFree(accessEntries);\n\n    return PhFinalStringBuilderString(&stringBuilder);\n}\n"
  },
  {
    "path": "third_party/phlib/secedit.c",
    "content": "/*\n * Process Hacker -\n *   object security editor\n *\n * Copyright (C) 2010-2016 wj32\n * Copyright (C) 2017 dmex\n *\n * This file is part of Process Hacker.\n *\n * Process Hacker is free software; you can redistribute it and/or modify\n * it under the terms of the GNU General Public License as published by\n * the Free Software Foundation, either version 3 of the License, or\n * (at your option) any later version.\n *\n * Process Hacker is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n * GNU General Public License for more details.\n *\n * You should have received a copy of the GNU General Public License\n * along with Process Hacker.  If not, see <http://www.gnu.org/licenses/>.\n */\n\n#include <ph.h>\n#include <secedit.h>\n#include <lsasup.h>\n\n#include <guisup.h>\n#include <hndlinfo.h>\n#include <settings.h>\n#include <seceditp.h>\n\nstatic ISecurityInformationVtbl PhSecurityInformation_VTable =\n{\n    PhSecurityInformation_QueryInterface,\n    PhSecurityInformation_AddRef,\n    PhSecurityInformation_Release,\n    PhSecurityInformation_GetObjectInformation,\n    PhSecurityInformation_GetSecurity,\n    PhSecurityInformation_SetSecurity,\n    PhSecurityInformation_GetAccessRights,\n    PhSecurityInformation_MapGeneric,\n    PhSecurityInformation_GetInheritTypes,\n    PhSecurityInformation_PropertySheetPageCallback\n};\n\nstatic ISecurityInformation2Vtbl PhSecurityInformation_VTable2 =\n{\n    PhSecurityInformation2_QueryInterface,\n    PhSecurityInformation2_AddRef,\n    PhSecurityInformation2_Release,\n    PhSecurityInformation2_IsDaclCanonical,\n    PhSecurityInformation2_LookupSids\n};\n\nstatic IDataObjectVtbl PhDataObject_VTable =\n{\n    PhSecurityDataObject_QueryInterface,\n    PhSecurityDataObject_AddRef,\n    PhSecurityDataObject_Release,\n    PhSecurityDataObject_GetData,\n    PhSecurityDataObject_GetDataHere,\n    PhSecurityDataObject_QueryGetData,\n    PhSecurityDataObject_GetCanonicalFormatEtc,\n    PhSecurityDataObject_SetData,\n    PhSecurityDataObject_EnumFormatEtc,\n    PhSecurityDataObject_DAdvise,\n    PhSecurityDataObject_DUnadvise,\n    PhSecurityDataObject_EnumDAdvise\n};\n\n/**\n * Creates a security editor page.\n *\n * \\param ObjectName The name of the object.\n * \\param GetObjectSecurity A callback function executed to retrieve the security descriptor of the\n * object.\n * \\param SetObjectSecurity A callback function executed to modify the security descriptor of the\n * object.\n * \\param Context A user-defined value to pass to the callback functions.\n * \\param AccessEntries An array of access mask descriptors.\n * \\param NumberOfAccessEntries The number of elements in \\a AccessEntries.\n */\nHPROPSHEETPAGE PhCreateSecurityPage(\n    _In_ PWSTR ObjectName,\n    _In_ PPH_GET_OBJECT_SECURITY GetObjectSecurity,\n    _In_ PPH_SET_OBJECT_SECURITY SetObjectSecurity,\n    _In_opt_ PVOID Context,\n    _In_ PPH_ACCESS_ENTRY AccessEntries,\n    _In_ ULONG NumberOfAccessEntries\n    )\n{\n    ISecurityInformation *info;\n    HPROPSHEETPAGE page;\n\n    info = PhSecurityInformation_Create(\n        ObjectName,\n        GetObjectSecurity,\n        SetObjectSecurity,\n        Context,\n        AccessEntries,\n        NumberOfAccessEntries,\n        TRUE\n        );\n\n    page = CreateSecurityPage(info);\n\n    PhSecurityInformation_Release(info);\n\n    return page;\n}\n\n/**\n * Displays a security editor dialog.\n *\n * \\param hWnd The parent window of the dialog.\n * \\param ObjectName The name of the object.\n * \\param GetObjectSecurity A callback function executed to retrieve the security descriptor of the\n * object.\n * \\param SetObjectSecurity A callback function executed to modify the security descriptor of the\n * object.\n * \\param Context A user-defined value to pass to the callback functions.\n * \\param AccessEntries An array of access mask descriptors.\n * \\param NumberOfAccessEntries The number of elements in \\a AccessEntries.\n */\nVOID PhEditSecurity(\n    _In_ HWND hWnd,\n    _In_ PWSTR ObjectName,\n    _In_ PPH_GET_OBJECT_SECURITY GetObjectSecurity,\n    _In_ PPH_SET_OBJECT_SECURITY SetObjectSecurity,\n    _In_opt_ PVOID Context,\n    _In_ PPH_ACCESS_ENTRY AccessEntries,\n    _In_ ULONG NumberOfAccessEntries\n    )\n{\n    ISecurityInformation *info;\n\n    info = PhSecurityInformation_Create(\n        ObjectName,\n        GetObjectSecurity,\n        SetObjectSecurity,\n        Context,\n        AccessEntries,\n        NumberOfAccessEntries,\n        FALSE\n        );\n\n    if (WindowsVersion >= WINDOWS_8 && PhGetIntegerSetting(L\"EnableSecurityAdvancedDialog\"))\n        EditSecurityAdvanced(hWnd, info, COMBINE_PAGE_ACTIVATION(SI_PAGE_PERM, SI_SHOW_PERM_ACTIVATED));\n    else\n        EditSecurity(hWnd, info);\n\n    PhSecurityInformation_Release(info);\n}\n\nISecurityInformation *PhSecurityInformation_Create(\n    _In_ PWSTR ObjectName,\n    _In_ PPH_GET_OBJECT_SECURITY GetObjectSecurity,\n    _In_ PPH_SET_OBJECT_SECURITY SetObjectSecurity,\n    _In_opt_ PVOID Context,\n    _In_ PPH_ACCESS_ENTRY AccessEntries,\n    _In_ ULONG NumberOfAccessEntries,\n    _In_ BOOLEAN IsPage\n    )\n{\n    PhSecurityInformation *info;\n    ULONG i;\n\n    info = PhAllocate(sizeof(PhSecurityInformation));\n    info->VTable = &PhSecurityInformation_VTable;\n    info->RefCount = 1;\n\n    info->ObjectName = PhCreateString(ObjectName);\n    info->GetObjectSecurity = GetObjectSecurity;\n    info->SetObjectSecurity = SetObjectSecurity;\n    info->Context = Context;\n    info->AccessEntries = PhAllocate(sizeof(SI_ACCESS) * NumberOfAccessEntries);\n    info->NumberOfAccessEntries = NumberOfAccessEntries;\n    info->IsPage = IsPage;\n\n    for (i = 0; i < NumberOfAccessEntries; i++)\n    {\n        memset(&info->AccessEntries[i], 0, sizeof(SI_ACCESS));\n        info->AccessEntries[i].pszName = AccessEntries[i].Name;\n        info->AccessEntries[i].mask = AccessEntries[i].Access;\n\n        if (AccessEntries[i].General)\n            info->AccessEntries[i].dwFlags |= SI_ACCESS_GENERAL;\n        if (AccessEntries[i].Specific)\n            info->AccessEntries[i].dwFlags |= SI_ACCESS_SPECIFIC;\n    }\n\n    return (ISecurityInformation *)info;\n}\n\nHRESULT STDMETHODCALLTYPE PhSecurityInformation_QueryInterface(\n    _In_ ISecurityInformation *This,\n    _In_ REFIID Riid,\n    _Out_ PVOID *Object\n    )\n{\n    if (\n        IsEqualIID(Riid, &IID_IUnknown) ||\n        IsEqualIID(Riid, &IID_ISecurityInformation)\n        )\n    {\n        PhSecurityInformation_AddRef(This);\n        *Object = This;\n        return S_OK;\n    }\n    else if (IsEqualGUID(Riid, &IID_ISecurityInformation2))\n    {\n        if (WindowsVersion >= WINDOWS_8)\n        {\n            PhSecurityInformation2 *info;\n\n            info = PhAllocate(sizeof(PhSecurityInformation2));\n            info->VTable = &PhSecurityInformation_VTable2;\n            info->RefCount = 1;\n\n            *Object = info;\n            return S_OK;\n        }\n    }\n\n    *Object = NULL;\n    return E_NOINTERFACE;\n}\n\nULONG STDMETHODCALLTYPE PhSecurityInformation_AddRef(\n    _In_ ISecurityInformation *This\n    )\n{\n    PhSecurityInformation *this = (PhSecurityInformation *)This;\n\n    this->RefCount++;\n\n    return this->RefCount;\n}\n\nULONG STDMETHODCALLTYPE PhSecurityInformation_Release(\n    _In_ ISecurityInformation *This\n    )\n{\n    PhSecurityInformation *this = (PhSecurityInformation *)This;\n\n    this->RefCount--;\n\n    if (this->RefCount == 0)\n    {\n        if (this->ObjectName) PhDereferenceObject(this->ObjectName);\n        PhFree(this->AccessEntries);\n\n        PhFree(this);\n\n        return 0;\n    }\n\n    return this->RefCount;\n}\n\nHRESULT STDMETHODCALLTYPE PhSecurityInformation_GetObjectInformation(\n    _In_ ISecurityInformation *This,\n    _Out_ PSI_OBJECT_INFO ObjectInfo\n    )\n{\n    PhSecurityInformation *this = (PhSecurityInformation *)This;\n\n    memset(ObjectInfo, 0, sizeof(SI_OBJECT_INFO));\n    ObjectInfo->dwFlags =\n        SI_EDIT_AUDITS |\n        SI_EDIT_OWNER |\n        SI_EDIT_PERMS |\n        SI_ADVANCED;\n        //SI_NO_ACL_PROTECT |\n        //SI_NO_TREE_APPLY;\n    ObjectInfo->hInstance = NULL;\n    ObjectInfo->pszObjectName = this->ObjectName->Buffer;\n\n    return S_OK;\n}\n\nHRESULT STDMETHODCALLTYPE PhSecurityInformation_GetSecurity(\n    _In_ ISecurityInformation *This,\n    _In_ SECURITY_INFORMATION RequestedInformation,\n    _Out_ PSECURITY_DESCRIPTOR *SecurityDescriptor,\n    _In_ BOOL Default\n    )\n{\n    PhSecurityInformation *this = (PhSecurityInformation *)This;\n    NTSTATUS status;\n    PSECURITY_DESCRIPTOR securityDescriptor;\n    ULONG sdLength;\n    PSECURITY_DESCRIPTOR newSd;\n\n    status = this->GetObjectSecurity(\n        &securityDescriptor,\n        RequestedInformation,\n        this->Context\n        );\n\n    if (!NT_SUCCESS(status))\n        return HRESULT_FROM_WIN32(PhNtStatusToDosError(status));\n\n    sdLength = RtlLengthSecurityDescriptor(securityDescriptor);\n    newSd = LocalAlloc(0, sdLength);\n    memcpy(newSd, securityDescriptor, sdLength);\n    PhFree(securityDescriptor);\n\n    *SecurityDescriptor = newSd;\n\n    return S_OK;\n}\n\nHRESULT STDMETHODCALLTYPE PhSecurityInformation_SetSecurity(\n    _In_ ISecurityInformation *This,\n    _In_ SECURITY_INFORMATION SecurityInformation,\n    _In_ PSECURITY_DESCRIPTOR SecurityDescriptor\n    )\n{\n    PhSecurityInformation *this = (PhSecurityInformation *)This;\n    NTSTATUS status;\n\n    status = this->SetObjectSecurity(\n        SecurityDescriptor,\n        SecurityInformation,\n        this->Context\n        );\n\n    if (!NT_SUCCESS(status))\n        return HRESULT_FROM_WIN32(PhNtStatusToDosError(status));\n\n    return S_OK;\n}\n\nHRESULT STDMETHODCALLTYPE PhSecurityInformation_GetAccessRights(\n    _In_ ISecurityInformation *This,\n    _In_ const GUID *ObjectType,\n    _In_ ULONG Flags,\n    _Out_ PSI_ACCESS *Access,\n    _Out_ PULONG Accesses,\n    _Out_ PULONG DefaultAccess\n    )\n{\n    PhSecurityInformation *this = (PhSecurityInformation *)This;\n\n    *Access = this->AccessEntries;\n    *Accesses = this->NumberOfAccessEntries;\n    *DefaultAccess = 0;\n\n    return S_OK;\n}\n\nHRESULT STDMETHODCALLTYPE PhSecurityInformation_MapGeneric(\n    _In_ ISecurityInformation *This,\n    _In_ const GUID *ObjectType,\n    _In_ PUCHAR AceFlags,\n    _Inout_ PACCESS_MASK Mask\n    )\n{\n    return S_OK;\n}\n\nHRESULT STDMETHODCALLTYPE PhSecurityInformation_GetInheritTypes(\n    _In_ ISecurityInformation *This,\n    _Out_ PSI_INHERIT_TYPE *InheritTypes,\n    _Out_ PULONG InheritTypesCount\n    )\n{\n    return E_NOTIMPL;\n}\n\nHRESULT STDMETHODCALLTYPE PhSecurityInformation_PropertySheetPageCallback(\n    _In_ ISecurityInformation *This,\n    _In_ HWND hwnd,\n    _In_ UINT uMsg,\n    _In_ SI_PAGE_TYPE uPage\n    )\n{\n    PhSecurityInformation *this = (PhSecurityInformation *)This;\n\n    if (uMsg == PSPCB_SI_INITDIALOG && !this->IsPage)\n    {\n        // Center the security editor window.\n        PhCenterWindow(GetParent(hwnd), GetParent(GetParent(hwnd)));\n    }\n\n    return E_NOTIMPL;\n}\n\nHRESULT STDMETHODCALLTYPE PhSecurityInformation2_QueryInterface(\n    _In_ ISecurityInformation2 *This,\n    _In_ REFIID Riid,\n    _Out_ PVOID *Object\n    )\n{\n    if (\n        IsEqualIID(Riid, &IID_IUnknown) ||\n        IsEqualIID(Riid, &IID_ISecurityInformation2)\n        )\n    {\n        PhSecurityInformation2_AddRef(This);\n        *Object = This;\n        return S_OK;\n    }\n\n    *Object = NULL;\n    return E_NOINTERFACE;\n}\n\nULONG STDMETHODCALLTYPE PhSecurityInformation2_AddRef(\n    _In_ ISecurityInformation2 *This\n    )\n{\n    PhSecurityInformation2 *this = (PhSecurityInformation2 *)This;\n\n    this->RefCount++;\n\n    return this->RefCount;\n}\n\nULONG STDMETHODCALLTYPE PhSecurityInformation2_Release(\n    _In_ ISecurityInformation2 *This\n    )\n{\n    PhSecurityInformation2 *this = (PhSecurityInformation2 *)This;\n\n    this->RefCount--;\n\n    if (this->RefCount == 0)\n    {\n        PhFree(this);\n        return 0;\n    }\n\n    return this->RefCount;\n}\n\nBOOL STDMETHODCALLTYPE PhSecurityInformation2_IsDaclCanonical(\n    _In_ ISecurityInformation2 *This,\n    _In_ PACL pDacl\n    )\n{\n    return TRUE;\n}\n\nHRESULT STDMETHODCALLTYPE PhSecurityInformation2_LookupSids(\n    _In_ ISecurityInformation2 *This,\n    _In_ ULONG cSids,\n    _In_ PSID *rgpSids,\n    _Out_ LPDATAOBJECT *ppdo\n    )\n{\n    PhSecurityIDataObject *dataObject;\n\n    dataObject = PhAllocate(sizeof(PhSecurityInformation));\n    dataObject->VTable = &PhDataObject_VTable;\n    dataObject->RefCount = 1;\n\n    dataObject->SidCount = cSids;\n    dataObject->Sids = rgpSids;\n    dataObject->NameCache = PhCreateList(1);\n\n    *ppdo = (LPDATAOBJECT)dataObject;\n\n    return S_OK;\n}\n\nHRESULT STDMETHODCALLTYPE PhSecurityDataObject_QueryInterface(\n    _In_ IDataObject *This,\n    _In_ REFIID Riid,\n    _COM_Outptr_ PVOID *Object\n    )\n{\n    if (\n        IsEqualIID(Riid, &IID_IUnknown) ||\n        IsEqualIID(Riid, &IID_IDataObject)\n        )\n    {\n        PhSecurityDataObject_AddRef(This);\n        *Object = This;\n        return S_OK;\n    }\n\n    *Object = NULL;\n    return E_NOINTERFACE;\n}\n\nULONG STDMETHODCALLTYPE PhSecurityDataObject_AddRef(\n    _In_ IDataObject *This\n    )\n{\n    PhSecurityIDataObject *this = (PhSecurityIDataObject *)This;\n\n    this->RefCount++;\n\n    return this->RefCount;\n}\n\nULONG STDMETHODCALLTYPE PhSecurityDataObject_Release(\n    _In_ IDataObject *This\n    )\n{\n    PhSecurityIDataObject *this = (PhSecurityIDataObject *)This;\n\n    this->RefCount--;\n\n    if (this->RefCount == 0)\n    {\n        for (ULONG i = 0; i < this->NameCache->Count; i++)\n            PhDereferenceObject(this->NameCache->Items[i]);\n        PhDereferenceObject(this->NameCache);\n\n        PhFree(this);\n        return 0;\n    }\n\n    return this->RefCount;\n}\n\nHRESULT STDMETHODCALLTYPE PhSecurityDataObject_GetData(\n    _In_ IDataObject *This,\n    _In_ FORMATETC *pformatetcIn,\n    _Out_ STGMEDIUM *pmedium\n    )\n{\n    PhSecurityIDataObject *this = (PhSecurityIDataObject *)This;\n    PSID_INFO_LIST sidInfoList;\n\n    sidInfoList = (PSID_INFO_LIST)GlobalAlloc(GMEM_ZEROINIT, sizeof(SID_INFO_LIST) + (sizeof(SID_INFO) * this->SidCount));\n    sidInfoList->cItems = this->SidCount;\n\n    for (ULONG i = 0; i < this->SidCount; i++)\n    {\n        SID_INFO sidInfo;\n        PPH_STRING sidString;\n        SID_NAME_USE sidUse;\n\n        memset(&sidInfo, 0, sizeof(SID_INFO));\n\n        sidInfo.pSid = this->Sids[i];\n\n        if (sidString = PhGetSidFullName(sidInfo.pSid, FALSE, &sidUse))\n        {\n            switch (sidUse)\n            {\n            case SidTypeUser:\n            case SidTypeLogonSession:\n                sidInfo.pwzClass = L\"User\";\n                break;\n            case SidTypeAlias:\n            case SidTypeGroup:\n                sidInfo.pwzClass = L\"Group\";\n                break;\n            case SidTypeComputer:\n                sidInfo.pwzClass = L\"Computer\";\n                break;\n            }\n\n            sidInfo.pwzCommonName = PhGetString(sidString);\n            PhAddItemList(this->NameCache, sidString);\n        }\n        else if (sidString = PhSidToStringSid(sidInfo.pSid))\n        {\n            static PH_STRINGREF appcontainerMappings = PH_STRINGREF_INIT(L\"Software\\\\Classes\\\\Local Settings\\\\Software\\\\Microsoft\\\\Windows\\\\CurrentVersion\\\\AppContainer\\\\Mappings\\\\\");\n            HANDLE keyHandle;\n            PPH_STRING keyPath;\n            PPH_STRING packageName = NULL;\n\n            if (PhEqualString2(sidString, L\"S-1-15-3-4096\", FALSE))\n            {\n                // Special case for Edge and Internet Explorer objects.\n                packageName = PhCreateString(L\"InternetExplorer (APP_PACKAGE)\");\n                sidInfo.pwzCommonName = PhGetString(packageName);;\n                PhAddItemList(this->NameCache, packageName);\n                sidInfoList->aSidInfo[i] = sidInfo;\n                continue;\n            }\n\n            keyPath = PhConcatStringRef2(&appcontainerMappings, &sidString->sr);\n\n            if (NT_SUCCESS(PhOpenKey(\n                &keyHandle,\n                KEY_READ,\n                PH_KEY_CURRENT_USER,\n                &keyPath->sr,\n                0\n                )))\n            {\n                packageName = PhQueryRegistryString(keyHandle, L\"Moniker\");\n                NtClose(keyHandle);\n            }\n\n            if (packageName)\n            {\n                PhMoveReference(&packageName, PhFormatString(L\"%s (APP_PACKAGE)\", PhGetString(packageName)));\n                sidInfo.pwzCommonName = PhGetString(packageName);\n                PhAddItemList(this->NameCache, packageName);\n            }\n\n            PhDereferenceObject(keyPath);\n            PhDereferenceObject(sidString);\n        }\n\n        sidInfoList->aSidInfo[i] = sidInfo;\n    }\n\n    pmedium->tymed = TYMED_HGLOBAL;\n    pmedium->hGlobal = (HGLOBAL)sidInfoList;\n\n    return S_OK;\n}\n\nHRESULT STDMETHODCALLTYPE PhSecurityDataObject_GetDataHere(\n    _In_ IDataObject *This,\n    _In_  FORMATETC *pformatetc,\n    _Inout_ STGMEDIUM *pmedium\n    )\n{\n    return E_NOTIMPL;\n}\n\nHRESULT STDMETHODCALLTYPE PhSecurityDataObject_QueryGetData(\n    _In_ IDataObject *This,\n    _In_opt_ FORMATETC *pformatetc\n    )\n{\n    return E_NOTIMPL;\n}\n\nHRESULT STDMETHODCALLTYPE PhSecurityDataObject_GetCanonicalFormatEtc(\n    _In_ IDataObject * This,\n    _In_opt_ FORMATETC *pformatectIn,\n    _Out_ FORMATETC *pformatetcOut\n    )\n{\n    return E_NOTIMPL;\n}\n\nHRESULT STDMETHODCALLTYPE PhSecurityDataObject_SetData(\n    _In_ IDataObject *This,\n    _In_ FORMATETC *pformatetc,\n    _In_ STGMEDIUM *pmedium,\n    _In_ BOOL fRelease\n    )\n{\n    return E_NOTIMPL;\n}\n\nHRESULT STDMETHODCALLTYPE PhSecurityDataObject_EnumFormatEtc(\n    _In_ IDataObject *This,\n    _In_ ULONG dwDirection,\n    _Out_opt_ IEnumFORMATETC **ppenumFormatEtc\n    )\n{\n    return E_NOTIMPL;\n}\n\nHRESULT STDMETHODCALLTYPE PhSecurityDataObject_DAdvise(\n    _In_ IDataObject *This,\n    _In_ FORMATETC *pformatetc,\n    _In_ ULONG advf,\n    _In_opt_ IAdviseSink *pAdvSink,\n    _Out_ ULONG *pdwConnection\n    )\n{\n    return E_NOTIMPL;\n}\n\nHRESULT STDMETHODCALLTYPE PhSecurityDataObject_DUnadvise(\n    _In_ IDataObject *This,\n    _In_ ULONG dwConnection\n    )\n{\n    return E_NOTIMPL;\n}\n\nHRESULT STDMETHODCALLTYPE PhSecurityDataObject_EnumDAdvise(\n    _In_ IDataObject *This,\n    _Out_opt_ IEnumSTATDATA **ppenumAdvise\n    )\n{\n    return E_NOTIMPL;\n}\n\nNTSTATUS PhpGetObjectSecurityWithTimeout(\n    _In_ HANDLE Handle,\n    _In_ SECURITY_INFORMATION SecurityInformation,\n    _Out_ PSECURITY_DESCRIPTOR *SecurityDescriptor\n    )\n{\n    NTSTATUS status;\n    ULONG bufferSize;\n    PVOID buffer;\n\n    bufferSize = 0x100;\n    buffer = PhAllocate(bufferSize);\n    // This is required (especially for File objects) because some drivers don't seem to handle\n    // QuerySecurity properly.\n    memset(buffer, 0, bufferSize);\n\n    status = PhCallNtQuerySecurityObjectWithTimeout(\n        Handle,\n        SecurityInformation,\n        buffer,\n        bufferSize,\n        &bufferSize\n        );\n\n    if (status == STATUS_BUFFER_TOO_SMALL)\n    {\n        PhFree(buffer);\n        buffer = PhAllocate(bufferSize);\n        memset(buffer, 0, bufferSize);\n\n        status = PhCallNtQuerySecurityObjectWithTimeout(\n            Handle,\n            SecurityInformation,\n            buffer,\n            bufferSize,\n            &bufferSize\n            );\n    }\n\n    if (!NT_SUCCESS(status))\n    {\n        PhFree(buffer);\n        return status;\n    }\n\n    *SecurityDescriptor = (PSECURITY_DESCRIPTOR)buffer;\n\n    return status;\n}\n\n/**\n * Retrieves the security descriptor of an object.\n *\n * \\param SecurityDescriptor A variable which receives a pointer to the security descriptor of the\n * object. The security descriptor must be freed using PhFree() when no longer needed.\n * \\param SecurityInformation The security information to retrieve.\n * \\param Context A pointer to a PH_STD_OBJECT_SECURITY structure describing the object.\n *\n * \\remarks This function may be used for the \\a GetObjectSecurity callback in\n * PhCreateSecurityPage() or PhEditSecurity().\n */\n_Callback_ NTSTATUS PhStdGetObjectSecurity(\n    _Out_ PSECURITY_DESCRIPTOR *SecurityDescriptor,\n    _In_ SECURITY_INFORMATION SecurityInformation,\n    _In_opt_ PVOID Context\n    )\n{\n    NTSTATUS status;\n    PPH_STD_OBJECT_SECURITY stdObjectSecurity;\n    HANDLE handle;\n\n    stdObjectSecurity = (PPH_STD_OBJECT_SECURITY)Context;\n\n    status = stdObjectSecurity->OpenObject(\n        &handle,\n        PhGetAccessForGetSecurity(SecurityInformation),\n        stdObjectSecurity->Context\n        );\n\n    if (!NT_SUCCESS(status))\n        return status;\n\n    if (PhEqualStringZ(stdObjectSecurity->ObjectType, L\"Service\", TRUE))\n    {\n        status = PhGetSeObjectSecurity(handle, SE_SERVICE, SecurityInformation, SecurityDescriptor);\n        CloseServiceHandle(handle);\n    }\n    else if (PhEqualStringZ(stdObjectSecurity->ObjectType, L\"File\", TRUE))\n    {\n        status = PhpGetObjectSecurityWithTimeout(handle, SecurityInformation, SecurityDescriptor);\n        NtClose(handle);\n    }\n    else\n    {\n        status = PhGetObjectSecurity(handle, SecurityInformation, SecurityDescriptor);\n        NtClose(handle);\n    }\n\n    return status;\n}\n\n/**\n * Modifies the security descriptor of an object.\n *\n * \\param SecurityDescriptor A security descriptor containing security information to set.\n * \\param SecurityInformation The security information to retrieve.\n * \\param Context A pointer to a PH_STD_OBJECT_SECURITY structure describing the object.\n *\n * \\remarks This function may be used for the \\a SetObjectSecurity callback in\n * PhCreateSecurityPage() or PhEditSecurity().\n */\n_Callback_ NTSTATUS PhStdSetObjectSecurity(\n    _In_ PSECURITY_DESCRIPTOR SecurityDescriptor,\n    _In_ SECURITY_INFORMATION SecurityInformation,\n    _In_opt_ PVOID Context\n    )\n{\n    NTSTATUS status;\n    PPH_STD_OBJECT_SECURITY stdObjectSecurity;\n    HANDLE handle;\n\n    stdObjectSecurity = (PPH_STD_OBJECT_SECURITY)Context;\n\n    status = stdObjectSecurity->OpenObject(\n        &handle,\n        PhGetAccessForSetSecurity(SecurityInformation),\n        stdObjectSecurity->Context\n        );\n\n    if (!NT_SUCCESS(status))\n        return status;\n\n    if (PhEqualStringZ(stdObjectSecurity->ObjectType, L\"Service\", TRUE))\n    {\n        status = PhSetSeObjectSecurity(handle, SE_SERVICE, SecurityInformation, SecurityDescriptor);\n        CloseServiceHandle(handle);\n    }\n    else\n    {\n        status = PhSetObjectSecurity(handle, SecurityInformation, SecurityDescriptor);\n        NtClose(handle);\n    }\n\n    return status;\n}\n\nNTSTATUS PhGetSeObjectSecurity(\n    _In_ HANDLE Handle,\n    _In_ ULONG ObjectType,\n    _In_ SECURITY_INFORMATION SecurityInformation,\n    _Out_ PSECURITY_DESCRIPTOR *SecurityDescriptor\n    )\n{\n    ULONG win32Result;\n    PSECURITY_DESCRIPTOR securityDescriptor;\n\n    win32Result = GetSecurityInfo(\n        Handle,\n        ObjectType,\n        SecurityInformation,\n        NULL,\n        NULL,\n        NULL,\n        NULL,\n        &securityDescriptor\n        );\n\n    if (win32Result != ERROR_SUCCESS)\n        return NTSTATUS_FROM_WIN32(win32Result);\n\n    *SecurityDescriptor = PhAllocateCopy(securityDescriptor, RtlLengthSecurityDescriptor(securityDescriptor));\n    LocalFree(securityDescriptor);\n\n    return STATUS_SUCCESS;\n}\n\nNTSTATUS PhSetSeObjectSecurity(\n    _In_ HANDLE Handle,\n    _In_ ULONG ObjectType,\n    _In_ SECURITY_INFORMATION SecurityInformation,\n    _In_ PSECURITY_DESCRIPTOR SecurityDescriptor\n    )\n{\n    ULONG win32Result;\n    SECURITY_INFORMATION securityInformation = 0;\n    BOOLEAN present;\n    BOOLEAN defaulted;\n    PSID owner = NULL;\n    PSID group = NULL;\n    PACL dacl = NULL;\n    PACL sacl = NULL;\n\n    if (SecurityInformation & OWNER_SECURITY_INFORMATION)\n    {\n        if (NT_SUCCESS(RtlGetOwnerSecurityDescriptor(SecurityDescriptor, &owner, &defaulted)))\n            securityInformation |= OWNER_SECURITY_INFORMATION;\n    }\n\n    if (SecurityInformation & GROUP_SECURITY_INFORMATION)\n    {\n        if (NT_SUCCESS(RtlGetGroupSecurityDescriptor(SecurityDescriptor, &group, &defaulted)))\n            securityInformation |= GROUP_SECURITY_INFORMATION;\n    }\n\n    if (SecurityInformation & DACL_SECURITY_INFORMATION)\n    {\n        if (NT_SUCCESS(RtlGetDaclSecurityDescriptor(SecurityDescriptor, &present, &dacl, &defaulted)) && present)\n            securityInformation |= DACL_SECURITY_INFORMATION;\n    }\n\n    if (SecurityInformation & SACL_SECURITY_INFORMATION)\n    {\n        if (NT_SUCCESS(RtlGetSaclSecurityDescriptor(SecurityDescriptor, &present, &sacl, &defaulted)) && present)\n            securityInformation |= SACL_SECURITY_INFORMATION;\n    }\n\n    win32Result = SetSecurityInfo(\n        Handle,\n        ObjectType,\n        SecurityInformation,\n        owner,\n        group,\n        dacl,\n        sacl\n        );\n\n    if (win32Result != ERROR_SUCCESS)\n        return NTSTATUS_FROM_WIN32(win32Result);\n\n    return STATUS_SUCCESS;\n}\n"
  },
  {
    "path": "third_party/phlib/settings.c",
    "content": "/*\n * Process Hacker -\n *   settings\n *\n * Copyright (C) 2010-2016 wj32\n * Copyright (C) 2017 dmex\n *\n * This file is part of Process Hacker.\n *\n * Process Hacker is free software; you can redistribute it and/or modify\n * it under the terms of the GNU General Public License as published by\n * the Free Software Foundation, either version 3 of the License, or\n * (at your option) any later version.\n *\n * Process Hacker is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n * GNU General Public License for more details.\n *\n * You should have received a copy of the GNU General Public License\n * along with Process Hacker.  If not, see <http://www.gnu.org/licenses/>.\n */\n\n/*\n * This file contains a program-specific settings system. All possible\n * settings are defined at program startup and added to a hashtable.\n * The values of these settings can then be read in from a XML file or\n * saved to a XML file at any time. Settings which are not recognized\n * are added to a list of \"ignored settings\"; this is necessary to\n * support plugin settings, as we don't want their settings to get\n * deleted whenever the plugins are disabled.\n *\n * The get/set functions are very strict. If the wrong function is used\n * (the get-integer-setting function is used on a string setting) or\n * the setting does not exist, an exception will be raised.\n */\n\n#include <ph.h>\n#include <phbasesup.h>\n#include <phutil.h>\n#include <settings.h>\n\n#include <commctrl.h>\n\n#include \"mxml/mxml.h\"\n\nBOOLEAN NTAPI PhpSettingsHashtableEqualFunction(\n    _In_ PVOID Entry1,\n    _In_ PVOID Entry2\n    );\n\nULONG NTAPI PhpSettingsHashtableHashFunction(\n    _In_ PVOID Entry\n    );\n\nULONG PhpGetCurrentScale(\n    VOID\n    );\n\nVOID PhpFreeSettingValue(\n    _In_ PH_SETTING_TYPE Type,\n    _In_ PPH_SETTING Setting\n    );\n\nPVOID PhpLookupSetting(\n    _In_ PPH_STRINGREF Name\n    );\n\nPPH_HASHTABLE PhSettingsHashtable;\nPH_QUEUED_LOCK PhSettingsLock = PH_QUEUED_LOCK_INIT;\nPPH_LIST PhIgnoredSettings;\n\nVOID PhSettingsInitialization(\n    VOID\n    )\n{\n    PhSettingsHashtable = PhCreateHashtable(\n        sizeof(PH_SETTING),\n        PhpSettingsHashtableEqualFunction,\n        PhpSettingsHashtableHashFunction,\n        256\n        );\n    PhIgnoredSettings = PhCreateList(4);\n\n    PhAddDefaultSettings();\n    PhUpdateCachedSettings();\n}\n\nBOOLEAN NTAPI PhpSettingsHashtableEqualFunction(\n    _In_ PVOID Entry1,\n    _In_ PVOID Entry2\n    )\n{\n    PPH_SETTING setting1 = (PPH_SETTING)Entry1;\n    PPH_SETTING setting2 = (PPH_SETTING)Entry2;\n\n    return PhEqualStringRef(&setting1->Name, &setting2->Name, FALSE);\n}\n\nULONG NTAPI PhpSettingsHashtableHashFunction(\n    _In_ PVOID Entry\n    )\n{\n    PPH_SETTING setting = (PPH_SETTING)Entry;\n\n    return PhHashBytes((PUCHAR)setting->Name.Buffer, setting->Name.Length);\n}\n\nstatic ULONG PhpGetCurrentScale(\n    VOID\n    )\n{\n    static PH_INITONCE initOnce;\n    static ULONG dpi = 96;\n\n    if (PhBeginInitOnce(&initOnce))\n    {\n        HDC hdc;\n\n        if (hdc = GetDC(NULL))\n        {\n            dpi = GetDeviceCaps(hdc, LOGPIXELSY);\n            ReleaseDC(NULL, hdc);\n        }\n\n        PhEndInitOnce(&initOnce);\n    }\n\n    return dpi;\n}\n\nPPH_STRING PhSettingToString(\n    _In_ PH_SETTING_TYPE Type,\n    _In_ PPH_SETTING Setting\n    )\n{\n    switch (Type)\n    {\n    case StringSettingType:\n        {\n            if (!Setting->u.Pointer)\n                return PhReferenceEmptyString();\n\n            PhReferenceObject(Setting->u.Pointer);\n\n            return (PPH_STRING)Setting->u.Pointer;\n        }\n    case IntegerSettingType:\n        {\n            return PhFormatString(L\"%x\", Setting->u.Integer);\n        }\n    case IntegerPairSettingType:\n        {\n            PPH_INTEGER_PAIR integerPair = &Setting->u.IntegerPair;\n\n            return PhFormatString(L\"%ld,%ld\", integerPair->X, integerPair->Y);\n        }\n    case ScalableIntegerPairSettingType:\n        {\n            PPH_SCALABLE_INTEGER_PAIR scalableIntegerPair = Setting->u.Pointer;\n\n            if (!scalableIntegerPair)\n                return PhReferenceEmptyString();\n\n            return PhFormatString(L\"@%lu|%ld,%ld\", scalableIntegerPair->Scale, scalableIntegerPair->X, scalableIntegerPair->Y);\n        }\n    }\n\n    return PhReferenceEmptyString();\n}\n\nBOOLEAN PhSettingFromString(\n    _In_ PH_SETTING_TYPE Type,\n    _In_ PPH_STRINGREF StringRef,\n    _In_opt_ PPH_STRING String,\n    _Inout_ PPH_SETTING Setting\n    )\n{\n    switch (Type)\n    {\n    case StringSettingType:\n        {\n            if (String)\n            {\n                PhSetReference(&Setting->u.Pointer, String);\n            }\n            else\n            {\n                Setting->u.Pointer = PhCreateString2(StringRef);\n            }\n\n            return TRUE;\n        }\n    case IntegerSettingType:\n        {\n            ULONG64 integer;\n\n            if (PhStringToInteger64(StringRef, 16, &integer))\n            {\n                Setting->u.Integer = (ULONG)integer;\n                return TRUE;\n            }\n            else\n            {\n                return FALSE;\n            }\n        }\n    case IntegerPairSettingType:\n        {\n            LONG64 x;\n            LONG64 y;\n            PH_STRINGREF xString;\n            PH_STRINGREF yString;\n\n            if (!PhSplitStringRefAtChar(StringRef, ',', &xString, &yString))\n                return FALSE;\n\n            if (PhStringToInteger64(&xString, 10, &x) && PhStringToInteger64(&yString, 10, &y))\n            {\n                Setting->u.IntegerPair.X = (LONG)x;\n                Setting->u.IntegerPair.Y = (LONG)y;\n                return TRUE;\n            }\n            else\n            {\n                return FALSE;\n            }\n        }\n    case ScalableIntegerPairSettingType:\n        {\n            ULONG64 scale;\n            LONG64 x;\n            LONG64 y;\n            PH_STRINGREF stringRef;\n            PH_STRINGREF firstPart;\n            PH_STRINGREF secondPart;\n            PPH_SCALABLE_INTEGER_PAIR scalableIntegerPair;\n\n            stringRef = *StringRef;\n\n            if (stringRef.Length != 0 && stringRef.Buffer[0] == '@')\n            {\n                PhSkipStringRef(&stringRef, sizeof(WCHAR));\n\n                if (!PhSplitStringRefAtChar(&stringRef, '|', &firstPart, &stringRef))\n                    return FALSE;\n                if (!PhStringToInteger64(&firstPart, 10, &scale))\n                    return FALSE;\n            }\n            else\n            {\n                scale = PhpGetCurrentScale();\n            }\n\n            if (!PhSplitStringRefAtChar(&stringRef, ',', &firstPart, &secondPart))\n                return FALSE;\n\n            if (PhStringToInteger64(&firstPart, 10, &x) && PhStringToInteger64(&secondPart, 10, &y))\n            {\n                scalableIntegerPair = PhAllocate(sizeof(PH_SCALABLE_INTEGER_PAIR));\n                scalableIntegerPair->X = (LONG)x;\n                scalableIntegerPair->Y = (LONG)y;\n                scalableIntegerPair->Scale = (ULONG)scale;\n                Setting->u.Pointer = scalableIntegerPair;\n                return TRUE;\n            }\n            else\n            {\n                return FALSE;\n            }\n        }\n    }\n\n    return FALSE;\n}\n\nstatic VOID PhpFreeSettingValue(\n    _In_ PH_SETTING_TYPE Type,\n    _In_ PPH_SETTING Setting\n    )\n{\n    switch (Type)\n    {\n    case StringSettingType:\n        PhClearReference(&Setting->u.Pointer);\n        break;\n    case ScalableIntegerPairSettingType:\n        PhFree(Setting->u.Pointer);\n        Setting->u.Pointer = NULL;\n        break;\n    }\n}\n\nstatic PVOID PhpLookupSetting(\n    _In_ PPH_STRINGREF Name\n    )\n{\n    PH_SETTING lookupSetting;\n    PPH_SETTING setting;\n\n    lookupSetting.Name = *Name;\n    setting = (PPH_SETTING)PhFindEntryHashtable(\n        PhSettingsHashtable,\n        &lookupSetting\n        );\n\n    return setting;\n}\n\nVOID PhEnumSettings(\n    _In_ PPH_SETTINGS_ENUM_CALLBACK Callback,\n    _In_ PVOID Context\n    )\n{\n    PH_HASHTABLE_ENUM_CONTEXT enumContext;\n    PPH_SETTING setting;\n\n    PhAcquireQueuedLockExclusive(&PhSettingsLock);\n\n    PhBeginEnumHashtable(PhSettingsHashtable, &enumContext);\n\n    while (setting = PhNextEnumHashtable(&enumContext))\n    {\n        if (!Callback(setting, Context))\n            break;\n    }\n\n    PhReleaseQueuedLockExclusive(&PhSettingsLock);\n}\n\n_May_raise_ ULONG PhGetIntegerSetting(\n    _In_ PWSTR Name\n    )\n{\n    PPH_SETTING setting;\n    PH_STRINGREF name;\n    ULONG value;\n\n    PhInitializeStringRef(&name, Name);\n\n    PhAcquireQueuedLockShared(&PhSettingsLock);\n\n    setting = PhpLookupSetting(&name);\n\n    if (setting && setting->Type == IntegerSettingType)\n    {\n        value = setting->u.Integer;\n    }\n    else\n    {\n        setting = NULL;\n    }\n\n    PhReleaseQueuedLockShared(&PhSettingsLock);\n\n    if (!setting)\n        PhRaiseStatus(STATUS_NOT_FOUND);\n\n    return value;\n}\n\n_May_raise_ PH_INTEGER_PAIR PhGetIntegerPairSetting(\n    _In_ PWSTR Name\n    )\n{\n    PPH_SETTING setting;\n    PH_STRINGREF name;\n    PH_INTEGER_PAIR value;\n\n    PhInitializeStringRef(&name, Name);\n\n    PhAcquireQueuedLockShared(&PhSettingsLock);\n\n    setting = PhpLookupSetting(&name);\n\n    if (setting && setting->Type == IntegerPairSettingType)\n    {\n        value = setting->u.IntegerPair;\n    }\n    else\n    {\n        setting = NULL;\n    }\n\n    PhReleaseQueuedLockShared(&PhSettingsLock);\n\n    if (!setting)\n        PhRaiseStatus(STATUS_NOT_FOUND);\n\n    return value;\n}\n\n_May_raise_ PH_SCALABLE_INTEGER_PAIR PhGetScalableIntegerPairSetting(\n    _In_ PWSTR Name,\n    _In_ BOOLEAN ScaleToCurrent\n    )\n{\n    PPH_SETTING setting;\n    PH_STRINGREF name;\n    PH_SCALABLE_INTEGER_PAIR value;\n\n    PhInitializeStringRef(&name, Name);\n\n    PhAcquireQueuedLockShared(&PhSettingsLock);\n\n    setting = PhpLookupSetting(&name);\n\n    if (setting && setting->Type == ScalableIntegerPairSettingType)\n    {\n        value = *(PPH_SCALABLE_INTEGER_PAIR)setting->u.Pointer;\n    }\n    else\n    {\n        setting = NULL;\n    }\n\n    PhReleaseQueuedLockShared(&PhSettingsLock);\n\n    if (!setting)\n        PhRaiseStatus(STATUS_NOT_FOUND);\n\n    if (ScaleToCurrent)\n    {\n        ULONG currentScale;\n\n        currentScale = PhpGetCurrentScale();\n\n        if (value.Scale != currentScale && value.Scale != 0)\n        {\n            value.X = PhMultiplyDivideSigned(value.X, currentScale, value.Scale);\n            value.Y = PhMultiplyDivideSigned(value.Y, currentScale, value.Scale);\n            value.Scale = currentScale;\n        }\n    }\n\n    return value;\n}\n\n_May_raise_ PPH_STRING PhGetStringSetting(\n    _In_ PWSTR Name\n    )\n{\n    PPH_SETTING setting;\n    PH_STRINGREF name;\n    PPH_STRING value;\n\n    PhInitializeStringRef(&name, Name);\n\n    PhAcquireQueuedLockShared(&PhSettingsLock);\n\n    setting = PhpLookupSetting(&name);\n\n    if (setting && setting->Type == StringSettingType)\n    {\n        if (setting->u.Pointer)\n        {\n            PhSetReference(&value, setting->u.Pointer);\n        }\n        else\n        {\n            // Set to NULL, create an empty string\n            // outside of the lock.\n            value = NULL;\n        }\n    }\n    else\n    {\n        setting = NULL;\n    }\n\n    PhReleaseQueuedLockShared(&PhSettingsLock);\n\n    if (!setting)\n        PhRaiseStatus(STATUS_NOT_FOUND);\n\n    if (!value)\n        value = PhReferenceEmptyString();\n\n    return value;\n}\n\n_May_raise_ BOOLEAN PhGetBinarySetting(\n    _In_ PWSTR Name,\n    _Out_ PVOID Buffer\n    )\n{\n    PPH_STRING setting;\n    BOOLEAN result;\n\n    setting = PhGetStringSetting(Name);\n    result = PhHexStringToBuffer(&setting->sr, (PUCHAR)Buffer);\n    PhDereferenceObject(setting);\n\n    return result;\n}\n\n_May_raise_ VOID PhSetIntegerSetting(\n    _In_ PWSTR Name,\n    _In_ ULONG Value\n    )\n{\n    PPH_SETTING setting;\n    PH_STRINGREF name;\n\n    PhInitializeStringRef(&name, Name);\n\n    PhAcquireQueuedLockExclusive(&PhSettingsLock);\n\n    setting = PhpLookupSetting(&name);\n\n    if (setting && setting->Type == IntegerSettingType)\n    {\n        setting->u.Integer = Value;\n    }\n\n    PhReleaseQueuedLockExclusive(&PhSettingsLock);\n\n    if (!setting)\n        PhRaiseStatus(STATUS_NOT_FOUND);\n}\n\n_May_raise_ VOID PhSetIntegerPairSetting(\n    _In_ PWSTR Name,\n    _In_ PH_INTEGER_PAIR Value\n    )\n{\n    PPH_SETTING setting;\n    PH_STRINGREF name;\n\n    PhInitializeStringRef(&name, Name);\n\n    PhAcquireQueuedLockExclusive(&PhSettingsLock);\n\n    setting = PhpLookupSetting(&name);\n\n    if (setting && setting->Type == IntegerPairSettingType)\n    {\n        setting->u.IntegerPair = Value;\n    }\n\n    PhReleaseQueuedLockExclusive(&PhSettingsLock);\n\n    if (!setting)\n        PhRaiseStatus(STATUS_NOT_FOUND);\n}\n\n_May_raise_ VOID PhSetScalableIntegerPairSetting(\n    _In_ PWSTR Name,\n    _In_ PH_SCALABLE_INTEGER_PAIR Value\n    )\n{\n    PPH_SETTING setting;\n    PH_STRINGREF name;\n\n    PhInitializeStringRef(&name, Name);\n\n    PhAcquireQueuedLockExclusive(&PhSettingsLock);\n\n    setting = PhpLookupSetting(&name);\n\n    if (setting && setting->Type == ScalableIntegerPairSettingType)\n    {\n        PhpFreeSettingValue(ScalableIntegerPairSettingType, setting);\n        setting->u.Pointer = PhAllocateCopy(&Value, sizeof(PH_SCALABLE_INTEGER_PAIR));\n    }\n\n    PhReleaseQueuedLockExclusive(&PhSettingsLock);\n\n    if (!setting)\n        PhRaiseStatus(STATUS_NOT_FOUND);\n}\n\n_May_raise_ VOID PhSetScalableIntegerPairSetting2(\n    _In_ PWSTR Name,\n    _In_ PH_INTEGER_PAIR Value\n    )\n{\n    PH_SCALABLE_INTEGER_PAIR scalableIntegerPair;\n\n    scalableIntegerPair.Pair = Value;\n    scalableIntegerPair.Scale = PhpGetCurrentScale();\n    PhSetScalableIntegerPairSetting(Name, scalableIntegerPair);\n}\n\n_May_raise_ VOID PhSetStringSetting(\n    _In_ PWSTR Name,\n    _In_ PWSTR Value\n    )\n{\n    PPH_SETTING setting;\n    PH_STRINGREF name;\n\n    PhInitializeStringRef(&name, Name);\n\n    PhAcquireQueuedLockExclusive(&PhSettingsLock);\n\n    setting = PhpLookupSetting(&name);\n\n    if (setting && setting->Type == StringSettingType)\n    {\n        PhpFreeSettingValue(StringSettingType, setting);\n        setting->u.Pointer = PhCreateString(Value);\n    }\n\n    PhReleaseQueuedLockExclusive(&PhSettingsLock);\n\n    if (!setting)\n        PhRaiseStatus(STATUS_NOT_FOUND);\n}\n\n_May_raise_ VOID PhSetStringSetting2(\n    _In_ PWSTR Name,\n    _In_ PPH_STRINGREF Value\n    )\n{\n    PPH_SETTING setting;\n    PH_STRINGREF name;\n\n    PhInitializeStringRef(&name, Name);\n\n    PhAcquireQueuedLockExclusive(&PhSettingsLock);\n\n    setting = PhpLookupSetting(&name);\n\n    if (setting && setting->Type == StringSettingType)\n    {\n        PhpFreeSettingValue(StringSettingType, setting);\n        setting->u.Pointer = PhCreateString2(Value);\n    }\n\n    PhReleaseQueuedLockExclusive(&PhSettingsLock);\n\n    if (!setting)\n        PhRaiseStatus(STATUS_NOT_FOUND);\n}\n\n_May_raise_ VOID PhSetBinarySetting(\n    _In_ PWSTR Name,\n    _In_ PVOID Buffer,\n    _In_ ULONG Length\n    )\n{\n    PPH_STRING binaryString;\n    \n    binaryString = PhBufferToHexString((PUCHAR)Buffer, Length);\n    PhSetStringSetting(Name, binaryString->Buffer);\n    PhDereferenceObject(binaryString);\n}\n\nVOID PhpFreeIgnoredSetting(\n    _In_ PPH_SETTING Setting\n    )\n{\n    PhFree(Setting->Name.Buffer);\n    PhDereferenceObject(Setting->u.Pointer);\n\n    PhFree(Setting);\n}\n\nVOID PhpClearIgnoredSettings(\n    VOID\n    )\n{\n    ULONG i;\n\n    PhAcquireQueuedLockExclusive(&PhSettingsLock);\n\n    for (i = 0; i < PhIgnoredSettings->Count; i++)\n    {\n        PhpFreeIgnoredSetting(PhIgnoredSettings->Items[i]);\n    }\n\n    PhClearList(PhIgnoredSettings);\n\n    PhReleaseQueuedLockExclusive(&PhSettingsLock);\n}\n\nVOID PhClearIgnoredSettings(\n    VOID\n    )\n{\n    PhpClearIgnoredSettings();\n}\n\nVOID PhConvertIgnoredSettings(\n    VOID\n    )\n{\n    ULONG i;\n\n    PhAcquireQueuedLockExclusive(&PhSettingsLock);\n\n    for (i = 0; i < PhIgnoredSettings->Count; i++)\n    {\n        PPH_SETTING ignoredSetting = PhIgnoredSettings->Items[i];\n        PPH_SETTING setting;\n\n        setting = PhpLookupSetting(&ignoredSetting->Name);\n\n        if (setting)\n        {\n            PhpFreeSettingValue(setting->Type, setting);\n\n            if (!PhSettingFromString(\n                setting->Type,\n                &((PPH_STRING)ignoredSetting->u.Pointer)->sr,\n                ignoredSetting->u.Pointer,\n                setting\n                ))\n            {\n                PhSettingFromString(\n                    setting->Type,\n                    &setting->DefaultValue,\n                    NULL,\n                    setting\n                    );\n            }\n\n            PhpFreeIgnoredSetting(ignoredSetting);\n\n            PhRemoveItemList(PhIgnoredSettings, i);\n            i--;\n        }\n    }\n\n    PhReleaseQueuedLockExclusive(&PhSettingsLock);\n}\n\nPPH_STRING PhpGetOpaqueXmlNodeText(\n    _In_ mxml_node_t *node\n    )\n{\n    if (node->child && node->child->type == MXML_OPAQUE && node->child->value.opaque)\n    {\n        return PhConvertUtf8ToUtf16(node->child->value.opaque);\n    }\n    else\n    {\n        return PhReferenceEmptyString();\n    }\n}\n\nNTSTATUS PhLoadSettings(\n    _In_ PWSTR FileName\n    )\n{\n    NTSTATUS status;\n    HANDLE fileHandle;\n    LARGE_INTEGER fileSize;\n    mxml_node_t *topNode;\n    mxml_node_t *currentNode;\n\n    PhpClearIgnoredSettings();\n\n    status = PhCreateFileWin32(\n        &fileHandle,\n        FileName,\n        FILE_GENERIC_READ,\n        0,\n        FILE_SHARE_READ | FILE_SHARE_DELETE,\n        FILE_OPEN,\n        FILE_NON_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT\n        );\n\n    if (!NT_SUCCESS(status))\n        return status;\n\n    if (NT_SUCCESS(PhGetFileSize(fileHandle, &fileSize)) && fileSize.QuadPart == 0)\n    {\n        // A blank file is OK. There are no settings to load.\n        NtClose(fileHandle);\n        return status;\n    }\n\n    topNode = mxmlLoadFd(NULL, fileHandle, MXML_OPAQUE_CALLBACK);\n    NtClose(fileHandle);\n\n    if (!topNode)\n        return STATUS_FILE_CORRUPT_ERROR;\n\n    if (topNode->type != MXML_ELEMENT)\n    {\n        mxmlDelete(topNode);\n        return STATUS_FILE_CORRUPT_ERROR;\n    }\n\n    currentNode = topNode->child;\n\n    while (currentNode)\n    {\n        PPH_STRING settingName = NULL;\n\n        if (\n            currentNode->type == MXML_ELEMENT &&\n            currentNode->value.element.num_attrs >= 1 &&\n            _stricmp(currentNode->value.element.attrs[0].name, \"name\") == 0\n            )\n        {\n            settingName = PhConvertUtf8ToUtf16(currentNode->value.element.attrs[0].value);\n        }\n\n        if (settingName)\n        {\n            PPH_STRING settingValue = 0;\n\n            settingValue = PhpGetOpaqueXmlNodeText(currentNode);\n\n            PhAcquireQueuedLockExclusive(&PhSettingsLock);\n\n            {\n                PPH_SETTING setting;\n\n                setting = PhpLookupSetting(&settingName->sr);\n\n                if (setting)\n                {\n                    PhpFreeSettingValue(setting->Type, setting);\n\n                    if (!PhSettingFromString(\n                        setting->Type,\n                        &settingValue->sr,\n                        settingValue,\n                        setting\n                        ))\n                    {\n                        PhSettingFromString(\n                            setting->Type,\n                            &setting->DefaultValue,\n                            NULL,\n                            setting\n                            );\n                    }\n                }\n                else\n                {\n                    setting = PhAllocate(sizeof(PH_SETTING));\n                    setting->Name.Buffer = PhAllocateCopy(settingName->Buffer, settingName->Length + sizeof(WCHAR));\n                    setting->Name.Length = settingName->Length;\n                    PhReferenceObject(settingValue);\n                    setting->u.Pointer = settingValue;\n\n                    PhAddItemList(PhIgnoredSettings, setting);\n                }\n            }\n\n            PhReleaseQueuedLockExclusive(&PhSettingsLock);\n\n            PhDereferenceObject(settingValue);\n            PhDereferenceObject(settingName);\n        }\n\n        currentNode = currentNode->next;\n    }\n\n    mxmlDelete(topNode);\n\n    PhUpdateCachedSettings();\n\n    return STATUS_SUCCESS;\n}\n\nchar *PhpSettingsSaveCallback(\n    _In_ mxml_node_t *node,\n    _In_ int position\n    )\n{\n    if (PhEqualBytesZ(node->value.element.name, \"setting\", TRUE))\n    {\n        if (position == MXML_WS_BEFORE_OPEN)\n            return \"  \";\n        else if (position == MXML_WS_AFTER_CLOSE)\n            return \"\\r\\n\";\n    }\n    else if (PhEqualBytesZ(node->value.element.name, \"settings\", TRUE))\n    {\n        if (position == MXML_WS_AFTER_OPEN)\n            return \"\\r\\n\";\n    }\n\n    return NULL;\n}\n\nmxml_node_t *PhpCreateSettingElement(\n    _Inout_ mxml_node_t *ParentNode,\n    _In_ PPH_STRINGREF SettingName,\n    _In_ PPH_STRINGREF SettingValue\n    )\n{\n    mxml_node_t *settingNode;\n    mxml_node_t *textNode;\n    PPH_BYTES settingNameUtf8;\n    PPH_BYTES settingValueUtf8;\n\n    // Create the setting element.\n\n    settingNode = mxmlNewElement(ParentNode, \"setting\");\n\n    settingNameUtf8 = PhConvertUtf16ToUtf8Ex(SettingName->Buffer, SettingName->Length);\n    mxmlElementSetAttr(settingNode, \"name\", settingNameUtf8->Buffer);\n    PhDereferenceObject(settingNameUtf8);\n\n    // Set the value.\n\n    settingValueUtf8 = PhConvertUtf16ToUtf8Ex(SettingValue->Buffer, SettingValue->Length);\n    textNode = mxmlNewOpaque(settingNode, settingValueUtf8->Buffer);\n    PhDereferenceObject(settingValueUtf8);\n\n    return settingNode;\n}\n\nNTSTATUS PhSaveSettings(\n    _In_ PWSTR FileName\n    )\n{\n    NTSTATUS status;\n    HANDLE fileHandle;\n    mxml_node_t *topNode;\n    PH_HASHTABLE_ENUM_CONTEXT enumContext;\n    PPH_SETTING setting;\n\n    topNode = mxmlNewElement(MXML_NO_PARENT, \"settings\");\n\n    PhAcquireQueuedLockShared(&PhSettingsLock);\n\n    PhBeginEnumHashtable(PhSettingsHashtable, &enumContext);\n\n    while (setting = PhNextEnumHashtable(&enumContext))\n    {\n        PPH_STRING settingValue;\n\n        settingValue = PhSettingToString(setting->Type, setting);\n        PhpCreateSettingElement(topNode, &setting->Name, &settingValue->sr);\n        PhDereferenceObject(settingValue);\n    }\n\n    // Write the ignored settings.\n    {\n        ULONG i;\n\n        for (i = 0; i < PhIgnoredSettings->Count; i++)\n        {\n            PPH_STRING settingValue;\n\n            setting = PhIgnoredSettings->Items[i];\n            settingValue = setting->u.Pointer;\n            PhpCreateSettingElement(topNode, &setting->Name, &settingValue->sr);\n        }\n    }\n\n    PhReleaseQueuedLockShared(&PhSettingsLock);\n\n    // Create the directory if it does not exist.\n    {\n        PPH_STRING fullPath;\n        ULONG indexOfFileName;\n        PPH_STRING directoryName;\n\n        fullPath = PhGetFullPath(FileName, &indexOfFileName);\n\n        if (fullPath)\n        {\n            if (indexOfFileName != -1)\n            {\n                directoryName = PhSubstring(fullPath, 0, indexOfFileName);\n                //PhCreateDirectory(directoryName);\n                PhDereferenceObject(directoryName);\n            }\n\n            PhDereferenceObject(fullPath);\n        }\n    }\n\n    status = PhCreateFileWin32(\n        &fileHandle,\n        FileName,\n        FILE_GENERIC_WRITE,\n        0,\n        FILE_SHARE_READ,\n        FILE_OVERWRITE_IF,\n        FILE_NON_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT\n        );\n\n    if (!NT_SUCCESS(status))\n    {\n        mxmlDelete(topNode);\n        return status;\n    }\n\n    mxmlSaveFd(topNode, fileHandle, PhpSettingsSaveCallback);\n    mxmlDelete(topNode);\n    NtClose(fileHandle);\n\n    return STATUS_SUCCESS;\n}\n\nVOID PhResetSettings(\n    VOID\n    )\n{\n    PH_HASHTABLE_ENUM_CONTEXT enumContext;\n    PPH_SETTING setting;\n\n    PhAcquireQueuedLockExclusive(&PhSettingsLock);\n\n    PhBeginEnumHashtable(PhSettingsHashtable, &enumContext);\n\n    while (setting = PhNextEnumHashtable(&enumContext))\n    {\n        PhpFreeSettingValue(setting->Type, setting);\n        PhSettingFromString(setting->Type, &setting->DefaultValue, NULL, setting);\n    }\n\n    PhReleaseQueuedLockExclusive(&PhSettingsLock);\n}\n\nVOID PhAddSetting(\n    _In_ PH_SETTING_TYPE Type,\n    _In_ PPH_STRINGREF Name,\n    _In_ PPH_STRINGREF DefaultValue\n    )\n{\n    PH_SETTING setting;\n\n    setting.Type = Type;\n    setting.Name = *Name;\n    setting.DefaultValue = *DefaultValue;\n    memset(&setting.u, 0, sizeof(setting.u));\n\n    PhSettingFromString(Type, &setting.DefaultValue, NULL, &setting);\n\n    PhAddEntryHashtable(PhSettingsHashtable, &setting);\n}\n\nVOID PhAddSettings(\n    _In_ PPH_SETTING_CREATE Settings,\n    _In_ ULONG NumberOfSettings\n    )\n{\n    ULONG i;\n\n    PhAcquireQueuedLockExclusive(&PhSettingsLock);\n\n    for (i = 0; i < NumberOfSettings; i++)\n    {\n        PH_STRINGREF name;\n        PH_STRINGREF defaultValue;\n\n        PhInitializeStringRefLongHint(&name, Settings[i].Name);\n        PhInitializeStringRefLongHint(&defaultValue, Settings[i].DefaultValue);\n        PhAddSetting(Settings[i].Type, &name, &defaultValue);\n    }\n\n    PhReleaseQueuedLockExclusive(&PhSettingsLock);\n}\n\nVOID PhLoadWindowPlacementFromSetting(\n    _In_opt_ PWSTR PositionSettingName,\n    _In_opt_ PWSTR SizeSettingName,\n    _In_ HWND WindowHandle\n    )\n{\n    PH_RECTANGLE windowRectangle;\n\n    if (PositionSettingName && SizeSettingName)\n    {\n        RECT rectForAdjust;\n\n        windowRectangle.Position = PhGetIntegerPairSetting(PositionSettingName);\n        windowRectangle.Size = PhGetScalableIntegerPairSetting(SizeSettingName, TRUE).Pair;\n        PhAdjustRectangleToWorkingArea(NULL, &windowRectangle);\n\n        // Let the window adjust for the minimum size if needed.\n        rectForAdjust = PhRectangleToRect(windowRectangle);\n        SendMessage(WindowHandle, WM_SIZING, WMSZ_BOTTOMRIGHT, (LPARAM)&rectForAdjust);\n        windowRectangle = PhRectToRectangle(rectForAdjust);\n\n        MoveWindow(WindowHandle, windowRectangle.Left, windowRectangle.Top,\n            windowRectangle.Width, windowRectangle.Height, FALSE);\n    }\n    else\n    {\n        PH_INTEGER_PAIR position;\n        PH_INTEGER_PAIR size;\n        ULONG flags;\n\n        flags = SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOREDRAW | SWP_NOSIZE | SWP_NOZORDER;\n\n        if (PositionSettingName)\n        {\n            position = PhGetIntegerPairSetting(PositionSettingName);\n            flags &= ~SWP_NOMOVE;\n        }\n        else\n        {\n            position.X = 0;\n            position.Y = 0;\n        }\n\n        if (SizeSettingName)\n        {\n            size = PhGetScalableIntegerPairSetting(SizeSettingName, TRUE).Pair;\n            flags &= ~SWP_NOSIZE;\n        }\n        else\n        {\n            size.X = 16;\n            size.Y = 16;\n        }\n\n        SetWindowPos(WindowHandle, NULL, position.X, position.Y, size.X, size.Y, flags);\n    }\n}\n\nVOID PhSaveWindowPlacementToSetting(\n    _In_opt_ PWSTR PositionSettingName,\n    _In_opt_ PWSTR SizeSettingName,\n    _In_ HWND WindowHandle\n    )\n{\n    WINDOWPLACEMENT placement = { sizeof(placement) };\n    PH_RECTANGLE windowRectangle;\n    MONITORINFO monitorInfo = { sizeof(MONITORINFO) };\n\n    GetWindowPlacement(WindowHandle, &placement);\n    windowRectangle = PhRectToRectangle(placement.rcNormalPosition);\n\n    // The rectangle is in workspace coordinates. Convert the values back to screen coordinates.\n    if (GetMonitorInfo(MonitorFromRect(&placement.rcNormalPosition, MONITOR_DEFAULTTOPRIMARY), &monitorInfo))\n    {\n        windowRectangle.Left += monitorInfo.rcWork.left - monitorInfo.rcMonitor.left;\n        windowRectangle.Top += monitorInfo.rcWork.top - monitorInfo.rcMonitor.top;\n    }\n\n    if (PositionSettingName)\n        PhSetIntegerPairSetting(PositionSettingName, windowRectangle.Position);\n    if (SizeSettingName)\n        PhSetScalableIntegerPairSetting2(SizeSettingName, windowRectangle.Size);\n}\n\nBOOLEAN PhLoadListViewColumnSettings(\n    _In_ HWND ListViewHandle,\n    _In_ PPH_STRING Settings\n    )\n{\n#define ORDER_LIMIT 50\n    PH_STRINGREF remainingPart;\n    ULONG columnIndex;\n    ULONG orderArray[ORDER_LIMIT]; // HACK, but reasonable limit\n    ULONG maxOrder;\n    ULONG scale;\n\n    if (Settings->Length == 0)\n        return FALSE;\n\n    remainingPart = Settings->sr;\n    columnIndex = 0;\n    memset(orderArray, 0, sizeof(orderArray));\n    maxOrder = 0;\n\n    if (remainingPart.Length != 0 && remainingPart.Buffer[0] == '@')\n    {\n        PH_STRINGREF scalePart;\n        ULONG64 integer;\n\n        PhSkipStringRef(&remainingPart, sizeof(WCHAR));\n        PhSplitStringRefAtChar(&remainingPart, '|', &scalePart, &remainingPart);\n\n        if (scalePart.Length == 0 || !PhStringToInteger64(&scalePart, 10, &integer))\n            return FALSE;\n\n        scale = (ULONG)integer;\n    }\n    else\n    {\n        scale = PhGlobalDpi;\n    }\n\n    while (remainingPart.Length != 0)\n    {\n        PH_STRINGREF columnPart;\n        PH_STRINGREF orderPart;\n        PH_STRINGREF widthPart;\n        ULONG64 integer;\n        ULONG order;\n        ULONG width;\n        LVCOLUMN lvColumn;\n\n        PhSplitStringRefAtChar(&remainingPart, '|', &columnPart, &remainingPart);\n\n        if (columnPart.Length == 0)\n            return FALSE;\n\n        PhSplitStringRefAtChar(&columnPart, ',', &orderPart, &widthPart);\n\n        if (orderPart.Length == 0 || widthPart.Length == 0)\n            return FALSE;\n\n        // Order\n\n        if (!PhStringToInteger64(&orderPart, 10, &integer))\n            return FALSE;\n\n        order = (ULONG)integer;\n\n        if (order < ORDER_LIMIT)\n        {\n            orderArray[order] = columnIndex;\n\n            if (maxOrder < order + 1)\n                maxOrder = order + 1;\n        }\n\n        // Width\n\n        if (!PhStringToInteger64(&widthPart, 10, &integer))\n            return FALSE;\n\n        width = (ULONG)integer;\n\n        if (scale != PhGlobalDpi && scale != 0)\n            width = PhMultiplyDivide(width, PhGlobalDpi, scale);\n\n        lvColumn.mask = LVCF_WIDTH;\n        lvColumn.cx = width;\n        ListView_SetColumn(ListViewHandle, columnIndex, &lvColumn);\n\n        columnIndex++;\n    }\n\n    ListView_SetColumnOrderArray(ListViewHandle, maxOrder, orderArray);\n\n    return TRUE;\n}\n\nPPH_STRING PhSaveListViewColumnSettings(\n    _In_ HWND ListViewHandle\n    )\n{\n    PH_STRING_BUILDER stringBuilder;\n    ULONG i = 0;\n    LVCOLUMN lvColumn;\n\n    PhInitializeStringBuilder(&stringBuilder, 20);\n\n    PhAppendFormatStringBuilder(&stringBuilder, L\"@%u|\", PhGlobalDpi);\n\n    lvColumn.mask = LVCF_WIDTH | LVCF_ORDER;\n\n    while (ListView_GetColumn(ListViewHandle, i, &lvColumn))\n    {\n        PhAppendFormatStringBuilder(\n            &stringBuilder,\n            L\"%u,%u|\",\n            lvColumn.iOrder,\n            lvColumn.cx\n            );\n        i++;\n    }\n\n    if (stringBuilder.String->Length != 0)\n        PhRemoveEndStringBuilder(&stringBuilder, 1);\n\n    return PhFinalStringBuilderString(&stringBuilder);\n}\n\nVOID PhLoadListViewColumnsFromSetting(\n    _In_ PWSTR Name,\n    _In_ HWND ListViewHandle\n    )\n{\n    PPH_STRING string;\n\n    string = PhGetStringSetting(Name);\n    PhLoadListViewColumnSettings(ListViewHandle, string);\n    PhDereferenceObject(string);\n}\n\nVOID PhSaveListViewColumnsToSetting(\n    _In_ PWSTR Name,\n    _In_ HWND ListViewHandle\n    )\n{\n    PPH_STRING string;\n\n    string = PhSaveListViewColumnSettings(ListViewHandle);\n    PhSetStringSetting2(Name, &string->sr);\n    PhDereferenceObject(string);\n}"
  },
  {
    "path": "third_party/phlib/sha.c",
    "content": "/*\n * Copyright 2004 Filip Navara\n * Based on public domain SHA code by Steve Reid <steve@edmweb.com>\n *\n * This library is free software; you can redistribute it and/or\n * modify it under the terms of the GNU Lesser General Public\n * License as published by the Free Software Foundation; either\n * version 2.1 of the License, or (at your option) any later version.\n *\n * This library is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n * Lesser General Public License for more details.\n *\n * You should have received a copy of the GNU Lesser General Public\n * License along with this library; if not, write to the Free Software\n * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA\n */\n\n/* This code was modified for Process Hacker. */\n\n#include <phbase.h>\n#include \"sha.h\"\n\n/* SHA1 Helper Macros */\n\n//#define rol(value, bits) (((value) << (bits)) | ((value) >> (32 - (bits))))\n#define rol(value, bits) (_rotl((value), (bits)))\n#define DWORD2BE(x) (((x) >> 24) & 0xff) | (((x) >> 8) & 0xff00) | (((x) << 8) & 0xff0000) | (((x) << 24) & 0xff000000);\n#define blk0(i) (Block[i] = (rol(Block[i],24)&0xFF00FF00)|(rol(Block[i],8)&0x00FF00FF))\n#define blk1(i) (Block[i&15] = rol(Block[(i+13)&15]^Block[(i+8)&15]^Block[(i+2)&15]^Block[i&15],1))\n#define f1(x,y,z) (z^(x&(y^z)))\n#define f2(x,y,z) (x^y^z)\n#define f3(x,y,z) ((x&y)|(z&(x|y)))\n#define f4(x,y,z) (x^y^z)\n/* (R0+R1), R2, R3, R4 are the different operations used in SHA1 */\n#define R0(v,w,x,y,z,i) z+=f1(w,x,y)+blk0(i)+0x5A827999+rol(v,5);w=rol(w,30);\n#define R1(v,w,x,y,z,i) z+=f1(w,x,y)+blk1(i)+0x5A827999+rol(v,5);w=rol(w,30);\n#define R2(v,w,x,y,z,i) z+=f2(w,x,y)+blk1(i)+0x6ED9EBA1+rol(v,5);w=rol(w,30);\n#define R3(v,w,x,y,z,i) z+=f3(w,x,y)+blk1(i)+0x8F1BBCDC+rol(v,5);w=rol(w,30);\n#define R4(v,w,x,y,z,i) z+=f4(w,x,y)+blk1(i)+0xCA62C1D6+rol(v,5);w=rol(w,30);\n\n/* Hash a single 512-bit block. This is the core of the algorithm. */\nstatic void SHATransform(ULONG State[5], UCHAR Buffer[64])\n{\n   ULONG a, b, c, d, e;\n   ULONG *Block;\n\n   Block = (ULONG*)Buffer;\n\n   /* Copy Context->State[] to working variables */\n   a = State[0];\n   b = State[1];\n   c = State[2];\n   d = State[3];\n   e = State[4];\n\n   /* 4 rounds of 20 operations each. Loop unrolled. */\n   R0(a,b,c,d,e, 0); R0(e,a,b,c,d, 1); R0(d,e,a,b,c, 2); R0(c,d,e,a,b, 3);\n   R0(b,c,d,e,a, 4); R0(a,b,c,d,e, 5); R0(e,a,b,c,d, 6); R0(d,e,a,b,c, 7);\n   R0(c,d,e,a,b, 8); R0(b,c,d,e,a, 9); R0(a,b,c,d,e,10); R0(e,a,b,c,d,11);\n   R0(d,e,a,b,c,12); R0(c,d,e,a,b,13); R0(b,c,d,e,a,14); R0(a,b,c,d,e,15);\n   R1(e,a,b,c,d,16); R1(d,e,a,b,c,17); R1(c,d,e,a,b,18); R1(b,c,d,e,a,19);\n   R2(a,b,c,d,e,20); R2(e,a,b,c,d,21); R2(d,e,a,b,c,22); R2(c,d,e,a,b,23);\n   R2(b,c,d,e,a,24); R2(a,b,c,d,e,25); R2(e,a,b,c,d,26); R2(d,e,a,b,c,27);\n   R2(c,d,e,a,b,28); R2(b,c,d,e,a,29); R2(a,b,c,d,e,30); R2(e,a,b,c,d,31);\n   R2(d,e,a,b,c,32); R2(c,d,e,a,b,33); R2(b,c,d,e,a,34); R2(a,b,c,d,e,35);\n   R2(e,a,b,c,d,36); R2(d,e,a,b,c,37); R2(c,d,e,a,b,38); R2(b,c,d,e,a,39);\n   R3(a,b,c,d,e,40); R3(e,a,b,c,d,41); R3(d,e,a,b,c,42); R3(c,d,e,a,b,43);\n   R3(b,c,d,e,a,44); R3(a,b,c,d,e,45); R3(e,a,b,c,d,46); R3(d,e,a,b,c,47);\n   R3(c,d,e,a,b,48); R3(b,c,d,e,a,49); R3(a,b,c,d,e,50); R3(e,a,b,c,d,51);\n   R3(d,e,a,b,c,52); R3(c,d,e,a,b,53); R3(b,c,d,e,a,54); R3(a,b,c,d,e,55);\n   R3(e,a,b,c,d,56); R3(d,e,a,b,c,57); R3(c,d,e,a,b,58); R3(b,c,d,e,a,59);\n   R4(a,b,c,d,e,60); R4(e,a,b,c,d,61); R4(d,e,a,b,c,62); R4(c,d,e,a,b,63);\n   R4(b,c,d,e,a,64); R4(a,b,c,d,e,65); R4(e,a,b,c,d,66); R4(d,e,a,b,c,67);\n   R4(c,d,e,a,b,68); R4(b,c,d,e,a,69); R4(a,b,c,d,e,70); R4(e,a,b,c,d,71);\n   R4(d,e,a,b,c,72); R4(c,d,e,a,b,73); R4(b,c,d,e,a,74); R4(a,b,c,d,e,75);\n   R4(e,a,b,c,d,76); R4(d,e,a,b,c,77); R4(c,d,e,a,b,78); R4(b,c,d,e,a,79);\n\n   /* Add the working variables back into Context->State[] */\n   State[0] += a;\n   State[1] += b;\n   State[2] += c;\n   State[3] += d;\n   State[4] += e;\n\n   /* Wipe variables */\n   a = b = c = d = e = 0;\n}\n\nVOID A_SHAInit(\n    _Out_ A_SHA_CTX *Context\n    )\n{\n   /* SHA1 initialization constants */\n   Context->state[0] = 0x67452301;\n   Context->state[1] = 0xEFCDAB89;\n   Context->state[2] = 0x98BADCFE;\n   Context->state[3] = 0x10325476;\n   Context->state[4] = 0xC3D2E1F0;\n   Context->count[0] = 0;\n   Context->count[1] = 0;\n}\n\nVOID A_SHAUpdate(\n    _Inout_ A_SHA_CTX *Context,\n    _In_reads_bytes_(Length) UCHAR *Input,\n    _In_ ULONG Length\n    )\n{\n   ULONG InputContentSize;\n\n   InputContentSize = Context->count[1] & 63;\n   Context->count[1] += Length;\n   if (Context->count[1] < Length)\n      Context->count[0]++;\n   Context->count[0] += (Length >> 29);\n\n   if (InputContentSize + Length < 64)\n   {\n      RtlCopyMemory(&Context->buffer[InputContentSize], Input,\n                    Length);\n   }\n   else\n   {\n      while (InputContentSize + Length >= 64)\n      {\n         RtlCopyMemory(Context->buffer + InputContentSize, Input,\n                       64 - InputContentSize);\n         Input += 64 - InputContentSize;\n         Length -= 64 - InputContentSize;\n         SHATransform(Context->state, Context->buffer);\n         InputContentSize = 0;\n      }\n      RtlCopyMemory(Context->buffer + InputContentSize, Input, Length);\n   }\n}\n\nVOID A_SHAFinal(\n    _Inout_ A_SHA_CTX *Context,\n    _Out_writes_bytes_(20) UCHAR *Hash\n    )\n{\n   INT Pad, Index;\n   UCHAR Buffer[72];\n   ULONG *Count;\n   ULONG BufferContentSize, LengthHi, LengthLo;\n   ULONG *Result;\n\n   BufferContentSize = Context->count[1] & 63;\n   if (BufferContentSize >= 56)\n      Pad = 56 + 64 - BufferContentSize;\n   else\n      Pad = 56 - BufferContentSize;\n\n   LengthHi = (Context->count[0] << 3) | (Context->count[1] >> (32 - 3));\n   LengthLo = (Context->count[1] << 3);\n\n   RtlZeroMemory(Buffer + 1, Pad - 1);\n   Buffer[0] = 0x80;\n   Count = (ULONG*)(Buffer + Pad);\n   Count[0] = DWORD2BE(LengthHi);\n   Count[1] = DWORD2BE(LengthLo);\n   A_SHAUpdate(Context, Buffer, Pad + 8);\n\n   Result = (ULONG *)Hash;\n\n   for (Index = 0; Index < 5; Index++)\n      Result[Index] = DWORD2BE(Context->state[Index]);\n\n   A_SHAInit(Context);\n}\n"
  },
  {
    "path": "third_party/phlib/sha.h",
    "content": "#ifndef _SHA_H\n#define _SHA_H\n\ntypedef struct\n{\n    ULONG flag;\n    UCHAR hash[20];\n    ULONG state[5];\n    ULONG count[2];\n    UCHAR buffer[64];\n} A_SHA_CTX;\n\nVOID A_SHAInit(\n    _Out_ A_SHA_CTX *Context\n    );\n\nVOID A_SHAUpdate(\n    _Inout_ A_SHA_CTX *Context,\n    _In_reads_bytes_(Length) UCHAR *Input,\n    _In_ ULONG Length\n    );\n\nVOID A_SHAFinal(\n    _Inout_ A_SHA_CTX *Context,\n    _Out_writes_bytes_(20) UCHAR *Hash\n    );\n\n#endif\n"
  },
  {
    "path": "third_party/phlib/sha256.c",
    "content": "/*\n *  FIPS-180-2 compliant SHA-256 implementation\n *\n *  Copyright (C) 2001-2003  Christophe Devine\n *\n *  This program is free software; you can redistribute it and/or modify\n *  it under the terms of the GNU General Public License as published by\n *  the Free Software Foundation; either version 2 of the License, or\n *  (at your option) any later version.\n *\n *  This program is distributed in the hope that it will be useful,\n *  but WITHOUT ANY WARRANTY; without even the implied warranty of\n *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n *  GNU General Public License for more details.\n *\n *  You should have received a copy of the GNU General Public License\n *  along with this program; if not, write to the Free Software\n *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA\n */\n\n#include <string.h>\n\n#include \"sha256.h\"\n\n#define GET_UINT32(n,b,i)                       \\\n{                                               \\\n    (n) = ( (uint32) (b)[(i)    ] << 24 )       \\\n        | ( (uint32) (b)[(i) + 1] << 16 )       \\\n        | ( (uint32) (b)[(i) + 2] <<  8 )       \\\n        | ( (uint32) (b)[(i) + 3]       );      \\\n}\n\n#define PUT_UINT32(n,b,i)                       \\\n{                                               \\\n    (b)[(i)    ] = (uint8) ( (n) >> 24 );       \\\n    (b)[(i) + 1] = (uint8) ( (n) >> 16 );       \\\n    (b)[(i) + 2] = (uint8) ( (n) >>  8 );       \\\n    (b)[(i) + 3] = (uint8) ( (n)       );       \\\n}\n\nvoid sha256_starts( sha256_context *ctx )\n{\n    ctx->total[0] = 0;\n    ctx->total[1] = 0;\n\n    ctx->state[0] = 0x6A09E667;\n    ctx->state[1] = 0xBB67AE85;\n    ctx->state[2] = 0x3C6EF372;\n    ctx->state[3] = 0xA54FF53A;\n    ctx->state[4] = 0x510E527F;\n    ctx->state[5] = 0x9B05688C;\n    ctx->state[6] = 0x1F83D9AB;\n    ctx->state[7] = 0x5BE0CD19;\n}\n\nvoid sha256_process( sha256_context *ctx, uint8 data[64] )\n{\n    uint32 temp1, temp2, W[64];\n    uint32 A, B, C, D, E, F, G, H;\n\n    GET_UINT32( W[0],  data,  0 );\n    GET_UINT32( W[1],  data,  4 );\n    GET_UINT32( W[2],  data,  8 );\n    GET_UINT32( W[3],  data, 12 );\n    GET_UINT32( W[4],  data, 16 );\n    GET_UINT32( W[5],  data, 20 );\n    GET_UINT32( W[6],  data, 24 );\n    GET_UINT32( W[7],  data, 28 );\n    GET_UINT32( W[8],  data, 32 );\n    GET_UINT32( W[9],  data, 36 );\n    GET_UINT32( W[10], data, 40 );\n    GET_UINT32( W[11], data, 44 );\n    GET_UINT32( W[12], data, 48 );\n    GET_UINT32( W[13], data, 52 );\n    GET_UINT32( W[14], data, 56 );\n    GET_UINT32( W[15], data, 60 );\n\n#define  SHR(x,n) ((x & 0xFFFFFFFF) >> n)\n#define ROTR(x,n) (SHR(x,n) | (x << (32 - n)))\n\n#define S0(x) (ROTR(x, 7) ^ ROTR(x,18) ^  SHR(x, 3))\n#define S1(x) (ROTR(x,17) ^ ROTR(x,19) ^  SHR(x,10))\n\n#define S2(x) (ROTR(x, 2) ^ ROTR(x,13) ^ ROTR(x,22))\n#define S3(x) (ROTR(x, 6) ^ ROTR(x,11) ^ ROTR(x,25))\n\n#define F0(x,y,z) ((x & y) | (z & (x | y)))\n#define F1(x,y,z) (z ^ (x & (y ^ z)))\n\n#define R(t)                                    \\\n(                                               \\\n    W[t] = S1(W[t -  2]) + W[t -  7] +          \\\n           S0(W[t - 15]) + W[t - 16]            \\\n)\n\n#define P(a,b,c,d,e,f,g,h,x,K)                  \\\n{                                               \\\n    temp1 = h + S3(e) + F1(e,f,g) + K + x;      \\\n    temp2 = S2(a) + F0(a,b,c);                  \\\n    d += temp1; h = temp1 + temp2;              \\\n}\n\n    A = ctx->state[0];\n    B = ctx->state[1];\n    C = ctx->state[2];\n    D = ctx->state[3];\n    E = ctx->state[4];\n    F = ctx->state[5];\n    G = ctx->state[6];\n    H = ctx->state[7];\n\n    P( A, B, C, D, E, F, G, H, W[ 0], 0x428A2F98 );\n    P( H, A, B, C, D, E, F, G, W[ 1], 0x71374491 );\n    P( G, H, A, B, C, D, E, F, W[ 2], 0xB5C0FBCF );\n    P( F, G, H, A, B, C, D, E, W[ 3], 0xE9B5DBA5 );\n    P( E, F, G, H, A, B, C, D, W[ 4], 0x3956C25B );\n    P( D, E, F, G, H, A, B, C, W[ 5], 0x59F111F1 );\n    P( C, D, E, F, G, H, A, B, W[ 6], 0x923F82A4 );\n    P( B, C, D, E, F, G, H, A, W[ 7], 0xAB1C5ED5 );\n    P( A, B, C, D, E, F, G, H, W[ 8], 0xD807AA98 );\n    P( H, A, B, C, D, E, F, G, W[ 9], 0x12835B01 );\n    P( G, H, A, B, C, D, E, F, W[10], 0x243185BE );\n    P( F, G, H, A, B, C, D, E, W[11], 0x550C7DC3 );\n    P( E, F, G, H, A, B, C, D, W[12], 0x72BE5D74 );\n    P( D, E, F, G, H, A, B, C, W[13], 0x80DEB1FE );\n    P( C, D, E, F, G, H, A, B, W[14], 0x9BDC06A7 );\n    P( B, C, D, E, F, G, H, A, W[15], 0xC19BF174 );\n    P( A, B, C, D, E, F, G, H, R(16), 0xE49B69C1 );\n    P( H, A, B, C, D, E, F, G, R(17), 0xEFBE4786 );\n    P( G, H, A, B, C, D, E, F, R(18), 0x0FC19DC6 );\n    P( F, G, H, A, B, C, D, E, R(19), 0x240CA1CC );\n    P( E, F, G, H, A, B, C, D, R(20), 0x2DE92C6F );\n    P( D, E, F, G, H, A, B, C, R(21), 0x4A7484AA );\n    P( C, D, E, F, G, H, A, B, R(22), 0x5CB0A9DC );\n    P( B, C, D, E, F, G, H, A, R(23), 0x76F988DA );\n    P( A, B, C, D, E, F, G, H, R(24), 0x983E5152 );\n    P( H, A, B, C, D, E, F, G, R(25), 0xA831C66D );\n    P( G, H, A, B, C, D, E, F, R(26), 0xB00327C8 );\n    P( F, G, H, A, B, C, D, E, R(27), 0xBF597FC7 );\n    P( E, F, G, H, A, B, C, D, R(28), 0xC6E00BF3 );\n    P( D, E, F, G, H, A, B, C, R(29), 0xD5A79147 );\n    P( C, D, E, F, G, H, A, B, R(30), 0x06CA6351 );\n    P( B, C, D, E, F, G, H, A, R(31), 0x14292967 );\n    P( A, B, C, D, E, F, G, H, R(32), 0x27B70A85 );\n    P( H, A, B, C, D, E, F, G, R(33), 0x2E1B2138 );\n    P( G, H, A, B, C, D, E, F, R(34), 0x4D2C6DFC );\n    P( F, G, H, A, B, C, D, E, R(35), 0x53380D13 );\n    P( E, F, G, H, A, B, C, D, R(36), 0x650A7354 );\n    P( D, E, F, G, H, A, B, C, R(37), 0x766A0ABB );\n    P( C, D, E, F, G, H, A, B, R(38), 0x81C2C92E );\n    P( B, C, D, E, F, G, H, A, R(39), 0x92722C85 );\n    P( A, B, C, D, E, F, G, H, R(40), 0xA2BFE8A1 );\n    P( H, A, B, C, D, E, F, G, R(41), 0xA81A664B );\n    P( G, H, A, B, C, D, E, F, R(42), 0xC24B8B70 );\n    P( F, G, H, A, B, C, D, E, R(43), 0xC76C51A3 );\n    P( E, F, G, H, A, B, C, D, R(44), 0xD192E819 );\n    P( D, E, F, G, H, A, B, C, R(45), 0xD6990624 );\n    P( C, D, E, F, G, H, A, B, R(46), 0xF40E3585 );\n    P( B, C, D, E, F, G, H, A, R(47), 0x106AA070 );\n    P( A, B, C, D, E, F, G, H, R(48), 0x19A4C116 );\n    P( H, A, B, C, D, E, F, G, R(49), 0x1E376C08 );\n    P( G, H, A, B, C, D, E, F, R(50), 0x2748774C );\n    P( F, G, H, A, B, C, D, E, R(51), 0x34B0BCB5 );\n    P( E, F, G, H, A, B, C, D, R(52), 0x391C0CB3 );\n    P( D, E, F, G, H, A, B, C, R(53), 0x4ED8AA4A );\n    P( C, D, E, F, G, H, A, B, R(54), 0x5B9CCA4F );\n    P( B, C, D, E, F, G, H, A, R(55), 0x682E6FF3 );\n    P( A, B, C, D, E, F, G, H, R(56), 0x748F82EE );\n    P( H, A, B, C, D, E, F, G, R(57), 0x78A5636F );\n    P( G, H, A, B, C, D, E, F, R(58), 0x84C87814 );\n    P( F, G, H, A, B, C, D, E, R(59), 0x8CC70208 );\n    P( E, F, G, H, A, B, C, D, R(60), 0x90BEFFFA );\n    P( D, E, F, G, H, A, B, C, R(61), 0xA4506CEB );\n    P( C, D, E, F, G, H, A, B, R(62), 0xBEF9A3F7 );\n    P( B, C, D, E, F, G, H, A, R(63), 0xC67178F2 );\n\n    ctx->state[0] += A;\n    ctx->state[1] += B;\n    ctx->state[2] += C;\n    ctx->state[3] += D;\n    ctx->state[4] += E;\n    ctx->state[5] += F;\n    ctx->state[6] += G;\n    ctx->state[7] += H;\n}\n\nvoid sha256_update( sha256_context *ctx, uint8 *input, uint32 length )\n{\n    uint32 left, fill;\n\n    if( ! length ) return;\n\n    left = ctx->total[0] & 0x3F;\n    fill = 64 - left;\n\n    ctx->total[0] += length;\n    ctx->total[0] &= 0xFFFFFFFF;\n\n    if( ctx->total[0] < length )\n        ctx->total[1]++;\n\n    if( left && length >= fill )\n    {\n        memcpy( (void *) (ctx->buffer + left),\n                (void *) input, fill );\n        sha256_process( ctx, ctx->buffer );\n        length -= fill;\n        input  += fill;\n        left = 0;\n    }\n\n    while( length >= 64 )\n    {\n        sha256_process( ctx, input );\n        length -= 64;\n        input  += 64;\n    }\n\n    if( length )\n    {\n        memcpy( (void *) (ctx->buffer + left),\n                (void *) input, length );\n    }\n}\n\nstatic uint8 sha256_padding[64] =\n{\n 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\n    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\n    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\n    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0\n};\n\nvoid sha256_finish( sha256_context *ctx, uint8 digest[32] )\n{\n    uint32 last, padn;\n    uint32 high, low;\n    uint8 msglen[8];\n\n    high = ( ctx->total[0] >> 29 )\n         | ( ctx->total[1] <<  3 );\n    low  = ( ctx->total[0] <<  3 );\n\n    PUT_UINT32( high, msglen, 0 );\n    PUT_UINT32( low,  msglen, 4 );\n\n    last = ctx->total[0] & 0x3F;\n    padn = ( last < 56 ) ? ( 56 - last ) : ( 120 - last );\n\n    sha256_update( ctx, sha256_padding, padn );\n    sha256_update( ctx, msglen, 8 );\n\n    PUT_UINT32( ctx->state[0], digest,  0 );\n    PUT_UINT32( ctx->state[1], digest,  4 );\n    PUT_UINT32( ctx->state[2], digest,  8 );\n    PUT_UINT32( ctx->state[3], digest, 12 );\n    PUT_UINT32( ctx->state[4], digest, 16 );\n    PUT_UINT32( ctx->state[5], digest, 20 );\n    PUT_UINT32( ctx->state[6], digest, 24 );\n    PUT_UINT32( ctx->state[7], digest, 28 );\n}\n\n#ifdef TEST\n\n#include <stdlib.h>\n#include <stdio.h>\n\n/*\n * those are the standard FIPS-180-2 test vectors\n */\n\nstatic char *msg[] =\n{\n    \"abc\",\n    \"abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq\",\n    NULL\n};\n\nstatic char *val[] =\n{\n    \"ba7816bf8f01cfea414140de5dae2223\" \\\n    \"b00361a396177a9cb410ff61f20015ad\",\n    \"248d6a61d20638b8e5c026930c3e6039\" \\\n    \"a33ce45964ff2167f6ecedd419db06c1\",\n    \"cdc76e5c9914fb9281a1c7e284d73e67\" \\\n    \"f1809a48a497200e046d39ccc7112cd0\"\n};\n\nint main( int argc, char *argv[] )\n{\n    FILE *f;\n    int i, j;\n    char output[65];\n    sha256_context ctx;\n    unsigned char buf[1000];\n    unsigned char sha256sum[32];\n\n    if( argc < 2 )\n    {\n        printf( \"\\n SHA-256 Validation Tests:\\n\\n\" );\n\n        for( i = 0; i < 3; i++ )\n        {\n            printf( \" Test %d \", i + 1 );\n\n            sha256_starts( &ctx );\n\n            if( i < 2 )\n            {\n                sha256_update( &ctx, (uint8 *) msg[i],\n                               strlen( msg[i] ) );\n            }\n            else\n            {\n                memset( buf, 'a', 1000 );\n\n                for( j = 0; j < 1000; j++ )\n                {\n                    sha256_update( &ctx, (uint8 *) buf, 1000 );\n                }\n            }\n\n            sha256_finish( &ctx, sha256sum );\n\n            for( j = 0; j < 32; j++ )\n            {\n                sprintf( output + j * 2, \"%02x\", sha256sum[j] );\n            }\n\n            if( memcmp( output, val[i], 64 ) )\n            {\n                printf( \"failed!\\n\" );\n                return( 1 );\n            }\n\n            printf( \"passed.\\n\" );\n        }\n\n        printf( \"\\n\" );\n    }\n    else\n    {\n        if( ! ( f = fopen( argv[1], \"rb\" ) ) )\n        {\n            perror( \"fopen\" );\n            return( 1 );\n        }\n\n        sha256_starts( &ctx );\n\n        while( ( i = fread( buf, 1, sizeof( buf ), f ) ) > 0 )\n        {\n            sha256_update( &ctx, buf, i );\n        }\n\n        sha256_finish( &ctx, sha256sum );\n\n        for( j = 0; j < 32; j++ )\n        {\n            printf( \"%02x\", sha256sum[j] );\n        }\n\n        printf( \"  %s\\n\", argv[1] );\n    }\n\n    return( 0 );\n}\n\n#endif\n"
  },
  {
    "path": "third_party/phlib/sha256.h",
    "content": "#ifndef _SHA256_H\n#define _SHA256_H\n\n#ifndef uint8\n#define uint8  unsigned char\n#endif\n\n#ifndef uint32\n#define uint32 unsigned long int\n#endif\n\ntypedef struct\n{\n    uint32 total[2];\n    uint32 state[8];\n    uint8 buffer[64];\n}\nsha256_context;\n\nvoid sha256_starts( sha256_context *ctx );\nvoid sha256_update( sha256_context *ctx, uint8 *input, uint32 length );\nvoid sha256_finish( sha256_context *ctx, uint8 digest[32] );\n\n#endif /* sha256.h */\n"
  },
  {
    "path": "third_party/phlib/svcsup.c",
    "content": "/*\n * Process Hacker -\n *   service support functions\n *\n * Copyright (C) 2010-2012 wj32\n *\n * This file is part of Process Hacker.\n *\n * Process Hacker is free software; you can redistribute it and/or modify\n * it under the terms of the GNU General Public License as published by\n * the Free Software Foundation, either version 3 of the License, or\n * (at your option) any later version.\n *\n * Process Hacker is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n * GNU General Public License for more details.\n *\n * You should have received a copy of the GNU General Public License\n * along with Process Hacker.  If not, see <http://www.gnu.org/licenses/>.\n */\n\n#include <ph.h>\n\n#include <subprocesstag.h>\n\n#include <svcsup.h>\n\n#define SIP(String, Integer) { (String), (PVOID)(Integer) }\n\nstatic PH_KEY_VALUE_PAIR PhpServiceStatePairs[] =\n{\n    SIP(L\"Stopped\", SERVICE_STOPPED),\n    SIP(L\"Start pending\", SERVICE_START_PENDING),\n    SIP(L\"Stop pending\", SERVICE_STOP_PENDING),\n    SIP(L\"Running\", SERVICE_RUNNING),\n    SIP(L\"Continue pending\", SERVICE_CONTINUE_PENDING),\n    SIP(L\"Pause pending\", SERVICE_PAUSE_PENDING),\n    SIP(L\"Paused\", SERVICE_PAUSED)\n};\n\nstatic PH_KEY_VALUE_PAIR PhpServiceTypePairs[] =\n{\n    SIP(L\"Driver\", SERVICE_KERNEL_DRIVER),\n    SIP(L\"FS driver\", SERVICE_FILE_SYSTEM_DRIVER),\n    SIP(L\"Own process\", SERVICE_WIN32_OWN_PROCESS),\n    SIP(L\"Share process\", SERVICE_WIN32_SHARE_PROCESS),\n    SIP(L\"Own interactive process\", SERVICE_WIN32_OWN_PROCESS | SERVICE_INTERACTIVE_PROCESS),\n    SIP(L\"Share interactive process\", SERVICE_WIN32_SHARE_PROCESS | SERVICE_INTERACTIVE_PROCESS),\n    SIP(L\"User own process\", SERVICE_USER_OWN_PROCESS),\n    SIP(L\"User own process (instance)\", SERVICE_USER_OWN_PROCESS | SERVICE_USERSERVICE_INSTANCE),\n    SIP(L\"User share process\", SERVICE_USER_SHARE_PROCESS),\n    SIP(L\"User share process (instance)\", SERVICE_USER_SHARE_PROCESS | SERVICE_USERSERVICE_INSTANCE)\n};\n\nstatic PH_KEY_VALUE_PAIR PhpServiceStartTypePairs[] =\n{\n    SIP(L\"Disabled\", SERVICE_DISABLED),\n    SIP(L\"Boot start\", SERVICE_BOOT_START),\n    SIP(L\"System start\", SERVICE_SYSTEM_START),\n    SIP(L\"Auto start\", SERVICE_AUTO_START),\n    SIP(L\"Demand start\", SERVICE_DEMAND_START)\n};\n\nstatic PH_KEY_VALUE_PAIR PhpServiceErrorControlPairs[] =\n{\n    SIP(L\"Ignore\", SERVICE_ERROR_IGNORE),\n    SIP(L\"Normal\", SERVICE_ERROR_NORMAL),\n    SIP(L\"Severe\", SERVICE_ERROR_SEVERE),\n    SIP(L\"Critical\", SERVICE_ERROR_CRITICAL)\n};\n\nWCHAR *PhServiceTypeStrings[10] = { L\"Driver\", L\"FS driver\", L\"Own process\", L\"Share process\",\n    L\"Own interactive process\", L\"Share interactive process\", L\"User own process\", L\"User own process (instance)\",\n    L\"User share process\", L\"User share process (instance)\" };\nWCHAR *PhServiceStartTypeStrings[5] = { L\"Disabled\", L\"Boot start\", L\"System start\",\n    L\"Auto start\", L\"Demand start\" };\nWCHAR *PhServiceErrorControlStrings[4] = { L\"Ignore\", L\"Normal\", L\"Severe\", L\"Critical\" };\n\nPVOID PhEnumServices(\n    _In_ SC_HANDLE ScManagerHandle,\n    _In_opt_ ULONG Type,\n    _In_opt_ ULONG State,\n    _Out_ PULONG Count\n    )\n{\n    static ULONG initialBufferSize = 0x8000;\n    LOGICAL result;\n    PVOID buffer;\n    ULONG bufferSize;\n    ULONG returnLength;\n    ULONG servicesReturned;\n\n    if (!Type)\n    {\n        if (WindowsVersion >= WINDOWS_10_RS1)\n        {\n            Type = SERVICE_TYPE_ALL;\n        }\n        else if (WindowsVersion >= WINDOWS_10)\n        {\n            Type = SERVICE_WIN32 |\n                SERVICE_ADAPTER |\n                SERVICE_DRIVER |\n                SERVICE_INTERACTIVE_PROCESS |\n                SERVICE_USER_SERVICE |\n                SERVICE_USERSERVICE_INSTANCE;\n        }\n        else\n        {\n            Type = SERVICE_DRIVER | SERVICE_WIN32;\n        }\n    }\n\n    if (!State)\n        State = SERVICE_STATE_ALL;\n\n    bufferSize = initialBufferSize;\n    buffer = PhAllocate(bufferSize);\n\n    if (!(result = EnumServicesStatusEx(\n        ScManagerHandle,\n        SC_ENUM_PROCESS_INFO,\n        Type,\n        State,\n        buffer,\n        bufferSize,\n        &returnLength,\n        &servicesReturned,\n        NULL,\n        NULL\n        )))\n    {\n        if (GetLastError() == ERROR_MORE_DATA)\n        {\n            PhFree(buffer);\n            bufferSize += returnLength;\n            buffer = PhAllocate(bufferSize);\n\n            result = EnumServicesStatusEx(\n                ScManagerHandle,\n                SC_ENUM_PROCESS_INFO,\n                Type,\n                State,\n                buffer,\n                bufferSize,\n                &returnLength,\n                &servicesReturned,\n                NULL,\n                NULL\n                );\n        }\n\n        if (!result)\n        {\n            PhFree(buffer);\n            return NULL;\n        }\n    }\n\n    if (bufferSize <= 0x20000) initialBufferSize = bufferSize;\n    *Count = servicesReturned;\n\n    return buffer;\n}\n\nSC_HANDLE PhOpenService(\n    _In_ PWSTR ServiceName,\n    _In_ ACCESS_MASK DesiredAccess\n    )\n{\n    SC_HANDLE scManagerHandle;\n    SC_HANDLE serviceHandle;\n\n    scManagerHandle = OpenSCManager(NULL, NULL, SC_MANAGER_CONNECT);\n\n    if (!scManagerHandle)\n        return NULL;\n\n    serviceHandle = OpenService(scManagerHandle, ServiceName, DesiredAccess);\n    CloseServiceHandle(scManagerHandle);\n\n    return serviceHandle;\n}\n\nPVOID PhGetServiceConfig(\n    _In_ SC_HANDLE ServiceHandle\n    )\n{\n    PVOID buffer;\n    ULONG bufferSize = 0x200;\n\n    buffer = PhAllocate(bufferSize);\n\n    if (!QueryServiceConfig(ServiceHandle, buffer, bufferSize, &bufferSize))\n    {\n        PhFree(buffer);\n        buffer = PhAllocate(bufferSize);\n\n        if (!QueryServiceConfig(ServiceHandle, buffer, bufferSize, &bufferSize))\n        {\n            PhFree(buffer);\n            return NULL;\n        }\n    }\n\n    return buffer;\n}\n\nPVOID PhQueryServiceVariableSize(\n    _In_ SC_HANDLE ServiceHandle,\n    _In_ ULONG InfoLevel\n    )\n{\n    PVOID buffer;\n    ULONG bufferSize = 0x100;\n\n    buffer = PhAllocate(bufferSize);\n\n    if (!QueryServiceConfig2(\n        ServiceHandle,\n        InfoLevel,\n        (BYTE *)buffer,\n        bufferSize,\n        &bufferSize\n        ))\n    {\n        PhFree(buffer);\n        buffer = PhAllocate(bufferSize);\n\n        if (!QueryServiceConfig2(\n            ServiceHandle,\n            InfoLevel,\n            (BYTE *)buffer,\n            bufferSize,\n            &bufferSize\n            ))\n        {\n            PhFree(buffer);\n            return NULL;\n        }\n    }\n\n    return buffer;\n}\n\nPPH_STRING PhGetServiceDescription(\n    _In_ SC_HANDLE ServiceHandle\n    )\n{\n    PPH_STRING description = NULL;\n    LPSERVICE_DESCRIPTION serviceDescription;\n\n    serviceDescription = PhQueryServiceVariableSize(ServiceHandle, SERVICE_CONFIG_DESCRIPTION);\n\n    if (serviceDescription)\n    {\n        if (serviceDescription->lpDescription)\n            description = PhCreateString(serviceDescription->lpDescription);\n\n        PhFree(serviceDescription);\n\n        return description;\n    }\n    else\n    {\n        return NULL;\n    }\n}\n\nBOOLEAN PhGetServiceDelayedAutoStart(\n    _In_ SC_HANDLE ServiceHandle,\n    _Out_ PBOOLEAN DelayedAutoStart\n    )\n{\n    SERVICE_DELAYED_AUTO_START_INFO delayedAutoStartInfo;\n    ULONG returnLength;\n\n    if (QueryServiceConfig2(\n        ServiceHandle,\n        SERVICE_CONFIG_DELAYED_AUTO_START_INFO,\n        (BYTE *)&delayedAutoStartInfo,\n        sizeof(SERVICE_DELAYED_AUTO_START_INFO),\n        &returnLength\n        ))\n    {\n        *DelayedAutoStart = !!delayedAutoStartInfo.fDelayedAutostart;\n        return TRUE;\n    }\n    else\n    {\n        return FALSE;\n    }\n}\n\nBOOLEAN PhSetServiceDelayedAutoStart(\n    _In_ SC_HANDLE ServiceHandle,\n    _In_ BOOLEAN DelayedAutoStart\n    )\n{\n    SERVICE_DELAYED_AUTO_START_INFO delayedAutoStartInfo;\n\n    delayedAutoStartInfo.fDelayedAutostart = DelayedAutoStart;\n\n    return !!ChangeServiceConfig2(\n        ServiceHandle,\n        SERVICE_CONFIG_DELAYED_AUTO_START_INFO,\n        &delayedAutoStartInfo\n        );\n}\n\nPWSTR PhGetServiceStateString(\n    _In_ ULONG ServiceState\n    )\n{\n    PWSTR string;\n\n    if (PhFindStringSiKeyValuePairs(\n        PhpServiceStatePairs,\n        sizeof(PhpServiceStatePairs),\n        ServiceState,\n        &string\n        ))\n        return string;\n    else\n        return L\"Unknown\";\n}\n\nPWSTR PhGetServiceTypeString(\n    _In_ ULONG ServiceType\n    )\n{\n    PWSTR string;\n\n    if (PhFindStringSiKeyValuePairs(\n        PhpServiceTypePairs,\n        sizeof(PhpServiceTypePairs),\n        ServiceType,\n        &string\n        ))\n        return string;\n    else\n        return L\"Unknown\";\n}\n\nULONG PhGetServiceTypeInteger(\n    _In_ PWSTR ServiceType\n    )\n{\n    ULONG integer;\n\n    if (PhFindIntegerSiKeyValuePairs(\n        PhpServiceTypePairs,\n        sizeof(PhpServiceTypePairs),\n        ServiceType,\n        &integer\n        ))\n        return integer;\n    else\n        return -1;\n}\n\nPWSTR PhGetServiceStartTypeString(\n    _In_ ULONG ServiceStartType\n    )\n{\n    PWSTR string;\n\n    if (PhFindStringSiKeyValuePairs(\n        PhpServiceStartTypePairs,\n        sizeof(PhpServiceStartTypePairs),\n        ServiceStartType,\n        &string\n        ))\n        return string;\n    else\n        return L\"Unknown\";\n}\n\nULONG PhGetServiceStartTypeInteger(\n    _In_ PWSTR ServiceStartType\n    )\n{\n    ULONG integer;\n\n    if (PhFindIntegerSiKeyValuePairs(\n        PhpServiceStartTypePairs,\n        sizeof(PhpServiceStartTypePairs),\n        ServiceStartType,\n        &integer\n        ))\n        return integer;\n    else\n        return -1;\n}\n\nPWSTR PhGetServiceErrorControlString(\n    _In_ ULONG ServiceErrorControl\n    )\n{\n    PWSTR string;\n\n    if (PhFindStringSiKeyValuePairs(\n        PhpServiceErrorControlPairs,\n        sizeof(PhpServiceErrorControlPairs),\n        ServiceErrorControl,\n        &string\n        ))\n        return string;\n    else\n        return L\"Unknown\";\n}\n\nULONG PhGetServiceErrorControlInteger(\n    _In_ PWSTR ServiceErrorControl\n    )\n{\n    ULONG integer;\n\n    if (PhFindIntegerSiKeyValuePairs(\n        PhpServiceErrorControlPairs,\n        sizeof(PhpServiceErrorControlPairs),\n        ServiceErrorControl,\n        &integer\n        ))\n        return integer;\n    else\n        return -1;\n}\n\nPPH_STRING PhGetServiceNameFromTag(\n    _In_ HANDLE ProcessId,\n    _In_ PVOID ServiceTag\n    )\n{\n    static PQUERY_TAG_INFORMATION I_QueryTagInformation = NULL;\n    PPH_STRING serviceName = NULL;\n    TAG_INFO_NAME_FROM_TAG nameFromTag;\n\n    if (!I_QueryTagInformation)\n    {\n        I_QueryTagInformation = PhGetModuleProcAddress(L\"advapi32.dll\", \"I_QueryTagInformation\");\n\n        if (!I_QueryTagInformation)\n            return NULL;\n    }\n\n    memset(&nameFromTag, 0, sizeof(TAG_INFO_NAME_FROM_TAG));\n    nameFromTag.InParams.dwPid = HandleToUlong(ProcessId);\n    nameFromTag.InParams.dwTag = PtrToUlong(ServiceTag);\n\n    I_QueryTagInformation(NULL, eTagInfoLevelNameFromTag, &nameFromTag);\n\n    if (nameFromTag.OutParams.pszName)\n    {\n        serviceName = PhCreateString(nameFromTag.OutParams.pszName);\n        LocalFree(nameFromTag.OutParams.pszName);\n    }\n\n    return serviceName;\n}\n\nPPH_STRING PhGetServiceNameForModuleReference(\n    _In_ HANDLE ProcessId,\n    _In_ PWSTR ModuleName\n    )\n{\n    static PQUERY_TAG_INFORMATION I_QueryTagInformation = NULL;\n    PPH_STRING serviceNames = NULL;\n    TAG_INFO_NAMES_REFERENCING_MODULE moduleNameRef;\n\n    if (!I_QueryTagInformation)\n    {\n        I_QueryTagInformation = PhGetModuleProcAddress(L\"advapi32.dll\", \"I_QueryTagInformation\");\n\n        if (!I_QueryTagInformation)\n            return NULL;\n    }\n\n    memset(&moduleNameRef, 0, sizeof(TAG_INFO_NAMES_REFERENCING_MODULE));\n    moduleNameRef.InParams.dwPid = HandleToUlong(ProcessId);\n    moduleNameRef.InParams.pszModule = ModuleName;\n\n    I_QueryTagInformation(NULL, eTagInfoLevelNamesReferencingModule, &moduleNameRef);\n\n    if (moduleNameRef.OutParams.pmszNames)\n    {\n        PH_STRING_BUILDER sb;\n        PWSTR serviceName;\n\n        PhInitializeStringBuilder(&sb, 0x40);\n\n        for (serviceName = moduleNameRef.OutParams.pmszNames; *serviceName; serviceName += PhCountStringZ(serviceName) + 1)\n            PhAppendFormatStringBuilder(&sb, L\"%s, \", serviceName);\n\n        if (sb.String->Length != 0)\n            PhRemoveEndStringBuilder(&sb, 2);\n\n        serviceNames = PhFinalStringBuilderString(&sb);\n        LocalFree(moduleNameRef.OutParams.pmszNames);\n    }\n\n    return serviceNames;\n}\n\nNTSTATUS PhGetThreadServiceTag(\n    _In_ HANDLE ThreadHandle,\n    _In_opt_ HANDLE ProcessHandle,\n    _Out_ PVOID *ServiceTag\n    )\n{\n    NTSTATUS status;\n    THREAD_BASIC_INFORMATION basicInfo;\n    BOOLEAN openedProcessHandle = FALSE;\n\n    if (!NT_SUCCESS(status = PhGetThreadBasicInformation(ThreadHandle, &basicInfo)))\n        return status;\n\n    if (!ProcessHandle)\n    {\n        if (!NT_SUCCESS(status = PhOpenThreadProcess(\n            ThreadHandle,\n            PROCESS_VM_READ,\n            &ProcessHandle\n            )))\n            return status;\n\n        openedProcessHandle = TRUE;\n    }\n\n    status = NtReadVirtualMemory(\n        ProcessHandle,\n        PTR_ADD_OFFSET(basicInfo.TebBaseAddress, FIELD_OFFSET(TEB, SubProcessTag)),\n        ServiceTag,\n        sizeof(PVOID),\n        NULL\n        );\n\n    if (openedProcessHandle)\n        NtClose(ProcessHandle);\n\n    return status;\n}\n\nNTSTATUS PhGetServiceDllParameter(\n    _In_ PPH_STRINGREF ServiceName,\n    _Out_ PPH_STRING *ServiceDll\n    )\n{\n    static PH_STRINGREF servicesKeyName = PH_STRINGREF_INIT(L\"System\\\\CurrentControlSet\\\\Services\\\\\");\n    static PH_STRINGREF parameters = PH_STRINGREF_INIT(L\"\\\\Parameters\");\n\n    NTSTATUS status;\n    HANDLE keyHandle;\n    PPH_STRING keyName;\n\n    keyName = PhConcatStringRef3(&servicesKeyName, ServiceName, &parameters);\n\n    if (NT_SUCCESS(status = PhOpenKey(\n        &keyHandle,\n        KEY_READ,\n        PH_KEY_LOCAL_MACHINE,\n        &keyName->sr,\n        0\n        )))\n    {\n        PPH_STRING serviceDllString;\n\n        if (serviceDllString = PhQueryRegistryString(keyHandle, L\"ServiceDll\"))\n        {\n            PPH_STRING expandedString;\n\n            if (expandedString = PhExpandEnvironmentStrings(&serviceDllString->sr))\n            {\n                *ServiceDll = expandedString;\n                PhDereferenceObject(serviceDllString);\n            }\n            else\n            {\n                *ServiceDll = serviceDllString;\n            }\n        }\n        else\n        {\n            status = STATUS_NOT_FOUND;\n        }\n\n        NtClose(keyHandle);\n    }\n\n    PhDereferenceObject(keyName);\n\n    return status;\n}\n"
  },
  {
    "path": "third_party/phlib/symprv.c",
    "content": "/*\n * Process Hacker -\n *   symbol provider\n *\n * Copyright (C) 2010-2015 wj32\n *\n * This file is part of Process Hacker.\n *\n * Process Hacker is free software; you can redistribute it and/or modify\n * it under the terms of the GNU General Public License as published by\n * the Free Software Foundation, either version 3 of the License, or\n * (at your option) any later version.\n *\n * Process Hacker is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n * GNU General Public License for more details.\n *\n * You should have received a copy of the GNU General Public License\n * along with Process Hacker.  If not, see <http://www.gnu.org/licenses/>.\n */\n\n#include <ph.h>\n#include <symprv.h>\n\n#include <dbghelp.h>\n\n#include <fastlock.h>\n#include <kphuser.h>\n#include <workqueue.h>\n\n#include <symprvp.h>\n\ntypedef struct _PH_SYMBOL_MODULE\n{\n    LIST_ENTRY ListEntry;\n    PH_AVL_LINKS Links;\n    ULONG64 BaseAddress;\n    ULONG Size;\n    PPH_STRING FileName;\n    ULONG BaseNameIndex;\n} PH_SYMBOL_MODULE, *PPH_SYMBOL_MODULE;\n\nVOID NTAPI PhpSymbolProviderDeleteProcedure(\n    _In_ PVOID Object,\n    _In_ ULONG Flags\n    );\n\nVOID PhpRegisterSymbolProvider(\n    _In_opt_ PPH_SYMBOL_PROVIDER SymbolProvider\n    );\n\nVOID PhpFreeSymbolModule(\n    _In_ PPH_SYMBOL_MODULE SymbolModule\n    );\n\nLONG NTAPI PhpSymbolModuleCompareFunction(\n    _In_ PPH_AVL_LINKS Links1,\n    _In_ PPH_AVL_LINKS Links2\n    );\n\nPPH_OBJECT_TYPE PhSymbolProviderType;\n\nstatic PH_INITONCE PhSymInitOnce = PH_INITONCE_INIT;\nDECLSPEC_SELECTANY PH_CALLBACK_DECLARE(PhSymInitCallback);\n\nstatic HANDLE PhNextFakeHandle = (HANDLE)0;\nstatic PH_FAST_LOCK PhSymMutex = PH_FAST_LOCK_INIT;\n\n#define PH_LOCK_SYMBOLS() PhAcquireFastLockExclusive(&PhSymMutex)\n#define PH_UNLOCK_SYMBOLS() PhReleaseFastLockExclusive(&PhSymMutex)\n\n_SymInitialize SymInitialize_I;\n_SymCleanup SymCleanup_I;\n_SymEnumSymbols SymEnumSymbols_I;\n_SymEnumSymbolsW SymEnumSymbolsW_I;\n_SymFromAddr SymFromAddr_I;\n_SymFromAddrW SymFromAddrW_I;\n_SymFromName SymFromName_I;\n_SymFromNameW SymFromNameW_I;\n_SymGetLineFromAddr64 SymGetLineFromAddr64_I;\n_SymGetLineFromAddrW64 SymGetLineFromAddrW64_I;\n_SymLoadModule64 SymLoadModule64_I;\n_SymLoadModuleExW SymLoadModuleExW_I;\n_SymGetOptions SymGetOptions_I;\n_SymSetOptions SymSetOptions_I;\n_SymGetSearchPath SymGetSearchPath_I;\n_SymGetSearchPathW SymGetSearchPathW_I;\n_SymSetSearchPath SymSetSearchPath_I;\n_SymSetSearchPathW SymSetSearchPathW_I;\n_SymUnloadModule64 SymUnloadModule64_I;\n_SymFunctionTableAccess64 SymFunctionTableAccess64_I;\n_SymGetModuleBase64 SymGetModuleBase64_I;\n_SymRegisterCallbackW64 SymRegisterCallbackW64_I;\n_StackWalk64 StackWalk64_I;\n_MiniDumpWriteDump MiniDumpWriteDump_I;\n_SymbolServerGetOptions SymbolServerGetOptions;\n_SymbolServerSetOptions SymbolServerSetOptions;\n_UnDecorateSymbolName UnDecorateSymbolName_I;\n_UnDecorateSymbolNameW UnDecorateSymbolNameW_I;\n\nBOOLEAN PhSymbolProviderInitialization(\n    VOID\n    )\n{\n    PhSymbolProviderType = PhCreateObjectType(L\"SymbolProvider\", 0, PhpSymbolProviderDeleteProcedure);\n\n    return TRUE;\n}\n\nVOID PhSymbolProviderCompleteInitialization(\n    _In_opt_ PVOID DbgHelpBase\n    )\n{\n    PVOID dbghelpHandle;\n    PVOID symsrvHandle;\n\n    // The user should have loaded dbghelp.dll and symsrv.dll already. If not, it's not our problem.\n\n    // The Unicode versions aren't available in dbghelp.dll 5.1, so we fallback on the ANSI versions.\n\n    if (DbgHelpBase)\n        dbghelpHandle = DbgHelpBase;\n    else\n        dbghelpHandle = PhGetDllHandle(L\"dbghelp.dll\");\n\n    symsrvHandle = PhGetDllHandle(L\"symsrv.dll\");\n\n    SymInitialize_I = PhGetProcedureAddress(dbghelpHandle, \"SymInitialize\", 0);\n    SymCleanup_I = PhGetProcedureAddress(dbghelpHandle, \"SymCleanup\", 0);\n    if (!(SymEnumSymbolsW_I = PhGetProcedureAddress(dbghelpHandle, \"SymEnumSymbolsW\", 0)))\n        SymEnumSymbols_I = PhGetProcedureAddress(dbghelpHandle, \"SymEnumSymbols\", 0);\n    if (!(SymFromAddrW_I = PhGetProcedureAddress(dbghelpHandle, \"SymFromAddrW\", 0)))\n        SymFromAddr_I = PhGetProcedureAddress(dbghelpHandle, \"SymFromAddr\", 0);\n    if (!(SymFromNameW_I = PhGetProcedureAddress(dbghelpHandle, \"SymFromNameW\", 0)))\n        SymFromName_I = PhGetProcedureAddress(dbghelpHandle, \"SymFromName\", 0);\n    if (!(SymGetLineFromAddrW64_I = PhGetProcedureAddress(dbghelpHandle, \"SymGetLineFromAddrW64\", 0)))\n        SymGetLineFromAddr64_I = PhGetProcedureAddress(dbghelpHandle, \"SymGetLineFromAddr64\", 0);\n    if (!(SymLoadModuleExW_I = PhGetProcedureAddress(dbghelpHandle, \"SymLoadModuleExW\", 0)))\n        SymLoadModule64_I = PhGetProcedureAddress(dbghelpHandle, \"SymLoadModule64\", 0);\n    SymGetOptions_I = PhGetProcedureAddress(dbghelpHandle, \"SymGetOptions\", 0);\n    SymSetOptions_I = PhGetProcedureAddress(dbghelpHandle, \"SymSetOptions\", 0);\n    if (!(SymGetSearchPathW_I = PhGetProcedureAddress(dbghelpHandle, \"SymGetSearchPathW\", 0)))\n        SymGetSearchPath_I = PhGetProcedureAddress(dbghelpHandle, \"SymGetSearchPath\", 0);\n    if (!(SymSetSearchPathW_I = PhGetProcedureAddress(dbghelpHandle, \"SymSetSearchPathW\", 0)))\n        SymSetSearchPath_I = PhGetProcedureAddress(dbghelpHandle, \"SymSetSearchPath\", 0);\n    SymUnloadModule64_I = PhGetProcedureAddress(dbghelpHandle, \"SymUnloadModule64\", 0);\n    SymFunctionTableAccess64_I = PhGetProcedureAddress(dbghelpHandle, \"SymFunctionTableAccess64\", 0);\n    SymGetModuleBase64_I = PhGetProcedureAddress(dbghelpHandle, \"SymGetModuleBase64\", 0);\n    SymRegisterCallbackW64_I = PhGetProcedureAddress(dbghelpHandle, \"SymRegisterCallbackW64\", 0);\n    StackWalk64_I = PhGetProcedureAddress(dbghelpHandle, \"StackWalk64\", 0);\n    MiniDumpWriteDump_I = PhGetProcedureAddress(dbghelpHandle, \"MiniDumpWriteDump\", 0);\n    SymbolServerGetOptions = PhGetProcedureAddress(symsrvHandle, \"SymbolServerGetOptions\", 0);\n    SymbolServerSetOptions = PhGetProcedureAddress(symsrvHandle, \"SymbolServerSetOptions\", 0);\n    UnDecorateSymbolName_I = PhGetProcedureAddress(dbghelpHandle, \"UnDecorateSymbolName\", 0);\n    UnDecorateSymbolNameW_I = PhGetProcedureAddress(dbghelpHandle, \"UnDecorateSymbolNameW\", 0);\n\n    if (SymGetOptions_I && SymSetOptions_I)\n    {\n        SymSetOptions_I(\n            SymGetOptions_I() |\n            SYMOPT_AUTO_PUBLICS | SYMOPT_CASE_INSENSITIVE | SYMOPT_DEFERRED_LOADS |\n            SYMOPT_FAIL_CRITICAL_ERRORS | SYMOPT_INCLUDE_32BIT_MODULES |\n            SYMOPT_LOAD_LINES | SYMOPT_OMAP_FIND_NEAREST | SYMOPT_UNDNAME\n            );\n    }\n}\n\nPPH_SYMBOL_PROVIDER PhCreateSymbolProvider(\n    _In_opt_ HANDLE ProcessId\n    )\n{\n    PPH_SYMBOL_PROVIDER symbolProvider;\n\n    symbolProvider = PhCreateObject(sizeof(PH_SYMBOL_PROVIDER), PhSymbolProviderType);\n    memset(symbolProvider, 0, sizeof(PH_SYMBOL_PROVIDER));\n    InitializeListHead(&symbolProvider->ModulesListHead);\n    PhInitializeQueuedLock(&symbolProvider->ModulesListLock);\n    PhInitializeAvlTree(&symbolProvider->ModulesSet, PhpSymbolModuleCompareFunction);\n    PhInitializeCallback(&symbolProvider->EventCallback);\n    PhInitializeInitOnce(&symbolProvider->InitOnce);\n\n    if (ProcessId)\n    {\n        static ACCESS_MASK accesses[] =\n        {\n            STANDARD_RIGHTS_REQUIRED | SYNCHRONIZE | 0xfff, // pre-Vista full access\n            PROCESS_QUERY_INFORMATION | PROCESS_VM_READ | PROCESS_DUP_HANDLE,\n            PROCESS_QUERY_INFORMATION | PROCESS_VM_READ,\n            MAXIMUM_ALLOWED\n        };\n\n        ULONG i;\n\n        // Try to open the process with many different accesses.\n        // This handle will be re-used when walking stacks, and doing various other things.\n        for (i = 0; i < sizeof(accesses) / sizeof(ACCESS_MASK); i++)\n        {\n            if (NT_SUCCESS(PhOpenProcess(&symbolProvider->ProcessHandle, accesses[i], ProcessId)))\n            {\n                symbolProvider->IsRealHandle = TRUE;\n                break;\n            }\n        }\n    }\n\n    if (!symbolProvider->IsRealHandle)\n    {\n        HANDLE fakeHandle;\n\n        // Just generate a fake handle.\n        fakeHandle = (HANDLE)_InterlockedExchangeAddPointer((PLONG_PTR)&PhNextFakeHandle, 4);\n        // Add one to make sure it isn't divisible by 4 (so it can't be mistaken for a real handle).\n        symbolProvider->ProcessHandle = (HANDLE)((ULONG_PTR)fakeHandle + 1);\n    }\n\n    return symbolProvider;\n}\n\nVOID NTAPI PhpSymbolProviderDeleteProcedure(\n    _In_ PVOID Object,\n    _In_ ULONG Flags\n    )\n{\n    PPH_SYMBOL_PROVIDER symbolProvider = (PPH_SYMBOL_PROVIDER)Object;\n    PLIST_ENTRY listEntry;\n\n    PhDeleteCallback(&symbolProvider->EventCallback);\n\n    if (SymCleanup_I)\n    {\n        PH_LOCK_SYMBOLS();\n\n        if (symbolProvider->IsRegistered)\n            SymCleanup_I(symbolProvider->ProcessHandle);\n\n        PH_UNLOCK_SYMBOLS();\n    }\n\n    listEntry = symbolProvider->ModulesListHead.Flink;\n\n    while (listEntry != &symbolProvider->ModulesListHead)\n    {\n        PPH_SYMBOL_MODULE module;\n\n        module = CONTAINING_RECORD(listEntry, PH_SYMBOL_MODULE, ListEntry);\n        listEntry = listEntry->Flink;\n\n        PhpFreeSymbolModule(module);\n    }\n\n    if (symbolProvider->IsRealHandle) NtClose(symbolProvider->ProcessHandle);\n}\n\nNTSTATUS PhpSymbolCallbackWorker(\n    _In_ PVOID Parameter\n    )\n{\n    PPH_SYMBOL_EVENT_DATA data = Parameter;\n\n    dprintf(\"symbol event %d: %S\\n\", data->Type, data->FileName->Buffer);\n    PhInvokeCallback(&data->SymbolProvider->EventCallback, data);\n    PhClearReference(&data->FileName);\n    PhDereferenceObject(data);\n\n    return STATUS_SUCCESS;\n}\n\nBOOL CALLBACK PhpSymbolCallbackFunction(\n    _In_ HANDLE hProcess,\n    _In_ ULONG ActionCode,\n    _In_opt_ ULONG64 CallbackData,\n    _In_opt_ ULONG64 UserContext\n    )\n{\n    PPH_SYMBOL_PROVIDER symbolProvider = (PPH_SYMBOL_PROVIDER)UserContext;\n    PPH_SYMBOL_EVENT_DATA data;\n    PIMAGEHLP_DEFERRED_SYMBOL_LOADW64 callbackData;\n\n    if (!IsListEmpty(&symbolProvider->EventCallback.ListHead))\n    {\n        switch (ActionCode)\n        {\n        case SymbolDeferredSymbolLoadStart:\n        case SymbolDeferredSymbolLoadComplete:\n        case SymbolDeferredSymbolLoadFailure:\n        case SymbolSymbolsUnloaded:\n        case SymbolDeferredSymbolLoadCancel:\n            data = PhCreateAlloc(sizeof(PH_SYMBOL_EVENT_DATA));\n            memset(data, 0, sizeof(PH_SYMBOL_EVENT_DATA));\n            data->SymbolProvider = symbolProvider;\n            data->Type = ActionCode;\n\n            if (ActionCode != SymbolSymbolsUnloaded)\n            {\n                callbackData = (PIMAGEHLP_DEFERRED_SYMBOL_LOADW64)CallbackData;\n                data->BaseAddress = callbackData->BaseOfImage;\n                data->CheckSum = callbackData->CheckSum;\n                data->TimeStamp = callbackData->TimeDateStamp;\n                data->FileName = PhCreateString(callbackData->FileName);\n            }\n\n            PhQueueItemWorkQueue(PhGetGlobalWorkQueue(), PhpSymbolCallbackWorker, data);\n\n            break;\n        }\n    }\n\n    return FALSE;\n}\n\nVOID PhpRegisterSymbolProvider(\n    _In_opt_ PPH_SYMBOL_PROVIDER SymbolProvider\n    )\n{\n    if (PhBeginInitOnce(&PhSymInitOnce))\n    {\n        PhInvokeCallback(&PhSymInitCallback, NULL);\n        PhEndInitOnce(&PhSymInitOnce);\n    }\n\n    if (!SymbolProvider)\n        return;\n\n    if (PhBeginInitOnce(&SymbolProvider->InitOnce))\n    {\n        if (SymInitialize_I)\n        {\n            PH_LOCK_SYMBOLS();\n\n            SymInitialize_I(SymbolProvider->ProcessHandle, NULL, FALSE);\n\n            if (SymRegisterCallbackW64_I)\n                SymRegisterCallbackW64_I(SymbolProvider->ProcessHandle, PhpSymbolCallbackFunction, (ULONG64)SymbolProvider);\n\n            PH_UNLOCK_SYMBOLS();\n\n            SymbolProvider->IsRegistered = TRUE;\n        }\n\n        PhEndInitOnce(&SymbolProvider->InitOnce);\n    }\n}\n\nVOID PhpFreeSymbolModule(\n    _In_ PPH_SYMBOL_MODULE SymbolModule\n    )\n{\n    if (SymbolModule->FileName) PhDereferenceObject(SymbolModule->FileName);\n\n    PhFree(SymbolModule);\n}\n\nstatic LONG NTAPI PhpSymbolModuleCompareFunction(\n    _In_ PPH_AVL_LINKS Links1,\n    _In_ PPH_AVL_LINKS Links2\n    )\n{\n    PPH_SYMBOL_MODULE symbolModule1 = CONTAINING_RECORD(Links1, PH_SYMBOL_MODULE, Links);\n    PPH_SYMBOL_MODULE symbolModule2 = CONTAINING_RECORD(Links2, PH_SYMBOL_MODULE, Links);\n\n    return uint64cmp(symbolModule1->BaseAddress, symbolModule2->BaseAddress);\n}\n\nBOOLEAN PhGetLineFromAddress(\n    _In_ PPH_SYMBOL_PROVIDER SymbolProvider,\n    _In_ ULONG64 Address,\n    _Out_ PPH_STRING *FileName,\n    _Out_opt_ PULONG Displacement,\n    _Out_opt_ PPH_SYMBOL_LINE_INFORMATION Information\n    )\n{\n    IMAGEHLP_LINEW64 line;\n    BOOL result;\n    ULONG displacement;\n    PPH_STRING fileName;\n\n    PhpRegisterSymbolProvider(SymbolProvider);\n\n    if (!SymGetLineFromAddrW64_I && !SymGetLineFromAddr64_I)\n        return FALSE;\n\n    line.SizeOfStruct = sizeof(IMAGEHLP_LINEW64);\n\n    PH_LOCK_SYMBOLS();\n\n    if (SymGetLineFromAddrW64_I)\n    {\n        result = SymGetLineFromAddrW64_I(\n            SymbolProvider->ProcessHandle,\n            Address,\n            &displacement,\n            &line\n            );\n\n        if (result)\n            fileName = PhCreateString(line.FileName);\n    }\n    else\n    {\n        IMAGEHLP_LINE64 lineA;\n\n        lineA.SizeOfStruct = sizeof(IMAGEHLP_LINE64);\n\n        result = SymGetLineFromAddr64_I(\n            SymbolProvider->ProcessHandle,\n            Address,\n            &displacement,\n            &lineA\n            );\n\n        if (result)\n        {\n            fileName = PhConvertMultiByteToUtf16(lineA.FileName);\n            line.LineNumber = lineA.LineNumber;\n            line.Address = lineA.Address;\n        }\n    }\n\n    PH_UNLOCK_SYMBOLS();\n\n    if (!result)\n        return FALSE;\n\n    *FileName = fileName;\n\n    if (Displacement)\n        *Displacement = displacement;\n\n    if (Information)\n    {\n        Information->LineNumber = line.LineNumber;\n        Information->Address = line.Address;\n    }\n\n    return TRUE;\n}\n\nULONG64 PhGetModuleFromAddress(\n    _In_ PPH_SYMBOL_PROVIDER SymbolProvider,\n    _In_ ULONG64 Address,\n    _Out_opt_ PPH_STRING *FileName\n    )\n{\n    PH_SYMBOL_MODULE lookupModule;\n    PPH_AVL_LINKS links;\n    PPH_SYMBOL_MODULE module;\n    PPH_STRING foundFileName;\n    ULONG64 foundBaseAddress;\n\n    foundFileName = NULL;\n    foundBaseAddress = 0;\n\n    PhAcquireQueuedLockShared(&SymbolProvider->ModulesListLock);\n\n    // Do an approximate search on the modules set to locate the module with the largest\n    // base address that is still smaller than the given address.\n    lookupModule.BaseAddress = Address;\n    links = PhUpperDualBoundElementAvlTree(&SymbolProvider->ModulesSet, &lookupModule.Links);\n\n    if (links)\n    {\n        module = CONTAINING_RECORD(links, PH_SYMBOL_MODULE, Links);\n\n        if (Address < module->BaseAddress + module->Size)\n        {\n            PhSetReference(&foundFileName, module->FileName);\n            foundBaseAddress = module->BaseAddress;\n        }\n    }\n\n    PhReleaseQueuedLockShared(&SymbolProvider->ModulesListLock);\n\n    if (foundFileName)\n    {\n        if (FileName)\n        {\n            *FileName = foundFileName;\n        }\n        else\n        {\n            PhDereferenceObject(foundFileName);\n        }\n    }\n\n    return foundBaseAddress;\n}\n\nVOID PhpSymbolInfoAnsiToUnicode(\n    _Out_ PSYMBOL_INFOW SymbolInfoW,\n    _In_ PSYMBOL_INFO SymbolInfoA\n    )\n{\n    SymbolInfoW->TypeIndex = SymbolInfoA->TypeIndex;\n    SymbolInfoW->Index = SymbolInfoA->Index;\n    SymbolInfoW->Size = SymbolInfoA->Size;\n    SymbolInfoW->ModBase = SymbolInfoA->ModBase;\n    SymbolInfoW->Flags = SymbolInfoA->Flags;\n    SymbolInfoW->Value = SymbolInfoA->Value;\n    SymbolInfoW->Address = SymbolInfoA->Address;\n    SymbolInfoW->Register = SymbolInfoA->Register;\n    SymbolInfoW->Scope = SymbolInfoA->Scope;\n    SymbolInfoW->Tag = SymbolInfoA->Tag;\n    SymbolInfoW->NameLen = 0;\n\n    if (SymbolInfoA->NameLen != 0 && SymbolInfoW->MaxNameLen != 0)\n    {\n        ULONG copyCount;\n\n        copyCount = min(SymbolInfoA->NameLen, SymbolInfoW->MaxNameLen - 1);\n\n        if (PhCopyStringZFromMultiByte(\n            SymbolInfoA->Name,\n            copyCount,\n            SymbolInfoW->Name,\n            SymbolInfoW->MaxNameLen,\n            NULL\n            ))\n        {\n            SymbolInfoW->NameLen = copyCount;\n        }\n    }\n}\n\nPPH_STRING PhGetSymbolFromAddress(\n    _In_ PPH_SYMBOL_PROVIDER SymbolProvider,\n    _In_ ULONG64 Address,\n    _Out_opt_ PPH_SYMBOL_RESOLVE_LEVEL ResolveLevel,\n    _Out_opt_ PPH_STRING *FileName,\n    _Out_opt_ PPH_STRING *SymbolName,\n    _Out_opt_ PULONG64 Displacement\n    )\n{\n    PSYMBOL_INFOW symbolInfo;\n    ULONG nameLength;\n    PPH_STRING symbol = NULL;\n    PH_SYMBOL_RESOLVE_LEVEL resolveLevel;\n    ULONG64 displacement;\n    PPH_STRING modFileName = NULL;\n    PPH_STRING modBaseName = NULL;\n    ULONG64 modBase;\n    PPH_STRING symbolName = NULL;\n\n    if (Address == 0)\n    {\n        if (ResolveLevel) *ResolveLevel = PhsrlInvalid;\n        if (FileName) *FileName = NULL;\n        if (SymbolName) *SymbolName = NULL;\n        if (Displacement) *Displacement = 0;\n\n        return NULL;\n    }\n\n    PhpRegisterSymbolProvider(SymbolProvider);\n\n    if (!SymFromAddrW_I && !SymFromAddr_I)\n        return NULL;\n\n    symbolInfo = PhAllocate(FIELD_OFFSET(SYMBOL_INFOW, Name) + PH_MAX_SYMBOL_NAME_LEN * 2);\n    memset(symbolInfo, 0, sizeof(SYMBOL_INFOW));\n    symbolInfo->SizeOfStruct = sizeof(SYMBOL_INFOW);\n    symbolInfo->MaxNameLen = PH_MAX_SYMBOL_NAME_LEN;\n\n    // Get the symbol name.\n\n    PH_LOCK_SYMBOLS();\n\n    // Note that we don't care whether this call succeeds or not, based on the assumption that it\n    // will not write to the symbolInfo structure if it fails. We've already zeroed the structure,\n    // so we can deal with it.\n\n    if (SymFromAddrW_I)\n    {\n        SymFromAddrW_I(\n            SymbolProvider->ProcessHandle,\n            Address,\n            &displacement,\n            symbolInfo\n            );\n        nameLength = symbolInfo->NameLen;\n\n        if (nameLength + 1 > PH_MAX_SYMBOL_NAME_LEN)\n        {\n            PhFree(symbolInfo);\n            symbolInfo = PhAllocate(FIELD_OFFSET(SYMBOL_INFOW, Name) + nameLength * 2 + 2);\n            memset(symbolInfo, 0, sizeof(SYMBOL_INFOW));\n            symbolInfo->SizeOfStruct = sizeof(SYMBOL_INFOW);\n            symbolInfo->MaxNameLen = nameLength + 1;\n\n            SymFromAddrW_I(\n                SymbolProvider->ProcessHandle,\n                Address,\n                &displacement,\n                symbolInfo\n                );\n        }\n    }\n    else if (SymFromAddr_I)\n    {\n        PSYMBOL_INFO symbolInfoA;\n\n        symbolInfoA = PhAllocate(FIELD_OFFSET(SYMBOL_INFO, Name) + PH_MAX_SYMBOL_NAME_LEN);\n        memset(symbolInfoA, 0, sizeof(SYMBOL_INFO));\n        symbolInfoA->SizeOfStruct = sizeof(SYMBOL_INFO);\n        symbolInfoA->MaxNameLen = PH_MAX_SYMBOL_NAME_LEN;\n\n        SymFromAddr_I(\n            SymbolProvider->ProcessHandle,\n            Address,\n            &displacement,\n            symbolInfoA\n            );\n        nameLength = symbolInfoA->NameLen;\n\n        if (nameLength + 1 > PH_MAX_SYMBOL_NAME_LEN)\n        {\n            PhFree(symbolInfoA);\n            symbolInfoA = PhAllocate(FIELD_OFFSET(SYMBOL_INFO, Name) + nameLength + 1);\n            memset(symbolInfoA, 0, sizeof(SYMBOL_INFO));\n            symbolInfoA->SizeOfStruct = sizeof(SYMBOL_INFO);\n            symbolInfoA->MaxNameLen = nameLength + 1;\n\n            SymFromAddr_I(\n                SymbolProvider->ProcessHandle,\n                Address,\n                &displacement,\n                symbolInfoA\n                );\n\n            // Also reallocate the Unicode-based buffer.\n            PhFree(symbolInfo);\n            symbolInfo = PhAllocate(FIELD_OFFSET(SYMBOL_INFOW, Name) + nameLength * 2 + 2);\n            memset(symbolInfo, 0, sizeof(SYMBOL_INFOW));\n            symbolInfo->SizeOfStruct = sizeof(SYMBOL_INFOW);\n            symbolInfo->MaxNameLen = nameLength + 1;\n        }\n\n        PhpSymbolInfoAnsiToUnicode(symbolInfo, symbolInfoA);\n        PhFree(symbolInfoA);\n    }\n\n    PH_UNLOCK_SYMBOLS();\n\n    // Find the module name.\n\n    if (symbolInfo->ModBase == 0)\n    {\n        modBase = PhGetModuleFromAddress(\n            SymbolProvider,\n            Address,\n            &modFileName\n            );\n    }\n    else\n    {\n        PH_SYMBOL_MODULE lookupSymbolModule;\n        PPH_AVL_LINKS existingLinks;\n        PPH_SYMBOL_MODULE symbolModule;\n\n        lookupSymbolModule.BaseAddress = symbolInfo->ModBase;\n\n        PhAcquireQueuedLockShared(&SymbolProvider->ModulesListLock);\n\n        existingLinks = PhFindElementAvlTree(&SymbolProvider->ModulesSet, &lookupSymbolModule.Links);\n\n        if (existingLinks)\n        {\n            symbolModule = CONTAINING_RECORD(existingLinks, PH_SYMBOL_MODULE, Links);\n            PhSetReference(&modFileName, symbolModule->FileName);\n        }\n\n        PhReleaseQueuedLockShared(&SymbolProvider->ModulesListLock);\n    }\n\n    // If we don't have a module name, return an address.\n    if (!modFileName)\n    {\n        resolveLevel = PhsrlAddress;\n        symbol = PhCreateStringEx(NULL, PH_PTR_STR_LEN * 2);\n        PhPrintPointer(symbol->Buffer, (PVOID)Address);\n        PhTrimToNullTerminatorString(symbol);\n\n        goto CleanupExit;\n    }\n\n    modBaseName = PhGetBaseName(modFileName);\n\n    // If we have a module name but not a symbol name, return the module plus an offset:\n    // module+offset.\n\n    if (symbolInfo->NameLen == 0)\n    {\n        PH_FORMAT format[3];\n\n        resolveLevel = PhsrlModule;\n\n        PhInitFormatSR(&format[0], modBaseName->sr);\n        PhInitFormatS(&format[1], L\"+0x\");\n        PhInitFormatIX(&format[2], (ULONG_PTR)(Address - modBase));\n        symbol = PhFormat(format, 3, modBaseName->Length + 6 + 32);\n\n        goto CleanupExit;\n    }\n\n    // If we have everything, return the full symbol name: module!symbol+offset.\n\n    symbolName = PhCreateStringEx(symbolInfo->Name, symbolInfo->NameLen * 2);\n    resolveLevel = PhsrlFunction;\n\n    if (displacement == 0)\n    {\n        PH_FORMAT format[3];\n\n        PhInitFormatSR(&format[0], modBaseName->sr);\n        PhInitFormatC(&format[1], '!');\n        PhInitFormatSR(&format[2], symbolName->sr);\n\n        symbol = PhFormat(format, 3, modBaseName->Length + 2 + symbolName->Length);\n    }\n    else\n    {\n        PH_FORMAT format[5];\n\n        PhInitFormatSR(&format[0], modBaseName->sr);\n        PhInitFormatC(&format[1], '!');\n        PhInitFormatSR(&format[2], symbolName->sr);\n        PhInitFormatS(&format[3], L\"+0x\");\n        PhInitFormatIX(&format[4], (ULONG_PTR)displacement);\n\n        symbol = PhFormat(format, 5, modBaseName->Length + 2 + symbolName->Length + 6 + 32);\n    }\n\nCleanupExit:\n\n    if (ResolveLevel)\n        *ResolveLevel = resolveLevel;\n    if (FileName)\n        PhSetReference(FileName, modFileName);\n    if (SymbolName)\n        PhSetReference(SymbolName, symbolName);\n    if (Displacement)\n        *Displacement = displacement;\n\n    PhClearReference(&modFileName);\n    PhClearReference(&modBaseName);\n    PhClearReference(&symbolName);\n    PhFree(symbolInfo);\n\n    return symbol;\n}\n\nBOOLEAN PhGetSymbolFromName(\n    _In_ PPH_SYMBOL_PROVIDER SymbolProvider,\n    _In_ PWSTR Name,\n    _Out_ PPH_SYMBOL_INFORMATION Information\n    )\n{\n    PSYMBOL_INFOW symbolInfo;\n    UCHAR symbolInfoBuffer[FIELD_OFFSET(SYMBOL_INFOW, Name) + PH_MAX_SYMBOL_NAME_LEN * 2];\n    BOOL result;\n\n    PhpRegisterSymbolProvider(SymbolProvider);\n\n    if (!SymFromNameW_I && !SymFromName_I)\n        return FALSE;\n\n    symbolInfo = (PSYMBOL_INFOW)symbolInfoBuffer;\n    memset(symbolInfo, 0, sizeof(SYMBOL_INFOW));\n    symbolInfo->SizeOfStruct = sizeof(SYMBOL_INFOW);\n    symbolInfo->MaxNameLen = PH_MAX_SYMBOL_NAME_LEN;\n\n    // Get the symbol information.\n\n    PH_LOCK_SYMBOLS();\n\n    if (SymFromNameW_I)\n    {\n        result = SymFromNameW_I(\n            SymbolProvider->ProcessHandle,\n            Name,\n            symbolInfo\n            );\n    }\n    else if (SymFromName_I)\n    {\n        UCHAR buffer[FIELD_OFFSET(SYMBOL_INFO, Name) + PH_MAX_SYMBOL_NAME_LEN];\n        PSYMBOL_INFO symbolInfoA;\n        PPH_BYTES name;\n\n        symbolInfoA = (PSYMBOL_INFO)buffer;\n        memset(symbolInfoA, 0, sizeof(SYMBOL_INFO));\n        symbolInfoA->SizeOfStruct = sizeof(SYMBOL_INFO);\n        symbolInfoA->MaxNameLen = PH_MAX_SYMBOL_NAME_LEN;\n\n        name = PhConvertUtf16ToMultiByte(Name);\n\n        if (result = SymFromName_I(\n            SymbolProvider->ProcessHandle,\n            name->Buffer,\n            symbolInfoA\n            ))\n        {\n            PhpSymbolInfoAnsiToUnicode(symbolInfo, symbolInfoA);\n        }\n\n        PhDereferenceObject(name);\n    }\n    else\n    {\n        result = FALSE;\n    }\n\n    PH_UNLOCK_SYMBOLS();\n\n    if (!result)\n        return FALSE;\n\n    Information->Address = symbolInfo->Address;\n    Information->ModuleBase = symbolInfo->ModBase;\n    Information->Index = symbolInfo->Index;\n    Information->Size = symbolInfo->Size;\n\n    return TRUE;\n}\n\nBOOLEAN PhLoadModuleSymbolProvider(\n    _In_ PPH_SYMBOL_PROVIDER SymbolProvider,\n    _In_ PWSTR FileName,\n    _In_ ULONG64 BaseAddress,\n    _In_ ULONG Size\n    )\n{\n    ULONG64 baseAddress;\n    PPH_SYMBOL_MODULE symbolModule = NULL;\n    PPH_AVL_LINKS existingLinks;\n    PH_SYMBOL_MODULE lookupSymbolModule;\n\n    PhpRegisterSymbolProvider(SymbolProvider);\n\n    if (!SymLoadModuleExW_I && !SymLoadModule64_I)\n        return FALSE;\n\n    // Check for duplicates. It is better to do this before calling SymLoadModuleExW, because it\n    // seems to force symbol loading when it is called twice on the same module even if deferred\n    // loading is enabled.\n    PhAcquireQueuedLockExclusive(&SymbolProvider->ModulesListLock);\n    lookupSymbolModule.BaseAddress = BaseAddress;\n    existingLinks = PhFindElementAvlTree(&SymbolProvider->ModulesSet, &lookupSymbolModule.Links);\n    PhReleaseQueuedLockExclusive(&SymbolProvider->ModulesListLock);\n\n    if (existingLinks)\n        return TRUE;\n\n    PH_LOCK_SYMBOLS();\n\n    if (SymLoadModuleExW_I)\n    {\n        baseAddress = SymLoadModuleExW_I(\n            SymbolProvider->ProcessHandle,\n            NULL,\n            FileName,\n            NULL,\n            BaseAddress,\n            Size,\n            NULL,\n            0\n            );\n    }\n    else\n    {\n        PPH_BYTES fileName;\n\n        fileName = PhConvertUtf16ToMultiByte(FileName);\n        baseAddress = SymLoadModule64_I(\n            SymbolProvider->ProcessHandle,\n            NULL,\n            fileName->Buffer,\n            NULL,\n            BaseAddress,\n            Size\n            );\n        PhDereferenceObject(fileName);\n    }\n\n    PH_UNLOCK_SYMBOLS();\n\n    // Add the module to the list, even if we couldn't load symbols for the module.\n\n    PhAcquireQueuedLockExclusive(&SymbolProvider->ModulesListLock);\n\n    // Check for duplicates again.\n    lookupSymbolModule.BaseAddress = BaseAddress;\n    existingLinks = PhFindElementAvlTree(&SymbolProvider->ModulesSet, &lookupSymbolModule.Links);\n\n    if (!existingLinks)\n    {\n        symbolModule = PhAllocate(sizeof(PH_SYMBOL_MODULE));\n        symbolModule->BaseAddress = BaseAddress;\n        symbolModule->Size = Size;\n        symbolModule->FileName = PhGetFullPath(FileName, &symbolModule->BaseNameIndex);\n\n        existingLinks = PhAddElementAvlTree(&SymbolProvider->ModulesSet, &symbolModule->Links);\n        assert(!existingLinks);\n        InsertTailList(&SymbolProvider->ModulesListHead, &symbolModule->ListEntry);\n    }\n\n    PhReleaseQueuedLockExclusive(&SymbolProvider->ModulesListLock);\n\n    if (!baseAddress)\n    {\n        if (GetLastError() != ERROR_SUCCESS)\n            return FALSE;\n        else\n            return TRUE;\n    }\n\n    return TRUE;\n}\n\nVOID PhSetOptionsSymbolProvider(\n    _In_ ULONG Mask,\n    _In_ ULONG Value\n    )\n{\n    ULONG options;\n\n    PhpRegisterSymbolProvider(NULL);\n\n    if (!SymGetOptions_I || !SymSetOptions_I)\n        return;\n\n    PH_LOCK_SYMBOLS();\n\n    options = SymGetOptions_I();\n    options &= ~Mask;\n    options |= Value;\n    SymSetOptions_I(options);\n\n    PH_UNLOCK_SYMBOLS();\n}\n\nVOID PhSetSearchPathSymbolProvider(\n    _In_ PPH_SYMBOL_PROVIDER SymbolProvider,\n    _In_ PWSTR Path\n    )\n{\n    PhpRegisterSymbolProvider(SymbolProvider);\n\n    if (!SymSetSearchPathW_I && !SymSetSearchPath_I)\n        return;\n\n    PH_LOCK_SYMBOLS();\n\n    if (SymSetSearchPathW_I)\n    {\n        SymSetSearchPathW_I(SymbolProvider->ProcessHandle, Path);\n    }\n    else if (SymSetSearchPath_I)\n    {\n        PPH_BYTES path;\n\n        path = PhConvertUtf16ToMultiByte(Path);\n        SymSetSearchPath_I(SymbolProvider->ProcessHandle, path->Buffer);\n        PhDereferenceObject(path);\n    }\n\n    PH_UNLOCK_SYMBOLS();\n}\n\n#ifdef _WIN64\n\nNTSTATUS PhpLookupDynamicFunctionTable(\n    _In_ HANDLE ProcessHandle,\n    _In_ ULONG64 Address,\n    _Out_opt_ PDYNAMIC_FUNCTION_TABLE *FunctionTableAddress,\n    _Out_opt_ PDYNAMIC_FUNCTION_TABLE FunctionTable,\n    _Out_writes_bytes_opt_(OutOfProcessCallbackDllBufferSize) PWCHAR OutOfProcessCallbackDllBuffer,\n    _In_ ULONG OutOfProcessCallbackDllBufferSize,\n    _Out_opt_ PUNICODE_STRING OutOfProcessCallbackDllString\n    )\n{\n    NTSTATUS status;\n    PLIST_ENTRY (NTAPI *rtlGetFunctionTableListHead)(VOID);\n    PLIST_ENTRY tableListHead;\n    LIST_ENTRY tableListHeadEntry;\n    PLIST_ENTRY tableListEntry;\n    PDYNAMIC_FUNCTION_TABLE functionTableAddress;\n    DYNAMIC_FUNCTION_TABLE functionTable;\n    ULONG count;\n    SIZE_T numberOfBytesRead;\n    ULONG i;\n    BOOLEAN foundNull;\n\n    rtlGetFunctionTableListHead = PhGetModuleProcAddress(L\"ntdll.dll\", \"RtlGetFunctionTableListHead\");\n\n    if (!rtlGetFunctionTableListHead)\n        return STATUS_PROCEDURE_NOT_FOUND;\n\n    tableListHead = rtlGetFunctionTableListHead();\n\n    // Find the function table entry for this address.\n\n    if (!NT_SUCCESS(status = NtReadVirtualMemory(\n        ProcessHandle,\n        tableListHead,\n        &tableListHeadEntry,\n        sizeof(LIST_ENTRY),\n        NULL\n        )))\n        return status;\n\n    tableListEntry = tableListHeadEntry.Flink;\n    count = 0; // make sure we can't be forced into an infinite loop by crafted data\n\n    while (tableListEntry != tableListHead && count < PH_ENUM_PROCESS_MODULES_LIMIT)\n    {\n        functionTableAddress = CONTAINING_RECORD(tableListEntry, DYNAMIC_FUNCTION_TABLE, ListEntry);\n\n        if (!NT_SUCCESS(status = NtReadVirtualMemory(\n            ProcessHandle,\n            functionTableAddress,\n            &functionTable,\n            sizeof(DYNAMIC_FUNCTION_TABLE),\n            NULL\n            )))\n            return status;\n\n        if (Address >= functionTable.MinimumAddress && Address < functionTable.MaximumAddress)\n        {\n            if (OutOfProcessCallbackDllBuffer)\n            {\n                if (functionTable.OutOfProcessCallbackDll)\n                {\n                    // Read the out-of-process callback DLL path. We don't have a length, so we'll\n                    // just have to read as much as possible.\n\n                    memset(OutOfProcessCallbackDllBuffer, 0xff, OutOfProcessCallbackDllBufferSize);\n                    status = NtReadVirtualMemory(\n                        ProcessHandle,\n                        functionTable.OutOfProcessCallbackDll,\n                        OutOfProcessCallbackDllBuffer,\n                        OutOfProcessCallbackDllBufferSize,\n                        &numberOfBytesRead\n                        );\n\n                    if (status != STATUS_PARTIAL_COPY && !NT_SUCCESS(status))\n                        return status;\n\n                    foundNull = FALSE;\n\n                    for (i = 0; i < OutOfProcessCallbackDllBufferSize / sizeof(WCHAR); i++)\n                    {\n                        if (OutOfProcessCallbackDllBuffer[i] == 0)\n                        {\n                            foundNull = TRUE;\n\n                            if (OutOfProcessCallbackDllString)\n                            {\n                                OutOfProcessCallbackDllString->Buffer = OutOfProcessCallbackDllBuffer;\n                                OutOfProcessCallbackDllString->Length = (USHORT)(i * sizeof(WCHAR));\n                                OutOfProcessCallbackDllString->MaximumLength = OutOfProcessCallbackDllString->Length;\n                            }\n\n                            break;\n                        }\n                    }\n\n                    // If there was no null terminator, then we didn't read the whole string in.\n                    // Fail the operation.\n                    if (!foundNull)\n                        return STATUS_BUFFER_OVERFLOW;\n                }\n                else\n                {\n                    OutOfProcessCallbackDllBuffer[0] = 0;\n\n                    if (OutOfProcessCallbackDllString)\n                    {\n                        OutOfProcessCallbackDllString->Buffer = NULL;\n                        OutOfProcessCallbackDllString->Length = 0;\n                        OutOfProcessCallbackDllString->MaximumLength = 0;\n                    }\n                }\n            }\n\n            if (FunctionTableAddress)\n                *FunctionTableAddress = functionTableAddress;\n\n            if (FunctionTable)\n                *FunctionTable = functionTable;\n\n            return STATUS_SUCCESS;\n        }\n\n        tableListEntry = functionTable.ListEntry.Flink;\n        count++;\n    }\n\n    return STATUS_NOT_FOUND;\n}\n\nPRUNTIME_FUNCTION PhpLookupFunctionEntry(\n    _In_ PRUNTIME_FUNCTION Functions,\n    _In_ ULONG NumberOfFunctions,\n    _In_ BOOLEAN Sorted,\n    _In_ ULONG64 RelativeControlPc\n    )\n{\n    LONG low;\n    LONG high;\n    ULONG i;\n\n    if (Sorted)\n    {\n        if (NumberOfFunctions == 0)\n            return NULL;\n\n        low = 0;\n        high = NumberOfFunctions - 1;\n\n        do\n        {\n            i = (low + high) / 2;\n\n            if (RelativeControlPc < Functions[i].BeginAddress)\n                high = i - 1;\n            else if (RelativeControlPc >= Functions[i].EndAddress)\n                low = i + 1;\n            else\n                return &Functions[i];\n        } while (low <= high);\n    }\n    else\n    {\n        for (i = 0; i < NumberOfFunctions; i++)\n        {\n            if (RelativeControlPc >= Functions[i].BeginAddress && RelativeControlPc < Functions[i].EndAddress)\n                return &Functions[i];\n        }\n    }\n\n    return NULL;\n}\n\nNTSTATUS PhpAccessCallbackFunctionTable(\n    _In_ HANDLE ProcessHandle,\n    _In_ PVOID FunctionTableAddress,\n    _In_ PUNICODE_STRING OutOfProcessCallbackDllString,\n    _Out_ PRUNTIME_FUNCTION *Functions,\n    _Out_ PULONG NumberOfFunctions\n    )\n{\n    static PH_STRINGREF knownFunctionTableDllsKeyName = PH_STRINGREF_INIT(L\"Software\\\\Microsoft\\\\Windows NT\\\\CurrentVersion\\\\KnownFunctionTableDlls\");\n\n    NTSTATUS status;\n    HANDLE keyHandle;\n    ULONG returnLength;\n    PVOID dllHandle;\n    ANSI_STRING outOfProcessFunctionTableCallbackName;\n    POUT_OF_PROCESS_FUNCTION_TABLE_CALLBACK outOfProcessFunctionTableCallback;\n\n    if (!OutOfProcessCallbackDllString->Buffer)\n        return STATUS_INVALID_PARAMETER;\n\n    // Don't load DLLs from arbitrary locations. Check if this is a known function table DLL.\n\n    if (!NT_SUCCESS(status = PhOpenKey(\n        &keyHandle,\n        KEY_READ,\n        PH_KEY_LOCAL_MACHINE,\n        &knownFunctionTableDllsKeyName,\n        0\n        )))\n        return status;\n\n    status = NtQueryValueKey(keyHandle, OutOfProcessCallbackDllString, KeyValuePartialInformation, NULL, 0, &returnLength);\n    NtClose(keyHandle);\n\n    if (status == STATUS_OBJECT_NAME_NOT_FOUND)\n        return STATUS_ACCESS_DISABLED_BY_POLICY_DEFAULT;\n\n    status = LdrLoadDll(NULL, NULL, OutOfProcessCallbackDllString, &dllHandle);\n\n    if (!NT_SUCCESS(status))\n        return status;\n\n    RtlInitAnsiString(&outOfProcessFunctionTableCallbackName, OUT_OF_PROCESS_FUNCTION_TABLE_CALLBACK_EXPORT_NAME);\n    status = LdrGetProcedureAddress(dllHandle, &outOfProcessFunctionTableCallbackName, 0, (PVOID *)&outOfProcessFunctionTableCallback);\n\n    if (NT_SUCCESS(status))\n    {\n        status = outOfProcessFunctionTableCallback(\n            ProcessHandle,\n            FunctionTableAddress,\n            NumberOfFunctions,\n            Functions\n            );\n    }\n\n    LdrUnloadDll(dllHandle);\n\n    return status;\n}\n\nNTSTATUS PhpAccessNormalFunctionTable(\n    _In_ HANDLE ProcessHandle,\n    _In_ PDYNAMIC_FUNCTION_TABLE FunctionTable,\n    _Out_ PRUNTIME_FUNCTION *Functions,\n    _Out_ PULONG NumberOfFunctions\n    )\n{\n    NTSTATUS status;\n    SIZE_T bufferSize;\n    PRUNTIME_FUNCTION functions;\n\n    // Put a reasonable limit on the number of entries we read.\n    if (FunctionTable->EntryCount > 0x100000)\n        return STATUS_BUFFER_OVERFLOW;\n\n    bufferSize = FunctionTable->EntryCount * sizeof(RUNTIME_FUNCTION);\n    functions = PhAllocatePage(bufferSize, NULL);\n\n    if (!functions)\n        return STATUS_NO_MEMORY;\n\n    status = NtReadVirtualMemory(ProcessHandle, FunctionTable->FunctionTable, functions, bufferSize, NULL);\n\n    if (NT_SUCCESS(status))\n    {\n        *Functions = functions;\n        *NumberOfFunctions = FunctionTable->EntryCount;\n    }\n    else\n    {\n        PhFreePage(functions);\n    }\n\n    return status;\n}\n\nNTSTATUS PhAccessOutOfProcessFunctionEntry(\n    _In_ HANDLE ProcessHandle,\n    _In_ ULONG64 ControlPc,\n    _Out_ PRUNTIME_FUNCTION Function\n    )\n{\n    NTSTATUS status;\n    PDYNAMIC_FUNCTION_TABLE functionTableAddress;\n    DYNAMIC_FUNCTION_TABLE functionTable;\n    WCHAR outOfProcessCallbackDll[512];\n    UNICODE_STRING outOfProcessCallbackDllString;\n    PRUNTIME_FUNCTION functions;\n    ULONG numberOfFunctions;\n    PRUNTIME_FUNCTION function;\n\n    if (!NT_SUCCESS(status = PhpLookupDynamicFunctionTable(\n        ProcessHandle,\n        ControlPc,\n        &functionTableAddress,\n        &functionTable,\n        outOfProcessCallbackDll,\n        sizeof(outOfProcessCallbackDll),\n        &outOfProcessCallbackDllString\n        )))\n    {\n        return status;\n    }\n\n    if (functionTable.Type == RF_CALLBACK)\n    {\n        if (!NT_SUCCESS(status = PhpAccessCallbackFunctionTable(\n            ProcessHandle,\n            functionTableAddress,\n            &outOfProcessCallbackDllString,\n            &functions,\n            &numberOfFunctions\n            )))\n        {\n            return status;\n        }\n\n        function = PhpLookupFunctionEntry(functions, numberOfFunctions, FALSE, ControlPc - functionTable.BaseAddress);\n\n        if (function)\n            *Function = *function;\n        else\n            status = STATUS_NOT_FOUND;\n\n        RtlFreeHeap(RtlProcessHeap(), 0, functions);\n    }\n    else\n    {\n        if (!NT_SUCCESS(status = PhpAccessNormalFunctionTable(\n            ProcessHandle,\n            &functionTable,\n            &functions,\n            &numberOfFunctions\n            )))\n        {\n            return status;\n        }\n\n        function = PhpLookupFunctionEntry(functions, numberOfFunctions, functionTable.Type == RF_SORTED, ControlPc - functionTable.BaseAddress);\n\n        if (function)\n            *Function = *function;\n        else\n            status = STATUS_NOT_FOUND;\n\n        PhFreePage(functions);\n    }\n\n    return status;\n}\n\n#endif\n\nULONG64 __stdcall PhGetModuleBase64(\n    _In_ HANDLE hProcess,\n    _In_ ULONG64 dwAddr\n    )\n{\n    ULONG64 base;\n#ifdef _WIN64\n    DYNAMIC_FUNCTION_TABLE functionTable;\n#endif\n\n#ifdef _WIN64\n    if (NT_SUCCESS(PhpLookupDynamicFunctionTable(\n        hProcess,\n        dwAddr,\n        NULL,\n        &functionTable,\n        NULL,\n        0,\n        NULL\n        )))\n    {\n        base = functionTable.BaseAddress;\n    }\n    else\n    {\n        base = 0;\n    }\n#else\n    base = 0;\n#endif\n\n    if (base == 0 && SymGetModuleBase64_I)\n        base = SymGetModuleBase64_I(hProcess, dwAddr);\n\n    return base;\n}\n\nPVOID __stdcall PhFunctionTableAccess64(\n    _In_ HANDLE hProcess,\n    _In_ ULONG64 AddrBase\n    )\n{\n#ifdef _WIN64\n    static RUNTIME_FUNCTION lastRuntimeFunction;\n#endif\n\n    PVOID entry;\n\n#ifdef _WIN64\n    if (NT_SUCCESS(PhAccessOutOfProcessFunctionEntry(hProcess, AddrBase, &lastRuntimeFunction)))\n        entry = &lastRuntimeFunction;\n    else\n        entry = NULL;\n#else\n    entry = NULL;\n#endif\n\n    if (!entry && SymFunctionTableAccess64_I)\n        entry = SymFunctionTableAccess64_I(hProcess, AddrBase);\n\n    return entry;\n}\n\nBOOLEAN PhStackWalk(\n    _In_ ULONG MachineType,\n    _In_ HANDLE ProcessHandle,\n    _In_ HANDLE ThreadHandle,\n    _Inout_ LPSTACKFRAME64 StackFrame,\n    _Inout_ PVOID ContextRecord,\n    _In_opt_ PPH_SYMBOL_PROVIDER SymbolProvider,\n    _In_opt_ PREAD_PROCESS_MEMORY_ROUTINE64 ReadMemoryRoutine,\n    _In_opt_ PFUNCTION_TABLE_ACCESS_ROUTINE64 FunctionTableAccessRoutine,\n    _In_opt_ PGET_MODULE_BASE_ROUTINE64 GetModuleBaseRoutine,\n    _In_opt_ PTRANSLATE_ADDRESS_ROUTINE64 TranslateAddress\n    )\n{\n    BOOLEAN result;\n\n    PhpRegisterSymbolProvider(SymbolProvider);\n\n    if (!StackWalk64_I)\n        return FALSE;\n\n    if (!FunctionTableAccessRoutine)\n    {\n        if (MachineType == IMAGE_FILE_MACHINE_AMD64)\n            FunctionTableAccessRoutine = PhFunctionTableAccess64;\n        else\n            FunctionTableAccessRoutine = SymFunctionTableAccess64_I;\n    }\n\n    if (!GetModuleBaseRoutine)\n    {\n        if (MachineType == IMAGE_FILE_MACHINE_AMD64)\n            GetModuleBaseRoutine = PhGetModuleBase64;\n        else\n            GetModuleBaseRoutine = SymGetModuleBase64_I;\n    }\n\n    PH_LOCK_SYMBOLS();\n    result = StackWalk64_I(\n        MachineType,\n        ProcessHandle,\n        ThreadHandle,\n        StackFrame,\n        ContextRecord,\n        ReadMemoryRoutine,\n        FunctionTableAccessRoutine,\n        GetModuleBaseRoutine,\n        TranslateAddress\n        );\n    PH_UNLOCK_SYMBOLS();\n\n    return result;\n}\n\nBOOLEAN PhWriteMiniDumpProcess(\n    _In_ HANDLE ProcessHandle,\n    _In_ HANDLE ProcessId,\n    _In_ HANDLE FileHandle,\n    _In_ MINIDUMP_TYPE DumpType,\n    _In_opt_ PMINIDUMP_EXCEPTION_INFORMATION ExceptionParam,\n    _In_opt_ PMINIDUMP_USER_STREAM_INFORMATION UserStreamParam,\n    _In_opt_ PMINIDUMP_CALLBACK_INFORMATION CallbackParam\n    )\n{\n    PhpRegisterSymbolProvider(NULL);\n\n    if (!MiniDumpWriteDump_I)\n    {\n        SetLastError(ERROR_PROC_NOT_FOUND);\n        return FALSE;\n    }\n\n    return MiniDumpWriteDump_I(\n        ProcessHandle,\n        HandleToUlong(ProcessId),\n        FileHandle,\n        DumpType,\n        ExceptionParam,\n        UserStreamParam,\n        CallbackParam\n        );\n}\n\n/**\n * Converts a STACKFRAME64 structure to a PH_THREAD_STACK_FRAME structure.\n *\n * \\param StackFrame64 A pointer to the STACKFRAME64 structure to convert.\n * \\param Flags Flags to set in the resulting structure.\n * \\param ThreadStackFrame A pointer to the resulting PH_THREAD_STACK_FRAME structure.\n */\nVOID PhpConvertStackFrame(\n    _In_ STACKFRAME64 *StackFrame64,\n    _In_ ULONG Flags,\n    _Out_ PPH_THREAD_STACK_FRAME ThreadStackFrame\n    )\n{\n    ULONG i;\n\n    ThreadStackFrame->PcAddress = (PVOID)StackFrame64->AddrPC.Offset;\n    ThreadStackFrame->ReturnAddress = (PVOID)StackFrame64->AddrReturn.Offset;\n    ThreadStackFrame->FrameAddress = (PVOID)StackFrame64->AddrFrame.Offset;\n    ThreadStackFrame->StackAddress = (PVOID)StackFrame64->AddrStack.Offset;\n    ThreadStackFrame->BStoreAddress = (PVOID)StackFrame64->AddrBStore.Offset;\n\n    for (i = 0; i < 4; i++)\n        ThreadStackFrame->Params[i] = (PVOID)StackFrame64->Params[i];\n\n    ThreadStackFrame->Flags = Flags;\n\n    if (StackFrame64->FuncTableEntry)\n        ThreadStackFrame->Flags |= PH_THREAD_STACK_FRAME_FPO_DATA_PRESENT;\n}\n\n/**\n * Walks a thread's stack.\n *\n * \\param ThreadHandle A handle to a thread. The handle must have THREAD_QUERY_LIMITED_INFORMATION,\n * THREAD_GET_CONTEXT and THREAD_SUSPEND_RESUME access. The handle can have any access for kernel\n * stack walking.\n * \\param ProcessHandle A handle to the thread's parent process. The handle must have\n * PROCESS_QUERY_INFORMATION and PROCESS_VM_READ access. If a symbol provider is being used, pass\n * its process handle and specify the symbol provider in \\a SymbolProvider.\n * \\param ClientId The client ID identifying the thread.\n * \\param SymbolProvider The associated symbol provider.\n * \\param Flags A combination of flags.\n * \\li \\c PH_WALK_I386_STACK Walks the x86 stack. On AMD64 systems this flag walks the WOW64 stack.\n * \\li \\c PH_WALK_AMD64_STACK Walks the AMD64 stack. On x86 systems this flag is ignored.\n * \\li \\c PH_WALK_KERNEL_STACK Walks the kernel stack. This flag is ignored if there is no active\n * KProcessHacker connection.\n * \\param Callback A callback function which is executed for each stack frame.\n * \\param Context A user-defined value to pass to the callback function.\n */\nNTSTATUS PhWalkThreadStack(\n    _In_ HANDLE ThreadHandle,\n    _In_opt_ HANDLE ProcessHandle,\n    _In_opt_ PCLIENT_ID ClientId,\n    _In_opt_ PPH_SYMBOL_PROVIDER SymbolProvider,\n    _In_ ULONG Flags,\n    _In_ PPH_WALK_THREAD_STACK_CALLBACK Callback,\n    _In_opt_ PVOID Context\n    )\n{\n    NTSTATUS status = STATUS_SUCCESS;\n    BOOLEAN suspended = FALSE;\n    BOOLEAN processOpened = FALSE;\n    BOOLEAN isCurrentThread = FALSE;\n    BOOLEAN isSystemThread = FALSE;\n    THREAD_BASIC_INFORMATION basicInfo;\n\n    // Open a handle to the process if we weren't given one.\n    if (!ProcessHandle)\n    {\n        if (KphIsConnected() || !ClientId)\n        {\n            if (!NT_SUCCESS(status = PhOpenThreadProcess(\n                ThreadHandle,\n                PROCESS_QUERY_INFORMATION | PROCESS_VM_READ,\n                &ProcessHandle\n                )))\n                return status;\n        }\n        else\n        {\n            if (!NT_SUCCESS(status = PhOpenProcess(\n                &ProcessHandle,\n                PROCESS_QUERY_INFORMATION | PROCESS_VM_READ,\n                ClientId->UniqueProcess\n                )))\n                return status;\n        }\n\n        processOpened = TRUE;\n    }\n\n    // Determine if the caller specified the current thread.\n    if (ClientId)\n    {\n        if (ClientId->UniqueThread == NtCurrentTeb()->ClientId.UniqueThread)\n            isCurrentThread = TRUE;\n        if (ClientId->UniqueProcess == SYSTEM_PROCESS_ID)\n            isSystemThread = TRUE;\n    }\n    else\n    {\n        if (ThreadHandle == NtCurrentThread())\n        {\n            isCurrentThread = TRUE;\n        }\n        else if (NT_SUCCESS(PhGetThreadBasicInformation(ThreadHandle, &basicInfo)))\n        {\n            if (basicInfo.ClientId.UniqueThread == NtCurrentTeb()->ClientId.UniqueThread)\n                isCurrentThread = TRUE;\n            if (basicInfo.ClientId.UniqueProcess == SYSTEM_PROCESS_ID)\n                isSystemThread = TRUE;\n        }\n    }\n\n    // Make sure this isn't a kernel-mode thread.\n    if (!isSystemThread)\n    {\n        PVOID startAddress;\n\n        if (NT_SUCCESS(NtQueryInformationThread(ThreadHandle, ThreadQuerySetWin32StartAddress,\n            &startAddress, sizeof(PVOID), NULL)))\n        {\n            if ((ULONG_PTR)startAddress > PhSystemBasicInformation.MaximumUserModeAddress)\n                isSystemThread = TRUE;\n        }\n    }\n\n    // Suspend the thread to avoid inaccurate results. Don't suspend if we're walking the stack of\n    // the current thread or this is a kernel-mode thread.\n    if (!isCurrentThread && !isSystemThread)\n    {\n        if (NT_SUCCESS(NtSuspendThread(ThreadHandle, NULL)))\n            suspended = TRUE;\n    }\n\n    // Kernel stack walk.\n    if ((Flags & PH_WALK_KERNEL_STACK) && KphIsConnected())\n    {\n        PVOID stack[256 - 2]; // See MAX_STACK_DEPTH\n        ULONG capturedFrames;\n        ULONG i;\n\n        if (NT_SUCCESS(KphCaptureStackBackTraceThread(\n            ThreadHandle,\n            1,\n            sizeof(stack) / sizeof(PVOID),\n            stack,\n            &capturedFrames,\n            NULL\n            )))\n        {\n            PH_THREAD_STACK_FRAME threadStackFrame;\n\n            memset(&threadStackFrame, 0, sizeof(PH_THREAD_STACK_FRAME));\n\n            for (i = 0; i < capturedFrames; i++)\n            {\n                threadStackFrame.PcAddress = stack[i];\n                threadStackFrame.Flags = PH_THREAD_STACK_FRAME_KERNEL;\n\n                if (!Callback(&threadStackFrame, Context))\n                {\n                    goto ResumeExit;\n                }\n            }\n        }\n    }\n\n#ifdef _WIN64\n    if (Flags & PH_WALK_AMD64_STACK)\n    {\n        STACKFRAME64 stackFrame;\n        PH_THREAD_STACK_FRAME threadStackFrame;\n        CONTEXT context;\n\n        context.ContextFlags = CONTEXT_ALL;\n\n        if (!NT_SUCCESS(status = NtGetContextThread(\n            ThreadHandle,\n            &context\n            )))\n            goto SkipAmd64Stack;\n\n        memset(&stackFrame, 0, sizeof(STACKFRAME64));\n        stackFrame.AddrPC.Mode = AddrModeFlat;\n        stackFrame.AddrPC.Offset = context.Rip;\n        stackFrame.AddrStack.Mode = AddrModeFlat;\n        stackFrame.AddrStack.Offset = context.Rsp;\n        stackFrame.AddrFrame.Mode = AddrModeFlat;\n        stackFrame.AddrFrame.Offset = context.Rbp;\n\n        while (TRUE)\n        {\n            if (!PhStackWalk(\n                IMAGE_FILE_MACHINE_AMD64,\n                ProcessHandle,\n                ThreadHandle,\n                &stackFrame,\n                &context,\n                SymbolProvider,\n                NULL,\n                NULL,\n                NULL,\n                NULL\n                ))\n                break;\n\n            // If we have an invalid instruction pointer, break.\n            if (!stackFrame.AddrPC.Offset || stackFrame.AddrPC.Offset == -1)\n                break;\n\n            // Convert the stack frame and execute the callback.\n\n            PhpConvertStackFrame(&stackFrame, PH_THREAD_STACK_FRAME_AMD64, &threadStackFrame);\n\n            if (!Callback(&threadStackFrame, Context))\n                goto ResumeExit;\n        }\n    }\n\nSkipAmd64Stack:\n#endif\n\n    // x86/WOW64 stack walk.\n    if (Flags & PH_WALK_I386_STACK)\n    {\n        STACKFRAME64 stackFrame;\n        PH_THREAD_STACK_FRAME threadStackFrame;\n#ifndef _WIN64\n        CONTEXT context;\n\n        context.ContextFlags = CONTEXT_ALL;\n\n        if (!NT_SUCCESS(status = NtGetContextThread(\n            ThreadHandle,\n            &context\n            )))\n            goto SkipI386Stack;\n#else\n        WOW64_CONTEXT context;\n\n        context.ContextFlags = WOW64_CONTEXT_ALL;\n\n        if (!NT_SUCCESS(status = NtQueryInformationThread(\n            ThreadHandle,\n            ThreadWow64Context,\n            &context,\n            sizeof(WOW64_CONTEXT),\n            NULL\n            )))\n            goto SkipI386Stack;\n#endif\n\n        memset(&stackFrame, 0, sizeof(STACKFRAME64));\n        stackFrame.AddrPC.Mode = AddrModeFlat;\n        stackFrame.AddrPC.Offset = context.Eip;\n        stackFrame.AddrStack.Mode = AddrModeFlat;\n        stackFrame.AddrStack.Offset = context.Esp;\n        stackFrame.AddrFrame.Mode = AddrModeFlat;\n        stackFrame.AddrFrame.Offset = context.Ebp;\n\n        while (TRUE)\n        {\n            if (!PhStackWalk(\n                IMAGE_FILE_MACHINE_I386,\n                ProcessHandle,\n                ThreadHandle,\n                &stackFrame,\n                &context,\n                SymbolProvider,\n                NULL,\n                NULL,\n                NULL,\n                NULL\n                ))\n                break;\n\n            // If we have an invalid instruction pointer, break.\n            if (!stackFrame.AddrPC.Offset || stackFrame.AddrPC.Offset == -1)\n                break;\n\n            // Convert the stack frame and execute the callback.\n\n            PhpConvertStackFrame(&stackFrame, PH_THREAD_STACK_FRAME_I386, &threadStackFrame);\n\n            if (!Callback(&threadStackFrame, Context))\n                goto ResumeExit;\n\n            // (x86 only) Allow the user to change Eip, Esp and Ebp.\n            context.Eip = PtrToUlong(threadStackFrame.PcAddress);\n            stackFrame.AddrPC.Offset = PtrToUlong(threadStackFrame.PcAddress);\n            context.Ebp = PtrToUlong(threadStackFrame.FrameAddress);\n            stackFrame.AddrFrame.Offset = PtrToUlong(threadStackFrame.FrameAddress);\n            context.Esp = PtrToUlong(threadStackFrame.StackAddress);\n            stackFrame.AddrStack.Offset = PtrToUlong(threadStackFrame.StackAddress);\n        }\n    }\n\nSkipI386Stack:\n\nResumeExit:\n    if (suspended)\n        NtResumeThread(ThreadHandle, NULL);\n\n    if (processOpened)\n        NtClose(ProcessHandle);\n\n    return status;\n}\n\nPPH_STRING PhUndecorateName(\n    _In_ PPH_SYMBOL_PROVIDER SymbolProvider,\n    _In_ PSTR DecoratedName\n    )\n{\n    PPH_STRING undecoratedStr = NULL;\n    PSTR undecoratedName = NULL;\n\n    PhpRegisterSymbolProvider(SymbolProvider);\n\n    if (!UnDecorateSymbolName_I)\n        return NULL;\n\n    // lucasg: there is no way to know the resulting length of an undecorated name\n    // if there is not enough place, the function does not fail. Instead it\n    // return a truncated name.\n\n    undecoratedName = PhAllocate(PAGE_SIZE * sizeof(CHAR));\n\n    PH_LOCK_SYMBOLS();\n    if (UnDecorateSymbolName_I(DecoratedName, undecoratedName, PAGE_SIZE, UNDNAME_COMPLETE) != 0)\n    {\n        undecoratedStr = PhZeroExtendToUtf16(undecoratedName);\n    }\n    PH_UNLOCK_SYMBOLS();\n\n    PhFree(undecoratedName);\n\n    return undecoratedStr;\n}\n\nPPH_STRING PhUndecorateNameW(\n    _In_ PPH_SYMBOL_PROVIDER SymbolProvider,\n    _In_ PWSTR DecoratedName\n    )\n{\n    PPH_STRING undecoratedStr = NULL;\n    PWSTR undecoratedName = NULL;\n\n    PhpRegisterSymbolProvider(SymbolProvider);\n\n    if (!UnDecorateSymbolNameW_I)\n        return NULL;\n\n    // lucasg: there is no way to know the resulting length of an undecorated name\n    // if there is not enough place, the function does not fail. Instead it\n    // return a truncated name.\n\n    undecoratedName = PhAllocate(PAGE_SIZE * sizeof(WCHAR));\n\n    PH_LOCK_SYMBOLS();\n    if (UnDecorateSymbolNameW_I(DecoratedName, undecoratedName, PAGE_SIZE, UNDNAME_COMPLETE) != 0)\n    {\n        undecoratedStr = PhCreateString(undecoratedName);\n    }\n    PH_UNLOCK_SYMBOLS();\n\n    PhFree(undecoratedName);\n\n    return undecoratedStr;\n}"
  },
  {
    "path": "third_party/phlib/sync.c",
    "content": "/*\n * Process Hacker -\n *   misc. synchronization utilities\n *\n * Copyright (C) 2010-2015 wj32\n *\n * This file is part of Process Hacker.\n *\n * Process Hacker is free software; you can redistribute it and/or modify\n * it under the terms of the GNU General Public License as published by\n * the Free Software Foundation, either version 3 of the License, or\n * (at your option) any later version.\n *\n * Process Hacker is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n * GNU General Public License for more details.\n *\n * You should have received a copy of the GNU General Public License\n * along with Process Hacker.  If not, see <http://www.gnu.org/licenses/>.\n */\n\n/*\n * This file contains code for several synchronization objects.\n *\n * Event. This is a lightweight notification event object that does not create a kernel event object\n * until needed. Additionally the kernel event object is automatically freed when no longer needed.\n * Note that PhfResetEvent is NOT thread-safe.\n *\n * Barrier. This is a non-traditional implementation of a barrier, built on the wake event object. I\n * have identified three types of participants in this process:\n * 1. The slaves, who wait for the master to release them. This is the main mechanism through which\n *    the threads are synchronized.\n * 2. The master, who is the last thread to wait on the barrier. This thread triggers the waking\n *    process, and waits until all slaves have woken.\n * 3. The observers, who are simply threads which were slaves before, were woken, and have tried to\n *    wait on the barrier again before all other slaves have woken.\n *\n * Rundown protection. This object allows a thread to wait until all other threads have finished\n * using a particular resource before freeing the resource.\n *\n * Init-once. This is a lightweight one-time initialization mechanism which uses the event object\n * for any required blocking. The overhead is very small - only a single inlined comparison.\n */\n\n#include <phbase.h>\n\n/**\n * Initializes an event object.\n *\n * \\param Event A pointer to an event object.\n */\nVOID FASTCALL PhfInitializeEvent(\n    _Out_ PPH_EVENT Event\n    )\n{\n    Event->Value = PH_EVENT_REFCOUNT_INC;\n    Event->EventHandle = NULL;\n}\n\n/**\n * Dereferences the event object used by an event.\n *\n * \\param Event A pointer to an event object.\n * \\param EventHandle The current value of the event object.\n */\nFORCEINLINE VOID PhpDereferenceEvent(\n    _Inout_ PPH_EVENT Event,\n    _In_opt_ HANDLE EventHandle\n    )\n{\n    ULONG_PTR value;\n\n    value = _InterlockedExchangeAddPointer((PLONG_PTR)&Event->Value, -PH_EVENT_REFCOUNT_INC);\n\n    // See if the reference count has become 0.\n    if (((value >> PH_EVENT_REFCOUNT_SHIFT) & PH_EVENT_REFCOUNT_MASK) - 1 == 0)\n    {\n        if (EventHandle)\n        {\n            NtClose(EventHandle);\n            Event->EventHandle = NULL;\n        }\n    }\n}\n\n/**\n * References the event object used by an event.\n *\n * \\param Event A pointer to an event object.\n */\nFORCEINLINE VOID PhpReferenceEvent(\n    _Inout_ PPH_EVENT Event\n    )\n{\n    _InterlockedExchangeAddPointer((PLONG_PTR)&Event->Value, PH_EVENT_REFCOUNT_INC);\n}\n\n/**\n * Sets an event object. Any threads waiting on the event will be released.\n *\n * \\param Event A pointer to an event object.\n */\nVOID FASTCALL PhfSetEvent(\n    _Inout_ PPH_EVENT Event\n    )\n{\n    HANDLE eventHandle;\n\n    // Only proceed if the event isn't set already.\n    if (!_InterlockedBitTestAndSetPointer((PLONG_PTR)&Event->Value, PH_EVENT_SET_SHIFT))\n    {\n        eventHandle = Event->EventHandle;\n\n        if (eventHandle)\n        {\n            NtSetEvent(eventHandle, NULL);\n        }\n\n        PhpDereferenceEvent(Event, eventHandle);\n    }\n}\n\n/**\n * Waits for an event object to be set.\n *\n * \\param Event A pointer to an event object.\n * \\param Timeout The timeout value.\n *\n * \\return TRUE if the event object was set before the timeout period expired, otherwise FALSE.\n *\n * \\remarks To test the event, use PhTestEvent() instead of using a timeout of zero.\n */\nBOOLEAN FASTCALL PhfWaitForEvent(\n    _Inout_ PPH_EVENT Event,\n    _In_opt_ PLARGE_INTEGER Timeout\n    )\n{\n    BOOLEAN result;\n    ULONG_PTR value;\n    HANDLE eventHandle;\n\n    value = Event->Value;\n\n    // Shortcut: if the event is set, return immediately.\n    if (value & PH_EVENT_SET)\n        return TRUE;\n\n    // Shortcut: if the timeout is 0, return immediately if the event isn't set.\n    if (Timeout && Timeout->QuadPart == 0)\n        return FALSE;\n\n    // Prevent the event from being invalidated.\n    PhpReferenceEvent(Event);\n\n    eventHandle = Event->EventHandle;\n\n    if (!eventHandle)\n    {\n        NtCreateEvent(&eventHandle, EVENT_ALL_ACCESS, NULL, NotificationEvent, FALSE);\n        assert(eventHandle);\n\n        // Try to set the event handle to our event.\n        if (_InterlockedCompareExchangePointer(\n            &Event->EventHandle,\n            eventHandle,\n            NULL\n            ) != NULL)\n        {\n            // Someone else set the event before we did.\n            NtClose(eventHandle);\n            eventHandle = Event->EventHandle;\n        }\n    }\n\n    // Essential: check the event one last time to see if it is set.\n    if (!(Event->Value & PH_EVENT_SET))\n    {\n        result = NtWaitForSingleObject(eventHandle, FALSE, Timeout) == STATUS_WAIT_0;\n    }\n    else\n    {\n        result = TRUE;\n    }\n\n    PhpDereferenceEvent(Event, eventHandle);\n\n    return result;\n}\n\n/**\n * Resets an event's state.\n *\n * \\param Event A pointer to an event object.\n *\n * \\remarks This function is not thread-safe. Make sure no other threads are using the event when\n * you call this function.\n */\nVOID FASTCALL PhfResetEvent(\n    _Inout_ PPH_EVENT Event\n    )\n{\n    assert(!Event->EventHandle);\n\n    if (PhTestEvent(Event))\n        Event->Value = PH_EVENT_REFCOUNT_INC;\n}\n\nVOID FASTCALL PhfInitializeBarrier(\n    _Out_ PPH_BARRIER Barrier,\n    _In_ ULONG_PTR Target\n    )\n{\n    Barrier->Value = Target << PH_BARRIER_TARGET_SHIFT;\n    PhInitializeWakeEvent(&Barrier->WakeEvent);\n}\n\nFORCEINLINE VOID PhpBlockOnBarrier(\n    _Inout_ PPH_BARRIER Barrier,\n    _In_ ULONG Role,\n    _In_ BOOLEAN Spin\n    )\n{\n    PH_QUEUED_WAIT_BLOCK waitBlock;\n    ULONG_PTR cancel;\n\n    PhQueueWakeEvent(&Barrier->WakeEvent, &waitBlock);\n\n    cancel = 0;\n\n    switch (Role)\n    {\n    case PH_BARRIER_MASTER:\n        cancel = ((Barrier->Value >> PH_BARRIER_COUNT_SHIFT) & PH_BARRIER_COUNT_MASK) == 1;\n        break;\n    case PH_BARRIER_SLAVE:\n        cancel = Barrier->Value & PH_BARRIER_WAKING;\n        break;\n    case PH_BARRIER_OBSERVER:\n        cancel = !(Barrier->Value & PH_BARRIER_WAKING);\n        break;\n    default:\n        ASSUME_NO_DEFAULT;\n    }\n\n    if (cancel)\n    {\n        PhSetWakeEvent(&Barrier->WakeEvent, &waitBlock);\n        return;\n    }\n\n    PhWaitForWakeEvent(&Barrier->WakeEvent, &waitBlock, Spin, NULL);\n}\n\n/**\n * Waits until all threads are blocking on the barrier, and resets the state of the barrier.\n *\n * \\param Barrier A barrier.\n * \\param Spin TRUE to spin on the barrier before blocking, FALSE to block immediately.\n *\n * \\return TRUE for an unspecified thread after each phase, and FALSE for all other threads.\n *\n * \\remarks By checking the return value of the function, in each phase an action can be performed\n * exactly once. This could, for example, involve merging the results of calculations.\n */\nBOOLEAN FASTCALL PhfWaitForBarrier(\n    _Inout_ PPH_BARRIER Barrier,\n    _In_ BOOLEAN Spin\n    )\n{\n    ULONG_PTR value;\n    ULONG_PTR newValue;\n    ULONG_PTR count;\n    ULONG_PTR target;\n\n    value = Barrier->Value;\n\n    while (TRUE)\n    {\n        if (!(value & PH_BARRIER_WAKING))\n        {\n            count = (value >> PH_BARRIER_COUNT_SHIFT) & PH_BARRIER_COUNT_MASK;\n            target = (value >> PH_BARRIER_TARGET_SHIFT) & PH_BARRIER_TARGET_MASK;\n            assert(count != target);\n\n            count++;\n\n            if (count != target)\n                newValue = value + PH_BARRIER_COUNT_INC;\n            else\n                newValue = value + PH_BARRIER_COUNT_INC + PH_BARRIER_WAKING;\n\n            if ((newValue = (ULONG_PTR)_InterlockedCompareExchangePointer(\n                (PVOID *)&Barrier->Value,\n                (PVOID)newValue,\n                (PVOID)value\n                )) == value)\n            {\n                if (count != target)\n                {\n                    // Wait for the master signal (the last thread to reach the barrier).\n                    // Once we get it, decrement the count to allow the master to continue.\n\n                    do\n                    {\n                        PhpBlockOnBarrier(Barrier, PH_BARRIER_SLAVE, Spin);\n                    } while (!(Barrier->Value & PH_BARRIER_WAKING));\n\n                    value = _InterlockedExchangeAddPointer((PLONG_PTR)&Barrier->Value, -PH_BARRIER_COUNT_INC);\n\n                    if (((value >> PH_BARRIER_COUNT_SHIFT) & PH_BARRIER_COUNT_MASK) - 1 == 1)\n                    {\n                        PhSetWakeEvent(&Barrier->WakeEvent, NULL); // for the master\n                    }\n\n                    return FALSE;\n                }\n                else\n                {\n                    // We're the last one to reach the barrier, so we become the master.\n                    // Wake the slaves and wait for them to decrease the count to 1. This is so that\n                    // we know the slaves have woken and we don't clear the waking bit before they\n                    // wake.\n\n                    PhSetWakeEvent(&Barrier->WakeEvent, NULL); // for slaves\n\n                    do\n                    {\n                        PhpBlockOnBarrier(Barrier, PH_BARRIER_MASTER, Spin);\n                    } while (((Barrier->Value >> PH_BARRIER_COUNT_SHIFT) & PH_BARRIER_COUNT_MASK) != 1);\n\n                    _InterlockedExchangeAddPointer((PLONG_PTR)&Barrier->Value, -(PH_BARRIER_WAKING + PH_BARRIER_COUNT_INC));\n                    PhSetWakeEvent(&Barrier->WakeEvent, NULL); // for observers\n\n                    return TRUE;\n                }\n            }\n        }\n        else\n        {\n            // We're too early; other threads are still waking. Wait for them to finish.\n\n            PhpBlockOnBarrier(Barrier, PH_BARRIER_OBSERVER, Spin);\n            newValue = Barrier->Value;\n        }\n\n        value = newValue;\n    }\n}\n\nVOID FASTCALL PhfInitializeRundownProtection(\n    _Out_ PPH_RUNDOWN_PROTECT Protection\n    )\n{\n    Protection->Value = 0;\n}\n\nBOOLEAN FASTCALL PhfAcquireRundownProtection(\n    _Inout_ PPH_RUNDOWN_PROTECT Protection\n    )\n{\n    ULONG_PTR value;\n\n    // Increment the reference count only if rundown has not started.\n\n    while (TRUE)\n    {\n        value = Protection->Value;\n\n        if (value & PH_RUNDOWN_ACTIVE)\n            return FALSE;\n\n        if ((ULONG_PTR)_InterlockedCompareExchangePointer(\n            (PVOID *)&Protection->Value,\n            (PVOID)(value + PH_RUNDOWN_REF_INC),\n            (PVOID)value\n            ) == value)\n            return TRUE;\n    }\n}\n\nVOID FASTCALL PhfReleaseRundownProtection(\n    _Inout_ PPH_RUNDOWN_PROTECT Protection\n    )\n{\n    ULONG_PTR value;\n\n    while (TRUE)\n    {\n        value = Protection->Value;\n\n        if (value & PH_RUNDOWN_ACTIVE)\n        {\n            PPH_RUNDOWN_WAIT_BLOCK waitBlock;\n\n            // Since rundown is active, the reference count has been moved to the waiter's wait\n            // block. If we are the last user, we must wake up the waiter.\n\n            waitBlock = (PPH_RUNDOWN_WAIT_BLOCK)(value & ~PH_RUNDOWN_ACTIVE);\n\n            if (_InterlockedDecrementPointer(&waitBlock->Count) == 0)\n            {\n                PhSetEvent(&waitBlock->WakeEvent);\n            }\n\n            break;\n        }\n        else\n        {\n            // Decrement the reference count normally.\n\n            if ((ULONG_PTR)_InterlockedCompareExchangePointer(\n                (PVOID *)&Protection->Value,\n                (PVOID)(value - PH_RUNDOWN_REF_INC),\n                (PVOID)value\n                ) == value)\n                break;\n        }\n    }\n}\n\nVOID FASTCALL PhfWaitForRundownProtection(\n    _Inout_ PPH_RUNDOWN_PROTECT Protection\n    )\n{\n    ULONG_PTR value;\n    ULONG_PTR count;\n    PH_RUNDOWN_WAIT_BLOCK waitBlock;\n    BOOLEAN waitBlockInitialized;\n\n    // Fast path. If the reference count is 0 or rundown has already been completed, return.\n    value = (ULONG_PTR)_InterlockedCompareExchangePointer(\n        (PVOID *)&Protection->Value,\n        (PVOID)PH_RUNDOWN_ACTIVE,\n        (PVOID)0\n        );\n\n    if (value == 0 || value == PH_RUNDOWN_ACTIVE)\n        return;\n\n    waitBlockInitialized = FALSE;\n\n    while (TRUE)\n    {\n        value = Protection->Value;\n        count = value >> PH_RUNDOWN_REF_SHIFT;\n\n        // Initialize the wait block if necessary.\n        if (count != 0 && !waitBlockInitialized)\n        {\n            PhInitializeEvent(&waitBlock.WakeEvent);\n            waitBlockInitialized = TRUE;\n        }\n\n        // Save the existing reference count.\n        waitBlock.Count = count;\n\n        if ((ULONG_PTR)_InterlockedCompareExchangePointer(\n            (PVOID *)&Protection->Value,\n            (PVOID)((ULONG_PTR)&waitBlock | PH_RUNDOWN_ACTIVE),\n            (PVOID)value\n            ) == value)\n        {\n            if (count != 0)\n                PhWaitForEvent(&waitBlock.WakeEvent, NULL);\n\n            break;\n        }\n    }\n}\n\nVOID FASTCALL PhfInitializeInitOnce(\n    _Out_ PPH_INITONCE InitOnce\n    )\n{\n    PhInitializeEvent(&InitOnce->Event);\n}\n\nBOOLEAN FASTCALL PhfBeginInitOnce(\n    _Inout_ PPH_INITONCE InitOnce\n    )\n{\n    if (!_InterlockedBitTestAndSetPointer(&InitOnce->Event.Value, PH_INITONCE_INITIALIZING_SHIFT))\n        return TRUE;\n\n    PhWaitForEvent(&InitOnce->Event, NULL);\n\n    return FALSE;\n}\n\nVOID FASTCALL PhfEndInitOnce(\n    _Inout_ PPH_INITONCE InitOnce\n    )\n{\n    PhSetEvent(&InitOnce->Event);\n}\n"
  },
  {
    "path": "third_party/phlib/treenew.c",
    "content": "/*\n * Process Hacker -\n *   tree new (tree list control)\n *\n * Copyright (C) 2011-2016 wj32\n * Copyright (C) 2017 dmex\n *\n * This file is part of Process Hacker.\n *\n * Process Hacker is free software; you can redistribute it and/or modify\n * it under the terms of the GNU General Public License as published by\n * the Free Software Foundation, either version 3 of the License, or\n * (at your option) any later version.\n *\n * Process Hacker is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n * GNU General Public License for more details.\n *\n * You should have received a copy of the GNU General Public License\n * along with Process Hacker.  If not, see <http://www.gnu.org/licenses/>.\n */\n\n/*\n * The tree new is a tree view with columns. Unlike the old tree list control, which was a wrapper\n * around the list view control, this control was written from scratch.\n *\n * Current issues not included in any comments:\n * * Adding, removing or changing columns does not cause invalidation.\n * * It is not possible to change a column to make it fixed. The current fixed column must be\n *   removed and the new fixed column must then be added.\n * * When there are no visible normal columns, the space usually occupied by the normal column\n *   headers is filled with a solid background color. We should catch this and paint the usual\n *   themed background there instead.\n * * It is not possible to update any TN_STYLE_* flags after the control is created.\n *\n * Possible additions:\n * * More flexible mouse input callbacks to allow custom controls inside columns.\n * * Allow custom drawn columns to customize their behaviour when TN_FLAG_ITEM_DRAG_SELECT is set\n *   (e.g. disable drag selection over certain areas).\n * * Virtual mode\n */\n\n#include <ph.h>\n#include <treenew.h>\n\n#include <uxtheme.h>\n#include <vssym32.h>\n#include <windowsx.h>\n\n#include <guisup.h>\n\n#include <treenewp.h>\n\nstatic PVOID ComCtl32Handle;\nstatic LONG SmallIconWidth;\nstatic LONG SmallIconHeight;\n\nBOOLEAN PhTreeNewInitialization(\n    VOID\n    )\n{\n    WNDCLASSEX c = { sizeof(c) };\n\n    c.style = CS_DBLCLKS | CS_GLOBALCLASS;\n    c.lpfnWndProc = PhTnpWndProc;\n    c.cbClsExtra = 0;\n    c.cbWndExtra = sizeof(PVOID);\n    c.hInstance = PhInstanceHandle;\n    c.hIcon = NULL;\n    c.hCursor = LoadCursor(NULL, IDC_ARROW);\n    c.hbrBackground = NULL;\n    c.lpszMenuName = NULL;\n    c.lpszClassName = PH_TREENEW_CLASSNAME;\n    c.hIconSm = NULL;\n\n    if (!RegisterClassEx(&c))\n        return FALSE;\n\n    ComCtl32Handle = PhGetDllHandle(L\"comctl32.dll\");\n    SmallIconWidth = GetSystemMetrics(SM_CXSMICON);\n    SmallIconHeight = GetSystemMetrics(SM_CYSMICON);\n\n    return TRUE;\n}\n\nLRESULT CALLBACK PhTnpWndProc(\n    _In_ HWND hwnd,\n    _In_ UINT uMsg,\n    _In_ WPARAM wParam,\n    _In_ LPARAM lParam\n    )\n{\n    PPH_TREENEW_CONTEXT context;\n\n    context = (PPH_TREENEW_CONTEXT)GetWindowLongPtr(hwnd, 0);\n\n    if (uMsg == WM_CREATE)\n    {\n        PhTnpCreateTreeNewContext(&context);\n        SetWindowLongPtr(hwnd, 0, (LONG_PTR)context);\n    }\n\n    if (!context)\n        return DefWindowProc(hwnd, uMsg, wParam, lParam);\n\n    if (context->Tracking && (GetAsyncKeyState(VK_ESCAPE) & 0x1))\n    {\n        PhTnpCancelTrack(context);\n    }\n\n    // Note: if we have suspended restructuring, we *cannot* access any nodes, because all node\n    // pointers are now invalid. Below, we disable all input.\n\n    switch (uMsg)\n    {\n    case WM_CREATE:\n        {\n            if (!PhTnpOnCreate(hwnd, context, (CREATESTRUCT *)lParam))\n                return -1;\n        }\n        return 0;\n    case WM_NCDESTROY:\n        {\n            context->Callback(hwnd, TreeNewDestroying, NULL, NULL, context->CallbackContext);\n            PhTnpDestroyTreeNewContext(context);\n            SetWindowLongPtr(hwnd, 0, (LONG_PTR)NULL);\n        }\n        return 0;\n    case WM_SIZE:\n        {\n            PhTnpOnSize(hwnd, context);\n        }\n        break;\n    case WM_ERASEBKGND:\n        return TRUE;\n    case WM_PAINT:\n        {\n            PhTnpOnPaint(hwnd, context);\n        }\n        return 0;\n    case WM_PRINTCLIENT:\n        {\n            if (!context->SuspendUpdateStructure)\n                PhTnpOnPrintClient(hwnd, context, (HDC)wParam, (ULONG)lParam);\n        }\n        return 0;\n    case WM_NCPAINT:\n        {\n            if (PhTnpOnNcPaint(hwnd, context, (HRGN)wParam))\n                return 0;\n        }\n        break;\n    case WM_GETFONT:\n        return (LRESULT)context->Font;\n    case WM_SETFONT:\n        {\n            PhTnpOnSetFont(hwnd, context, (HFONT)wParam, LOWORD(lParam));\n        }\n        break;\n    case WM_STYLECHANGED:\n        {\n            PhTnpOnStyleChanged(hwnd, context, (LONG)wParam, (STYLESTRUCT *)lParam);\n        }\n        break;\n    case WM_SETTINGCHANGE:\n        {\n            PhTnpOnSettingChange(hwnd, context);\n        }\n        break;\n    case WM_THEMECHANGED:\n        {\n            PhTnpOnThemeChanged(hwnd, context);\n        }\n        break;\n    case WM_GETDLGCODE:\n        return PhTnpOnGetDlgCode(hwnd, context, (ULONG)wParam, (PMSG)lParam);\n    case WM_SETFOCUS:\n        {\n            context->HasFocus = TRUE;\n            InvalidateRect(context->Handle, NULL, FALSE);\n        }\n        return 0;\n    case WM_KILLFOCUS:\n        {\n            context->HasFocus = FALSE;\n            InvalidateRect(context->Handle, NULL, FALSE);\n        }\n        return 0;\n    case WM_SETCURSOR:\n        {\n            if (PhTnpOnSetCursor(hwnd, context, (HWND)wParam))\n                return TRUE;\n        }\n        break;\n    case WM_TIMER:\n        {\n            PhTnpOnTimer(hwnd, context, (ULONG)wParam);\n        }\n        return 0;\n    case WM_MOUSEMOVE:\n        {\n            if (!context->SuspendUpdateStructure)\n                PhTnpOnMouseMove(hwnd, context, (ULONG)wParam, GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam));\n            else\n                context->SuspendUpdateMoveMouse = TRUE;\n        }\n        break;\n    case WM_MOUSELEAVE:\n        {\n            if (!context->SuspendUpdateStructure)\n                PhTnpOnMouseLeave(hwnd, context);\n        }\n        break;\n    case WM_LBUTTONDOWN:\n    case WM_LBUTTONUP:\n    case WM_LBUTTONDBLCLK:\n    case WM_RBUTTONDOWN:\n    case WM_RBUTTONUP:\n    case WM_RBUTTONDBLCLK:\n    case WM_MBUTTONDOWN:\n    case WM_MBUTTONUP:\n    case WM_MBUTTONDBLCLK:\n        {\n            if (!context->SuspendUpdateStructure)\n                PhTnpOnXxxButtonXxx(hwnd, context, uMsg, (ULONG)wParam, GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam));\n        }\n        break;\n    case WM_CAPTURECHANGED:\n        {\n            PhTnpOnCaptureChanged(hwnd, context);\n        }\n        break;\n    case WM_KEYDOWN:\n        {\n            if (!context->SuspendUpdateStructure)\n                PhTnpOnKeyDown(hwnd, context, (ULONG)wParam, (ULONG)lParam);\n        }\n        break;\n    case WM_CHAR:\n        {\n            if (!context->SuspendUpdateStructure)\n                PhTnpOnChar(hwnd, context, (ULONG)wParam, (ULONG)lParam);\n        }\n        return 0;\n    case WM_MOUSEWHEEL:\n        {\n            PhTnpOnMouseWheel(hwnd, context, (SHORT)HIWORD(wParam), LOWORD(wParam), GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam));\n        }\n        break;\n    case WM_MOUSEHWHEEL:\n        {\n            PhTnpOnMouseHWheel(hwnd, context, (SHORT)HIWORD(wParam), LOWORD(wParam), GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam));\n        }\n        break;\n    case WM_CONTEXTMENU:\n        {\n            if (!context->SuspendUpdateStructure)\n                PhTnpOnContextMenu(hwnd, context, GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam));\n        }\n        return 0;\n    case WM_VSCROLL:\n        {\n            PhTnpOnVScroll(hwnd, context, LOWORD(wParam), HIWORD(wParam));\n        }\n        return 0;\n    case WM_HSCROLL:\n        {\n            PhTnpOnHScroll(hwnd, context, LOWORD(wParam), HIWORD(wParam));\n        }\n        return 0;\n    case WM_NOTIFY:\n        {\n            LRESULT result;\n\n            if (PhTnpOnNotify(hwnd, context, (NMHDR *)lParam, &result))\n                return result;\n        }\n        break;\n    }\n\n    if (uMsg >= TNM_FIRST && uMsg <= TNM_LAST)\n    {\n        return PhTnpOnUserMessage(hwnd, context, uMsg, wParam, lParam);\n    }\n\n    switch (uMsg)\n    {\n    case WM_MOUSEMOVE:\n    case WM_LBUTTONDOWN:\n    case WM_LBUTTONUP:\n    case WM_RBUTTONDOWN:\n    case WM_RBUTTONUP:\n    case WM_MBUTTONDOWN:\n    case WM_MBUTTONUP:\n        {\n            if (context->TooltipsHandle)\n            {\n                MSG message;\n\n                message.hwnd = hwnd;\n                message.message = uMsg;\n                message.wParam = wParam;\n                message.lParam = lParam;\n                SendMessage(context->TooltipsHandle, TTM_RELAYEVENT, 0, (LPARAM)&message);\n            }\n        }\n        break;\n    }\n\n    return DefWindowProc(hwnd, uMsg, wParam, lParam);\n}\n\nBOOLEAN NTAPI PhTnpNullCallback(\n    _In_ HWND hwnd,\n    _In_ PH_TREENEW_MESSAGE Message,\n    _In_opt_ PVOID Parameter1,\n    _In_opt_ PVOID Parameter2,\n    _In_opt_ PVOID Context\n    )\n{\n    return FALSE;\n}\n\nVOID PhTnpCreateTreeNewContext(\n    _Out_ PPH_TREENEW_CONTEXT *Context\n    )\n{\n    PPH_TREENEW_CONTEXT context;\n\n    context = PhAllocate(sizeof(PH_TREENEW_CONTEXT));\n    memset(context, 0, sizeof(PH_TREENEW_CONTEXT));\n\n    context->FixedWidthMinimum = 20;\n    context->RowHeight = 1; // must never be 0\n    context->HotNodeIndex = -1;\n    context->Callback = PhTnpNullCallback;\n    context->FlatList = PhCreateList(64);\n    context->TooltipIndex = -1;\n    context->TooltipId = -1;\n    context->TooltipColumnId = -1;\n    context->EnableRedraw = 1;\n    context->DefaultBackColor = GetSysColor(COLOR_WINDOW); // RGB(0xff, 0xff, 0xff)\n    context->DefaultForeColor = GetSysColor(COLOR_WINDOWTEXT); // RGB(0x00, 0x00, 0x00)\n\n    *Context = context;\n}\n\nVOID PhTnpDestroyTreeNewContext(\n    _In_ PPH_TREENEW_CONTEXT Context\n    )\n{\n    ULONG i;\n\n    if (Context->Columns)\n    {\n        for (i = 0; i < Context->NextId; i++)\n        {\n            if (Context->Columns[i])\n                PhFree(Context->Columns[i]);\n        }\n\n        PhFree(Context->Columns);\n    }\n\n    if (Context->ColumnsByDisplay)\n        PhFree(Context->ColumnsByDisplay);\n\n    PhDereferenceObject(Context->FlatList);\n\n    if (Context->FontOwned)\n        DeleteObject(Context->Font);\n\n    if (Context->ThemeData)\n        CloseThemeData(Context->ThemeData);\n\n    if (Context->SearchString)\n        PhFree(Context->SearchString);\n\n    if (Context->TooltipText)\n        PhDereferenceObject(Context->TooltipText);\n\n    if (Context->BufferedContext)\n        PhTnpDestroyBufferedContext(Context);\n\n    if (Context->SuspendUpdateRegion)\n        DeleteObject(Context->SuspendUpdateRegion);\n\n    PhFree(Context);\n}\n\nBOOLEAN PhTnpOnCreate(\n    _In_ HWND hwnd,\n    _In_ PPH_TREENEW_CONTEXT Context,\n    _In_ CREATESTRUCT *CreateStruct\n    )\n{\n    ULONG headerStyle;\n\n    Context->Handle = hwnd;\n    Context->InstanceHandle = CreateStruct->hInstance;\n    Context->Style = CreateStruct->style;\n    Context->ExtendedStyle = CreateStruct->dwExStyle;\n\n    if (Context->Style & TN_STYLE_DOUBLE_BUFFERED)\n        Context->DoubleBuffered = TRUE;\n    if ((Context->Style & TN_STYLE_ANIMATE_DIVIDER) && Context->DoubleBuffered)\n        Context->AnimateDivider = TRUE;\n\n    headerStyle = HDS_HORZ | HDS_FULLDRAG;\n\n    if (!(Context->Style & TN_STYLE_NO_COLUMN_SORT))\n        headerStyle |= HDS_BUTTONS;\n    if (!(Context->Style & TN_STYLE_NO_COLUMN_HEADER))\n        headerStyle |= WS_VISIBLE;\n\n    if (!(Context->FixedHeaderHandle = CreateWindow(\n        WC_HEADER,\n        NULL,\n        WS_CHILD | WS_CLIPSIBLINGS | headerStyle,\n        0,\n        0,\n        0,\n        0,\n        hwnd,\n        NULL,\n        CreateStruct->hInstance,\n        NULL\n        )))\n    {\n        return FALSE;\n    }\n\n    if (!(Context->Style & TN_STYLE_NO_COLUMN_REORDER))\n        headerStyle |= HDS_DRAGDROP;\n\n    if (!(Context->HeaderHandle = CreateWindow(\n        WC_HEADER,\n        NULL,\n        WS_CHILD | WS_CLIPSIBLINGS | headerStyle,\n        0,\n        0,\n        0,\n        0,\n        hwnd,\n        NULL,\n        CreateStruct->hInstance,\n        NULL\n        )))\n    {\n        return FALSE;\n    }\n\n    if (!(Context->VScrollHandle = CreateWindow(\n        WC_SCROLLBAR,\n        NULL,\n        WS_CHILD | WS_CLIPSIBLINGS | WS_VISIBLE | SBS_VERT,\n        0,\n        0,\n        0,\n        0,\n        hwnd,\n        NULL,\n        CreateStruct->hInstance,\n        NULL\n        )))\n    {\n        return FALSE;\n    }\n\n    if (!(Context->HScrollHandle = CreateWindow(\n        WC_SCROLLBAR,\n        NULL,\n        WS_CHILD | WS_CLIPSIBLINGS | WS_VISIBLE | SBS_HORZ,\n        0,\n        0,\n        0,\n        0,\n        hwnd,\n        NULL,\n        CreateStruct->hInstance,\n        NULL\n        )))\n    {\n        return FALSE;\n    }\n\n    if (!(Context->FillerBoxHandle = CreateWindow(\n        WC_STATIC,\n        NULL,\n        WS_CHILD | WS_CLIPSIBLINGS | WS_VISIBLE,\n        0,\n        0,\n        0,\n        0,\n        hwnd,\n        NULL,\n        CreateStruct->hInstance,\n        NULL\n        )))\n    {\n        return FALSE;\n    }\n\n    PhTnpSetFont(Context, NULL, FALSE); // use default font\n    PhTnpUpdateSystemMetrics(Context);\n    PhTnpInitializeTooltips(Context);\n\n    return TRUE;\n}\n\nVOID PhTnpOnSize(\n    _In_ HWND hwnd,\n    _In_ PPH_TREENEW_CONTEXT Context\n    )\n{\n    GetClientRect(hwnd, &Context->ClientRect);\n\n    if (Context->BufferedContext && (\n        Context->BufferedContextRect.right < Context->ClientRect.right ||\n        Context->BufferedContextRect.bottom < Context->ClientRect.bottom))\n    {\n        // Invalidate the buffered context because the client size has increased.\n        PhTnpDestroyBufferedContext(Context);\n    }\n\n    PhTnpLayout(Context);\n\n    if (Context->TooltipsHandle)\n    {\n        TOOLINFO toolInfo;\n\n        memset(&toolInfo, 0, sizeof(TOOLINFO));\n        toolInfo.cbSize = sizeof(TOOLINFO);\n        toolInfo.hwnd = hwnd;\n        toolInfo.uId = TNP_TOOLTIPS_ITEM;\n        toolInfo.rect = Context->ClientRect;\n        SendMessage(Context->TooltipsHandle, TTM_NEWTOOLRECT, 0, (LPARAM)&toolInfo);\n    }\n}\n\nVOID PhTnpOnSetFont(\n    _In_ HWND hwnd,\n    _In_ PPH_TREENEW_CONTEXT Context,\n    _In_opt_ HFONT Font,\n    _In_ LOGICAL Redraw\n    )\n{\n    PhTnpSetFont(Context, Font, !!Redraw);\n    PhTnpLayout(Context);\n}\n\nVOID PhTnpOnStyleChanged(\n    _In_ HWND hwnd,\n    _In_ PPH_TREENEW_CONTEXT Context,\n    _In_ LONG Type,\n    _In_ STYLESTRUCT *StyleStruct\n    )\n{\n    if (Type == GWL_EXSTYLE)\n        Context->ExtendedStyle = StyleStruct->styleNew;\n}\n\nVOID PhTnpOnSettingChange(\n    _In_ HWND hwnd,\n    _In_ PPH_TREENEW_CONTEXT Context\n    )\n{\n    PhTnpUpdateSystemMetrics(Context);\n    PhTnpUpdateTextMetrics(Context);\n    PhTnpLayout(Context);\n}\n\nVOID PhTnpOnThemeChanged(\n    _In_ HWND hwnd,\n    _In_ PPH_TREENEW_CONTEXT Context\n    )\n{\n    PhTnpUpdateThemeData(Context);\n}\n\nULONG PhTnpOnGetDlgCode(\n    _In_ HWND hwnd,\n    _In_ PPH_TREENEW_CONTEXT Context,\n    _In_ ULONG VirtualKey,\n    _In_opt_ PMSG Message\n    )\n{\n    ULONG code;\n\n    if (Context->Callback(hwnd, TreeNewGetDialogCode, UlongToPtr(VirtualKey), &code, Context->CallbackContext))\n    {\n        return code;\n    }\n\n    return DLGC_WANTARROWS | DLGC_WANTCHARS;\n}\n\nVOID PhTnpOnPaint(\n    _In_ HWND hwnd,\n    _In_ PPH_TREENEW_CONTEXT Context\n    )\n{\n    RECT updateRect;\n    HDC hdc;\n    PAINTSTRUCT paintStruct;\n\n    if (GetUpdateRect(hwnd, &updateRect, FALSE) && (updateRect.left | updateRect.right | updateRect.top | updateRect.bottom))\n    {\n        if (Context->EnableRedraw <= 0)\n        {\n            HRGN updateRegion;\n\n            updateRegion = CreateRectRgn(0, 0, 0, 0);\n            GetUpdateRgn(hwnd, updateRegion, FALSE);\n\n            if (!Context->SuspendUpdateRegion)\n            {\n                Context->SuspendUpdateRegion = updateRegion;\n            }\n            else\n            {\n                CombineRgn(Context->SuspendUpdateRegion, Context->SuspendUpdateRegion, updateRegion, RGN_OR);\n                DeleteObject(updateRegion);\n            }\n\n            // Pretend we painted something; this ensures the update region is validated properly.\n            if (BeginPaint(hwnd, &paintStruct))\n                EndPaint(hwnd, &paintStruct);\n\n            return;\n        }\n\n        if (Context->DoubleBuffered)\n        {\n            if (!Context->BufferedContext)\n            {\n                PhTnpCreateBufferedContext(Context);\n            }\n        }\n\n        if (hdc = BeginPaint(hwnd, &paintStruct))\n        {\n            updateRect = paintStruct.rcPaint;\n\n            if (Context->BufferedContext)\n            {\n                PhTnpPaint(hwnd, Context, Context->BufferedContext, &updateRect);\n                BitBlt(\n                    hdc,\n                    updateRect.left,\n                    updateRect.top,\n                    updateRect.right - updateRect.left,\n                    updateRect.bottom - updateRect.top,\n                    Context->BufferedContext,\n                    updateRect.left,\n                    updateRect.top,\n                    SRCCOPY\n                    );\n            }\n            else\n            {\n                PhTnpPaint(hwnd, Context, hdc, &updateRect);\n            }\n\n            EndPaint(hwnd, &paintStruct);\n        }\n    }\n}\n\nVOID PhTnpOnPrintClient(\n    _In_ HWND hwnd,\n    _In_ PPH_TREENEW_CONTEXT Context,\n    _In_ HDC hdc,\n    _In_ ULONG Flags\n    )\n{\n    PhTnpPaint(hwnd, Context, hdc, &Context->ClientRect);\n}\n\nBOOLEAN PhTnpOnNcPaint(\n    _In_ HWND hwnd,\n    _In_ PPH_TREENEW_CONTEXT Context,\n    _In_opt_ HRGN UpdateRegion\n    )\n{\n    PhTnpInitializeThemeData(Context);\n\n    // Themed border\n    if ((Context->ExtendedStyle & WS_EX_CLIENTEDGE) && Context->ThemeData)\n    {\n        HDC hdc;\n        ULONG flags;\n\n        if (UpdateRegion == HRGN_FULL)\n            UpdateRegion = NULL;\n\n        // Note the use of undocumented flags below. GetDCEx doesn't work without these.\n\n        flags = DCX_WINDOW | DCX_LOCKWINDOWUPDATE | 0x10000;\n\n        if (UpdateRegion)\n            flags |= DCX_INTERSECTRGN | 0x40000;\n\n        if (hdc = GetDCEx(hwnd, UpdateRegion, flags))\n        {\n            PhTnpDrawThemedBorder(Context, hdc);\n            ReleaseDC(hwnd, hdc);\n            return TRUE;\n        }\n    }\n\n    return FALSE;\n}\n\nBOOLEAN PhTnpOnSetCursor(\n    _In_ HWND hwnd,\n    _In_ PPH_TREENEW_CONTEXT Context,\n    _In_ HWND CursorWindowHandle\n    )\n{\n    POINT point;\n\n    PhTnpGetMessagePos(hwnd, &point);\n\n    if (TNP_HIT_TEST_FIXED_DIVIDER(point.x, Context))\n    {\n        if (!Context->DividerCursor)\n            Context->DividerCursor = LoadCursor(ComCtl32Handle, MAKEINTRESOURCE(106)); // HACK (the divider icon resource has been 106 for quite a while...)\n\n        SetCursor(Context->DividerCursor);\n        return TRUE;\n    }\n\n    if (Context->Cursor)\n    {\n        SetCursor(Context->Cursor);\n        return TRUE;\n    }\n\n    return FALSE;\n}\n\nVOID PhTnpOnTimer(\n    _In_ HWND hwnd,\n    _In_ PPH_TREENEW_CONTEXT Context,\n    _In_ ULONG Id\n    )\n{\n    if (Id == TNP_TIMER_ANIMATE_DIVIDER)\n    {\n        RECT dividerRect;\n\n        dividerRect.left = Context->FixedWidth;\n        dividerRect.top = Context->HeaderHeight;\n        dividerRect.right = Context->FixedWidth + 1;\n        dividerRect.bottom = Context->ClientRect.bottom;\n\n        if (Context->AnimateDividerFadingIn)\n        {\n            Context->DividerHot += TNP_ANIMATE_DIVIDER_INCREMENT;\n\n            if (Context->DividerHot >= 100)\n            {\n                Context->DividerHot = 100;\n                Context->AnimateDividerFadingIn = FALSE;\n                KillTimer(hwnd, TNP_TIMER_ANIMATE_DIVIDER);\n            }\n\n            InvalidateRect(hwnd, &dividerRect, FALSE);\n        }\n        else if (Context->AnimateDividerFadingOut)\n        {\n            if (Context->DividerHot <= TNP_ANIMATE_DIVIDER_DECREMENT)\n            {\n                Context->DividerHot = 0;\n                Context->AnimateDividerFadingOut = FALSE;\n                KillTimer(hwnd, TNP_TIMER_ANIMATE_DIVIDER);\n            }\n            else\n            {\n                Context->DividerHot -= TNP_ANIMATE_DIVIDER_DECREMENT;\n            }\n\n            InvalidateRect(hwnd, &dividerRect, FALSE);\n        }\n    }\n}\n\nVOID PhTnpOnMouseMove(\n    _In_ HWND hwnd,\n    _In_ PPH_TREENEW_CONTEXT Context,\n    _In_ ULONG VirtualKeys,\n    _In_ LONG CursorX,\n    _In_ LONG CursorY\n    )\n{\n    TRACKMOUSEEVENT trackMouseEvent;\n\n    trackMouseEvent.cbSize = sizeof(TRACKMOUSEEVENT);\n    trackMouseEvent.dwFlags = TME_LEAVE;\n    trackMouseEvent.hwndTrack = hwnd;\n    trackMouseEvent.dwHoverTime = 0;\n    TrackMouseEvent(&trackMouseEvent);\n\n    if (Context->Tracking)\n    {\n        ULONG newFixedWidth;\n\n        newFixedWidth = Context->TrackOldFixedWidth + (CursorX - Context->TrackStartX);\n        PhTnpSetFixedWidth(Context, newFixedWidth);\n    }\n\n    PhTnpProcessMoveMouse(Context, CursorX, CursorY);\n}\n\nVOID PhTnpOnMouseLeave(\n    _In_ HWND hwnd,\n    _In_ PPH_TREENEW_CONTEXT Context\n    )\n{\n    RECT rect;\n\n    if (Context->HotNodeIndex != -1 && Context->ThemeData)\n    {\n        // Update the old hot node because it may have a different non-hot background and plus minus part.\n        if (PhTnpGetRowRects(Context, Context->HotNodeIndex, Context->HotNodeIndex, TRUE, &rect))\n        {\n            InvalidateRect(Context->Handle, &rect, FALSE);\n        }\n    }\n\n    Context->HotNodeIndex = -1;\n\n    if (Context->AnimateDivider && Context->FixedDividerVisible)\n    {\n        if ((Context->DividerHot != 0 || Context->AnimateDividerFadingIn) && !Context->AnimateDividerFadingOut)\n        {\n            // Fade out the divider.\n            Context->AnimateDividerFadingOut = TRUE;\n            Context->AnimateDividerFadingIn = FALSE;\n            SetTimer(Context->Handle, TNP_TIMER_ANIMATE_DIVIDER, TNP_ANIMATE_DIVIDER_INTERVAL, NULL);\n        }\n    }\n}\n\nVOID PhTnpOnXxxButtonXxx(\n    _In_ HWND hwnd,\n    _In_ PPH_TREENEW_CONTEXT Context,\n    _In_ ULONG Message,\n    _In_ ULONG VirtualKeys,\n    _In_ LONG CursorX,\n    _In_ LONG CursorY\n    )\n{\n    BOOLEAN startingTracking;\n    PH_TREENEW_HIT_TEST hitTest;\n    LOGICAL controlKey;\n    LOGICAL shiftKey;\n    RECT rect;\n    ULONG changedStart;\n    ULONG changedEnd;\n    PH_TREENEW_MESSAGE clickMessage;\n\n    // Focus\n\n    if (Message == WM_LBUTTONDOWN || Message == WM_RBUTTONDOWN)\n        SetFocus(hwnd);\n\n    // Divider tracking\n\n    startingTracking = FALSE;\n\n    switch (Message)\n    {\n    case WM_LBUTTONDOWN:\n        {\n            if (TNP_HIT_TEST_FIXED_DIVIDER(CursorX, Context))\n            {\n                startingTracking = TRUE;\n                Context->Tracking = TRUE;\n                Context->TrackStartX = CursorX;\n                Context->TrackOldFixedWidth = Context->FixedWidth;\n                SetCapture(hwnd);\n\n                SetTimer(hwnd, TNP_TIMER_NULL, 100, NULL); // make sure we get messages once in a while so we can detect the escape key\n                GetAsyncKeyState(VK_ESCAPE);\n            }\n        }\n        break;\n    case WM_LBUTTONUP:\n        {\n            if (Context->Tracking)\n            {\n                ReleaseCapture();\n            }\n        }\n        break;\n    case WM_RBUTTONDOWN:\n        {\n            if (Context->Tracking)\n            {\n                PhTnpCancelTrack(Context);\n            }\n        }\n        break;\n    }\n\n    if (!startingTracking && Context->Tracking) // still OK to process further if the user is only starting to drag the divider\n        return;\n\n    hitTest.Point.x = CursorX;\n    hitTest.Point.y = CursorY;\n    hitTest.InFlags = TN_TEST_COLUMN | TN_TEST_SUBITEM;\n    PhTnpHitTest(Context, &hitTest);\n\n    controlKey = VirtualKeys & MK_CONTROL;\n    shiftKey = VirtualKeys & MK_SHIFT;\n\n    // Plus minus glyph\n\n    if ((hitTest.Flags & TN_HIT_ITEM_PLUSMINUS) && Message == WM_LBUTTONDOWN)\n    {\n        PhTnpSetExpandedNode(Context, hitTest.Node, !hitTest.Node->Expanded);\n    }\n\n    // Selection\n\n    if (!(hitTest.Flags & TN_HIT_ITEM_PLUSMINUS) && (Message == WM_LBUTTONDOWN || Message == WM_RBUTTONDOWN))\n    {\n        LOGICAL allowDragSelect;\n        PH_TREENEW_CELL_PARTS parts;\n\n        PhTnpPopTooltip(Context);\n        allowDragSelect = TRUE;\n\n        if (hitTest.Flags & TN_HIT_ITEM)\n        {\n            allowDragSelect = FALSE;\n            Context->FocusNode = hitTest.Node;\n\n            if (Context->ExtendedFlags & TN_FLAG_ITEM_DRAG_SELECT)\n            {\n                // To allow drag selection to begin even if the cursor is on an item, we check if\n                // the cursor is on the item icon or text. Exceptions are:\n                // * When the item is already selected\n                // * When user is beginning to drag the divider\n\n                if (!hitTest.Node->Selected && !startingTracking)\n                {\n                    if (PhTnpGetCellParts(Context, hitTest.Node->Index, hitTest.Column, TN_MEASURE_TEXT, &parts))\n                    {\n                        allowDragSelect = TRUE;\n\n                        if ((parts.Flags & TN_PART_ICON) && CursorX >= parts.IconRect.left && CursorX < parts.IconRect.right)\n                            allowDragSelect = FALSE;\n\n                        if ((parts.Flags & TN_PART_CONTENT) && (parts.Flags & TN_PART_TEXT))\n                        {\n                            if (CursorX >= parts.TextRect.left && CursorX < parts.TextRect.right)\n                                allowDragSelect = FALSE;\n                        }\n                    }\n                }\n            }\n\n            PhTnpProcessSelectNode(Context, hitTest.Node, controlKey, shiftKey, Message == WM_RBUTTONDOWN);\n        }\n\n        if (allowDragSelect)\n        {\n            BOOLEAN dragSelect;\n            ULONG indexToSelect;\n            BOOLEAN selectionProcessed;\n            BOOLEAN showContextMenu;\n\n            dragSelect = FALSE;\n            indexToSelect = -1;\n            selectionProcessed = FALSE;\n            showContextMenu = FALSE;\n\n            if (!(hitTest.Flags & (TN_HIT_LEFT | TN_HIT_RIGHT | TN_HIT_ABOVE | TN_HIT_BELOW)) && !startingTracking) // don't interfere with divider\n            {\n                BOOLEAN result;\n                ULONG saveIndex;\n                ULONG saveId;\n                ULONG cancelledByMessage;\n\n                // Check for drag selection. PhTnpDetectDrag has its own message loop, so we need to\n                // clear our pointers before we continue or we will have some access violations when\n                // items get deleted.\n\n                if (hitTest.Node)\n                    saveIndex = hitTest.Node->Index;\n                else\n                    saveIndex = -1;\n\n                if (hitTest.Column)\n                    saveId = hitTest.Column->Id;\n                else\n                    saveId = -1;\n\n                result = PhTnpDetectDrag(Context, CursorX, CursorY, TRUE, &cancelledByMessage);\n\n                // Restore the pointers.\n\n                if (saveIndex == -1)\n                    hitTest.Node = NULL;\n                else if (saveIndex < Context->FlatList->Count)\n                    hitTest.Node = Context->FlatList->Items[saveIndex];\n                else\n                    return;\n\n                if (saveId != -1 && !(hitTest.Column = PhTnpLookupColumnById(Context, saveId)))\n                    return;\n\n                if (result)\n                {\n                    dragSelect = TRUE;\n\n                    if ((hitTest.Flags & TN_HIT_ITEM) && (Context->ExtendedFlags & TN_FLAG_ITEM_DRAG_SELECT))\n                    {\n                        // Include the current node before starting the drag selection, otherwise\n                        // the user will never be able to select the current node.\n                        indexToSelect = hitTest.Node->Index;\n                    }\n                }\n                else\n                {\n                    if ((Message == WM_LBUTTONDOWN && cancelledByMessage == WM_LBUTTONUP) ||\n                        (Message == WM_RBUTTONDOWN && cancelledByMessage == WM_RBUTTONUP))\n                    {\n                        POINT point;\n\n                        if ((hitTest.Flags & TN_HIT_ITEM) && (Context->ExtendedFlags & TN_FLAG_ITEM_DRAG_SELECT))\n                        {\n                            // The user isn't performing a drag selection, so prevent deselection.\n                            selectionProcessed = TRUE;\n                        }\n\n                        // The button up message gets consumed by PhTnpDetectDrag, so send the mouse\n                        // event here.\n                        // Check if the cursor stayed in the same place.\n\n                        PhTnpGetMessagePos(Context->Handle, &point);\n\n                        if (point.x == CursorX && point.y == CursorY)\n                        {\n                            PhTnpSendMouseEvent(\n                                Context,\n                                Message == WM_LBUTTONDOWN ? TreeNewLeftClick : TreeNewRightClick,\n                                CursorX,\n                                CursorY,\n                                hitTest.Node,\n                                hitTest.Column,\n                                VirtualKeys\n                                );\n                        }\n\n                        if (Message == WM_RBUTTONDOWN)\n                            showContextMenu = TRUE;\n                    }\n                }\n            }\n\n            if (!selectionProcessed && !controlKey && !shiftKey)\n            {\n                // Nothing: deselect everything.\n\n                PhTnpSelectRange(Context, indexToSelect, indexToSelect, TN_SELECT_RESET, &changedStart, &changedEnd);\n\n                if (PhTnpGetRowRects(Context, changedStart, changedEnd, TRUE, &rect))\n                {\n                    InvalidateRect(hwnd, &rect, FALSE);\n                }\n            }\n\n            if (dragSelect)\n            {\n                PhTnpDragSelect(Context, CursorX, CursorY);\n            }\n\n            if (showContextMenu)\n            {\n                SendMessage(Context->Handle, WM_CONTEXTMENU, (WPARAM)Context->Handle, GetMessagePos());\n            }\n\n            return;\n        }\n    }\n\n    // Click, double-click\n    // Note: If TN_FLAG_ITEM_DRAG_SELECT is enabled, the code below that processes WM_xBUTTONDOWN\n    // and WM_xBUTTONUP messages only takes effect when the user clicks directly on an item's icon\n    // or text.\n\n    clickMessage = -1;\n\n    if (Message == WM_LBUTTONDOWN || Message == WM_RBUTTONDOWN)\n    {\n        if (Context->MouseDownLast != 0 && Context->MouseDownLast != Message)\n        {\n            // User pressed one button and pressed the other without letting go of the first one.\n            // This counts as a click.\n\n            if (Context->MouseDownLast == WM_LBUTTONDOWN)\n                clickMessage = TreeNewLeftClick;\n            else\n                clickMessage = TreeNewRightClick;\n        }\n\n        Context->MouseDownLast = Message;\n        Context->MouseDownLocation.x = CursorX;\n        Context->MouseDownLocation.y = CursorY;\n    }\n    else if (Message == WM_LBUTTONUP || Message == WM_RBUTTONUP)\n    {\n        if (Context->MouseDownLast != 0 &&\n            Context->MouseDownLocation.x == CursorX && Context->MouseDownLocation.y == CursorY)\n        {\n            if (Context->MouseDownLast == WM_LBUTTONDOWN)\n                clickMessage = TreeNewLeftClick;\n            else\n                clickMessage = TreeNewRightClick;\n        }\n\n        Context->MouseDownLast = 0;\n    }\n    else if (Message == WM_LBUTTONDBLCLK)\n    {\n        clickMessage = TreeNewLeftDoubleClick;\n    }\n    else if (Message == WM_RBUTTONDBLCLK)\n    {\n        clickMessage = TreeNewRightDoubleClick;\n    }\n\n    if (!(hitTest.Flags & TN_HIT_ITEM_PLUSMINUS) && clickMessage != -1)\n    {\n        PhTnpSendMouseEvent(Context, clickMessage, CursorX, CursorY, hitTest.Node, hitTest.Column, VirtualKeys);\n    }\n}\n\nVOID PhTnpOnCaptureChanged(\n    _In_ HWND hwnd,\n    _In_ PPH_TREENEW_CONTEXT Context\n    )\n{\n    Context->Tracking = FALSE;\n    KillTimer(hwnd, TNP_TIMER_NULL);\n}\n\nVOID PhTnpOnKeyDown(\n    _In_ HWND hwnd,\n    _In_ PPH_TREENEW_CONTEXT Context,\n    _In_ ULONG VirtualKey,\n    _In_ ULONG Data\n    )\n{\n    PH_TREENEW_KEY_EVENT keyEvent;\n\n    keyEvent.Handled = FALSE;\n    keyEvent.VirtualKey = VirtualKey;\n    keyEvent.Data = Data;\n    Context->Callback(Context->Handle, TreeNewKeyDown, &keyEvent, NULL, Context->CallbackContext);\n\n    if (keyEvent.Handled)\n        return;\n\n    if (PhTnpProcessFocusKey(Context, VirtualKey))\n        return;\n    if (PhTnpProcessNodeKey(Context, VirtualKey))\n        return;\n}\n\nVOID PhTnpOnChar(\n    _In_ HWND hwnd,\n    _In_ PPH_TREENEW_CONTEXT Context,\n    _In_ ULONG Character,\n    _In_ ULONG Data\n    )\n{\n    // Make sure the character is printable.\n    if (Character >= ' ' && Character <= '~')\n    {\n        PhTnpProcessSearchKey(Context, Character);\n    }\n}\n\nVOID PhTnpOnMouseWheel(\n    _In_ HWND hwnd,\n    _In_ PPH_TREENEW_CONTEXT Context,\n    _In_ LONG Distance,\n    _In_ ULONG VirtualKeys,\n    _In_ LONG CursorX,\n    _In_ LONG CursorY\n    )\n{\n    // The normal mouse wheel can affect both the vertical scrollbar and the horizontal scrollbar,\n    // but the vertical scrollbar takes precedence.\n    if (Context->VScrollVisible)\n    {\n        PhTnpProcessMouseVWheel(Context, -Distance);\n    }\n    else if (Context->HScrollVisible)\n    {\n        PhTnpProcessMouseHWheel(Context, -Distance);\n    }\n}\n\nVOID PhTnpOnMouseHWheel(\n    _In_ HWND hwnd,\n    _In_ PPH_TREENEW_CONTEXT Context,\n    _In_ LONG Distance,\n    _In_ ULONG VirtualKeys,\n    _In_ LONG CursorX,\n    _In_ LONG CursorY\n    )\n{\n    PhTnpProcessMouseHWheel(Context, Distance);\n}\n\nVOID PhTnpOnContextMenu(\n    _In_ HWND hwnd,\n    _In_ PPH_TREENEW_CONTEXT Context,\n    _In_ LONG CursorScreenX,\n    _In_ LONG CursorScreenY\n    )\n{\n    POINT clientPoint;\n    BOOLEAN keyboardInvoked;\n    PH_TREENEW_HIT_TEST hitTest;\n    PH_TREENEW_CONTEXT_MENU contextMenu;\n\n    if (CursorScreenX == -1 && CursorScreenY == -1)\n    {\n        ULONG i;\n        BOOLEAN found;\n        RECT windowRect;\n        RECT rect;\n\n        keyboardInvoked = TRUE;\n\n        // Context menu was invoked via keyboard. Display the context menu at the selected item.\n\n        found = FALSE;\n\n        for (i = 0; i < Context->FlatList->Count; i++)\n        {\n            if (((PPH_TREENEW_NODE)Context->FlatList->Items[i])->Selected)\n            {\n                found = TRUE;\n                break;\n            }\n        }\n\n        if (found && PhTnpGetRowRects(Context, i, i, FALSE, &rect) &&\n            rect.top >= Context->ClientRect.top && rect.top < Context->ClientRect.bottom)\n        {\n            clientPoint.x = rect.left + SmallIconWidth / 2;\n            clientPoint.y = rect.top + Context->RowHeight / 2;\n        }\n        else\n        {\n            clientPoint.x = 0;\n            clientPoint.y = 0;\n        }\n\n        GetWindowRect(hwnd, &windowRect);\n        CursorScreenX = windowRect.left + clientPoint.x;\n        CursorScreenY = windowRect.top + clientPoint.y;\n    }\n    else\n    {\n        keyboardInvoked = FALSE;\n\n        clientPoint.x = CursorScreenX;\n        clientPoint.y = CursorScreenY;\n        ScreenToClient(hwnd, &clientPoint);\n\n        if (clientPoint.y < Context->HeaderHeight)\n        {\n            // Already handled by TreeNewHeaderRightClick.\n            return;\n        }\n    }\n\n    hitTest.Point = clientPoint;\n    hitTest.InFlags = TN_TEST_COLUMN;\n    PhTnpHitTest(Context, &hitTest);\n\n    contextMenu.Location.x = CursorScreenX;\n    contextMenu.Location.y = CursorScreenY;\n    contextMenu.ClientLocation = clientPoint;\n    contextMenu.Node = hitTest.Node;\n    contextMenu.Column = hitTest.Column;\n    contextMenu.KeyboardInvoked = keyboardInvoked;\n    Context->Callback(hwnd, TreeNewContextMenu, &contextMenu, NULL, Context->CallbackContext);\n}\n\nVOID PhTnpOnVScroll(\n    _In_ HWND hwnd,\n    _In_ PPH_TREENEW_CONTEXT Context,\n    _In_ ULONG Request,\n    _In_ USHORT Position\n    )\n{\n    SCROLLINFO scrollInfo;\n    LONG oldPosition;\n\n    scrollInfo.cbSize = sizeof(SCROLLINFO);\n    scrollInfo.fMask = SIF_ALL;\n    GetScrollInfo(Context->VScrollHandle, SB_CTL, &scrollInfo);\n    oldPosition = scrollInfo.nPos;\n\n    switch (Request)\n    {\n    case SB_LINEUP:\n        scrollInfo.nPos--;\n        break;\n    case SB_LINEDOWN:\n        scrollInfo.nPos++;\n        break;\n    case SB_PAGEUP:\n        scrollInfo.nPos -= scrollInfo.nPage;\n        break;\n    case SB_PAGEDOWN:\n        scrollInfo.nPos += scrollInfo.nPage;\n        break;\n    case SB_THUMBPOSITION:\n        // Touch scrolling seems to give us Position but not nTrackPos. The problem is that Position\n        // is a 16-bit value, so don't use it if we have too many rows.\n        if (Context->FlatList->Count <= 0xffff)\n            scrollInfo.nPos = Position;\n        break;\n    case SB_THUMBTRACK:\n        scrollInfo.nPos = scrollInfo.nTrackPos;\n        break;\n    case SB_TOP:\n        scrollInfo.nPos = 0;\n        break;\n    case SB_BOTTOM:\n        scrollInfo.nPos = MAXINT;\n        break;\n    }\n\n    scrollInfo.fMask = SIF_POS;\n    SetScrollInfo(Context->VScrollHandle, SB_CTL, &scrollInfo, TRUE);\n    GetScrollInfo(Context->VScrollHandle, SB_CTL, &scrollInfo);\n\n    if (scrollInfo.nPos != oldPosition)\n    {\n        Context->VScrollPosition = scrollInfo.nPos;\n        PhTnpProcessScroll(Context, scrollInfo.nPos - oldPosition, 0);\n    }\n}\n\nVOID PhTnpOnHScroll(\n    _In_ HWND hwnd,\n    _In_ PPH_TREENEW_CONTEXT Context,\n    _In_ ULONG Request,\n    _In_ USHORT Position\n    )\n{\n    SCROLLINFO scrollInfo;\n    LONG oldPosition;\n\n    scrollInfo.cbSize = sizeof(SCROLLINFO);\n    scrollInfo.fMask = SIF_ALL;\n    GetScrollInfo(Context->HScrollHandle, SB_CTL, &scrollInfo);\n    oldPosition = scrollInfo.nPos;\n\n    switch (Request)\n    {\n    case SB_LINELEFT:\n        scrollInfo.nPos -= Context->TextMetrics.tmAveCharWidth;\n        break;\n    case SB_LINERIGHT:\n        scrollInfo.nPos += Context->TextMetrics.tmAveCharWidth;\n        break;\n    case SB_PAGELEFT:\n        scrollInfo.nPos -= scrollInfo.nPage;\n        break;\n    case SB_PAGERIGHT:\n        scrollInfo.nPos += scrollInfo.nPage;\n        break;\n    case SB_THUMBPOSITION:\n        // Touch scrolling seems to give us Position but not nTrackPos. The problem is that Position\n        // is a 16-bit value, so don't use it if we have too many rows.\n        if (Context->FlatList->Count <= 0xffff)\n            scrollInfo.nPos = Position;\n        break;\n    case SB_THUMBTRACK:\n        scrollInfo.nPos = scrollInfo.nTrackPos;\n        break;\n    case SB_LEFT:\n        scrollInfo.nPos = 0;\n        break;\n    case SB_RIGHT:\n        scrollInfo.nPos = MAXINT;\n        break;\n    }\n\n    scrollInfo.fMask = SIF_POS;\n    SetScrollInfo(Context->HScrollHandle, SB_CTL, &scrollInfo, TRUE);\n    GetScrollInfo(Context->HScrollHandle, SB_CTL, &scrollInfo);\n\n    if (scrollInfo.nPos != oldPosition)\n    {\n        Context->HScrollPosition = scrollInfo.nPos;\n        PhTnpProcessScroll(Context, 0, scrollInfo.nPos - oldPosition);\n    }\n}\n\nBOOLEAN PhTnpOnNotify(\n    _In_ HWND hwnd,\n    _In_ PPH_TREENEW_CONTEXT Context,\n    _In_ NMHDR *Header,\n    _Out_ LRESULT *Result\n    )\n{\n    switch (Header->code)\n    {\n    case HDN_ITEMCHANGING:\n    case HDN_ITEMCHANGED:\n        {\n            NMHEADER *nmHeader = (NMHEADER *)Header;\n\n            if (Header->code == HDN_ITEMCHANGING && Header->hwndFrom == Context->FixedHeaderHandle)\n            {\n                if (nmHeader->pitem->mask & HDI_WIDTH)\n                {\n                    if (Context->FixedColumnVisible)\n                    {\n                        Context->FixedWidth = nmHeader->pitem->cxy - 1;\n\n                        if (Context->FixedWidth < Context->FixedWidthMinimum)\n                            Context->FixedWidth = Context->FixedWidthMinimum;\n\n                        Context->NormalLeft = Context->FixedWidth + 1;\n                        nmHeader->pitem->cxy = Context->FixedWidth + 1;\n                    }\n                    else\n                    {\n                        Context->FixedWidth = 0;\n                        Context->NormalLeft = 0;\n                    }\n                }\n            }\n\n            if (Header->hwndFrom == Context->FixedHeaderHandle || Header->hwndFrom == Context->HeaderHandle)\n            {\n                if (nmHeader->pitem->mask & HDI_WIDTH)\n                {\n                    // A column has been resized. Update our stored information.\n                    PhTnpUpdateColumnHeaders(Context);\n                    PhTnpUpdateColumnMaps(Context);\n\n                    if (Header->code == HDN_ITEMCHANGING)\n                    {\n                        HDITEM item;\n\n                        item.mask = HDI_WIDTH | HDI_LPARAM;\n\n                        if (Header_GetItem(Header->hwndFrom, nmHeader->iItem, &item))\n                        {\n                            Context->ResizingColumn = (PPH_TREENEW_COLUMN)item.lParam;\n                            Context->OldColumnWidth = item.cxy;\n                        }\n                        else\n                        {\n                            Context->ResizingColumn = NULL;\n                            Context->OldColumnWidth = -1;\n                        }\n                    }\n                    else if (Header->code == HDN_ITEMCHANGED)\n                    {\n                        if (Context->ResizingColumn)\n                        {\n                            LONG delta;\n\n                            delta = nmHeader->pitem->cxy - Context->OldColumnWidth;\n\n                            if (delta != 0)\n                            {\n                                PhTnpProcessResizeColumn(Context, Context->ResizingColumn, delta);\n                                Context->Callback(Context->Handle, TreeNewColumnResized, Context->ResizingColumn, NULL, Context->CallbackContext);\n                            }\n\n                            Context->ResizingColumn = NULL;\n\n                            // Redraw the entire window if we are displaying empty text.\n                            if (Context->FlatList->Count == 0 && Context->EmptyText.Length != 0)\n                                InvalidateRect(Context->Handle, NULL, FALSE);\n                        }\n                        else\n                        {\n                            // An error occurred during HDN_ITEMCHANGED, so redraw the entire window.\n                            InvalidateRect(Context->Handle, NULL, FALSE);\n                        }\n                    }\n                }\n            }\n        }\n        break;\n    case HDN_ITEMCLICK:\n        {\n            if ((Header->hwndFrom == Context->FixedHeaderHandle || Header->hwndFrom == Context->HeaderHandle) &&\n                !(Context->Style & TN_STYLE_NO_COLUMN_SORT))\n            {\n                NMHEADER *nmHeader = (NMHEADER *)Header;\n                HDITEM item;\n                PPH_TREENEW_COLUMN column;\n\n                // A column has been clicked, so update the sort state.\n\n                item.mask = HDI_LPARAM;\n\n                if (Header_GetItem(Header->hwndFrom, nmHeader->iItem, &item))\n                {\n                    column = (PPH_TREENEW_COLUMN)item.lParam;\n                    PhTnpProcessSortColumn(Context, column);\n                }\n            }\n        }\n        break;\n    case HDN_ENDDRAG:\n    case NM_RELEASEDCAPTURE:\n        {\n            if (Header->hwndFrom == Context->HeaderHandle)\n            {\n                // Columns have been re-ordered, so refresh our information.\n                // Note: The fixed column cannot be re-ordered.\n                PhTnpUpdateColumnHeaders(Context);\n                PhTnpUpdateColumnMaps(Context);\n                Context->Callback(Context->Handle, TreeNewColumnReordered, NULL, NULL, Context->CallbackContext);\n                InvalidateRect(Context->Handle, NULL, FALSE);\n            }\n        }\n        break;\n    case HDN_DIVIDERDBLCLICK:\n        {\n            if (Header->hwndFrom == Context->FixedHeaderHandle || Header->hwndFrom == Context->HeaderHandle)\n            {\n                NMHEADER *nmHeader = (NMHEADER *)Header;\n                HDITEM item;\n\n                if (Context->SuspendUpdateStructure)\n                    break;\n\n                item.mask = HDI_LPARAM;\n\n                if (Header_GetItem(Header->hwndFrom, nmHeader->iItem, &item))\n                {\n                    PhTnpAutoSizeColumnHeader(\n                        Context,\n                        Header->hwndFrom,\n                        (PPH_TREENEW_COLUMN)item.lParam,\n                        0\n                        );\n                }\n            }\n        }\n        break;\n    case NM_RCLICK:\n        {\n            if (Header->hwndFrom == Context->FixedHeaderHandle || Header->hwndFrom == Context->HeaderHandle)\n            {\n                PH_TREENEW_HEADER_MOUSE_EVENT mouseEvent;\n                ULONG position;\n\n                position = GetMessagePos();\n                mouseEvent.ScreenLocation.x = GET_X_LPARAM(position);\n                mouseEvent.ScreenLocation.y = GET_Y_LPARAM(position);\n\n                mouseEvent.Location = mouseEvent.ScreenLocation;\n                ScreenToClient(hwnd, &mouseEvent.Location);\n                mouseEvent.HeaderLocation = mouseEvent.ScreenLocation;\n                ScreenToClient(Header->hwndFrom, &mouseEvent.HeaderLocation);\n                mouseEvent.Column = PhTnpHitTestHeader(Context, Header->hwndFrom == Context->FixedHeaderHandle, &mouseEvent.HeaderLocation, NULL);\n                Context->Callback(hwnd, TreeNewHeaderRightClick, &mouseEvent, NULL, Context->CallbackContext);\n            }\n        }\n        break;\n    case TTN_GETDISPINFO:\n        {\n            if (Header->hwndFrom == Context->TooltipsHandle)\n            {\n                NMTTDISPINFO *info = (NMTTDISPINFO *)Header;\n                POINT point;\n\n                PhTnpGetMessagePos(hwnd, &point);\n                PhTnpGetTooltipText(Context, &point, &info->lpszText);\n            }\n        }\n        break;\n    case TTN_SHOW:\n        {\n            if (Header->hwndFrom == Context->TooltipsHandle)\n            {\n                *Result = PhTnpPrepareTooltipShow(Context);\n                return TRUE;\n            }\n        }\n        break;\n    case TTN_POP:\n        {\n            if (Header->hwndFrom == Context->TooltipsHandle)\n            {\n                PhTnpPrepareTooltipPop(Context);\n            }\n        }\n        break;\n    }\n\n    return FALSE;\n}\n\nULONG_PTR PhTnpOnUserMessage(\n    _In_ HWND hwnd,\n    _In_ PPH_TREENEW_CONTEXT Context,\n    _In_ ULONG Message,\n    _In_ ULONG_PTR WParam,\n    _In_ ULONG_PTR LParam\n    )\n{\n    switch (Message)\n    {\n    case TNM_SETCALLBACK:\n        {\n            Context->Callback = (PPH_TREENEW_CALLBACK)LParam;\n            Context->CallbackContext = (PVOID)WParam;\n\n            if (!Context->Callback)\n                Context->Callback = PhTnpNullCallback;\n        }\n        return TRUE;\n    case TNM_NODESSTRUCTURED:\n        {\n            if (Context->EnableRedraw <= 0)\n            {\n                Context->SuspendUpdateStructure = TRUE;\n                Context->SuspendUpdateLayout = TRUE;\n                InvalidateRect(Context->Handle, NULL, FALSE);\n                return TRUE;\n            }\n\n            PhTnpRestructureNodes(Context);\n            PhTnpLayout(Context);\n            InvalidateRect(Context->Handle, NULL, FALSE);\n        }\n        return TRUE;\n    case TNM_ADDCOLUMN:\n        return PhTnpAddColumn(Context, (PPH_TREENEW_COLUMN)LParam);\n    case TNM_REMOVECOLUMN:\n        return PhTnpRemoveColumn(Context, (ULONG)WParam);\n    case TNM_GETCOLUMN:\n        return PhTnpCopyColumn(Context, (ULONG)WParam, (PPH_TREENEW_COLUMN)LParam);\n    case TNM_SETCOLUMN:\n        {\n            PPH_TREENEW_COLUMN column = (PPH_TREENEW_COLUMN)LParam;\n\n            return PhTnpChangeColumn(Context, (ULONG)WParam, column->Id, column);\n        }\n        break;\n    case TNM_GETCOLUMNORDERARRAY:\n        {\n            ULONG count = (ULONG)WParam;\n            PULONG order = (PULONG)LParam;\n            ULONG i;\n\n            if (count != Context->NumberOfColumnsByDisplay)\n                return FALSE;\n\n            for (i = 0; i < count; i++)\n            {\n                order[i] = Context->ColumnsByDisplay[i]->Id;\n            }\n        }\n        return TRUE;\n    case TNM_SETCOLUMNORDERARRAY:\n        {\n            ULONG count = (ULONG)WParam;\n            PULONG order = (PULONG)LParam;\n            ULONG i;\n            PULONG newOrder;\n            PPH_TREENEW_COLUMN column;\n\n            newOrder = PhAllocate(count * sizeof(ULONG));\n\n            for (i = 0; i < count; i++)\n            {\n                if (!(column = PhTnpLookupColumnById(Context, order[i])))\n                {\n                    PhFree(newOrder);\n                    return FALSE;\n                }\n\n                newOrder[i] = column->s.ViewIndex;\n            }\n\n            if (!Header_SetOrderArray(Context->HeaderHandle, count, newOrder))\n            {\n                PhFree(newOrder);\n                return FALSE;\n            }\n\n            PhFree(newOrder);\n\n            PhTnpUpdateColumnHeaders(Context);\n            PhTnpUpdateColumnMaps(Context);\n        }\n        return TRUE;\n    case TNM_SETCURSOR:\n        {\n            Context->Cursor = (HCURSOR)LParam;\n        }\n        return TRUE;\n    case TNM_GETSORT:\n        {\n            PULONG sortColumn = (PULONG)WParam;\n            PPH_SORT_ORDER sortOrder = (PPH_SORT_ORDER)LParam;\n\n            if (sortColumn)\n                *sortColumn = Context->SortColumn;\n            if (sortOrder)\n                *sortOrder = Context->SortOrder;\n        }\n        return TRUE;\n    case TNM_SETSORT:\n        {\n            ULONG sortColumn = (ULONG)WParam;\n            PH_SORT_ORDER sortOrder = (PH_SORT_ORDER)LParam;\n            PPH_TREENEW_COLUMN column;\n\n            if (sortOrder != NoSortOrder)\n            {\n                if (!(column = PhTnpLookupColumnById(Context, sortColumn)))\n                    return FALSE;\n            }\n            else\n            {\n                sortColumn = 0;\n                column = NULL;\n            }\n\n            Context->SortColumn = sortColumn;\n            Context->SortOrder = sortOrder;\n\n            PhTnpSetColumnHeaderSortIcon(Context, column);\n\n            Context->Callback(Context->Handle, TreeNewSortChanged, NULL, NULL, Context->CallbackContext);\n        }\n        return TRUE;\n    case TNM_SETTRISTATE:\n        Context->TriState = !!WParam;\n        return TRUE;\n    case TNM_ENSUREVISIBLE:\n        return PhTnpEnsureVisibleNode(Context, ((PPH_TREENEW_NODE)LParam)->Index);\n    case TNM_SCROLL:\n        PhTnpScroll(Context, (LONG)WParam, (LONG)LParam);\n        return TRUE;\n    case TNM_GETFLATNODECOUNT:\n        if (!Context->SuspendUpdateStructure)\n            return (LRESULT)Context->FlatList->Count;\n        else\n            return 0;\n    case TNM_GETFLATNODE:\n        {\n            ULONG index = (ULONG)WParam;\n\n            if (index >= Context->FlatList->Count)\n                return (LRESULT)NULL;\n\n            return (LRESULT)Context->FlatList->Items[index];\n        }\n        break;\n    case TNM_GETCELLTEXT:\n        {\n            PPH_TREENEW_GET_CELL_TEXT getCellText = (PPH_TREENEW_GET_CELL_TEXT)LParam;\n\n            return PhTnpGetCellText(\n                Context,\n                getCellText->Node,\n                getCellText->Id,\n                &getCellText->Text\n                );\n        }\n        break;\n    case TNM_SETNODEEXPANDED:\n        PhTnpSetExpandedNode(Context, (PPH_TREENEW_NODE)LParam, !!WParam);\n        return TRUE;\n    case TNM_GETMAXID:\n        return (LRESULT)(Context->NextId - 1);\n    case TNM_SETMAXID:\n        {\n            ULONG maxId = (ULONG)WParam;\n\n            if (Context->NextId < maxId + 1)\n            {\n                Context->NextId = maxId + 1;\n\n                if (Context->AllocatedColumns < Context->NextId)\n                {\n                    PhTnpExpandAllocatedColumns(Context);\n                }\n            }\n        }\n        return TRUE;\n    case TNM_INVALIDATENODE:\n        {\n            PPH_TREENEW_NODE node = (PPH_TREENEW_NODE)LParam;\n            RECT rect;\n\n            if (!node->Visible)\n                return FALSE;\n\n            if (!PhTnpGetRowRects(Context, node->Index, node->Index, TRUE, &rect))\n                return FALSE;\n\n            InvalidateRect(hwnd, &rect, FALSE);\n        }\n        return TRUE;\n    case TNM_INVALIDATENODES:\n        {\n            RECT rect;\n\n            if (!PhTnpGetRowRects(Context, (ULONG)WParam, (ULONG)LParam, TRUE, &rect))\n                return FALSE;\n\n            InvalidateRect(hwnd, &rect, FALSE);\n        }\n        return TRUE;\n    case TNM_GETFIXEDHEADER:\n        return (LRESULT)Context->FixedHeaderHandle;\n    case TNM_GETHEADER:\n        return (LRESULT)Context->HeaderHandle;\n    case TNM_GETTOOLTIPS:\n        return (LRESULT)Context->TooltipsHandle;\n    case TNM_SELECTRANGE:\n    case TNM_DESELECTRANGE:\n        {\n            ULONG flags;\n            ULONG changedStart;\n            ULONG changedEnd;\n            RECT rect;\n\n            flags = 0;\n\n            if (Message == TNM_DESELECTRANGE)\n                flags |= TN_SELECT_DESELECT;\n\n            PhTnpSelectRange(Context, (ULONG)WParam, (ULONG)LParam, flags, &changedStart, &changedEnd);\n\n            if (PhTnpGetRowRects(Context, changedStart, changedEnd, TRUE, &rect))\n            {\n                InvalidateRect(hwnd, &rect, FALSE);\n            }\n        }\n        return TRUE;\n    case TNM_GETCOLUMNCOUNT:\n        return (LRESULT)Context->NumberOfColumns;\n    case TNM_SETREDRAW:\n        PhTnpSetRedraw(Context, !!WParam);\n        return (LRESULT)Context->EnableRedraw;\n    case TNM_GETVIEWPARTS:\n        {\n            PPH_TREENEW_VIEW_PARTS parts = (PPH_TREENEW_VIEW_PARTS)LParam;\n\n            parts->ClientRect = Context->ClientRect;\n            parts->HeaderHeight = Context->HeaderHeight;\n            parts->RowHeight = Context->RowHeight;\n            parts->VScrollWidth = Context->VScrollVisible ? Context->VScrollWidth : 0;\n            parts->HScrollHeight = Context->HScrollHeight ? Context->HScrollHeight : 0;\n            parts->VScrollPosition = Context->VScrollPosition;\n            parts->HScrollPosition = Context->HScrollPosition;\n            parts->FixedWidth = Context->FixedWidth;\n            parts->NormalLeft = Context->NormalLeft;\n            parts->NormalWidth = Context->TotalViewX;\n        }\n        return TRUE;\n    case TNM_GETFIXEDCOLUMN:\n        return (LRESULT)Context->FixedColumn;\n    case TNM_GETFIRSTCOLUMN:\n        return (LRESULT)Context->FirstColumn;\n    case TNM_SETFOCUSNODE:\n        Context->FocusNode = (PPH_TREENEW_NODE)LParam;\n        return TRUE;\n    case TNM_SETMARKNODE:\n        Context->MarkNodeIndex = ((PPH_TREENEW_NODE)LParam)->Index;\n        return TRUE;\n    case TNM_SETHOTNODE:\n        PhTnpSetHotNode(Context, (PPH_TREENEW_NODE)LParam, FALSE);\n        return TRUE;\n    case TNM_SETEXTENDEDFLAGS:\n        Context->ExtendedFlags = (Context->ExtendedFlags & ~(ULONG)WParam) | ((ULONG)LParam & (ULONG)WParam);\n        return TRUE;\n    case TNM_GETCALLBACK:\n        {\n            PPH_TREENEW_CALLBACK *callback = (PPH_TREENEW_CALLBACK *)LParam;\n            PVOID *callbackContext = (PVOID *)WParam;\n\n            if (callback)\n            {\n                if (Context->Callback != PhTnpNullCallback)\n                    *callback = Context->Callback;\n                else\n                    *callback = NULL;\n            }\n\n            if (callbackContext)\n            {\n                *callbackContext = Context->CallbackContext;\n            }\n        }\n        return TRUE;\n    case TNM_HITTEST:\n        PhTnpHitTest(Context, (PPH_TREENEW_HIT_TEST)LParam);\n        return TRUE;\n    case TNM_GETVISIBLECOLUMNCOUNT:\n        return Context->NumberOfColumnsByDisplay + (Context->FixedColumnVisible ? 1 : 0);\n    case TNM_AUTOSIZECOLUMN:\n        {\n            ULONG id = (ULONG)WParam;\n            ULONG flags = (ULONG)LParam;\n            PPH_TREENEW_COLUMN column;\n\n            if (!(column = PhTnpLookupColumnById(Context, id)))\n                return FALSE;\n\n            if (!column->Visible)\n                return FALSE;\n\n            PhTnpAutoSizeColumnHeader(\n                Context,\n                column->Fixed ? Context->FixedHeaderHandle : Context->HeaderHandle,\n                column,\n                flags\n                );\n        }\n        return TRUE;\n    case TNM_SETEMPTYTEXT:\n        {\n            PPH_STRINGREF text = (PPH_STRINGREF)LParam;\n            ULONG flags = (ULONG)WParam;\n\n            Context->EmptyText = *text;\n        }\n        return TRUE;\n    case TNM_SETROWHEIGHT:\n        {\n            LONG rowHeight = (LONG)WParam;\n\n            if (rowHeight != 0)\n            {\n                Context->CustomRowHeight = TRUE;\n                Context->RowHeight = rowHeight;\n            }\n            else\n            {\n                Context->CustomRowHeight = FALSE;\n                PhTnpUpdateTextMetrics(Context);\n            }\n        }\n        return TRUE;\n    case TNM_ISFLATNODEVALID:\n        return !Context->SuspendUpdateStructure;\n    }\n\n    return 0;\n}\n\nVOID PhTnpSetFont(\n    _In_ PPH_TREENEW_CONTEXT Context,\n    _In_opt_ HFONT Font,\n    _In_ BOOLEAN Redraw\n    )\n{\n    if (Context->FontOwned)\n    {\n        DeleteObject(Context->Font);\n        Context->FontOwned = FALSE;\n    }\n\n    Context->Font = Font;\n\n    if (!Context->Font)\n    {\n        LOGFONT logFont;\n\n        if (SystemParametersInfo(SPI_GETICONTITLELOGFONT, sizeof(LOGFONT), &logFont, 0))\n        {\n            Context->Font = CreateFontIndirect(&logFont);\n            Context->FontOwned = TRUE;\n        }\n    }\n\n    SendMessage(Context->FixedHeaderHandle, WM_SETFONT, (WPARAM)Context->Font, Redraw);\n    SendMessage(Context->HeaderHandle, WM_SETFONT, (WPARAM)Context->Font, Redraw);\n\n    if (Context->TooltipsHandle)\n    {\n        SendMessage(Context->TooltipsHandle, WM_SETFONT, (WPARAM)Context->Font, FALSE);\n        Context->TooltipFont = Context->Font;\n    }\n\n    PhTnpUpdateTextMetrics(Context);\n}\n\nVOID PhTnpUpdateSystemMetrics(\n    _In_ PPH_TREENEW_CONTEXT Context\n    )\n{\n    Context->VScrollWidth = GetSystemMetrics(SM_CXVSCROLL);\n    Context->HScrollHeight = GetSystemMetrics(SM_CYHSCROLL);\n    Context->SystemBorderX = GetSystemMetrics(SM_CXBORDER);\n    Context->SystemBorderY = GetSystemMetrics(SM_CYBORDER);\n    Context->SystemEdgeX = GetSystemMetrics(SM_CXEDGE);\n    Context->SystemEdgeY = GetSystemMetrics(SM_CYEDGE);\n    Context->SystemDragX = GetSystemMetrics(SM_CXDRAG);\n    Context->SystemDragY = GetSystemMetrics(SM_CYDRAG);\n\n    if (Context->SystemDragX < 2)\n        Context->SystemDragX = 2;\n    if (Context->SystemDragY < 2)\n        Context->SystemDragY = 2;\n}\n\nVOID PhTnpUpdateTextMetrics(\n    _In_ PPH_TREENEW_CONTEXT Context\n    )\n{\n    HDC hdc;\n\n    if (hdc = GetDC(Context->Handle))\n    {\n        SelectObject(hdc, Context->Font);\n        GetTextMetrics(hdc, &Context->TextMetrics);\n\n        if (!Context->CustomRowHeight)\n        {\n            // Below we try to match the row height as calculated by the list view, even if it\n            // involves magic numbers. On Vista and above there seems to be extra padding.\n\n            Context->RowHeight = Context->TextMetrics.tmHeight;\n\n            if (Context->Style & TN_STYLE_ICONS)\n            {\n                if (Context->RowHeight < SmallIconHeight)\n                    Context->RowHeight = SmallIconHeight;\n            }\n            else\n            {\n                if (!(Context->Style & TN_STYLE_THIN_ROWS))\n                    Context->RowHeight += 1; // HACK\n            }\n\n            Context->RowHeight += 1; // HACK\n\n            if (!(Context->Style & TN_STYLE_THIN_ROWS))\n                Context->RowHeight += 2; // HACK\n        }\n\n        ReleaseDC(Context->Handle, hdc);\n    }\n}\n\nVOID PhTnpUpdateThemeData(\n    _In_ PPH_TREENEW_CONTEXT Context\n    )\n{\n    Context->ThemeActive = !!IsThemeActive();\n\n    if (Context->ThemeData)\n    {\n        CloseThemeData(Context->ThemeData);\n        Context->ThemeData = NULL;\n    }\n\n    Context->ThemeData = OpenThemeData(Context->Handle, L\"TREEVIEW\");\n\n    if (Context->ThemeData)\n    {\n        Context->ThemeHasItemBackground = !!IsThemePartDefined(Context->ThemeData, TVP_TREEITEM, 0);\n        Context->ThemeHasGlyph = !!IsThemePartDefined(Context->ThemeData, TVP_GLYPH, 0);\n        Context->ThemeHasHotGlyph = !!IsThemePartDefined(Context->ThemeData, TVP_HOTGLYPH, 0);\n    }\n    else\n    {\n        Context->ThemeHasItemBackground = FALSE;\n        Context->ThemeHasGlyph = FALSE;\n        Context->ThemeHasHotGlyph = FALSE;\n    }\n}\n\nVOID PhTnpInitializeThemeData(\n    _In_ PPH_TREENEW_CONTEXT Context\n    )\n{\n    if (!Context->ThemeInitialized)\n    {\n        PhTnpUpdateThemeData(Context);\n        Context->ThemeInitialized = TRUE;\n    }\n}\n\nVOID PhTnpCancelTrack(\n    _In_ PPH_TREENEW_CONTEXT Context\n    )\n{\n    PhTnpSetFixedWidth(Context, Context->TrackOldFixedWidth);\n    ReleaseCapture();\n}\n\nVOID PhTnpLayout(\n    _In_ PPH_TREENEW_CONTEXT Context\n    )\n{\n    RECT clientRect;\n\n    if (Context->EnableRedraw <= 0)\n    {\n        Context->SuspendUpdateLayout = TRUE;\n        return;\n    }\n\n    clientRect = Context->ClientRect;\n\n    PhTnpUpdateScrollBars(Context);\n\n    // Vertical scroll bar\n    if (Context->VScrollVisible)\n    {\n        MoveWindow(\n            Context->VScrollHandle,\n            clientRect.right - Context->VScrollWidth,\n            0,\n            Context->VScrollWidth,\n            clientRect.bottom - (Context->HScrollVisible ? Context->HScrollHeight : 0),\n            TRUE\n            );\n    }\n\n    // Horizontal scroll bar\n    if (Context->HScrollVisible)\n    {\n        MoveWindow(\n            Context->HScrollHandle,\n            Context->NormalLeft,\n            clientRect.bottom - Context->HScrollHeight,\n            clientRect.right - Context->NormalLeft - (Context->VScrollVisible ? Context->VScrollWidth : 0),\n            Context->HScrollHeight,\n            TRUE\n            );\n    }\n\n    // Filler box\n    if (Context->VScrollVisible && Context->HScrollVisible)\n    {\n        MoveWindow(\n            Context->FillerBoxHandle,\n            clientRect.right - Context->VScrollWidth,\n            clientRect.bottom - Context->HScrollHeight,\n            Context->VScrollWidth,\n            Context->HScrollHeight,\n            TRUE\n            );\n    }\n\n    PhTnpLayoutHeader(Context);\n\n    // Redraw the entire window if we are displaying empty text.\n    if (Context->FlatList->Count == 0 && Context->EmptyText.Length != 0)\n        InvalidateRect(Context->Handle, NULL, FALSE);\n}\n\nVOID PhTnpLayoutHeader(\n    _In_ PPH_TREENEW_CONTEXT Context\n    )\n{\n    RECT rect;\n    HDLAYOUT hdl;\n    WINDOWPOS windowPos;\n\n    hdl.prc = &rect;\n    hdl.pwpos = &windowPos;\n\n    if (!(Context->Style & TN_STYLE_NO_COLUMN_HEADER))\n    {\n        // Fixed portion header control\n        rect.left = 0;\n        rect.top = 0;\n        rect.right = Context->NormalLeft;\n        rect.bottom = Context->ClientRect.bottom;\n        Header_Layout(Context->FixedHeaderHandle, &hdl);\n        SetWindowPos(Context->FixedHeaderHandle, NULL, windowPos.x, windowPos.y, windowPos.cx, windowPos.cy, windowPos.flags);\n        Context->HeaderHeight = windowPos.cy;\n\n        // Normal portion header control\n        rect.left = Context->NormalLeft - Context->HScrollPosition;\n        rect.top = 0;\n        rect.right = Context->ClientRect.right - (Context->VScrollVisible ? Context->VScrollWidth : 0);\n        rect.bottom = Context->ClientRect.bottom;\n        Header_Layout(Context->HeaderHandle, &hdl);\n        SetWindowPos(Context->HeaderHandle, NULL, windowPos.x, windowPos.y, windowPos.cx, windowPos.cy, windowPos.flags);\n    }\n    else\n    {\n        Context->HeaderHeight = 0;\n    }\n\n    if (Context->TooltipsHandle)\n    {\n        TOOLINFO toolInfo;\n\n        memset(&toolInfo, 0, sizeof(TOOLINFO));\n        toolInfo.cbSize = sizeof(TOOLINFO);\n        toolInfo.hwnd = Context->FixedHeaderHandle;\n        toolInfo.uId = TNP_TOOLTIPS_FIXED_HEADER;\n        GetClientRect(Context->FixedHeaderHandle, &toolInfo.rect);\n        SendMessage(Context->TooltipsHandle, TTM_NEWTOOLRECT, 0, (LPARAM)&toolInfo);\n\n        toolInfo.hwnd = Context->HeaderHandle;\n        toolInfo.uId = TNP_TOOLTIPS_HEADER;\n        GetClientRect(Context->HeaderHandle, &toolInfo.rect);\n        SendMessage(Context->TooltipsHandle, TTM_NEWTOOLRECT, 0, (LPARAM)&toolInfo);\n    }\n}\n\nVOID PhTnpSetFixedWidth(\n    _In_ PPH_TREENEW_CONTEXT Context,\n    _In_ ULONG FixedWidth\n    )\n{\n    HDITEM item;\n\n    if (Context->FixedColumnVisible)\n    {\n        Context->FixedWidth = FixedWidth;\n\n        if (Context->FixedWidth < Context->FixedWidthMinimum)\n            Context->FixedWidth = Context->FixedWidthMinimum;\n\n        Context->NormalLeft = Context->FixedWidth + 1;\n\n        item.mask = HDI_WIDTH;\n        item.cxy = Context->FixedWidth + 1;\n        Header_SetItem(Context->FixedHeaderHandle, 0, &item);\n    }\n    else\n    {\n        Context->FixedWidth = 0;\n        Context->NormalLeft = 0;\n    }\n}\n\nVOID PhTnpSetRedraw(\n    _In_ PPH_TREENEW_CONTEXT Context,\n    _In_ BOOLEAN Redraw\n    )\n{\n    if (Redraw)\n        Context->EnableRedraw++;\n    else\n        Context->EnableRedraw--;\n\n    if (Context->EnableRedraw == 1)\n    {\n        if (Context->SuspendUpdateStructure)\n        {\n            PhTnpRestructureNodes(Context);\n        }\n\n        if (Context->SuspendUpdateLayout)\n        {\n            PhTnpLayout(Context);\n        }\n\n        if (Context->SuspendUpdateMoveMouse)\n        {\n            POINT point;\n\n            PhTnpGetMessagePos(Context->Handle, &point);\n            PhTnpProcessMoveMouse(Context, point.x, point.y);\n        }\n\n        Context->SuspendUpdateStructure = FALSE;\n        Context->SuspendUpdateLayout = FALSE;\n        Context->SuspendUpdateMoveMouse = FALSE;\n\n        if (Context->SuspendUpdateRegion)\n        {\n            InvalidateRgn(Context->Handle, Context->SuspendUpdateRegion, FALSE);\n            DeleteObject(Context->SuspendUpdateRegion);\n            Context->SuspendUpdateRegion = NULL;\n        }\n    }\n}\n\nVOID PhTnpSendMouseEvent(\n    _In_ PPH_TREENEW_CONTEXT Context,\n    _In_ PH_TREENEW_MESSAGE Message,\n    _In_ LONG CursorX,\n    _In_ LONG CursorY,\n    _In_ PPH_TREENEW_NODE Node,\n    _In_ PPH_TREENEW_COLUMN Column,\n    _In_ ULONG VirtualKeys\n    )\n{\n    PH_TREENEW_MOUSE_EVENT mouseEvent;\n\n    mouseEvent.Location.x = CursorX;\n    mouseEvent.Location.y = CursorY;\n    mouseEvent.Node = Node;\n    mouseEvent.Column = Column;\n    mouseEvent.KeyFlags = VirtualKeys;\n    Context->Callback(Context->Handle, Message, &mouseEvent, NULL, Context->CallbackContext);\n}\n\nPPH_TREENEW_COLUMN PhTnpLookupColumnById(\n    _In_ PPH_TREENEW_CONTEXT Context,\n    _In_ ULONG Id\n    )\n{\n    if (Id >= Context->AllocatedColumns)\n        return NULL;\n\n    return Context->Columns[Id];\n}\n\nBOOLEAN PhTnpAddColumn(\n    _In_ PPH_TREENEW_CONTEXT Context,\n    _In_ PPH_TREENEW_COLUMN Column\n    )\n{\n    PPH_TREENEW_COLUMN realColumn;\n\n    // Check if a column with the same ID already exists.\n    if (Column->Id < Context->AllocatedColumns && Context->Columns[Column->Id])\n        return FALSE;\n\n    if (Context->NextId < Column->Id + 1)\n        Context->NextId = Column->Id + 1;\n\n    realColumn = PhAllocateCopy(Column, sizeof(PH_TREENEW_COLUMN));\n\n    if (realColumn->DpiScaleOnAdd)\n    {\n        realColumn->Width = PhMultiplyDivide(realColumn->Width, PhGlobalDpi, 96);\n        realColumn->DpiScaleOnAdd = FALSE;\n    }\n\n    if (Context->AllocatedColumns < Context->NextId)\n    {\n        PhTnpExpandAllocatedColumns(Context);\n    }\n\n    Context->Columns[Column->Id] = realColumn;\n    Context->NumberOfColumns++;\n\n    if (realColumn->Fixed)\n    {\n        if (Context->FixedColumn)\n        {\n            // We already have a fixed column, and we can't have two. Make this new column un-fixed.\n            realColumn->Fixed = FALSE;\n        }\n        else\n        {\n            Context->FixedColumn = realColumn;\n        }\n\n        realColumn->DisplayIndex = 0;\n        realColumn->s.ViewX = 0;\n    }\n\n    if (realColumn->Visible)\n    {\n        BOOLEAN updateHeaders;\n\n        updateHeaders = FALSE;\n\n        if (!realColumn->Fixed && realColumn->DisplayIndex != Header_GetItemCount(Context->HeaderHandle))\n            updateHeaders = TRUE;\n\n        realColumn->s.ViewIndex = PhTnpInsertColumnHeader(Context, realColumn);\n\n        if (updateHeaders)\n            PhTnpUpdateColumnHeaders(Context);\n    }\n    else\n    {\n        realColumn->s.ViewIndex = -1;\n    }\n\n    PhTnpUpdateColumnMaps(Context);\n\n    if (realColumn->Visible)\n        PhTnpLayout(Context);\n\n    return TRUE;\n}\n\nBOOLEAN PhTnpRemoveColumn(\n    _In_ PPH_TREENEW_CONTEXT Context,\n    _In_ ULONG Id\n    )\n{\n    PPH_TREENEW_COLUMN realColumn;\n    BOOLEAN updateLayout;\n\n    if (!(realColumn = PhTnpLookupColumnById(Context, Id)))\n        return FALSE;\n\n    updateLayout = FALSE;\n\n    if (realColumn->Visible)\n        updateLayout = TRUE;\n\n    PhTnpDeleteColumnHeader(Context, realColumn);\n    Context->Columns[realColumn->Id] = NULL;\n    PhFree(realColumn);\n    PhTnpUpdateColumnMaps(Context);\n\n    if (updateLayout)\n        PhTnpLayout(Context);\n\n    Context->NumberOfColumns--;\n\n    return TRUE;\n}\n\nBOOLEAN PhTnpCopyColumn(\n    _In_ PPH_TREENEW_CONTEXT Context,\n    _In_ ULONG Id,\n    _Out_ PPH_TREENEW_COLUMN Column\n    )\n{\n    PPH_TREENEW_COLUMN realColumn;\n\n    if (!(realColumn = PhTnpLookupColumnById(Context, Id)))\n        return FALSE;\n\n    memcpy(Column, realColumn, sizeof(PH_TREENEW_COLUMN));\n\n    return TRUE;\n}\n\nBOOLEAN PhTnpChangeColumn(\n    _In_ PPH_TREENEW_CONTEXT Context,\n    _In_ ULONG Mask,\n    _In_ ULONG Id,\n    _In_ PPH_TREENEW_COLUMN Column\n    )\n{\n    PPH_TREENEW_COLUMN realColumn;\n    BOOLEAN addingOrRemoving;\n\n    if (!(realColumn = PhTnpLookupColumnById(Context, Id)))\n        return FALSE;\n\n    addingOrRemoving = FALSE;\n\n    if (Mask & TN_COLUMN_FLAG_VISIBLE)\n    {\n        if (realColumn->Visible != Column->Visible)\n        {\n            addingOrRemoving = TRUE;\n        }\n    }\n\n    if (Mask & TN_COLUMN_FLAG_CUSTOMDRAW)\n    {\n        realColumn->CustomDraw = Column->CustomDraw;\n    }\n\n    if (Mask & TN_COLUMN_FLAG_SORTDESCENDING)\n    {\n        realColumn->SortDescending = Column->SortDescending;\n    }\n\n    if (Mask & (TN_COLUMN_TEXT | TN_COLUMN_WIDTH | TN_COLUMN_ALIGNMENT | TN_COLUMN_DISPLAYINDEX))\n    {\n        BOOLEAN updateHeaders;\n        BOOLEAN updateMaps;\n        BOOLEAN updateLayout;\n\n        updateHeaders = FALSE;\n        updateMaps = FALSE;\n        updateLayout = FALSE;\n\n        if (Mask & TN_COLUMN_TEXT)\n        {\n            realColumn->Text = Column->Text;\n        }\n\n        if (Mask & TN_COLUMN_WIDTH)\n        {\n            realColumn->Width = Column->Width;\n            updateMaps = TRUE;\n        }\n\n        if (Mask & TN_COLUMN_ALIGNMENT)\n        {\n            realColumn->Alignment = Column->Alignment;\n        }\n\n        if (Mask & TN_COLUMN_DISPLAYINDEX)\n        {\n            realColumn->DisplayIndex = Column->DisplayIndex;\n            updateHeaders = TRUE;\n            updateMaps = TRUE;\n            updateLayout = TRUE;\n        }\n\n        if (!addingOrRemoving && realColumn->Visible)\n        {\n            PhTnpChangeColumnHeader(Context, Mask, realColumn);\n\n            if (updateHeaders)\n                PhTnpUpdateColumnHeaders(Context);\n            if (updateMaps)\n                PhTnpUpdateColumnMaps(Context);\n            if (updateLayout)\n                PhTnpLayout(Context);\n        }\n    }\n\n    if (Mask & TN_COLUMN_CONTEXT)\n    {\n        realColumn->Context = Column->Context;\n    }\n\n    if (Mask & TN_COLUMN_TEXTFLAGS)\n    {\n        realColumn->TextFlags = Column->TextFlags;\n    }\n\n    if (addingOrRemoving)\n    {\n        if (Column->Visible)\n        {\n            BOOLEAN updateHeaders;\n\n            updateHeaders = FALSE;\n\n            if (realColumn->Fixed)\n            {\n                realColumn->DisplayIndex = 0;\n            }\n            else\n            {\n                if (Mask & TN_COLUMN_DISPLAYINDEX)\n                    updateHeaders = TRUE;\n                else\n                    realColumn->DisplayIndex = Header_GetItemCount(Context->HeaderHandle);\n            }\n\n            realColumn->s.ViewIndex = PhTnpInsertColumnHeader(Context, realColumn);\n\n            if (updateHeaders)\n                PhTnpUpdateColumnHeaders(Context);\n        }\n        else\n        {\n            PhTnpDeleteColumnHeader(Context, realColumn);\n        }\n\n        PhTnpUpdateColumnMaps(Context);\n        PhTnpLayout(Context);\n    }\n\n    return TRUE;\n}\n\nVOID PhTnpExpandAllocatedColumns(\n    _In_ PPH_TREENEW_CONTEXT Context\n    )\n{\n    if (Context->Columns)\n    {\n        ULONG oldAllocatedColumns;\n\n        oldAllocatedColumns = Context->AllocatedColumns;\n        Context->AllocatedColumns *= 2;\n\n        if (Context->AllocatedColumns < Context->NextId)\n            Context->AllocatedColumns = Context->NextId;\n\n        Context->Columns = PhReAllocate(\n            Context->Columns,\n            Context->AllocatedColumns * sizeof(PPH_TREENEW_COLUMN)\n            );\n\n        // Zero the newly allocated portion.\n        memset(\n            &Context->Columns[oldAllocatedColumns],\n            0,\n            (Context->AllocatedColumns - oldAllocatedColumns) * sizeof(PPH_TREENEW_COLUMN)\n            );\n    }\n    else\n    {\n        Context->AllocatedColumns = 16;\n\n        if (Context->AllocatedColumns < Context->NextId)\n            Context->AllocatedColumns = Context->NextId;\n\n        Context->Columns = PhAllocate(\n            Context->AllocatedColumns * sizeof(PPH_TREENEW_COLUMN)\n            );\n        memset(Context->Columns, 0, Context->AllocatedColumns * sizeof(PPH_TREENEW_COLUMN));\n    }\n}\n\nVOID PhTnpUpdateColumnMaps(\n    _In_ PPH_TREENEW_CONTEXT Context\n    )\n{\n    ULONG i;\n    LONG x;\n\n    if (Context->AllocatedColumnsByDisplay < Context->NumberOfColumns)\n    {\n        if (Context->ColumnsByDisplay)\n            PhFree(Context->ColumnsByDisplay);\n\n        Context->ColumnsByDisplay = PhAllocate(sizeof(PPH_TREENEW_COLUMN) * Context->NumberOfColumns);\n        Context->AllocatedColumnsByDisplay = Context->NumberOfColumns;\n    }\n\n    memset(Context->ColumnsByDisplay, 0, sizeof(PPH_TREENEW_COLUMN) * Context->AllocatedColumnsByDisplay);\n\n    for (i = 0; i < Context->NextId; i++)\n    {\n        if (!Context->Columns[i])\n            continue;\n\n        if (Context->Columns[i]->Visible && !Context->Columns[i]->Fixed && Context->Columns[i]->DisplayIndex != -1)\n        {\n            if (Context->Columns[i]->DisplayIndex >= Context->NumberOfColumns)\n                PhRaiseStatus(STATUS_INTERNAL_ERROR);\n\n            Context->ColumnsByDisplay[Context->Columns[i]->DisplayIndex] = Context->Columns[i];\n        }\n    }\n\n    x = 0;\n\n    for (i = 0; i < Context->AllocatedColumnsByDisplay; i++)\n    {\n        if (!Context->ColumnsByDisplay[i])\n            break;\n\n        Context->ColumnsByDisplay[i]->s.ViewX = x;\n        x += Context->ColumnsByDisplay[i]->Width;\n    }\n\n    Context->NumberOfColumnsByDisplay = i;\n    Context->TotalViewX = x;\n\n    if (Context->FixedColumnVisible)\n        Context->FirstColumn = Context->FixedColumn;\n    else if (Context->NumberOfColumnsByDisplay != 0)\n        Context->FirstColumn = Context->ColumnsByDisplay[0];\n    else\n        Context->FirstColumn = NULL;\n\n    if (Context->NumberOfColumnsByDisplay != 0)\n        Context->LastColumn = Context->ColumnsByDisplay[Context->NumberOfColumnsByDisplay - 1];\n    else if (Context->FixedColumnVisible)\n        Context->LastColumn = Context->FixedColumn;\n    else\n        Context->LastColumn = NULL;\n}\n\nLONG PhTnpInsertColumnHeader(\n    _In_ PPH_TREENEW_CONTEXT Context,\n    _In_ PPH_TREENEW_COLUMN Column\n    )\n{\n    HDITEM item;\n\n    if (Column->Fixed)\n    {\n        if (Column->Width < Context->FixedWidthMinimum)\n            Column->Width = Context->FixedWidthMinimum;\n\n        Context->FixedWidth = Column->Width;\n        Context->NormalLeft = Context->FixedWidth + 1;\n        Context->FixedColumnVisible = TRUE;\n\n        if (!(Context->Style & TN_STYLE_NO_DIVIDER))\n            Context->FixedDividerVisible = TRUE;\n    }\n\n    memset(&item, 0, sizeof(HDITEM));\n    item.mask = HDI_WIDTH | HDI_TEXT | HDI_FORMAT | HDI_LPARAM | HDI_ORDER;\n    item.cxy = Column->Width;\n    item.pszText = Column->Text;\n    item.fmt = 0;\n    item.lParam = (LPARAM)Column;\n\n    if (Column->Fixed)\n        item.cxy++;\n\n    if (Column->Fixed)\n        item.iOrder = 0;\n    else\n        item.iOrder = Column->DisplayIndex;\n\n    if (Column->Alignment & PH_ALIGN_LEFT)\n        item.fmt |= HDF_LEFT;\n    else if (Column->Alignment & PH_ALIGN_RIGHT)\n        item.fmt |= HDF_RIGHT;\n    else\n        item.fmt |= HDF_CENTER;\n\n    if (Column->Id == Context->SortColumn)\n    {\n        if (Context->SortOrder == AscendingSortOrder)\n            item.fmt |= HDF_SORTUP;\n        else if (Context->SortOrder == DescendingSortOrder)\n            item.fmt |= HDF_SORTDOWN;\n    }\n\n    Column->Visible = TRUE;\n\n    if (Column->Fixed)\n        return Header_InsertItem(Context->FixedHeaderHandle, 0, &item);\n    else\n        return Header_InsertItem(Context->HeaderHandle, MAXINT, &item);\n}\n\nVOID PhTnpChangeColumnHeader(\n    _In_ PPH_TREENEW_CONTEXT Context,\n    _In_ ULONG Mask,\n    _In_ PPH_TREENEW_COLUMN Column\n    )\n{\n    HDITEM item;\n\n    memset(&item, 0, sizeof(HDITEM));\n    item.mask = 0;\n\n    if (Mask & TN_COLUMN_TEXT)\n    {\n        item.mask |= HDI_TEXT;\n        item.pszText = Column->Text;\n    }\n\n    if (Mask & TN_COLUMN_WIDTH)\n    {\n        item.mask |= HDI_WIDTH;\n        item.cxy = Column->Width;\n\n        if (Column->Fixed)\n            item.cxy++;\n    }\n\n    if (Mask & TN_COLUMN_ALIGNMENT)\n    {\n        item.mask |= HDI_FORMAT;\n        item.fmt = 0;\n\n        if (Column->Alignment & PH_ALIGN_LEFT)\n            item.fmt |= HDF_LEFT;\n        else if (Column->Alignment & PH_ALIGN_RIGHT)\n            item.fmt |= HDF_RIGHT;\n        else\n            item.fmt |= HDF_CENTER;\n\n        if (Column->Id == Context->SortColumn)\n        {\n            if (Context->SortOrder == AscendingSortOrder)\n                item.fmt |= HDF_SORTUP;\n            else if (Context->SortOrder == DescendingSortOrder)\n                item.fmt |= HDF_SORTDOWN;\n        }\n    }\n\n    if (Mask & TN_COLUMN_DISPLAYINDEX)\n    {\n        item.mask |= HDI_ORDER;\n\n        if (Column->Fixed)\n            item.iOrder = 0;\n        else\n            item.iOrder = Column->DisplayIndex;\n    }\n\n    if (Column->Fixed)\n        Header_SetItem(Context->FixedHeaderHandle, 0, &item);\n    else\n        Header_SetItem(Context->HeaderHandle, Column->s.ViewIndex, &item);\n}\n\nVOID PhTnpDeleteColumnHeader(\n    _In_ PPH_TREENEW_CONTEXT Context,\n    _Inout_ PPH_TREENEW_COLUMN Column\n    )\n{\n    if (Column->Fixed)\n    {\n        Context->FixedColumn = NULL;\n        Context->FixedWidth = 0;\n        Context->NormalLeft = 0;\n        Context->FixedColumnVisible = FALSE;\n        Context->FixedDividerVisible = FALSE;\n    }\n\n    if (Column->Fixed)\n        Header_DeleteItem(Context->FixedHeaderHandle, Column->s.ViewIndex);\n    else\n        Header_DeleteItem(Context->HeaderHandle, Column->s.ViewIndex);\n\n    Column->Visible = FALSE;\n    Column->s.ViewIndex = -1;\n    PhTnpUpdateColumnHeaders(Context);\n}\n\nVOID PhTnpUpdateColumnHeaders(\n    _In_ PPH_TREENEW_CONTEXT Context\n    )\n{\n    ULONG count;\n    ULONG i;\n    HDITEM item;\n    PPH_TREENEW_COLUMN column;\n\n    item.mask = HDI_WIDTH | HDI_LPARAM | HDI_ORDER;\n\n    // Fixed column\n\n    if (Context->FixedColumnVisible && Header_GetItem(Context->FixedHeaderHandle, 0, &item))\n    {\n        column = Context->FixedColumn;\n        column->Width = item.cxy - 1;\n    }\n\n    // Normal columns\n\n    count = Header_GetItemCount(Context->HeaderHandle);\n\n    if (count != -1)\n    {\n        for (i = 0; i < count; i++)\n        {\n            if (Header_GetItem(Context->HeaderHandle, i, &item))\n            {\n                column = (PPH_TREENEW_COLUMN)item.lParam;\n                column->s.ViewIndex = i;\n                column->Width = item.cxy;\n                column->DisplayIndex = item.iOrder;\n            }\n        }\n    }\n}\n\nVOID PhTnpProcessResizeColumn(\n    _In_ PPH_TREENEW_CONTEXT Context,\n    _In_ PPH_TREENEW_COLUMN Column,\n    _In_ LONG Delta\n    )\n{\n    RECT rect;\n    LONG columnLeft;\n\n    if (Column->Fixed)\n    {\n        columnLeft = 0;\n    }\n    else\n    {\n        columnLeft = Context->NormalLeft + Column->s.ViewX - Context->HScrollPosition;\n    }\n\n    // Scroll the content to the right of the column.\n    //\n    // Clip the scroll area to the new width, or the old width if that is further to the left. We\n    // may have the WS_CLIPCHILDREN style set, so we need to remove the horizontal scrollbar from\n    // the rectangle, otherwise ScrollWindowEx will want to invalidate the entire region! (The\n    // horizontal scrollbar is an overlapping child control.)\n    rect.left = columnLeft + Column->Width;\n    rect.top = Context->HeaderHeight;\n    rect.right = Context->ClientRect.right - (Context->VScrollVisible ? Context->VScrollWidth : 0);\n    rect.bottom = Context->ClientRect.bottom - (Context->HScrollVisible ? Context->HScrollHeight : 0);\n\n    if (Delta > 0)\n        rect.left -= Delta; // old width\n\n    // Scroll the window.\n    ScrollWindowEx(\n        Context->Handle,\n        Delta,\n        0,\n        &rect,\n        &rect,\n        NULL,\n        NULL,\n        SW_INVALIDATE\n        );\n\n    UpdateWindow(Context->Handle); // required\n\n    if (Context->HScrollVisible)\n    {\n        // We excluded the bottom region - invalidate it now.\n        rect.top = rect.bottom;\n        rect.bottom = Context->ClientRect.bottom;\n        InvalidateRect(Context->Handle, &rect, FALSE);\n    }\n\n    PhTnpLayout(Context);\n\n    // Redraw the whole column because the content may depend on the width (e.g. text ellipsis).\n    rect.left = columnLeft;\n    rect.top = Context->HeaderHeight;\n    rect.right = columnLeft + Column->Width;\n    RedrawWindow(Context->Handle, &rect, NULL, RDW_INVALIDATE | RDW_UPDATENOW); // must be RedrawWindow\n}\n\nVOID PhTnpProcessSortColumn(\n    _In_ PPH_TREENEW_CONTEXT Context,\n    _In_ PPH_TREENEW_COLUMN NewColumn\n    )\n{\n    if (NewColumn->Id == Context->SortColumn)\n    {\n        if (Context->TriState)\n        {\n            if (!NewColumn->SortDescending)\n            {\n                // Ascending -> Descending -> None\n\n                if (Context->SortOrder == AscendingSortOrder)\n                    Context->SortOrder = DescendingSortOrder;\n                else if (Context->SortOrder == DescendingSortOrder)\n                    Context->SortOrder = NoSortOrder;\n                else\n                    Context->SortOrder = AscendingSortOrder;\n            }\n            else\n            {\n                // Descending -> Ascending -> None\n\n                if (Context->SortOrder == DescendingSortOrder)\n                    Context->SortOrder = AscendingSortOrder;\n                else if (Context->SortOrder == AscendingSortOrder)\n                    Context->SortOrder = NoSortOrder;\n                else\n                    Context->SortOrder = DescendingSortOrder;\n            }\n        }\n        else\n        {\n            if (Context->SortOrder == AscendingSortOrder)\n                Context->SortOrder = DescendingSortOrder;\n            else\n                Context->SortOrder = AscendingSortOrder;\n        }\n    }\n    else\n    {\n        Context->SortColumn = NewColumn->Id;\n\n        if (!NewColumn->SortDescending)\n            Context->SortOrder = AscendingSortOrder;\n        else\n            Context->SortOrder = DescendingSortOrder;\n    }\n\n    PhTnpSetColumnHeaderSortIcon(Context, NewColumn);\n\n    Context->Callback(Context->Handle, TreeNewSortChanged, NULL, NULL, Context->CallbackContext);\n}\n\nBOOLEAN PhTnpSetColumnHeaderSortIcon(\n    _In_ PPH_TREENEW_CONTEXT Context,\n    _In_opt_ PPH_TREENEW_COLUMN SortColumnPointer\n    )\n{\n    if (Context->SortOrder == NoSortOrder)\n    {\n        PhSetHeaderSortIcon(\n            Context->FixedHeaderHandle,\n            -1,\n            NoSortOrder\n            );\n        PhSetHeaderSortIcon(\n            Context->HeaderHandle,\n            -1,\n            NoSortOrder\n            );\n\n        return TRUE;\n    }\n\n    if (!SortColumnPointer)\n    {\n        if (!(SortColumnPointer = PhTnpLookupColumnById(Context, Context->SortColumn)))\n            return FALSE;\n    }\n\n    if (SortColumnPointer->Fixed)\n    {\n        PhSetHeaderSortIcon(\n            Context->FixedHeaderHandle,\n            0,\n            Context->SortOrder\n            );\n        PhSetHeaderSortIcon(\n            Context->HeaderHandle,\n            -1,\n            NoSortOrder\n            );\n    }\n    else\n    {\n        PhSetHeaderSortIcon(\n            Context->FixedHeaderHandle,\n            -1,\n            NoSortOrder\n            );\n        PhSetHeaderSortIcon(\n            Context->HeaderHandle,\n            SortColumnPointer->s.ViewIndex,\n            Context->SortOrder\n            );\n    }\n\n    return TRUE;\n}\n\nVOID PhTnpAutoSizeColumnHeader(\n    _In_ PPH_TREENEW_CONTEXT Context,\n    _In_ HWND HeaderHandle,\n    _In_ PPH_TREENEW_COLUMN Column,\n    _In_ ULONG Flags\n    )\n{\n    LONG newWidth;\n    HDITEM item;\n\n    if (Flags & TN_AUTOSIZE_REMAINING_SPACE)\n    {\n        newWidth = Context->ClientRect.right - (Context->TotalViewX - Column->Width);\n\n        if (Context->FixedColumn)\n            newWidth -= Context->FixedColumn->Width;\n        if (Context->VScrollVisible)\n            newWidth -= Context->VScrollWidth;\n\n        if (newWidth <= 0)\n            return;\n    }\n    else\n    {\n        ULONG i;\n        LONG maximumWidth;\n        PH_TREENEW_CELL_PARTS parts;\n        LONG width;\n\n        if (Context->FlatList->Count == 0)\n            return;\n        if (Column->CustomDraw)\n            return;\n\n        maximumWidth = 0;\n\n        for (i = 0; i < Context->FlatList->Count; i++)\n        {\n            if (PhTnpGetCellParts(Context, i, Column, TN_MEASURE_TEXT, &parts) &&\n                (parts.Flags & TN_PART_CELL) && (parts.Flags & TN_PART_CONTENT) && (parts.Flags & TN_PART_TEXT))\n            {\n                width = parts.TextRect.right - parts.TextRect.left; // text width\n                width += parts.ContentRect.left - parts.CellRect.left; // left padding\n\n                if (maximumWidth < width)\n                    maximumWidth = width;\n            }\n        }\n\n        newWidth = maximumWidth + TNP_CELL_RIGHT_MARGIN; // right padding\n\n        if (Column->Fixed)\n            newWidth++;\n    }\n\n    item.mask = HDI_WIDTH;\n    item.cxy = newWidth;\n\n    Header_SetItem(HeaderHandle, Column->s.ViewIndex, &item);\n}\n\nBOOLEAN PhTnpGetNodeChildren(\n    _In_ PPH_TREENEW_CONTEXT Context,\n    _In_opt_ PPH_TREENEW_NODE Node,\n    _Out_ PPH_TREENEW_NODE **Children,\n    _Out_ PULONG NumberOfChildren\n    )\n{\n    PH_TREENEW_GET_CHILDREN getChildren;\n\n    getChildren.Flags = 0;\n    getChildren.Node = Node;\n    getChildren.Children = NULL;\n    getChildren.NumberOfChildren = 0;\n\n    if (Context->Callback(\n        Context->Handle,\n        TreeNewGetChildren,\n        &getChildren,\n        NULL,\n        Context->CallbackContext\n        ))\n    {\n        *Children = getChildren.Children;\n        *NumberOfChildren = getChildren.NumberOfChildren;\n\n        return TRUE;\n    }\n\n    return FALSE;\n}\n\nBOOLEAN PhTnpIsNodeLeaf(\n    _In_ PPH_TREENEW_CONTEXT Context,\n    _In_ PPH_TREENEW_NODE Node\n    )\n{\n    PH_TREENEW_IS_LEAF isLeaf;\n\n    isLeaf.Flags = 0;\n    isLeaf.Node = Node;\n    isLeaf.IsLeaf = TRUE;\n\n    if (Context->Callback(\n        Context->Handle,\n        TreeNewIsLeaf,\n        &isLeaf,\n        NULL,\n        Context->CallbackContext\n        ))\n    {\n        return isLeaf.IsLeaf;\n    }\n\n    // Doesn't matter, decide when we do the get-children callback.\n    return FALSE;\n}\n\nBOOLEAN PhTnpGetCellText(\n    _In_ PPH_TREENEW_CONTEXT Context,\n    _In_ PPH_TREENEW_NODE Node,\n    _In_ ULONG Id,\n    _Out_ PPH_STRINGREF Text\n    )\n{\n    PH_TREENEW_GET_CELL_TEXT getCellText;\n\n    if (Id < Node->TextCacheSize && Node->TextCache[Id].Buffer)\n    {\n        *Text = Node->TextCache[Id];\n        return TRUE;\n    }\n\n    getCellText.Flags = 0;\n    getCellText.Node = Node;\n    getCellText.Id = Id;\n    PhInitializeEmptyStringRef(&getCellText.Text);\n\n    if (Context->Callback(\n        Context->Handle,\n        TreeNewGetCellText,\n        &getCellText,\n        NULL,\n        Context->CallbackContext\n        ) && getCellText.Text.Buffer)\n    {\n        *Text = getCellText.Text;\n\n        if ((getCellText.Flags & TN_CACHE) && Id < Node->TextCacheSize)\n            Node->TextCache[Id] = getCellText.Text;\n\n        return TRUE;\n    }\n\n    return FALSE;\n}\n\nVOID PhTnpRestructureNodes(\n    _In_ PPH_TREENEW_CONTEXT Context\n    )\n{\n    PPH_TREENEW_NODE *children;\n    ULONG numberOfChildren;\n    ULONG i;\n\n    if (!PhTnpGetNodeChildren(Context, NULL, &children, &numberOfChildren))\n        return;\n\n    // We try to preserve the hot node, the focused node and the selection mark node. At this point\n    // all node pointers must be regarded as invalid, so we must not follow any pointers.\n\n    Context->FocusNodeFound = FALSE;\n\n    PhClearList(Context->FlatList);\n    Context->CanAnyExpand = FALSE;\n\n    for (i = 0; i < numberOfChildren; i++)\n    {\n        PhTnpInsertNodeChildren(Context, children[i], 0);\n    }\n\n    if (!Context->FocusNodeFound)\n        Context->FocusNode = NULL; // focused node is no longer present\n\n    if (Context->HotNodeIndex >= Context->FlatList->Count) // covers -1 case as well\n        Context->HotNodeIndex = -1;\n\n    if (Context->MarkNodeIndex >= Context->FlatList->Count)\n        Context->MarkNodeIndex = -1;\n}\n\nVOID PhTnpInsertNodeChildren(\n    _In_ PPH_TREENEW_CONTEXT Context,\n    _In_ PPH_TREENEW_NODE Node,\n    _In_ ULONG Level\n    )\n{\n    PPH_TREENEW_NODE *children;\n    ULONG numberOfChildren;\n    ULONG i;\n    ULONG nextLevel;\n\n    if (Node->Visible)\n    {\n        Node->Level = Level;\n\n        Node->Index = Context->FlatList->Count;\n        PhAddItemList(Context->FlatList, Node);\n\n        if (Context->FocusNode == Node)\n            Context->FocusNodeFound = TRUE;\n\n        nextLevel = Level + 1;\n    }\n    else\n    {\n        nextLevel = 0; // children of this node should be level 0\n    }\n\n    if (!(Node->s.IsLeaf = PhTnpIsNodeLeaf(Context, Node)))\n    {\n        Context->CanAnyExpand = TRUE;\n\n        if (Node->Expanded)\n        {\n            if (PhTnpGetNodeChildren(Context, Node, &children, &numberOfChildren))\n            {\n                for (i = 0; i < numberOfChildren; i++)\n                {\n                    PhTnpInsertNodeChildren(Context, children[i], nextLevel);\n                }\n\n                if (numberOfChildren == 0)\n                    Node->s.IsLeaf = TRUE;\n            }\n        }\n    }\n}\n\nVOID PhTnpSetExpandedNode(\n    _In_ PPH_TREENEW_CONTEXT Context,\n    _In_ PPH_TREENEW_NODE Node,\n    _In_ BOOLEAN Expanded\n    )\n{\n    if (Node->Expanded != Expanded)\n    {\n        PH_TREENEW_NODE_EVENT nodeEvent;\n\n        memset(&nodeEvent, 0, sizeof(PH_TREENEW_NODE_EVENT));\n        Context->Callback(Context->Handle, TreeNewNodeExpanding, Node, &nodeEvent, Context->CallbackContext);\n\n        if (!nodeEvent.Handled)\n        {\n            if (!Expanded)\n            {\n                ULONG i;\n                PPH_TREENEW_NODE node;\n                BOOLEAN changed;\n\n                // Make sure no children are selected - we don't want invisible selected nodes. Note\n                // that this does not cause any UI changes by itself, since we are hiding the nodes.\n\n                changed = FALSE;\n\n                for (i = Node->Index + 1; i < Context->FlatList->Count; i++)\n                {\n                    node = Context->FlatList->Items[i];\n\n                    if (node->Level <= Node->Level)\n                        break; // no more children\n\n                    if (node->Selected)\n                    {\n                        node->Selected = FALSE;\n                        changed = TRUE;\n                    }\n                }\n\n                if (changed)\n                {\n                    Context->Callback(Context->Handle, TreeNewSelectionChanged, NULL, NULL, Context->CallbackContext);\n                }\n            }\n\n            Node->Expanded = Expanded;\n            PhTnpRestructureNodes(Context);\n            // We need to update the window before the scrollbars get updated in order for the\n            // scroll processing to work properly.\n            InvalidateRect(Context->Handle, NULL, FALSE);\n            UpdateWindow(Context->Handle);\n            PhTnpLayout(Context);\n        }\n    }\n}\n\nBOOLEAN PhTnpGetCellParts(\n    _In_ PPH_TREENEW_CONTEXT Context,\n    _In_ ULONG Index,\n    _In_opt_ PPH_TREENEW_COLUMN Column,\n    _In_ ULONG Flags,\n    _Out_ PPH_TREENEW_CELL_PARTS Parts\n    )\n{\n    PPH_TREENEW_NODE node;\n    LONG viewWidth;\n    LONG nodeY;\n    LONG iconVerticalMargin;\n    LONG currentX;\n\n    if (Index >= Context->FlatList->Count)\n        return FALSE;\n\n    node = Context->FlatList->Items[Index];\n    nodeY = Context->HeaderHeight + ((LONG)Index - Context->VScrollPosition) * Context->RowHeight;\n\n    Parts->Flags = 0;\n    Parts->RowRect.left = 0;\n    Parts->RowRect.right = Context->NormalLeft + Context->TotalViewX - Context->HScrollPosition;\n    Parts->RowRect.top = nodeY;\n    Parts->RowRect.bottom = nodeY + Context->RowHeight;\n\n    viewWidth = Context->ClientRect.right - (Context->VScrollVisible ? Context->VScrollWidth : 0);\n\n    if (Parts->RowRect.right > viewWidth)\n        Parts->RowRect.right = viewWidth;\n\n    if (!Column)\n        return TRUE;\n    if (!Column->Visible)\n        return FALSE;\n\n    iconVerticalMargin = (Context->RowHeight - SmallIconHeight) / 2;\n\n    if (Column->Fixed)\n    {\n        currentX = 0;\n    }\n    else\n    {\n        currentX = Context->NormalLeft + Column->s.ViewX - Context->HScrollPosition;\n    }\n\n    Parts->Flags |= TN_PART_CELL;\n    Parts->CellRect.left = currentX;\n    Parts->CellRect.right = currentX + Column->Width;\n    Parts->CellRect.top = Parts->RowRect.top;\n    Parts->CellRect.bottom = Parts->RowRect.bottom;\n\n    currentX += TNP_CELL_LEFT_MARGIN;\n\n    if (Column == Context->FirstColumn)\n    {\n        currentX += (LONG)node->Level * SmallIconWidth;\n\n        if (Context->CanAnyExpand)\n        {\n            if (!node->s.IsLeaf)\n            {\n                Parts->Flags |= TN_PART_PLUSMINUS;\n                Parts->PlusMinusRect.left = currentX;\n                Parts->PlusMinusRect.right = currentX + SmallIconWidth;\n                Parts->PlusMinusRect.top = Parts->RowRect.top + iconVerticalMargin;\n                Parts->PlusMinusRect.bottom = Parts->RowRect.bottom - iconVerticalMargin;\n            }\n\n            currentX += SmallIconWidth;\n        }\n\n        if (node->Icon)\n        {\n            Parts->Flags |= TN_PART_ICON;\n            Parts->IconRect.left = currentX;\n            Parts->IconRect.right = currentX + SmallIconWidth;\n            Parts->IconRect.top = Parts->RowRect.top + iconVerticalMargin;\n            Parts->IconRect.bottom = Parts->RowRect.bottom - iconVerticalMargin;\n\n            currentX += SmallIconWidth + TNP_ICON_RIGHT_PADDING;\n        }\n    }\n\n    Parts->Flags |= TN_PART_CONTENT;\n    Parts->ContentRect.left = currentX;\n    Parts->ContentRect.right = Parts->CellRect.right - TNP_CELL_RIGHT_MARGIN;\n    Parts->ContentRect.top = Parts->RowRect.top;\n    Parts->ContentRect.bottom = Parts->RowRect.bottom;\n\n    if (Flags & TN_MEASURE_TEXT)\n    {\n        HDC hdc;\n        PH_STRINGREF text;\n        HFONT font;\n        SIZE textSize;\n\n        if (hdc = GetDC(Context->Handle))\n        {\n            PhTnpPrepareRowForDraw(Context, hdc, node);\n\n            if (PhTnpGetCellText(Context, node, Column->Id, &text))\n            {\n                if (node->Font)\n                    font = node->Font;\n                else\n                    font = Context->Font;\n\n                SelectObject(hdc, font);\n\n                if (GetTextExtentPoint32(hdc, text.Buffer, (ULONG)text.Length / sizeof(WCHAR), &textSize))\n                {\n                    Parts->Flags |= TN_PART_TEXT;\n                    Parts->TextRect.left = currentX;\n                    Parts->TextRect.right = currentX + textSize.cx;\n                    Parts->TextRect.top = Parts->RowRect.top + (Context->RowHeight - textSize.cy) / 2;\n                    Parts->TextRect.bottom = Parts->RowRect.bottom - (Context->RowHeight - textSize.cy) / 2;\n\n                    if (Column->TextFlags & DT_CENTER)\n                    {\n                        Parts->TextRect.left = Parts->ContentRect.left / 2 + (Parts->ContentRect.right - textSize.cx) / 2;\n                        Parts->TextRect.right = Parts->ContentRect.left + textSize.cx;\n                    }\n                    else if (Column->TextFlags & DT_RIGHT)\n                    {\n                        Parts->TextRect.right = Parts->ContentRect.right;\n                        Parts->TextRect.left = Parts->TextRect.right - textSize.cx;\n                    }\n\n                    Parts->Text = text;\n                    Parts->Font = font;\n                }\n            }\n\n            ReleaseDC(Context->Handle, hdc);\n        }\n    }\n\n    return TRUE;\n}\n\nBOOLEAN PhTnpGetRowRects(\n    _In_ PPH_TREENEW_CONTEXT Context,\n    _In_ ULONG Start,\n    _In_ ULONG End,\n    _In_ BOOLEAN Clip,\n    _Out_ PRECT Rect\n    )\n{\n    LONG startY;\n    LONG endY;\n    LONG viewWidth;\n\n    if (End >= Context->FlatList->Count)\n        return FALSE;\n    if (Start > End)\n        return FALSE;\n\n    startY = Context->HeaderHeight + ((LONG)Start - Context->VScrollPosition) * Context->RowHeight;\n    endY = Context->HeaderHeight + ((LONG)End - Context->VScrollPosition) * Context->RowHeight;\n\n    Rect->left = 0;\n    Rect->right = Context->NormalLeft + Context->TotalViewX - Context->HScrollPosition;\n    Rect->top = startY;\n    Rect->bottom = endY + Context->RowHeight;\n\n    viewWidth = Context->ClientRect.right - (Context->VScrollVisible ? Context->VScrollWidth : 0);\n\n    if (Rect->right > viewWidth)\n        Rect->right = viewWidth;\n\n    if (Clip)\n    {\n        if (Rect->top < Context->HeaderHeight)\n            Rect->top = Context->HeaderHeight;\n        if (Rect->bottom > Context->ClientRect.bottom)\n            Rect->bottom = Context->ClientRect.bottom;\n    }\n\n    return TRUE;\n}\n\nVOID PhTnpHitTest(\n    _In_ PPH_TREENEW_CONTEXT Context,\n    _Inout_ PPH_TREENEW_HIT_TEST HitTest\n    )\n{\n    RECT clientRect;\n    LONG x;\n    LONG y;\n    ULONG index;\n    PPH_TREENEW_NODE node;\n\n    HitTest->Flags = 0;\n    HitTest->Node = NULL;\n    HitTest->Column = NULL;\n\n    clientRect = Context->ClientRect;\n    x = HitTest->Point.x;\n    y = HitTest->Point.y;\n\n    if (x < 0)\n        HitTest->Flags |= TN_HIT_LEFT;\n    if (x >= clientRect.right)\n        HitTest->Flags |= TN_HIT_RIGHT;\n    if (y < 0)\n        HitTest->Flags |= TN_HIT_ABOVE;\n    if (y >= clientRect.bottom)\n        HitTest->Flags |= TN_HIT_BELOW;\n\n    if (HitTest->Flags == 0)\n    {\n        if (TNP_HIT_TEST_FIXED_DIVIDER(x, Context))\n        {\n            HitTest->Flags |= TN_HIT_DIVIDER;\n        }\n\n        if (y >= Context->HeaderHeight && x < Context->FixedWidth + Context->TotalViewX)\n        {\n            index = (y - Context->HeaderHeight) / Context->RowHeight + Context->VScrollPosition;\n\n            if (index < Context->FlatList->Count)\n            {\n                HitTest->Flags |= TN_HIT_ITEM;\n                node = Context->FlatList->Items[index];\n                HitTest->Node = node;\n\n                if (HitTest->InFlags & TN_TEST_COLUMN)\n                {\n                    PPH_TREENEW_COLUMN column;\n                    LONG columnX;\n\n                    column = NULL;\n\n                    if (x < Context->FixedWidth && Context->FixedColumnVisible)\n                    {\n                        column = Context->FixedColumn;\n                        columnX = 0;\n                    }\n                    else\n                    {\n                        LONG currentX;\n                        ULONG i;\n                        PPH_TREENEW_COLUMN currentColumn;\n\n                        currentX = Context->NormalLeft - Context->HScrollPosition;\n\n                        for (i = 0; i < Context->NumberOfColumnsByDisplay; i++)\n                        {\n                            currentColumn = Context->ColumnsByDisplay[i];\n\n                            if (x >= currentX && x < currentX + currentColumn->Width)\n                            {\n                                column = currentColumn;\n                                columnX = currentX;\n                                break;\n                            }\n\n                            currentX += currentColumn->Width;\n                        }\n                    }\n\n                    HitTest->Column = column;\n\n                    if (column && (HitTest->InFlags & TN_TEST_SUBITEM))\n                    {\n                        BOOLEAN isFirstColumn;\n                        LONG currentX;\n\n                        isFirstColumn = HitTest->Column == Context->FirstColumn;\n\n                        currentX = columnX;\n                        currentX += TNP_CELL_LEFT_MARGIN;\n\n                        if (isFirstColumn)\n                        {\n                            currentX += (LONG)node->Level * SmallIconWidth;\n\n                            if (!node->s.IsLeaf)\n                            {\n                                if (x >= currentX && x < currentX + SmallIconWidth)\n                                    HitTest->Flags |= TN_HIT_ITEM_PLUSMINUS;\n\n                                currentX += SmallIconWidth;\n                            }\n\n                            if (node->Icon)\n                            {\n                                if (x >= currentX && x < currentX + SmallIconWidth)\n                                    HitTest->Flags |= TN_HIT_ITEM_ICON;\n\n                                currentX += SmallIconWidth + TNP_ICON_RIGHT_PADDING;\n                            }\n                        }\n\n                        if (x >= currentX)\n                        {\n                            HitTest->Flags |= TN_HIT_ITEM_CONTENT;\n                        }\n                    }\n                }\n            }\n        }\n    }\n}\n\nVOID PhTnpSelectRange(\n    _In_ PPH_TREENEW_CONTEXT Context,\n    _In_ ULONG Start,\n    _In_ ULONG End,\n    _In_ ULONG Flags,\n    _Out_opt_ PULONG ChangedStart,\n    _Out_opt_ PULONG ChangedEnd\n    )\n{\n    ULONG maximum;\n    ULONG i;\n    PPH_TREENEW_NODE node;\n    BOOLEAN targetValue;\n    ULONG changedStart;\n    ULONG changedEnd;\n\n    if (Context->FlatList->Count == 0)\n        return;\n\n    maximum = Context->FlatList->Count - 1;\n\n    if (End > maximum)\n    {\n        End = maximum;\n    }\n\n    if (Start > End)\n    {\n        // Start is too big, so the selection range becomes empty.\n        // Set it to max + 1 so that Reset still works.\n        Start = maximum + 1;\n        End = 0;\n    }\n\n    targetValue = !(Flags & TN_SELECT_DESELECT);\n    changedStart = maximum;\n    changedEnd = 0;\n\n    if (Flags & TN_SELECT_RESET)\n    {\n        for (i = 0; i < Start; i++)\n        {\n            node = Context->FlatList->Items[i];\n\n            if (node->Selected)\n            {\n                node->Selected = FALSE;\n\n                if (changedStart > i)\n                    changedStart = i;\n                if (changedEnd < i)\n                    changedEnd = i;\n            }\n        }\n    }\n\n    for (i = Start; i <= End; i++)\n    {\n        node = Context->FlatList->Items[i];\n\n        if (!node->Unselectable && ((Flags & TN_SELECT_TOGGLE) || node->Selected != targetValue))\n        {\n            node->Selected = !node->Selected;\n\n            if (changedStart > i)\n                changedStart = i;\n            if (changedEnd < i)\n                changedEnd = i;\n        }\n    }\n\n    if (Flags & TN_SELECT_RESET)\n    {\n        for (i = End + 1; i <= maximum; i++)\n        {\n            node = Context->FlatList->Items[i];\n\n            if (node->Selected)\n            {\n                node->Selected = FALSE;\n\n                if (changedStart > i)\n                    changedStart = i;\n                if (changedEnd < i)\n                    changedEnd = i;\n            }\n        }\n    }\n\n    if (changedStart <= changedEnd)\n    {\n        Context->Callback(Context->Handle, TreeNewSelectionChanged, NULL, NULL, Context->CallbackContext);\n    }\n\n    if (ChangedStart)\n        *ChangedStart = changedStart;\n    if (ChangedEnd)\n        *ChangedEnd = changedEnd;\n}\n\nVOID PhTnpSetHotNode(\n    _In_ PPH_TREENEW_CONTEXT Context,\n    _In_opt_ PPH_TREENEW_NODE NewHotNode,\n    _In_ BOOLEAN NewPlusMinusHot\n    )\n{\n    ULONG newHotNodeIndex;\n    RECT rowRect;\n    BOOLEAN needsInvalidate;\n\n    if (NewHotNode)\n        newHotNodeIndex = NewHotNode->Index;\n    else\n        newHotNodeIndex = -1;\n\n    needsInvalidate = FALSE;\n\n    if (Context->HotNodeIndex != newHotNodeIndex)\n    {\n        if (Context->HotNodeIndex != -1)\n        {\n            if (Context->ThemeData && PhTnpGetRowRects(Context, Context->HotNodeIndex, Context->HotNodeIndex, TRUE, &rowRect))\n            {\n                // Update the old hot node because it may have a different non-hot background and\n                // plus minus part.\n                InvalidateRect(Context->Handle, &rowRect, FALSE);\n            }\n        }\n\n        Context->HotNodeIndex = newHotNodeIndex;\n\n        if (NewHotNode)\n        {\n            needsInvalidate = TRUE;\n        }\n    }\n\n    if (NewHotNode)\n    {\n        if (NewHotNode->s.PlusMinusHot != NewPlusMinusHot)\n        {\n            NewHotNode->s.PlusMinusHot = NewPlusMinusHot;\n            needsInvalidate = TRUE;\n        }\n\n        if (needsInvalidate && Context->ThemeData && PhTnpGetRowRects(Context, newHotNodeIndex, newHotNodeIndex, TRUE, &rowRect))\n        {\n            InvalidateRect(Context->Handle, &rowRect, FALSE);\n        }\n    }\n}\n\nVOID PhTnpProcessSelectNode(\n    _In_ PPH_TREENEW_CONTEXT Context,\n    _In_ PPH_TREENEW_NODE Node,\n    _In_ LOGICAL ControlKey,\n    _In_ LOGICAL ShiftKey,\n    _In_ LOGICAL RightButton\n    )\n{\n    ULONG changedStart;\n    ULONG changedEnd;\n    RECT rect;\n\n    if (RightButton)\n    {\n        // Right button:\n        // If the current node is selected, then do nothing. This is to allow context menus to\n        // operate on multiple items.\n        // If the current node is not selected, select only that node.\n\n        if (!ControlKey && !ShiftKey && !Node->Selected)\n        {\n            PhTnpSelectRange(Context, Node->Index, Node->Index, TN_SELECT_RESET, &changedStart, &changedEnd);\n            Context->MarkNodeIndex = Node->Index;\n\n            if (PhTnpGetRowRects(Context, changedStart, changedEnd, TRUE, &rect))\n            {\n                InvalidateRect(Context->Handle, &rect, FALSE);\n            }\n        }\n    }\n    else if (ShiftKey && Context->MarkNodeIndex != -1)\n    {\n        ULONG start;\n        ULONG end;\n\n        // Shift key: select a range from the selection mark node to the current node.\n\n        if (Node->Index > Context->MarkNodeIndex)\n        {\n            start = Context->MarkNodeIndex;\n            end = Node->Index;\n        }\n        else\n        {\n            start = Node->Index;\n            end = Context->MarkNodeIndex;\n        }\n\n        PhTnpSelectRange(Context, start, end, TN_SELECT_RESET, &changedStart, &changedEnd);\n\n        if (PhTnpGetRowRects(Context, changedStart, changedEnd, TRUE, &rect))\n        {\n            InvalidateRect(Context->Handle, &rect, FALSE);\n        }\n    }\n    else if (ControlKey)\n    {\n        // Control key: toggle the selection on the current node, and also make it the selection\n        // mark.\n\n        PhTnpSelectRange(Context, Node->Index, Node->Index, TN_SELECT_TOGGLE, NULL, NULL);\n        Context->MarkNodeIndex = Node->Index;\n\n        if (PhTnpGetRowRects(Context, Node->Index, Node->Index, TRUE, &rect))\n        {\n            InvalidateRect(Context->Handle, &rect, FALSE);\n        }\n    }\n    else\n    {\n        // Normal: select the current node, and also make it the selection mark.\n\n        PhTnpSelectRange(Context, Node->Index, Node->Index, TN_SELECT_RESET, &changedStart, &changedEnd);\n        Context->MarkNodeIndex = Node->Index;\n\n        if (PhTnpGetRowRects(Context, changedStart, changedEnd, TRUE, &rect))\n        {\n            InvalidateRect(Context->Handle, &rect, FALSE);\n        }\n    }\n}\n\nBOOLEAN PhTnpEnsureVisibleNode(\n    _In_ PPH_TREENEW_CONTEXT Context,\n    _In_ ULONG Index\n    )\n{\n    LONG viewTop;\n    LONG viewBottom;\n    LONG rowTop;\n    LONG rowBottom;\n    LONG deltaY;\n    LONG deltaRows;\n\n    if (Index >= Context->FlatList->Count)\n        return FALSE;\n\n    viewTop = Context->HeaderHeight;\n    viewBottom = Context->ClientRect.bottom - (Context->HScrollVisible ? Context->HScrollHeight : 0);\n    rowTop = Context->HeaderHeight + ((LONG)Index - Context->VScrollPosition) * Context->RowHeight;\n    rowBottom = rowTop + Context->RowHeight;\n\n    // Check if the row is fully visible.\n    if (rowTop >= viewTop && rowBottom <= viewBottom)\n        return TRUE;\n\n    deltaY = rowTop - viewTop;\n\n    if (deltaY > 0)\n    {\n        // The row is below the view area. We want to scroll the row into view at the bottom of the\n        // screen. We need to round up when dividing to make sure the node becomes fully visible.\n        deltaY = rowBottom - viewBottom;\n        deltaRows = (deltaY + Context->RowHeight - 1) / Context->RowHeight; // divide, round up\n    }\n    else\n    {\n        deltaRows = deltaY / Context->RowHeight;\n    }\n\n    PhTnpScroll(Context, deltaRows, 0);\n\n    return TRUE;\n}\n\nVOID PhTnpProcessMoveMouse(\n    _In_ PPH_TREENEW_CONTEXT Context,\n    _In_ LONG CursorX,\n    _In_ LONG CursorY\n    )\n{\n    PH_TREENEW_HIT_TEST hitTest;\n    PPH_TREENEW_NODE hotNode;\n\n    hitTest.Point.x = CursorX;\n    hitTest.Point.y = CursorY;\n    hitTest.InFlags = TN_TEST_COLUMN | TN_TEST_SUBITEM;\n    PhTnpHitTest(Context, &hitTest);\n\n    if (hitTest.Flags & TN_HIT_ITEM)\n        hotNode = hitTest.Node;\n    else\n        hotNode = NULL;\n\n    PhTnpSetHotNode(Context, hotNode, !!(hitTest.Flags & TN_HIT_ITEM_PLUSMINUS));\n\n    if (Context->AnimateDivider && Context->FixedDividerVisible)\n    {\n        if (hitTest.Flags & TN_HIT_DIVIDER)\n        {\n            if ((Context->DividerHot < 100 || Context->AnimateDividerFadingOut) && !Context->AnimateDividerFadingIn)\n            {\n                // Begin fading in the divider.\n                Context->AnimateDividerFadingIn = TRUE;\n                Context->AnimateDividerFadingOut = FALSE;\n                SetTimer(Context->Handle, TNP_TIMER_ANIMATE_DIVIDER, TNP_ANIMATE_DIVIDER_INTERVAL, NULL);\n            }\n        }\n        else\n        {\n            if ((Context->DividerHot != 0 || Context->AnimateDividerFadingIn) && !Context->AnimateDividerFadingOut)\n            {\n                Context->AnimateDividerFadingOut = TRUE;\n                Context->AnimateDividerFadingIn = FALSE;\n                SetTimer(Context->Handle, TNP_TIMER_ANIMATE_DIVIDER, TNP_ANIMATE_DIVIDER_INTERVAL, NULL);\n            }\n        }\n    }\n\n    if (Context->TooltipsHandle)\n    {\n        ULONG index;\n        ULONG id;\n\n        if (!(hitTest.Flags & TN_HIT_DIVIDER))\n        {\n            index = hitTest.Node ? hitTest.Node->Index : -1;\n            id = hitTest.Column ? hitTest.Column->Id : -1;\n        }\n        else\n        {\n            index = -1;\n            id = -1;\n        }\n\n        // This pops unnecessarily - when the cell has no tooltip text, and the user is moving the\n        // mouse over it. However these unnecessary calls seem to fix a certain tooltip bug (move\n        // the mouse around very quickly over the last column and the blank space to the right, and\n        // no more tooltips will appear).\n        if (Context->TooltipIndex != index || Context->TooltipId != id)\n        {\n            PhTnpPopTooltip(Context);\n        }\n    }\n}\n\nVOID PhTnpProcessMouseVWheel(\n    _In_ PPH_TREENEW_CONTEXT Context,\n    _In_ LONG Distance\n    )\n{\n    ULONG wheelScrollLines;\n    FLOAT linesToScroll;\n    LONG wholeLinesToScroll;\n    SCROLLINFO scrollInfo;\n    LONG oldPosition;\n\n    if (!SystemParametersInfo(SPI_GETWHEELSCROLLLINES, 0, &wheelScrollLines, 0))\n        wheelScrollLines = 3;\n\n    // If page scrolling is enabled, use the number of visible rows.\n    if (wheelScrollLines == -1)\n        wheelScrollLines = (Context->ClientRect.bottom - Context->HeaderHeight - (Context->HScrollVisible ? Context->HScrollHeight : 0)) / Context->RowHeight;\n\n    // Zero the remainder if the direction changed.\n    if ((Context->VScrollRemainder > 0) != (Distance > 0))\n        Context->VScrollRemainder = 0;\n\n    linesToScroll = (FLOAT)wheelScrollLines * Distance / WHEEL_DELTA + Context->VScrollRemainder;\n    wholeLinesToScroll = (LONG)linesToScroll;\n    Context->VScrollRemainder = linesToScroll - wholeLinesToScroll;\n\n    scrollInfo.cbSize = sizeof(SCROLLINFO);\n    scrollInfo.fMask = SIF_ALL;\n    GetScrollInfo(Context->VScrollHandle, SB_CTL, &scrollInfo);\n    oldPosition = scrollInfo.nPos;\n\n    scrollInfo.nPos += wholeLinesToScroll;\n\n    scrollInfo.fMask = SIF_POS;\n    SetScrollInfo(Context->VScrollHandle, SB_CTL, &scrollInfo, TRUE);\n    GetScrollInfo(Context->VScrollHandle, SB_CTL, &scrollInfo);\n\n    if (scrollInfo.nPos != oldPosition)\n    {\n        Context->VScrollPosition = scrollInfo.nPos;\n        PhTnpProcessScroll(Context, scrollInfo.nPos - oldPosition, 0);\n\n        if (Context->TooltipsHandle)\n        {\n            MSG message;\n            POINT point;\n\n            PhTnpPopTooltip(Context);\n            PhTnpGetMessagePos(Context->Handle, &point);\n\n            if (point.x >= 0 && point.y >= 0 && point.x < Context->ClientRect.right && point.y < Context->ClientRect.bottom)\n            {\n                // Send a fake mouse move message for the new node that the mouse may be hovering over.\n                message.hwnd = Context->Handle;\n                message.message = WM_MOUSEMOVE;\n                message.wParam = 0;\n                message.lParam = MAKELPARAM(point.x, point.y);\n                SendMessage(Context->TooltipsHandle, TTM_RELAYEVENT, 0, (LPARAM)&message);\n            }\n        }\n    }\n}\n\nVOID PhTnpProcessMouseHWheel(\n    _In_ PPH_TREENEW_CONTEXT Context,\n    _In_ LONG Distance\n    )\n{\n    ULONG wheelScrollChars;\n    FLOAT pixelsToScroll;\n    LONG wholePixelsToScroll;\n    SCROLLINFO scrollInfo;\n    LONG oldPosition;\n\n    if (!SystemParametersInfo(SPI_GETWHEELSCROLLCHARS, 0, &wheelScrollChars, 0))\n        wheelScrollChars = 3;\n\n    // Zero the remainder if the direction changed.\n    if ((Context->HScrollRemainder > 0) != (Distance > 0))\n        Context->HScrollRemainder = 0;\n\n    pixelsToScroll = (FLOAT)wheelScrollChars * Context->TextMetrics.tmAveCharWidth * Distance / WHEEL_DELTA + Context->HScrollRemainder;\n    wholePixelsToScroll = (LONG)pixelsToScroll;\n    Context->HScrollRemainder = pixelsToScroll - wholePixelsToScroll;\n\n    scrollInfo.cbSize = sizeof(SCROLLINFO);\n    scrollInfo.fMask = SIF_ALL;\n    GetScrollInfo(Context->HScrollHandle, SB_CTL, &scrollInfo);\n    oldPosition = scrollInfo.nPos;\n\n    scrollInfo.nPos += wholePixelsToScroll;\n\n    scrollInfo.fMask = SIF_POS;\n    SetScrollInfo(Context->HScrollHandle, SB_CTL, &scrollInfo, TRUE);\n    GetScrollInfo(Context->HScrollHandle, SB_CTL, &scrollInfo);\n\n    if (scrollInfo.nPos != oldPosition)\n    {\n        Context->HScrollPosition = scrollInfo.nPos;\n        PhTnpProcessScroll(Context, 0, scrollInfo.nPos - oldPosition);\n    }\n}\n\nBOOLEAN PhTnpProcessFocusKey(\n    _In_ PPH_TREENEW_CONTEXT Context,\n    _In_ ULONG VirtualKey\n    )\n{\n    ULONG count;\n    ULONG index;\n    BOOLEAN controlKey;\n    BOOLEAN shiftKey;\n    ULONG start;\n    ULONG end;\n    ULONG changedStart;\n    ULONG changedEnd;\n    RECT rect;\n\n    if (VirtualKey != VK_UP && VirtualKey != VK_DOWN &&\n        VirtualKey != VK_HOME && VirtualKey != VK_END &&\n        VirtualKey != VK_PRIOR && VirtualKey != VK_NEXT)\n    {\n        return FALSE;\n    }\n\n    count = Context->FlatList->Count;\n\n    if (count == 0)\n        return TRUE;\n\n    // Find the new node to focus.\n\n    switch (VirtualKey)\n    {\n    case VK_UP:\n        {\n            if (Context->FocusNode && Context->FocusNode->Index > 0)\n            {\n                index = Context->FocusNode->Index - 1;\n            }\n            else\n            {\n                index = 0;\n            }\n        }\n        break;\n    case VK_DOWN:\n        {\n            if (Context->FocusNode)\n            {\n                index = Context->FocusNode->Index + 1;\n\n                if (index >= count)\n                    index = count - 1;\n            }\n            else\n            {\n                index = 0;\n            }\n        }\n        break;\n    case VK_HOME:\n        index = 0;\n        break;\n    case VK_END:\n        index = count - 1;\n        break;\n    case VK_PRIOR:\n    case VK_NEXT:\n        {\n            LONG rowsPerPage;\n\n            if (Context->FocusNode)\n                index = Context->FocusNode->Index;\n            else\n                index = 0;\n\n            rowsPerPage = Context->ClientRect.bottom - Context->HeaderHeight - (Context->HScrollVisible ? Context->HScrollHeight : 0);\n\n            if (rowsPerPage < 0)\n                return TRUE;\n\n            rowsPerPage = rowsPerPage / Context->RowHeight - 1;\n\n            if (rowsPerPage < 0)\n                return TRUE;\n\n            if (VirtualKey == VK_PRIOR)\n            {\n                ULONG startOfPageIndex;\n\n                startOfPageIndex = Context->VScrollPosition;\n\n                if (index > startOfPageIndex)\n                {\n                    index = startOfPageIndex;\n                }\n                else\n                {\n                    // Already at or before the start of the page. Go back a page.\n                    if (index >= (ULONG)rowsPerPage)\n                        index -= rowsPerPage;\n                    else\n                        index = 0;\n                }\n            }\n            else\n            {\n                ULONG endOfPageIndex;\n\n                endOfPageIndex = Context->VScrollPosition + rowsPerPage;\n\n                if (endOfPageIndex >= count)\n                    endOfPageIndex = count - 1;\n\n                if (index < endOfPageIndex)\n                {\n                    index = endOfPageIndex;\n                }\n                else\n                {\n                    // Already at or after the end of the page. Go forward a page.\n                    index += rowsPerPage;\n\n                    if (index >= count)\n                        index = count - 1;\n                }\n            }\n        }\n        break;\n    }\n\n    // Select the relevant nodes.\n\n    controlKey = GetKeyState(VK_CONTROL) < 0;\n    shiftKey = GetKeyState(VK_SHIFT) < 0;\n\n    Context->FocusNode = Context->FlatList->Items[index];\n    PhTnpSetHotNode(Context, Context->FocusNode, FALSE);\n\n    if (shiftKey && Context->MarkNodeIndex != -1)\n    {\n        if (index > Context->MarkNodeIndex)\n        {\n            start = Context->MarkNodeIndex;\n            end = index;\n        }\n        else\n        {\n            start = index;\n            end = Context->MarkNodeIndex;\n        }\n\n        PhTnpSelectRange(Context, start, end, TN_SELECT_RESET, &changedStart, &changedEnd);\n\n        if (PhTnpGetRowRects(Context, changedStart, changedEnd, TRUE, &rect))\n        {\n            InvalidateRect(Context->Handle, &rect, FALSE);\n        }\n    }\n    else if (!controlKey)\n    {\n        Context->MarkNodeIndex = Context->FocusNode->Index;\n        PhTnpSelectRange(Context, index, index, TN_SELECT_RESET, &changedStart, &changedEnd);\n\n        if (PhTnpGetRowRects(Context, changedStart, changedEnd, TRUE, &rect))\n        {\n            InvalidateRect(Context->Handle, &rect, FALSE);\n        }\n    }\n\n    PhTnpEnsureVisibleNode(Context, index);\n    PhTnpPopTooltip(Context);\n\n    return TRUE;\n}\n\nBOOLEAN PhTnpProcessNodeKey(\n    _In_ PPH_TREENEW_CONTEXT Context,\n    _In_ ULONG VirtualKey\n    )\n{\n    BOOLEAN controlKey;\n    BOOLEAN shiftKey;\n    ULONG changedStart;\n    ULONG changedEnd;\n    RECT rect;\n\n    if (VirtualKey != VK_SPACE && VirtualKey != VK_LEFT && VirtualKey != VK_RIGHT && VirtualKey != VK_ADD && VirtualKey != VK_OEM_PLUS)\n    {\n        return FALSE;\n    }\n\n    if (!Context->FocusNode)\n        return TRUE;\n\n    controlKey = GetKeyState(VK_CONTROL) < 0;\n    shiftKey = GetKeyState(VK_SHIFT) < 0;\n\n    switch (VirtualKey)\n    {\n    case VK_SPACE:\n        {\n            if (controlKey)\n            {\n                // Control key: toggle the selection on the focused node.\n\n                Context->MarkNodeIndex = Context->FocusNode->Index;\n                PhTnpSelectRange(Context, Context->FocusNode->Index, Context->FocusNode->Index, TN_SELECT_TOGGLE, &changedStart, &changedEnd);\n\n                if (PhTnpGetRowRects(Context, changedStart, changedEnd, TRUE, &rect))\n                {\n                    InvalidateRect(Context->Handle, &rect, FALSE);\n                }\n            }\n            else if (shiftKey)\n            {\n                ULONG start;\n                ULONG end;\n\n                // Shift key: select a range from the selection mark node to the focused node.\n\n                if (Context->FocusNode->Index > Context->MarkNodeIndex)\n                {\n                    start = Context->MarkNodeIndex;\n                    end = Context->FocusNode->Index;\n                }\n                else\n                {\n                    start = Context->FocusNode->Index;\n                    end = Context->MarkNodeIndex;\n                }\n\n                PhTnpSelectRange(Context, start, end, TN_SELECT_RESET, &changedStart, &changedEnd);\n\n                if (PhTnpGetRowRects(Context, changedStart, changedEnd, TRUE, &rect))\n                {\n                    InvalidateRect(Context->Handle, &rect, FALSE);\n                }\n            }\n        }\n        break;\n    case VK_LEFT:\n        {\n            ULONG i;\n            ULONG targetLevel;\n            PPH_TREENEW_NODE newNode;\n\n            // If the node is expanded, collapse it. Otherwise, select the node's parent.\n            if (!Context->FocusNode->s.IsLeaf && Context->FocusNode->Expanded)\n            {\n                PhTnpSetExpandedNode(Context, Context->FocusNode, FALSE);\n            }\n            else if (Context->FocusNode->Level != 0)\n            {\n                i = Context->FocusNode->Index;\n                targetLevel = Context->FocusNode->Level - 1;\n\n                while (i != 0)\n                {\n                    i--;\n                    newNode = Context->FlatList->Items[i];\n\n                    if (newNode->Level == targetLevel)\n                    {\n                        Context->FocusNode = newNode;\n                        Context->MarkNodeIndex = newNode->Index;\n                        PhTnpEnsureVisibleNode(Context, i);\n                        PhTnpSetHotNode(Context, newNode, FALSE);\n                        PhTnpSelectRange(Context, i, i, TN_SELECT_RESET, &changedStart, &changedEnd);\n\n                        if (PhTnpGetRowRects(Context, changedStart, changedEnd, TRUE, &rect))\n                        {\n                            InvalidateRect(Context->Handle, &rect, FALSE);\n                        }\n\n                        PhTnpPopTooltip(Context);\n\n                        break;\n                    }\n                }\n            }\n        }\n        break;\n    case VK_RIGHT:\n        {\n            PPH_TREENEW_NODE newNode;\n\n            if (!Context->FocusNode->s.IsLeaf)\n            {\n                // If the node is collapsed, expand it. Otherwise, select the node's first child.\n                if (!Context->FocusNode->Expanded)\n                {\n                    PhTnpSetExpandedNode(Context, Context->FocusNode, TRUE);\n                }\n                else\n                {\n                    if (Context->FocusNode->Index + 1 < Context->FlatList->Count)\n                    {\n                        newNode = Context->FlatList->Items[Context->FocusNode->Index + 1];\n\n                        if (newNode->Level == Context->FocusNode->Level + 1)\n                        {\n                            Context->FocusNode = newNode;\n                            Context->MarkNodeIndex = newNode->Index;\n                            PhTnpEnsureVisibleNode(Context, Context->FocusNode->Index + 1);\n                            PhTnpSetHotNode(Context, newNode, FALSE);\n                            PhTnpSelectRange(Context, Context->FocusNode->Index, Context->FocusNode->Index, TN_SELECT_RESET, &changedStart, &changedEnd);\n\n                            if (PhTnpGetRowRects(Context, changedStart, changedEnd, TRUE, &rect))\n                            {\n                                InvalidateRect(Context->Handle, &rect, FALSE);\n                            }\n\n                            PhTnpPopTooltip(Context);\n                        }\n                    }\n                }\n            }\n        }\n        break;\n    case VK_ADD:\n    case VK_OEM_PLUS:\n        {\n            if ((VirtualKey == VK_ADD && controlKey) ||\n                (VirtualKey == VK_OEM_PLUS && controlKey && shiftKey))\n            {\n                ULONG i;\n\n                if (Context->FixedColumnVisible)\n                    PhTnpAutoSizeColumnHeader(Context, Context->FixedHeaderHandle, Context->FixedColumn, 0);\n\n                for (i = 0; i < Context->NumberOfColumnsByDisplay; i++)\n                    PhTnpAutoSizeColumnHeader(Context, Context->HeaderHandle, Context->ColumnsByDisplay[i], 0);\n            }\n        }\n        break;\n    }\n\n    return TRUE;\n}\n\nVOID PhTnpProcessSearchKey(\n    _In_ PPH_TREENEW_CONTEXT Context,\n    _In_ ULONG Character\n    )\n{\n    LONG messageTime;\n    BOOLEAN newSearch;\n    PH_TREENEW_SEARCH_EVENT searchEvent;\n    PPH_TREENEW_NODE foundNode;\n    ULONG changedStart;\n    ULONG changedEnd;\n    RECT rect;\n\n    if (Context->FlatList->Count == 0)\n        return;\n\n    messageTime = GetMessageTime();\n    newSearch = FALSE;\n\n    // Check if the search timed out.\n    if (messageTime - Context->SearchMessageTime > PH_TREENEW_SEARCH_TIMEOUT)\n    {\n        Context->SearchStringCount = 0;\n        Context->SearchFailed = FALSE;\n        newSearch = TRUE;\n        Context->SearchSingleCharMode = TRUE;\n    }\n\n    Context->SearchMessageTime = messageTime;\n\n    // Append the character to the search buffer.\n\n    if (!Context->SearchString)\n    {\n        Context->AllocatedSearchString = 32;\n        Context->SearchString = PhAllocate(Context->AllocatedSearchString * sizeof(WCHAR));\n        newSearch = TRUE;\n        Context->SearchSingleCharMode = TRUE;\n    }\n\n    if (Context->SearchStringCount > PH_TREENEW_SEARCH_MAXIMUM_LENGTH)\n    {\n        // The search string has become too long. Fail the search.\n        if (!Context->SearchFailed)\n        {\n            MessageBeep(0);\n            Context->SearchFailed = TRUE;\n            return;\n        }\n    }\n    else if (Context->SearchStringCount == Context->AllocatedSearchString)\n    {\n        Context->AllocatedSearchString *= 2;\n        Context->SearchString = PhReAllocate(Context->SearchString, Context->AllocatedSearchString * sizeof(WCHAR));\n    }\n\n    Context->SearchString[Context->SearchStringCount++] = (WCHAR)Character;\n\n    if (Context->SearchString[Context->SearchStringCount - 1] != Context->SearchString[0])\n    {\n        // The user has stopped typing the same character (or never started). Turn single-character\n        // search off.\n        Context->SearchSingleCharMode = FALSE;\n    }\n\n    searchEvent.FoundIndex = -1;\n\n    if (Context->FocusNode)\n    {\n        searchEvent.StartIndex = Context->FocusNode->Index;\n\n        if (newSearch || Context->SearchSingleCharMode)\n        {\n            // If it's a new search, start at the next item so the user doesn't find the same item\n            // again.\n            searchEvent.StartIndex++;\n\n            if (searchEvent.StartIndex == Context->FlatList->Count)\n                searchEvent.StartIndex = 0;\n        }\n    }\n    else\n    {\n        searchEvent.StartIndex = 0;\n    }\n\n    searchEvent.String.Buffer = Context->SearchString;\n\n    if (!Context->SearchSingleCharMode)\n        searchEvent.String.Length = Context->SearchStringCount * sizeof(WCHAR);\n    else\n        searchEvent.String.Length = sizeof(WCHAR);\n\n    // Give the user a chance to modify how the search is performed.\n    if (!Context->Callback(Context->Handle, TreeNewIncrementalSearch, &searchEvent, NULL, Context->CallbackContext))\n    {\n        // Use the default search function.\n        if (!PhTnpDefaultIncrementalSearch(Context, &searchEvent, TRUE, TRUE))\n        {\n            return;\n        }\n    }\n\n    if (searchEvent.FoundIndex == -1 && !Context->SearchFailed)\n    {\n        // No search result. Beep to indicate an error, and set the flag so we don't beep again. But\n        // don't beep if the first character was a space, because that's used for other purposes\n        // elsewhere (see PhTnpProcessNodeKey).\n        if (searchEvent.String.Buffer[0] != ' ')\n        {\n            MessageBeep(0);\n        }\n\n        Context->SearchFailed = TRUE;\n        return;\n    }\n\n    if (searchEvent.FoundIndex < 0 || searchEvent.FoundIndex >= (LONG)Context->FlatList->Count)\n        return;\n\n    foundNode = Context->FlatList->Items[searchEvent.FoundIndex];\n    Context->FocusNode = foundNode;\n    PhTnpEnsureVisibleNode(Context, searchEvent.FoundIndex);\n    PhTnpSetHotNode(Context, foundNode, FALSE);\n    PhTnpSelectRange(Context, searchEvent.FoundIndex, searchEvent.FoundIndex, TN_SELECT_RESET, &changedStart, &changedEnd);\n\n    if (PhTnpGetRowRects(Context, changedStart, changedEnd, TRUE, &rect))\n    {\n        InvalidateRect(Context->Handle, &rect, FALSE);\n    }\n\n    PhTnpPopTooltip(Context);\n}\n\nBOOLEAN PhTnpDefaultIncrementalSearch(\n    _In_ PPH_TREENEW_CONTEXT Context,\n    _Inout_ PPH_TREENEW_SEARCH_EVENT SearchEvent,\n    _In_ BOOLEAN Partial,\n    _In_ BOOLEAN Wrap\n    )\n{\n    LONG startIndex;\n    LONG currentIndex;\n    LONG foundIndex;\n    BOOLEAN firstTime;\n\n    if (Context->FlatList->Count == 0)\n        return FALSE;\n    if (!Context->FirstColumn)\n        return FALSE;\n\n    startIndex = SearchEvent->StartIndex;\n    currentIndex = startIndex;\n    foundIndex = -1;\n    firstTime = TRUE;\n\n    while (TRUE)\n    {\n        PH_STRINGREF text;\n\n        if (currentIndex >= (LONG)Context->FlatList->Count)\n        {\n            if (Wrap)\n                currentIndex = 0;\n            else\n                break;\n        }\n\n        // We use the firstTime variable instead of a simpler check because we want to include the\n        // current item in the search. E.g. the current item is the only item beginning with \"Z\". If\n        // the user searches for \"Z\", we want to return the current item as being found.\n        if (!firstTime && currentIndex == startIndex)\n            break;\n\n        if (PhTnpGetCellText(Context, Context->FlatList->Items[currentIndex], Context->FirstColumn->Id, &text))\n        {\n            if (Partial)\n            {\n                if (PhStartsWithStringRef(&text, &SearchEvent->String, TRUE))\n                {\n                    foundIndex = currentIndex;\n                    break;\n                }\n            }\n            else\n            {\n                if (PhEqualStringRef(&text, &SearchEvent->String, TRUE))\n                {\n                    foundIndex = currentIndex;\n                    break;\n                }\n            }\n        }\n\n        currentIndex++;\n        firstTime = FALSE;\n    }\n\n    SearchEvent->FoundIndex = foundIndex;\n\n    return TRUE;\n}\n\nVOID PhTnpUpdateScrollBars(\n    _In_ PPH_TREENEW_CONTEXT Context\n    )\n{\n    RECT clientRect;\n    LONG width;\n    LONG height;\n    LONG contentWidth;\n    LONG contentHeight;\n    SCROLLINFO scrollInfo;\n    LONG oldPosition;\n    LONG deltaRows;\n    LONG deltaX;\n    LOGICAL oldHScrollVisible;\n    RECT rect;\n\n    clientRect = Context->ClientRect;\n    width = clientRect.right - Context->FixedWidth;\n    height = clientRect.bottom - Context->HeaderHeight;\n\n    contentWidth = Context->TotalViewX;\n    contentHeight = (LONG)Context->FlatList->Count * Context->RowHeight;\n\n    if (contentHeight > height)\n    {\n        // We need a vertical scrollbar, so we can't use that area of the screen for content.\n        width -= Context->VScrollWidth;\n    }\n\n    if (contentWidth > width)\n    {\n        height -= Context->HScrollHeight;\n    }\n\n    deltaRows = 0;\n    deltaX = 0;\n\n    // Vertical scroll bar\n\n    scrollInfo.cbSize = sizeof(SCROLLINFO);\n    scrollInfo.fMask = SIF_POS;\n    GetScrollInfo(Context->VScrollHandle, SB_CTL, &scrollInfo);\n    oldPosition = scrollInfo.nPos;\n\n    scrollInfo.fMask = SIF_RANGE | SIF_PAGE;\n    scrollInfo.nMin = 0;\n    scrollInfo.nMax = Context->FlatList->Count != 0 ? Context->FlatList->Count - 1 : 0;\n    scrollInfo.nPage = height / Context->RowHeight;\n    SetScrollInfo(Context->VScrollHandle, SB_CTL, &scrollInfo, TRUE);\n\n    // The scroll position may have changed due to the modified scroll range.\n    scrollInfo.fMask = SIF_POS;\n    GetScrollInfo(Context->VScrollHandle, SB_CTL, &scrollInfo);\n    deltaRows = scrollInfo.nPos - oldPosition;\n    Context->VScrollPosition = scrollInfo.nPos;\n\n    if (contentHeight > height && contentHeight != 0)\n    {\n        ShowWindow(Context->VScrollHandle, SW_SHOW);\n        Context->VScrollVisible = TRUE;\n    }\n    else\n    {\n        ShowWindow(Context->VScrollHandle, SW_HIDE);\n        Context->VScrollVisible = FALSE;\n    }\n\n    // Horizontal scroll bar\n\n    scrollInfo.cbSize = sizeof(SCROLLINFO);\n    scrollInfo.fMask = SIF_POS;\n    GetScrollInfo(Context->HScrollHandle, SB_CTL, &scrollInfo);\n    oldPosition = scrollInfo.nPos;\n\n    scrollInfo.fMask = SIF_RANGE | SIF_PAGE;\n    scrollInfo.nMin = 0;\n    scrollInfo.nMax = contentWidth != 0 ? contentWidth - 1 : 0;\n    scrollInfo.nPage = width;\n    SetScrollInfo(Context->HScrollHandle, SB_CTL, &scrollInfo, TRUE);\n\n    scrollInfo.fMask = SIF_POS;\n    GetScrollInfo(Context->HScrollHandle, SB_CTL, &scrollInfo);\n    deltaX = scrollInfo.nPos - oldPosition;\n    Context->HScrollPosition = scrollInfo.nPos;\n\n    oldHScrollVisible = Context->HScrollVisible;\n\n    if (contentWidth > width && contentWidth != 0)\n    {\n        ShowWindow(Context->HScrollHandle, SW_SHOW);\n        Context->HScrollVisible = TRUE;\n    }\n    else\n    {\n        ShowWindow(Context->HScrollHandle, SW_HIDE);\n        Context->HScrollVisible = FALSE;\n    }\n\n    if ((Context->HScrollVisible != oldHScrollVisible) && Context->FixedDividerVisible && Context->AnimateDivider)\n    {\n        rect.left = Context->FixedWidth;\n        rect.top = Context->HeaderHeight;\n        rect.right = Context->FixedWidth + 1;\n        rect.bottom = Context->ClientRect.bottom;\n        InvalidateRect(Context->Handle, &rect, FALSE);\n    }\n\n    if (deltaRows != 0 || deltaX != 0)\n        PhTnpProcessScroll(Context, deltaRows, deltaX);\n\n    ShowWindow(Context->FillerBoxHandle, (Context->VScrollVisible && Context->HScrollVisible) ? SW_SHOW : SW_HIDE);\n}\n\nVOID PhTnpScroll(\n    _In_ PPH_TREENEW_CONTEXT Context,\n    _In_ LONG DeltaRows,\n    _In_ LONG DeltaX\n    )\n{\n    SCROLLINFO scrollInfo;\n    LONG oldPosition;\n    LONG deltaRows;\n    LONG deltaX;\n\n    deltaRows = 0;\n    deltaX = 0;\n\n    scrollInfo.cbSize = sizeof(SCROLLINFO);\n    scrollInfo.fMask = SIF_POS;\n\n    if (DeltaRows != 0 && Context->VScrollVisible)\n    {\n        GetScrollInfo(Context->VScrollHandle, SB_CTL, &scrollInfo);\n        oldPosition = scrollInfo.nPos;\n\n        if (DeltaRows == MINLONG)\n            scrollInfo.nPos = 0;\n        else if (DeltaRows == MAXLONG)\n            scrollInfo.nPos = Context->FlatList->Count - 1;\n        else\n            scrollInfo.nPos += DeltaRows;\n\n        SetScrollInfo(Context->VScrollHandle, SB_CTL, &scrollInfo, TRUE);\n        GetScrollInfo(Context->VScrollHandle, SB_CTL, &scrollInfo);\n        Context->VScrollPosition = scrollInfo.nPos;\n        deltaRows = scrollInfo.nPos - oldPosition;\n    }\n\n    if (DeltaX != 0 && Context->HScrollVisible)\n    {\n        GetScrollInfo(Context->HScrollHandle, SB_CTL, &scrollInfo);\n        oldPosition = scrollInfo.nPos;\n\n        if (DeltaX == MINLONG)\n            scrollInfo.nPos = 0;\n        else if (DeltaX == MAXLONG)\n            scrollInfo.nPos = Context->TotalViewX;\n        else\n            scrollInfo.nPos += DeltaX;\n\n        SetScrollInfo(Context->HScrollHandle, SB_CTL, &scrollInfo, TRUE);\n        GetScrollInfo(Context->HScrollHandle, SB_CTL, &scrollInfo);\n        Context->HScrollPosition = scrollInfo.nPos;\n        deltaX = scrollInfo.nPos - oldPosition;\n    }\n\n    if (deltaRows != 0 || deltaX != 0)\n        PhTnpProcessScroll(Context, deltaRows, deltaX);\n}\n\nVOID PhTnpProcessScroll(\n    _In_ PPH_TREENEW_CONTEXT Context,\n    _In_ LONG DeltaRows,\n    _In_ LONG DeltaX\n    )\n{\n    RECT rect;\n    LONG deltaY;\n\n    rect.top = Context->HeaderHeight;\n    rect.bottom = Context->ClientRect.bottom;\n\n    if (DeltaX == 0)\n    {\n        rect.left = 0;\n        rect.right = Context->ClientRect.right - (Context->VScrollVisible ? Context->VScrollWidth : 0);\n        ScrollWindowEx(\n            Context->Handle,\n            0,\n            -DeltaRows * Context->RowHeight,\n            &rect,\n            NULL,\n            NULL,\n            NULL,\n            SW_INVALIDATE\n            );\n    }\n    else\n    {\n        // Don't scroll if there are no rows. This is especially important if the user wants us to\n        // display empty text.\n        if (Context->FlatList->Count != 0)\n        {\n            deltaY = DeltaRows * Context->RowHeight;\n\n            // If we're scrolling vertically as well, we need to scroll the fixed part and the\n            // normal part separately.\n\n            if (DeltaRows != 0)\n            {\n                rect.left = 0;\n                rect.right = Context->NormalLeft;\n                ScrollWindowEx(\n                    Context->Handle,\n                    0,\n                    -deltaY,\n                    &rect,\n                    &rect,\n                    NULL,\n                    NULL,\n                    SW_INVALIDATE\n                    );\n            }\n\n            rect.left = Context->NormalLeft;\n            rect.right = Context->ClientRect.right - (Context->VScrollVisible ? Context->VScrollWidth : 0);\n            ScrollWindowEx(\n                Context->Handle,\n                -DeltaX,\n                -deltaY,\n                &rect,\n                &rect,\n                NULL,\n                NULL,\n                SW_INVALIDATE\n                );\n        }\n\n        PhTnpLayoutHeader(Context);\n    }\n}\n\nBOOLEAN PhTnpCanScroll(\n    _In_ PPH_TREENEW_CONTEXT Context,\n    _In_ BOOLEAN Horizontal,\n    _In_ BOOLEAN Positive\n    )\n{\n    SCROLLINFO scrollInfo;\n\n    scrollInfo.cbSize = sizeof(SCROLLINFO);\n    scrollInfo.fMask = SIF_RANGE | SIF_PAGE | SIF_POS;\n\n    if (!Horizontal)\n        GetScrollInfo(Context->VScrollHandle, SB_CTL, &scrollInfo);\n    else\n        GetScrollInfo(Context->HScrollHandle, SB_CTL, &scrollInfo);\n\n    if (Positive)\n    {\n        if (scrollInfo.nPage != 0)\n            scrollInfo.nMax -= scrollInfo.nPage - 1;\n\n        return scrollInfo.nPos < scrollInfo.nMax;\n    }\n    else\n    {\n        return scrollInfo.nPos > scrollInfo.nMin;\n    }\n}\n\nVOID PhTnpPaint(\n    _In_ HWND hwnd,\n    _In_ PPH_TREENEW_CONTEXT Context,\n    _In_ HDC hdc,\n    _In_ PRECT PaintRect\n    )\n{\n    RECT viewRect;\n    LONG vScrollPosition;\n    LONG hScrollPosition;\n    LONG firstRowToUpdate;\n    LONG lastRowToUpdate;\n    LONG i;\n    LONG j;\n    PPH_TREENEW_NODE node;\n    PPH_TREENEW_COLUMN column;\n    RECT rowRect;\n    LONG x;\n    BOOLEAN fixedUpdate;\n    LONG normalUpdateLeftX;\n    LONG normalUpdateRightX;\n    LONG normalUpdateLeftIndex;\n    LONG normalUpdateRightIndex;\n    LONG normalTotalX;\n    RECT cellRect;\n    HBRUSH backBrush;\n    HRGN oldClipRegion;\n\n    PhTnpInitializeThemeData(Context);\n\n    viewRect = Context->ClientRect;\n\n    if (Context->VScrollVisible)\n        viewRect.right -= Context->VScrollWidth;\n\n    vScrollPosition = Context->VScrollPosition;\n    hScrollPosition = Context->HScrollPosition;\n\n    // Calculate the indicies of the first and last rows that need painting. These indicies are\n    // relative to the top of the view area.\n\n    firstRowToUpdate = (PaintRect->top - Context->HeaderHeight) / Context->RowHeight;\n    lastRowToUpdate = (PaintRect->bottom - 1 - Context->HeaderHeight) / Context->RowHeight; // minus one since bottom is exclusive\n\n    if (firstRowToUpdate < 0)\n        firstRowToUpdate = 0;\n\n    rowRect.left = 0;\n    rowRect.top = Context->HeaderHeight + firstRowToUpdate * Context->RowHeight;\n    rowRect.right = Context->NormalLeft + Context->TotalViewX - Context->HScrollPosition;\n    rowRect.bottom = rowRect.top + Context->RowHeight;\n\n    // Change the indicies to absolute row indicies.\n\n    firstRowToUpdate += vScrollPosition;\n    lastRowToUpdate += vScrollPosition;\n\n    if (lastRowToUpdate >= (LONG)Context->FlatList->Count)\n        lastRowToUpdate = Context->FlatList->Count - 1; // becomes -1 when there are no items, handled correctly by loop below\n\n    // Determine whether the fixed column needs painting, and which normal columns need painting.\n\n    fixedUpdate = FALSE;\n\n    if (Context->FixedColumnVisible && PaintRect->left < Context->FixedWidth)\n        fixedUpdate = TRUE;\n\n    x = Context->NormalLeft - hScrollPosition;\n    normalUpdateLeftX = viewRect.right;\n    normalUpdateLeftIndex = 0;\n    normalUpdateRightX = 0;\n    normalUpdateRightIndex = -1;\n\n    for (j = 0; j < (LONG)Context->NumberOfColumnsByDisplay; j++)\n    {\n        column = Context->ColumnsByDisplay[j];\n\n        if (x + column->Width >= Context->NormalLeft && x + column->Width > PaintRect->left && x < PaintRect->right)\n        {\n            if (normalUpdateLeftX > x)\n            {\n                normalUpdateLeftX = x;\n                normalUpdateLeftIndex = j;\n            }\n\n            if (normalUpdateRightX < x + column->Width)\n            {\n                normalUpdateRightX = x + column->Width;\n                normalUpdateRightIndex = j;\n            }\n        }\n\n        x += column->Width;\n    }\n\n    normalTotalX = x;\n\n    if (normalUpdateRightIndex >= (LONG)Context->NumberOfColumnsByDisplay)\n        normalUpdateRightIndex = Context->NumberOfColumnsByDisplay - 1;\n\n    // Paint the rows.\n\n    SelectObject(hdc, Context->Font);\n    SetBkMode(hdc, TRANSPARENT);\n\n    for (i = firstRowToUpdate; i <= lastRowToUpdate; i++)\n    {\n        node = Context->FlatList->Items[i];\n\n        // Prepare the row for drawing.\n\n        PhTnpPrepareRowForDraw(Context, hdc, node);\n\n        if (node->Selected && !Context->ThemeHasItemBackground)\n        {\n            // Non-themed background\n            if (Context->HasFocus)\n            {\n                SetTextColor(hdc, GetSysColor(COLOR_HIGHLIGHTTEXT));\n                backBrush = GetSysColorBrush(COLOR_HIGHLIGHT);\n            }\n            else\n            {\n                SetTextColor(hdc, GetSysColor(COLOR_BTNTEXT));\n                backBrush = GetSysColorBrush(COLOR_BTNFACE);\n            }\n        }\n        else\n        {\n            SetTextColor(hdc, node->s.DrawForeColor);\n            SetDCBrushColor(hdc, node->s.DrawBackColor);\n            backBrush = GetStockObject(DC_BRUSH);\n        }\n\n        FillRect(hdc, &rowRect, backBrush);\n\n        if (Context->ThemeHasItemBackground)\n        {\n            INT stateId;\n\n            // Themed background\n\n            if (node->Selected)\n            {\n                if (i == Context->HotNodeIndex)\n                    stateId = TREIS_HOTSELECTED;\n                else if (!Context->HasFocus)\n                    stateId = TREIS_SELECTEDNOTFOCUS;\n                else\n                    stateId = TREIS_SELECTED;\n            }\n            else\n            {\n                if (i == Context->HotNodeIndex)\n                    stateId = TREIS_HOT;\n                else\n                    stateId = -1;\n            }\n\n            if (stateId != -1)\n            {\n                if (!Context->FixedColumnVisible)\n                {\n                    rowRect.left = Context->NormalLeft - hScrollPosition;\n                }\n\n                DrawThemeBackground(\n                    Context->ThemeData,\n                    hdc,\n                    TVP_TREEITEM,\n                    stateId,\n                    &rowRect,\n                    PaintRect\n                    );\n            }\n        }\n\n        // Paint the fixed column.\n\n        cellRect.top = rowRect.top;\n        cellRect.bottom = rowRect.bottom;\n\n        if (fixedUpdate)\n        {\n            cellRect.left = 0;\n            cellRect.right = Context->FixedWidth;\n            PhTnpDrawCell(Context, hdc, &cellRect, node, Context->FixedColumn, i, -1);\n        }\n\n        // Paint the normal columns.\n\n        if (normalUpdateLeftX < normalUpdateRightX)\n        {\n            cellRect.left = normalUpdateLeftX;\n            cellRect.right = cellRect.left;\n\n            oldClipRegion = CreateRectRgn(0, 0, 0, 0);\n\n            if (GetClipRgn(hdc, oldClipRegion) != 1)\n            {\n                DeleteObject(oldClipRegion);\n                oldClipRegion = NULL;\n            }\n\n            IntersectClipRect(hdc, Context->NormalLeft, cellRect.top, viewRect.right, cellRect.bottom);\n\n            for (j = normalUpdateLeftIndex; j <= normalUpdateRightIndex; j++)\n            {\n                column = Context->ColumnsByDisplay[j];\n\n                cellRect.left = cellRect.right;\n                cellRect.right = cellRect.left + column->Width;\n                PhTnpDrawCell(Context, hdc, &cellRect, node, column, i, j);\n            }\n\n            SelectClipRgn(hdc, oldClipRegion);\n\n            if (oldClipRegion)\n            {\n                DeleteObject(oldClipRegion);\n            }\n        }\n\n        rowRect.top += Context->RowHeight;\n        rowRect.bottom += Context->RowHeight;\n    }\n\n    if (lastRowToUpdate == Context->FlatList->Count - 1) // works even if there are no items\n    {\n        // Fill the rest of the space on the bottom with the window color.\n        rowRect.bottom = viewRect.bottom;\n        FillRect(hdc, &rowRect, GetSysColorBrush(COLOR_WINDOW));\n    }\n\n    if (normalTotalX < viewRect.right && viewRect.right > PaintRect->left && normalTotalX < PaintRect->right)\n    {\n        // Fill the rest of the space on the right with the window color.\n        rowRect.left = normalTotalX;\n        rowRect.top = Context->HeaderHeight;\n        rowRect.right = viewRect.right;\n        rowRect.bottom = viewRect.bottom;\n        FillRect(hdc, &rowRect, GetSysColorBrush(COLOR_WINDOW));\n    }\n\n    if (Context->FlatList->Count == 0 && Context->EmptyText.Length != 0)\n    {\n        RECT textRect;\n\n        textRect.left = 20;\n        textRect.top = Context->HeaderHeight + 10;\n        textRect.right = viewRect.right - 20;\n        textRect.bottom = viewRect.bottom - 5;\n\n        SetTextColor(hdc, GetSysColor(COLOR_GRAYTEXT));\n        DrawText(\n            hdc,\n            Context->EmptyText.Buffer,\n            (ULONG)Context->EmptyText.Length / 2,\n            &textRect,\n            DT_NOPREFIX | DT_CENTER | DT_END_ELLIPSIS\n            );\n    }\n\n    if (Context->FixedDividerVisible && Context->FixedWidth >= PaintRect->left && Context->FixedWidth < PaintRect->right)\n    {\n        PhTnpDrawDivider(Context, hdc);\n    }\n\n    if (Context->DragSelectionActive)\n    {\n        PhTnpDrawSelectionRectangle(Context, hdc, &Context->DragRect);\n    }\n}\n\nVOID PhTnpPrepareRowForDraw(\n    _In_ PPH_TREENEW_CONTEXT Context,\n    _In_ HDC hdc,\n    _Inout_ PPH_TREENEW_NODE Node\n    )\n{\n    if (!Node->s.CachedColorValid)\n    {\n        PH_TREENEW_GET_NODE_COLOR getNodeColor;\n\n        getNodeColor.Flags = 0;\n        getNodeColor.Node = Node;\n        getNodeColor.BackColor = Context->DefaultBackColor;\n        getNodeColor.ForeColor = Context->DefaultForeColor;\n\n        if (Context->Callback(\n            Context->Handle,\n            TreeNewGetNodeColor,\n            &getNodeColor,\n            NULL,\n            Context->CallbackContext\n            ))\n        {\n            Node->BackColor = getNodeColor.BackColor;\n            Node->ForeColor = getNodeColor.ForeColor;\n            Node->UseAutoForeColor = !!(getNodeColor.Flags & TN_AUTO_FORECOLOR);\n\n            if (getNodeColor.Flags & TN_CACHE)\n                Node->s.CachedColorValid = TRUE;\n        }\n        else\n        {\n            Node->BackColor = getNodeColor.BackColor;\n            Node->ForeColor = getNodeColor.ForeColor;\n        }\n    }\n\n    Node->s.DrawForeColor = Node->ForeColor;\n\n    if (Node->UseTempBackColor)\n        Node->s.DrawBackColor = Node->TempBackColor;\n    else\n        Node->s.DrawBackColor = Node->BackColor;\n\n    if (!Node->s.CachedFontValid)\n    {\n        PH_TREENEW_GET_NODE_FONT getNodeFont;\n\n        getNodeFont.Flags = 0;\n        getNodeFont.Node = Node;\n        getNodeFont.Font = NULL;\n\n        if (Context->Callback(\n            Context->Handle,\n            TreeNewGetNodeFont,\n            &getNodeFont,\n            NULL,\n            Context->CallbackContext\n            ))\n        {\n            Node->Font = getNodeFont.Font;\n\n            if (getNodeFont.Flags & TN_CACHE)\n                Node->s.CachedFontValid = TRUE;\n        }\n        else\n        {\n            Node->Font = NULL;\n        }\n    }\n\n    if (!Node->s.CachedIconValid)\n    {\n        PH_TREENEW_GET_NODE_ICON getNodeIcon;\n\n        getNodeIcon.Flags = 0;\n        getNodeIcon.Node = Node;\n        getNodeIcon.Icon = NULL;\n\n        if (Context->Callback(\n            Context->Handle,\n            TreeNewGetNodeIcon,\n            &getNodeIcon,\n            NULL,\n            Context->CallbackContext\n            ))\n        {\n            Node->Icon = getNodeIcon.Icon;\n\n            if (getNodeIcon.Flags & TN_CACHE)\n                Node->s.CachedIconValid = TRUE;\n        }\n        else\n        {\n            Node->Icon = NULL;\n        }\n    }\n\n    if (Node->UseAutoForeColor || Node->UseTempBackColor)\n    {\n        if (PhGetColorBrightness(Node->s.DrawBackColor) > 100) // slightly less than half\n            Node->s.DrawForeColor = RGB(0x00, 0x00, 0x00);\n        else\n            Node->s.DrawForeColor = RGB(0xff, 0xff, 0xff);\n    }\n}\n\nVOID PhTnpDrawCell(\n    _In_ PPH_TREENEW_CONTEXT Context,\n    _In_ HDC hdc,\n    _In_ PRECT CellRect,\n    _In_ PPH_TREENEW_NODE Node,\n    _In_ PPH_TREENEW_COLUMN Column,\n    _In_ LONG RowIndex,\n    _In_ LONG ColumnIndex\n    )\n{\n    HFONT font; // font to use\n    HFONT oldFont;\n    PH_STRINGREF text; // text to draw\n    RECT textRect; // working rectangle, modified as needed\n    ULONG textFlags; // DT_* flags\n    LONG iconVerticalMargin; // top/bottom margin for icons (determined using height of small icon)\n\n    font = Node->Font;\n    textFlags = Column->TextFlags;\n\n    textRect = *CellRect;\n\n    // Initial margins used by default list view\n    textRect.left += TNP_CELL_LEFT_MARGIN;\n    textRect.right -= TNP_CELL_RIGHT_MARGIN;\n\n    // icon margin = (height of row - height of small icon) / 2\n    iconVerticalMargin = ((textRect.bottom - textRect.top) - SmallIconHeight) / 2;\n\n    textRect.top += iconVerticalMargin;\n    textRect.bottom -= iconVerticalMargin;\n\n    if (Column == Context->FirstColumn)\n    {\n        BOOLEAN needsClip;\n        HRGN oldClipRegion;\n\n        textRect.left += Node->Level * SmallIconWidth;\n\n        // The icon may need to be clipped if the column is too small.\n        needsClip = Column->Width < textRect.left + (Context->CanAnyExpand ? SmallIconWidth : 0) + (Node->Icon ? SmallIconWidth : 0);\n\n        if (needsClip)\n        {\n            oldClipRegion = CreateRectRgn(0, 0, 0, 0);\n\n            if (GetClipRgn(hdc, oldClipRegion) != 1)\n            {\n                DeleteObject(oldClipRegion);\n                oldClipRegion = NULL;\n            }\n\n            // Clip contents to the column.\n            IntersectClipRect(hdc, CellRect->left, textRect.top, CellRect->right, textRect.bottom);\n        }\n\n        if (Context->CanAnyExpand) // flag is used so we can avoid indenting when it's a flat list\n        {\n            BOOLEAN drewUsingTheme = FALSE;\n            RECT themeRect;\n\n            if (!Node->s.IsLeaf)\n            {\n                // Draw the plus/minus glyph.\n\n                themeRect.left = textRect.left;\n                themeRect.right = themeRect.left + SmallIconWidth;\n                themeRect.top = textRect.top;\n                themeRect.bottom = themeRect.top + SmallIconHeight;\n\n                if (Context->ThemeHasGlyph)\n                {\n                    INT partId;\n                    INT stateId;\n\n                    partId = (RowIndex == Context->HotNodeIndex && Node->s.PlusMinusHot && Context->ThemeHasHotGlyph) ? TVP_HOTGLYPH : TVP_GLYPH;\n                    stateId = Node->Expanded ? GLPS_OPENED : GLPS_CLOSED;\n\n                    if (SUCCEEDED(DrawThemeBackground(\n                        Context->ThemeData,\n                        hdc,\n                        partId,\n                        stateId,\n                        &themeRect,\n                        NULL\n                        )))\n                        drewUsingTheme = TRUE;\n                }\n\n                if (!drewUsingTheme)\n                {\n                    ULONG glyphWidth;\n                    ULONG glyphHeight;\n                    RECT glyphRect;\n\n                    glyphWidth = SmallIconWidth / 2;\n                    glyphHeight = SmallIconHeight / 2;\n\n                    glyphRect.left = textRect.left + (SmallIconWidth - glyphWidth) / 2;\n                    glyphRect.right = glyphRect.left + glyphWidth;\n                    glyphRect.top = textRect.top + (SmallIconHeight - glyphHeight) / 2;\n                    glyphRect.bottom = glyphRect.top + glyphHeight;\n\n                    PhTnpDrawPlusMinusGlyph(hdc, &glyphRect, !Node->Expanded);\n                }\n            }\n\n            textRect.left += SmallIconWidth;\n        }\n\n        // Draw the icon.\n        if (Node->Icon)\n        {\n            DrawIconEx(\n                hdc,\n                textRect.left,\n                textRect.top,\n                Node->Icon,\n                SmallIconWidth,\n                SmallIconHeight,\n                0,\n                NULL,\n                DI_NORMAL\n                );\n\n            textRect.left += SmallIconWidth + TNP_ICON_RIGHT_PADDING;\n        }\n\n        if (needsClip)\n        {\n            SelectClipRgn(hdc, oldClipRegion);\n\n            if (oldClipRegion)\n                DeleteObject(oldClipRegion);\n        }\n\n        if (textRect.left > textRect.right)\n            textRect.left = textRect.right;\n    }\n\n    if (Column->CustomDraw)\n    {\n        BOOLEAN result;\n        PH_TREENEW_CUSTOM_DRAW customDraw;\n        INT savedDc;\n\n        customDraw.Node = Node;\n        customDraw.Column = Column;\n        customDraw.Dc = hdc;\n        customDraw.CellRect = *CellRect;\n        customDraw.TextRect = textRect;\n\n        // Fix up the rectangles before giving them to the user.\n        if (customDraw.CellRect.left > customDraw.CellRect.right)\n            customDraw.CellRect.left = customDraw.CellRect.right;\n        if (customDraw.TextRect.left > customDraw.TextRect.right)\n            customDraw.TextRect.left = customDraw.TextRect.right;\n\n        savedDc = SaveDC(hdc);\n        result = Context->Callback(Context->Handle, TreeNewCustomDraw, &customDraw, NULL, Context->CallbackContext);\n        RestoreDC(hdc, savedDc);\n\n        if (result)\n            return;\n    }\n\n    if (PhTnpGetCellText(Context, Node, Column->Id, &text))\n    {\n        if (!(textFlags & (DT_PATH_ELLIPSIS | DT_WORD_ELLIPSIS)))\n            textFlags |= DT_END_ELLIPSIS;\n\n        textFlags |= DT_NOPREFIX | DT_VCENTER | DT_SINGLELINE;\n\n        textRect.top = CellRect->top;\n        textRect.bottom = CellRect->bottom;\n\n        if (font)\n            oldFont = SelectObject(hdc, font);\n\n        DrawText(\n            hdc,\n            text.Buffer,\n            (ULONG)text.Length / 2,\n            &textRect,\n            textFlags\n            );\n\n        if (font)\n            SelectObject(hdc, oldFont);\n    }\n}\n\nVOID PhTnpDrawDivider(\n    _In_ PPH_TREENEW_CONTEXT Context,\n    _In_ HDC hdc\n    )\n{\n    POINT points[2];\n\n    if (Context->AnimateDivider)\n    {\n        if (Context->DividerHot == 0 && !Context->HScrollVisible)\n            return; // divider is invisible\n\n        if (Context->DividerHot < 100)\n        {\n            BLENDFUNCTION blendFunction;\n\n            // We need to draw and alpha blend the divider.\n            // We can use the extra column allocated in the buffered context to initially draw the\n            // divider.\n\n            points[0].x = Context->ClientRect.right;\n            points[0].y = Context->HeaderHeight;\n            points[1].x = Context->ClientRect.right;\n            points[1].y = Context->ClientRect.bottom;\n            SetDCPenColor(Context->BufferedContext, RGB(0x77, 0x77, 0x77));\n            SelectObject(Context->BufferedContext, GetStockObject(DC_PEN));\n            Polyline(Context->BufferedContext, points, 2);\n\n            blendFunction.BlendOp = AC_SRC_OVER;\n            blendFunction.BlendFlags = 0;\n            blendFunction.AlphaFormat = 0;\n\n            // If the horizontal scroll bar is visible, we need to display a line even if the\n            // divider is not hot. In this case we increase the base alpha value.\n            if (!Context->HScrollVisible)\n                blendFunction.SourceConstantAlpha = (UCHAR)(Context->DividerHot * 255 / 100);\n            else\n                blendFunction.SourceConstantAlpha = 55 + (UCHAR)(Context->DividerHot * 2);\n\n            GdiAlphaBlend(\n                hdc,\n                Context->FixedWidth,\n                Context->HeaderHeight,\n                1,\n                Context->ClientRect.bottom - Context->HeaderHeight,\n                Context->BufferedContext,\n                Context->ClientRect.right,\n                Context->HeaderHeight,\n                1,\n                Context->ClientRect.bottom - Context->HeaderHeight,\n                blendFunction\n                );\n\n            return;\n        }\n    }\n\n    points[0].x = Context->FixedWidth;\n    points[0].y = Context->HeaderHeight;\n    points[1].x = Context->FixedWidth;\n    points[1].y = Context->ClientRect.bottom;\n    SetDCPenColor(hdc, RGB(0x77, 0x77, 0x77));\n    SelectObject(hdc, GetStockObject(DC_PEN));\n    Polyline(hdc, points, 2);\n}\n\nVOID PhTnpDrawPlusMinusGlyph(\n    _In_ HDC hdc,\n    _In_ PRECT Rect,\n    _In_ BOOLEAN Plus\n    )\n{\n    INT savedDc;\n    ULONG width;\n    ULONG height;\n    POINT points[2];\n\n    savedDc = SaveDC(hdc);\n\n    SelectObject(hdc, GetStockObject(DC_PEN));\n    SetDCPenColor(hdc, RGB(0x55, 0x55, 0x55));\n    SelectObject(hdc, GetStockObject(DC_BRUSH));\n    SetDCBrushColor(hdc, RGB(0xff, 0xff, 0xff));\n\n    width = Rect->right - Rect->left;\n    height = Rect->bottom - Rect->top;\n\n    // Draw the rectangle.\n    Rectangle(hdc, Rect->left, Rect->top, Rect->right + 1, Rect->bottom + 1);\n\n    SetDCPenColor(hdc, RGB(0x00, 0x00, 0x00));\n\n    // Draw the horizontal line.\n    points[0].x = Rect->left + 2;\n    points[0].y = Rect->top + height / 2;\n    points[1].x = Rect->right - 2 + 1;\n    points[1].y = points[0].y;\n    Polyline(hdc, points, 2);\n\n    if (Plus)\n    {\n        // Draw the vertical line.\n        points[0].x = Rect->left + width / 2;\n        points[0].y = Rect->top + 2;\n        points[1].x = points[0].x;\n        points[1].y = Rect->bottom - 2 + 1;\n        Polyline(hdc, points, 2);\n    }\n\n    RestoreDC(hdc, savedDc);\n}\n\nVOID PhTnpDrawSelectionRectangle(\n    _In_ PPH_TREENEW_CONTEXT Context,\n    _In_ HDC hdc,\n    _In_ PRECT Rect\n    )\n{\n    RECT rect;\n    BOOLEAN drewWithAlpha;\n\n    rect = *Rect;\n\n    // MSDN says FrameRect/DrawFocusRect doesn't draw anything if bottom <= top or right <= left.\n    // That's complete rubbish.\n    if (rect.right - rect.left == 0 || rect.bottom - rect.top == 0)\n        return;\n\n    drewWithAlpha = FALSE;\n\n    if (Context->SelectionRectangleAlpha)\n    {\n        HDC tempDc;\n        BITMAPINFOHEADER header;\n        HBITMAP bitmap;\n        HBITMAP oldBitmap;\n        PVOID bits;\n        RECT tempRect;\n        BLENDFUNCTION blendFunction;\n\n        tempDc = CreateCompatibleDC(hdc);\n\n        if (tempDc)\n        {\n            memset(&header, 0, sizeof(BITMAPINFOHEADER));\n            header.biSize = sizeof(BITMAPINFOHEADER);\n            header.biWidth = 1;\n            header.biHeight = 1;\n            header.biPlanes = 1;\n            header.biBitCount = 24;\n            bitmap = CreateDIBSection(tempDc, (BITMAPINFO *)&header, DIB_RGB_COLORS, &bits, NULL, 0);\n\n            if (bitmap)\n            {\n                // Draw the outline of the selection rectangle.\n                FrameRect(hdc, &rect, GetSysColorBrush(COLOR_HIGHLIGHT));\n\n                // Fill in the selection rectangle.\n\n                oldBitmap = SelectObject(tempDc, bitmap);\n                tempRect.left = 0;\n                tempRect.top = 0;\n                tempRect.right = 1;\n                tempRect.bottom = 1;\n                FillRect(tempDc, &tempRect, GetSysColorBrush(COLOR_HOTLIGHT));\n\n                blendFunction.BlendOp = AC_SRC_OVER;\n                blendFunction.BlendFlags = 0;\n                blendFunction.SourceConstantAlpha = 70;\n                blendFunction.AlphaFormat = 0;\n\n                GdiAlphaBlend(\n                    hdc,\n                    rect.left,\n                    rect.top,\n                    rect.right - rect.left,\n                    rect.bottom - rect.top,\n                    tempDc,\n                    0,\n                    0,\n                    1,\n                    1,\n                    blendFunction\n                    );\n\n                drewWithAlpha = TRUE;\n\n                SelectObject(tempDc, oldBitmap);\n                DeleteObject(bitmap);\n            }\n\n            DeleteDC(tempDc);\n        }\n    }\n\n    if (!drewWithAlpha)\n    {\n        DrawFocusRect(hdc, &rect);\n    }\n}\n\nVOID PhTnpDrawThemedBorder(\n    _In_ PPH_TREENEW_CONTEXT Context,\n    _In_ HDC hdc\n    )\n{\n    RECT windowRect;\n    RECT clientRect;\n    LONG sizingBorderWidth;\n    LONG borderX;\n    LONG borderY;\n\n    GetWindowRect(Context->Handle, &windowRect);\n    windowRect.right -= windowRect.left;\n    windowRect.bottom -= windowRect.top;\n    windowRect.left = 0;\n    windowRect.top = 0;\n\n    clientRect.left = windowRect.left + Context->SystemEdgeX;\n    clientRect.top = windowRect.top + Context->SystemEdgeY;\n    clientRect.right = windowRect.right - Context->SystemEdgeX;\n    clientRect.bottom = windowRect.bottom - Context->SystemEdgeY;\n\n    // Make sure we don't paint in the client area.\n    ExcludeClipRect(hdc, clientRect.left, clientRect.top, clientRect.right, clientRect.bottom);\n\n    // Draw the themed border.\n    DrawThemeBackground(Context->ThemeData, hdc, 0, 0, &windowRect, NULL);\n\n    // Calculate the size of the border we just drew, and fill in the rest of the space if we didn't\n    // fully paint the region.\n\n    if (SUCCEEDED(GetThemeInt(Context->ThemeData, 0, 0, TMT_SIZINGBORDERWIDTH, &sizingBorderWidth)))\n    {\n        borderX = sizingBorderWidth;\n        borderY = sizingBorderWidth;\n    }\n    else\n    {\n        borderX = Context->SystemBorderX;\n        borderY = Context->SystemBorderY;\n    }\n\n    if (borderX < Context->SystemEdgeX || borderY < Context->SystemEdgeY)\n    {\n        windowRect.left += Context->SystemEdgeX - borderX;\n        windowRect.top += Context->SystemEdgeY - borderY;\n        windowRect.right -= Context->SystemEdgeX - borderX;\n        windowRect.bottom -= Context->SystemEdgeY - borderY;\n        FillRect(hdc, &windowRect, GetSysColorBrush(COLOR_WINDOW));\n    }\n}\n\nVOID PhTnpInitializeTooltips(\n    _In_ PPH_TREENEW_CONTEXT Context\n    )\n{\n    TOOLINFO toolInfo;\n\n    Context->TooltipsHandle = CreateWindowEx(\n        WS_EX_TRANSPARENT, // solves double-click problem\n        TOOLTIPS_CLASS,\n        NULL,\n        WS_POPUP | TTS_NOPREFIX | TTS_ALWAYSTIP,\n        0,\n        0,\n        0,\n        0,\n        NULL,\n        NULL,\n        Context->InstanceHandle,\n        NULL\n        );\n\n    if (!Context->TooltipsHandle)\n        return;\n\n    // Item tooltips\n    memset(&toolInfo, 0, sizeof(TOOLINFO));\n    toolInfo.cbSize = sizeof(TOOLINFO);\n    toolInfo.uFlags = TTF_TRANSPARENT;\n    toolInfo.hwnd = Context->Handle;\n    toolInfo.uId = TNP_TOOLTIPS_ITEM;\n    toolInfo.lpszText = LPSTR_TEXTCALLBACK;\n    toolInfo.lParam = TNP_TOOLTIPS_ITEM;\n    SendMessage(Context->TooltipsHandle, TTM_ADDTOOL, 0, (LPARAM)&toolInfo);\n\n    // Fixed column tooltips\n    toolInfo.uFlags = 0;\n    toolInfo.hwnd = Context->FixedHeaderHandle;\n    toolInfo.uId = TNP_TOOLTIPS_FIXED_HEADER;\n    toolInfo.lpszText = LPSTR_TEXTCALLBACK;\n    toolInfo.lParam = TNP_TOOLTIPS_FIXED_HEADER;\n    SendMessage(Context->TooltipsHandle, TTM_ADDTOOL, 0, (LPARAM)&toolInfo);\n\n    // Normal column tooltips\n    toolInfo.uFlags = 0;\n    toolInfo.hwnd = Context->HeaderHandle;\n    toolInfo.uId = TNP_TOOLTIPS_HEADER;\n    toolInfo.lpszText = LPSTR_TEXTCALLBACK;\n    toolInfo.lParam = TNP_TOOLTIPS_HEADER;\n    SendMessage(Context->TooltipsHandle, TTM_ADDTOOL, 0, (LPARAM)&toolInfo);\n\n    // Hook the header control window procedures so we can forward mouse messages to the tooltip\n    // control.\n    SetWindowSubclass(Context->FixedHeaderHandle, PhTnpHeaderHookWndProc, 0, (ULONG_PTR)Context);\n    SetWindowSubclass(Context->HeaderHandle, PhTnpHeaderHookWndProc, 0, (ULONG_PTR)Context);\n\n    SendMessage(Context->TooltipsHandle, TTM_SETMAXTIPWIDTH, 0, MAXSHORT); // no limit\n    SendMessage(Context->TooltipsHandle, WM_SETFONT, (WPARAM)Context->Font, FALSE);\n    Context->TooltipFont = Context->Font;\n}\n\nVOID PhTnpGetTooltipText(\n    _In_ PPH_TREENEW_CONTEXT Context,\n    _In_ PPOINT Point,\n    _Out_ PWSTR *Text\n    )\n{\n    PH_TREENEW_HIT_TEST hitTest;\n    BOOLEAN unfoldingTooltip;\n    BOOLEAN unfoldingTooltipFromViewCancelled;\n    PH_TREENEW_CELL_PARTS parts;\n    LONG viewRight;\n    PH_TREENEW_GET_CELL_TOOLTIP getCellTooltip;\n\n    hitTest.Point = *Point;\n    hitTest.InFlags = TN_TEST_COLUMN | TN_TEST_SUBITEM;\n    PhTnpHitTest(Context, &hitTest);\n\n    if (Context->DragSelectionActive)\n        return;\n    if (!(hitTest.Flags & TN_HIT_ITEM))\n        return;\n    if (hitTest.Flags & (TN_HIT_ITEM_PLUSMINUS | TN_HIT_DIVIDER))\n        return;\n    if (!hitTest.Column)\n        return;\n\n    if (Context->TooltipIndex != hitTest.Node->Index || Context->TooltipId != hitTest.Column->Id)\n    {\n        Context->TooltipIndex = hitTest.Node->Index;\n        Context->TooltipId = hitTest.Column->Id;\n\n        getCellTooltip.Flags = 0;\n        getCellTooltip.Node = hitTest.Node;\n        getCellTooltip.Column = hitTest.Column;\n        getCellTooltip.Unfolding = FALSE;\n        PhInitializeEmptyStringRef(&getCellTooltip.Text);\n        getCellTooltip.Font = Context->Font;\n        getCellTooltip.MaximumWidth = -1;\n\n        unfoldingTooltip = FALSE;\n        unfoldingTooltipFromViewCancelled = FALSE;\n\n        if (!(Context->ExtendedFlags & TN_FLAG_NO_UNFOLDING_TOOLTIPS) &&\n            PhTnpGetCellParts(Context, hitTest.Node->Index, hitTest.Column, TN_MEASURE_TEXT, &parts) &&\n            (parts.Flags & TN_PART_CONTENT) && (parts.Flags & TN_PART_TEXT))\n        {\n            viewRight = Context->ClientRect.right - (Context->VScrollVisible ? Context->VScrollWidth : 0);\n\n            // Use an unfolding tooltip if the text was truncated within the column, or the text\n            // extends beyond the view area in either direction.\n\n            if (parts.TextRect.left < parts.ContentRect.left || parts.TextRect.right > parts.ContentRect.right)\n            {\n                unfoldingTooltip = TRUE;\n            }\n            else if ((!hitTest.Column->Fixed && parts.TextRect.left < Context->NormalLeft) || parts.TextRect.right > viewRight)\n            {\n                // Only show view-based unfolding tooltips if the mouse is over the text itself.\n                if (Point->x >= parts.TextRect.left && Point->x < parts.TextRect.right)\n                    unfoldingTooltip = TRUE;\n                else\n                    unfoldingTooltipFromViewCancelled = TRUE;\n            }\n\n            if (unfoldingTooltip)\n            {\n                getCellTooltip.Unfolding = TRUE;\n                getCellTooltip.Text = parts.Text;\n                getCellTooltip.Font = parts.Font; // try to use the same font as the cell\n\n                Context->TooltipRect = parts.TextRect;\n            }\n        }\n\n        Context->Callback(Context->Handle, TreeNewGetCellTooltip, &getCellTooltip, NULL, Context->CallbackContext);\n\n        Context->TooltipUnfolding = getCellTooltip.Unfolding;\n\n        if (getCellTooltip.Text.Buffer && getCellTooltip.Text.Length != 0)\n        {\n            PhMoveReference(&Context->TooltipText, PhCreateString2(&getCellTooltip.Text));\n        }\n        else\n        {\n            PhClearReference(&Context->TooltipText);\n\n            if (unfoldingTooltipFromViewCancelled)\n            {\n                // We may need to show the view-based unfolding tooltip if the mouse moves over the\n                // text in the future. Reset the index and ID to make sure we keep checking.\n                Context->TooltipIndex = -1;\n                Context->TooltipId = -1;\n            }\n        }\n\n        Context->NewTooltipFont = getCellTooltip.Font;\n\n        if (!Context->NewTooltipFont)\n            Context->NewTooltipFont = Context->Font;\n\n        if (getCellTooltip.MaximumWidth <= MAXSHORT) // seems to be the maximum value that the tooltip control supports\n            SendMessage(Context->TooltipsHandle, TTM_SETMAXTIPWIDTH, 0, getCellTooltip.MaximumWidth);\n        else\n            SendMessage(Context->TooltipsHandle, TTM_SETMAXTIPWIDTH, 0, MAXSHORT);\n    }\n\n    if (Context->TooltipText)\n        *Text = Context->TooltipText->Buffer;\n}\n\nBOOLEAN PhTnpPrepareTooltipShow(\n    _In_ PPH_TREENEW_CONTEXT Context\n    )\n{\n    RECT rect;\n\n    if (Context->TooltipFont != Context->NewTooltipFont)\n    {\n        Context->TooltipFont = Context->NewTooltipFont;\n        SendMessage(Context->TooltipsHandle, WM_SETFONT, (WPARAM)Context->TooltipFont, FALSE);\n    }\n\n    if (!Context->TooltipUnfolding)\n    {\n        SetWindowPos(\n            Context->TooltipsHandle,\n            HWND_TOPMOST,\n            0,\n            0,\n            0,\n            0,\n            SWP_NOSIZE | SWP_NOMOVE | SWP_NOACTIVATE | SWP_HIDEWINDOW\n            );\n\n        return FALSE;\n    }\n\n    rect = Context->TooltipRect;\n    SendMessage(Context->TooltipsHandle, TTM_ADJUSTRECT, TRUE, (LPARAM)&rect);\n    MapWindowPoints(Context->Handle, NULL, (POINT *)&rect, 2);\n    SetWindowPos(\n        Context->TooltipsHandle,\n        HWND_TOPMOST,\n        rect.left,\n        rect.top,\n        0,\n        0,\n        SWP_NOSIZE | SWP_NOACTIVATE | SWP_HIDEWINDOW\n        );\n\n    return TRUE;\n}\n\nVOID PhTnpPrepareTooltipPop(\n    _In_ PPH_TREENEW_CONTEXT Context\n    )\n{\n    Context->TooltipIndex = -1;\n    Context->TooltipId = -1;\n    Context->TooltipColumnId = -1;\n}\n\nVOID PhTnpPopTooltip(\n    _In_ PPH_TREENEW_CONTEXT Context\n    )\n{\n    if (Context->TooltipsHandle)\n    {\n        SendMessage(Context->TooltipsHandle, TTM_POP, 0, 0);\n        PhTnpPrepareTooltipPop(Context);\n    }\n}\n\nPPH_TREENEW_COLUMN PhTnpHitTestHeader(\n    _In_ PPH_TREENEW_CONTEXT Context,\n    _In_ BOOLEAN Fixed,\n    _In_ PPOINT Point,\n    _Out_opt_ PRECT ItemRect\n    )\n{\n    PPH_TREENEW_COLUMN column;\n    RECT itemRect;\n\n    if (Fixed)\n    {\n        if (!Context->FixedColumnVisible)\n            return NULL;\n\n        column = Context->FixedColumn;\n\n        if (!Header_GetItemRect(Context->FixedHeaderHandle, 0, &itemRect))\n            return NULL;\n    }\n    else\n    {\n        HDHITTESTINFO hitTestInfo;\n\n        hitTestInfo.pt = *Point;\n        hitTestInfo.flags = 0;\n        hitTestInfo.iItem = -1;\n\n        if (SendMessage(Context->HeaderHandle, HDM_HITTEST, 0, (LPARAM)&hitTestInfo) != -1 && hitTestInfo.iItem != -1)\n        {\n            HDITEM item;\n\n            item.mask = HDI_LPARAM;\n\n            if (!Header_GetItem(Context->HeaderHandle, hitTestInfo.iItem, &item))\n                return NULL;\n\n            column = (PPH_TREENEW_COLUMN)item.lParam;\n\n            if (!Header_GetItemRect(Context->HeaderHandle, hitTestInfo.iItem, &itemRect))\n                return NULL;\n        }\n        else\n        {\n            return NULL;\n        }\n    }\n\n    if (ItemRect)\n        *ItemRect = itemRect;\n\n    return column;\n}\n\nVOID PhTnpGetHeaderTooltipText(\n    _In_ PPH_TREENEW_CONTEXT Context,\n    _In_ BOOLEAN Fixed,\n    _In_ PPOINT Point,\n    _Out_ PWSTR *Text\n    )\n{\n    LOGICAL result;\n    PPH_TREENEW_COLUMN column;\n    RECT itemRect;\n    PWSTR text;\n    SIZE_T textCount;\n    HDC hdc;\n    SIZE textSize;\n\n    column = PhTnpHitTestHeader(Context, Fixed, Point, &itemRect);\n\n    if (!column)\n        return;\n\n    if (Context->TooltipColumnId != column->Id)\n    {\n        // Determine if the tooltip needs to be shown.\n\n        text = column->Text;\n        textCount = PhCountStringZ(text);\n\n        if (!(hdc = GetDC(Context->Handle)))\n            return;\n\n        SelectObject(hdc, Context->Font);\n\n        result = GetTextExtentPoint32(hdc, text, (ULONG)textCount, &textSize);\n        ReleaseDC(Context->Handle, hdc);\n\n        if (!result)\n            return;\n\n        if (textSize.cx + 6 + 6 <= itemRect.right - itemRect.left) // HACK: Magic values (same as our cell margins?)\n            return;\n\n        Context->TooltipColumnId = column->Id;\n        PhMoveReference(&Context->TooltipText, PhCreateStringEx(text, textCount * sizeof(WCHAR)));\n    }\n\n    *Text = Context->TooltipText->Buffer;\n\n    // Always use the default parameters for column header tooltips.\n    Context->NewTooltipFont = Context->Font;\n    Context->TooltipUnfolding = FALSE;\n    SendMessage(Context->TooltipsHandle, TTM_SETMAXTIPWIDTH, 0, TNP_TOOLTIPS_DEFAULT_MAXIMUM_WIDTH);\n}\n\nLRESULT CALLBACK PhTnpHeaderHookWndProc(\n    _In_ HWND hwnd,\n    _In_ UINT uMsg,\n    _In_ WPARAM wParam,\n    _In_ LPARAM lParam,\n    _In_ UINT_PTR uIdSubclass,\n    _In_ ULONG_PTR dwRefData\n    )\n{\n    PPH_TREENEW_CONTEXT context = (PPH_TREENEW_CONTEXT)dwRefData;\n\n    switch (uMsg)\n    {\n    case WM_DESTROY:\n        RemoveWindowSubclass(hwnd, PhTnpHeaderHookWndProc, uIdSubclass);\n        break;\n    case WM_MOUSEMOVE:\n        {\n            POINT point;\n            PPH_TREENEW_COLUMN column;\n            ULONG id;\n\n            point.x = GET_X_LPARAM(lParam);\n            point.y = GET_Y_LPARAM(lParam);\n            column = PhTnpHitTestHeader(context, hwnd == context->FixedHeaderHandle, &point, NULL);\n\n            if (column)\n                id = column->Id;\n            else\n                id = -1;\n\n            if (context->TooltipColumnId != id)\n            {\n                PhTnpPopTooltip(context);\n            }\n        }\n        break;\n    case WM_NOTIFY:\n        {\n            NMHDR *header = (NMHDR *)lParam;\n\n            switch (header->code)\n            {\n            case TTN_GETDISPINFO:\n                {\n                    if (header->hwndFrom == context->TooltipsHandle)\n                    {\n                        NMTTDISPINFO *info = (NMTTDISPINFO *)header;\n                        POINT point;\n\n                        PhTnpGetMessagePos(hwnd, &point);\n                        PhTnpGetHeaderTooltipText(context, info->lParam == TNP_TOOLTIPS_FIXED_HEADER, &point, &info->lpszText);\n                    }\n                }\n                break;\n            case TTN_SHOW:\n                {\n                    if (header->hwndFrom == context->TooltipsHandle)\n                    {\n                        return PhTnpPrepareTooltipShow(context);\n                    }\n                }\n                break;\n            case TTN_POP:\n                {\n                    if (header->hwndFrom == context->TooltipsHandle)\n                    {\n                        PhTnpPrepareTooltipPop(context);\n                    }\n                }\n                break;\n            }\n        }\n        break;\n    }\n\n    switch (uMsg)\n    {\n    case WM_MOUSEMOVE:\n    case WM_LBUTTONDOWN:\n    case WM_LBUTTONUP:\n    case WM_RBUTTONDOWN:\n    case WM_RBUTTONUP:\n    case WM_MBUTTONDOWN:\n    case WM_MBUTTONUP:\n        {\n            if (context->TooltipsHandle)\n            {\n                MSG message;\n\n                message.hwnd = hwnd;\n                message.message = uMsg;\n                message.wParam = wParam;\n                message.lParam = lParam;\n                SendMessage(context->TooltipsHandle, TTM_RELAYEVENT, 0, (LPARAM)&message);\n            }\n        }\n        break;\n    }\n\n    return DefSubclassProc(hwnd, uMsg, wParam, lParam);\n}\n\nBOOLEAN PhTnpDetectDrag(\n    _In_ PPH_TREENEW_CONTEXT Context,\n    _In_ LONG CursorX,\n    _In_ LONG CursorY,\n    _In_ BOOLEAN DispatchMessages,\n    _Out_opt_ PULONG CancelledByMessage\n    )\n{\n    RECT dragRect;\n    MSG msg;\n\n    // Capture mouse input and see if the user moves the mouse beyond the drag rectangle.\n\n    dragRect.left = CursorX - Context->SystemDragX;\n    dragRect.top = CursorY - Context->SystemDragY;\n    dragRect.right = CursorX + Context->SystemDragX;\n    dragRect.bottom = CursorY + Context->SystemDragY;\n    MapWindowPoints(Context->Handle, NULL, (POINT *)&dragRect, 2);\n\n    SetCapture(Context->Handle);\n\n    if (CancelledByMessage)\n        *CancelledByMessage = 0;\n\n    do\n    {\n        // It seems that GetMessage dispatches nonqueued messages directly from kernel-mode, so we\n        // have to use PeekMessage and WaitMessage in order to process WM_CAPTURECHANGED messages.\n        if (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))\n        {\n            switch (msg.message)\n            {\n            case WM_LBUTTONDOWN:\n            case WM_LBUTTONUP:\n            case WM_RBUTTONDOWN:\n            case WM_RBUTTONUP:\n                ReleaseCapture();\n\n                if (CancelledByMessage)\n                    *CancelledByMessage = msg.message;\n\n                break;\n            case WM_MOUSEMOVE:\n                if (msg.pt.x < dragRect.left || msg.pt.x >= dragRect.right ||\n                    msg.pt.y < dragRect.top || msg.pt.y >= dragRect.bottom)\n                {\n                    if (IsWindow(Context->Handle))\n                        return TRUE;\n                    else\n                        return FALSE;\n                }\n                break;\n            default:\n                if (DispatchMessages)\n                {\n                    TranslateMessage(&msg);\n                    DispatchMessage(&msg);\n                }\n                break;\n            }\n        }\n        else\n        {\n            WaitMessage();\n        }\n    } while (IsWindow(Context->Handle) && GetCapture() == Context->Handle);\n\n    return FALSE;\n}\n\nVOID PhTnpDragSelect(\n    _In_ PPH_TREENEW_CONTEXT Context,\n    _In_ LONG CursorX,\n    _In_ LONG CursorY\n    )\n{\n    MSG msg;\n    LONG cursorX;\n    LONG cursorY;\n    BOOLEAN originFixed;\n    RECT dragRect;\n    RECT oldDragRect;\n    RECT windowRect;\n    POINT cursorPoint;\n    BOOLEAN showContextMenu;\n\n    cursorX = CursorX;\n    cursorY = CursorY;\n    originFixed = cursorX < Context->FixedWidth;\n\n    dragRect.left = cursorX;\n    dragRect.top = cursorY;\n    dragRect.right = cursorX;\n    dragRect.bottom = cursorY;\n    oldDragRect = dragRect;\n    Context->DragRect = dragRect;\n    Context->DragSelectionActive = TRUE;\n\n    if (Context->DoubleBuffered)\n        Context->SelectionRectangleAlpha = TRUE;\n    // TODO: Make sure the monitor's color depth is sufficient for alpha-blended selection\n    // rectangles.\n\n    GetWindowRect(Context->Handle, &windowRect);\n\n    cursorPoint.x = windowRect.left + cursorX;\n    cursorPoint.y = windowRect.top + cursorY;\n\n    showContextMenu = FALSE;\n\n    SetCapture(Context->Handle);\n\n    while (TRUE)\n    {\n        if (!PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))\n        {\n            BOOLEAN leftOrRight;\n            BOOLEAN aboveOrBelow;\n\n            // If the cursor is outside of the window, generate some messages so the window keeps\n            // scrolling.\n\n            leftOrRight = cursorPoint.x < windowRect.left || cursorPoint.x > windowRect.right;\n            aboveOrBelow = cursorPoint.y < windowRect.top || cursorPoint.y > windowRect.bottom;\n\n            if ((Context->VScrollVisible && aboveOrBelow && PhTnpCanScroll(Context, FALSE, cursorPoint.y > windowRect.bottom)) ||\n                (Context->HScrollVisible && leftOrRight && PhTnpCanScroll(Context, TRUE, cursorPoint.x > windowRect.right)))\n            {\n                SetCursorPos(cursorPoint.x, cursorPoint.y);\n            }\n            else\n            {\n                WaitMessage();\n            }\n\n            goto EndOfLoop;\n        }\n\n        cursorPoint = msg.pt;\n\n        switch (msg.message)\n        {\n        case WM_LBUTTONDOWN:\n        case WM_LBUTTONUP:\n        case WM_RBUTTONDOWN:\n        case WM_MBUTTONDOWN:\n        case WM_MBUTTONUP:\n            ReleaseCapture();\n            goto EndOfLoop;\n        case WM_RBUTTONUP:\n            ReleaseCapture();\n            showContextMenu = TRUE;\n            goto EndOfLoop;\n        case WM_MOUSEMOVE:\n            {\n                LONG newCursorX;\n                LONG newCursorY;\n                LONG deltaRows;\n                LONG deltaX;\n                LONG oldVScrollPosition;\n                LONG oldHScrollPosition;\n                LONG newDeltaX;\n                LONG newDeltaY;\n                LONG viewLeft;\n                LONG viewTop;\n                LONG viewRight;\n                LONG viewBottom;\n                LONG temp;\n                RECT totalRect;\n\n                newCursorX = GET_X_LPARAM(msg.lParam);\n                newCursorY = GET_Y_LPARAM(msg.lParam);\n\n                // Scroll the window if the cursor is outside of it.\n\n                deltaRows = 0;\n                deltaX = 0;\n\n                if (Context->VScrollVisible)\n                {\n                    if (cursorPoint.y < windowRect.top)\n                        deltaRows = -(windowRect.top - cursorPoint.y + Context->RowHeight - 1) / Context->RowHeight; // scroll up\n                    else if (cursorPoint.y >= windowRect.bottom)\n                        deltaRows = (cursorPoint.y - windowRect.bottom + Context->RowHeight - 1) / Context->RowHeight; // scroll down\n                }\n\n                if (Context->HScrollVisible)\n                {\n                    if (cursorPoint.x < windowRect.left)\n                        deltaX = -(windowRect.left - cursorPoint.x); // scroll left\n                    else if (cursorPoint.x >= windowRect.right)\n                        deltaX = cursorPoint.x - windowRect.right; // scroll right\n                }\n\n                oldVScrollPosition = Context->VScrollPosition;\n                oldHScrollPosition = Context->HScrollPosition;\n\n                if (deltaRows != 0 || deltaX != 0)\n                    PhTnpScroll(Context, deltaRows, deltaX);\n\n                newDeltaX = oldHScrollPosition - Context->HScrollPosition;\n                newDeltaY = (oldVScrollPosition - Context->VScrollPosition) * Context->RowHeight;\n\n                // Adjust our original drag point for the scrolling.\n                if (!originFixed)\n                    cursorX += newDeltaX;\n                cursorY += newDeltaY;\n\n                // Adjust the old drag rectangle for the scrolling.\n                if (!originFixed)\n                    oldDragRect.left += newDeltaX;\n                oldDragRect.top += newDeltaY;\n                if (!originFixed)\n                    oldDragRect.right += newDeltaX;\n                oldDragRect.bottom += newDeltaY;\n\n                // Ensure that the new cursor position is within the content area.\n\n                viewLeft = Context->FixedColumnVisible ? 0 : -Context->HScrollPosition;\n                viewTop = Context->HeaderHeight - Context->VScrollPosition;\n                viewRight = Context->NormalLeft + Context->TotalViewX - Context->HScrollPosition;\n                viewBottom = Context->HeaderHeight + ((LONG)Context->FlatList->Count - Context->VScrollPosition) * Context->RowHeight;\n\n                temp = Context->ClientRect.right - (Context->VScrollVisible ? Context->VScrollWidth : 0);\n                viewRight = max(viewRight, temp);\n                temp = Context->ClientRect.bottom - ((!Context->FixedColumnVisible && Context->HScrollVisible) ? Context->HScrollHeight : 0);\n                viewBottom = max(viewBottom, temp);\n\n                if (newCursorX < viewLeft)\n                    newCursorX = viewLeft;\n                if (newCursorX > viewRight)\n                    newCursorX = viewRight;\n                if (newCursorY < viewTop)\n                    newCursorY = viewTop;\n                if (newCursorY > viewBottom)\n                    newCursorY = viewBottom;\n\n                // Create the new drag rectangle.\n\n                if (cursorX < newCursorX)\n                {\n                    dragRect.left = cursorX;\n                    dragRect.right = newCursorX;\n                }\n                else\n                {\n                    dragRect.left = newCursorX;\n                    dragRect.right = cursorX;\n                }\n\n                if (cursorY < newCursorY)\n                {\n                    dragRect.top = cursorY;\n                    dragRect.bottom = newCursorY;\n                }\n                else\n                {\n                    dragRect.top = newCursorY;\n                    dragRect.bottom = cursorY;\n                }\n\n                // Has anything changed from before?\n                if (dragRect.left == oldDragRect.left && dragRect.top == oldDragRect.top &&\n                    dragRect.right == oldDragRect.right && dragRect.bottom == oldDragRect.bottom)\n                {\n                    break;\n                }\n\n                Context->DragRect = dragRect;\n\n                // Process the selection.\n                totalRect.left = min(dragRect.left, oldDragRect.left);\n                totalRect.top = min(dragRect.top, oldDragRect.top);\n                totalRect.right = max(dragRect.right, oldDragRect.right);\n                totalRect.bottom = max(dragRect.bottom, oldDragRect.bottom);\n                PhTnpProcessDragSelect(Context, (ULONG)msg.wParam, &oldDragRect, &dragRect, &totalRect);\n\n                // Redraw the drag rectangle.\n                RedrawWindow(Context->Handle, &totalRect, NULL, RDW_INVALIDATE | RDW_UPDATENOW);\n\n                oldDragRect = dragRect;\n            }\n            break;\n        case WM_MOUSELEAVE:\n            break; // don't process\n        case WM_MOUSEWHEEL:\n            break; // don't process\n        case WM_KEYDOWN:\n            if (msg.wParam == VK_ESCAPE)\n            {\n                ULONG changedStart;\n                ULONG changedEnd;\n                RECT rect;\n\n                PhTnpSelectRange(Context, -1, -1, TN_SELECT_RESET, &changedStart, &changedEnd);\n\n                if (PhTnpGetRowRects(Context, changedStart, changedEnd, TRUE, &rect))\n                {\n                    InvalidateRect(Context->Handle, &rect, FALSE);\n                }\n\n                ReleaseCapture();\n            }\n            break; // don't process\n        case WM_CHAR:\n            break; // don't process\n        default:\n            TranslateMessage(&msg);\n            DispatchMessage(&msg);\n            break;\n        }\n\nEndOfLoop:\n        if (GetCapture() != Context->Handle)\n            break;\n    }\n\n    Context->DragSelectionActive = FALSE;\n    RedrawWindow(Context->Handle, &dragRect, NULL, RDW_INVALIDATE | RDW_UPDATENOW);\n\n    if (showContextMenu)\n    {\n        // Display a context menu at the original drag point.\n        SendMessage(Context->Handle, WM_CONTEXTMENU, (WPARAM)Context->Handle, MAKELPARAM(windowRect.left + CursorX, windowRect.top + CursorY));\n    }\n}\n\nVOID PhTnpProcessDragSelect(\n    _In_ PPH_TREENEW_CONTEXT Context,\n    _In_ ULONG VirtualKeys,\n    _In_ PRECT OldRect,\n    _In_ PRECT NewRect,\n    _In_ PRECT TotalRect\n    )\n{\n    LONG firstRow;\n    LONG lastRow;\n    RECT rowRect;\n    LONG i;\n    PPH_TREENEW_NODE node;\n    LONG changedStart;\n    LONG changedEnd;\n    RECT rect;\n\n    // Determine which rows we need to test. The divisions below must be done on positive integers\n    // to ensure correct rounding.\n\n    firstRow = (TotalRect->top - Context->HeaderHeight + Context->VScrollPosition * Context->RowHeight) / Context->RowHeight;\n    lastRow = (TotalRect->bottom - 1 - Context->HeaderHeight + Context->VScrollPosition * Context->RowHeight) / Context->RowHeight;\n\n    if (firstRow < 0)\n        firstRow = 0;\n    if (lastRow >= (LONG)Context->FlatList->Count)\n        lastRow = Context->FlatList->Count - 1;\n\n    rowRect.left = 0;\n    rowRect.top = Context->HeaderHeight + (firstRow - Context->VScrollPosition) * Context->RowHeight;\n    rowRect.right = Context->NormalLeft + Context->TotalViewX - Context->HScrollPosition;\n    rowRect.bottom = rowRect.top + Context->RowHeight;\n\n    changedStart = lastRow;\n    changedEnd = firstRow;\n\n    // Process the rows.\n    for (i = firstRow; i <= lastRow; i++)\n    {\n        BOOLEAN inOldRect;\n        BOOLEAN inNewRect;\n\n        node = Context->FlatList->Items[i];\n\n        inOldRect = rowRect.top < OldRect->bottom && rowRect.bottom > OldRect->top &&\n            rowRect.left < OldRect->right && rowRect.right > OldRect->left;\n        inNewRect = rowRect.top < NewRect->bottom && rowRect.bottom > NewRect->top &&\n            rowRect.left < NewRect->right && rowRect.right > NewRect->left;\n\n        if (VirtualKeys & MK_CONTROL)\n        {\n            if (!node->Unselectable && inOldRect != inNewRect)\n            {\n                node->Selected = !node->Selected;\n\n                if (changedStart > i)\n                    changedStart = i;\n                if (changedEnd < i)\n                    changedEnd = i;\n            }\n        }\n        else\n        {\n            if (!node->Unselectable && inOldRect != inNewRect)\n            {\n                node->Selected = inNewRect;\n\n                if (changedStart > i)\n                    changedStart = i;\n                if (changedEnd < i)\n                    changedEnd = i;\n            }\n        }\n\n        rowRect.top = rowRect.bottom;\n        rowRect.bottom += Context->RowHeight;\n    }\n\n    if (changedStart <= changedEnd)\n    {\n        Context->Callback(Context->Handle, TreeNewSelectionChanged, NULL, NULL, Context->CallbackContext);\n    }\n\n    if (PhTnpGetRowRects(Context, changedStart, changedEnd, TRUE, &rect))\n    {\n        InvalidateRect(Context->Handle, &rect, FALSE);\n    }\n}\n\nVOID PhTnpCreateBufferedContext(\n    _In_ PPH_TREENEW_CONTEXT Context\n    )\n{\n    HDC hdc;\n\n    if (hdc = GetDC(Context->Handle))\n    {\n        Context->BufferedContext = CreateCompatibleDC(hdc);\n\n        if (!Context->BufferedContext)\n            return;\n\n        Context->BufferedContextRect = Context->ClientRect;\n        Context->BufferedBitmap = CreateCompatibleBitmap(\n            hdc,\n            Context->BufferedContextRect.right + 1, // leave one extra pixel for divider animation\n            Context->BufferedContextRect.bottom\n            );\n\n        if (!Context->BufferedBitmap)\n        {\n            DeleteDC(Context->BufferedContext);\n            Context->BufferedContext = NULL;\n            return;\n        }\n\n        ReleaseDC(Context->Handle, hdc);\n        Context->BufferedOldBitmap = SelectObject(Context->BufferedContext, Context->BufferedBitmap);\n    }\n}\n\nVOID PhTnpDestroyBufferedContext(\n    _In_ PPH_TREENEW_CONTEXT Context\n    )\n{\n    // The original bitmap must be selected back into the context, otherwise the bitmap can't be\n    // deleted.\n    SelectObject(Context->BufferedContext, Context->BufferedOldBitmap);\n    DeleteObject(Context->BufferedBitmap);\n    DeleteDC(Context->BufferedContext);\n\n    Context->BufferedContext = NULL;\n    Context->BufferedBitmap = NULL;\n}\n\nVOID PhTnpGetMessagePos(\n    _In_ HWND hwnd,\n    _Out_ PPOINT ClientPoint\n    )\n{\n    ULONG position;\n    POINT point;\n\n    position = GetMessagePos();\n    point.x = GET_X_LPARAM(position);\n    point.y = GET_Y_LPARAM(position);\n    ScreenToClient(hwnd, &point);\n\n    *ClientPoint = point;\n}\n"
  },
  {
    "path": "third_party/phlib/util.c",
    "content": "/*\n * Process Hacker -\n *   general support functions\n *\n * Copyright (C) 2009-2016 wj32\n * Copyright (C) 2017 dmex\n *\n * This file is part of Process Hacker.\n *\n * Process Hacker is free software; you can redistribute it and/or modify\n * it under the terms of the GNU General Public License as published by\n * the Free Software Foundation, either version 3 of the License, or\n * (at your option) any later version.\n *\n * Process Hacker is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n * GNU General Public License for more details.\n *\n * You should have received a copy of the GNU General Public License\n * along with Process Hacker.  If not, see <http://www.gnu.org/licenses/>.\n */\n\n#include <ph.h>\n\n#include <commctrl.h>\n#include <commdlg.h>\n#include <shellapi.h>\n#define CINTERFACE\n#define COBJMACROS\n#include <shlobj.h>\n#undef CINTERFACE\n#undef COBJMACROS\n#include <winsta.h>\n\n#include <apiimport.h>\n#include <lsasup.h>\n#include <mapimg.h>\n#include <settings.h>\n\n#include \"md5.h\"\n#include \"sha.h\"\n#include \"sha256.h\"\n\ntypedef BOOLEAN (NTAPI *_WinStationQueryInformationW)(\n    _In_opt_ HANDLE ServerHandle,\n    _In_ ULONG LogonId,\n    _In_ WINSTATIONINFOCLASS WinStationInformationClass,\n    _Out_writes_bytes_(WinStationInformationLength) PVOID WinStationInformation,\n    _In_ ULONG WinStationInformationLength,\n    _Out_ PULONG ReturnLength\n    );\n\ntypedef BOOL (WINAPI *_CreateEnvironmentBlock)(\n    _Out_ LPVOID *lpEnvironment,\n    _In_opt_ HANDLE hToken,\n    _In_ BOOL bInherit\n    );\n\ntypedef BOOL (WINAPI *_DestroyEnvironmentBlock)(\n    _In_ LPVOID lpEnvironment\n    );\n\nDECLSPEC_SELECTANY WCHAR *PhSizeUnitNames[7] = { L\"B\", L\"kB\", L\"MB\", L\"GB\", L\"TB\", L\"PB\", L\"EB\" };\nDECLSPEC_SELECTANY ULONG PhMaxSizeUnit = MAXULONG32;\n\n/**\n * Ensures a rectangle is positioned within the specified bounds.\n *\n * \\param Rectangle The rectangle to be adjusted.\n * \\param Bounds The bounds.\n *\n * \\remarks If the rectangle is too large to fit inside the bounds, it is positioned at the top-left\n * of the bounds.\n */\nVOID PhAdjustRectangleToBounds(\n    _Inout_ PPH_RECTANGLE Rectangle,\n    _In_ PPH_RECTANGLE Bounds\n    )\n{\n    if (Rectangle->Left + Rectangle->Width > Bounds->Left + Bounds->Width)\n        Rectangle->Left = Bounds->Left + Bounds->Width - Rectangle->Width;\n    if (Rectangle->Top + Rectangle->Height > Bounds->Top + Bounds->Height)\n        Rectangle->Top = Bounds->Top + Bounds->Height - Rectangle->Height;\n\n    if (Rectangle->Left < Bounds->Left)\n        Rectangle->Left = Bounds->Left;\n    if (Rectangle->Top < Bounds->Top)\n        Rectangle->Top = Bounds->Top;\n}\n\n/**\n * Positions a rectangle in the center of the specified bounds.\n *\n * \\param Rectangle The rectangle to be adjusted.\n * \\param Bounds The bounds.\n */\nVOID PhCenterRectangle(\n    _Inout_ PPH_RECTANGLE Rectangle,\n    _In_ PPH_RECTANGLE Bounds\n    )\n{\n    Rectangle->Left = Bounds->Left + (Bounds->Width - Rectangle->Width) / 2;\n    Rectangle->Top = Bounds->Top + (Bounds->Height - Rectangle->Height) / 2;\n}\n\n/**\n * Ensures a rectangle is positioned within the working area of the specified window's monitor.\n *\n * \\param hWnd A handle to a window. If NULL, the monitor closest to \\a Rectangle is used.\n * \\param Rectangle The rectangle to be adjusted.\n */\nVOID PhAdjustRectangleToWorkingArea(\n    _In_opt_ HWND hWnd,\n    _Inout_ PPH_RECTANGLE Rectangle\n    )\n{\n    HMONITOR monitor;\n    MONITORINFO monitorInfo = { sizeof(monitorInfo) };\n\n    if (hWnd)\n    {\n        monitor = MonitorFromWindow(hWnd, MONITOR_DEFAULTTONEAREST);\n    }\n    else\n    {\n        RECT rect;\n\n        rect = PhRectangleToRect(*Rectangle);\n        monitor = MonitorFromRect(&rect, MONITOR_DEFAULTTONEAREST);\n    }\n\n    if (GetMonitorInfo(monitor, &monitorInfo))\n    {\n        PH_RECTANGLE bounds;\n\n        bounds = PhRectToRectangle(monitorInfo.rcWork);\n        PhAdjustRectangleToBounds(Rectangle, &bounds);\n    }\n}\n\n/**\n * Centers a window.\n *\n * \\param WindowHandle The window to center.\n * \\param ParentWindowHandle If specified, the window will be positioned at the center of this\n * window. Otherwise, the window will be positioned at the center of the monitor.\n */\nVOID PhCenterWindow(\n    _In_ HWND WindowHandle,\n    _In_opt_ HWND ParentWindowHandle\n    )\n{\n    if (ParentWindowHandle)\n    {\n        RECT rect, parentRect;\n        PH_RECTANGLE rectangle, parentRectangle;\n\n        GetWindowRect(WindowHandle, &rect);\n        GetWindowRect(ParentWindowHandle, &parentRect);\n        rectangle = PhRectToRectangle(rect);\n        parentRectangle = PhRectToRectangle(parentRect);\n\n        PhCenterRectangle(&rectangle, &parentRectangle);\n        PhAdjustRectangleToWorkingArea(WindowHandle, &rectangle);\n        MoveWindow(WindowHandle, rectangle.Left, rectangle.Top,\n            rectangle.Width, rectangle.Height, FALSE);\n    }\n    else\n    {\n        MONITORINFO monitorInfo = { sizeof(monitorInfo) };\n\n        if (GetMonitorInfo(\n            MonitorFromWindow(WindowHandle, MONITOR_DEFAULTTONEAREST),\n            &monitorInfo\n            ))\n        {\n            RECT rect;\n            PH_RECTANGLE rectangle;\n            PH_RECTANGLE bounds;\n\n            GetWindowRect(WindowHandle, &rect);\n            rectangle = PhRectToRectangle(rect);\n            bounds = PhRectToRectangle(monitorInfo.rcWork);\n\n            PhCenterRectangle(&rectangle, &bounds);\n            MoveWindow(WindowHandle, rectangle.Left, rectangle.Top,\n                rectangle.Width, rectangle.Height, FALSE);\n        }\n    }\n}\n\n/**\n * References an array of objects.\n *\n * \\param Objects An array of objects.\n * \\param NumberOfObjects The number of elements in \\a Objects.\n */\nVOID PhReferenceObjects(\n    _In_reads_(NumberOfObjects) PVOID *Objects,\n    _In_ ULONG NumberOfObjects\n    )\n{\n    ULONG i;\n\n    for (i = 0; i < NumberOfObjects; i++)\n        PhReferenceObject(Objects[i]);\n}\n\n/**\n * Dereferences an array of objects.\n *\n * \\param Objects An array of objects.\n * \\param NumberOfObjects The number of elements in \\a Objects.\n */\nVOID PhDereferenceObjects(\n    _In_reads_(NumberOfObjects) PVOID *Objects,\n    _In_ ULONG NumberOfObjects\n    )\n{\n    ULONG i;\n\n    for (i = 0; i < NumberOfObjects; i++)\n        PhDereferenceObject(Objects[i]);\n}\n\n/**\n * Gets a string stored in a DLL's message table.\n *\n * \\param DllHandle The base address of the DLL.\n * \\param MessageTableId The identifier of the message table.\n * \\param MessageLanguageId The language ID of the message.\n * \\param MessageId The identifier of the message.\n *\n * \\return A pointer to a string containing the message. You must free the string using\n * PhDereferenceObject() when you no longer need it.\n */\nPPH_STRING PhGetMessage(\n    _In_ PVOID DllHandle,\n    _In_ ULONG MessageTableId,\n    _In_ ULONG MessageLanguageId,\n    _In_ ULONG MessageId\n    )\n{\n    NTSTATUS status;\n    PMESSAGE_RESOURCE_ENTRY messageEntry;\n\n    status = RtlFindMessage(\n        DllHandle,\n        MessageTableId,\n        MessageLanguageId,\n        MessageId,\n        &messageEntry\n        );\n\n    // Try using the system LANGID.\n    if (!NT_SUCCESS(status))\n    {\n        status = RtlFindMessage(\n            DllHandle,\n            MessageTableId,\n            GetSystemDefaultLangID(),\n            MessageId,\n            &messageEntry\n            );\n    }\n\n    // Try using U.S. English.\n    if (!NT_SUCCESS(status))\n    {\n        status = RtlFindMessage(\n            DllHandle,\n            MessageTableId,\n            MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US),\n            MessageId,\n            &messageEntry\n            );\n    }\n\n    if (!NT_SUCCESS(status))\n        return NULL;\n\n    // dmex: We don't support parsing insert sequences.\n    if (messageEntry->Text[0] == '%')\n        return NULL;\n\n    if (messageEntry->Flags & MESSAGE_RESOURCE_UNICODE)\n    {\n        return PhCreateStringEx((PWCHAR)messageEntry->Text, messageEntry->Length);\n    }\n    else\n    {\n        return PhConvertMultiByteToUtf16Ex((PCHAR)messageEntry->Text, messageEntry->Length);\n    }\n}\n\n/**\n * Gets a message describing a NT status value.\n *\n * \\param Status The NT status value.\n */\nPPH_STRING PhGetNtMessage(\n    _In_ NTSTATUS Status\n    )\n{\n    PPH_STRING message;\n\n    if (!NT_NTWIN32(Status))\n        message = PhGetMessage(PhGetDllHandle(L\"ntdll.dll\"), 0xb, GetUserDefaultLangID(), (ULONG)Status);\n    else\n        message = PhGetWin32Message(WIN32_FROM_NTSTATUS(Status));\n\n    if (PhIsNullOrEmptyString(message))\n        return message;\n\n    PhTrimToNullTerminatorString(message);\n\n    // Remove any trailing newline.\n    if (message->Length >= 2 * sizeof(WCHAR) &&\n        message->Buffer[message->Length / sizeof(WCHAR) - 2] == '\\r' &&\n        message->Buffer[message->Length / sizeof(WCHAR) - 1] == '\\n')\n    {\n        PhMoveReference(&message, PhCreateStringEx(message->Buffer, message->Length - 2 * sizeof(WCHAR)));\n    }\n\n    // Fix those messages which are formatted like:\n    // {Asdf}\\r\\nAsdf asdf asdf...\n    if (message->Buffer[0] == '{')\n    {\n        PH_STRINGREF titlePart;\n        PH_STRINGREF remainingPart;\n\n        if (PhSplitStringRefAtChar(&message->sr, '\\n', &titlePart, &remainingPart))\n            PhMoveReference(&message, PhCreateString2(&remainingPart));\n    }\n\n    return message;\n}\n\n/**\n * Gets a message describing a Win32 error code.\n *\n * \\param Result The Win32 error code.\n */\nPPH_STRING PhGetWin32Message(\n    _In_ ULONG Result\n    )\n{\n    PPH_STRING message;\n\n    message = PhGetMessage(PhGetDllHandle(L\"kernel32.dll\"), 0xb, GetUserDefaultLangID(), Result);\n\n    if (message)\n        PhTrimToNullTerminatorString(message);\n\n    // Remove any trailing newline.\n    if (message && message->Length >= 2 * sizeof(WCHAR) &&\n        message->Buffer[message->Length / sizeof(WCHAR) - 2] == '\\r' &&\n        message->Buffer[message->Length / sizeof(WCHAR) - 1] == '\\n')\n    {\n        PhMoveReference(&message, PhCreateStringEx(message->Buffer, message->Length - 2 * sizeof(WCHAR)));\n    }\n\n    return message;\n}\n\n/**\n * Displays a message box.\n *\n * \\param hWnd The owner window of the message box.\n * \\param Type The type of message box to display.\n * \\param Format A format string.\n *\n * \\return The user's response.\n */\nINT PhShowMessage(\n    _In_ HWND hWnd,\n    _In_ ULONG Type,\n    _In_ PWSTR Format,\n    ...\n    )\n{\n    INT result;\n    va_list argptr;\n    PPH_STRING message;\n\n    va_start(argptr, Format);\n    message = PhFormatString_V(Format, argptr);\n    va_end(argptr);\n\n    if (!message)\n        return -1;\n\n    result = MessageBox(hWnd, message->Buffer, PhApplicationName, Type);\n    PhDereferenceObject(message);\n\n    return result;\n}\n\nINT PhShowMessage2(\n    _In_ HWND hWnd,\n    _In_ ULONG Buttons,\n    _In_opt_ PWSTR Icon,\n    _In_opt_ PWSTR Title,\n    _In_ PWSTR Format,\n    ...\n    )\n{\n    INT result;\n    va_list argptr;\n    PPH_STRING message;\n    TASKDIALOGCONFIG config = { sizeof(config) };\n\n    va_start(argptr, Format);\n    message = PhFormatString_V(Format, argptr);\n    va_end(argptr);\n\n    if (!message)\n        return -1;\n\n    config.hwndParent = hWnd;\n    config.hInstance = PhInstanceHandle;\n    config.dwFlags = TDF_ALLOW_DIALOG_CANCELLATION | (IsWindowVisible(hWnd) ? TDF_POSITION_RELATIVE_TO_WINDOW : 0);\n    config.dwCommonButtons = Buttons;\n    config.pszWindowTitle = PhApplicationName;\n    config.pszMainIcon = Icon;\n    config.pszMainInstruction = Title;\n    config.pszContent = message->Buffer;\n\n    if (TaskDialogIndirect(\n        &config,\n        &result,\n        NULL,\n        NULL\n        ) == S_OK)\n    {\n        PhDereferenceObject(message);\n        return result;\n    }\n    else\n    {\n        PhDereferenceObject(message);\n        return -1;\n    }\n}\n\nPPH_STRING PhGetStatusMessage(\n    _In_ NTSTATUS Status,\n    _In_opt_ ULONG Win32Result\n    )\n{\n    if (!Win32Result)\n    {\n        // In some cases we want the simple Win32 messages.\n        if (\n            Status == STATUS_ACCESS_DENIED ||\n            Status == STATUS_ACCESS_VIOLATION\n            )\n        {\n            Win32Result = RtlNtStatusToDosError(Status);\n        }\n        // Process NTSTATUS values with the NT-Win32 facility.\n        else if (NT_NTWIN32(Status))\n        {\n            Win32Result = WIN32_FROM_NTSTATUS(Status);\n        }\n    }\n\n    if (!Win32Result)\n        return PhGetNtMessage(Status);\n    else\n        return PhGetWin32Message(Win32Result);\n}\n\n/**\n * Displays an error message for a NTSTATUS value or Win32 error code.\n *\n * \\param hWnd The owner window of the message box.\n * \\param Message A message describing the operation that failed.\n * \\param Status A NTSTATUS value, or 0 if there is none.\n * \\param Win32Result A Win32 error code, or 0 if there is none.\n */\nVOID PhShowStatus(\n    _In_ HWND hWnd,\n    _In_opt_ PWSTR Message,\n    _In_ NTSTATUS Status,\n    _In_opt_ ULONG Win32Result\n    )\n{\n    PPH_STRING statusMessage;\n\n    statusMessage = PhGetStatusMessage(Status, Win32Result);\n\n    if (!statusMessage)\n    {\n        if (Message)\n        {\n            PhShowError(hWnd, L\"%s.\", Message);\n        }\n        else\n        {\n            PhShowError(hWnd, L\"Unable to perform the operation.\");\n        }\n\n        return;\n    }\n\n    if (Message)\n    {\n        PhShowError2(hWnd, Message, statusMessage->Buffer);\n    }\n    else\n    {\n        PhShowError(hWnd, L\"%s\", statusMessage->Buffer);\n    }\n\n    PhDereferenceObject(statusMessage);\n}\n\n/**\n * Displays an error message for a NTSTATUS value or Win32 error code, and allows the user to cancel\n * the current operation.\n *\n * \\param hWnd The owner window of the message box.\n * \\param Message A message describing the operation that failed.\n * \\param Status A NTSTATUS value, or 0 if there is none.\n * \\param Win32Result A Win32 error code, or 0 if there is none.\n *\n * \\return TRUE if the user wishes to continue with the current operation, otherwise FALSE.\n */\nBOOLEAN PhShowContinueStatus(\n    _In_ HWND hWnd,\n    _In_opt_ PWSTR Message,\n    _In_ NTSTATUS Status,\n    _In_opt_ ULONG Win32Result\n    )\n{\n    PPH_STRING statusMessage;\n    INT result;\n\n    statusMessage = PhGetStatusMessage(Status, Win32Result);\n\n    if (!statusMessage)\n    {\n        if (Message)\n        {\n            result = PhShowMessage(hWnd, MB_ICONERROR | MB_OKCANCEL, L\"%s.\", Message);\n        }\n        else\n        {\n            result = PhShowMessage(hWnd, MB_ICONERROR | MB_OKCANCEL, L\"Unable to perform the operation.\");\n        }\n\n        return result == IDOK;\n    }\n\n    if (Message)\n    {\n        result = PhShowError2(hWnd, Message, statusMessage->Buffer);\n    }\n    else\n    {\n        result = PhShowMessage(hWnd, MB_ICONERROR | MB_OKCANCEL, L\"%s\", statusMessage->Buffer);\n    }\n\n    PhDereferenceObject(statusMessage);\n\n    return result == IDOK;\n}\n\n/**\n * Displays a confirmation message.\n *\n * \\param hWnd The owner window of the message box.\n * \\param Verb A verb describing the operation, e.g. \"terminate\".\n * \\param Object The object of the operation, e.g. \"the process\".\n * \\param Message A message describing the operation.\n * \\param Warning TRUE to display the confirmation message as a warning, otherwise FALSE.\n *\n * \\return TRUE if the user wishes to continue, otherwise FALSE.\n */\nBOOLEAN PhShowConfirmMessage(\n    _In_ HWND hWnd,\n    _In_ PWSTR Verb,\n    _In_ PWSTR Object,\n    _In_opt_ PWSTR Message,\n    _In_ BOOLEAN Warning\n    )\n{\n    PPH_STRING verb;\n    PPH_STRING verbCaps;\n    PPH_STRING action;\n    TASKDIALOGCONFIG config = { sizeof(config) };\n    TASKDIALOG_BUTTON buttons[2];\n    INT button;\n\n    // Make sure the verb is all lowercase.\n    verb = PhaLowerString(PhaCreateString(Verb));\n\n    // \"terminate\" -> \"Terminate\"\n    verbCaps = PhaDuplicateString(verb);\n    if (verbCaps->Length > 0) verbCaps->Buffer[0] = towupper(verbCaps->Buffer[0]);\n\n    // \"terminate\", \"the process\" -> \"terminate the process\"\n    action = PhaConcatStrings(3, verb->Buffer, L\" \", Object);\n\n    config.hwndParent = hWnd;\n    config.hInstance = PhInstanceHandle;\n    config.dwFlags = TDF_ALLOW_DIALOG_CANCELLATION | (IsWindowVisible(hWnd) ? TDF_POSITION_RELATIVE_TO_WINDOW : 0);\n    config.pszWindowTitle = PhApplicationName;\n    config.pszMainIcon = Warning ? TD_WARNING_ICON : NULL;\n    config.pszMainInstruction = PhaConcatStrings(3, L\"Do you want to \", action->Buffer, L\"?\")->Buffer;\n\n    if (Message)\n        config.pszContent = PhaConcatStrings2(Message, L\" Are you sure you want to continue?\")->Buffer;\n\n    buttons[0].nButtonID = IDYES;\n    buttons[0].pszButtonText = verbCaps->Buffer;\n    buttons[1].nButtonID = IDNO;\n    buttons[1].pszButtonText = L\"Cancel\";\n\n    config.cButtons = 2;\n    config.pButtons = buttons;\n    config.nDefaultButton = IDYES;\n\n    if (TaskDialogIndirect(\n        &config,\n        &button,\n        NULL,\n        NULL\n        ) == S_OK)\n    {\n        return button == IDYES;\n    }\n    else\n    {\n        return FALSE;\n    }\n}\n\n/**\n * Finds an integer in an array of string-integer pairs.\n *\n * \\param KeyValuePairs The array.\n * \\param SizeOfKeyValuePairs The size of the array, in bytes.\n * \\param String The string to search for.\n * \\param Integer A variable which receives the found integer.\n *\n * \\return TRUE if the string was found, otherwise FALSE.\n *\n * \\remarks The search is case-sensitive.\n */\nBOOLEAN PhFindIntegerSiKeyValuePairs(\n    _In_ PPH_KEY_VALUE_PAIR KeyValuePairs,\n    _In_ ULONG SizeOfKeyValuePairs,\n    _In_ PWSTR String,\n    _Out_ PULONG Integer\n    )\n{\n    ULONG i;\n\n    for (i = 0; i < SizeOfKeyValuePairs / sizeof(PH_KEY_VALUE_PAIR); i++)\n    {\n        if (PhEqualStringZ(KeyValuePairs[i].Key, String, TRUE))\n        {\n            *Integer = PtrToUlong(KeyValuePairs[i].Value);\n            return TRUE;\n        }\n    }\n\n    return FALSE;\n}\n\n/**\n * Finds a string in an array of string-integer pairs.\n *\n * \\param KeyValuePairs The array.\n * \\param SizeOfKeyValuePairs The size of the array, in bytes.\n * \\param Integer The integer to search for.\n * \\param String A variable which receives the found string.\n *\n * \\return TRUE if the integer was found, otherwise FALSE.\n */\nBOOLEAN PhFindStringSiKeyValuePairs(\n    _In_ PPH_KEY_VALUE_PAIR KeyValuePairs,\n    _In_ ULONG SizeOfKeyValuePairs,\n    _In_ ULONG Integer,\n    _Out_ PWSTR *String\n    )\n{\n    ULONG i;\n\n    for (i = 0; i < SizeOfKeyValuePairs / sizeof(PH_KEY_VALUE_PAIR); i++)\n    {\n        if (PtrToUlong(KeyValuePairs[i].Value) == Integer)\n        {\n            *String = (PWSTR)KeyValuePairs[i].Key;\n            return TRUE;\n        }\n    }\n\n    return FALSE;\n}\n\n/**\n * Creates a random (type 4) UUID.\n *\n * \\param Guid The destination UUID.\n */\nVOID PhGenerateGuid(\n    _Out_ PGUID Guid\n    )\n{\n    static ULONG seed = 0;\n    // The top/sign bit is always unusable for RtlRandomEx (the result is always unsigned), so we'll\n    // take the bottom 24 bits. We need 128 bits in total, so we'll call the function 6 times.\n    ULONG random[6];\n    ULONG i;\n\n    for (i = 0; i < 6; i++)\n        random[i] = RtlRandomEx(&seed);\n\n    // random[0] is usable\n    *(PUSHORT)&Guid->Data1 = (USHORT)random[0];\n    // top byte from random[0] is usable\n    *((PUSHORT)&Guid->Data1 + 1) = (USHORT)((random[0] >> 16) | (random[1] & 0xff));\n    // top 2 bytes from random[1] are usable\n    Guid->Data2 = (SHORT)(random[1] >> 8);\n    // random[2] is usable\n    Guid->Data3 = (SHORT)random[2];\n    // top byte from random[2] is usable\n    *(PUSHORT)&Guid->Data4[0] = (USHORT)((random[2] >> 16) | (random[3] & 0xff));\n    // top 2 bytes from random[3] are usable\n    *(PUSHORT)&Guid->Data4[2] = (USHORT)(random[3] >> 8);\n    // random[4] is usable\n    *(PUSHORT)&Guid->Data4[4] = (USHORT)random[4];\n    // top byte from random[4] is usable\n    *(PUSHORT)&Guid->Data4[6] = (USHORT)((random[4] >> 16) | (random[5] & 0xff));\n\n    ((PGUID_EX)Guid)->s2.Version = GUID_VERSION_RANDOM;\n    ((PGUID_EX)Guid)->s2.Variant &= ~GUID_VARIANT_STANDARD_MASK;\n    ((PGUID_EX)Guid)->s2.Variant |= GUID_VARIANT_STANDARD;\n}\n\nFORCEINLINE VOID PhpReverseGuid(\n    _Inout_ PGUID Guid\n    )\n{\n    Guid->Data1 = _byteswap_ulong(Guid->Data1);\n    Guid->Data2 = _byteswap_ushort(Guid->Data2);\n    Guid->Data3 = _byteswap_ushort(Guid->Data3);\n}\n\n/**\n * Creates a name-based (type 3 or 5) UUID.\n *\n * \\param Guid The destination UUID.\n * \\param Namespace The UUID of the namespace.\n * \\param Name The input name.\n * \\param NameLength The length of the input name, not including the null terminator if present.\n * \\param Version The type of UUID.\n * \\li \\c GUID_VERSION_MD5 Creates a type 3, MD5-based UUID.\n * \\li \\c GUID_VERSION_SHA1 Creates a type 5, SHA1-based UUID.\n */\nVOID PhGenerateGuidFromName(\n    _Out_ PGUID Guid,\n    _In_ PGUID Namespace,\n    _In_ PCHAR Name,\n    _In_ ULONG NameLength,\n    _In_ UCHAR Version\n    )\n{\n    PGUID_EX guid;\n    PUCHAR data;\n    ULONG dataLength;\n    GUID ns;\n    UCHAR hash[20];\n\n    // Convert the namespace to big endian.\n\n    ns = *Namespace;\n    PhpReverseGuid(&ns);\n\n    // Compute the hash of the namespace concatenated with the name.\n\n    dataLength = 16 + NameLength;\n    data = PhAllocate(dataLength);\n    memcpy(data, &ns, 16);\n    memcpy(&data[16], Name, NameLength);\n\n    if (Version == GUID_VERSION_MD5)\n    {\n        MD5_CTX context;\n\n        MD5Init(&context);\n        MD5Update(&context, data, dataLength);\n        MD5Final(&context);\n\n        memcpy(hash, context.digest, 16);\n    }\n    else\n    {\n        A_SHA_CTX context;\n\n        A_SHAInit(&context);\n        A_SHAUpdate(&context, data, dataLength);\n        A_SHAFinal(&context, hash);\n\n        Version = GUID_VERSION_SHA1;\n    }\n\n    PhFree(data);\n\n    guid = (PGUID_EX)Guid;\n    memcpy(guid->Data, hash, 16);\n    PhpReverseGuid(&guid->Guid);\n    guid->s2.Version = Version;\n    guid->s2.Variant &= ~GUID_VARIANT_STANDARD_MASK;\n    guid->s2.Variant |= GUID_VARIANT_STANDARD;\n}\n\n/**\n * Fills a buffer with random uppercase alphabetical characters.\n *\n * \\param Buffer The buffer to fill with random characters, plus a null terminator.\n * \\param Count The number of characters available in the buffer, including space for the null\n * terminator.\n */\nVOID PhGenerateRandomAlphaString(\n    _Out_writes_z_(Count) PWSTR Buffer,\n    _In_ ULONG Count\n    )\n{\n    static ULONG seed = 0;\n    ULONG i;\n\n    if (Count == 0)\n        return;\n\n    for (i = 0; i < Count - 1; i++)\n    {\n        Buffer[i] = 'A' + (RtlRandomEx(&seed) % 26);\n    }\n\n    Buffer[Count - 1] = 0;\n}\n\n/**\n * Modifies a string to ensure it is within the specified length.\n *\n * \\param String The input string.\n * \\param DesiredCount The desired number of characters in the new string. If necessary, parts of\n * the string are replaced with an ellipsis to indicate characters have been omitted.\n *\n * \\return The new string.\n */\nPPH_STRING PhEllipsisString(\n    _In_ PPH_STRING String,\n    _In_ ULONG DesiredCount\n    )\n{\n    if (\n        (ULONG)String->Length / 2 <= DesiredCount ||\n        DesiredCount < 3\n        )\n    {\n        return PhReferenceObject(String);\n    }\n    else\n    {\n        PPH_STRING string;\n\n        string = PhCreateStringEx(NULL, DesiredCount * 2);\n        memcpy(string->Buffer, String->Buffer, (DesiredCount - 3) * 2);\n        memcpy(&string->Buffer[DesiredCount - 3], L\"...\", 6);\n\n        return string;\n    }\n}\n\n/**\n * Modifies a string to ensure it is within the specified length, parsing the string as a path.\n *\n * \\param String The input string.\n * \\param DesiredCount The desired number of characters in the new string. If necessary, parts of\n * the string are replaced with an ellipsis to indicate characters have been omitted.\n *\n * \\return The new string.\n */\nPPH_STRING PhEllipsisStringPath(\n    _In_ PPH_STRING String,\n    _In_ ULONG DesiredCount\n    )\n{\n    ULONG_PTR secondPartIndex;\n\n    secondPartIndex = PhFindLastCharInString(String, 0, L'\\\\');\n\n    if (secondPartIndex == -1)\n        secondPartIndex = PhFindLastCharInString(String, 0, L'/');\n    if (secondPartIndex == -1)\n        return PhEllipsisString(String, DesiredCount);\n\n    if (\n        String->Length / 2 <= DesiredCount ||\n        DesiredCount < 3\n        )\n    {\n        return PhReferenceObject(String);\n    }\n    else\n    {\n        PPH_STRING string;\n        ULONG_PTR firstPartCopyLength;\n        ULONG_PTR secondPartCopyLength;\n\n        string = PhCreateStringEx(NULL, DesiredCount * 2);\n        secondPartCopyLength = String->Length / 2 - secondPartIndex;\n\n        // Check if we have enough space for the entire second part of the string.\n        if (secondPartCopyLength + 3 <= DesiredCount)\n        {\n            // Yes, copy part of the first part and the entire second part.\n            firstPartCopyLength = DesiredCount - secondPartCopyLength - 3;\n        }\n        else\n        {\n            // No, copy part of both, from the beginning of the first part and the end of the second\n            // part.\n            firstPartCopyLength = (DesiredCount - 3) / 2;\n            secondPartCopyLength = DesiredCount - 3 - firstPartCopyLength;\n            secondPartIndex = String->Length / 2 - secondPartCopyLength;\n        }\n\n        memcpy(\n            string->Buffer,\n            String->Buffer,\n            firstPartCopyLength * 2\n            );\n        memcpy(\n            &string->Buffer[firstPartCopyLength],\n            L\"...\",\n            6\n            );\n        memcpy(\n            &string->Buffer[firstPartCopyLength + 3],\n            &String->Buffer[secondPartIndex],\n            secondPartCopyLength * 2\n            );\n\n        return string;\n    }\n}\n\nFORCEINLINE BOOLEAN PhpMatchWildcards(\n    _In_ PWSTR Pattern,\n    _In_ PWSTR String,\n    _In_ BOOLEAN IgnoreCase\n    )\n{\n    PWCHAR s, p;\n    BOOLEAN star = FALSE;\n\n    // Code is from http://xoomer.virgilio.it/acantato/dev/wildcard/wildmatch.html\n\nLoopStart:\n    for (s = String, p = Pattern; *s; s++, p++)\n    {\n        switch (*p)\n        {\n        case '?':\n            break;\n        case '*':\n            star = TRUE;\n            String = s;\n            Pattern = p;\n\n            do\n            {\n                Pattern++;\n            } while (*Pattern == '*');\n\n            if (!*Pattern) return TRUE;\n\n            goto LoopStart;\n        default:\n            if (!IgnoreCase)\n            {\n                if (*s != *p)\n                    goto StarCheck;\n            }\n            else\n            {\n                if (towupper(*s) != towupper(*p))\n                    goto StarCheck;\n            }\n\n            break;\n        }\n    }\n\n    while (*p == '*')\n        p++;\n\n    return (!*p);\n\nStarCheck:\n    if (!star)\n        return FALSE;\n\n    String++;\n    goto LoopStart;\n}\n\n/**\n * Matches a pattern against a string.\n *\n * \\param Pattern The pattern, which can contain asterisks and question marks.\n * \\param String The string which the pattern is matched against.\n * \\param IgnoreCase Whether to ignore character cases.\n */\nBOOLEAN PhMatchWildcards(\n    _In_ PWSTR Pattern,\n    _In_ PWSTR String,\n    _In_ BOOLEAN IgnoreCase\n    )\n{\n    if (!IgnoreCase)\n        return PhpMatchWildcards(Pattern, String, FALSE);\n    else\n        return PhpMatchWildcards(Pattern, String, TRUE);\n}\n\n/**\n * Escapes a string for prefix characters (ampersands).\n *\n * \\param String The string to process.\n *\n * \\return The escaped string, with each ampersand replaced by 2 ampersands.\n */\nPPH_STRING PhEscapeStringForMenuPrefix(\n    _In_ PPH_STRINGREF String\n    )\n{\n    PH_STRING_BUILDER stringBuilder;\n    SIZE_T i;\n    SIZE_T length;\n    PWCHAR runStart;\n    SIZE_T runCount;\n\n    length = String->Length / sizeof(WCHAR);\n    runStart = NULL;\n\n    PhInitializeStringBuilder(&stringBuilder, String->Length);\n\n    for (i = 0; i < length; i++)\n    {\n        switch (String->Buffer[i])\n        {\n        case '&':\n            if (runStart)\n            {\n                PhAppendStringBuilderEx(&stringBuilder, runStart, runCount * sizeof(WCHAR));\n                runStart = NULL;\n            }\n\n            PhAppendStringBuilder2(&stringBuilder, L\"&&\");\n\n            break;\n        default:\n            if (runStart)\n            {\n                runCount++;\n            }\n            else\n            {\n                runStart = &String->Buffer[i];\n                runCount = 1;\n            }\n\n            break;\n        }\n    }\n\n    if (runStart)\n        PhAppendStringBuilderEx(&stringBuilder, runStart, runCount * sizeof(WCHAR));\n\n    return PhFinalStringBuilderString(&stringBuilder);\n}\n\n/**\n * Compares two strings, ignoring prefix characters (ampersands).\n *\n * \\param A The first string.\n * \\param B The second string.\n * \\param IgnoreCase Whether to ignore character cases.\n * \\param MatchIfPrefix Specify TRUE to return 0 when \\a A is a prefix of \\a B.\n */\nLONG PhCompareUnicodeStringZIgnoreMenuPrefix(\n    _In_ PWSTR A,\n    _In_ PWSTR B,\n    _In_ BOOLEAN IgnoreCase,\n    _In_ BOOLEAN MatchIfPrefix\n    )\n{\n    WCHAR t;\n\n    if (!A || !B)\n        return -1;\n\n    if (!IgnoreCase)\n    {\n        while (TRUE)\n        {\n            // This takes care of double ampersands as well (they are treated as one literal\n            // ampersand).\n            if (*A == '&')\n                A++;\n            if (*B == '&')\n                B++;\n\n            t = *A;\n\n            if (t == 0)\n            {\n                if (MatchIfPrefix)\n                    return 0;\n\n                break;\n            }\n\n            if (t != *B)\n                break;\n\n            A++;\n            B++;\n        }\n\n        return C_2uTo4(t) - C_2uTo4(*B);\n    }\n    else\n    {\n        while (TRUE)\n        {\n            if (*A == '&')\n                A++;\n            if (*B == '&')\n                B++;\n\n            t = *A;\n\n            if (t == 0)\n            {\n                if (MatchIfPrefix)\n                    return 0;\n\n                break;\n            }\n\n            if (towupper(t) != towupper(*B))\n                break;\n\n            A++;\n            B++;\n        }\n\n        return C_2uTo4(t) - C_2uTo4(*B);\n    }\n}\n\n/**\n * Formats a date using the user's default locale.\n *\n * \\param Date The time structure. If NULL, the current time is used.\n * \\param Format The format of the date. If NULL, the format appropriate to the user's locale is\n * used.\n */\nPPH_STRING PhFormatDate(\n    _In_opt_ PSYSTEMTIME Date,\n    _In_opt_ PWSTR Format\n    )\n{\n    PPH_STRING string;\n    ULONG bufferSize;\n\n    bufferSize = GetDateFormat(LOCALE_USER_DEFAULT, 0, Date, Format, NULL, 0);\n    string = PhCreateStringEx(NULL, bufferSize * 2);\n\n    if (!GetDateFormat(LOCALE_USER_DEFAULT, 0, Date, Format, string->Buffer, bufferSize))\n    {\n        PhDereferenceObject(string);\n        return NULL;\n    }\n\n    PhTrimToNullTerminatorString(string);\n\n    return string;\n}\n\n/**\n * Formats a time using the user's default locale.\n *\n * \\param Time The time structure. If NULL, the current time is used.\n * \\param Format The format of the time. If NULL, the format appropriate to the user's locale is\n * used.\n */\nPPH_STRING PhFormatTime(\n    _In_opt_ PSYSTEMTIME Time,\n    _In_opt_ PWSTR Format\n    )\n{\n    PPH_STRING string;\n    ULONG bufferSize;\n\n    bufferSize = GetTimeFormat(LOCALE_USER_DEFAULT, 0, Time, Format, NULL, 0);\n    string = PhCreateStringEx(NULL, bufferSize * 2);\n\n    if (!GetTimeFormat(LOCALE_USER_DEFAULT, 0, Time, Format, string->Buffer, bufferSize))\n    {\n        PhDereferenceObject(string);\n        return NULL;\n    }\n\n    PhTrimToNullTerminatorString(string);\n\n    return string;\n}\n\n/**\n * Formats a date and time using the user's default locale.\n *\n * \\param DateTime The time structure. If NULL, the current time is used.\n *\n * \\return A string containing the time, a space character, then the date.\n */\nPPH_STRING PhFormatDateTime(\n    _In_opt_ PSYSTEMTIME DateTime\n    )\n{\n    PPH_STRING string;\n    ULONG timeBufferSize;\n    ULONG dateBufferSize;\n    ULONG count;\n\n    timeBufferSize = GetTimeFormat(LOCALE_USER_DEFAULT, 0, DateTime, NULL, NULL, 0);\n    dateBufferSize = GetDateFormat(LOCALE_USER_DEFAULT, 0, DateTime, NULL, NULL, 0);\n\n    string = PhCreateStringEx(NULL, (timeBufferSize + 1 + dateBufferSize) * 2);\n\n    if (!GetTimeFormat(LOCALE_USER_DEFAULT, 0, DateTime, NULL, &string->Buffer[0], timeBufferSize))\n    {\n        PhDereferenceObject(string);\n        return NULL;\n    }\n\n    count = (ULONG)PhCountStringZ(string->Buffer);\n    string->Buffer[count] = ' ';\n\n    if (!GetDateFormat(LOCALE_USER_DEFAULT, 0, DateTime, NULL, &string->Buffer[count + 1], dateBufferSize))\n    {\n        PhDereferenceObject(string);\n        return NULL;\n    }\n\n    PhTrimToNullTerminatorString(string);\n\n    return string;\n}\n\nPPH_STRING PhFormatTimeSpan(\n    _In_ ULONG64 Ticks,\n    _In_opt_ ULONG Mode\n    )\n{\n    PPH_STRING string;\n\n    string = PhCreateStringEx(NULL, PH_TIMESPAN_STR_LEN);\n    PhPrintTimeSpan(string->Buffer, Ticks, Mode);\n    PhTrimToNullTerminatorString(string);\n\n    return string;\n}\n\n/**\n * Formats a relative time span.\n *\n * \\param TimeSpan The time span, in ticks.\n */\nPPH_STRING PhFormatTimeSpanRelative(\n    _In_ ULONG64 TimeSpan\n    )\n{\n    PH_AUTO_POOL autoPool;\n    PPH_STRING string;\n    DOUBLE days;\n    DOUBLE weeks;\n    DOUBLE fortnights;\n    DOUBLE months;\n    DOUBLE years;\n    DOUBLE centuries;\n\n    PhInitializeAutoPool(&autoPool);\n\n    days = (DOUBLE)TimeSpan / PH_TICKS_PER_DAY;\n    weeks = days / 7;\n    fortnights = weeks / 2;\n    years = days / 365.2425;\n    months = years * 12;\n    centuries = years / 100;\n\n    if (centuries >= 1)\n    {\n        string = PhaFormatString(L\"%u %s\", (ULONG)centuries, (ULONG)centuries == 1 ? L\"century\" : L\"centuries\");\n    }\n    else if (years >= 1)\n    {\n        string = PhaFormatString(L\"%u %s\", (ULONG)years, (ULONG)years == 1 ? L\"year\" : L\"years\");\n    }\n    else if (months >= 1)\n    {\n        string = PhaFormatString(L\"%u %s\", (ULONG)months, (ULONG)months == 1 ? L\"month\" : L\"months\");\n    }\n    else if (fortnights >= 1)\n    {\n        string = PhaFormatString(L\"%u %s\", (ULONG)fortnights, (ULONG)fortnights == 1 ? L\"fortnight\" : L\"fortnights\");\n    }\n    else if (weeks >= 1)\n    {\n        string = PhaFormatString(L\"%u %s\", (ULONG)weeks, (ULONG)weeks == 1 ? L\"week\" : L\"weeks\");\n    }\n    else\n    {\n        DOUBLE milliseconds;\n        DOUBLE seconds;\n        DOUBLE minutes;\n        DOUBLE hours;\n        ULONG secondsPartial;\n        ULONG minutesPartial;\n        ULONG hoursPartial;\n\n        milliseconds = (DOUBLE)TimeSpan / PH_TICKS_PER_MS;\n        seconds = (DOUBLE)TimeSpan / PH_TICKS_PER_SEC;\n        minutes = (DOUBLE)TimeSpan / PH_TICKS_PER_MIN;\n        hours = (DOUBLE)TimeSpan / PH_TICKS_PER_HOUR;\n\n        if (days >= 1)\n        {\n            string = PhaFormatString(L\"%u %s\", (ULONG)days, (ULONG)days == 1 ? L\"day\" : L\"days\");\n            hoursPartial = (ULONG)PH_TICKS_PARTIAL_HOURS(TimeSpan);\n\n            if (hoursPartial >= 1)\n            {\n                string = PhaFormatString(L\"%s and %u %s\", string->Buffer, hoursPartial, hoursPartial == 1 ? L\"hour\" : L\"hours\");\n            }\n        }\n        else if (hours >= 1)\n        {\n            string = PhaFormatString(L\"%u %s\", (ULONG)hours, (ULONG)hours == 1 ? L\"hour\" : L\"hours\");\n            minutesPartial = (ULONG)PH_TICKS_PARTIAL_MIN(TimeSpan);\n\n            if (minutesPartial >= 1)\n            {\n                string = PhaFormatString(L\"%s and %u %s\", string->Buffer, (ULONG)minutesPartial, (ULONG)minutesPartial == 1 ? L\"minute\" : L\"minutes\");\n            }\n        }\n        else if (minutes >= 1)\n        {\n            string = PhaFormatString(L\"%u %s\", (ULONG)minutes, (ULONG)minutes == 1 ? L\"minute\" : L\"minutes\");\n            secondsPartial = (ULONG)PH_TICKS_PARTIAL_SEC(TimeSpan);\n\n            if (secondsPartial >= 1)\n            {\n                string = PhaFormatString(L\"%s and %u %s\", string->Buffer, (ULONG)secondsPartial, (ULONG)secondsPartial == 1 ? L\"second\" : L\"seconds\");\n            }\n        }\n        else if (seconds >= 1)\n        {\n            string = PhaFormatString(L\"%u %s\", (ULONG)seconds, (ULONG)seconds == 1 ? L\"second\" : L\"seconds\");\n        }\n        else if (milliseconds >= 1)\n        {\n            string = PhaFormatString(L\"%u %s\", (ULONG)milliseconds, (ULONG)milliseconds == 1 ? L\"millisecond\" : L\"milliseconds\");\n        }\n        else\n        {\n            string = PhaCreateString(L\"a very short time\");\n        }\n    }\n\n    // Turn 1 into \"a\", e.g. 1 minute -> a minute\n    if (PhStartsWithString2(string, L\"1 \", FALSE))\n    {\n        // Special vowel case: a hour -> an hour\n        if (string->Buffer[2] != 'h')\n            string = PhaConcatStrings2(L\"a \", &string->Buffer[2]);\n        else\n            string = PhaConcatStrings2(L\"an \", &string->Buffer[2]);\n    }\n\n    PhReferenceObject(string);\n    PhDeleteAutoPool(&autoPool);\n\n    return string;\n}\n\n/**\n * Formats a 64-bit unsigned integer.\n *\n * \\param Value The integer.\n * \\param GroupDigits TRUE to group digits, otherwise FALSE.\n */\nPPH_STRING PhFormatUInt64(\n    _In_ ULONG64 Value,\n    _In_ BOOLEAN GroupDigits\n    )\n{\n    PH_FORMAT format;\n\n    format.Type = UInt64FormatType | (GroupDigits ? FormatGroupDigits : 0);\n    format.u.UInt64 = Value;\n\n    return PhFormat(&format, 1, 0);\n}\n\nPPH_STRING PhFormatDecimal(\n    _In_ PWSTR Value,\n    _In_ ULONG FractionalDigits,\n    _In_ BOOLEAN GroupDigits\n    )\n{\n    static PH_INITONCE initOnce = PH_INITONCE_INIT;\n    static WCHAR decimalSeparator[4];\n    static WCHAR thousandSeparator[4];\n\n    PPH_STRING string;\n    NUMBERFMT format;\n    ULONG bufferSize;\n\n    if (PhBeginInitOnce(&initOnce))\n    {\n        if (!GetLocaleInfo(LOCALE_USER_DEFAULT, LOCALE_SDECIMAL, decimalSeparator, 4))\n        {\n            decimalSeparator[0] = '.';\n            decimalSeparator[1] = 0;\n        }\n\n        if (!GetLocaleInfo(LOCALE_USER_DEFAULT, LOCALE_STHOUSAND, thousandSeparator, 4))\n        {\n            thousandSeparator[0] = ',';\n            thousandSeparator[1] = 0;\n        }\n\n        PhEndInitOnce(&initOnce);\n    }\n\n    format.NumDigits = FractionalDigits;\n    format.LeadingZero = 0;\n    format.Grouping = GroupDigits ? 3 : 0;\n    format.lpDecimalSep = decimalSeparator;\n    format.lpThousandSep = thousandSeparator;\n    format.NegativeOrder = 1;\n\n    bufferSize = GetNumberFormat(LOCALE_USER_DEFAULT, 0, Value, &format, NULL, 0);\n    string = PhCreateStringEx(NULL, bufferSize * 2);\n\n    if (!GetNumberFormat(LOCALE_USER_DEFAULT, 0, Value, &format, string->Buffer, bufferSize))\n    {\n        PhDereferenceObject(string);\n        return NULL;\n    }\n\n    PhTrimToNullTerminatorString(string);\n\n    return string;\n}\n\n/**\n * Gets a string representing a size.\n *\n * \\param Size The size value.\n * \\param MaxSizeUnit The largest unit of size to use, -1 to use PhMaxSizeUnit, or -2 for no limit.\n * \\li \\c 0 Bytes.\n * \\li \\c 1 Kilobytes.\n * \\li \\c 2 Megabytes.\n * \\li \\c 3 Gigabytes.\n * \\li \\c 4 Terabytes.\n * \\li \\c 5 Petabytes.\n * \\li \\c 6 Exabytes.\n */\nPPH_STRING PhFormatSize(\n    _In_ ULONG64 Size,\n    _In_ ULONG MaxSizeUnit\n    )\n{\n    PH_FORMAT format;\n\n    // PhFormat handles this better than the old method.\n\n    format.Type = SizeFormatType | FormatUseRadix;\n    format.Radix = (UCHAR)(MaxSizeUnit != -1 ? MaxSizeUnit : PhMaxSizeUnit);\n    format.u.Size = Size;\n\n    return PhFormat(&format, 1, 0);\n}\n\n/**\n * Converts a UUID to its string representation.\n *\n * \\param Guid A UUID.\n */\nPPH_STRING PhFormatGuid(\n    _In_ PGUID Guid\n    )\n{\n    PPH_STRING string;\n    UNICODE_STRING unicodeString;\n\n    if (!NT_SUCCESS(RtlStringFromGUID(Guid, &unicodeString)))\n        return NULL;\n\n    string = PhCreateStringFromUnicodeString(&unicodeString);\n    RtlFreeUnicodeString(&unicodeString);\n\n    return string;\n}\n\n/**\n * Retrieves image version information for a file.\n *\n * \\param FileName The file name.\n *\n * \\return A version information block. You must free this using PhFree() when you no longer need\n * it.\n */\nPVOID PhGetFileVersionInfo(\n    _In_ PWSTR FileName\n    )\n{\n    PVOID libraryModule;\n    PVOID versionInfo;\n\n    libraryModule = LoadLibraryEx(FileName, NULL, LOAD_LIBRARY_AS_DATAFILE);\n\n    if (!libraryModule)\n        return NULL;\n\n    if (PhLoadResource(\n        libraryModule, \n        MAKEINTRESOURCE(VS_VERSION_INFO), \n        VS_FILE_INFO, \n        NULL, \n        &versionInfo\n        ))\n    {\n        FreeLibrary(libraryModule);\n        return versionInfo;\n    }\n\n    FreeLibrary(libraryModule);\n    return NULL;\n}\n\n/**\n * Retrieves the language ID and code page used by a version information block.\n *\n * \\param VersionInfo The version information block.\n */\nULONG PhGetFileVersionInfoLangCodePage(\n    _In_ PVOID VersionInfo\n    )\n{\n    PVOID buffer;\n    ULONG length;\n\n    if (VerQueryValue(VersionInfo, L\"\\\\VarFileInfo\\\\Translation\", &buffer, &length))\n    {\n        // Combine the language ID and code page.\n        return (*(PUSHORT)buffer << 16) + *((PUSHORT)buffer + 1);\n    }\n    else\n    {\n        return (MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US) << 16) + 1252;\n    }\n}\n\n/**\n * Retrieves a string in a version information block.\n *\n * \\param VersionInfo The version information block.\n * \\param SubBlock The path to the sub-block.\n */\nPPH_STRING PhGetFileVersionInfoString(\n    _In_ PVOID VersionInfo,\n    _In_ PWSTR SubBlock\n    )\n{\n    PVOID buffer;\n    ULONG length;\n\n    if (VerQueryValue(VersionInfo, SubBlock, &buffer, &length))\n    {\n        PPH_STRING string;\n\n        // Check if the string has a valid length.\n        if (length <= sizeof(WCHAR))\n            return NULL;\n\n        string = PhCreateStringEx((PWCHAR)buffer, length * sizeof(WCHAR));\n        // length may include the null terminator.\n        PhTrimToNullTerminatorString(string);\n\n        return string;\n    }\n    else\n    {\n        return NULL;\n    }\n}\n\n/**\n * Retrieves a string in a version information block.\n *\n * \\param VersionInfo The version information block.\n * \\param LangCodePage The language ID and code page of the string.\n * \\param StringName The name of the string.\n */\nPPH_STRING PhGetFileVersionInfoString2(\n    _In_ PVOID VersionInfo,\n    _In_ ULONG LangCodePage,\n    _In_ PWSTR StringName\n    )\n{\n    WCHAR subBlock[65];\n    PH_FORMAT format[4];\n\n    PhInitFormatS(&format[0], L\"\\\\StringFileInfo\\\\\");\n    PhInitFormatX(&format[1], LangCodePage);\n    format[1].Type |= FormatPadZeros | FormatUpperCase;\n    format[1].Width = 8;\n    PhInitFormatC(&format[2], '\\\\');\n    PhInitFormatS(&format[3], StringName);\n\n    if (PhFormatToBuffer(format, 4, subBlock, sizeof(subBlock), NULL))\n        return PhGetFileVersionInfoString(VersionInfo, subBlock);\n    else\n        return NULL;\n}\n\nVOID PhpGetImageVersionInfoFields(\n    _Out_ PPH_IMAGE_VERSION_INFO ImageVersionInfo,\n    _In_ PVOID VersionInfo,\n    _In_ ULONG LangCodePage\n    )\n{\n    ImageVersionInfo->CompanyName = PhGetFileVersionInfoString2(VersionInfo, LangCodePage, L\"CompanyName\");\n    ImageVersionInfo->FileDescription = PhGetFileVersionInfoString2(VersionInfo, LangCodePage, L\"FileDescription\");\n    ImageVersionInfo->ProductName = PhGetFileVersionInfoString2(VersionInfo, LangCodePage, L\"ProductName\");\n}\n\n/**\n * Initializes a structure with version information.\n *\n * \\param ImageVersionInfo The version information structure.\n * \\param FileName The file name of an image.\n */\nBOOLEAN PhInitializeImageVersionInfo(\n    _Out_ PPH_IMAGE_VERSION_INFO ImageVersionInfo,\n    _In_ PWSTR FileName\n    )\n{\n    PVOID versionInfo;\n    ULONG langCodePage;\n    VS_FIXEDFILEINFO *rootBlock;\n    ULONG rootBlockLength;\n    PH_FORMAT fileVersionFormat[7];\n\n    versionInfo = PhGetFileVersionInfo(FileName);\n\n    if (!versionInfo)\n        return FALSE;\n\n    langCodePage = PhGetFileVersionInfoLangCodePage(versionInfo);\n    PhpGetImageVersionInfoFields(ImageVersionInfo, versionInfo, langCodePage);\n\n    if (!ImageVersionInfo->CompanyName && !ImageVersionInfo->FileDescription && !ImageVersionInfo->ProductName)\n    {\n        // Use the windows-1252 code page.\n        PhpGetImageVersionInfoFields(ImageVersionInfo, versionInfo, (langCodePage & 0xffff0000) + 1252);\n\n        // Use the default language (US English).\n        if (!ImageVersionInfo->CompanyName && !ImageVersionInfo->FileDescription && !ImageVersionInfo->ProductName)\n        {\n            PhpGetImageVersionInfoFields(ImageVersionInfo, versionInfo, (MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US) << 16) + 1252);\n\n            if (!ImageVersionInfo->CompanyName && !ImageVersionInfo->FileDescription && !ImageVersionInfo->ProductName)\n                PhpGetImageVersionInfoFields(ImageVersionInfo, versionInfo, (MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US) << 16) + 0);\n        }\n    }\n\n    // The version information is language-independent and must be read from the root block.\n    if (VerQueryValue(versionInfo, L\"\\\\\", &rootBlock, &rootBlockLength) && rootBlockLength != 0)\n    {\n        PhInitFormatU(&fileVersionFormat[0], rootBlock->dwFileVersionMS >> 16);\n        PhInitFormatC(&fileVersionFormat[1], '.');\n        PhInitFormatU(&fileVersionFormat[2], rootBlock->dwFileVersionMS & 0xffff);\n        PhInitFormatC(&fileVersionFormat[3], '.');\n        PhInitFormatU(&fileVersionFormat[4], rootBlock->dwFileVersionLS >> 16);\n        PhInitFormatC(&fileVersionFormat[5], '.');\n        PhInitFormatU(&fileVersionFormat[6], rootBlock->dwFileVersionLS & 0xffff);\n\n        ImageVersionInfo->FileVersion = PhFormat(fileVersionFormat, 7, 30);\n    }\n    else\n    {\n        ImageVersionInfo->FileVersion = NULL;\n    }\n\n    PhFree(versionInfo);\n\n    return TRUE;\n}\n\n/**\n * Frees a version information structure initialized by PhInitializeImageVersionInfo().\n *\n * \\param ImageVersionInfo The version information structure.\n */\nVOID PhDeleteImageVersionInfo(\n    _Inout_ PPH_IMAGE_VERSION_INFO ImageVersionInfo\n    )\n{\n    if (ImageVersionInfo->CompanyName) PhDereferenceObject(ImageVersionInfo->CompanyName);\n    if (ImageVersionInfo->FileDescription) PhDereferenceObject(ImageVersionInfo->FileDescription);\n    if (ImageVersionInfo->FileVersion) PhDereferenceObject(ImageVersionInfo->FileVersion);\n    if (ImageVersionInfo->ProductName) PhDereferenceObject(ImageVersionInfo->ProductName);\n}\n\nPPH_STRING PhFormatImageVersionInfo(\n    _In_opt_ PPH_STRING FileName,\n    _In_ PPH_IMAGE_VERSION_INFO ImageVersionInfo,\n    _In_opt_ PPH_STRINGREF Indent,\n    _In_opt_ ULONG LineLimit\n    )\n{\n    PH_STRING_BUILDER stringBuilder;\n\n    if (LineLimit == 0)\n        LineLimit = MAXULONG32;\n\n    PhInitializeStringBuilder(&stringBuilder, 40);\n\n    // File name\n\n    if (!PhIsNullOrEmptyString(FileName))\n    {\n        PPH_STRING temp;\n\n        if (Indent) PhAppendStringBuilder(&stringBuilder, Indent);\n\n        temp = PhEllipsisStringPath(FileName, LineLimit);\n        PhAppendStringBuilder(&stringBuilder, &temp->sr);\n        PhDereferenceObject(temp);\n        PhAppendCharStringBuilder(&stringBuilder, '\\n');\n    }\n\n    // File description & version\n\n    if (!(\n        PhIsNullOrEmptyString(ImageVersionInfo->FileDescription) &&\n        PhIsNullOrEmptyString(ImageVersionInfo->FileVersion)\n        ))\n    {\n        PPH_STRING tempDescription = NULL;\n        PPH_STRING tempVersion = NULL;\n        ULONG limitForDescription;\n        ULONG limitForVersion;\n\n        if (LineLimit != MAXULONG32)\n        {\n            limitForVersion = (LineLimit - 1) / 4; // 1/4 space for version (and space character)\n            limitForDescription = LineLimit - limitForVersion;\n        }\n        else\n        {\n            limitForDescription = MAXULONG32;\n            limitForVersion = MAXULONG32;\n        }\n\n        if (!PhIsNullOrEmptyString(ImageVersionInfo->FileDescription))\n        {\n            tempDescription = PhEllipsisString(\n                ImageVersionInfo->FileDescription,\n                limitForDescription\n                );\n        }\n\n        if (!PhIsNullOrEmptyString(ImageVersionInfo->FileVersion))\n        {\n            tempVersion = PhEllipsisString(\n                ImageVersionInfo->FileVersion,\n                limitForVersion\n                );\n        }\n\n        if (Indent) PhAppendStringBuilder(&stringBuilder, Indent);\n\n        if (tempDescription)\n        {\n            PhAppendStringBuilder(&stringBuilder, &tempDescription->sr);\n\n            if (tempVersion)\n                PhAppendCharStringBuilder(&stringBuilder, ' ');\n        }\n\n        if (tempVersion)\n            PhAppendStringBuilder(&stringBuilder, &tempVersion->sr);\n\n        if (tempDescription)\n            PhDereferenceObject(tempDescription);\n        if (tempVersion)\n            PhDereferenceObject(tempVersion);\n\n        PhAppendCharStringBuilder(&stringBuilder, '\\n');\n    }\n\n    // File company\n\n    if (!PhIsNullOrEmptyString(ImageVersionInfo->CompanyName))\n    {\n        PPH_STRING temp;\n\n        if (Indent) PhAppendStringBuilder(&stringBuilder, Indent);\n\n        temp = PhEllipsisString(ImageVersionInfo->CompanyName, LineLimit);\n        PhAppendStringBuilder(&stringBuilder, &temp->sr);\n        PhDereferenceObject(temp);\n        PhAppendCharStringBuilder(&stringBuilder, '\\n');\n    }\n\n    // Remove the extra newline.\n    if (stringBuilder.String->Length != 0)\n        PhRemoveEndStringBuilder(&stringBuilder, 1);\n\n    return PhFinalStringBuilderString(&stringBuilder);\n}\n\n/**\n * Gets an absolute file name.\n *\n * \\param FileName A file name.\n * \\param IndexOfFileName A variable which receives the index of the base name.\n *\n * \\return An absolute file name, or NULL if the function failed.\n */\nPPH_STRING PhGetFullPath(\n    _In_ PWSTR FileName,\n    _Out_opt_ PULONG IndexOfFileName\n    )\n{\n    PPH_STRING fullPath;\n    ULONG bufferSize;\n    ULONG returnLength;\n    PWSTR filePart;\n\n    bufferSize = 0x80;\n    fullPath = PhCreateStringEx(NULL, bufferSize * 2);\n\n    returnLength = RtlGetFullPathName_U(FileName, bufferSize, fullPath->Buffer, &filePart);\n\n    if (returnLength > bufferSize)\n    {\n        PhDereferenceObject(fullPath);\n        bufferSize = returnLength;\n        fullPath = PhCreateStringEx(NULL, bufferSize * 2);\n\n        returnLength = RtlGetFullPathName_U(FileName, bufferSize, fullPath->Buffer, &filePart);\n    }\n\n    if (returnLength == 0)\n    {\n        PhDereferenceObject(fullPath);\n        return NULL;\n    }\n\n    PhTrimToNullTerminatorString(fullPath);\n\n    if (IndexOfFileName)\n    {\n        if (filePart)\n        {\n            // The path points to a file.\n            *IndexOfFileName = (ULONG)(filePart - fullPath->Buffer);\n        }\n        else\n        {\n            // The path points to a directory.\n            *IndexOfFileName = -1;\n        }\n    }\n\n    return fullPath;\n}\n\n/**\n * Expands environment variables in a string.\n *\n * \\param String The string.\n */\nPPH_STRING PhExpandEnvironmentStrings(\n    _In_ PPH_STRINGREF String\n    )\n{\n    NTSTATUS status;\n    UNICODE_STRING inputString;\n    UNICODE_STRING outputString;\n    PPH_STRING string;\n    ULONG bufferLength;\n\n    if (!PhStringRefToUnicodeString(String, &inputString))\n        return NULL;\n\n    bufferLength = 0x40;\n    string = PhCreateStringEx(NULL, bufferLength);\n    outputString.MaximumLength = (USHORT)bufferLength;\n    outputString.Length = 0;\n    outputString.Buffer = string->Buffer;\n\n    status = RtlExpandEnvironmentStrings_U(\n        NULL,\n        &inputString,\n        &outputString,\n        &bufferLength\n        );\n\n    if (status == STATUS_BUFFER_TOO_SMALL)\n    {\n        PhDereferenceObject(string);\n        string = PhCreateStringEx(NULL, bufferLength);\n        outputString.MaximumLength = (USHORT)bufferLength;\n        outputString.Length = 0;\n        outputString.Buffer = string->Buffer;\n\n        status = RtlExpandEnvironmentStrings_U(\n            NULL,\n            &inputString,\n            &outputString,\n            &bufferLength\n            );\n    }\n\n    if (!NT_SUCCESS(status))\n    {\n        PhDereferenceObject(string);\n        return NULL;\n    }\n\n    string->Length = outputString.Length;\n    string->Buffer[string->Length / 2] = 0; // make sure there is a null terminator\n\n    return string;\n}\n\n/**\n * Gets the base name from a file name.\n *\n * \\param FileName The file name.\n */\nPPH_STRING PhGetBaseName(\n    _In_ PPH_STRING FileName\n    )\n{\n    PH_STRINGREF pathPart;\n    PH_STRINGREF baseNamePart;\n\n    if (!PhSplitStringRefAtLastChar(&FileName->sr, '\\\\', &pathPart, &baseNamePart))\n        return PhReferenceObject(FileName);\n\n    return PhCreateString2(&baseNamePart);\n}\n\n/**\n * Gets the parent directory from a file name.\n *\n * \\param FileName The file name.\n */\nPPH_STRING PhGetBaseDirectory(\n    _In_ PPH_STRING FileName\n    )\n{\n    PH_STRINGREF pathPart;\n    PH_STRINGREF baseNamePart;\n\n    if (!PhSplitStringRefAtLastChar(&FileName->sr, '\\\\', &pathPart, &baseNamePart))\n        return NULL;\n\n    return PhCreateString2(&pathPart);\n}\n\n/**\n * Retrieves the system directory path.\n */\nPPH_STRING PhGetSystemDirectory(\n    VOID\n    )\n{\n    static PH_STRINGREF system32String = PH_STRINGREF_INIT(L\"\\\\System32\");\n    static PPH_STRING cachedSystemDirectory = NULL;\n    PPH_STRING systemDirectory;\n    PH_STRINGREF systemRootString;\n\n    // Use the cached value if possible.\n\n    if (cachedSystemDirectory)\n        return PhReferenceObject(cachedSystemDirectory);\n\n    PhGetSystemRoot(&systemRootString);\n    systemDirectory = PhConcatStringRef2(&systemRootString, &system32String);\n\n    // Try to cache the value.\n    if (_InterlockedCompareExchangePointer(\n        &cachedSystemDirectory,\n        systemDirectory,\n        NULL\n        ) == NULL)\n    {\n        // Success, add one more reference for the cache.\n        PhReferenceObject(systemDirectory);\n    }\n\n    return systemDirectory;\n}\n\n/**\n * Retrieves the Windows directory path.\n */\nVOID PhGetSystemRoot(\n    _Out_ PPH_STRINGREF SystemRoot\n    )\n{\n    static PH_STRINGREF systemRoot;\n\n    PH_STRINGREF localSystemRoot;\n    SIZE_T count;\n\n    if (systemRoot.Buffer)\n    {\n        *SystemRoot = systemRoot;\n        return;\n    }\n\n    localSystemRoot.Buffer = USER_SHARED_DATA->NtSystemRoot;\n    count = PhCountStringZ(localSystemRoot.Buffer);\n    localSystemRoot.Length = count * sizeof(WCHAR);\n\n    // Make sure the system root string doesn't have a trailing backslash.\n    if (localSystemRoot.Buffer[count - 1] == '\\\\')\n        localSystemRoot.Length -= sizeof(WCHAR);\n\n    *SystemRoot = localSystemRoot;\n\n    systemRoot.Length = localSystemRoot.Length;\n    MemoryBarrier();\n    systemRoot.Buffer = localSystemRoot.Buffer;\n}\n\n/**\n * Locates a loader entry in the current process.\n *\n * \\param DllBase The base address of the DLL. Specify NULL if this is not a search criteria.\n * \\param FullDllName The full name of the DLL. Specify NULL if this is not a search criteria.\n * \\param BaseDllName The base name of the DLL. Specify NULL if this is not a search criteria.\n *\n * \\remarks This function must be called with the loader lock acquired. The first entry matching all\n * of the specified values is returned.\n */\nPLDR_DATA_TABLE_ENTRY PhFindLoaderEntry(\n    _In_opt_ PVOID DllBase,\n    _In_opt_ PPH_STRINGREF FullDllName,\n    _In_opt_ PPH_STRINGREF BaseDllName\n    )\n{\n    PLDR_DATA_TABLE_ENTRY result = NULL;\n    PLDR_DATA_TABLE_ENTRY entry;\n    PH_STRINGREF fullDllName;\n    PH_STRINGREF baseDllName;\n    PLIST_ENTRY listHead;\n    PLIST_ENTRY listEntry;\n\n    listHead = &NtCurrentPeb()->Ldr->InLoadOrderModuleList;\n    listEntry = listHead->Flink;\n\n    while (listEntry != listHead)\n    {\n        entry = CONTAINING_RECORD(listEntry, LDR_DATA_TABLE_ENTRY, InLoadOrderLinks);\n        PhUnicodeStringToStringRef(&entry->FullDllName, &fullDllName);\n        PhUnicodeStringToStringRef(&entry->BaseDllName, &baseDllName);\n\n        if (\n            (!DllBase || entry->DllBase == DllBase) &&\n            (!FullDllName || PhEqualStringRef(&fullDllName, FullDllName, TRUE)) &&\n            (!BaseDllName || PhEqualStringRef(&baseDllName, BaseDllName, TRUE))\n            )\n        {\n            result = entry;\n            break;\n        }\n\n        listEntry = listEntry->Flink;\n    }\n\n    return result;\n}\n\n/**\n * Retrieves the file name of a DLL loaded by the current process.\n *\n * \\param DllHandle The base address of the DLL.\n * \\param IndexOfFileName A variable which receives the index of the base name of the DLL in the\n * returned string.\n *\n * \\return The file name of the DLL, or NULL if the DLL could not be found.\n */\nPPH_STRING PhGetDllFileName(\n    _In_ PVOID DllHandle,\n    _Out_opt_ PULONG IndexOfFileName\n    )\n{\n    PLDR_DATA_TABLE_ENTRY entry;\n    PPH_STRING fileName;\n    PPH_STRING newFileName;\n    ULONG_PTR indexOfFileName;\n\n    RtlEnterCriticalSection(NtCurrentPeb()->LoaderLock);\n\n    entry = PhFindLoaderEntry(DllHandle, NULL, NULL);\n\n    if (entry)\n        fileName = PhCreateStringFromUnicodeString(&entry->FullDllName);\n    else\n        fileName = NULL;\n\n    RtlLeaveCriticalSection(NtCurrentPeb()->LoaderLock);\n\n    if (!fileName)\n        return NULL;\n\n    newFileName = PhGetFileName(fileName);\n    PhDereferenceObject(fileName);\n    fileName = newFileName;\n\n    if (IndexOfFileName)\n    {\n        indexOfFileName = PhFindLastCharInString(fileName, 0, '\\\\');\n\n        if (indexOfFileName != -1)\n            indexOfFileName++;\n        else\n            indexOfFileName = 0;\n\n        *IndexOfFileName = (ULONG)indexOfFileName;\n    }\n\n    return fileName;\n}\n\n/**\n * Retrieves the file name of the current process image.\n */\nPPH_STRING PhGetApplicationFileName(\n    VOID\n    )\n{\n    PPH_STRING fileName;\n\n    if (NT_SUCCESS(PhGetProcessImageFileNameWin32(NtCurrentProcess(), &fileName)))\n    {\n        PhMoveReference(&fileName, PhGetFileName(fileName));\n        return fileName;\n    }\n\n    return PhGetDllFileName(NtCurrentPeb()->ImageBaseAddress, NULL);\n}\n\n/**\n * Retrieves the directory of the current process image.\n */\nPPH_STRING PhGetApplicationDirectory(\n    VOID\n    )\n{\n    PPH_STRING fileName;\n    ULONG_PTR indexOfFileName;\n    PPH_STRING path = NULL;\n\n    fileName = PhGetApplicationFileName();\n\n    if (fileName)\n    {\n        indexOfFileName = PhFindLastCharInString(fileName, 0, '\\\\');\n\n        if (indexOfFileName != -1)\n            indexOfFileName++;\n        else\n            indexOfFileName = 0;\n\n        if (indexOfFileName != 0)\n        {\n            // Remove the file name from the path.\n            path = PhSubstring(fileName, 0, indexOfFileName);\n        }\n\n        PhDereferenceObject(fileName);\n    }\n\n    return path;\n}\n\n/**\n * Gets a known location as a file name.\n *\n * \\param Folder A CSIDL value representing the known location.\n * \\param AppendPath A string to append to the folder path.\n */\nPPH_STRING PhGetKnownLocation(\n    _In_ ULONG Folder,\n    _In_opt_ PWSTR AppendPath\n    )\n{\n    PPH_STRING path;\n    SIZE_T appendPathLength;\n\n    if (AppendPath)\n        appendPathLength = PhCountStringZ(AppendPath) * 2;\n    else\n        appendPathLength = 0;\n\n    path = PhCreateStringEx(NULL, MAX_PATH * 2 + appendPathLength);\n\n    if (SUCCEEDED(SHGetFolderPath(\n        NULL,\n        Folder,\n        NULL,\n        SHGFP_TYPE_CURRENT,\n        path->Buffer\n        )))\n    {\n        PhTrimToNullTerminatorString(path);\n\n        if (AppendPath)\n        {\n            memcpy(&path->Buffer[path->Length / 2], AppendPath, appendPathLength + 2); // +2 for null terminator\n            path->Length += appendPathLength;\n        }\n\n        return path;\n    }\n\n    PhDereferenceObject(path);\n\n    return NULL;\n}\n\n/**\n * Waits on multiple objects while processing window messages.\n *\n * \\param hWnd The window to process messages for, or NULL to process all messages for the current\n * thread.\n * \\param NumberOfHandles The number of handles specified in \\a Handles. This must not be greater\n * than MAXIMUM_WAIT_OBJECTS - 1.\n * \\param Handles An array of handles.\n * \\param Timeout The number of milliseconds to wait on the objects, or INFINITE for no timeout.\n *\n * \\remarks The wait is always in WaitAny mode.\n */\nNTSTATUS PhWaitForMultipleObjectsAndPump(\n    _In_opt_ HWND hWnd,\n    _In_ ULONG NumberOfHandles,\n    _In_ PHANDLE Handles,\n    _In_ ULONG Timeout\n    )\n{\n    NTSTATUS status;\n    ULONG64 startTickCount;\n    ULONG64 currentTickCount;\n    ULONG64 currentTimeout;\n\n    startTickCount = NtGetTickCount64();\n    currentTimeout = Timeout;\n\n    while (TRUE)\n    {\n        status = MsgWaitForMultipleObjects(\n            NumberOfHandles,\n            Handles,\n            FALSE,\n            (ULONG)currentTimeout,\n            QS_ALLEVENTS\n            );\n\n        if (status >= STATUS_WAIT_0 && status < (NTSTATUS)(STATUS_WAIT_0 + NumberOfHandles))\n        {\n            return status;\n        }\n        else if (status == (STATUS_WAIT_0 + NumberOfHandles))\n        {\n            MSG msg;\n\n            // Pump messages\n\n            while (PeekMessage(&msg, hWnd, 0, 0, PM_REMOVE))\n            {\n                TranslateMessage(&msg);\n                DispatchMessage(&msg);\n            }\n        }\n        else\n        {\n            return status;\n        }\n\n        // Recompute the timeout value.\n\n        if (Timeout != INFINITE)\n        {\n            currentTickCount = NtGetTickCount64();\n            currentTimeout = Timeout - (currentTickCount - startTickCount);\n\n            if ((LONG64)currentTimeout < 0)\n                return STATUS_TIMEOUT;\n        }\n    }\n}\n\n/**\n * Creates a native process and an initial thread.\n *\n * \\param FileName The Win32 file name of the image.\n * \\param CommandLine The command line string to pass to the process. This string cannot be used to\n * specify the image to execute.\n * \\param Environment The environment block for the process. Specify NULL to use the environment of\n * the current process.\n * \\param CurrentDirectory The current directory string to pass to the process.\n * \\param Information Additional parameters to pass to the process.\n * \\param Flags A combination of the following:\n * \\li \\c PH_CREATE_PROCESS_INHERIT_HANDLES Inheritable handles will be duplicated to the process\n * from the parent process.\n * \\li \\c PH_CREATE_PROCESS_SUSPENDED The initial thread will be created suspended.\n * \\li \\c PH_CREATE_PROCESS_BREAKAWAY_FROM_JOB The process will not be assigned to the job object\n * associated with the parent process.\n * \\li \\c PH_CREATE_PROCESS_NEW_CONSOLE The process will have its own console, instead of inheriting\n * the console of the parent process.\n * \\param ParentProcessHandle The process from which the new process will inherit attributes.\n * Specify NULL for the current process.\n * \\param ClientId A variable which recieves the identifier of the initial thread.\n * \\param ProcessHandle A variable which receives a handle to the process.\n * \\param ThreadHandle A variable which receives a handle to the initial thread.\n */\nNTSTATUS PhCreateProcess(\n    _In_ PWSTR FileName,\n    _In_opt_ PPH_STRINGREF CommandLine,\n    _In_opt_ PVOID Environment,\n    _In_opt_ PPH_STRINGREF CurrentDirectory,\n    _In_opt_ PPH_CREATE_PROCESS_INFO Information,\n    _In_ ULONG Flags,\n    _In_opt_ HANDLE ParentProcessHandle,\n    _Out_opt_ PCLIENT_ID ClientId,\n    _Out_opt_ PHANDLE ProcessHandle,\n    _Out_opt_ PHANDLE ThreadHandle\n    )\n{\n    NTSTATUS status;\n    RTL_USER_PROCESS_INFORMATION processInfo;\n    PRTL_USER_PROCESS_PARAMETERS parameters;\n    UNICODE_STRING fileName;\n    UNICODE_STRING commandLine;\n    UNICODE_STRING currentDirectory;\n    PUNICODE_STRING windowTitle;\n    PUNICODE_STRING desktopInfo;\n\n    if (!NT_SUCCESS(status = RtlDosPathNameToNtPathName_U_WithStatus(\n        FileName,\n        &fileName,\n        NULL,\n        NULL\n        )))\n        return status;\n\n    if (CommandLine)\n    {\n        if (!PhStringRefToUnicodeString(CommandLine, &commandLine))\n            return STATUS_NAME_TOO_LONG;\n    }\n\n    if (CurrentDirectory)\n    {\n        if (!PhStringRefToUnicodeString(CurrentDirectory, &currentDirectory))\n            return STATUS_NAME_TOO_LONG;\n    }\n\n    if (Information)\n    {\n        windowTitle = Information->WindowTitle;\n        desktopInfo = Information->DesktopInfo;\n    }\n    else\n    {\n        windowTitle = NULL;\n        desktopInfo = NULL;\n    }\n\n    if (!windowTitle)\n        windowTitle = &fileName;\n\n    if (!desktopInfo)\n        desktopInfo = &NtCurrentPeb()->ProcessParameters->DesktopInfo;\n\n    status = RtlCreateProcessParameters(\n        &parameters,\n        &fileName,\n        Information ? Information->DllPath : NULL,\n        CurrentDirectory ? &currentDirectory : NULL,\n        CommandLine ? &commandLine : &fileName,\n        Environment,\n        windowTitle,\n        desktopInfo,\n        Information ? Information->ShellInfo : NULL,\n        Information ? Information->RuntimeData : NULL\n        );\n\n    if (NT_SUCCESS(status))\n    {\n        status = RtlCreateUserProcess(\n            &fileName,\n            OBJ_CASE_INSENSITIVE,\n            parameters,\n            NULL,\n            NULL,\n            ParentProcessHandle,\n            !!(Flags & PH_CREATE_PROCESS_INHERIT_HANDLES),\n            NULL,\n            NULL,\n            &processInfo\n            );\n        RtlDestroyProcessParameters(parameters);\n    }\n\n    RtlFreeUnicodeString(&fileName);\n\n    if (NT_SUCCESS(status))\n    {\n        if (!(Flags & PH_CREATE_PROCESS_SUSPENDED))\n            NtResumeThread(processInfo.Thread, NULL);\n\n        if (ClientId)\n            *ClientId = processInfo.ClientId;\n\n        if (ProcessHandle)\n            *ProcessHandle = processInfo.Process;\n        else\n            NtClose(processInfo.Process);\n\n        if (ThreadHandle)\n            *ThreadHandle = processInfo.Thread;\n        else\n            NtClose(processInfo.Thread);\n    }\n\n    return status;\n}\n\n/**\n * Creates a Win32 process and an initial thread.\n *\n * \\param FileName The Win32 file name of the image.\n * \\param CommandLine The command line to execute. This can be specified instead of \\a FileName to\n * indicate the image to execute.\n * \\param Environment The environment block for the process. Specify NULL to use the environment of\n * the current process.\n * \\param CurrentDirectory The current directory string to pass to the process.\n * \\param Flags See PhCreateProcess().\n * \\param TokenHandle The token of the process. Specify NULL for the token of the parent process.\n * \\param ProcessHandle A variable which receives a handle to the process.\n * \\param ThreadHandle A variable which receives a handle to the initial thread.\n */\nNTSTATUS PhCreateProcessWin32(\n    _In_opt_ PWSTR FileName,\n    _In_opt_ PWSTR CommandLine,\n    _In_opt_ PVOID Environment,\n    _In_opt_ PWSTR CurrentDirectory,\n    _In_ ULONG Flags,\n    _In_opt_ HANDLE TokenHandle,\n    _Out_opt_ PHANDLE ProcessHandle,\n    _Out_opt_ PHANDLE ThreadHandle\n    )\n{\n    return PhCreateProcessWin32Ex(\n        FileName,\n        CommandLine,\n        Environment,\n        CurrentDirectory,\n        NULL,\n        Flags,\n        TokenHandle,\n        NULL,\n        ProcessHandle,\n        ThreadHandle\n        );\n}\n\nstatic const PH_FLAG_MAPPING PhpCreateProcessMappings[] =\n{\n    { PH_CREATE_PROCESS_UNICODE_ENVIRONMENT, CREATE_UNICODE_ENVIRONMENT },\n    { PH_CREATE_PROCESS_SUSPENDED, CREATE_SUSPENDED },\n    { PH_CREATE_PROCESS_BREAKAWAY_FROM_JOB, CREATE_BREAKAWAY_FROM_JOB },\n    { PH_CREATE_PROCESS_NEW_CONSOLE, CREATE_NEW_CONSOLE }\n};\n\nFORCEINLINE VOID PhpConvertProcessInformation(\n    _In_ PPROCESS_INFORMATION ProcessInfo,\n    _Out_opt_ PCLIENT_ID ClientId,\n    _Out_opt_ PHANDLE ProcessHandle,\n    _Out_opt_ PHANDLE ThreadHandle\n    )\n{\n    if (ClientId)\n    {\n        ClientId->UniqueProcess = UlongToHandle(ProcessInfo->dwProcessId);\n        ClientId->UniqueThread = UlongToHandle(ProcessInfo->dwThreadId);\n    }\n\n    if (ProcessHandle)\n        *ProcessHandle = ProcessInfo->hProcess;\n    else if (ProcessInfo->hProcess)\n        NtClose(ProcessInfo->hProcess);\n\n    if (ThreadHandle)\n        *ThreadHandle = ProcessInfo->hThread;\n    else if (ProcessInfo->hThread)\n        NtClose(ProcessInfo->hThread);\n}\n\n/**\n * Creates a Win32 process and an initial thread.\n *\n * \\param FileName The Win32 file name of the image.\n * \\param CommandLine The command line to execute. This can be specified instead of \\a FileName to\n * indicate the image to execute.\n * \\param Environment The environment block for the process. Specify NULL to use the environment of\n * the current process.\n * \\param CurrentDirectory The current directory string to pass to the process.\n * \\param StartupInfo A STARTUPINFO structure containing additional parameters for the process.\n * \\param Flags See PhCreateProcess().\n * \\param TokenHandle The token of the process. Specify NULL for the token of the parent process.\n * \\param ClientId A variable which recieves the identifier of the initial thread.\n * \\param ProcessHandle A variable which receives a handle to the process.\n * \\param ThreadHandle A variable which receives a handle to the initial thread.\n */\nNTSTATUS PhCreateProcessWin32Ex(\n    _In_opt_ PWSTR FileName,\n    _In_opt_ PWSTR CommandLine,\n    _In_opt_ PVOID Environment,\n    _In_opt_ PWSTR CurrentDirectory,\n    _In_opt_ STARTUPINFO *StartupInfo,\n    _In_ ULONG Flags,\n    _In_opt_ HANDLE TokenHandle,\n    _Out_opt_ PCLIENT_ID ClientId,\n    _Out_opt_ PHANDLE ProcessHandle,\n    _Out_opt_ PHANDLE ThreadHandle\n    )\n{\n    NTSTATUS status;\n    PPH_STRING fileName = NULL;\n    PPH_STRING commandLine = NULL;\n    STARTUPINFO startupInfo;\n    PROCESS_INFORMATION processInfo;\n    ULONG newFlags;\n\n    if (CommandLine) // duplicate because CreateProcess modifies the string\n        commandLine = PhCreateString(CommandLine);\n\n    if (FileName)\n        fileName = PhCreateString(FileName);\n    else\n    {\n        INT cmdlineArgCount;\n        PWSTR* cmdlineArgList;\n\n        // (dmex) Try extract the filename or CreateProcess might execute the wrong executable.\n        if (commandLine && (cmdlineArgList = CommandLineToArgvW(commandLine->Buffer, &cmdlineArgCount)))\n        {\n            PhMoveReference(&fileName, PhCreateString(cmdlineArgList[0]));\n            LocalFree(cmdlineArgList);\n        }\n\n        if (fileName && !RtlDoesFileExists_U(fileName->Buffer))\n        {\n            WCHAR buffer[MAX_PATH];\n\n            // The user typed a name without a path so attempt to locate the executable.\n            if (PhSearchFilePath(fileName->Buffer, L\".exe\", buffer))\n                PhMoveReference(&fileName, PhCreateString(buffer));\n            else\n                PhClearReference(&fileName);\n        }\n    }\n\n    newFlags = 0;\n    PhMapFlags1(&newFlags, Flags, PhpCreateProcessMappings, sizeof(PhpCreateProcessMappings) / sizeof(PH_FLAG_MAPPING));\n\n    if (StartupInfo)\n    {\n        startupInfo = *StartupInfo;\n    }\n    else\n    {\n        memset(&startupInfo, 0, sizeof(STARTUPINFO));\n        startupInfo.cb = sizeof(STARTUPINFO);\n    }\n\n    if (!TokenHandle)\n    {\n        if (CreateProcess(\n            PhGetString(fileName),\n            PhGetString(commandLine),\n            NULL,\n            NULL,\n            !!(Flags & PH_CREATE_PROCESS_INHERIT_HANDLES),\n            newFlags,\n            Environment,\n            CurrentDirectory,\n            &startupInfo,\n            &processInfo\n            ))\n            status = STATUS_SUCCESS;\n        else\n            status = PhGetLastWin32ErrorAsNtStatus();\n    }\n    else\n    {\n        if (CreateProcessAsUser(\n            TokenHandle,\n            PhGetString(fileName),\n            PhGetString(commandLine),\n            NULL,\n            NULL,\n            !!(Flags & PH_CREATE_PROCESS_INHERIT_HANDLES),\n            newFlags,\n            Environment,\n            CurrentDirectory,\n            &startupInfo,\n            &processInfo\n            ))\n            status = STATUS_SUCCESS;\n        else\n            status = PhGetLastWin32ErrorAsNtStatus();\n    }\n\n    if (fileName)\n        PhDereferenceObject(fileName);\n    if (commandLine)\n        PhDereferenceObject(commandLine);\n\n    if (NT_SUCCESS(status))\n    {\n        PhpConvertProcessInformation(&processInfo, ClientId, ProcessHandle, ThreadHandle);\n    }\n\n    return status;\n}\n\n/**\n * Creates a Win32 process and an initial thread under the specified user.\n *\n * \\param Information Parameters specifying how to create the process.\n * \\param Flags See PhCreateProcess(). Additional flags may be used:\n * \\li \\c PH_CREATE_PROCESS_USE_PROCESS_TOKEN Use the token of the process specified by\n * \\a ProcessIdWithToken in \\a Information.\n * \\li \\c PH_CREATE_PROCESS_USE_SESSION_TOKEN Use the token of the session specified by\n * \\a SessionIdWithToken in \\a Information.\n * \\li \\c PH_CREATE_PROCESS_USE_LINKED_TOKEN Use the linked token to create the process; this causes\n * the process to be elevated or unelevated depending on the specified options.\n * \\li \\c PH_CREATE_PROCESS_SET_SESSION_ID \\a SessionId is specified in \\a Information.\n * \\li \\c PH_CREATE_PROCESS_WITH_PROFILE Load the user profile, if supported.\n * \\param ClientId A variable which recieves the identifier of the initial thread.\n * \\param ProcessHandle A variable which receives a handle to the process.\n * \\param ThreadHandle A variable which receives a handle to the initial thread.\n */\nNTSTATUS PhCreateProcessAsUser(\n    _In_ PPH_CREATE_PROCESS_AS_USER_INFO Information,\n    _In_ ULONG Flags,\n    _Out_opt_ PCLIENT_ID ClientId,\n    _Out_opt_ PHANDLE ProcessHandle,\n    _Out_opt_ PHANDLE ThreadHandle\n    )\n{\n    static PH_INITONCE initOnce = PH_INITONCE_INIT;\n    static _WinStationQueryInformationW WinStationQueryInformationW_I = NULL;\n    static _CreateEnvironmentBlock CreateEnvironmentBlock_I = NULL;\n    static _DestroyEnvironmentBlock DestroyEnvironmentBlock_I = NULL;\n\n    NTSTATUS status;\n    HANDLE tokenHandle;\n    PVOID defaultEnvironment = NULL;\n    STARTUPINFO startupInfo = { sizeof(startupInfo) };\n    BOOLEAN needsDuplicate = FALSE;\n\n    if (PhBeginInitOnce(&initOnce))\n    {\n        HMODULE winsta;\n        HMODULE userEnv;\n\n        winsta = LoadLibrary(L\"winsta.dll\");\n        WinStationQueryInformationW_I = PhGetProcedureAddress(winsta, \"WinStationQueryInformationW\", 0);\n\n        userEnv = LoadLibrary(L\"userenv.dll\");\n        CreateEnvironmentBlock_I = PhGetProcedureAddress(userEnv, \"CreateEnvironmentBlock\", 0);\n        DestroyEnvironmentBlock_I = PhGetProcedureAddress(userEnv, \"DestroyEnvironmentBlock\", 0);\n\n        PhEndInitOnce(&initOnce);\n    }\n\n    if ((Flags & PH_CREATE_PROCESS_USE_PROCESS_TOKEN) && (Flags & PH_CREATE_PROCESS_USE_SESSION_TOKEN))\n        return STATUS_INVALID_PARAMETER_2;\n    if (!Information->ApplicationName && !Information->CommandLine)\n        return STATUS_INVALID_PARAMETER_MIX;\n\n    startupInfo.lpDesktop = Information->DesktopName;\n\n    // Try to use CreateProcessWithLogonW if we need to load the user profile.\n    // This isn't compatible with some options.\n    if (Flags & PH_CREATE_PROCESS_WITH_PROFILE)\n    {\n        BOOLEAN useWithLogon;\n\n        useWithLogon = TRUE;\n\n        if (Flags & (PH_CREATE_PROCESS_USE_PROCESS_TOKEN | PH_CREATE_PROCESS_USE_SESSION_TOKEN))\n            useWithLogon = FALSE;\n\n        if (Flags & PH_CREATE_PROCESS_USE_LINKED_TOKEN)\n            useWithLogon = FALSE;\n\n        if (Flags & PH_CREATE_PROCESS_SET_SESSION_ID)\n        {\n            if (Information->SessionId != NtCurrentPeb()->SessionId)\n                useWithLogon = FALSE;\n        }\n\n        if (Information->LogonType && Information->LogonType != LOGON32_LOGON_INTERACTIVE)\n            useWithLogon = FALSE;\n\n        if (useWithLogon)\n        {\n            PPH_STRING commandLine;\n            PROCESS_INFORMATION processInfo;\n            ULONG newFlags;\n\n            if (Information->CommandLine) // duplicate because CreateProcess modifies the string\n                commandLine = PhCreateString(Information->CommandLine);\n            else\n                commandLine = NULL;\n\n            if (!Information->Environment)\n                Flags |= PH_CREATE_PROCESS_UNICODE_ENVIRONMENT;\n\n            newFlags = 0;\n            PhMapFlags1(&newFlags, Flags, PhpCreateProcessMappings, sizeof(PhpCreateProcessMappings) / sizeof(PH_FLAG_MAPPING));\n\n            if (CreateProcessWithLogonW(\n                Information->UserName,\n                Information->DomainName,\n                Information->Password,\n                LOGON_WITH_PROFILE,\n                Information->ApplicationName,\n                PhGetString(commandLine),\n                newFlags,\n                Information->Environment,\n                Information->CurrentDirectory,\n                &startupInfo,\n                &processInfo\n                ))\n                status = STATUS_SUCCESS;\n            else\n                status = PhGetLastWin32ErrorAsNtStatus();\n\n            if (commandLine)\n                PhDereferenceObject(commandLine);\n\n            if (NT_SUCCESS(status))\n            {\n                PhpConvertProcessInformation(&processInfo, ClientId, ProcessHandle, ThreadHandle);\n            }\n\n            return status;\n        }\n    }\n\n    // Get the token handle. Various methods are supported.\n\n    if (Flags & PH_CREATE_PROCESS_USE_PROCESS_TOKEN)\n    {\n        HANDLE processHandle;\n\n        if (!NT_SUCCESS(status = PhOpenProcess(\n            &processHandle,\n            ProcessQueryAccess,\n            Information->ProcessIdWithToken\n            )))\n            return status;\n\n        status = PhOpenProcessToken(\n            processHandle,\n            TOKEN_ALL_ACCESS,\n            &tokenHandle\n            );\n        NtClose(processHandle);\n\n        if (!NT_SUCCESS(status))\n            return status;\n\n        if (Flags & PH_CREATE_PROCESS_SET_SESSION_ID)\n            needsDuplicate = TRUE; // can't set the session ID of a token in use by a process\n    }\n    else if (Flags & PH_CREATE_PROCESS_USE_SESSION_TOKEN)\n    {\n        WINSTATIONUSERTOKEN userToken;\n        ULONG returnLength;\n\n        if (!WinStationQueryInformationW_I)\n            return STATUS_PROCEDURE_NOT_FOUND;\n\n        if (!WinStationQueryInformationW_I(\n            NULL,\n            Information->SessionIdWithToken,\n            WinStationUserToken,\n            &userToken,\n            sizeof(WINSTATIONUSERTOKEN),\n            &returnLength\n            ))\n        {\n            return PhGetLastWin32ErrorAsNtStatus();\n        }\n\n        tokenHandle = userToken.UserToken;\n\n        if (Flags & PH_CREATE_PROCESS_SET_SESSION_ID)\n            needsDuplicate = TRUE; // not sure if this is necessary\n    }\n    else\n    {\n        ULONG logonType;\n\n        if (Information->LogonType)\n        {\n            logonType = Information->LogonType;\n        }\n        else\n        {\n            logonType = LOGON32_LOGON_INTERACTIVE;\n\n            // Check if this is a service logon.\n            if (PhEqualStringZ(Information->DomainName, L\"NT AUTHORITY\", TRUE))\n            {\n                if (PhEqualStringZ(Information->UserName, L\"SYSTEM\", TRUE) ||\n                    PhEqualStringZ(Information->UserName, L\"LOCAL SERVICE\", TRUE) ||\n                    PhEqualStringZ(Information->UserName, L\"NETWORK SERVICE\", TRUE))\n                {\n                    logonType = LOGON32_LOGON_SERVICE;\n                }\n            }\n        }\n\n        if (!LogonUser(\n            Information->UserName,\n            Information->DomainName,\n            Information->Password,\n            logonType,\n            LOGON32_PROVIDER_DEFAULT,\n            &tokenHandle\n            ))\n            return PhGetLastWin32ErrorAsNtStatus();\n    }\n\n    if (Flags & PH_CREATE_PROCESS_USE_LINKED_TOKEN)\n    {\n        HANDLE linkedTokenHandle;\n        TOKEN_TYPE tokenType;\n        ULONG returnLength;\n\n        // NtQueryInformationToken normally returns an impersonation token with\n        // SecurityIdentification, but if the process is running with SeTcbPrivilege, it returns a\n        // primary token. We can never duplicate a SecurityIdentification impersonation token to\n        // make it a primary token, so we just check if the token is primary before using it.\n\n        if (NT_SUCCESS(PhGetTokenLinkedToken(tokenHandle, &linkedTokenHandle)))\n        {\n            if (NT_SUCCESS(NtQueryInformationToken(\n                linkedTokenHandle,\n                TokenType,\n                &tokenType,\n                sizeof(TOKEN_TYPE),\n                &returnLength\n                )) && tokenType == TokenPrimary)\n            {\n                NtClose(tokenHandle);\n                tokenHandle = linkedTokenHandle;\n                needsDuplicate = FALSE; // the linked token that is returned is always a copy, so no need to duplicate\n            }\n            else\n            {\n                NtClose(linkedTokenHandle);\n            }\n        }\n    }\n\n    if (needsDuplicate)\n    {\n        HANDLE newTokenHandle;\n        OBJECT_ATTRIBUTES objectAttributes;\n\n        InitializeObjectAttributes(\n            &objectAttributes,\n            NULL,\n            0,\n            NULL,\n            NULL\n            );\n\n        status = NtDuplicateToken(\n            tokenHandle,\n            TOKEN_ALL_ACCESS,\n            &objectAttributes,\n            FALSE,\n            TokenPrimary,\n            &newTokenHandle\n            );\n        NtClose(tokenHandle);\n\n        if (!NT_SUCCESS(status))\n            return status;\n\n        tokenHandle = newTokenHandle;\n    }\n\n    // Set the session ID if needed.\n\n    if (Flags & PH_CREATE_PROCESS_SET_SESSION_ID)\n    {\n        if (!NT_SUCCESS(status = PhSetTokenSessionId(\n            tokenHandle,\n            Information->SessionId\n            )))\n        {\n            NtClose(tokenHandle);\n            return status;\n        }\n    }\n\n    if (!Information->Environment)\n    {\n        if (CreateEnvironmentBlock_I)\n        {\n            CreateEnvironmentBlock_I(&defaultEnvironment, tokenHandle, FALSE);\n\n            if (defaultEnvironment)\n                Flags |= PH_CREATE_PROCESS_UNICODE_ENVIRONMENT;\n        }\n    }\n\n    status = PhCreateProcessWin32Ex(\n        Information->ApplicationName,\n        Information->CommandLine,\n        Information->Environment ? Information->Environment : defaultEnvironment,\n        Information->CurrentDirectory,\n        &startupInfo,\n        Flags,\n        tokenHandle,\n        ClientId,\n        ProcessHandle,\n        ThreadHandle\n        );\n\n    if (defaultEnvironment)\n    {\n        if (DestroyEnvironmentBlock_I)\n            DestroyEnvironmentBlock_I(defaultEnvironment);\n    }\n\n    NtClose(tokenHandle);\n\n    return status;\n}\n\nNTSTATUS PhpGetAccountPrivileges(\n    _In_ PSID AccountSid,\n    _Out_ PTOKEN_PRIVILEGES *Privileges\n    )\n{\n    NTSTATUS status;\n    LSA_HANDLE accountHandle;\n    PPRIVILEGE_SET accountPrivileges;\n    PTOKEN_PRIVILEGES privileges;\n\n    status = LsaOpenAccount(PhGetLookupPolicyHandle(), AccountSid, ACCOUNT_VIEW, &accountHandle);\n\n    if (!NT_SUCCESS(status))\n        return status;\n\n    status = LsaEnumeratePrivilegesOfAccount(accountHandle, &accountPrivileges);\n    LsaClose(accountHandle);\n\n    if (!NT_SUCCESS(status))\n        return status;\n\n    privileges = PhAllocate(FIELD_OFFSET(TOKEN_PRIVILEGES, Privileges) + sizeof(LUID_AND_ATTRIBUTES) * accountPrivileges->PrivilegeCount);\n    privileges->PrivilegeCount = accountPrivileges->PrivilegeCount;\n    memcpy(privileges->Privileges, accountPrivileges->Privilege, sizeof(LUID_AND_ATTRIBUTES) * accountPrivileges->PrivilegeCount);\n\n    LsaFreeMemory(accountPrivileges);\n\n    *Privileges = privileges;\n\n    return status;\n}\n\n/**\n * Filters a token to create a limited user security context.\n *\n * \\param TokenHandle A handle to an existing token. The handle must have TOKEN_DUPLICATE,\n * TOKEN_QUERY, TOKEN_ADJUST_GROUPS, TOKEN_ADJUST_DEFAULT, READ_CONTROL and WRITE_DAC access.\n * \\param NewTokenHandle A variable which receives a handle to the filtered token. The handle will\n * have the same granted access as \\a TokenHandle.\n */\nNTSTATUS PhFilterTokenForLimitedUser(\n    _In_ HANDLE TokenHandle,\n    _Out_ PHANDLE NewTokenHandle\n    )\n{\n    static SID_IDENTIFIER_AUTHORITY ntAuthority = SECURITY_NT_AUTHORITY;\n    static SID_IDENTIFIER_AUTHORITY mandatoryLabelAuthority = SECURITY_MANDATORY_LABEL_AUTHORITY;\n    static LUID_AND_ATTRIBUTES defaultAllowedPrivileges[] =\n    {\n        { { SE_SHUTDOWN_PRIVILEGE, 0 }, 0 },\n        { { SE_CHANGE_NOTIFY_PRIVILEGE, 0 }, 0 },\n        { { SE_UNDOCK_PRIVILEGE, 0 }, 0 },\n        { { SE_INC_WORKING_SET_PRIVILEGE, 0 }, 0 },\n        { { SE_TIME_ZONE_PRIVILEGE, 0 }, 0 }\n    };\n\n    NTSTATUS status;\n    UCHAR administratorsSidBuffer[FIELD_OFFSET(SID, SubAuthority) + sizeof(ULONG) * 2];\n    PSID administratorsSid;\n    UCHAR usersSidBuffer[FIELD_OFFSET(SID, SubAuthority) + sizeof(ULONG) * 2];\n    PSID usersSid;\n    UCHAR sidsToDisableBuffer[FIELD_OFFSET(TOKEN_GROUPS, Groups) + sizeof(SID_AND_ATTRIBUTES)];\n    PTOKEN_GROUPS sidsToDisable;\n    ULONG i;\n    ULONG j;\n    ULONG deleteIndex;\n    BOOLEAN found;\n    PTOKEN_PRIVILEGES privilegesOfToken;\n    PTOKEN_PRIVILEGES privilegesOfUsers;\n    PTOKEN_PRIVILEGES privilegesToDelete;\n    UCHAR lowMandatoryLevelSidBuffer[FIELD_OFFSET(SID, SubAuthority) + sizeof(ULONG)];\n    PSID lowMandatoryLevelSid;\n    TOKEN_MANDATORY_LABEL mandatoryLabel;\n    PSECURITY_DESCRIPTOR currentSecurityDescriptor;\n    BOOLEAN currentDaclPresent;\n    BOOLEAN currentDaclDefaulted;\n    PACL currentDacl;\n    PTOKEN_USER currentUser;\n    PACE_HEADER currentAce;\n    ULONG newDaclLength;\n    PACL newDacl;\n    SECURITY_DESCRIPTOR newSecurityDescriptor;\n    TOKEN_DEFAULT_DACL newDefaultDacl;\n    HANDLE newTokenHandle;\n\n    // Set up the SIDs to Disable structure.\n\n    // Initialize the Administrators SID.\n    administratorsSid = (PSID)administratorsSidBuffer;\n    RtlInitializeSid(administratorsSid, &ntAuthority, 2);\n    *RtlSubAuthoritySid(administratorsSid, 0) = SECURITY_BUILTIN_DOMAIN_RID;\n    *RtlSubAuthoritySid(administratorsSid, 1) = DOMAIN_ALIAS_RID_ADMINS;\n\n    // Initialize the Users SID.\n    usersSid = (PSID)usersSidBuffer;\n    RtlInitializeSid(usersSid, &ntAuthority, 2);\n    *RtlSubAuthoritySid(usersSid, 0) = SECURITY_BUILTIN_DOMAIN_RID;\n    *RtlSubAuthoritySid(usersSid, 1) = DOMAIN_ALIAS_RID_USERS;\n\n    sidsToDisable = (PTOKEN_GROUPS)sidsToDisableBuffer;\n    sidsToDisable->GroupCount = 1;\n    sidsToDisable->Groups[0].Sid = administratorsSid;\n    sidsToDisable->Groups[0].Attributes = 0;\n\n    // Set up the Privileges to Delete structure.\n\n    // Get the privileges that the input token contains.\n    if (!NT_SUCCESS(status = PhGetTokenPrivileges(TokenHandle, &privilegesOfToken)))\n        return status;\n\n    // Get the privileges of the Users group - the privileges that we are going to allow.\n    if (!NT_SUCCESS(PhpGetAccountPrivileges(usersSid, &privilegesOfUsers)))\n    {\n        // Unsuccessful, so use the default set of privileges.\n        privilegesOfUsers = PhAllocate(FIELD_OFFSET(TOKEN_PRIVILEGES, Privileges) + sizeof(defaultAllowedPrivileges));\n        privilegesOfUsers->PrivilegeCount = sizeof(defaultAllowedPrivileges) / sizeof(LUID_AND_ATTRIBUTES);\n        memcpy(privilegesOfUsers->Privileges, defaultAllowedPrivileges, sizeof(defaultAllowedPrivileges));\n    }\n\n    // Allocate storage for the privileges we need to delete. The worst case scenario is that all\n    // privileges in the token need to be deleted.\n    privilegesToDelete = PhAllocate(FIELD_OFFSET(TOKEN_PRIVILEGES, Privileges) + sizeof(LUID_AND_ATTRIBUTES) * privilegesOfToken->PrivilegeCount);\n    deleteIndex = 0;\n\n    // Compute the privileges that we need to delete.\n    for (i = 0; i < privilegesOfToken->PrivilegeCount; i++)\n    {\n        found = FALSE;\n\n        // Is the privilege allowed?\n        for (j = 0; j < privilegesOfUsers->PrivilegeCount; j++)\n        {\n            if (RtlIsEqualLuid(&privilegesOfToken->Privileges[i].Luid, &privilegesOfUsers->Privileges[j].Luid))\n            {\n                found = TRUE;\n                break;\n            }\n        }\n\n        if (!found)\n        {\n            // This privilege needs to be deleted.\n            privilegesToDelete->Privileges[deleteIndex].Attributes = 0;\n            privilegesToDelete->Privileges[deleteIndex].Luid = privilegesOfToken->Privileges[i].Luid;\n            deleteIndex++;\n        }\n    }\n\n    privilegesToDelete->PrivilegeCount = deleteIndex;\n\n    // Filter the token.\n\n    status = NtFilterToken(\n        TokenHandle,\n        0,\n        sidsToDisable,\n        privilegesToDelete,\n        NULL,\n        &newTokenHandle\n        );\n    PhFree(privilegesToDelete);\n    PhFree(privilegesOfUsers);\n    PhFree(privilegesOfToken);\n\n    if (!NT_SUCCESS(status))\n        return status;\n\n    // Set the integrity level to Low if we're on Vista and above.\n    {\n        lowMandatoryLevelSid = (PSID)lowMandatoryLevelSidBuffer;\n        RtlInitializeSid(lowMandatoryLevelSid, &mandatoryLabelAuthority, 1);\n        *RtlSubAuthoritySid(lowMandatoryLevelSid, 0) = SECURITY_MANDATORY_LOW_RID;\n\n        mandatoryLabel.Label.Sid = lowMandatoryLevelSid;\n        mandatoryLabel.Label.Attributes = SE_GROUP_INTEGRITY;\n\n        NtSetInformationToken(newTokenHandle, TokenIntegrityLevel, &mandatoryLabel, sizeof(TOKEN_MANDATORY_LABEL));\n    }\n\n    // Fix up the security descriptor and default DACL.\n    if (NT_SUCCESS(PhGetObjectSecurity(newTokenHandle, DACL_SECURITY_INFORMATION, &currentSecurityDescriptor)))\n    {\n        if (NT_SUCCESS(PhGetTokenUser(TokenHandle, &currentUser)))\n        {\n            if (!NT_SUCCESS(RtlGetDaclSecurityDescriptor(\n                currentSecurityDescriptor,\n                &currentDaclPresent,\n                &currentDacl,\n                &currentDaclDefaulted\n                )))\n            {\n                currentDaclPresent = FALSE;\n            }\n\n            newDaclLength = sizeof(ACL) + FIELD_OFFSET(ACCESS_ALLOWED_ACE, SidStart) + RtlLengthSid(currentUser->User.Sid);\n\n            if (currentDaclPresent)\n                newDaclLength += currentDacl->AclSize - sizeof(ACL);\n\n            newDacl = PhAllocate(newDaclLength);\n            RtlCreateAcl(newDacl, newDaclLength, ACL_REVISION);\n\n            // Add the existing DACL entries.\n            if (currentDaclPresent)\n            {\n                for (i = 0; i < currentDacl->AceCount; i++)\n                {\n                    if (NT_SUCCESS(RtlGetAce(currentDacl, i, &currentAce)))\n                        RtlAddAce(newDacl, ACL_REVISION, MAXULONG32, currentAce, currentAce->AceSize);\n                }\n            }\n\n            // Allow access for the current user.\n            RtlAddAccessAllowedAce(newDacl, ACL_REVISION, GENERIC_ALL, currentUser->User.Sid);\n\n            // Set the security descriptor of the new token.\n\n            RtlCreateSecurityDescriptor(&newSecurityDescriptor, SECURITY_DESCRIPTOR_REVISION);\n\n            if (NT_SUCCESS(RtlSetDaclSecurityDescriptor(&newSecurityDescriptor, TRUE, newDacl, FALSE)))\n                PhSetObjectSecurity(newTokenHandle, DACL_SECURITY_INFORMATION, &newSecurityDescriptor);\n\n            // Set the default DACL.\n\n            newDefaultDacl.DefaultDacl = newDacl;\n            NtSetInformationToken(newTokenHandle, TokenDefaultDacl, &newDefaultDacl, sizeof(TOKEN_DEFAULT_DACL));\n\n            PhFree(newDacl);\n\n            PhFree(currentUser);\n        }\n\n        PhFree(currentSecurityDescriptor);\n    }\n\n    *NewTokenHandle = newTokenHandle;\n\n    return STATUS_SUCCESS;\n}\n\n/**\n * Opens a file or location through the shell.\n *\n * \\param hWnd The window to display user interface components on.\n * \\param FileName A file name or location.\n * \\param Parameters The parameters to pass to the executed application.\n */\nVOID PhShellExecute(\n    _In_ HWND hWnd,\n    _In_ PWSTR FileName,\n    _In_opt_ PWSTR Parameters\n    )\n{\n    SHELLEXECUTEINFO info = { sizeof(info) };\n\n    info.lpFile = FileName;\n    info.lpParameters = Parameters;\n    info.fMask = SEE_MASK_FLAG_NO_UI;\n    info.nShow = SW_SHOW;\n    info.hwnd = hWnd;\n\n    if (!ShellExecuteEx(&info))\n    {\n        PhShowStatus(hWnd, L\"Unable to execute the program.\", 0, GetLastError());\n    }\n}\n\n/**\n * Opens a file or location through the shell.\n *\n * \\param hWnd The window to display user interface components on.\n * \\param FileName A file name or location.\n * \\param Parameters The parameters to pass to the executed application.\n * \\param ShowWindowType A value specifying how to show the application.\n * \\param Flags A combination of the following:\n * \\li \\c PH_SHELL_EXECUTE_ADMIN Execute the application elevated.\n * \\li \\c PH_SHELL_EXECUTE_PUMP_MESSAGES Waits on the application while pumping messages, if\n * \\a Timeout is specified.\n * \\param Timeout The number of milliseconds to wait on the application, or 0 to return immediately\n * after the application is started.\n * \\param ProcessHandle A variable which receives a handle to the new process.\n */\nBOOLEAN PhShellExecuteEx(\n    _In_opt_ HWND hWnd,\n    _In_ PWSTR FileName,\n    _In_opt_ PWSTR Parameters,\n    _In_ ULONG ShowWindowType,\n    _In_ ULONG Flags,\n    _In_opt_ ULONG Timeout,\n    _Out_opt_ PHANDLE ProcessHandle\n    )\n{\n    SHELLEXECUTEINFO info = { sizeof(info) };\n\n    info.lpFile = FileName;\n    info.lpParameters = Parameters;\n    info.fMask = SEE_MASK_NOCLOSEPROCESS | SEE_MASK_FLAG_NO_UI;\n    info.nShow = ShowWindowType;\n    info.hwnd = hWnd;\n\n    if (Flags & PH_SHELL_EXECUTE_ADMIN)\n        info.lpVerb = L\"runas\";\n\n    if (ShellExecuteEx(&info))\n    {\n        if (Timeout)\n        {\n            if (!(Flags & PH_SHELL_EXECUTE_PUMP_MESSAGES))\n            {\n                LARGE_INTEGER timeout;\n\n                NtWaitForSingleObject(info.hProcess, FALSE, PhTimeoutFromMilliseconds(&timeout, Timeout));\n            }\n            else\n            {\n                PhWaitForMultipleObjectsAndPump(NULL, 1, &info.hProcess, Timeout);\n            }\n        }\n\n        if (ProcessHandle)\n            *ProcessHandle = info.hProcess;\n        else\n            NtClose(info.hProcess);\n\n        return TRUE;\n    }\n    else\n    {\n        return FALSE;\n    }\n}\n\n/**\n * Opens Windows Explorer with a file selected.\n *\n * \\param hWnd A handle to the parent window.\n * \\param FileName A file name.\n */\nVOID PhShellExploreFile(\n    _In_ HWND hWnd,\n    _In_ PWSTR FileName\n    )\n{\n    if (SHOpenFolderAndSelectItems_Import() && SHParseDisplayName_Import())\n    {\n        LPITEMIDLIST item;\n        SFGAOF attributes;\n\n        if (SUCCEEDED(SHParseDisplayName_Import()(FileName, NULL, &item, 0, &attributes)))\n        {\n            SHOpenFolderAndSelectItems_Import()(item, 0, NULL, 0);\n            CoTaskMemFree(item);\n        }\n        else\n        {\n            PhShowError(hWnd, L\"The location \\\"%s\\\" could not be found.\", FileName);\n        }\n    }\n    else\n    {\n        PPH_STRING selectFileName;\n\n        selectFileName = PhConcatStrings2(L\"/select,\", FileName);\n        PhShellExecute(hWnd, L\"explorer.exe\", selectFileName->Buffer);\n        PhDereferenceObject(selectFileName);\n    }\n}\n\n/**\n * Shows properties for a file.\n *\n * \\param hWnd A handle to the parent window.\n * \\param FileName A file name.\n */\nVOID PhShellProperties(\n    _In_ HWND hWnd,\n    _In_ PWSTR FileName\n    )\n{\n    SHELLEXECUTEINFO info = { sizeof(info) };\n\n    info.lpFile = FileName;\n    info.nShow = SW_SHOW;\n    info.fMask = SEE_MASK_INVOKEIDLIST | SEE_MASK_FLAG_NO_UI;\n    info.lpVerb = L\"properties\";\n    info.hwnd = hWnd;\n\n    if (!ShellExecuteEx(&info))\n    {\n        PhShowStatus(hWnd, L\"Unable to execute the program.\", 0, GetLastError());\n    }\n}\n\n/**\n * Expands registry name abbreviations.\n *\n * \\param KeyName The key name.\n * \\param Computer TRUE to prepend \"Computer\" or \"My Computer\" for use with the Registry Editor.\n */\nPPH_STRING PhExpandKeyName(\n    _In_ PPH_STRING KeyName,\n    _In_ BOOLEAN Computer\n    )\n{\n    PPH_STRING keyName;\n    PPH_STRING tempString;\n\n    if (PhStartsWithString2(KeyName, L\"HKCU\", TRUE))\n    {\n        keyName = PhConcatStrings2(L\"HKEY_CURRENT_USER\", &KeyName->Buffer[4]);\n    }\n    else if (PhStartsWithString2(KeyName, L\"HKU\", TRUE))\n    {\n        keyName = PhConcatStrings2(L\"HKEY_USERS\", &KeyName->Buffer[3]);\n    }\n    else if (PhStartsWithString2(KeyName, L\"HKCR\", TRUE))\n    {\n        keyName = PhConcatStrings2(L\"HKEY_CLASSES_ROOT\", &KeyName->Buffer[4]);\n    }\n    else if (PhStartsWithString2(KeyName, L\"HKLM\", TRUE))\n    {\n        keyName = PhConcatStrings2(L\"HKEY_LOCAL_MACHINE\", &KeyName->Buffer[4]);\n    }\n    else\n    {\n        PhSetReference(&keyName, KeyName);\n    }\n\n    if (Computer)\n    {\n        tempString = PhConcatStrings2(L\"Computer\\\\\", keyName->Buffer);\n        PhDereferenceObject(keyName);\n        keyName = tempString;\n    }\n\n    return keyName;\n}\n\n/**\n * Opens a key in the Registry Editor.\n *\n * \\param hWnd A handle to the parent window.\n * \\param KeyName The key name to open.\n */\nVOID PhShellOpenKey(\n    _In_ HWND hWnd,\n    _In_ PPH_STRING KeyName\n    )\n{\n    static PH_STRINGREF regeditKeyName = PH_STRINGREF_INIT(L\"Software\\\\Microsoft\\\\Windows\\\\CurrentVersion\\\\Applets\\\\Regedit\");\n\n    PPH_STRING lastKey;\n    HANDLE regeditKeyHandle;\n    UNICODE_STRING valueName;\n    PPH_STRING regeditFileName;\n\n    if (!NT_SUCCESS(PhCreateKey(\n        &regeditKeyHandle,\n        KEY_WRITE,\n        PH_KEY_CURRENT_USER,\n        &regeditKeyName,\n        0,\n        0,\n        NULL\n        )))\n        return;\n\n    RtlInitUnicodeString(&valueName, L\"LastKey\");\n    lastKey = PhExpandKeyName(KeyName, TRUE);\n    NtSetValueKey(regeditKeyHandle, &valueName, 0, REG_SZ, lastKey->Buffer, (ULONG)lastKey->Length + 2);\n    PhDereferenceObject(lastKey);\n\n    NtClose(regeditKeyHandle);\n\n    // Start regedit. If we aren't elevated, request that regedit be elevated. This is so we can get\n    // the consent dialog in the center of the specified window.\n\n    regeditFileName = PhGetKnownLocation(CSIDL_WINDOWS, L\"\\\\regedit.exe\");\n\n    if (!regeditFileName)\n        regeditFileName = PhCreateString(L\"regedit.exe\");\n\n    if (!PhGetOwnTokenAttributes().Elevated)\n    {\n        PhShellExecuteEx(hWnd, regeditFileName->Buffer, L\"\", SW_NORMAL, PH_SHELL_EXECUTE_ADMIN, 0, NULL);\n    }\n    else\n    {\n        PhShellExecute(hWnd, regeditFileName->Buffer, L\"\");\n    }\n\n    PhDereferenceObject(regeditFileName);\n}\n\n/**\n * Gets a registry string value.\n *\n * \\param KeyHandle A handle to the key.\n * \\param ValueName The name of the value.\n *\n * \\return A pointer to a string containing the value, or NULL if the function failed. You must free\n * the string using PhDereferenceObject() when you no longer need it.\n */\nPPH_STRING PhQueryRegistryString(\n    _In_ HANDLE KeyHandle,\n    _In_opt_ PWSTR ValueName\n    )\n{\n    PPH_STRING string = NULL;\n    PH_STRINGREF valueName;\n    PKEY_VALUE_PARTIAL_INFORMATION buffer;\n\n    if (ValueName)\n        PhInitializeStringRef(&valueName, ValueName);\n    else\n        PhInitializeEmptyStringRef(&valueName);\n\n    if (NT_SUCCESS(PhQueryValueKey(KeyHandle, &valueName, KeyValuePartialInformation, &buffer)))\n    {\n        if (buffer->Type == REG_SZ ||\n            buffer->Type == REG_MULTI_SZ ||\n            buffer->Type == REG_EXPAND_SZ)\n        {\n            if (buffer->DataLength >= sizeof(WCHAR))\n                string = PhCreateStringEx((PWCHAR)buffer->Data, buffer->DataLength - sizeof(WCHAR));\n            else\n                string = PhReferenceEmptyString();\n        }\n\n        PhFree(buffer);\n    }\n\n    return string;\n}\n\nULONG PhQueryRegistryUlong(\n    _In_ HANDLE KeyHandle,\n    _In_opt_ PWSTR ValueName\n    )\n{\n    ULONG ulong = 0;\n    PH_STRINGREF valueName;\n    PKEY_VALUE_PARTIAL_INFORMATION buffer;\n\n    if (ValueName)\n        PhInitializeStringRef(&valueName, ValueName);\n    else\n        PhInitializeEmptyStringRef(&valueName);\n\n    if (NT_SUCCESS(PhQueryValueKey(KeyHandle, &valueName, KeyValuePartialInformation, &buffer)))\n    {\n        if (buffer->Type == REG_DWORD)\n        {\n            if (buffer->DataLength == sizeof(ULONG))\n                ulong = *(PULONG)buffer->Data;\n        }\n\n        PhFree(buffer);\n    }\n\n    return ulong;\n}\n\nULONG64 PhQueryRegistryUlong64(\n    _In_ HANDLE KeyHandle,\n    _In_opt_ PWSTR ValueName\n    )\n{\n    ULONG64 ulong64 = 0;\n    PH_STRINGREF valueName;\n    PKEY_VALUE_PARTIAL_INFORMATION buffer;\n\n    if (ValueName)\n        PhInitializeStringRef(&valueName, ValueName);\n    else\n        PhInitializeEmptyStringRef(&valueName);\n\n    if (NT_SUCCESS(PhQueryValueKey(KeyHandle, &valueName, KeyValuePartialInformation, &buffer)))\n    {\n        if (buffer->Type == REG_QWORD)\n        {\n            if (buffer->DataLength == sizeof(ULONG64))\n                ulong64 = *(PULONG64)buffer->Data;\n        }\n\n        PhFree(buffer);\n    }\n\n    return ulong64;\n}\n\nVOID PhMapFlags1(\n    _Inout_ PULONG Value2,\n    _In_ ULONG Value1,\n    _In_ const PH_FLAG_MAPPING *Mappings,\n    _In_ ULONG NumberOfMappings\n    )\n{\n    ULONG i;\n    ULONG value2;\n\n    value2 = *Value2;\n\n    if (value2 != 0)\n    {\n        // There are existing flags. Map the flags we know about by clearing/setting them. The flags\n        // we don't know about won't be affected.\n\n        for (i = 0; i < NumberOfMappings; i++)\n        {\n            if (Value1 & Mappings[i].Flag1)\n                value2 |= Mappings[i].Flag2;\n            else\n                value2 &= ~Mappings[i].Flag2;\n        }\n    }\n    else\n    {\n        // There are no existing flags, which means we can build the value from scratch, with no\n        // clearing needed.\n\n        for (i = 0; i < NumberOfMappings; i++)\n        {\n            if (Value1 & Mappings[i].Flag1)\n                value2 |= Mappings[i].Flag2;\n        }\n    }\n\n    *Value2 = value2;\n}\n\nVOID PhMapFlags2(\n    _Inout_ PULONG Value1,\n    _In_ ULONG Value2,\n    _In_ const PH_FLAG_MAPPING *Mappings,\n    _In_ ULONG NumberOfMappings\n    )\n{\n    ULONG i;\n    ULONG value1;\n\n    value1 = *Value1;\n\n    if (value1 != 0)\n    {\n        for (i = 0; i < NumberOfMappings; i++)\n        {\n            if (Value2 & Mappings[i].Flag2)\n                value1 |= Mappings[i].Flag1;\n            else\n                value1 &= ~Mappings[i].Flag1;\n        }\n    }\n    else\n    {\n        for (i = 0; i < NumberOfMappings; i++)\n        {\n            if (Value2 & Mappings[i].Flag2)\n                value1 |= Mappings[i].Flag1;\n        }\n    }\n\n    *Value1 = value1;\n}\n\nUINT_PTR CALLBACK PhpOpenFileNameHookProc(\n    _In_ HWND hdlg,\n    _In_ UINT uiMsg,\n    _In_ WPARAM wParam,\n    _In_ LPARAM lParam\n    )\n{\n    switch (uiMsg)\n    {\n    case WM_NOTIFY:\n        {\n            LPOFNOTIFY header = (LPOFNOTIFY)lParam;\n\n            // We can't use CDN_FILEOK because it's not sent if the buffer is too small, defeating\n            // the entire purpose of this callback function.\n\n            switch (header->hdr.code)\n            {\n            case CDN_SELCHANGE:\n                {\n                    ULONG returnLength;\n\n                    returnLength = CommDlg_OpenSave_GetFilePath(\n                        header->hdr.hwndFrom,\n                        header->lpOFN->lpstrFile,\n                        header->lpOFN->nMaxFile\n                        );\n\n                    if ((LONG)returnLength > 0 && returnLength > header->lpOFN->nMaxFile)\n                    {\n                        PhFree(header->lpOFN->lpstrFile);\n                        header->lpOFN->nMaxFile = returnLength + 0x200; // pre-allocate some more\n                        header->lpOFN->lpstrFile = PhAllocate(header->lpOFN->nMaxFile * 2);\n\n                        returnLength = CommDlg_OpenSave_GetFilePath(\n                            header->hdr.hwndFrom,\n                            header->lpOFN->lpstrFile,\n                            header->lpOFN->nMaxFile\n                            );\n                    }\n                }\n                break;\n            }\n        }\n        break;\n    }\n\n    return FALSE;\n}\n\nOPENFILENAME *PhpCreateOpenFileName(\n    VOID\n    )\n{\n    OPENFILENAME *ofn;\n\n    ofn = PhAllocate(sizeof(OPENFILENAME));\n    memset(ofn, 0, sizeof(OPENFILENAME));\n\n    ofn->lStructSize = sizeof(OPENFILENAME);\n    ofn->nMaxFile = 0x400;\n    ofn->lpstrFile = PhAllocate(ofn->nMaxFile * 2);\n    ofn->lpstrFileTitle = NULL;\n    ofn->Flags = OFN_ENABLEHOOK | OFN_EXPLORER;\n    ofn->lpfnHook = PhpOpenFileNameHookProc;\n\n    ofn->lpstrFile[0] = 0;\n\n    return ofn;\n}\n\nVOID PhpFreeOpenFileName(\n    _In_ OPENFILENAME *OpenFileName\n    )\n{\n    if (OpenFileName->lpstrFilter) PhFree((PVOID)OpenFileName->lpstrFilter);\n    if (OpenFileName->lpstrFile) PhFree((PVOID)OpenFileName->lpstrFile);\n\n    PhFree(OpenFileName);\n}\n\ntypedef struct _PHP_FILE_DIALOG\n{\n    BOOLEAN UseIFileDialog;\n    BOOLEAN Save;\n    union\n    {\n        OPENFILENAME *OpenFileName;\n        IFileDialog *FileDialog;\n    } u;\n} PHP_FILE_DIALOG, *PPHP_FILE_DIALOG;\n\nPPHP_FILE_DIALOG PhpCreateFileDialog(\n    _In_ BOOLEAN Save,\n    _In_opt_ OPENFILENAME *OpenFileName,\n    _In_opt_ IFileDialog *FileDialog\n    )\n{\n    PPHP_FILE_DIALOG fileDialog;\n\n    assert(!!OpenFileName != !!FileDialog);\n    fileDialog = PhAllocate(sizeof(PHP_FILE_DIALOG));\n    fileDialog->Save = Save;\n\n    if (OpenFileName)\n    {\n        fileDialog->UseIFileDialog = FALSE;\n        fileDialog->u.OpenFileName = OpenFileName;\n    }\n    else if (FileDialog)\n    {\n        fileDialog->UseIFileDialog = TRUE;\n        fileDialog->u.FileDialog = FileDialog;\n    }\n    else\n    {\n        PhRaiseStatus(STATUS_INVALID_PARAMETER);\n    }\n\n    return fileDialog;\n}\n\n/**\n * Creates a file dialog for the user to select a file to open.\n *\n * \\return An opaque pointer representing the file dialog. You must free the file dialog using\n * PhFreeFileDialog() when you no longer need it.\n */\nPVOID PhCreateOpenFileDialog(\n    VOID\n    )\n{\n    IFileDialog *fileDialog;\n\n    if (SUCCEEDED(CoCreateInstance(\n        &CLSID_FileOpenDialog,\n        NULL,\n        CLSCTX_INPROC_SERVER,\n        &IID_IFileDialog,\n        &fileDialog\n        )))\n    {\n        // The default options are fine.\n        return PhpCreateFileDialog(FALSE, NULL, fileDialog);\n    }\n\n    return NULL;\n}\n\n/**\n * Creates a file dialog for the user to select a file to save to.\n *\n * \\return An opaque pointer representing the file dialog. You must free the file dialog using\n * PhFreeFileDialog() when you no longer need it.\n */\nPVOID PhCreateSaveFileDialog(\n    VOID\n    )\n{\n    IFileDialog *fileDialog;\n\n    if (SUCCEEDED(CoCreateInstance(\n        &CLSID_FileSaveDialog,\n        NULL,\n        CLSCTX_INPROC_SERVER,\n        &IID_IFileDialog,\n        &fileDialog\n        )))\n    {\n        // The default options are fine.\n        return PhpCreateFileDialog(TRUE, NULL, fileDialog);\n    }\n\n    return NULL;\n}\n\n/**\n * Frees a file dialog.\n *\n * \\param FileDialog The file dialog.\n */\nVOID PhFreeFileDialog(\n    _In_ PVOID FileDialog\n    )\n{\n    PPHP_FILE_DIALOG fileDialog = FileDialog;\n\n    if (fileDialog->UseIFileDialog)\n    {\n        IFileDialog_Release(fileDialog->u.FileDialog);\n    }\n    else\n    {\n        PhpFreeOpenFileName(fileDialog->u.OpenFileName);\n    }\n\n    PhFree(fileDialog);\n}\n\n/**\n * Shows a file dialog to the user.\n *\n * \\param hWnd A handle to the parent window.\n * \\param FileDialog The file dialog.\n *\n * \\return TRUE if the user selected a file, FALSE if the user cancelled the operation or an error\n * occurred.\n */\nBOOLEAN PhShowFileDialog(\n    _In_ HWND hWnd,\n    _In_ PVOID FileDialog\n    )\n{\n    PPHP_FILE_DIALOG fileDialog = FileDialog;\n\n    if (fileDialog->UseIFileDialog)\n    {\n        // Set a blank default extension. This will have an effect when the user selects a different\n        // file type.\n        IFileDialog_SetDefaultExtension(fileDialog->u.FileDialog, L\"\");\n\n        return SUCCEEDED(IFileDialog_Show(fileDialog->u.FileDialog, hWnd));\n    }\n    else\n    {\n        OPENFILENAME *ofn = fileDialog->u.OpenFileName;\n\n        ofn->hwndOwner = hWnd;\n\n        // Determine whether the structure represents a open or save dialog and call the appropriate\n        // function.\n        if (!fileDialog->Save)\n        {\n            return GetOpenFileName(ofn);\n        }\n        else\n        {\n            return GetSaveFileName(ofn);\n        }\n    }\n}\n\nstatic const PH_FLAG_MAPPING PhpFileDialogIfdMappings[] =\n{\n    { PH_FILEDIALOG_CREATEPROMPT, FOS_CREATEPROMPT },\n    { PH_FILEDIALOG_PATHMUSTEXIST, FOS_PATHMUSTEXIST },\n    { PH_FILEDIALOG_FILEMUSTEXIST, FOS_FILEMUSTEXIST },\n    { PH_FILEDIALOG_SHOWHIDDEN, FOS_FORCESHOWHIDDEN },\n    { PH_FILEDIALOG_NODEREFERENCELINKS, FOS_NODEREFERENCELINKS },\n    { PH_FILEDIALOG_OVERWRITEPROMPT, FOS_OVERWRITEPROMPT },\n    { PH_FILEDIALOG_DEFAULTEXPANDED, FOS_DEFAULTNOMINIMODE },\n    { PH_FILEDIALOG_STRICTFILETYPES, FOS_STRICTFILETYPES },\n    { PH_FILEDIALOG_PICKFOLDERS, FOS_PICKFOLDERS },\n    { PH_FILEDIALOG_NOPATHVALIDATE, FOS_NOVALIDATE },\n};\n\nstatic const PH_FLAG_MAPPING PhpFileDialogOfnMappings[] =\n{\n    { PH_FILEDIALOG_CREATEPROMPT, OFN_CREATEPROMPT },\n    { PH_FILEDIALOG_PATHMUSTEXIST, OFN_PATHMUSTEXIST },\n    { PH_FILEDIALOG_FILEMUSTEXIST, OFN_FILEMUSTEXIST },\n    { PH_FILEDIALOG_SHOWHIDDEN, OFN_FORCESHOWHIDDEN },\n    { PH_FILEDIALOG_NODEREFERENCELINKS, OFN_NODEREFERENCELINKS },\n    { PH_FILEDIALOG_OVERWRITEPROMPT, OFN_OVERWRITEPROMPT },\n    { PH_FILEDIALOG_NOPATHVALIDATE, OFN_NOVALIDATE }\n};\n\n/**\n * Gets the options for a file dialog.\n *\n * \\param FileDialog The file dialog.\n *\n * \\return The currently enabled options. See the documentation for PhSetFileDialogOptions() for\n * details.\n */\nULONG PhGetFileDialogOptions(\n    _In_ PVOID FileDialog\n    )\n{\n    PPHP_FILE_DIALOG fileDialog = FileDialog;\n\n    if (fileDialog->UseIFileDialog)\n    {\n        FILEOPENDIALOGOPTIONS dialogOptions;\n        ULONG options;\n\n        if (SUCCEEDED(IFileDialog_GetOptions(fileDialog->u.FileDialog, &dialogOptions)))\n        {\n            options = 0;\n\n            PhMapFlags2(\n                &options,\n                dialogOptions,\n                PhpFileDialogIfdMappings,\n                sizeof(PhpFileDialogIfdMappings) / sizeof(PH_FLAG_MAPPING)\n                );\n\n            return options;\n        }\n        else\n        {\n            return 0;\n        }\n    }\n    else\n    {\n        OPENFILENAME *ofn = fileDialog->u.OpenFileName;\n        ULONG options;\n\n        options = 0;\n\n        PhMapFlags2(\n            &options,\n            ofn->Flags,\n            PhpFileDialogOfnMappings,\n            sizeof(PhpFileDialogOfnMappings) / sizeof(PH_FLAG_MAPPING)\n            );\n\n        return options;\n    }\n}\n\n/**\n * Sets the options for a file dialog.\n *\n * \\param FileDialog The file dialog.\n * \\param Options A combination of flags specifying the options.\n * \\li \\c PH_FILEDIALOG_CREATEPROMPT A prompt for creation will be displayed when the selected item\n * does not exist. This is only valid for Save dialogs.\n * \\li \\c PH_FILEDIALOG_PATHMUSTEXIST The selected item must be in an existing folder. This is\n * enabled by default.\n * \\li \\c PH_FILEDIALOG_FILEMUSTEXIST The selected item must exist. This is enabled by default and\n * is only valid for Open dialogs.\n * \\li \\c PH_FILEDIALOG_SHOWHIDDEN Items with the System and Hidden attributes will be displayed.\n * \\li \\c PH_FILEDIALOG_NODEREFERENCELINKS Shortcuts will not be followed, allowing .lnk files to be\n * opened.\n * \\li \\c PH_FILEDIALOG_OVERWRITEPROMPT An overwrite prompt will be displayed if an existing item is\n * selected. This is enabled by default and is only valid for Save dialogs.\n * \\li \\c PH_FILEDIALOG_DEFAULTEXPANDED The file dialog should be expanded by default (i.e. the\n * folder browser should be displayed). This is only valid for Save dialogs.\n */\nVOID PhSetFileDialogOptions(\n    _In_ PVOID FileDialog,\n    _In_ ULONG Options\n    )\n{\n    PPHP_FILE_DIALOG fileDialog = FileDialog;\n\n    if (fileDialog->UseIFileDialog)\n    {\n        FILEOPENDIALOGOPTIONS dialogOptions;\n\n        if (SUCCEEDED(IFileDialog_GetOptions(fileDialog->u.FileDialog, &dialogOptions)))\n        {\n            PhMapFlags1(\n                &dialogOptions,\n                Options,\n                PhpFileDialogIfdMappings,\n                sizeof(PhpFileDialogIfdMappings) / sizeof(PH_FLAG_MAPPING)\n                );\n\n            IFileDialog_SetOptions(fileDialog->u.FileDialog, dialogOptions);\n        }\n    }\n    else\n    {\n        OPENFILENAME *ofn = fileDialog->u.OpenFileName;\n\n        PhMapFlags1(\n            &ofn->Flags,\n            Options,\n            PhpFileDialogOfnMappings,\n            sizeof(PhpFileDialogOfnMappings) / sizeof(PH_FLAG_MAPPING)\n            );\n    }\n}\n\n/**\n * Gets the index of the currently selected file type filter for a file dialog.\n *\n * \\param FileDialog The file dialog.\n *\n * \\return The one-based index of the selected file type, or 0 if an error occurred.\n */\nULONG PhGetFileDialogFilterIndex(\n    _In_ PVOID FileDialog\n    )\n{\n    PPHP_FILE_DIALOG fileDialog = FileDialog;\n\n    if (fileDialog->UseIFileDialog)\n    {\n        ULONG index;\n\n        if (SUCCEEDED(IFileDialog_GetFileTypeIndex(fileDialog->u.FileDialog, &index)))\n        {\n            return index;\n        }\n        else\n        {\n            return 0;\n        }\n    }\n    else\n    {\n        OPENFILENAME *ofn = fileDialog->u.OpenFileName;\n\n        return ofn->nFilterIndex;\n    }\n}\n\n/**\n * Sets the file type filter for a file dialog.\n *\n * \\param FileDialog The file dialog.\n * \\param Filters A pointer to an array of file type structures.\n * \\param NumberOfFilters The number of file types.\n */\nVOID PhSetFileDialogFilter(\n    _In_ PVOID FileDialog,\n    _In_ PPH_FILETYPE_FILTER Filters,\n    _In_ ULONG NumberOfFilters\n    )\n{\n    PPHP_FILE_DIALOG fileDialog = FileDialog;\n\n    if (fileDialog->UseIFileDialog)\n    {\n        IFileDialog_SetFileTypes(\n            fileDialog->u.FileDialog,\n            NumberOfFilters,\n            (COMDLG_FILTERSPEC *)Filters\n            );\n    }\n    else\n    {\n        OPENFILENAME *ofn = fileDialog->u.OpenFileName;\n        PPH_STRING filterString;\n        PH_STRING_BUILDER filterBuilder;\n        ULONG i;\n\n        PhInitializeStringBuilder(&filterBuilder, 10);\n\n        for (i = 0; i < NumberOfFilters; i++)\n        {\n            PhAppendStringBuilder2(&filterBuilder, Filters[i].Name);\n            PhAppendCharStringBuilder(&filterBuilder, 0);\n            PhAppendStringBuilder2(&filterBuilder, Filters[i].Filter);\n            PhAppendCharStringBuilder(&filterBuilder, 0);\n        }\n\n        filterString = PhFinalStringBuilderString(&filterBuilder);\n\n        if (ofn->lpstrFilter)\n            PhFree((PVOID)ofn->lpstrFilter);\n\n        ofn->lpstrFilter = PhAllocateCopy(filterString->Buffer, filterString->Length + 2);\n        PhDereferenceObject(filterString);\n    }\n}\n\n/**\n * Gets the file name selected in a file dialog.\n *\n * \\param FileDialog The file dialog.\n *\n * \\return A pointer to a string containing the file name. You must free the string using\n * PhDereferenceObject() when you no longer need it.\n */\nPPH_STRING PhGetFileDialogFileName(\n    _In_ PVOID FileDialog\n    )\n{\n    PPHP_FILE_DIALOG fileDialog = FileDialog;\n\n    if (fileDialog->UseIFileDialog)\n    {\n        IShellItem *result;\n        PPH_STRING fileName = NULL;\n\n        if (SUCCEEDED(IFileDialog_GetResult(fileDialog->u.FileDialog, &result)))\n        {\n            PWSTR name;\n\n            if (SUCCEEDED(IShellItem_GetDisplayName(result, SIGDN_FILESYSPATH, &name)))\n            {\n                fileName = PhCreateString(name);\n                CoTaskMemFree(name);\n            }\n\n            IShellItem_Release(result);\n        }\n\n        if (!fileName)\n        {\n            PWSTR name;\n\n            if (SUCCEEDED(IFileDialog_GetFileName(fileDialog->u.FileDialog, &name)))\n            {\n                fileName = PhCreateString(name);\n                CoTaskMemFree(name);\n            }\n        }\n\n        return fileName;\n    }\n    else\n    {\n        return PhCreateString(fileDialog->u.OpenFileName->lpstrFile);\n    }\n}\n\n/**\n * Sets the file name of a file dialog.\n *\n * \\param FileDialog The file dialog.\n * \\param FileName The new file name.\n */\nVOID PhSetFileDialogFileName(\n    _In_ PVOID FileDialog,\n    _In_ PWSTR FileName\n    )\n{\n    PPHP_FILE_DIALOG fileDialog = FileDialog;\n    PH_STRINGREF fileName;\n\n    PhInitializeStringRefLongHint(&fileName, FileName);\n\n    if (fileDialog->UseIFileDialog)\n    {\n        IShellItem *shellItem = NULL;\n        PH_STRINGREF pathNamePart;\n        PH_STRINGREF baseNamePart;\n\n        if (PhSplitStringRefAtLastChar(&fileName, '\\\\', &pathNamePart, &baseNamePart) &&\n            SHParseDisplayName_Import() && SHCreateShellItem_Import())\n        {\n            LPITEMIDLIST item;\n            SFGAOF attributes;\n            PPH_STRING pathName;\n\n            pathName = PhCreateString2(&pathNamePart);\n\n            if (SUCCEEDED(SHParseDisplayName_Import()(pathName->Buffer, NULL, &item, 0, &attributes)))\n            {\n                SHCreateShellItem_Import()(NULL, NULL, item, &shellItem);\n                CoTaskMemFree(item);\n            }\n\n            PhDereferenceObject(pathName);\n        }\n\n        if (shellItem)\n        {\n            IFileDialog_SetFolder(fileDialog->u.FileDialog, shellItem);\n            IFileDialog_SetFileName(fileDialog->u.FileDialog, baseNamePart.Buffer);\n            IShellItem_Release(shellItem);\n        }\n        else\n        {\n            IFileDialog_SetFileName(fileDialog->u.FileDialog, FileName);\n        }\n    }\n    else\n    {\n        OPENFILENAME *ofn = fileDialog->u.OpenFileName;\n\n        if (PhFindCharInStringRef(&fileName, '/', FALSE) != -1 || PhFindCharInStringRef(&fileName, '\\\"', FALSE) != -1)\n        {\n            // It refuses to take any filenames with a slash or quotation mark.\n            return;\n        }\n\n        PhFree(ofn->lpstrFile);\n\n        ofn->nMaxFile = (ULONG)max(fileName.Length / sizeof(WCHAR) + 1, 0x400);\n        ofn->lpstrFile = PhAllocate(ofn->nMaxFile * 2);\n        memcpy(ofn->lpstrFile, fileName.Buffer, fileName.Length + sizeof(WCHAR));\n    }\n}\n\n/**\n * Determines if an executable image is packed.\n *\n * \\param FileName The file name of the image.\n * \\param IsPacked A variable that receives TRUE if the image is packed, otherwise FALSE.\n * \\param NumberOfModules A variable that receives the number of DLLs that the image imports\n * functions from.\n * \\param NumberOfFunctions A variable that receives the number of functions that the image imports.\n */\nNTSTATUS PhIsExecutablePacked(\n    _In_ PWSTR FileName,\n    _Out_ PBOOLEAN IsPacked,\n    _Out_opt_ PULONG NumberOfModules,\n    _Out_opt_ PULONG NumberOfFunctions\n    )\n{\n    // An image is packed if:\n    //\n    // 1. It references fewer than 3 modules, and\n    // 2. It imports fewer than 5 functions, and\n    // 3. It does not use the Native subsystem.\n    //\n    // Or:\n    //\n    // 1. The function-to-module ratio is lower than 3 (on average fewer than 3 functions are\n    //    imported from each module), and\n    // 2. It references more than 2 modules but fewer than 6 modules.\n    //\n    // Or:\n    //\n    // 1. The function-to-module ratio is lower than 2 (on average fewer than 2 functions are\n    //    imported from each module), and\n    // 2. It references more than 5 modules but fewer than 31 modules.\n    //\n    // Or:\n    //\n    // 1. It does not have a section named \".text\".\n    //\n    // An image is not considered to be packed if it has only one import from a module named\n    // \"mscoree.dll\".\n\n    NTSTATUS status;\n    PH_MAPPED_IMAGE mappedImage;\n    PH_MAPPED_IMAGE_IMPORTS imports;\n    PH_MAPPED_IMAGE_IMPORT_DLL importDll;\n    ULONG i;\n    //ULONG limitNumberOfSections;\n    ULONG limitNumberOfModules;\n    ULONG numberOfModules;\n    ULONG numberOfFunctions = 0;\n    BOOLEAN hasTextSection = FALSE;\n    BOOLEAN isModuleMscoree = FALSE;\n    BOOLEAN isPacked;\n\n    status = PhLoadMappedImage(\n        FileName,\n        NULL,\n        TRUE,\n        &mappedImage\n        );\n\n    if (!NT_SUCCESS(status))\n        return status;\n\n    // Go through the sections and look for the \".text\" section.\n\n    // This rule is currently disabled.\n    hasTextSection = TRUE;\n\n    //limitNumberOfSections = min(mappedImage.NumberOfSections, 64);\n\n    //for (i = 0; i < limitNumberOfSections; i++)\n    //{\n    //    CHAR sectionName[IMAGE_SIZEOF_SHORT_NAME + 1];\n\n    //    if (PhGetMappedImageSectionName(\n    //        &mappedImage.Sections[i],\n    //        sectionName,\n    //        IMAGE_SIZEOF_SHORT_NAME + 1,\n    //        NULL\n    //        ))\n    //    {\n    //        if (STR_IEQUAL(sectionName, \".text\"))\n    //        {\n    //            hasTextSection = TRUE;\n    //            break;\n    //        }\n    //    }\n    //}\n\n    status = PhGetMappedImageImports(\n        &imports,\n        &mappedImage\n        );\n\n    if (!NT_SUCCESS(status))\n        goto CleanupExit;\n\n    // Get the module and function totals.\n\n    numberOfModules = imports.NumberOfDlls;\n    limitNumberOfModules = min(numberOfModules, 64);\n\n    for (i = 0; i < limitNumberOfModules; i++)\n    {\n        if (!NT_SUCCESS(status = PhGetMappedImageImportDll(\n            &imports,\n            i,\n            &importDll\n            )))\n            goto CleanupExit;\n\n        if (PhEqualBytesZ(importDll.Name, \"mscoree.dll\", TRUE))\n            isModuleMscoree = TRUE;\n\n        numberOfFunctions += importDll.NumberOfEntries;\n    }\n\n    // Determine if the image is packed.\n\n    if (\n        numberOfModules != 0 &&\n        (\n        // Rule 1\n        (numberOfModules < 3 && numberOfFunctions < 5 &&\n        mappedImage.NtHeaders->OptionalHeader.Subsystem != IMAGE_SUBSYSTEM_NATIVE) ||\n        // Rule 2\n        ((numberOfFunctions / numberOfModules) < 3 &&\n        numberOfModules > 2 && numberOfModules < 5) ||\n        // Rule 3\n        ((numberOfFunctions / numberOfModules) < 2 &&\n        numberOfModules > 4 && numberOfModules < 31) ||\n        // Rule 4\n        !hasTextSection\n        ) &&\n        // Additional .NET rule\n        !(numberOfModules == 1 && numberOfFunctions == 1 && isModuleMscoree)\n        )\n    {\n        isPacked = TRUE;\n    }\n    else\n    {\n        isPacked = FALSE;\n    }\n\n    *IsPacked = isPacked;\n\n    if (NumberOfModules)\n        *NumberOfModules = numberOfModules;\n    if (NumberOfFunctions)\n        *NumberOfFunctions = numberOfFunctions;\n\nCleanupExit:\n    PhUnloadMappedImage(&mappedImage);\n\n    return status;\n}\n\nULONG PhCrc32(\n    _In_ ULONG Crc,\n    _In_reads_(Length) PCHAR Buffer,\n    _In_ SIZE_T Length\n    )\n{\n    Crc ^= 0xffffffff;\n\n    while (Length--)\n        Crc = (Crc >> 8) ^ PhCrc32Table[(Crc ^ *Buffer++) & 0xff];\n\n    return Crc ^ 0xffffffff;\n}\n\nC_ASSERT(RTL_FIELD_SIZE(PH_HASH_CONTEXT, Context) >= sizeof(MD5_CTX));\nC_ASSERT(RTL_FIELD_SIZE(PH_HASH_CONTEXT, Context) >= sizeof(A_SHA_CTX));\n\n/**\n * Initializes hashing.\n *\n * \\param Context A hashing context structure.\n * \\param Algorithm The hash algorithm to use:\n * \\li \\c Md5HashAlgorithm MD5 (128 bits)\n * \\li \\c Sha1HashAlgorithm SHA-1 (160 bits)\n * \\li \\c Crc32HashAlgorithm CRC-32-IEEE 802.3 (32 bits)\n * \\li \\c Sha256HashAlgorithm SHA-256 (256 bits)\n */\nVOID PhInitializeHash(\n    _Out_ PPH_HASH_CONTEXT Context,\n    _In_ PH_HASH_ALGORITHM Algorithm\n    )\n{\n    Context->Algorithm = Algorithm;\n\n    switch (Algorithm)\n    {\n    case Md5HashAlgorithm:\n        MD5Init((MD5_CTX *)Context->Context);\n        break;\n    case Sha1HashAlgorithm:\n        A_SHAInit((A_SHA_CTX *)Context->Context);\n        break;\n    case Crc32HashAlgorithm:\n        Context->Context[0] = 0;\n        break;\n    case Sha256HashAlgorithm:\n        sha256_starts((sha256_context *)Context->Context);\n        break;\n    default:\n        PhRaiseStatus(STATUS_INVALID_PARAMETER_2);\n        break;\n    }\n}\n\n/**\n * Hashes a block of data.\n *\n * \\param Context A hashing context structure.\n * \\param Buffer The block of data.\n * \\param Length The number of bytes in the block.\n */\nVOID PhUpdateHash(\n    _Inout_ PPH_HASH_CONTEXT Context,\n    _In_reads_bytes_(Length) PVOID Buffer,\n    _In_ ULONG Length\n    )\n{\n    switch (Context->Algorithm)\n    {\n    case Md5HashAlgorithm:\n        MD5Update((MD5_CTX *)Context->Context, (PUCHAR)Buffer, Length);\n        break;\n    case Sha1HashAlgorithm:\n        A_SHAUpdate((A_SHA_CTX *)Context->Context, (PUCHAR)Buffer, Length);\n        break;\n    case Crc32HashAlgorithm:\n        Context->Context[0] = PhCrc32(Context->Context[0], (PUCHAR)Buffer, Length);\n        break;\n    case Sha256HashAlgorithm:\n        sha256_update((sha256_context *)Context->Context, (PUCHAR)Buffer, Length);\n        break;\n    default:\n        PhRaiseStatus(STATUS_INVALID_PARAMETER);\n    }\n}\n\n/**\n * Computes the final hash value.\n *\n * \\param Context A hashing context structure.\n * \\param Hash A buffer which receives the final hash value.\n * \\param HashLength The size of the buffer, in bytes.\n * \\param ReturnLength A variable which receives the required size of the buffer, in bytes.\n */\nBOOLEAN PhFinalHash(\n    _Inout_ PPH_HASH_CONTEXT Context,\n    _Out_writes_bytes_(HashLength) PVOID Hash,\n    _In_ ULONG HashLength,\n    _Out_opt_ PULONG ReturnLength\n    )\n{\n    BOOLEAN result;\n    ULONG returnLength;\n\n    result = FALSE;\n\n    switch (Context->Algorithm)\n    {\n    case Md5HashAlgorithm:\n        if (HashLength >= 16)\n        {\n            MD5Final((MD5_CTX *)Context->Context);\n            memcpy(Hash, ((MD5_CTX *)Context->Context)->digest, 16);\n            result = TRUE;\n        }\n\n        returnLength = 16;\n\n        break;\n    case Sha1HashAlgorithm:\n        if (HashLength >= 20)\n        {\n            A_SHAFinal((A_SHA_CTX *)Context->Context, (PUCHAR)Hash);\n            result = TRUE;\n        }\n\n        returnLength = 20;\n\n        break;\n    case Crc32HashAlgorithm:\n        if (HashLength >= 4)\n        {\n            *(PULONG)Hash = Context->Context[0];\n            result = TRUE;\n        }\n\n        returnLength = 4;\n\n        break;\n    case Sha256HashAlgorithm:\n        if (HashLength >= 32)\n        {\n            sha256_finish((sha256_context *)Context->Context, (PUCHAR)Hash);\n            result = TRUE;\n        }\n\n        returnLength = 32;\n\n        break;\n    default:\n        PhRaiseStatus(STATUS_INVALID_PARAMETER);\n    }\n\n    if (ReturnLength)\n        *ReturnLength = returnLength;\n\n    return result;\n}\n\n/**\n * Parses one part of a command line string. Quotation marks and backslashes are handled\n * appropriately.\n *\n * \\param CommandLine The entire command line string.\n * \\param Index The starting index of the command line part to be parsed. There should be no leading\n * whitespace at this index. The index is updated to point to the end of the command line part.\n */\nPPH_STRING PhParseCommandLinePart(\n    _In_ PPH_STRINGREF CommandLine,\n    _Inout_ PULONG_PTR Index\n    )\n{\n    PH_STRING_BUILDER stringBuilder;\n    SIZE_T length;\n    SIZE_T i;\n\n    ULONG numberOfBackslashes;\n    BOOLEAN inQuote;\n    BOOLEAN endOfValue;\n\n    length = CommandLine->Length / 2;\n    i = *Index;\n\n    // This function follows the rules used by CommandLineToArgvW:\n    //\n    // * 2n backslashes and a quotation mark produces n backslashes and a quotation mark\n    //   (non-literal).\n    // * 2n + 1 backslashes and a quotation mark produces n and a quotation mark (literal).\n    // * n backslashes and no quotation mark produces n backslashes.\n\n    PhInitializeStringBuilder(&stringBuilder, 10);\n    numberOfBackslashes = 0;\n    inQuote = FALSE;\n    endOfValue = FALSE;\n\n    for (; i < length; i++)\n    {\n        switch (CommandLine->Buffer[i])\n        {\n        case '\\\\':\n            numberOfBackslashes++;\n            break;\n        case '\\\"':\n            if (numberOfBackslashes != 0)\n            {\n                if (numberOfBackslashes & 1)\n                {\n                    numberOfBackslashes /= 2;\n\n                    if (numberOfBackslashes != 0)\n                    {\n                        PhAppendCharStringBuilder2(&stringBuilder, '\\\\', numberOfBackslashes);\n                        numberOfBackslashes = 0;\n                    }\n\n                    PhAppendCharStringBuilder(&stringBuilder, '\\\"');\n\n                    break;\n                }\n                else\n                {\n                    numberOfBackslashes /= 2;\n                    PhAppendCharStringBuilder2(&stringBuilder, '\\\\', numberOfBackslashes);\n                    numberOfBackslashes = 0;\n                }\n            }\n\n            if (!inQuote)\n                inQuote = TRUE;\n            else\n                inQuote = FALSE;\n\n            break;\n        default:\n            if (numberOfBackslashes != 0)\n            {\n                PhAppendCharStringBuilder2(&stringBuilder, '\\\\', numberOfBackslashes);\n                numberOfBackslashes = 0;\n            }\n\n            if (CommandLine->Buffer[i] == ' ' && !inQuote)\n            {\n                endOfValue = TRUE;\n            }\n            else\n            {\n                PhAppendCharStringBuilder(&stringBuilder, CommandLine->Buffer[i]);\n            }\n\n            break;\n        }\n\n        if (endOfValue)\n            break;\n    }\n\n    *Index = i;\n\n    return PhFinalStringBuilderString(&stringBuilder);\n}\n\n/**\n * Parses a command line string.\n *\n * \\param CommandLine The command line string.\n * \\param Options An array of supported command line options.\n * \\param NumberOfOptions The number of elements in \\a Options.\n * \\param Flags A combination of flags.\n * \\li \\c PH_COMMAND_LINE_IGNORE_UNKNOWN_OPTIONS Unknown command line options are ignored instead of\n * failing the function.\n * \\li \\c PH_COMMAND_LINE_IGNORE_FIRST_PART The first part of the command line string is ignored.\n * This is used when the first part of the string contains the executable file name.\n * \\param Callback A callback function to execute for each command line option found.\n * \\param Context A user-defined value to pass to \\a Callback.\n */\nBOOLEAN PhParseCommandLine(\n    _In_ PPH_STRINGREF CommandLine,\n    _In_opt_ PPH_COMMAND_LINE_OPTION Options,\n    _In_ ULONG NumberOfOptions,\n    _In_ ULONG Flags,\n    _In_ PPH_COMMAND_LINE_CALLBACK Callback,\n    _In_opt_ PVOID Context\n    )\n{\n    SIZE_T i;\n    SIZE_T j;\n    SIZE_T length;\n    BOOLEAN cont = TRUE;\n    BOOLEAN wasFirst = TRUE;\n\n    PH_STRINGREF optionName;\n    PPH_COMMAND_LINE_OPTION option = NULL;\n    PPH_STRING optionValue;\n\n    if (CommandLine->Length == 0)\n        return TRUE;\n\n    i = 0;\n    length = CommandLine->Length / 2;\n\n    while (TRUE)\n    {\n        // Skip spaces.\n        while (i < length && CommandLine->Buffer[i] == ' ')\n            i++;\n\n        if (i >= length)\n            break;\n\n        if (option &&\n            (option->Type == MandatoryArgumentType ||\n            (option->Type == OptionalArgumentType && CommandLine->Buffer[i] != '-')))\n        {\n            // Read the value and execute the callback function.\n\n            optionValue = PhParseCommandLinePart(CommandLine, &i);\n            cont = Callback(option, optionValue, Context);\n            PhDereferenceObject(optionValue);\n\n            if (!cont)\n                break;\n\n            option = NULL;\n        }\n        else if (CommandLine->Buffer[i] == '-')\n        {\n            ULONG_PTR originalIndex;\n            SIZE_T optionNameLength;\n\n            // Read the option (only alphanumeric characters allowed).\n\n            // Skip the dash.\n            i++;\n\n            originalIndex = i;\n\n            for (; i < length; i++)\n            {\n                if (!iswalnum(CommandLine->Buffer[i]) && CommandLine->Buffer[i] != '-')\n                    break;\n            }\n\n            optionNameLength = i - originalIndex;\n\n            optionName.Buffer = &CommandLine->Buffer[originalIndex];\n            optionName.Length = optionNameLength * 2;\n\n            // Take care of any pending optional argument.\n\n            if (option && option->Type == OptionalArgumentType)\n            {\n                cont = Callback(option, NULL, Context);\n\n                if (!cont)\n                    break;\n\n                option = NULL;\n            }\n\n            // Find the option descriptor.\n\n            option = NULL;\n\n            for (j = 0; j < NumberOfOptions; j++)\n            {\n                if (PhEqualStringRef2(&optionName, Options[j].Name, FALSE))\n                {\n                    option = &Options[j];\n                    break;\n                }\n            }\n\n            if (!option && !(Flags & PH_COMMAND_LINE_IGNORE_UNKNOWN_OPTIONS))\n                return FALSE;\n\n            if (option && option->Type == NoArgumentType)\n            {\n                cont = Callback(option, NULL, Context);\n\n                if (!cont)\n                    break;\n\n                option = NULL;\n            }\n\n            wasFirst = FALSE;\n        }\n        else\n        {\n            PPH_STRING value;\n\n            value = PhParseCommandLinePart(CommandLine, &i);\n\n            if ((Flags & PH_COMMAND_LINE_IGNORE_FIRST_PART) && wasFirst)\n            {\n                PhDereferenceObject(value);\n                value = NULL;\n            }\n\n            if (value)\n            {\n                cont = Callback(NULL, value, Context);\n                PhDereferenceObject(value);\n\n                if (!cont)\n                    break;\n            }\n\n            wasFirst = FALSE;\n        }\n    }\n\n    if (cont && option && option->Type == OptionalArgumentType)\n        Callback(option, NULL, Context);\n\n    return TRUE;\n}\n\n/**\n * Escapes a string for use in a command line.\n *\n * \\param String The string to escape.\n *\n * \\return The escaped string.\n *\n * \\remarks Only the double quotation mark is escaped.\n */\nPPH_STRING PhEscapeCommandLinePart(\n    _In_ PPH_STRINGREF String\n    )\n{\n    static PH_STRINGREF backslashAndQuote = PH_STRINGREF_INIT(L\"\\\\\\\"\");\n\n    PH_STRING_BUILDER stringBuilder;\n    ULONG length;\n    ULONG i;\n\n    ULONG numberOfBackslashes;\n\n    length = (ULONG)String->Length / 2;\n    PhInitializeStringBuilder(&stringBuilder, String->Length / 2 * 3);\n    numberOfBackslashes = 0;\n\n    // Simply replacing \" with \\\" won't work here. See PhParseCommandLinePart for the quoting rules.\n\n    for (i = 0; i < length; i++)\n    {\n        switch (String->Buffer[i])\n        {\n        case '\\\\':\n            numberOfBackslashes++;\n            break;\n        case '\\\"':\n            if (numberOfBackslashes != 0)\n            {\n                PhAppendCharStringBuilder2(&stringBuilder, '\\\\', numberOfBackslashes * 2);\n                numberOfBackslashes = 0;\n            }\n\n            PhAppendStringBuilder(&stringBuilder, &backslashAndQuote);\n\n            break;\n        default:\n            if (numberOfBackslashes != 0)\n            {\n                PhAppendCharStringBuilder2(&stringBuilder, '\\\\', numberOfBackslashes);\n                numberOfBackslashes = 0;\n            }\n\n            PhAppendCharStringBuilder(&stringBuilder, String->Buffer[i]);\n\n            break;\n        }\n    }\n\n    return PhFinalStringBuilderString(&stringBuilder);\n}\n\n/**\n * Parses a command line string. If the string does not contain quotation marks around the file name\n * part, the function determines the file name to use.\n *\n * \\param CommandLine The command line string.\n * \\param FileName A variable which receives the part of \\a CommandLine that contains the file name.\n * \\param Arguments A variable which receives the part of \\a CommandLine that contains the\n * arguments.\n * \\param FullFileName A variable which receives the full path and file name. This may be NULL if\n * the file was not found.\n */\nBOOLEAN PhParseCommandLineFuzzy(\n    _In_ PPH_STRINGREF CommandLine,\n    _Out_ PPH_STRINGREF FileName,\n    _Out_ PPH_STRINGREF Arguments,\n    _Out_opt_ PPH_STRING *FullFileName\n    )\n{\n    static PH_STRINGREF whitespace = PH_STRINGREF_INIT(L\" \\t\");\n\n    PH_STRINGREF commandLine;\n    PH_STRINGREF temp;\n    PH_STRINGREF currentPart;\n    PH_STRINGREF remainingPart;\n    WCHAR buffer[MAX_PATH];\n    WCHAR originalChar;\n\n    commandLine = *CommandLine;\n    PhTrimStringRef(&commandLine, &whitespace, 0);\n\n    if (commandLine.Length == 0)\n    {\n        PhInitializeEmptyStringRef(FileName);\n        PhInitializeEmptyStringRef(Arguments);\n\n        if (FullFileName)\n            *FullFileName = NULL;\n\n        return FALSE;\n    }\n\n    if (*commandLine.Buffer == '\"')\n    {\n        PH_STRINGREF arguments;\n\n        PhSkipStringRef(&commandLine, sizeof(WCHAR));\n\n        // Find the matching quote character and we have our file name.\n\n        if (!PhSplitStringRefAtChar(&commandLine, '\"', &commandLine, &arguments))\n        {\n            PhSkipStringRef(&commandLine, -(LONG_PTR)sizeof(WCHAR)); // Unskip the initial quote character\n            *FileName = commandLine;\n            PhInitializeEmptyStringRef(Arguments);\n\n            if (FullFileName)\n                *FullFileName = NULL;\n\n            return FALSE;\n        }\n\n        PhTrimStringRef(&arguments, &whitespace, PH_TRIM_START_ONLY);\n        *FileName = commandLine;\n        *Arguments = arguments;\n\n        if (FullFileName)\n        {\n            PPH_STRING tempCommandLine;\n\n            tempCommandLine = PhCreateString2(&commandLine);\n\n            if (PhSearchFilePath(tempCommandLine->Buffer, L\".exe\", buffer))\n            {\n                *FullFileName = PhCreateString(buffer);\n            }\n            else\n            {\n                *FullFileName = NULL;\n            }\n\n            PhDereferenceObject(tempCommandLine);\n        }\n\n        return TRUE;\n    }\n\n    // Try to find an existing executable file, starting with the first part of the command line and\n    // successively restoring the rest of the command line.\n    // For example, in \"C:\\Program Files\\Internet   Explorer\\iexplore\", we try to match:\n    // * \"C:\\Program\"\n    // * \"C:\\Program Files\\Internet\"\n    // * \"C:\\Program Files\\Internet \"\n    // * \"C:\\Program Files\\Internet  \"\n    // * \"C:\\Program Files\\Internet   Explorer\\iexplore\"\n    //\n    // Note that we do not trim whitespace in each part because filenames can contain trailing\n    // whitespace before the extension (e.g. \"Internet  .exe\").\n\n    temp.Buffer = PhAllocate(commandLine.Length + sizeof(WCHAR));\n    memcpy(temp.Buffer, commandLine.Buffer, commandLine.Length);\n    temp.Buffer[commandLine.Length / sizeof(WCHAR)] = 0;\n    temp.Length = commandLine.Length;\n    remainingPart = temp;\n\n    while (remainingPart.Length != 0)\n    {\n        BOOLEAN found;\n        BOOLEAN result;\n\n        found = PhSplitStringRefAtChar(&remainingPart, ' ', &currentPart, &remainingPart);\n\n        if (found)\n        {\n            originalChar = *(remainingPart.Buffer - 1);\n            *(remainingPart.Buffer - 1) = 0;\n        }\n\n        result = PhSearchFilePath(temp.Buffer, L\".exe\", buffer);\n\n        if (found)\n        {\n            *(remainingPart.Buffer - 1) = originalChar;\n        }\n\n        if (result)\n        {\n            FileName->Buffer = commandLine.Buffer;\n            FileName->Length = ((PCHAR)currentPart.Buffer - (PCHAR)temp.Buffer) + currentPart.Length;\n\n            PhTrimStringRef(&remainingPart, &whitespace, PH_TRIM_START_ONLY);\n            *Arguments = remainingPart;\n\n            if (FullFileName)\n                *FullFileName = PhCreateString(buffer);\n\n            PhFree(temp.Buffer);\n\n            return TRUE;\n        }\n    }\n\n    PhFree(temp.Buffer);\n\n    *FileName = *CommandLine;\n    PhInitializeEmptyStringRef(Arguments);\n\n    if (FullFileName)\n        *FullFileName = NULL;\n\n    return FALSE;\n}\n\nBOOLEAN PhSearchFilePath(\n    _In_ PWSTR FileName,\n    _In_opt_ PWSTR Extension,\n    _Out_writes_(MAX_PATH) PWSTR Buffer\n    )\n{\n    NTSTATUS status;\n    ULONG result;\n    UNICODE_STRING fileName;\n    OBJECT_ATTRIBUTES objectAttributes;\n    FILE_BASIC_INFORMATION basicInfo;\n\n    result = SearchPath(\n        NULL,\n        FileName,\n        Extension,\n        MAX_PATH,\n        Buffer,\n        NULL\n        );\n\n    if (result == 0 || result >= MAX_PATH)\n        return FALSE;\n\n    // Make sure this is not a directory.\n\n    if (!NT_SUCCESS(RtlDosPathNameToNtPathName_U_WithStatus(\n        Buffer,\n        &fileName,\n        NULL,\n        NULL\n        )))\n        return FALSE;\n\n    InitializeObjectAttributes(\n        &objectAttributes,\n        &fileName,\n        OBJ_CASE_INSENSITIVE,\n        NULL,\n        NULL\n        );\n\n    status = NtQueryAttributesFile(&objectAttributes, &basicInfo);\n    RtlFreeUnicodeString(&fileName);\n\n    if (!NT_SUCCESS(status))\n        return FALSE;\n    if (basicInfo.FileAttributes & FILE_ATTRIBUTE_DIRECTORY)\n        return FALSE;\n\n    return TRUE;\n}\n\n\nPPH_STRING PhGetCacheDirectory(\n    VOID\n    )\n{\n    return PhGetKnownLocation(CSIDL_LOCAL_APPDATA, L\"\\\\Process Hacker\\\\Cache\");\n}\n\nVOID PhClearCacheDirectory(\n    VOID\n    )\n{\n    PPH_STRING cacheDirectory;\n\n    cacheDirectory = PhGetCacheDirectory();\n    PhDeleteDirectory(cacheDirectory);\n\n    PhDereferenceObject(cacheDirectory);\n}\n\nPPH_STRING PhCreateCacheFile(\n    _In_ PPH_STRING FileName\n    )\n{\n    PPH_STRING cacheDirectory;\n    PPH_STRING cacheFilePath;\n    PPH_STRING cacheFullFilePath = NULL;\n    ULONG indexOfFileName = -1;\n    WCHAR alphastring[16] = L\"\";\n\n    cacheDirectory = PhGetCacheDirectory();\n    PhGenerateRandomAlphaString(alphastring, ARRAYSIZE(alphastring));\n\n    cacheFilePath = PhConcatStrings(\n        5,\n        PhGetStringOrEmpty(cacheDirectory),\n        L\"\\\\\",\n        alphastring,\n        L\"\\\\\",\n        PhGetStringOrEmpty(FileName)\n        );\n\n    if (cacheFullFilePath = PhGetFullPath(PhGetString(cacheFilePath), &indexOfFileName))\n    {\n        PPH_STRING directoryPath;\n\n        if (indexOfFileName != -1 && (directoryPath = PhSubstring(cacheFullFilePath, 0, indexOfFileName)))\n        {\n            PhCreateDirectory(directoryPath);\n            PhDereferenceObject(directoryPath);\n        }\n    }\n\n    PhDereferenceObject(cacheFilePath);\n    PhDereferenceObject(cacheDirectory);\n\n    return cacheFullFilePath;\n}\n\nVOID PhDeleteCacheFile(\n    _In_ PPH_STRING FileName\n    )\n{\n    PPH_STRING cacheDirectory;\n    PPH_STRING cacheFullFilePath;\n    ULONG indexOfFileName = -1;\n\n    if (RtlDoesFileExists_U(PhGetString(FileName)))\n    {\n        PhDeleteFileWin32(PhGetString(FileName));\n    }\n\n    if (cacheFullFilePath = PhGetFullPath(PhGetString(FileName), &indexOfFileName))\n    {\n        if (indexOfFileName != -1 && (cacheDirectory = PhSubstring(cacheFullFilePath, 0, indexOfFileName)))\n        {\n            PhDeleteDirectory(cacheDirectory);\n            PhDereferenceObject(cacheDirectory);\n        }\n\n        PhDereferenceObject(cacheFullFilePath);\n    }\n}\n\nHANDLE PhGetNamespaceHandle(\n    VOID\n    )\n{\n    static PH_INITONCE initOnce = PH_INITONCE_INIT;\n    static UNICODE_STRING namespacePathUs = RTL_CONSTANT_STRING(L\"\\\\BaseNamedObjects\\\\ProcessHacker\");\n    static HANDLE directory = NULL;\n\n    if (PhBeginInitOnce(&initOnce))\n    {\n        static SID_IDENTIFIER_AUTHORITY ntAuthority = SECURITY_NT_AUTHORITY;\n        OBJECT_ATTRIBUTES objectAttributes;\n        PSECURITY_DESCRIPTOR securityDescriptor;\n        ULONG sdAllocationLength;\n        UCHAR administratorsSidBuffer[FIELD_OFFSET(SID, SubAuthority) + sizeof(ULONG) * 2];\n        PSID administratorsSid;\n        PACL dacl;\n\n        // Create the default namespace DACL.\n\n        administratorsSid = (PSID)administratorsSidBuffer;\n        RtlInitializeSid(administratorsSid, &ntAuthority, 2);\n        *RtlSubAuthoritySid(administratorsSid, 0) = SECURITY_BUILTIN_DOMAIN_RID;\n        *RtlSubAuthoritySid(administratorsSid, 1) = DOMAIN_ALIAS_RID_ADMINS;\n\n        sdAllocationLength = SECURITY_DESCRIPTOR_MIN_LENGTH +\n            (ULONG)sizeof(ACL) +\n            (ULONG)sizeof(ACCESS_ALLOWED_ACE) +\n            RtlLengthSid(&PhSeLocalSid) +\n            (ULONG)sizeof(ACCESS_ALLOWED_ACE) +\n            RtlLengthSid(administratorsSid) +\n            (ULONG)sizeof(ACCESS_ALLOWED_ACE) +\n            RtlLengthSid(&PhSeInteractiveSid);\n\n        securityDescriptor = PhAllocate(sdAllocationLength);\n        dacl = (PACL)PTR_ADD_OFFSET(securityDescriptor, SECURITY_DESCRIPTOR_MIN_LENGTH);\n\n        RtlCreateSecurityDescriptor(securityDescriptor, SECURITY_DESCRIPTOR_REVISION);\n        RtlCreateAcl(dacl, sdAllocationLength - SECURITY_DESCRIPTOR_MIN_LENGTH, ACL_REVISION);\n        RtlAddAccessAllowedAce(dacl, ACL_REVISION, DIRECTORY_ALL_ACCESS, &PhSeLocalSid);\n        RtlAddAccessAllowedAce(dacl, ACL_REVISION, DIRECTORY_ALL_ACCESS, administratorsSid);\n        RtlAddAccessAllowedAce(dacl, ACL_REVISION, DIRECTORY_QUERY | DIRECTORY_TRAVERSE | DIRECTORY_CREATE_OBJECT, &PhSeInteractiveSid);\n        RtlSetDaclSecurityDescriptor(securityDescriptor, TRUE, dacl, FALSE);\n\n        InitializeObjectAttributes(\n            &objectAttributes,\n            &namespacePathUs,\n            OBJ_OPENIF,\n            NULL,\n            securityDescriptor\n            );\n\n        NtCreateDirectoryObject(\n            &directory,\n            MAXIMUM_ALLOWED,\n            &objectAttributes\n            );\n\n        PhFree(securityDescriptor);\n\n        PhEndInitOnce(&initOnce);\n    }\n\n    return directory;\n}\n\nBOOLEAN PhLoadResource(\n    _In_ PVOID DllBase,\n    _In_ PCWSTR Name,\n    _In_ PCWSTR Type,\n    _Out_opt_ ULONG *ResourceLength,\n    _Out_ PVOID *ResourceBuffer\n    )\n{\n    LDR_RESOURCE_INFO resourceInfo;\n    PIMAGE_RESOURCE_DATA_ENTRY resourceData;\n    ULONG resourceLength;\n    PVOID resourceBuffer;\n\n    resourceInfo.Type = (ULONG_PTR)Type;\n    resourceInfo.Name = (ULONG_PTR)Name;\n    resourceInfo.Language = MAKELANGID(LANG_NEUTRAL, SUBLANG_NEUTRAL);\n\n    if (!NT_SUCCESS(LdrFindResource_U(DllBase, &resourceInfo, RESOURCE_DATA_LEVEL, &resourceData)))\n        return FALSE;\n\n    if (!NT_SUCCESS(LdrAccessResource(DllBase, resourceData, &resourceBuffer, &resourceLength)))\n        return FALSE;\n\n    if (ResourceLength)\n        *ResourceLength = resourceLength;\n    *ResourceBuffer = PhAllocateCopy(resourceBuffer, resourceLength);\n\n    return TRUE;\n}\n\nPPH_STRING PhLoadString(\n    _In_ PVOID DllBase,\n    _In_ ULONG ResourceId\n    )\n{\n    PPH_STRING string = NULL;\n    ULONG resourceLength;\n    PVOID resourceBuffer;\n    ULONG stringCount;\n    PWSTR stringBuffer;\n    ULONG i;\n\n    if (!PhLoadResource(\n        DllBase,\n        MAKEINTRESOURCE((LOWORD(ResourceId) >> 4) + 1),\n        RT_STRING,\n        &resourceLength,\n        &resourceBuffer\n        ))\n    {\n        return NULL;\n    }\n\n    stringBuffer = resourceBuffer;\n    stringCount = ResourceId & 0x000F;\n\n    for (i = 0; i < stringCount; i++) // dmex: Copied from ReactOS.\n    {\n        stringBuffer += *stringBuffer + 1;\n    }\n\n    i = min(resourceLength - 1, *stringBuffer);\n\n    if (i > 0)\n    {\n        string = PhCreateStringEx(stringBuffer + 1, i * sizeof(WCHAR));\n    }\n\n    PhFree(resourceBuffer);\n    return string;\n}\n\n// rev from SHLoadIndirectString\n/**\n * Extracts a specified text resource when given that resource in the form of an indirect string (a string that begins with the '@' symbol).\n *\n * \\param SourceString The indirect string from which the resource will be retrieved.\n */\nPPH_STRING PhLoadIndirectString(\n    _In_ PWSTR SourceString\n    )\n{\n    PPH_STRING indirectString = NULL;\n\n    if (SourceString[0] == L'@')\n    {\n        PPH_STRING libraryString;\n        PVOID libraryModule;\n        PH_STRINGREF sourceRef;\n        PH_STRINGREF dllNameRef;\n        PH_STRINGREF dllIndexRef;\n        ULONG64 index64;\n        LONG index;\n\n        PhInitializeStringRefLongHint(&sourceRef, SourceString);\n        PhSkipStringRef(&sourceRef, sizeof(WCHAR)); // Skip the @ character.\n\n        if (!PhSplitStringRefAtChar(&sourceRef, L',', &dllNameRef, &dllIndexRef))\n            return NULL;\n        if (!PhStringToInteger64(&dllIndexRef, 10, &index64))\n            return NULL;\n\n        libraryString = PhCreateString2(&dllNameRef);\n        index = (LONG)index64;\n\n        if (libraryString->Buffer[0] == L'%')\n        {\n            PPH_STRING expandedString;\n\n            if (expandedString = PhExpandEnvironmentStrings(&libraryString->sr))\n                PhMoveReference(&libraryString, expandedString);\n        }\n\n        if (libraryModule = LoadLibraryEx(libraryString->Buffer, NULL, LOAD_LIBRARY_AS_DATAFILE))\n        { \n            indirectString = PhLoadString(libraryModule, -index);\n            FreeLibrary(libraryModule);\n        }\n\n        PhDereferenceObject(libraryString);\n    }\n    else\n    {\n        //indirectString = PhCreateString(SourceString);\n    }\n\n    return indirectString;\n}\n\n// rev from ExtractIconExW\nBOOLEAN PhExtractIcon(\n    _In_ PWSTR FileName, \n    _In_ HICON *IconLarge,\n    _In_ HICON *IconSmall\n    )\n{\n    static PH_INITONCE initOnce = PH_INITONCE_INIT;\n    static UINT (WINAPI *PrivateExtractIconExW)(PCWSTR, INT, HICON*, HICON*, UINT) = NULL;\n\n    if (PhBeginInitOnce(&initOnce))\n    {\n        if (!PrivateExtractIconExW)\n            PrivateExtractIconExW = PhGetModuleProcAddress(L\"user32.dll\", \"PrivateExtractIconExW\");\n\n        PhEndInitOnce(&initOnce);\n    }\n\n    if (!PrivateExtractIconExW)\n        return FALSE;\n\n    return PrivateExtractIconExW(FileName, 0, IconLarge, IconSmall, 1) > 0;\n}"
  },
  {
    "path": "third_party/phlib/verify.c",
    "content": "/*\n * Process Hacker -\n *   image verification\n *\n * Copyright (C) 2009-2013 wj32\n *\n * This file is part of Process Hacker.\n *\n * Process Hacker is free software; you can redistribute it and/or modify\n * it under the terms of the GNU General Public License as published by\n * the Free Software Foundation, either version 3 of the License, or\n * (at your option) any later version.\n *\n * Process Hacker is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n * GNU General Public License for more details.\n *\n * You should have received a copy of the GNU General Public License\n * along with Process Hacker.  If not, see <http://www.gnu.org/licenses/>.\n */\n\n#include <ph.h>\n#include <verify.h>\n#include <verifyp.h>\n\n_CryptCATAdminCalcHashFromFileHandle CryptCATAdminCalcHashFromFileHandle;\n_CryptCATAdminCalcHashFromFileHandle2 CryptCATAdminCalcHashFromFileHandle2;\n_CryptCATAdminAcquireContext CryptCATAdminAcquireContext;\n_CryptCATAdminAcquireContext2 CryptCATAdminAcquireContext2;\n_CryptCATAdminEnumCatalogFromHash CryptCATAdminEnumCatalogFromHash;\n_CryptCATCatalogInfoFromContext CryptCATCatalogInfoFromContext;\n_CryptCATAdminReleaseCatalogContext CryptCATAdminReleaseCatalogContext;\n_CryptCATAdminReleaseContext CryptCATAdminReleaseContext;\n_WTHelperProvDataFromStateData WTHelperProvDataFromStateData_I;\n_WTHelperGetProvSignerFromChain WTHelperGetProvSignerFromChain_I;\n_WinVerifyTrust WinVerifyTrust_I;\n_CertNameToStr CertNameToStr_I;\n_CertDuplicateCertificateContext CertDuplicateCertificateContext_I;\n_CertFreeCertificateContext CertFreeCertificateContext_I;\nstatic PH_INITONCE PhpVerifyInitOnce = PH_INITONCE_INIT;\n\nstatic GUID WinTrustActionGenericVerifyV2 = WINTRUST_ACTION_GENERIC_VERIFY_V2;\nstatic GUID DriverActionVerify = DRIVER_ACTION_VERIFY;\n\nstatic VOID PhpVerifyInitialization(\n    VOID\n    )\n{\n    HMODULE wintrust;\n    HMODULE crypt32;\n\n    wintrust = LoadLibrary(L\"wintrust.dll\");\n    crypt32 = LoadLibrary(L\"crypt32.dll\");\n\n    CryptCATAdminCalcHashFromFileHandle = PhGetProcedureAddress(wintrust, \"CryptCATAdminCalcHashFromFileHandle\", 0);\n    CryptCATAdminCalcHashFromFileHandle2 = PhGetProcedureAddress(wintrust, \"CryptCATAdminCalcHashFromFileHandle2\", 0);\n    CryptCATAdminAcquireContext = PhGetProcedureAddress(wintrust, \"CryptCATAdminAcquireContext\", 0);\n    CryptCATAdminAcquireContext2 = PhGetProcedureAddress(wintrust, \"CryptCATAdminAcquireContext2\", 0);\n    CryptCATAdminEnumCatalogFromHash = PhGetProcedureAddress(wintrust, \"CryptCATAdminEnumCatalogFromHash\", 0);\n    CryptCATCatalogInfoFromContext = PhGetProcedureAddress(wintrust, \"CryptCATCatalogInfoFromContext\", 0);\n    CryptCATAdminReleaseCatalogContext = PhGetProcedureAddress(wintrust, \"CryptCATAdminReleaseCatalogContext\", 0);\n    CryptCATAdminReleaseContext = PhGetProcedureAddress(wintrust, \"CryptCATAdminReleaseContext\", 0);\n    WTHelperProvDataFromStateData_I = PhGetProcedureAddress(wintrust, \"WTHelperProvDataFromStateData\", 0);\n    WTHelperGetProvSignerFromChain_I = PhGetProcedureAddress(wintrust, \"WTHelperGetProvSignerFromChain\", 0);\n    WinVerifyTrust_I = PhGetProcedureAddress(wintrust, \"WinVerifyTrust\", 0);\n    CertNameToStr_I = PhGetProcedureAddress(crypt32, \"CertNameToStrW\", 0);\n    CertDuplicateCertificateContext_I = PhGetProcedureAddress(crypt32, \"CertDuplicateCertificateContext\", 0);\n    CertFreeCertificateContext_I = PhGetProcedureAddress(crypt32, \"CertFreeCertificateContext\", 0);\n}\n\nVERIFY_RESULT PhpStatusToVerifyResult(\n    _In_ LONG Status\n    )\n{\n    switch (Status)\n    {\n    case 0:\n        return VrTrusted;\n    case TRUST_E_NOSIGNATURE:\n        return VrNoSignature;\n    case CERT_E_EXPIRED:\n        return VrExpired;\n    case CERT_E_REVOKED:\n        return VrRevoked;\n    case TRUST_E_EXPLICIT_DISTRUST:\n        return VrDistrust;\n    case CRYPT_E_SECURITY_SETTINGS:\n        return VrSecuritySettings;\n    case TRUST_E_BAD_DIGEST:\n        return VrBadSignature;\n    default:\n        return VrSecuritySettings;\n    }\n}\n\nBOOLEAN PhpGetSignaturesFromStateData(\n    _In_ HANDLE StateData,\n    _Out_ PCERT_CONTEXT **Signatures,\n    _Out_ PULONG NumberOfSignatures\n    )\n{\n    PCRYPT_PROVIDER_DATA provData;\n    PCRYPT_PROVIDER_SGNR sgnr;\n    PCERT_CONTEXT *signatures;\n    ULONG i;\n    ULONG numberOfSignatures;\n    ULONG index;\n\n    provData = WTHelperProvDataFromStateData_I(StateData);\n\n    if (!provData)\n    {\n        *Signatures = NULL;\n        *NumberOfSignatures = 0;\n        return FALSE;\n    }\n\n    i = 0;\n    numberOfSignatures = 0;\n\n    while (sgnr = WTHelperGetProvSignerFromChain_I(provData, i, FALSE, 0))\n    {\n        if (sgnr->csCertChain != 0)\n            numberOfSignatures++;\n\n        i++;\n    }\n\n    if (numberOfSignatures != 0)\n    {\n        signatures = PhAllocate(numberOfSignatures * sizeof(PCERT_CONTEXT));\n        i = 0;\n        index = 0;\n\n        while (sgnr = WTHelperGetProvSignerFromChain_I(provData, i, FALSE, 0))\n        {\n            if (sgnr->csCertChain != 0)\n                signatures[index++] = (PCERT_CONTEXT)CertDuplicateCertificateContext_I(sgnr->pasCertChain[0].pCert);\n\n            i++;\n        }\n    }\n    else\n    {\n        signatures = NULL;\n    }\n\n    *Signatures = signatures;\n    *NumberOfSignatures = numberOfSignatures;\n\n    return TRUE;\n}\n\nVOID PhpViewSignerInfo(\n    _In_ PPH_VERIFY_FILE_INFO Information,\n    _In_ HANDLE StateData\n    )\n{\n    static PH_INITONCE initOnce = PH_INITONCE_INIT;\n    static _CryptUIDlgViewSignerInfo cryptUIDlgViewSignerInfo;\n\n    if (PhBeginInitOnce(&initOnce))\n    {\n        HMODULE cryptui = LoadLibrary(L\"cryptui.dll\");\n\n        cryptUIDlgViewSignerInfo = PhGetProcedureAddress(cryptui, \"CryptUIDlgViewSignerInfoW\", 0);\n        PhEndInitOnce(&initOnce);\n    }\n\n    if (cryptUIDlgViewSignerInfo)\n    {\n        CRYPTUI_VIEWSIGNERINFO_STRUCT viewSignerInfo = { sizeof(CRYPTUI_VIEWSIGNERINFO_STRUCT) };\n        PCRYPT_PROVIDER_DATA provData;\n        PCRYPT_PROVIDER_SGNR sgnr;\n\n        if (!(provData = WTHelperProvDataFromStateData_I(StateData)))\n            return;\n        if (!(sgnr = WTHelperGetProvSignerFromChain_I(provData, 0, FALSE, 0)))\n            return;\n\n        viewSignerInfo.hwndParent = Information->hWnd;\n        viewSignerInfo.pSignerInfo = sgnr->psSigner;\n        viewSignerInfo.hMsg = provData->hMsg;\n        viewSignerInfo.pszOID = szOID_PKIX_KP_CODE_SIGNING;\n        cryptUIDlgViewSignerInfo(&viewSignerInfo);\n    }\n}\n\nVERIFY_RESULT PhpVerifyFile(\n    _In_ PPH_VERIFY_FILE_INFO Information,\n    _In_ ULONG UnionChoice,\n    _In_ PVOID UnionData,\n    _In_ PGUID ActionId,\n    _In_opt_ PVOID PolicyCallbackData,\n    _Out_ PCERT_CONTEXT **Signatures,\n    _Out_ PULONG NumberOfSignatures\n    )\n{\n    LONG status;\n    WINTRUST_DATA trustData = { 0 };\n\n    trustData.cbStruct = sizeof(WINTRUST_DATA);\n    trustData.pPolicyCallbackData = PolicyCallbackData;\n    trustData.dwUIChoice = WTD_UI_NONE;\n    trustData.fdwRevocationChecks = WTD_REVOKE_WHOLECHAIN;\n    trustData.dwUnionChoice = UnionChoice;\n    trustData.dwStateAction = WTD_STATEACTION_VERIFY;\n    trustData.dwProvFlags = WTD_SAFER_FLAG;\n\n    trustData.pFile = UnionData;\n\n    if (UnionChoice == WTD_CHOICE_CATALOG)\n        trustData.pCatalog = UnionData;\n\n    if (Information->Flags & PH_VERIFY_PREVENT_NETWORK_ACCESS)\n    {\n        trustData.fdwRevocationChecks = WTD_REVOKE_NONE;\n        trustData.dwProvFlags |= WTD_CACHE_ONLY_URL_RETRIEVAL;\n    }\n\n    status = WinVerifyTrust_I(INVALID_HANDLE_VALUE, ActionId, &trustData);\n    PhpGetSignaturesFromStateData(trustData.hWVTStateData, Signatures, NumberOfSignatures);\n\n    if (status == 0 && (Information->Flags & PH_VERIFY_VIEW_PROPERTIES))\n        PhpViewSignerInfo(Information, trustData.hWVTStateData);\n\n    // Close the state data.\n    trustData.dwStateAction = WTD_STATEACTION_CLOSE;\n    WinVerifyTrust_I(INVALID_HANDLE_VALUE, ActionId, &trustData);\n\n    return PhpStatusToVerifyResult(status);\n}\n\nBOOLEAN PhpCalculateFileHash(\n    _In_ HANDLE FileHandle,\n    _In_ PWSTR HashAlgorithm,\n    _Out_ PUCHAR *FileHash,\n    _Out_ PULONG FileHashLength,\n    _Out_ HANDLE *CatAdminHandle\n    )\n{\n    HANDLE catAdminHandle;\n    PUCHAR fileHash;\n    ULONG fileHashLength;\n\n    if (CryptCATAdminAcquireContext2)\n    {\n        if (!CryptCATAdminAcquireContext2(&catAdminHandle, &DriverActionVerify, HashAlgorithm, NULL, 0))\n            return FALSE;\n    }\n    else\n    {\n        if (!CryptCATAdminAcquireContext(&catAdminHandle, &DriverActionVerify, 0))\n            return FALSE;\n    }\n\n    fileHashLength = 32;\n    fileHash = PhAllocate(fileHashLength);\n\n    if (CryptCATAdminCalcHashFromFileHandle2)\n    {\n        if (!CryptCATAdminCalcHashFromFileHandle2(catAdminHandle, FileHandle, &fileHashLength, fileHash, 0))\n        {\n            PhFree(fileHash);\n            fileHash = PhAllocate(fileHashLength);\n\n            if (!CryptCATAdminCalcHashFromFileHandle2(catAdminHandle, FileHandle, &fileHashLength, fileHash, 0))\n            {\n                CryptCATAdminReleaseContext(catAdminHandle, 0);\n                PhFree(fileHash);\n                return FALSE;\n            }\n        }\n    }\n    else\n    {\n        if (!CryptCATAdminCalcHashFromFileHandle(FileHandle, &fileHashLength, fileHash, 0))\n        {\n            PhFree(fileHash);\n            fileHash = PhAllocate(fileHashLength);\n\n            if (!CryptCATAdminCalcHashFromFileHandle(FileHandle, &fileHashLength, fileHash, 0))\n            {\n                CryptCATAdminReleaseContext(catAdminHandle, 0);\n                PhFree(fileHash);\n                return FALSE;\n            }\n        }\n    }\n\n    *FileHash = fileHash;\n    *FileHashLength = fileHashLength;\n    *CatAdminHandle = catAdminHandle;\n\n    return TRUE;\n}\n\nVERIFY_RESULT PhpVerifyFileFromCatalog(\n    _In_ PPH_VERIFY_FILE_INFO Information,\n    _In_ HANDLE FileHandle,\n    _In_opt_ PWSTR HashAlgorithm,\n    _Out_ PCERT_CONTEXT **Signatures,\n    _Out_ PULONG NumberOfSignatures\n    )\n{\n    VERIFY_RESULT verifyResult = VrNoSignature;\n    PCERT_CONTEXT *signatures;\n    ULONG numberOfSignatures;\n    WINTRUST_CATALOG_INFO catalogInfo = { 0 };\n    LARGE_INTEGER fileSize;\n    ULONG fileSizeLimit;\n    PUCHAR fileHash;\n    ULONG fileHashLength;\n    PPH_STRING fileHashTag;\n    HANDLE catAdminHandle;\n    HANDLE catInfoHandle;\n    ULONG i;\n\n    *Signatures = NULL;\n    *NumberOfSignatures = 0;\n\n    if (!NT_SUCCESS(PhGetFileSize(FileHandle, &fileSize)))\n        return VrNoSignature;\n\n    signatures = NULL;\n    numberOfSignatures = 0;\n\n    if (Information->FileSizeLimitForHash != -1)\n    {\n        fileSizeLimit = PH_VERIFY_DEFAULT_SIZE_LIMIT;\n\n        if (Information->FileSizeLimitForHash != 0)\n            fileSizeLimit = Information->FileSizeLimitForHash;\n\n        if (fileSize.QuadPart > fileSizeLimit)\n            return VrNoSignature;\n    }\n\n    if (PhpCalculateFileHash(FileHandle, HashAlgorithm, &fileHash, &fileHashLength, &catAdminHandle))\n    {\n        fileHashTag = PhBufferToHexStringEx(fileHash, fileHashLength, TRUE);\n\n        // Search the system catalogs.\n\n        catInfoHandle = CryptCATAdminEnumCatalogFromHash(\n            catAdminHandle,\n            fileHash,\n            fileHashLength,\n            0,\n            NULL\n            );\n\n        if (catInfoHandle)\n        {\n            CATALOG_INFO ci = { 0 };\n            DRIVER_VER_INFO verInfo = { 0 };\n\n            if (CryptCATCatalogInfoFromContext(catInfoHandle, &ci, 0))\n            {\n                // Disable OS version checking by passing in a DRIVER_VER_INFO structure.\n                verInfo.cbStruct = sizeof(DRIVER_VER_INFO);\n\n                catalogInfo.cbStruct = sizeof(catalogInfo);\n                catalogInfo.pcwszCatalogFilePath = ci.wszCatalogFile;\n                catalogInfo.pcwszMemberFilePath = Information->FileName;\n                catalogInfo.hMemberFile = FileHandle;\n                catalogInfo.pcwszMemberTag = fileHashTag->Buffer;\n                catalogInfo.pbCalculatedFileHash = fileHash;\n                catalogInfo.cbCalculatedFileHash = fileHashLength;\n                catalogInfo.hCatAdmin = catAdminHandle;\n                verifyResult = PhpVerifyFile(Information, WTD_CHOICE_CATALOG, &catalogInfo, &DriverActionVerify, &verInfo, &signatures, &numberOfSignatures);\n\n                if (verInfo.pcSignerCertContext)\n                    CertFreeCertificateContext_I(verInfo.pcSignerCertContext);\n            }\n\n            CryptCATAdminReleaseCatalogContext(catAdminHandle, catInfoHandle, 0);\n        }\n        else\n        {\n            // Search any user-supplied catalogs.\n\n            for (i = 0; i < Information->NumberOfCatalogFileNames; i++)\n            {\n                PhFreeVerifySignatures(signatures, numberOfSignatures);\n\n                catalogInfo.cbStruct = sizeof(catalogInfo);\n                catalogInfo.pcwszCatalogFilePath = Information->CatalogFileNames[i];\n                catalogInfo.pcwszMemberFilePath = Information->FileName;\n                catalogInfo.hMemberFile = FileHandle;\n                catalogInfo.pcwszMemberTag = fileHashTag->Buffer;\n                catalogInfo.pbCalculatedFileHash = fileHash;\n                catalogInfo.cbCalculatedFileHash = fileHashLength;\n                catalogInfo.hCatAdmin = catAdminHandle;\n                verifyResult = PhpVerifyFile(Information, WTD_CHOICE_CATALOG, &catalogInfo, &WinTrustActionGenericVerifyV2, NULL, &signatures, &numberOfSignatures);\n\n                if (verifyResult == VrTrusted)\n                    break;\n            }\n        }\n\n        PhDereferenceObject(fileHashTag);\n        PhFree(fileHash);\n        CryptCATAdminReleaseContext(catAdminHandle, 0);\n    }\n\n    *Signatures = signatures;\n    *NumberOfSignatures = numberOfSignatures;\n\n    return verifyResult;\n}\n\nNTSTATUS PhVerifyFileEx(\n    _In_ PPH_VERIFY_FILE_INFO Information,\n    _Out_ VERIFY_RESULT *VerifyResult,\n    _Out_opt_ PCERT_CONTEXT **Signatures,\n    _Out_opt_ PULONG NumberOfSignatures\n    )\n{\n    NTSTATUS status;\n    HANDLE fileHandle;\n    VERIFY_RESULT verifyResult;\n    PCERT_CONTEXT *signatures;\n    ULONG numberOfSignatures;\n    WINTRUST_FILE_INFO fileInfo = { 0 };\n\n    if (PhBeginInitOnce(&PhpVerifyInitOnce))\n    {\n        PhpVerifyInitialization();\n        PhEndInitOnce(&PhpVerifyInitOnce);\n    }\n\n    // Make sure we have successfully imported the required functions.\n    if (\n        !CryptCATAdminCalcHashFromFileHandle ||\n        !CryptCATAdminAcquireContext ||\n        !CryptCATAdminEnumCatalogFromHash ||\n        !CryptCATCatalogInfoFromContext ||\n        !CryptCATAdminReleaseCatalogContext ||\n        !CryptCATAdminReleaseContext ||\n        !WinVerifyTrust_I ||\n        !WTHelperProvDataFromStateData_I ||\n        !WTHelperGetProvSignerFromChain_I ||\n        !CertNameToStr_I ||\n        !CertDuplicateCertificateContext_I ||\n        !CertFreeCertificateContext_I\n        )\n        return STATUS_NOT_SUPPORTED;\n\n    if (!NT_SUCCESS(status = PhCreateFileWin32(\n        &fileHandle,\n        Information->FileName,\n        FILE_GENERIC_READ,\n        FILE_ATTRIBUTE_NORMAL,\n        FILE_SHARE_READ | FILE_SHARE_DELETE,\n        FILE_OPEN,\n        FILE_NON_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT\n        )))\n        return status;\n\n    fileInfo.cbStruct = sizeof(WINTRUST_FILE_INFO);\n    fileInfo.pcwszFilePath = Information->FileName;\n    fileInfo.hFile = fileHandle;\n\n    verifyResult = PhpVerifyFile(Information, WTD_CHOICE_FILE, &fileInfo, &WinTrustActionGenericVerifyV2, NULL, &signatures, &numberOfSignatures);\n\n    if (verifyResult == VrNoSignature)\n    {\n        if (CryptCATAdminAcquireContext2 && CryptCATAdminCalcHashFromFileHandle2)\n        {\n            PhFreeVerifySignatures(signatures, numberOfSignatures);\n            verifyResult = PhpVerifyFileFromCatalog(Information, fileHandle, BCRYPT_SHA256_ALGORITHM, &signatures, &numberOfSignatures);\n        }\n\n        if (verifyResult != VrTrusted)\n        {\n            PhFreeVerifySignatures(signatures, numberOfSignatures);\n            verifyResult = PhpVerifyFileFromCatalog(Information, fileHandle, NULL, &signatures, &numberOfSignatures);\n        }\n    }\n\n    *VerifyResult = verifyResult;\n\n    if (Signatures)\n        *Signatures = signatures;\n    else\n        PhFreeVerifySignatures(signatures, numberOfSignatures);\n\n    if (NumberOfSignatures)\n        *NumberOfSignatures = numberOfSignatures;\n\n    NtClose(fileHandle);\n\n    return STATUS_SUCCESS;\n}\n\nVOID PhFreeVerifySignatures(\n    _In_ PCERT_CONTEXT *Signatures,\n    _In_ ULONG NumberOfSignatures\n    )\n{\n    ULONG i;\n\n    if (Signatures)\n    {\n        for (i = 0; i < NumberOfSignatures; i++)\n            CertFreeCertificateContext_I(Signatures[i]);\n\n        PhFree(Signatures);\n    }\n}\n\nPPH_STRING PhpGetCertNameString(\n    _In_ PCERT_NAME_BLOB Blob\n    )\n{\n    PPH_STRING string;\n    ULONG bufferSize;\n\n    // CertNameToStr doesn't give us the correct buffer size unless we don't provide a buffer at\n    // all.\n    bufferSize = CertNameToStr_I(\n        X509_ASN_ENCODING,\n        Blob,\n        CERT_X500_NAME_STR,\n        NULL,\n        0\n        );\n\n    string = PhCreateStringEx(NULL, bufferSize * sizeof(WCHAR));\n    CertNameToStr_I(\n        X509_ASN_ENCODING,\n        Blob,\n        CERT_X500_NAME_STR,\n        string->Buffer,\n        bufferSize\n        );\n\n    PhTrimToNullTerminatorString(string);\n\n    return string;\n}\n\nPPH_STRING PhpGetX500Value(\n    _In_ PPH_STRINGREF String,\n    _In_ PPH_STRINGREF KeyName\n    )\n{\n    WCHAR keyNamePlusEqualsBuffer[10];\n    PH_STRINGREF keyNamePlusEquals;\n    SIZE_T keyNameLength;\n    PH_STRINGREF firstPart;\n    PH_STRINGREF remainingPart;\n\n    keyNameLength = KeyName->Length / sizeof(WCHAR);\n    assert(!(keyNameLength > sizeof(keyNamePlusEquals) / sizeof(WCHAR) - 1));\n    keyNamePlusEquals.Buffer = keyNamePlusEqualsBuffer;\n    keyNamePlusEquals.Length = (keyNameLength + 1) * sizeof(WCHAR);\n\n    memcpy(keyNamePlusEquals.Buffer, KeyName->Buffer, KeyName->Length);\n    keyNamePlusEquals.Buffer[keyNameLength] = '=';\n\n    // Find \"Key=\".\n\n    if (!PhSplitStringRefAtString(String, &keyNamePlusEquals, FALSE, &firstPart, &remainingPart))\n        return NULL;\n    if (remainingPart.Length == 0)\n        return NULL;\n\n    // Is the value quoted? If so, return the part inside the quotes.\n    if (remainingPart.Buffer[0] == '\"')\n    {\n        PhSkipStringRef(&remainingPart, sizeof(WCHAR));\n\n        if (!PhSplitStringRefAtChar(&remainingPart, '\"', &firstPart, &remainingPart))\n            return NULL;\n\n        return PhCreateString2(&firstPart);\n    }\n    else\n    {\n        PhSplitStringRefAtChar(&remainingPart, ',', &firstPart, &remainingPart);\n\n        return PhCreateString2(&firstPart);\n    }\n}\n\nPPH_STRING PhGetSignerNameFromCertificate(\n    _In_ PCERT_CONTEXT Certificate\n    )\n{\n    PCERT_INFO certInfo;\n    PH_STRINGREF keyName;\n    PPH_STRING name;\n    PPH_STRING value;\n\n    // Cert context -> Cert info\n\n    certInfo = Certificate->pCertInfo;\n\n    if (!certInfo)\n        return NULL;\n\n    // Cert info subject -> Subject X.500 string\n\n    name = PhpGetCertNameString(&certInfo->Subject);\n\n    // Subject X.500 string -> CN or OU value\n\n    PhInitializeStringRef(&keyName, L\"CN\");\n    value = PhpGetX500Value(&name->sr, &keyName);\n\n    if (!value)\n    {\n        PhInitializeStringRef(&keyName, L\"OU\");\n        value = PhpGetX500Value(&name->sr, &keyName);\n    }\n\n    PhDereferenceObject(name);\n\n    return value;\n}\n\n/**\n * Verifies a file's digital signature.\n *\n * \\param FileName A file name.\n * \\param SignerName A variable which receives a pointer to a string containing the signer name. You\n * must free the string using PhDereferenceObject() when you no longer need it. Note that the signer\n * name may be NULL if it is not valid.\n *\n * \\return A VERIFY_RESULT value.\n */\nVERIFY_RESULT PhVerifyFile(\n    _In_ PWSTR FileName,\n    _Out_opt_ PPH_STRING *SignerName\n    )\n{\n    PH_VERIFY_FILE_INFO info = { 0 };\n    VERIFY_RESULT verifyResult;\n    PCERT_CONTEXT *signatures;\n    ULONG numberOfSignatures;\n\n    info.FileName = FileName;\n    info.Flags = PH_VERIFY_PREVENT_NETWORK_ACCESS;\n\n    if (NT_SUCCESS(PhVerifyFileEx(&info, &verifyResult, &signatures, &numberOfSignatures)))\n    {\n        if (SignerName)\n        {\n            *SignerName = NULL;\n\n            if (numberOfSignatures != 0)\n                *SignerName = PhGetSignerNameFromCertificate(signatures[0]);\n        }\n\n        PhFreeVerifySignatures(signatures, numberOfSignatures);\n        return verifyResult;\n    }\n    else\n    {\n        if (SignerName)\n            *SignerName = NULL;\n\n        return VrNoSignature;\n    }\n}\n"
  },
  {
    "path": "third_party/phlib/workqueue.c",
    "content": "/*\n * Process Hacker -\n *   thread pool / work queue\n *\n * Copyright (C) 2009-2016 wj32\n *\n * This file is part of Process Hacker.\n *\n * Process Hacker is free software; you can redistribute it and/or modify\n * it under the terms of the GNU General Public License as published by\n * the Free Software Foundation, either version 3 of the License, or\n * (at your option) any later version.\n *\n * Process Hacker is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n * GNU General Public License for more details.\n *\n * You should have received a copy of the GNU General Public License\n * along with Process Hacker.  If not, see <http://www.gnu.org/licenses/>.\n */\n\n#include <phbase.h>\n#include <workqueue.h>\n\n#include <phintrnl.h>\n\n#include <workqueuep.h>\n\nstatic PH_INITONCE PhWorkQueueInitOnce = PH_INITONCE_INIT;\nstatic PH_FREE_LIST PhWorkQueueItemFreeList;\nstatic PH_INITONCE PhGlobalWorkQueueInitOnce = PH_INITONCE_INIT;\nstatic PH_WORK_QUEUE PhGlobalWorkQueue;\n#ifdef DEBUG\nPPH_LIST PhDbgWorkQueueList;\nPH_QUEUED_LOCK PhDbgWorkQueueListLock = PH_QUEUED_LOCK_INIT;\n#endif\n\n/**\n * Initializes a work queue.\n *\n * \\param WorkQueue A work queue object.\n * \\param MinimumThreads The suggested minimum number of threads to keep alive, even when there is\n * no work to be performed.\n * \\param MaximumThreads The suggested maximum number of threads to create.\n * \\param NoWorkTimeout The number of milliseconds after which threads without work will terminate.\n */\nVOID PhInitializeWorkQueue(\n    _Out_ PPH_WORK_QUEUE WorkQueue,\n    _In_ ULONG MinimumThreads,\n    _In_ ULONG MaximumThreads,\n    _In_ ULONG NoWorkTimeout\n    )\n{\n    if (PhBeginInitOnce(&PhWorkQueueInitOnce))\n    {\n        PhInitializeFreeList(&PhWorkQueueItemFreeList, sizeof(PH_WORK_QUEUE_ITEM), 32);\n#ifdef DEBUG\n        PhDbgWorkQueueList = PhCreateList(4);\n#endif\n\n        PhEndInitOnce(&PhWorkQueueInitOnce);\n    }\n\n    PhInitializeRundownProtection(&WorkQueue->RundownProtect);\n    WorkQueue->Terminating = FALSE;\n\n    InitializeListHead(&WorkQueue->QueueListHead);\n    PhInitializeQueuedLock(&WorkQueue->QueueLock);\n    PhInitializeCondition(&WorkQueue->QueueEmptyCondition);\n\n    WorkQueue->MinimumThreads = MinimumThreads;\n    WorkQueue->MaximumThreads = MaximumThreads;\n    WorkQueue->NoWorkTimeout = NoWorkTimeout;\n\n    PhInitializeQueuedLock(&WorkQueue->StateLock);\n\n    WorkQueue->SemaphoreHandle = NULL;\n    WorkQueue->CurrentThreads = 0;\n    WorkQueue->BusyCount = 0;\n\n#ifdef DEBUG\n    PhAcquireQueuedLockExclusive(&PhDbgWorkQueueListLock);\n    PhAddItemList(PhDbgWorkQueueList, WorkQueue);\n    PhReleaseQueuedLockExclusive(&PhDbgWorkQueueListLock);\n#endif\n}\n\n/**\n * Frees resources used by a work queue.\n *\n * \\param WorkQueue A work queue object.\n */\nVOID PhDeleteWorkQueue(\n    _Inout_ PPH_WORK_QUEUE WorkQueue\n    )\n{\n    PLIST_ENTRY listEntry;\n    PPH_WORK_QUEUE_ITEM workQueueItem;\n#ifdef DEBUG\n    ULONG index;\n#endif\n\n#ifdef DEBUG\n    PhAcquireQueuedLockExclusive(&PhDbgWorkQueueListLock);\n    if ((index = PhFindItemList(PhDbgWorkQueueList, WorkQueue)) != -1)\n        PhRemoveItemList(PhDbgWorkQueueList, index);\n    PhReleaseQueuedLockExclusive(&PhDbgWorkQueueListLock);\n#endif\n\n    // Wait for all worker threads to exit.\n\n    WorkQueue->Terminating = TRUE;\n    MemoryBarrier();\n\n    if (WorkQueue->SemaphoreHandle)\n        NtReleaseSemaphore(WorkQueue->SemaphoreHandle, WorkQueue->CurrentThreads, NULL);\n\n    PhWaitForRundownProtection(&WorkQueue->RundownProtect);\n\n    // Free all un-executed work items.\n\n    listEntry = WorkQueue->QueueListHead.Flink;\n\n    while (listEntry != &WorkQueue->QueueListHead)\n    {\n        workQueueItem = CONTAINING_RECORD(listEntry, PH_WORK_QUEUE_ITEM, ListEntry);\n        listEntry = listEntry->Flink;\n        PhpDestroyWorkQueueItem(workQueueItem);\n    }\n\n    if (WorkQueue->SemaphoreHandle)\n        NtClose(WorkQueue->SemaphoreHandle);\n}\n\n/**\n * Waits for all queued work items to be executed.\n *\n * \\param WorkQueue A work queue object.\n */\nVOID PhWaitForWorkQueue(\n    _Inout_ PPH_WORK_QUEUE WorkQueue\n    )\n{\n    PhAcquireQueuedLockExclusive(&WorkQueue->QueueLock);\n\n    while (!IsListEmpty(&WorkQueue->QueueListHead))\n        PhWaitForCondition(&WorkQueue->QueueEmptyCondition, &WorkQueue->QueueLock, NULL);\n\n    PhReleaseQueuedLockExclusive(&WorkQueue->QueueLock);\n}\n\n/**\n * Queues a work item to a work queue.\n *\n * \\param WorkQueue A work queue object.\n * \\param Function A function to execute.\n * \\param Context A user-defined value to pass to the function.\n */\nVOID PhQueueItemWorkQueue(\n    _Inout_ PPH_WORK_QUEUE WorkQueue,\n    _In_ PUSER_THREAD_START_ROUTINE Function,\n    _In_opt_ PVOID Context\n    )\n{\n    PhQueueItemWorkQueueEx(WorkQueue, Function, Context, NULL, NULL);\n}\n\n/**\n * Queues a work item to a work queue.\n *\n * \\param WorkQueue A work queue object.\n * \\param Function A function to execute.\n * \\param Context A user-defined value to pass to the function.\n * \\param DeleteFunction A callback function that is executed when the work queue item is about to\n * be freed.\n * \\param Environment Execution environment parameters (e.g. priority).\n */\nVOID PhQueueItemWorkQueueEx(\n    _Inout_ PPH_WORK_QUEUE WorkQueue,\n    _In_ PUSER_THREAD_START_ROUTINE Function,\n    _In_opt_ PVOID Context,\n    _In_opt_ PPH_WORK_QUEUE_ITEM_DELETE_FUNCTION DeleteFunction,\n    _In_opt_ PPH_WORK_QUEUE_ENVIRONMENT Environment\n    )\n{\n    PPH_WORK_QUEUE_ITEM workQueueItem;\n\n    workQueueItem = PhpCreateWorkQueueItem(Function, Context, DeleteFunction, Environment);\n\n    // Enqueue the work item.\n    PhAcquireQueuedLockExclusive(&WorkQueue->QueueLock);\n    InsertTailList(&WorkQueue->QueueListHead, &workQueueItem->ListEntry);\n    _InterlockedIncrement(&WorkQueue->BusyCount);\n    PhReleaseQueuedLockExclusive(&WorkQueue->QueueLock);\n    // Signal the semaphore once to let a worker thread continue.\n    NtReleaseSemaphore(PhpGetSemaphoreWorkQueue(WorkQueue), 1, NULL);\n\n    PHLIB_INC_STATISTIC(WqWorkItemsQueued);\n\n    // Check if all worker threads are currently busy, and if we can create more threads.\n    if (WorkQueue->BusyCount >= WorkQueue->CurrentThreads &&\n        WorkQueue->CurrentThreads < WorkQueue->MaximumThreads)\n    {\n        // Lock and re-check.\n        PhAcquireQueuedLockExclusive(&WorkQueue->StateLock);\n\n        if (WorkQueue->CurrentThreads < WorkQueue->MaximumThreads)\n            PhpCreateWorkQueueThread(WorkQueue);\n\n        PhReleaseQueuedLockExclusive(&WorkQueue->StateLock);\n    }\n}\n\nVOID PhInitializeWorkQueueEnvironment(\n    _Out_ PPH_WORK_QUEUE_ENVIRONMENT Environment\n    )\n{\n    PhpGetDefaultWorkQueueEnvironment(Environment);\n}\n\n/** Returns a pointer to the default shared work queue. */\nPPH_WORK_QUEUE PhGetGlobalWorkQueue(\n    VOID\n    )\n{\n    if (PhBeginInitOnce(&PhGlobalWorkQueueInitOnce))\n    {\n        PhInitializeWorkQueue(\n            &PhGlobalWorkQueue,\n            0,\n            3,\n            1000\n            );\n        PhEndInitOnce(&PhGlobalWorkQueueInitOnce);\n    }\n\n    return &PhGlobalWorkQueue;\n}\n\nVOID PhpGetDefaultWorkQueueEnvironment(\n    _Out_ PPH_WORK_QUEUE_ENVIRONMENT Environment\n    )\n{\n    memset(Environment, 0, sizeof(PH_WORK_QUEUE_ENVIRONMENT));\n    Environment->BasePriority = 0;\n    Environment->IoPriority = IoPriorityNormal;\n    Environment->PagePriority = MEMORY_PRIORITY_NORMAL;\n    Environment->ForceUpdate = FALSE;\n}\n\nVOID PhpUpdateWorkQueueEnvironment(\n    _Inout_ PPH_WORK_QUEUE_ENVIRONMENT CurrentEnvironment,\n    _In_ PPH_WORK_QUEUE_ENVIRONMENT NewEnvironment\n    )\n{\n    if (CurrentEnvironment->BasePriority != NewEnvironment->BasePriority || NewEnvironment->ForceUpdate)\n    {\n        LONG increment;\n\n        increment = NewEnvironment->BasePriority;\n\n        if (NT_SUCCESS(NtSetInformationThread(NtCurrentThread(), ThreadBasePriority,\n            &increment, sizeof(LONG))))\n        {\n            CurrentEnvironment->BasePriority = NewEnvironment->BasePriority;\n        }\n    }\n\n    if (CurrentEnvironment->IoPriority != NewEnvironment->IoPriority || NewEnvironment->ForceUpdate)\n    {\n        IO_PRIORITY_HINT ioPriority;\n\n        ioPriority = NewEnvironment->IoPriority;\n\n        if (NT_SUCCESS(NtSetInformationThread(NtCurrentThread(), ThreadIoPriority,\n            &ioPriority, sizeof(IO_PRIORITY_HINT))))\n        {\n            CurrentEnvironment->IoPriority = NewEnvironment->IoPriority;\n        }\n    }\n\n    if (CurrentEnvironment->PagePriority != NewEnvironment->PagePriority || NewEnvironment->ForceUpdate)\n    {\n        ULONG pagePriority;\n\n        pagePriority = NewEnvironment->PagePriority;\n\n        if (NT_SUCCESS(NtSetInformationThread(NtCurrentThread(), ThreadPagePriority,\n            &pagePriority, sizeof(ULONG))))\n        {\n            CurrentEnvironment->PagePriority = NewEnvironment->PagePriority;\n        }\n    }\n}\n\nPPH_WORK_QUEUE_ITEM PhpCreateWorkQueueItem(\n    _In_ PUSER_THREAD_START_ROUTINE Function,\n    _In_opt_ PVOID Context,\n    _In_opt_ PPH_WORK_QUEUE_ITEM_DELETE_FUNCTION DeleteFunction,\n    _In_opt_ PPH_WORK_QUEUE_ENVIRONMENT Environment\n    )\n{\n    PPH_WORK_QUEUE_ITEM workQueueItem;\n\n    workQueueItem = PhAllocateFromFreeList(&PhWorkQueueItemFreeList);\n    workQueueItem->Function = Function;\n    workQueueItem->Context = Context;\n    workQueueItem->DeleteFunction = DeleteFunction;\n\n    if (Environment)\n        workQueueItem->Environment = *Environment;\n    else\n        PhpGetDefaultWorkQueueEnvironment(&workQueueItem->Environment);\n\n    return workQueueItem;\n}\n\nVOID PhpDestroyWorkQueueItem(\n    _In_ PPH_WORK_QUEUE_ITEM WorkQueueItem\n    )\n{\n    if (WorkQueueItem->DeleteFunction)\n        WorkQueueItem->DeleteFunction(WorkQueueItem->Function, WorkQueueItem->Context);\n\n    PhFreeToFreeList(&PhWorkQueueItemFreeList, WorkQueueItem);\n}\n\nVOID PhpExecuteWorkQueueItem(\n    _Inout_ PPH_WORK_QUEUE_ITEM WorkQueueItem\n    )\n{\n    WorkQueueItem->Function(WorkQueueItem->Context);\n}\n\nHANDLE PhpGetSemaphoreWorkQueue(\n    _Inout_ PPH_WORK_QUEUE WorkQueue\n    )\n{\n    HANDLE semaphoreHandle;\n\n    semaphoreHandle = WorkQueue->SemaphoreHandle;\n\n    if (!semaphoreHandle)\n    {\n        NtCreateSemaphore(&semaphoreHandle, SEMAPHORE_ALL_ACCESS, NULL, 0, MAXLONG);\n        assert(semaphoreHandle);\n\n        if (_InterlockedCompareExchangePointer(\n            &WorkQueue->SemaphoreHandle,\n            semaphoreHandle,\n            NULL\n            ) != NULL)\n        {\n            // Someone else created the semaphore before we did.\n            NtClose(semaphoreHandle);\n            semaphoreHandle = WorkQueue->SemaphoreHandle;\n        }\n    }\n\n    return semaphoreHandle;\n}\n\nBOOLEAN PhpCreateWorkQueueThread(\n    _Inout_ PPH_WORK_QUEUE WorkQueue\n    )\n{\n    HANDLE threadHandle;\n\n    // Make sure the structure doesn't get deleted while the thread is running.\n    if (!PhAcquireRundownProtection(&WorkQueue->RundownProtect))\n        return FALSE;\n\n    threadHandle = PhCreateThread(0, PhpWorkQueueThreadStart, WorkQueue);\n\n    if (threadHandle)\n    {\n        PHLIB_INC_STATISTIC(WqWorkQueueThreadsCreated);\n        WorkQueue->CurrentThreads++;\n        NtClose(threadHandle);\n\n        return TRUE;\n    }\n    else\n    {\n        PHLIB_INC_STATISTIC(WqWorkQueueThreadsCreateFailed);\n        PhReleaseRundownProtection(&WorkQueue->RundownProtect);\n        return FALSE;\n    }\n}\n\nNTSTATUS PhpWorkQueueThreadStart(\n    _In_ PVOID Parameter\n    )\n{\n    PH_AUTO_POOL autoPool;\n    PPH_WORK_QUEUE workQueue = (PPH_WORK_QUEUE)Parameter;\n    PH_WORK_QUEUE_ENVIRONMENT currentEnvironment;\n\n    PhInitializeAutoPool(&autoPool);\n    PhpGetDefaultWorkQueueEnvironment(&currentEnvironment);\n\n    while (TRUE)\n    {\n        NTSTATUS status;\n        HANDLE semaphoreHandle;\n        LARGE_INTEGER timeout;\n        PPH_WORK_QUEUE_ITEM workQueueItem = NULL;\n\n        // Check if we have more threads than the limit.\n        if (workQueue->CurrentThreads > workQueue->MaximumThreads)\n        {\n            BOOLEAN terminate = FALSE;\n\n            // Lock and re-check.\n            PhAcquireQueuedLockExclusive(&workQueue->StateLock);\n\n            // Check the minimum as well.\n            if (workQueue->CurrentThreads > workQueue->MaximumThreads &&\n                workQueue->CurrentThreads > workQueue->MinimumThreads)\n            {\n                workQueue->CurrentThreads--;\n                terminate = TRUE;\n            }\n\n            PhReleaseQueuedLockExclusive(&workQueue->StateLock);\n\n            if (terminate)\n                break;\n        }\n\n        semaphoreHandle = PhpGetSemaphoreWorkQueue(workQueue);\n\n        if (!workQueue->Terminating)\n        {\n            // Wait for work.\n            status = NtWaitForSingleObject(\n                semaphoreHandle,\n                FALSE,\n                PhTimeoutFromMilliseconds(&timeout, workQueue->NoWorkTimeout)\n                );\n        }\n        else\n        {\n            status = STATUS_UNSUCCESSFUL;\n        }\n\n        if (status == STATUS_WAIT_0 && !workQueue->Terminating)\n        {\n            PLIST_ENTRY listEntry;\n\n            // Dequeue the work item.\n\n            PhAcquireQueuedLockExclusive(&workQueue->QueueLock);\n\n            listEntry = RemoveHeadList(&workQueue->QueueListHead);\n\n            if (IsListEmpty(&workQueue->QueueListHead))\n                PhPulseCondition(&workQueue->QueueEmptyCondition);\n\n            PhReleaseQueuedLockExclusive(&workQueue->QueueLock);\n\n            // Make sure we got work.\n            if (listEntry != &workQueue->QueueListHead)\n            {\n                workQueueItem = CONTAINING_RECORD(listEntry, PH_WORK_QUEUE_ITEM, ListEntry);\n\n                PhpUpdateWorkQueueEnvironment(&currentEnvironment, &workQueueItem->Environment);\n                PhpExecuteWorkQueueItem(workQueueItem);\n                _InterlockedDecrement(&workQueue->BusyCount);\n\n                PhpDestroyWorkQueueItem(workQueueItem);\n            }\n        }\n        else\n        {\n            BOOLEAN terminate = FALSE;\n\n            // No work arrived before the timeout passed, or we are terminating, or some error\n            // occurred. Terminate the thread.\n\n            PhAcquireQueuedLockExclusive(&workQueue->StateLock);\n\n            if (workQueue->Terminating || workQueue->CurrentThreads > workQueue->MinimumThreads)\n            {\n                workQueue->CurrentThreads--;\n                terminate = TRUE;\n            }\n\n            PhReleaseQueuedLockExclusive(&workQueue->StateLock);\n\n            if (terminate)\n                break;\n        }\n\n        PhDrainAutoPool(&autoPool);\n    }\n\n    PhReleaseRundownProtection(&workQueue->RundownProtect);\n    PhDeleteAutoPool(&autoPool);\n\n    return STATUS_SUCCESS;\n}\n"
  },
  {
    "path": "third_party/phnt/README.md",
    "content": "This collection of Native API header files has been maintained since 2009 for the Process Hacker project, and is the most up-to-date set of Native API definitions that I know of. I have gathered these definitions from official Microsoft header files and symbol files, as well as a lot of reverse engineering and guessing. See `phnt.h` for more information.\n\n## Usage\n\nFirst make sure that your program is using the latest Windows SDK.\n\nThese header files are designed to be used by user-mode programs. Instead of `#include <windows.h>`, place\n\n```\n#include <phnt_windows.h>\n#include <phnt.h>\n```\n\nat the top of your program. The first line provides access to the Win32 API as well as the `NTSTATUS` values. The second line provides access to the entire Native API. By default, only definitions present in Windows XP are included into your program. To change this, use one of the following:\n\n```\n#define PHNT_VERSION PHNT_WINXP // Windows XP\n#define PHNT_VERSION PHNT_WS03 // Windows Server 2003\n#define PHNT_VERSION PHNT_VISTA // Windows Vista\n#define PHNT_VERSION PHNT_WIN7 // Windows 7\n#define PHNT_VERSION PHNT_WIN8 // Windows 8\n#define PHNT_VERSION PHNT_WINBLUE // Windows 8.1\n#define PHNT_VERSION PHNT_THRESHOLD // Windows 10\n```\n"
  },
  {
    "path": "third_party/phnt/include/ntdbg.h",
    "content": "#ifndef _NTDBG_H\n#define _NTDBG_H\n\n// Definitions\n\ntypedef struct _DBGKM_EXCEPTION\n{\n    EXCEPTION_RECORD ExceptionRecord;\n    ULONG FirstChance;\n} DBGKM_EXCEPTION, *PDBGKM_EXCEPTION;\n\ntypedef struct _DBGKM_CREATE_THREAD\n{\n    ULONG SubSystemKey;\n    PVOID StartAddress;\n} DBGKM_CREATE_THREAD, *PDBGKM_CREATE_THREAD;\n\ntypedef struct _DBGKM_CREATE_PROCESS\n{\n    ULONG SubSystemKey;\n    HANDLE FileHandle;\n    PVOID BaseOfImage;\n    ULONG DebugInfoFileOffset;\n    ULONG DebugInfoSize;\n    DBGKM_CREATE_THREAD InitialThread;\n} DBGKM_CREATE_PROCESS, *PDBGKM_CREATE_PROCESS;\n\ntypedef struct _DBGKM_EXIT_THREAD\n{\n    NTSTATUS ExitStatus;\n} DBGKM_EXIT_THREAD, *PDBGKM_EXIT_THREAD;\n\ntypedef struct _DBGKM_EXIT_PROCESS\n{\n    NTSTATUS ExitStatus;\n} DBGKM_EXIT_PROCESS, *PDBGKM_EXIT_PROCESS;\n\ntypedef struct _DBGKM_LOAD_DLL\n{\n    HANDLE FileHandle;\n    PVOID BaseOfDll;\n    ULONG DebugInfoFileOffset;\n    ULONG DebugInfoSize;\n    PVOID NamePointer;\n} DBGKM_LOAD_DLL, *PDBGKM_LOAD_DLL;\n\ntypedef struct _DBGKM_UNLOAD_DLL\n{\n    PVOID BaseAddress;\n} DBGKM_UNLOAD_DLL, *PDBGKM_UNLOAD_DLL;\n\ntypedef enum _DBG_STATE\n{\n    DbgIdle,\n    DbgReplyPending,\n    DbgCreateThreadStateChange,\n    DbgCreateProcessStateChange,\n    DbgExitThreadStateChange,\n    DbgExitProcessStateChange,\n    DbgExceptionStateChange,\n    DbgBreakpointStateChange,\n    DbgSingleStepStateChange,\n    DbgLoadDllStateChange,\n    DbgUnloadDllStateChange\n} DBG_STATE, *PDBG_STATE;\n\ntypedef struct _DBGUI_CREATE_THREAD\n{\n    HANDLE HandleToThread;\n    DBGKM_CREATE_THREAD NewThread;\n} DBGUI_CREATE_THREAD, *PDBGUI_CREATE_THREAD;\n\ntypedef struct _DBGUI_CREATE_PROCESS\n{\n    HANDLE HandleToProcess;\n    HANDLE HandleToThread;\n    DBGKM_CREATE_PROCESS NewProcess;\n} DBGUI_CREATE_PROCESS, *PDBGUI_CREATE_PROCESS;\n\ntypedef struct _DBGUI_WAIT_STATE_CHANGE\n{\n    DBG_STATE NewState;\n    CLIENT_ID AppClientId;\n    union\n    {\n        DBGKM_EXCEPTION Exception;\n        DBGUI_CREATE_THREAD CreateThread;\n        DBGUI_CREATE_PROCESS CreateProcessInfo;\n        DBGKM_EXIT_THREAD ExitThread;\n        DBGKM_EXIT_PROCESS ExitProcess;\n        DBGKM_LOAD_DLL LoadDll;\n        DBGKM_UNLOAD_DLL UnloadDll;\n    } StateInfo;\n} DBGUI_WAIT_STATE_CHANGE, *PDBGUI_WAIT_STATE_CHANGE;\n\n// System calls\n\n#define DEBUG_READ_EVENT 0x0001\n#define DEBUG_PROCESS_ASSIGN 0x0002\n#define DEBUG_SET_INFORMATION 0x0004\n#define DEBUG_QUERY_INFORMATION 0x0008\n#define DEBUG_ALL_ACCESS (STANDARD_RIGHTS_REQUIRED | SYNCHRONIZE | \\\n    DEBUG_READ_EVENT | DEBUG_PROCESS_ASSIGN | DEBUG_SET_INFORMATION | \\\n    DEBUG_QUERY_INFORMATION)\n\n#define DEBUG_KILL_ON_CLOSE 0x1\n\ntypedef enum _DEBUGOBJECTINFOCLASS\n{\n    DebugObjectFlags = 1,\n    MaxDebugObjectInfoClass\n} DEBUGOBJECTINFOCLASS, *PDEBUGOBJECTINFOCLASS;\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtCreateDebugObject(\n    _Out_ PHANDLE DebugObjectHandle,\n    _In_ ACCESS_MASK DesiredAccess,\n    _In_ POBJECT_ATTRIBUTES ObjectAttributes,\n    _In_ ULONG Flags\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtDebugActiveProcess(\n    _In_ HANDLE ProcessHandle,\n    _In_ HANDLE DebugObjectHandle\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtDebugContinue(\n    _In_ HANDLE DebugObjectHandle,\n    _In_ PCLIENT_ID ClientId,\n    _In_ NTSTATUS ContinueStatus\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtRemoveProcessDebug(\n    _In_ HANDLE ProcessHandle,\n    _In_ HANDLE DebugObjectHandle\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtSetInformationDebugObject(\n    _In_ HANDLE DebugObjectHandle,\n    _In_ DEBUGOBJECTINFOCLASS DebugObjectInformationClass,\n    _In_ PVOID DebugInformation,\n    _In_ ULONG DebugInformationLength,\n    _Out_opt_ PULONG ReturnLength\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtWaitForDebugEvent(\n    _In_ HANDLE DebugObjectHandle,\n    _In_ BOOLEAN Alertable,\n    _In_opt_ PLARGE_INTEGER Timeout,\n    _Out_ PVOID WaitStateChange\n    );\n\n// Debugging UI\n\nNTSYSAPI\nNTSTATUS\nNTAPI\nDbgUiConnectToDbg(\n    VOID\n    );\n\nNTSYSAPI\nHANDLE\nNTAPI\nDbgUiGetThreadDebugObject(\n    VOID\n    );\n\nNTSYSAPI\nVOID\nNTAPI\nDbgUiSetThreadDebugObject(\n    _In_ HANDLE DebugObject\n    );\n\nNTSYSAPI\nNTSTATUS\nNTAPI\nDbgUiWaitStateChange(\n    _Out_ PDBGUI_WAIT_STATE_CHANGE StateChange,\n    _In_opt_ PLARGE_INTEGER Timeout\n    );\n\nNTSYSAPI\nNTSTATUS\nNTAPI\nDbgUiContinue(\n    _In_ PCLIENT_ID AppClientId,\n    _In_ NTSTATUS ContinueStatus\n    );\n\nNTSYSAPI\nNTSTATUS\nNTAPI\nDbgUiStopDebugging(\n    _In_ HANDLE Process\n    );\n\nNTSYSAPI\nNTSTATUS\nNTAPI\nDbgUiDebugActiveProcess(\n    _In_ HANDLE Process\n    );\n\nNTSYSAPI\nVOID\nNTAPI\nDbgUiRemoteBreakin(\n    _In_ PVOID Context\n    );\n\nNTSYSAPI\nNTSTATUS\nNTAPI\nDbgUiIssueRemoteBreakin(\n    _In_ HANDLE Process\n    );\n\nstruct _DEBUG_EVENT;\n\nNTSYSAPI\nNTSTATUS\nNTAPI\nDbgUiConvertStateChangeStructure(\n    _In_ PDBGUI_WAIT_STATE_CHANGE StateChange,\n    _Out_ struct _DEBUG_EVENT *DebugEvent\n    );\n\nstruct _EVENT_FILTER_DESCRIPTOR;\n\ntypedef VOID (NTAPI *PENABLECALLBACK)(\n    _In_ LPCGUID SourceId,\n    _In_ ULONG IsEnabled,\n    _In_ UCHAR Level,\n    _In_ ULONGLONG MatchAnyKeyword,\n    _In_ ULONGLONG MatchAllKeyword,\n    _In_opt_ struct _EVENT_FILTER_DESCRIPTOR *FilterData,\n    _Inout_opt_ PVOID CallbackContext\n    );\n\ntypedef ULONGLONG REGHANDLE, *PREGHANDLE;\n\nNTSYSAPI\nNTSTATUS\nNTAPI\nEtwEventRegister(\n    _In_ LPCGUID ProviderId,\n    _In_opt_ PENABLECALLBACK EnableCallback,\n    _In_opt_ PVOID CallbackContext,\n    _Out_ PREGHANDLE RegHandle\n    );\n\n#endif\n"
  },
  {
    "path": "third_party/phnt/include/ntexapi.h",
    "content": "#ifndef _NTEXAPI_H\n#define _NTEXAPI_H\n\n#include <ntkeapi.h>\n\n#if (PHNT_MODE != PHNT_MODE_KERNEL)\n\n// Thread execution\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtDelayExecution(\n    _In_ BOOLEAN Alertable,\n    _In_ PLARGE_INTEGER DelayInterval\n    );\n\n// Environment values\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtQuerySystemEnvironmentValue(\n    _In_ PUNICODE_STRING VariableName,\n    _Out_writes_bytes_(ValueLength) PWSTR VariableValue,\n    _In_ USHORT ValueLength,\n    _Out_opt_ PUSHORT ReturnLength\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtSetSystemEnvironmentValue(\n    _In_ PUNICODE_STRING VariableName,\n    _In_ PUNICODE_STRING VariableValue\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtQuerySystemEnvironmentValueEx(\n    _In_ PUNICODE_STRING VariableName,\n    _In_ LPGUID VendorGuid,\n    _Out_writes_bytes_opt_(*ValueLength) PVOID Value,\n    _Inout_ PULONG ValueLength,\n    _Out_opt_ PULONG Attributes\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtSetSystemEnvironmentValueEx(\n    _In_ PUNICODE_STRING VariableName,\n    _In_ LPGUID VendorGuid,\n    _In_reads_bytes_opt_(ValueLength) PVOID Value,\n    _In_ ULONG ValueLength,\n    _In_ ULONG Attributes\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtEnumerateSystemEnvironmentValuesEx(\n    _In_ ULONG InformationClass,\n    _Out_ PVOID Buffer,\n    _Inout_ PULONG BufferLength\n    );\n\n// EFI\n\n// private\ntypedef struct _BOOT_ENTRY\n{\n    ULONG Version;\n    ULONG Length;\n    ULONG Id;\n    ULONG Attributes;\n    ULONG FriendlyNameOffset;\n    ULONG BootFilePathOffset;\n    ULONG OsOptionsLength;\n    UCHAR OsOptions[1];\n} BOOT_ENTRY, *PBOOT_ENTRY;\n\n// private\ntypedef struct _BOOT_ENTRY_LIST\n{\n    ULONG NextEntryOffset;\n    BOOT_ENTRY BootEntry;\n} BOOT_ENTRY_LIST, *PBOOT_ENTRY_LIST;\n\n// private\ntypedef struct _BOOT_OPTIONS\n{\n    ULONG Version;\n    ULONG Length;\n    ULONG Timeout;\n    ULONG CurrentBootEntryId;\n    ULONG NextBootEntryId;\n    WCHAR HeadlessRedirection[1];\n} BOOT_OPTIONS, *PBOOT_OPTIONS;\n\n// private\ntypedef struct _FILE_PATH\n{\n    ULONG Version;\n    ULONG Length;\n    ULONG Type;\n    UCHAR FilePath[1];\n} FILE_PATH, *PFILE_PATH;\n\n// private\ntypedef struct _EFI_DRIVER_ENTRY\n{\n    ULONG Version;\n    ULONG Length;\n    ULONG Id;\n    ULONG FriendlyNameOffset;\n    ULONG DriverFilePathOffset;\n} EFI_DRIVER_ENTRY, *PEFI_DRIVER_ENTRY;\n\n// private\ntypedef struct _EFI_DRIVER_ENTRY_LIST\n{\n    ULONG NextEntryOffset;\n    EFI_DRIVER_ENTRY DriverEntry;\n} EFI_DRIVER_ENTRY_LIST, *PEFI_DRIVER_ENTRY_LIST;\n\n#if (PHNT_VERSION >= PHNT_VISTA)\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtAddBootEntry(\n    _In_ PBOOT_ENTRY BootEntry,\n    _Out_opt_ PULONG Id\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtDeleteBootEntry(\n    _In_ ULONG Id\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtModifyBootEntry(\n    _In_ PBOOT_ENTRY BootEntry\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtEnumerateBootEntries(\n    _Out_writes_bytes_opt_(*BufferLength) PVOID Buffer,\n    _Inout_ PULONG BufferLength\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtQueryBootEntryOrder(\n    _Out_writes_opt_(*Count) PULONG Ids,\n    _Inout_ PULONG Count\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtSetBootEntryOrder(\n    _In_reads_(Count) PULONG Ids,\n    _In_ ULONG Count\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtQueryBootOptions(\n    _Out_writes_bytes_opt_(*BootOptionsLength) PBOOT_OPTIONS BootOptions,\n    _Inout_ PULONG BootOptionsLength\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtSetBootOptions(\n    _In_ PBOOT_OPTIONS BootOptions,\n    _In_ ULONG FieldsToChange\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtTranslateFilePath(\n    _In_ PFILE_PATH InputFilePath,\n    _In_ ULONG OutputType,\n    _Out_writes_bytes_opt_(*OutputFilePathLength) PFILE_PATH OutputFilePath,\n    _Inout_opt_ PULONG OutputFilePathLength\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtAddDriverEntry(\n    _In_ PEFI_DRIVER_ENTRY DriverEntry,\n    _Out_opt_ PULONG Id\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtDeleteDriverEntry(\n    _In_ ULONG Id\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtModifyDriverEntry(\n    _In_ PEFI_DRIVER_ENTRY DriverEntry\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtEnumerateDriverEntries(\n    _Out_writes_bytes_opt_(*BufferLength) PVOID Buffer,\n    _Inout_ PULONG BufferLength\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtQueryDriverEntryOrder(\n    _Out_writes_opt_(*Count) PULONG Ids,\n    _Inout_ PULONG Count\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtSetDriverEntryOrder(\n    _In_reads_(Count) PULONG Ids,\n    _In_ ULONG Count\n    );\n\n#endif\n\n// Event\n\n#ifndef EVENT_QUERY_STATE\n#define EVENT_QUERY_STATE 0x0001\n#endif\n\ntypedef enum _EVENT_INFORMATION_CLASS\n{\n    EventBasicInformation\n} EVENT_INFORMATION_CLASS;\n\ntypedef struct _EVENT_BASIC_INFORMATION\n{\n    EVENT_TYPE EventType;\n    LONG EventState;\n} EVENT_BASIC_INFORMATION, *PEVENT_BASIC_INFORMATION;\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtCreateEvent(\n    _Out_ PHANDLE EventHandle,\n    _In_ ACCESS_MASK DesiredAccess,\n    _In_opt_ POBJECT_ATTRIBUTES ObjectAttributes,\n    _In_ EVENT_TYPE EventType,\n    _In_ BOOLEAN InitialState\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtOpenEvent(\n    _Out_ PHANDLE EventHandle,\n    _In_ ACCESS_MASK DesiredAccess,\n    _In_ POBJECT_ATTRIBUTES ObjectAttributes\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtSetEvent(\n    _In_ HANDLE EventHandle,\n    _Out_opt_ PLONG PreviousState\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtSetEventBoostPriority(\n    _In_ HANDLE EventHandle\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtClearEvent(\n    _In_ HANDLE EventHandle\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtResetEvent(\n    _In_ HANDLE EventHandle,\n    _Out_opt_ PLONG PreviousState\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtPulseEvent(\n    _In_ HANDLE EventHandle,\n    _Out_opt_ PLONG PreviousState\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtQueryEvent(\n    _In_ HANDLE EventHandle,\n    _In_ EVENT_INFORMATION_CLASS EventInformationClass,\n    _Out_writes_bytes_(EventInformationLength) PVOID EventInformation,\n    _In_ ULONG EventInformationLength,\n    _Out_opt_ PULONG ReturnLength\n    );\n\n// Event Pair\n\n#define EVENT_PAIR_ALL_ACCESS (STANDARD_RIGHTS_REQUIRED | SYNCHRONIZE)\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtCreateEventPair(\n    _Out_ PHANDLE EventPairHandle,\n    _In_ ACCESS_MASK DesiredAccess,\n    _In_opt_ POBJECT_ATTRIBUTES ObjectAttributes\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtOpenEventPair(\n    _Out_ PHANDLE EventPairHandle,\n    _In_ ACCESS_MASK DesiredAccess,\n    _In_ POBJECT_ATTRIBUTES ObjectAttributes\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtSetLowEventPair(\n    _In_ HANDLE EventPairHandle\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtSetHighEventPair(\n    _In_ HANDLE EventPairHandle\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtWaitLowEventPair(\n    _In_ HANDLE EventPairHandle\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtWaitHighEventPair(\n    _In_ HANDLE EventPairHandle\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtSetLowWaitHighEventPair(\n    _In_ HANDLE EventPairHandle\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtSetHighWaitLowEventPair(\n    _In_ HANDLE EventPairHandle\n    );\n\n// Mutant\n\ntypedef enum _MUTANT_INFORMATION_CLASS\n{\n    MutantBasicInformation,\n    MutantOwnerInformation\n} MUTANT_INFORMATION_CLASS;\n\ntypedef struct _MUTANT_BASIC_INFORMATION\n{\n    LONG CurrentCount;\n    BOOLEAN OwnedByCaller;\n    BOOLEAN AbandonedState;\n} MUTANT_BASIC_INFORMATION, *PMUTANT_BASIC_INFORMATION;\n\ntypedef struct _MUTANT_OWNER_INFORMATION\n{\n    CLIENT_ID ClientId;\n} MUTANT_OWNER_INFORMATION, *PMUTANT_OWNER_INFORMATION;\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtCreateMutant(\n    _Out_ PHANDLE MutantHandle,\n    _In_ ACCESS_MASK DesiredAccess,\n    _In_opt_ POBJECT_ATTRIBUTES ObjectAttributes,\n    _In_ BOOLEAN InitialOwner\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtOpenMutant(\n    _Out_ PHANDLE MutantHandle,\n    _In_ ACCESS_MASK DesiredAccess,\n    _In_ POBJECT_ATTRIBUTES ObjectAttributes\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtReleaseMutant(\n    _In_ HANDLE MutantHandle,\n    _Out_opt_ PLONG PreviousCount\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtQueryMutant(\n    _In_ HANDLE MutantHandle,\n    _In_ MUTANT_INFORMATION_CLASS MutantInformationClass,\n    _Out_writes_bytes_(MutantInformationLength) PVOID MutantInformation,\n    _In_ ULONG MutantInformationLength,\n    _Out_opt_ PULONG ReturnLength\n    );\n\n// Semaphore\n\n#ifndef SEMAPHORE_QUERY_STATE\n#define SEMAPHORE_QUERY_STATE 0x0001\n#endif\n\ntypedef enum _SEMAPHORE_INFORMATION_CLASS\n{\n    SemaphoreBasicInformation\n} SEMAPHORE_INFORMATION_CLASS;\n\ntypedef struct _SEMAPHORE_BASIC_INFORMATION\n{\n    LONG CurrentCount;\n    LONG MaximumCount;\n} SEMAPHORE_BASIC_INFORMATION, *PSEMAPHORE_BASIC_INFORMATION;\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtCreateSemaphore(\n    _Out_ PHANDLE SemaphoreHandle,\n    _In_ ACCESS_MASK DesiredAccess,\n    _In_opt_ POBJECT_ATTRIBUTES ObjectAttributes,\n    _In_ LONG InitialCount,\n    _In_ LONG MaximumCount\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtOpenSemaphore(\n    _Out_ PHANDLE SemaphoreHandle,\n    _In_ ACCESS_MASK DesiredAccess,\n    _In_ POBJECT_ATTRIBUTES ObjectAttributes\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtReleaseSemaphore(\n    _In_ HANDLE SemaphoreHandle,\n    _In_ LONG ReleaseCount,\n    _Out_opt_ PLONG PreviousCount\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtQuerySemaphore(\n    _In_ HANDLE SemaphoreHandle,\n    _In_ SEMAPHORE_INFORMATION_CLASS SemaphoreInformationClass,\n    _Out_writes_bytes_(SemaphoreInformationLength) PVOID SemaphoreInformation,\n    _In_ ULONG SemaphoreInformationLength,\n    _Out_opt_ PULONG ReturnLength\n    );\n\n// Timer\n\ntypedef enum _TIMER_INFORMATION_CLASS\n{\n    TimerBasicInformation\n} TIMER_INFORMATION_CLASS;\n\ntypedef struct _TIMER_BASIC_INFORMATION\n{\n    LARGE_INTEGER RemainingTime;\n    BOOLEAN TimerState;\n} TIMER_BASIC_INFORMATION, *PTIMER_BASIC_INFORMATION;\n\ntypedef VOID (NTAPI *PTIMER_APC_ROUTINE)(\n    _In_ PVOID TimerContext,\n    _In_ ULONG TimerLowValue,\n    _In_ LONG TimerHighValue\n    );\n\ntypedef enum _TIMER_SET_INFORMATION_CLASS\n{\n    TimerSetCoalescableTimer,\n    MaxTimerInfoClass\n} TIMER_SET_INFORMATION_CLASS;\n\n#if (PHNT_VERSION >= PHNT_WIN7)\nstruct _COUNTED_REASON_CONTEXT;\n\ntypedef struct _TIMER_SET_COALESCABLE_TIMER_INFO\n{\n    _In_ LARGE_INTEGER DueTime;\n    _In_opt_ PTIMER_APC_ROUTINE TimerApcRoutine;\n    _In_opt_ PVOID TimerContext;\n    _In_opt_ struct _COUNTED_REASON_CONTEXT *WakeContext;\n    _In_opt_ ULONG Period;\n    _In_ ULONG TolerableDelay;\n    _Out_opt_ PBOOLEAN PreviousState;\n} TIMER_SET_COALESCABLE_TIMER_INFO, *PTIMER_SET_COALESCABLE_TIMER_INFO;\n#endif\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtCreateTimer(\n    _Out_ PHANDLE TimerHandle,\n    _In_ ACCESS_MASK DesiredAccess,\n    _In_opt_ POBJECT_ATTRIBUTES ObjectAttributes,\n    _In_ TIMER_TYPE TimerType\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtOpenTimer(\n    _Out_ PHANDLE TimerHandle,\n    _In_ ACCESS_MASK DesiredAccess,\n    _In_ POBJECT_ATTRIBUTES ObjectAttributes\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtSetTimer(\n    _In_ HANDLE TimerHandle,\n    _In_ PLARGE_INTEGER DueTime,\n    _In_opt_ PTIMER_APC_ROUTINE TimerApcRoutine,\n    _In_opt_ PVOID TimerContext,\n    _In_ BOOLEAN ResumeTimer,\n    _In_opt_ LONG Period,\n    _Out_opt_ PBOOLEAN PreviousState\n    );\n\n#if (PHNT_VERSION >= PHNT_WIN7)\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtSetTimerEx(\n    _In_ HANDLE TimerHandle,\n    _In_ TIMER_SET_INFORMATION_CLASS TimerSetInformationClass,\n    _Inout_updates_bytes_opt_(TimerSetInformationLength) PVOID TimerSetInformation,\n    _In_ ULONG TimerSetInformationLength\n    );\n#endif\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtCancelTimer(\n    _In_ HANDLE TimerHandle,\n    _Out_opt_ PBOOLEAN CurrentState\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtQueryTimer(\n    _In_ HANDLE TimerHandle,\n    _In_ TIMER_INFORMATION_CLASS TimerInformationClass,\n    _Out_writes_bytes_(TimerInformationLength) PVOID TimerInformation,\n    _In_ ULONG TimerInformationLength,\n    _Out_opt_ PULONG ReturnLength\n    );\n\n#if (PHNT_VERSION >= PHNT_WIN8)\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtCreateIRTimer(\n    _Out_ PHANDLE TimerHandle,\n    _In_ ACCESS_MASK DesiredAccess\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtSetIRTimer(\n    _In_ HANDLE TimerHandle,\n    _In_opt_ PLARGE_INTEGER DueTime\n    );\n\n#endif\n\ntypedef struct _T2_SET_PARAMETERS_V0\n{\n    ULONG Version;\n    ULONG Reserved;\n    LONGLONG NoWakeTolerance;\n} T2_SET_PARAMETERS, *PT2_SET_PARAMETERS;\n\ntypedef PVOID PT2_CANCEL_PARAMETERS;\n\n#if (PHNT_VERSION >= PHNT_THRESHOLD)\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtCreateTimer2(\n    _Out_ PHANDLE TimerHandle,\n    _In_opt_ PVOID Reserved1,\n    _In_opt_ PVOID Reserved2,\n    _In_ ULONG Attributes,\n    _In_ ACCESS_MASK DesiredAccess\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtSetTimer2(\n    _In_ HANDLE TimerHandle,\n    _In_ PLARGE_INTEGER DueTime,\n    _In_opt_ PLARGE_INTEGER Period,\n    _In_ PT2_SET_PARAMETERS Parameters\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtCancelTimer2(\n    _In_ HANDLE TimerHandle,\n    _In_ PT2_CANCEL_PARAMETERS Parameters\n    );\n\n#endif\n\n// Profile\n\n#define PROFILE_CONTROL 0x0001\n#define PROFILE_ALL_ACCESS (STANDARD_RIGHTS_REQUIRED | PROFILE_CONTROL)\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtCreateProfile(\n    _Out_ PHANDLE ProfileHandle,\n    _In_opt_ HANDLE Process,\n    _In_ PVOID ProfileBase,\n    _In_ SIZE_T ProfileSize,\n    _In_ ULONG BucketSize,\n    _In_reads_bytes_(BufferSize) PULONG Buffer,\n    _In_ ULONG BufferSize,\n    _In_ KPROFILE_SOURCE ProfileSource,\n    _In_ KAFFINITY Affinity\n    );\n\n#if (PHNT_VERSION >= PHNT_WIN7)\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtCreateProfileEx(\n    _Out_ PHANDLE ProfileHandle,\n    _In_opt_ HANDLE Process,\n    _In_ PVOID ProfileBase,\n    _In_ SIZE_T ProfileSize,\n    _In_ ULONG BucketSize,\n    _In_reads_bytes_(BufferSize) PULONG Buffer,\n    _In_ ULONG BufferSize,\n    _In_ KPROFILE_SOURCE ProfileSource,\n    _In_ USHORT GroupCount,\n    _In_reads_(GroupCount) PGROUP_AFFINITY GroupAffinity\n    );\n#endif\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtStartProfile(\n    _In_ HANDLE ProfileHandle\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtStopProfile(\n    _In_ HANDLE ProfileHandle\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtQueryIntervalProfile(\n    _In_ KPROFILE_SOURCE ProfileSource,\n    _Out_ PULONG Interval\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtSetIntervalProfile(\n    _In_ ULONG Interval,\n    _In_ KPROFILE_SOURCE Source\n    );\n\n// Keyed Event\n\n#define KEYEDEVENT_WAIT 0x0001\n#define KEYEDEVENT_WAKE 0x0002\n#define KEYEDEVENT_ALL_ACCESS \\\n    (STANDARD_RIGHTS_REQUIRED | KEYEDEVENT_WAIT | KEYEDEVENT_WAKE)\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtCreateKeyedEvent(\n    _Out_ PHANDLE KeyedEventHandle,\n    _In_ ACCESS_MASK DesiredAccess,\n    _In_opt_ POBJECT_ATTRIBUTES ObjectAttributes,\n    _In_ ULONG Flags\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtOpenKeyedEvent(\n    _Out_ PHANDLE KeyedEventHandle,\n    _In_ ACCESS_MASK DesiredAccess,\n    _In_ POBJECT_ATTRIBUTES ObjectAttributes\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtReleaseKeyedEvent(\n    _In_ HANDLE KeyedEventHandle,\n    _In_ PVOID KeyValue,\n    _In_ BOOLEAN Alertable,\n    _In_opt_ PLARGE_INTEGER Timeout\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtWaitForKeyedEvent(\n    _In_ HANDLE KeyedEventHandle,\n    _In_ PVOID KeyValue,\n    _In_ BOOLEAN Alertable,\n    _In_opt_ PLARGE_INTEGER Timeout\n    );\n\n// UMS\n\n#if (PHNT_VERSION >= PHNT_WIN7)\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtUmsThreadYield(\n    _In_ PVOID SchedulerParam\n    );\n#endif\n\n// WNF\n\n// begin_private\n\ntypedef struct _WNF_STATE_NAME\n{\n    ULONG Data[2];\n} WNF_STATE_NAME, *PWNF_STATE_NAME;\n\ntypedef const WNF_STATE_NAME *PCWNF_STATE_NAME;\n\ntypedef enum _WNF_STATE_NAME_LIFETIME\n{\n    WnfWellKnownStateName,\n    WnfPermanentStateName,\n    WnfPersistentStateName,\n    WnfTemporaryStateName\n} WNF_STATE_NAME_LIFETIME;\n\ntypedef enum _WNF_STATE_NAME_INFORMATION\n{\n    WnfInfoStateNameExist,\n    WnfInfoSubscribersPresent,\n    WnfInfoIsQuiescent\n} WNF_STATE_NAME_INFORMATION;\n\ntypedef enum _WNF_DATA_SCOPE\n{\n    WnfDataScopeSystem,\n    WnfDataScopeSession,\n    WnfDataScopeUser,\n    WnfDataScopeProcess,\n    WnfDataScopeMachine // REDSTONE3\n} WNF_DATA_SCOPE;\n\ntypedef struct _WNF_TYPE_ID\n{\n    GUID TypeId;\n} WNF_TYPE_ID, *PWNF_TYPE_ID;\n\ntypedef const WNF_TYPE_ID *PCWNF_TYPE_ID;\n\n// rev\ntypedef ULONG WNF_CHANGE_STAMP, *PWNF_CHANGE_STAMP;\n\ntypedef struct _WNF_DELIVERY_DESCRIPTOR\n{\n    ULONGLONG SubscriptionId;\n    WNF_STATE_NAME StateName;\n    WNF_CHANGE_STAMP ChangeStamp;\n    ULONG StateDataSize;\n    ULONG EventMask;\n    WNF_TYPE_ID TypeId;\n    ULONG StateDataOffset;\n} WNF_DELIVERY_DESCRIPTOR, *PWNF_DELIVERY_DESCRIPTOR;\n\n// end_private\n\n#if (PHNT_VERSION >= PHNT_WIN8)\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtCreateWnfStateName(\n    _Out_ PWNF_STATE_NAME StateName,\n    _In_ WNF_STATE_NAME_LIFETIME NameLifetime,\n    _In_ WNF_DATA_SCOPE DataScope,\n    _In_ BOOLEAN PersistData,\n    _In_opt_ PCWNF_TYPE_ID TypeId,\n    _In_ ULONG MaximumStateSize,\n    _In_ PSECURITY_DESCRIPTOR SecurityDescriptor\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtDeleteWnfStateName(\n    _In_ PCWNF_STATE_NAME StateName\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtUpdateWnfStateData(\n    _In_ PCWNF_STATE_NAME StateName,\n    _In_reads_bytes_opt_(Length) const VOID *Buffer,\n    _In_opt_ ULONG Length,\n    _In_opt_ PCWNF_TYPE_ID TypeId,\n    _In_opt_ const VOID *ExplicitScope,\n    _In_ WNF_CHANGE_STAMP MatchingChangeStamp,\n    _In_ LOGICAL CheckStamp\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtDeleteWnfStateData(\n    _In_ PCWNF_STATE_NAME StateName,\n    _In_opt_ const VOID *ExplicitScope\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtQueryWnfStateData(\n    _In_ PCWNF_STATE_NAME StateName,\n    _In_opt_ PCWNF_TYPE_ID TypeId,\n    _In_opt_ const VOID *ExplicitScope,\n    _Out_ PWNF_CHANGE_STAMP ChangeStamp,\n    _Out_writes_bytes_to_opt_(*BufferSize, *BufferSize) PVOID Buffer,\n    _Inout_ PULONG BufferSize\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtQueryWnfStateNameInformation(\n    _In_ PCWNF_STATE_NAME StateName,\n    _In_ WNF_STATE_NAME_INFORMATION NameInfoClass,\n    _In_opt_ const VOID *ExplicitScope,\n    _Out_writes_bytes_(InfoBufferSize) PVOID InfoBuffer,\n    _In_ ULONG InfoBufferSize\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtSubscribeWnfStateChange(\n    _In_ PCWNF_STATE_NAME StateName,\n    _In_opt_ WNF_CHANGE_STAMP ChangeStamp,\n    _In_ ULONG EventMask,\n    _Out_opt_ PULONG64 SubscriptionId\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtUnsubscribeWnfStateChange(\n    _In_ PCWNF_STATE_NAME StateName\n    );\n\n#endif\n\n#if (PHNT_VERSION >= PHNT_THRESHOLD)\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtGetCompleteWnfStateSubscription(\n    _In_opt_ PWNF_STATE_NAME OldDescriptorStateName,\n    _In_opt_ ULONG64 *OldSubscriptionId,\n    _In_opt_ ULONG OldDescriptorEventMask,\n    _In_opt_ ULONG OldDescriptorStatus,\n    _Out_writes_bytes_(DescriptorSize) PWNF_DELIVERY_DESCRIPTOR NewDeliveryDescriptor,\n    _In_ ULONG DescriptorSize\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtSetWnfProcessNotificationEvent(\n    _In_ HANDLE NotificationEvent\n    );\n\n#endif\n\n// Worker factory\n\n// begin_rev\n\n#define WORKER_FACTORY_RELEASE_WORKER 0x0001\n#define WORKER_FACTORY_WAIT 0x0002\n#define WORKER_FACTORY_SET_INFORMATION 0x0004\n#define WORKER_FACTORY_QUERY_INFORMATION 0x0008\n#define WORKER_FACTORY_READY_WORKER 0x0010\n#define WORKER_FACTORY_SHUTDOWN 0x0020\n\n#define WORKER_FACTORY_ALL_ACCESS ( \\\n    STANDARD_RIGHTS_REQUIRED | \\\n    WORKER_FACTORY_RELEASE_WORKER | \\\n    WORKER_FACTORY_WAIT | \\\n    WORKER_FACTORY_SET_INFORMATION | \\\n    WORKER_FACTORY_QUERY_INFORMATION | \\\n    WORKER_FACTORY_READY_WORKER | \\\n    WORKER_FACTORY_SHUTDOWN \\\n    )\n\n// end_rev\n\n// begin_private\n\ntypedef enum _WORKERFACTORYINFOCLASS\n{\n    WorkerFactoryTimeout,\n    WorkerFactoryRetryTimeout,\n    WorkerFactoryIdleTimeout,\n    WorkerFactoryBindingCount,\n    WorkerFactoryThreadMinimum,\n    WorkerFactoryThreadMaximum,\n    WorkerFactoryPaused,\n    WorkerFactoryBasicInformation,\n    WorkerFactoryAdjustThreadGoal,\n    WorkerFactoryCallbackType,\n    WorkerFactoryStackInformation, // 10\n    WorkerFactoryThreadBasePriority,\n    WorkerFactoryTimeoutWaiters, // since THRESHOLD\n    WorkerFactoryFlags,\n    WorkerFactoryThreadSoftMaximum,\n    MaxWorkerFactoryInfoClass\n} WORKERFACTORYINFOCLASS, *PWORKERFACTORYINFOCLASS;\n\ntypedef struct _WORKER_FACTORY_BASIC_INFORMATION\n{\n    LARGE_INTEGER Timeout;\n    LARGE_INTEGER RetryTimeout;\n    LARGE_INTEGER IdleTimeout;\n    BOOLEAN Paused;\n    BOOLEAN TimerSet;\n    BOOLEAN QueuedToExWorker;\n    BOOLEAN MayCreate;\n    BOOLEAN CreateInProgress;\n    BOOLEAN InsertedIntoQueue;\n    BOOLEAN Shutdown;\n    ULONG BindingCount;\n    ULONG ThreadMinimum;\n    ULONG ThreadMaximum;\n    ULONG PendingWorkerCount;\n    ULONG WaitingWorkerCount;\n    ULONG TotalWorkerCount;\n    ULONG ReleaseCount;\n    LONGLONG InfiniteWaitGoal;\n    PVOID StartRoutine;\n    PVOID StartParameter;\n    HANDLE ProcessId;\n    SIZE_T StackReserve;\n    SIZE_T StackCommit;\n    NTSTATUS LastThreadCreationStatus;\n} WORKER_FACTORY_BASIC_INFORMATION, *PWORKER_FACTORY_BASIC_INFORMATION;\n\n// end_private\n\n#if (PHNT_VERSION >= PHNT_VISTA)\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtCreateWorkerFactory(\n    _Out_ PHANDLE WorkerFactoryHandleReturn,\n    _In_ ACCESS_MASK DesiredAccess,\n    _In_opt_ POBJECT_ATTRIBUTES ObjectAttributes,\n    _In_ HANDLE CompletionPortHandle,\n    _In_ HANDLE WorkerProcessHandle,\n    _In_ PVOID StartRoutine,\n    _In_opt_ PVOID StartParameter,\n    _In_opt_ ULONG MaxThreadCount,\n    _In_opt_ SIZE_T StackReserve,\n    _In_opt_ SIZE_T StackCommit\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtQueryInformationWorkerFactory(\n    _In_ HANDLE WorkerFactoryHandle,\n    _In_ WORKERFACTORYINFOCLASS WorkerFactoryInformationClass,\n    _Out_writes_bytes_(WorkerFactoryInformationLength) PVOID WorkerFactoryInformation,\n    _In_ ULONG WorkerFactoryInformationLength,\n    _Out_opt_ PULONG ReturnLength\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtSetInformationWorkerFactory(\n    _In_ HANDLE WorkerFactoryHandle,\n    _In_ WORKERFACTORYINFOCLASS WorkerFactoryInformationClass,\n    _In_reads_bytes_(WorkerFactoryInformationLength) PVOID WorkerFactoryInformation,\n    _In_ ULONG WorkerFactoryInformationLength\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtShutdownWorkerFactory(\n    _In_ HANDLE WorkerFactoryHandle,\n    _Inout_ volatile LONG *PendingWorkerCount\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtReleaseWorkerFactoryWorker(\n    _In_ HANDLE WorkerFactoryHandle\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtWorkerFactoryWorkerReady(\n    _In_ HANDLE WorkerFactoryHandle\n    );\n\nstruct _FILE_IO_COMPLETION_INFORMATION;\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtWaitForWorkViaWorkerFactory(\n    _In_ HANDLE WorkerFactoryHandle,\n    _Out_ struct _FILE_IO_COMPLETION_INFORMATION *MiniPacket\n    );\n\n#endif\n\n// Time\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtQuerySystemTime(\n    _Out_ PLARGE_INTEGER SystemTime\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtSetSystemTime(\n    _In_opt_ PLARGE_INTEGER SystemTime,\n    _Out_opt_ PLARGE_INTEGER PreviousTime\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtQueryTimerResolution(\n    _Out_ PULONG MaximumTime,\n    _Out_ PULONG MinimumTime,\n    _Out_ PULONG CurrentTime\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtSetTimerResolution(\n    _In_ ULONG DesiredTime,\n    _In_ BOOLEAN SetResolution,\n    _Out_ PULONG ActualTime\n    );\n\n// Performance Counter\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtQueryPerformanceCounter(\n    _Out_ PLARGE_INTEGER PerformanceCounter,\n    _Out_opt_ PLARGE_INTEGER PerformanceFrequency\n    );\n\n// LUIDs\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtAllocateLocallyUniqueId(\n    _Out_ PLUID Luid\n    );\n\n// UUIDs\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtSetUuidSeed(\n    _In_ PCHAR Seed\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtAllocateUuids(\n    _Out_ PULARGE_INTEGER Time,\n    _Out_ PULONG Range,\n    _Out_ PULONG Sequence,\n    _Out_ PCHAR Seed\n    );\n\n// System Information\n\n#endif // (PHNT_MODE != PHNT_MODE_KERNEL)\n\n// rev\n// private\ntypedef enum _SYSTEM_INFORMATION_CLASS\n{\n    SystemBasicInformation, // q: SYSTEM_BASIC_INFORMATION\n    SystemProcessorInformation, // q: SYSTEM_PROCESSOR_INFORMATION\n    SystemPerformanceInformation, // q: SYSTEM_PERFORMANCE_INFORMATION\n    SystemTimeOfDayInformation, // q: SYSTEM_TIMEOFDAY_INFORMATION\n    SystemPathInformation, // not implemented\n    SystemProcessInformation, // q: SYSTEM_PROCESS_INFORMATION\n    SystemCallCountInformation, // q: SYSTEM_CALL_COUNT_INFORMATION\n    SystemDeviceInformation, // q: SYSTEM_DEVICE_INFORMATION\n    SystemProcessorPerformanceInformation, // q: SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION\n    SystemFlagsInformation, // q: SYSTEM_FLAGS_INFORMATION\n    SystemCallTimeInformation, // not implemented // SYSTEM_CALL_TIME_INFORMATION // 10\n    SystemModuleInformation, // q: RTL_PROCESS_MODULES\n    SystemLocksInformation, // q: RTL_PROCESS_LOCKS\n    SystemStackTraceInformation, // q: RTL_PROCESS_BACKTRACES\n    SystemPagedPoolInformation, // not implemented\n    SystemNonPagedPoolInformation, // not implemented\n    SystemHandleInformation, // q: SYSTEM_HANDLE_INFORMATION\n    SystemObjectInformation, // q: SYSTEM_OBJECTTYPE_INFORMATION mixed with SYSTEM_OBJECT_INFORMATION\n    SystemPageFileInformation, // q: SYSTEM_PAGEFILE_INFORMATION\n    SystemVdmInstemulInformation, // q\n    SystemVdmBopInformation, // not implemented // 20\n    SystemFileCacheInformation, // q: SYSTEM_FILECACHE_INFORMATION; s (requires SeIncreaseQuotaPrivilege) (info for WorkingSetTypeSystemCache)\n    SystemPoolTagInformation, // q: SYSTEM_POOLTAG_INFORMATION\n    SystemInterruptInformation, // q: SYSTEM_INTERRUPT_INFORMATION\n    SystemDpcBehaviorInformation, // q: SYSTEM_DPC_BEHAVIOR_INFORMATION; s: SYSTEM_DPC_BEHAVIOR_INFORMATION (requires SeLoadDriverPrivilege)\n    SystemFullMemoryInformation, // not implemented\n    SystemLoadGdiDriverInformation, // s (kernel-mode only)\n    SystemUnloadGdiDriverInformation, // s (kernel-mode only)\n    SystemTimeAdjustmentInformation, // q: SYSTEM_QUERY_TIME_ADJUST_INFORMATION; s: SYSTEM_SET_TIME_ADJUST_INFORMATION (requires SeSystemtimePrivilege)\n    SystemSummaryMemoryInformation, // not implemented\n    SystemMirrorMemoryInformation, // s (requires license value \"Kernel-MemoryMirroringSupported\") (requires SeShutdownPrivilege) // 30\n    SystemPerformanceTraceInformation, // q; s: (type depends on EVENT_TRACE_INFORMATION_CLASS)\n    SystemObsolete0, // not implemented\n    SystemExceptionInformation, // q: SYSTEM_EXCEPTION_INFORMATION\n    SystemCrashDumpStateInformation, // s (requires SeDebugPrivilege)\n    SystemKernelDebuggerInformation, // q: SYSTEM_KERNEL_DEBUGGER_INFORMATION\n    SystemContextSwitchInformation, // q: SYSTEM_CONTEXT_SWITCH_INFORMATION\n    SystemRegistryQuotaInformation, // q: SYSTEM_REGISTRY_QUOTA_INFORMATION; s (requires SeIncreaseQuotaPrivilege)\n    SystemExtendServiceTableInformation, // s (requires SeLoadDriverPrivilege) // loads win32k only\n    SystemPrioritySeperation, // s (requires SeTcbPrivilege)\n    SystemVerifierAddDriverInformation, // s (requires SeDebugPrivilege) // 40\n    SystemVerifierRemoveDriverInformation, // s (requires SeDebugPrivilege)\n    SystemProcessorIdleInformation, // q: SYSTEM_PROCESSOR_IDLE_INFORMATION\n    SystemLegacyDriverInformation, // q: SYSTEM_LEGACY_DRIVER_INFORMATION\n    SystemCurrentTimeZoneInformation, // q; s: RTL_TIME_ZONE_INFORMATION\n    SystemLookasideInformation, // q: SYSTEM_LOOKASIDE_INFORMATION\n    SystemTimeSlipNotification, // s (requires SeSystemtimePrivilege)\n    SystemSessionCreate, // not implemented\n    SystemSessionDetach, // not implemented\n    SystemSessionInformation, // not implemented (SYSTEM_SESSION_INFORMATION)\n    SystemRangeStartInformation, // q: SYSTEM_RANGE_START_INFORMATION // 50\n    SystemVerifierInformation, // q: SYSTEM_VERIFIER_INFORMATION; s (requires SeDebugPrivilege)\n    SystemVerifierThunkExtend, // s (kernel-mode only)\n    SystemSessionProcessInformation, // q: SYSTEM_SESSION_PROCESS_INFORMATION\n    SystemLoadGdiDriverInSystemSpace, // s (kernel-mode only) (same as SystemLoadGdiDriverInformation)\n    SystemNumaProcessorMap, // q\n    SystemPrefetcherInformation, // q: PREFETCHER_INFORMATION; s: PREFETCHER_INFORMATION // PfSnQueryPrefetcherInformation\n    SystemExtendedProcessInformation, // q: SYSTEM_PROCESS_INFORMATION\n    SystemRecommendedSharedDataAlignment, // q\n    SystemComPlusPackage, // q; s\n    SystemNumaAvailableMemory, // 60\n    SystemProcessorPowerInformation, // q: SYSTEM_PROCESSOR_POWER_INFORMATION\n    SystemEmulationBasicInformation, // q\n    SystemEmulationProcessorInformation,\n    SystemExtendedHandleInformation, // q: SYSTEM_HANDLE_INFORMATION_EX\n    SystemLostDelayedWriteInformation, // q: ULONG\n    SystemBigPoolInformation, // q: SYSTEM_BIGPOOL_INFORMATION\n    SystemSessionPoolTagInformation, // q: SYSTEM_SESSION_POOLTAG_INFORMATION\n    SystemSessionMappedViewInformation, // q: SYSTEM_SESSION_MAPPED_VIEW_INFORMATION\n    SystemHotpatchInformation, // q; s: SYSTEM_HOTPATCH_CODE_INFORMATION\n    SystemObjectSecurityMode, // q: ULONG // 70\n    SystemWatchdogTimerHandler, // s (kernel-mode only)\n    SystemWatchdogTimerInformation, // q (kernel-mode only); s (kernel-mode only)\n    SystemLogicalProcessorInformation, // q: SYSTEM_LOGICAL_PROCESSOR_INFORMATION\n    SystemWow64SharedInformationObsolete, // not implemented\n    SystemRegisterFirmwareTableInformationHandler, // s (kernel-mode only)\n    SystemFirmwareTableInformation, // SYSTEM_FIRMWARE_TABLE_INFORMATION\n    SystemModuleInformationEx, // q: RTL_PROCESS_MODULE_INFORMATION_EX\n    SystemVerifierTriageInformation, // not implemented\n    SystemSuperfetchInformation, // q; s: SUPERFETCH_INFORMATION // PfQuerySuperfetchInformation\n    SystemMemoryListInformation, // q: SYSTEM_MEMORY_LIST_INFORMATION; s: SYSTEM_MEMORY_LIST_COMMAND (requires SeProfileSingleProcessPrivilege) // 80\n    SystemFileCacheInformationEx, // q: SYSTEM_FILECACHE_INFORMATION; s (requires SeIncreaseQuotaPrivilege) (same as SystemFileCacheInformation)\n    SystemThreadPriorityClientIdInformation, // s: SYSTEM_THREAD_CID_PRIORITY_INFORMATION (requires SeIncreaseBasePriorityPrivilege)\n    SystemProcessorIdleCycleTimeInformation, // q: SYSTEM_PROCESSOR_IDLE_CYCLE_TIME_INFORMATION[]\n    SystemVerifierCancellationInformation, // not implemented // name:wow64:whNT32QuerySystemVerifierCancellationInformation\n    SystemProcessorPowerInformationEx, // not implemented\n    SystemRefTraceInformation, // q; s: SYSTEM_REF_TRACE_INFORMATION // ObQueryRefTraceInformation\n    SystemSpecialPoolInformation, // q; s (requires SeDebugPrivilege) // MmSpecialPoolTag, then MmSpecialPoolCatchOverruns != 0\n    SystemProcessIdInformation, // q: SYSTEM_PROCESS_ID_INFORMATION\n    SystemErrorPortInformation, // s (requires SeTcbPrivilege)\n    SystemBootEnvironmentInformation, // q: SYSTEM_BOOT_ENVIRONMENT_INFORMATION // 90\n    SystemHypervisorInformation, // q; s (kernel-mode only)\n    SystemVerifierInformationEx, // q; s: SYSTEM_VERIFIER_INFORMATION_EX\n    SystemTimeZoneInformation, // s (requires SeTimeZonePrivilege)\n    SystemImageFileExecutionOptionsInformation, // s: SYSTEM_IMAGE_FILE_EXECUTION_OPTIONS_INFORMATION (requires SeTcbPrivilege)\n    SystemCoverageInformation, // q; s // name:wow64:whNT32QuerySystemCoverageInformation; ExpCovQueryInformation\n    SystemPrefetchPatchInformation, // not implemented\n    SystemVerifierFaultsInformation, // s (requires SeDebugPrivilege)\n    SystemSystemPartitionInformation, // q: SYSTEM_SYSTEM_PARTITION_INFORMATION\n    SystemSystemDiskInformation, // q: SYSTEM_SYSTEM_DISK_INFORMATION\n    SystemProcessorPerformanceDistribution, // q: SYSTEM_PROCESSOR_PERFORMANCE_DISTRIBUTION // 100\n    SystemNumaProximityNodeInformation, // q\n    SystemDynamicTimeZoneInformation, // q; s (requires SeTimeZonePrivilege)\n    SystemCodeIntegrityInformation, // q: SYSTEM_CODEINTEGRITY_INFORMATION // SeCodeIntegrityQueryInformation\n    SystemProcessorMicrocodeUpdateInformation, // s\n    SystemProcessorBrandString, // q // HaliQuerySystemInformation -> HalpGetProcessorBrandString, info class 23\n    SystemVirtualAddressInformation, // q: SYSTEM_VA_LIST_INFORMATION[]; s: SYSTEM_VA_LIST_INFORMATION[] (requires SeIncreaseQuotaPrivilege) // MmQuerySystemVaInformation\n    SystemLogicalProcessorAndGroupInformation, // q: SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX // since WIN7 // KeQueryLogicalProcessorRelationship\n    SystemProcessorCycleTimeInformation, // q: SYSTEM_PROCESSOR_CYCLE_TIME_INFORMATION[]\n    SystemStoreInformation, // q; s // SmQueryStoreInformation\n    SystemRegistryAppendString, // s: SYSTEM_REGISTRY_APPEND_STRING_PARAMETERS // 110\n    SystemAitSamplingValue, // s: ULONG (requires SeProfileSingleProcessPrivilege)\n    SystemVhdBootInformation, // q: SYSTEM_VHD_BOOT_INFORMATION\n    SystemCpuQuotaInformation, // q; s // PsQueryCpuQuotaInformation\n    SystemNativeBasicInformation, // not implemented\n    SystemSpare1, // not implemented\n    SystemLowPriorityIoInformation, // q: SYSTEM_LOW_PRIORITY_IO_INFORMATION\n    SystemTpmBootEntropyInformation, // q: TPM_BOOT_ENTROPY_NT_RESULT // ExQueryTpmBootEntropyInformation\n    SystemVerifierCountersInformation, // q: SYSTEM_VERIFIER_COUNTERS_INFORMATION\n    SystemPagedPoolInformationEx, // q: SYSTEM_FILECACHE_INFORMATION; s (requires SeIncreaseQuotaPrivilege) (info for WorkingSetTypePagedPool)\n    SystemSystemPtesInformationEx, // q: SYSTEM_FILECACHE_INFORMATION; s (requires SeIncreaseQuotaPrivilege) (info for WorkingSetTypeSystemPtes) // 120\n    SystemNodeDistanceInformation, // q\n    SystemAcpiAuditInformation, // q: SYSTEM_ACPI_AUDIT_INFORMATION // HaliQuerySystemInformation -> HalpAuditQueryResults, info class 26\n    SystemBasicPerformanceInformation, // q: SYSTEM_BASIC_PERFORMANCE_INFORMATION // name:wow64:whNtQuerySystemInformation_SystemBasicPerformanceInformation\n    SystemQueryPerformanceCounterInformation, // q: SYSTEM_QUERY_PERFORMANCE_COUNTER_INFORMATION // since WIN7 SP1\n    SystemSessionBigPoolInformation, // q: SYSTEM_SESSION_POOLTAG_INFORMATION // since WIN8\n    SystemBootGraphicsInformation, // q; s: SYSTEM_BOOT_GRAPHICS_INFORMATION (kernel-mode only)\n    SystemScrubPhysicalMemoryInformation, // q; s: MEMORY_SCRUB_INFORMATION\n    SystemBadPageInformation,\n    SystemProcessorProfileControlArea, // q; s: SYSTEM_PROCESSOR_PROFILE_CONTROL_AREA\n    SystemCombinePhysicalMemoryInformation, // s: MEMORY_COMBINE_INFORMATION, MEMORY_COMBINE_INFORMATION_EX, MEMORY_COMBINE_INFORMATION_EX2 // 130\n    SystemEntropyInterruptTimingCallback,\n    SystemConsoleInformation, // q: SYSTEM_CONSOLE_INFORMATION\n    SystemPlatformBinaryInformation, // q: SYSTEM_PLATFORM_BINARY_INFORMATION\n    SystemThrottleNotificationInformation,\n    SystemHypervisorProcessorCountInformation, // q: SYSTEM_HYPERVISOR_PROCESSOR_COUNT_INFORMATION\n    SystemDeviceDataInformation, // q: SYSTEM_DEVICE_DATA_INFORMATION\n    SystemDeviceDataEnumerationInformation,\n    SystemMemoryTopologyInformation, // q: SYSTEM_MEMORY_TOPOLOGY_INFORMATION\n    SystemMemoryChannelInformation, // q: SYSTEM_MEMORY_CHANNEL_INFORMATION\n    SystemBootLogoInformation, // q: SYSTEM_BOOT_LOGO_INFORMATION // 140\n    SystemProcessorPerformanceInformationEx, // q: SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION_EX // since WINBLUE\n    SystemSpare0,\n    SystemSecureBootPolicyInformation, // q: SYSTEM_SECUREBOOT_POLICY_INFORMATION\n    SystemPageFileInformationEx, // q: SYSTEM_PAGEFILE_INFORMATION_EX\n    SystemSecureBootInformation, // q: SYSTEM_SECUREBOOT_INFORMATION\n    SystemEntropyInterruptTimingRawInformation,\n    SystemPortableWorkspaceEfiLauncherInformation, // q: SYSTEM_PORTABLE_WORKSPACE_EFI_LAUNCHER_INFORMATION\n    SystemFullProcessInformation, // q: SYSTEM_PROCESS_INFORMATION with SYSTEM_PROCESS_INFORMATION_EXTENSION (requires admin)\n    SystemKernelDebuggerInformationEx, // q: SYSTEM_KERNEL_DEBUGGER_INFORMATION_EX\n    SystemBootMetadataInformation, // 150\n    SystemSoftRebootInformation,\n    SystemElamCertificateInformation, // s: SYSTEM_ELAM_CERTIFICATE_INFORMATION\n    SystemOfflineDumpConfigInformation,\n    SystemProcessorFeaturesInformation, // q: SYSTEM_PROCESSOR_FEATURES_INFORMATION\n    SystemRegistryReconciliationInformation,\n    SystemEdidInformation,\n    SystemManufacturingInformation, // q: SYSTEM_MANUFACTURING_INFORMATION // since THRESHOLD\n    SystemEnergyEstimationConfigInformation, // q: SYSTEM_ENERGY_ESTIMATION_CONFIG_INFORMATION\n    SystemHypervisorDetailInformation, // q: SYSTEM_HYPERVISOR_DETAIL_INFORMATION\n    SystemProcessorCycleStatsInformation, // q: SYSTEM_PROCESSOR_CYCLE_STATS_INFORMATION // 160\n    SystemVmGenerationCountInformation,\n    SystemTrustedPlatformModuleInformation, // q: SYSTEM_TPM_INFORMATION\n    SystemKernelDebuggerFlags,\n    SystemCodeIntegrityPolicyInformation, // q: SYSTEM_CODEINTEGRITYPOLICY_INFORMATION\n    SystemIsolatedUserModeInformation, // q: SYSTEM_ISOLATED_USER_MODE_INFORMATION\n    SystemHardwareSecurityTestInterfaceResultsInformation,\n    SystemSingleModuleInformation, // q: SYSTEM_SINGLE_MODULE_INFORMATION\n    SystemAllowedCpuSetsInformation,\n    SystemDmaProtectionInformation, // q: SYSTEM_DMA_PROTECTION_INFORMATION\n    SystemInterruptCpuSetsInformation, // q: SYSTEM_INTERRUPT_CPU_SET_INFORMATION // 170\n    SystemSecureBootPolicyFullInformation, // q: SYSTEM_SECUREBOOT_POLICY_FULL_INFORMATION\n    SystemCodeIntegrityPolicyFullInformation,\n    SystemAffinitizedInterruptProcessorInformation,\n    SystemRootSiloInformation, // q: SYSTEM_ROOT_SILO_INFORMATION\n    SystemCpuSetInformation, // q: SYSTEM_CPU_SET_INFORMATION // since THRESHOLD2\n    SystemCpuSetTagInformation, // q: SYSTEM_CPU_SET_TAG_INFORMATION\n    SystemWin32WerStartCallout,\n    SystemSecureKernelProfileInformation, // q: SYSTEM_SECURE_KERNEL_HYPERGUARD_PROFILE_INFORMATION\n    SystemCodeIntegrityPlatformManifestInformation, // q: SYSTEM_SECUREBOOT_PLATFORM_MANIFEST_INFORMATION // since REDSTONE\n    SystemInterruptSteeringInformation, // 180\n    SystemSupportedProcessorArchitectures,\n    SystemMemoryUsageInformation, // q: SYSTEM_MEMORY_USAGE_INFORMATION\n    SystemCodeIntegrityCertificateInformation, // q: SYSTEM_CODEINTEGRITY_CERTIFICATE_INFORMATION\n    SystemPhysicalMemoryInformation, // q: SYSTEM_PHYSICAL_MEMORY_INFORMATION // since REDSTONE2\n    SystemControlFlowTransition,\n    SystemKernelDebuggingAllowed,\n    SystemActivityModerationExeState, // SYSTEM_ACTIVITY_MODERATION_EXE_STATE\n    SystemActivityModerationUserSettings, // SYSTEM_ACTIVITY_MODERATION_USER_SETTINGS\n    SystemCodeIntegrityPoliciesFullInformation,\n    SystemCodeIntegrityUnlockInformation, // SYSTEM_CODEINTEGRITY_UNLOCK_INFORMATION // 190\n    SystemIntegrityQuotaInformation,\n    SystemFlushInformation, // q: SYSTEM_FLUSH_INFORMATION\n    SystemProcessorIdleMaskInformation, // since REDSTONE3\n    SystemSecureDumpEncryptionInformation,\n    SystemWriteConstraintInformation, // SYSTEM_WRITE_CONSTRAINT_INFORMATION\n    SystemKernelVaShadowInformation, // SYSTEM_KERNEL_VA_SHADOW_INFORMATION\n    SystemSpeculationControlInformation = 201, // SYSTEM_SPECULATION_CONTROL_INFORMATION\n    MaxSystemInfoClass\n} SYSTEM_INFORMATION_CLASS;\n\ntypedef struct _SYSTEM_BASIC_INFORMATION\n{\n    ULONG Reserved;\n    ULONG TimerResolution;\n    ULONG PageSize;\n    ULONG NumberOfPhysicalPages;\n    ULONG LowestPhysicalPageNumber;\n    ULONG HighestPhysicalPageNumber;\n    ULONG AllocationGranularity;\n    ULONG_PTR MinimumUserModeAddress;\n    ULONG_PTR MaximumUserModeAddress;\n    ULONG_PTR ActiveProcessorsAffinityMask;\n    CCHAR NumberOfProcessors;\n} SYSTEM_BASIC_INFORMATION, *PSYSTEM_BASIC_INFORMATION;\n\ntypedef struct _SYSTEM_PROCESSOR_INFORMATION\n{\n    USHORT ProcessorArchitecture;\n    USHORT ProcessorLevel;\n    USHORT ProcessorRevision;\n    USHORT ProcessorCount;\n    ULONG ProcessorFeatureBits;\n} SYSTEM_PROCESSOR_INFORMATION, *PSYSTEM_PROCESSOR_INFORMATION;\n\ntypedef struct _SYSTEM_PERFORMANCE_INFORMATION\n{\n    LARGE_INTEGER IdleProcessTime;\n    LARGE_INTEGER IoReadTransferCount;\n    LARGE_INTEGER IoWriteTransferCount;\n    LARGE_INTEGER IoOtherTransferCount;\n    ULONG IoReadOperationCount;\n    ULONG IoWriteOperationCount;\n    ULONG IoOtherOperationCount;\n    ULONG AvailablePages;\n    ULONG CommittedPages;\n    ULONG CommitLimit;\n    ULONG PeakCommitment;\n    ULONG PageFaultCount;\n    ULONG CopyOnWriteCount;\n    ULONG TransitionCount;\n    ULONG CacheTransitionCount;\n    ULONG DemandZeroCount;\n    ULONG PageReadCount;\n    ULONG PageReadIoCount;\n    ULONG CacheReadCount;\n    ULONG CacheIoCount;\n    ULONG DirtyPagesWriteCount;\n    ULONG DirtyWriteIoCount;\n    ULONG MappedPagesWriteCount;\n    ULONG MappedWriteIoCount;\n    ULONG PagedPoolPages;\n    ULONG NonPagedPoolPages;\n    ULONG PagedPoolAllocs;\n    ULONG PagedPoolFrees;\n    ULONG NonPagedPoolAllocs;\n    ULONG NonPagedPoolFrees;\n    ULONG FreeSystemPtes;\n    ULONG ResidentSystemCodePage;\n    ULONG TotalSystemDriverPages;\n    ULONG TotalSystemCodePages;\n    ULONG NonPagedPoolLookasideHits;\n    ULONG PagedPoolLookasideHits;\n    ULONG AvailablePagedPoolPages;\n    ULONG ResidentSystemCachePage;\n    ULONG ResidentPagedPoolPage;\n    ULONG ResidentSystemDriverPage;\n    ULONG CcFastReadNoWait;\n    ULONG CcFastReadWait;\n    ULONG CcFastReadResourceMiss;\n    ULONG CcFastReadNotPossible;\n    ULONG CcFastMdlReadNoWait;\n    ULONG CcFastMdlReadWait;\n    ULONG CcFastMdlReadResourceMiss;\n    ULONG CcFastMdlReadNotPossible;\n    ULONG CcMapDataNoWait;\n    ULONG CcMapDataWait;\n    ULONG CcMapDataNoWaitMiss;\n    ULONG CcMapDataWaitMiss;\n    ULONG CcPinMappedDataCount;\n    ULONG CcPinReadNoWait;\n    ULONG CcPinReadWait;\n    ULONG CcPinReadNoWaitMiss;\n    ULONG CcPinReadWaitMiss;\n    ULONG CcCopyReadNoWait;\n    ULONG CcCopyReadWait;\n    ULONG CcCopyReadNoWaitMiss;\n    ULONG CcCopyReadWaitMiss;\n    ULONG CcMdlReadNoWait;\n    ULONG CcMdlReadWait;\n    ULONG CcMdlReadNoWaitMiss;\n    ULONG CcMdlReadWaitMiss;\n    ULONG CcReadAheadIos;\n    ULONG CcLazyWriteIos;\n    ULONG CcLazyWritePages;\n    ULONG CcDataFlushes;\n    ULONG CcDataPages;\n    ULONG ContextSwitches;\n    ULONG FirstLevelTbFills;\n    ULONG SecondLevelTbFills;\n    ULONG SystemCalls;\n    ULONGLONG CcTotalDirtyPages; // since THRESHOLD\n    ULONGLONG CcDirtyPageThreshold; // since THRESHOLD\n    LONGLONG ResidentAvailablePages; // since THRESHOLD\n    ULONGLONG SharedCommittedPages; // since THRESHOLD\n} SYSTEM_PERFORMANCE_INFORMATION, *PSYSTEM_PERFORMANCE_INFORMATION;\n\ntypedef struct _SYSTEM_TIMEOFDAY_INFORMATION\n{\n    LARGE_INTEGER BootTime;\n    LARGE_INTEGER CurrentTime;\n    LARGE_INTEGER TimeZoneBias;\n    ULONG TimeZoneId;\n    ULONG Reserved;\n    ULONGLONG BootTimeBias;\n    ULONGLONG SleepTimeBias;\n} SYSTEM_TIMEOFDAY_INFORMATION, *PSYSTEM_TIMEOFDAY_INFORMATION;\n\ntypedef struct _SYSTEM_THREAD_INFORMATION\n{\n    LARGE_INTEGER KernelTime;\n    LARGE_INTEGER UserTime;\n    LARGE_INTEGER CreateTime;\n    ULONG WaitTime;\n    PVOID StartAddress;\n    CLIENT_ID ClientId;\n    KPRIORITY Priority;\n    LONG BasePriority;\n    ULONG ContextSwitches;\n    ULONG ThreadState;\n    KWAIT_REASON WaitReason;\n} SYSTEM_THREAD_INFORMATION, *PSYSTEM_THREAD_INFORMATION;\n\ntypedef struct _TEB *PTEB;\n\n// private\ntypedef struct _SYSTEM_EXTENDED_THREAD_INFORMATION\n{\n    SYSTEM_THREAD_INFORMATION ThreadInfo;\n    PVOID StackBase;\n    PVOID StackLimit;\n    PVOID Win32StartAddress;\n    PTEB TebBase; // since VISTA\n    ULONG_PTR Reserved2;\n    ULONG_PTR Reserved3;\n    ULONG_PTR Reserved4;\n} SYSTEM_EXTENDED_THREAD_INFORMATION, *PSYSTEM_EXTENDED_THREAD_INFORMATION;\n\ntypedef struct _SYSTEM_PROCESS_INFORMATION\n{\n    ULONG NextEntryOffset;\n    ULONG NumberOfThreads;\n    LARGE_INTEGER WorkingSetPrivateSize; // since VISTA\n    ULONG HardFaultCount; // since WIN7\n    ULONG NumberOfThreadsHighWatermark; // since WIN7\n    ULONGLONG CycleTime; // since WIN7\n    LARGE_INTEGER CreateTime;\n    LARGE_INTEGER UserTime;\n    LARGE_INTEGER KernelTime;\n    UNICODE_STRING ImageName;\n    KPRIORITY BasePriority;\n    HANDLE UniqueProcessId;\n    HANDLE InheritedFromUniqueProcessId;\n    ULONG HandleCount;\n    ULONG SessionId;\n    ULONG_PTR UniqueProcessKey; // since VISTA (requires SystemExtendedProcessInformation)\n    SIZE_T PeakVirtualSize;\n    SIZE_T VirtualSize;\n    ULONG PageFaultCount;\n    SIZE_T PeakWorkingSetSize;\n    SIZE_T WorkingSetSize;\n    SIZE_T QuotaPeakPagedPoolUsage;\n    SIZE_T QuotaPagedPoolUsage;\n    SIZE_T QuotaPeakNonPagedPoolUsage;\n    SIZE_T QuotaNonPagedPoolUsage;\n    SIZE_T PagefileUsage;\n    SIZE_T PeakPagefileUsage;\n    SIZE_T PrivatePageCount;\n    LARGE_INTEGER ReadOperationCount;\n    LARGE_INTEGER WriteOperationCount;\n    LARGE_INTEGER OtherOperationCount;\n    LARGE_INTEGER ReadTransferCount;\n    LARGE_INTEGER WriteTransferCount;\n    LARGE_INTEGER OtherTransferCount;\n    SYSTEM_THREAD_INFORMATION Threads[1]; // SystemProcessInformation\n    // SYSTEM_EXTENDED_THREAD_INFORMATION Threads[1]; // SystemExtendedProcessinformation\n    // SYSTEM_EXTENDED_THREAD_INFORMATION + SYSTEM_PROCESS_INFORMATION_EXTENSION // SystemFullProcessInformation\n} SYSTEM_PROCESS_INFORMATION, *PSYSTEM_PROCESS_INFORMATION;\n\ntypedef struct _SYSTEM_CALL_COUNT_INFORMATION\n{\n    ULONG Length;\n    ULONG NumberOfTables;\n} SYSTEM_CALL_COUNT_INFORMATION, *PSYSTEM_CALL_COUNT_INFORMATION;\n\ntypedef struct _SYSTEM_DEVICE_INFORMATION\n{\n    ULONG NumberOfDisks;\n    ULONG NumberOfFloppies;\n    ULONG NumberOfCdRoms;\n    ULONG NumberOfTapes;\n    ULONG NumberOfSerialPorts;\n    ULONG NumberOfParallelPorts;\n} SYSTEM_DEVICE_INFORMATION, *PSYSTEM_DEVICE_INFORMATION;\n\ntypedef struct _SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION\n{\n    LARGE_INTEGER IdleTime;\n    LARGE_INTEGER KernelTime;\n    LARGE_INTEGER UserTime;\n    LARGE_INTEGER DpcTime;\n    LARGE_INTEGER InterruptTime;\n    ULONG InterruptCount;\n} SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION, *PSYSTEM_PROCESSOR_PERFORMANCE_INFORMATION;\n\ntypedef struct _SYSTEM_FLAGS_INFORMATION\n{\n    ULONG Flags; // NtGlobalFlag\n} SYSTEM_FLAGS_INFORMATION, *PSYSTEM_FLAGS_INFORMATION;\n\n// private\ntypedef struct _SYSTEM_CALL_TIME_INFORMATION\n{\n    ULONG Length;\n    ULONG TotalCalls;\n    LARGE_INTEGER TimeOfCalls[1];\n} SYSTEM_CALL_TIME_INFORMATION, *PSYSTEM_CALL_TIME_INFORMATION;\n\n// private\ntypedef struct _RTL_PROCESS_LOCK_INFORMATION\n{\n    PVOID Address;\n    USHORT Type;\n    USHORT CreatorBackTraceIndex;\n    HANDLE OwningThread;\n    LONG LockCount;\n    ULONG ContentionCount;\n    ULONG EntryCount;\n    LONG RecursionCount;\n    ULONG NumberOfWaitingShared;\n    ULONG NumberOfWaitingExclusive;\n} RTL_PROCESS_LOCK_INFORMATION, *PRTL_PROCESS_LOCK_INFORMATION;\n\n// private\ntypedef struct _RTL_PROCESS_LOCKS\n{\n    ULONG NumberOfLocks;\n    RTL_PROCESS_LOCK_INFORMATION Locks[1];\n} RTL_PROCESS_LOCKS, *PRTL_PROCESS_LOCKS;\n\n// private\ntypedef struct _RTL_PROCESS_BACKTRACE_INFORMATION\n{\n    PCHAR SymbolicBackTrace;\n    ULONG TraceCount;\n    USHORT Index;\n    USHORT Depth;\n    PVOID BackTrace[32];\n} RTL_PROCESS_BACKTRACE_INFORMATION, *PRTL_PROCESS_BACKTRACE_INFORMATION;\n\n// private\ntypedef struct _RTL_PROCESS_BACKTRACES\n{\n    ULONG CommittedMemory;\n    ULONG ReservedMemory;\n    ULONG NumberOfBackTraceLookups;\n    ULONG NumberOfBackTraces;\n    RTL_PROCESS_BACKTRACE_INFORMATION BackTraces[1];\n} RTL_PROCESS_BACKTRACES, *PRTL_PROCESS_BACKTRACES;\n\ntypedef struct _SYSTEM_HANDLE_TABLE_ENTRY_INFO\n{\n    USHORT UniqueProcessId;\n    USHORT CreatorBackTraceIndex;\n    UCHAR ObjectTypeIndex;\n    UCHAR HandleAttributes;\n    USHORT HandleValue;\n    PVOID Object;\n    ULONG GrantedAccess;\n} SYSTEM_HANDLE_TABLE_ENTRY_INFO, *PSYSTEM_HANDLE_TABLE_ENTRY_INFO;\n\ntypedef struct _SYSTEM_HANDLE_INFORMATION\n{\n    ULONG NumberOfHandles;\n    SYSTEM_HANDLE_TABLE_ENTRY_INFO Handles[1];\n} SYSTEM_HANDLE_INFORMATION, *PSYSTEM_HANDLE_INFORMATION;\n\ntypedef struct _SYSTEM_OBJECTTYPE_INFORMATION\n{\n    ULONG NextEntryOffset;\n    ULONG NumberOfObjects;\n    ULONG NumberOfHandles;\n    ULONG TypeIndex;\n    ULONG InvalidAttributes;\n    GENERIC_MAPPING GenericMapping;\n    ULONG ValidAccessMask;\n    ULONG PoolType;\n    BOOLEAN SecurityRequired;\n    BOOLEAN WaitableObject;\n    UNICODE_STRING TypeName;\n} SYSTEM_OBJECTTYPE_INFORMATION, *PSYSTEM_OBJECTTYPE_INFORMATION;\n\ntypedef struct _SYSTEM_OBJECT_INFORMATION\n{\n    ULONG NextEntryOffset;\n    PVOID Object;\n    HANDLE CreatorUniqueProcess;\n    USHORT CreatorBackTraceIndex;\n    USHORT Flags;\n    LONG PointerCount;\n    LONG HandleCount;\n    ULONG PagedPoolCharge;\n    ULONG NonPagedPoolCharge;\n    HANDLE ExclusiveProcessId;\n    PVOID SecurityDescriptor;\n    UNICODE_STRING NameInfo;\n} SYSTEM_OBJECT_INFORMATION, *PSYSTEM_OBJECT_INFORMATION;\n\ntypedef struct _SYSTEM_PAGEFILE_INFORMATION\n{\n    ULONG NextEntryOffset;\n    ULONG TotalSize;\n    ULONG TotalInUse;\n    ULONG PeakUsage;\n    UNICODE_STRING PageFileName;\n} SYSTEM_PAGEFILE_INFORMATION, *PSYSTEM_PAGEFILE_INFORMATION;\n\n#define MM_WORKING_SET_MAX_HARD_ENABLE 0x1\n#define MM_WORKING_SET_MAX_HARD_DISABLE 0x2\n#define MM_WORKING_SET_MIN_HARD_ENABLE 0x4\n#define MM_WORKING_SET_MIN_HARD_DISABLE 0x8\n\ntypedef struct _SYSTEM_FILECACHE_INFORMATION\n{\n    SIZE_T CurrentSize;\n    SIZE_T PeakSize;\n    ULONG PageFaultCount;\n    SIZE_T MinimumWorkingSet;\n    SIZE_T MaximumWorkingSet;\n    SIZE_T CurrentSizeIncludingTransitionInPages;\n    SIZE_T PeakSizeIncludingTransitionInPages;\n    ULONG TransitionRePurposeCount;\n    ULONG Flags;\n} SYSTEM_FILECACHE_INFORMATION, *PSYSTEM_FILECACHE_INFORMATION;\n\n// Can be used instead of SYSTEM_FILECACHE_INFORMATION\ntypedef struct _SYSTEM_BASIC_WORKING_SET_INFORMATION\n{\n    SIZE_T CurrentSize;\n    SIZE_T PeakSize;\n    ULONG PageFaultCount;\n} SYSTEM_BASIC_WORKING_SET_INFORMATION, *PSYSTEM_BASIC_WORKING_SET_INFORMATION;\n\ntypedef struct _SYSTEM_POOLTAG\n{\n    union\n    {\n        UCHAR Tag[4];\n        ULONG TagUlong;\n    };\n    ULONG PagedAllocs;\n    ULONG PagedFrees;\n    SIZE_T PagedUsed;\n    ULONG NonPagedAllocs;\n    ULONG NonPagedFrees;\n    SIZE_T NonPagedUsed;\n} SYSTEM_POOLTAG, *PSYSTEM_POOLTAG;\n\ntypedef struct _SYSTEM_POOLTAG_INFORMATION\n{\n    ULONG Count;\n    SYSTEM_POOLTAG TagInfo[1];\n} SYSTEM_POOLTAG_INFORMATION, *PSYSTEM_POOLTAG_INFORMATION;\n\ntypedef struct _SYSTEM_INTERRUPT_INFORMATION\n{\n    ULONG ContextSwitches;\n    ULONG DpcCount;\n    ULONG DpcRate;\n    ULONG TimeIncrement;\n    ULONG DpcBypassCount;\n    ULONG ApcBypassCount;\n} SYSTEM_INTERRUPT_INFORMATION, *PSYSTEM_INTERRUPT_INFORMATION;\n\ntypedef struct _SYSTEM_DPC_BEHAVIOR_INFORMATION\n{\n    ULONG Spare;\n    ULONG DpcQueueDepth;\n    ULONG MinimumDpcRate;\n    ULONG AdjustDpcThreshold;\n    ULONG IdealDpcRate;\n} SYSTEM_DPC_BEHAVIOR_INFORMATION, *PSYSTEM_DPC_BEHAVIOR_INFORMATION;\n\ntypedef struct _SYSTEM_QUERY_TIME_ADJUST_INFORMATION\n{\n    ULONG TimeAdjustment;\n    ULONG TimeIncrement;\n    BOOLEAN Enable;\n} SYSTEM_QUERY_TIME_ADJUST_INFORMATION, *PSYSTEM_QUERY_TIME_ADJUST_INFORMATION;\n\ntypedef struct _SYSTEM_QUERY_TIME_ADJUST_INFORMATION_PRECISE\n{\n    ULONGLONG TimeAdjustment;\n    ULONGLONG TimeIncrement;\n    BOOLEAN Enable;\n} SYSTEM_QUERY_TIME_ADJUST_INFORMATION_PRECISE, *PSYSTEM_QUERY_TIME_ADJUST_INFORMATION_PRECISE;\n\ntypedef struct _SYSTEM_SET_TIME_ADJUST_INFORMATION\n{\n    ULONG TimeAdjustment;\n    BOOLEAN Enable;\n} SYSTEM_SET_TIME_ADJUST_INFORMATION, *PSYSTEM_SET_TIME_ADJUST_INFORMATION;\n\ntypedef struct _SYSTEM_SET_TIME_ADJUST_INFORMATION_PRECISE\n{\n    ULONGLONG TimeAdjustment;\n    BOOLEAN Enable;\n} SYSTEM_SET_TIME_ADJUST_INFORMATION_PRECISE, *PSYSTEM_SET_TIME_ADJUST_INFORMATION_PRECISE;\n\ntypedef enum _EVENT_TRACE_INFORMATION_CLASS\n{\n    EventTraceKernelVersionInformation, // EVENT_TRACE_VERSION_INFORMATION\n    EventTraceGroupMaskInformation, // EVENT_TRACE_GROUPMASK_INFORMATION\n    EventTracePerformanceInformation, // EVENT_TRACE_PERFORMANCE_INFORMATION\n    EventTraceTimeProfileInformation, // EVENT_TRACE_TIME_PROFILE_INFORMATION\n    EventTraceSessionSecurityInformation, // EVENT_TRACE_SESSION_SECURITY_INFORMATION\n    EventTraceSpinlockInformation, // EVENT_TRACE_SPINLOCK_INFORMATION\n    EventTraceStackTracingInformation, // EVENT_TRACE_SYSTEM_EVENT_INFORMATION\n    EventTraceExecutiveResourceInformation, // EVENT_TRACE_EXECUTIVE_RESOURCE_INFORMATION\n    EventTraceHeapTracingInformation, // EVENT_TRACE_HEAP_TRACING_INFORMATION\n    EventTraceHeapSummaryTracingInformation, // EVENT_TRACE_HEAP_TRACING_INFORMATION\n    EventTracePoolTagFilterInformation, // EVENT_TRACE_TAG_FILTER_INFORMATION\n    EventTracePebsTracingInformation, // EVENT_TRACE_SYSTEM_EVENT_INFORMATION \n    EventTraceProfileConfigInformation, // EVENT_TRACE_PROFILE_COUNTER_INFORMATION\n    EventTraceProfileSourceListInformation, // EVENT_TRACE_PROFILE_LIST_INFORMATION\n    EventTraceProfileEventListInformation, // EVENT_TRACE_SYSTEM_EVENT_INFORMATION \n    EventTraceProfileCounterListInformation, // EVENT_TRACE_PROFILE_COUNTER_INFORMATION \n    EventTraceStackCachingInformation, // EVENT_TRACE_STACK_CACHING_INFORMATION\n    EventTraceObjectTypeFilterInformation, // EVENT_TRACE_TAG_FILTER_INFORMATION\n    EventTraceSoftRestartInformation, // EVENT_TRACE_SOFT_RESTART_INFORMATION\n    EventTraceLastBranchConfigurationInformation, // REDSTONE3\n    EventTraceLastBranchEventListInformation,\n    MaxEventTraceInfoClass\n} EVENT_TRACE_INFORMATION_CLASS;\n\ntypedef struct _EVENT_TRACE_VERSION_INFORMATION\n{\n    EVENT_TRACE_INFORMATION_CLASS EventTraceInformationClass;\n    ULONG EventTraceKernelVersion;\n} EVENT_TRACE_VERSION_INFORMATION, *PEVENT_TRACE_VERSION_INFORMATION;\n\ntypedef struct _PERFINFO_GROUPMASK\n{\n    ULONG Masks[8];\n} PERFINFO_GROUPMASK, *PPERFINFO_GROUPMASK;\n\ntypedef struct _EVENT_TRACE_GROUPMASK_INFORMATION\n{\n    EVENT_TRACE_INFORMATION_CLASS EventTraceInformationClass;\n    HANDLE TraceHandle;\n    PERFINFO_GROUPMASK EventTraceGroupMasks;\n} EVENT_TRACE_GROUPMASK_INFORMATION, *PEVENT_TRACE_GROUPMASK_INFORMATION;\n\ntypedef struct _EVENT_TRACE_PERFORMANCE_INFORMATION\n{\n    EVENT_TRACE_INFORMATION_CLASS EventTraceInformationClass;\n    LARGE_INTEGER LogfileBytesWritten;\n} EVENT_TRACE_PERFORMANCE_INFORMATION, *PEVENT_TRACE_PERFORMANCE_INFORMATION;\n\ntypedef struct _EVENT_TRACE_TIME_PROFILE_INFORMATION\n{\n    EVENT_TRACE_INFORMATION_CLASS EventTraceInformationClass;\n    ULONG ProfileInterval;\n} EVENT_TRACE_TIME_PROFILE_INFORMATION, *PEVENT_TRACE_TIME_PROFILE_INFORMATION;\n\ntypedef struct _EVENT_TRACE_SESSION_SECURITY_INFORMATION\n{\n    EVENT_TRACE_INFORMATION_CLASS EventTraceInformationClass;\n    ULONG SecurityInformation;\n    HANDLE TraceHandle;\n    UCHAR SecurityDescriptor[1];\n} EVENT_TRACE_SESSION_SECURITY_INFORMATION, *PEVENT_TRACE_SESSION_SECURITY_INFORMATION;\n\ntypedef struct _EVENT_TRACE_SPINLOCK_INFORMATION\n{\n    EVENT_TRACE_INFORMATION_CLASS EventTraceInformationClass;\n    ULONG SpinLockSpinThreshold;\n    ULONG SpinLockAcquireSampleRate;\n    ULONG SpinLockContentionSampleRate;\n    ULONG SpinLockHoldThreshold;\n} EVENT_TRACE_SPINLOCK_INFORMATION, *PEVENT_TRACE_SPINLOCK_INFORMATION;\n\ntypedef struct _EVENT_TRACE_SYSTEM_EVENT_INFORMATION\n{\n    EVENT_TRACE_INFORMATION_CLASS EventTraceInformationClass;\n    HANDLE TraceHandle;\n    ULONG HookId[1];\n} EVENT_TRACE_SYSTEM_EVENT_INFORMATION, *PEVENT_TRACE_SYSTEM_EVENT_INFORMATION;\n\ntypedef struct _EVENT_TRACE_EXECUTIVE_RESOURCE_INFORMATION\n{\n    EVENT_TRACE_INFORMATION_CLASS EventTraceInformationClass;\n    ULONG ReleaseSamplingRate;\n    ULONG ContentionSamplingRate;\n    ULONG NumberOfExcessiveTimeouts;\n} EVENT_TRACE_EXECUTIVE_RESOURCE_INFORMATION, *PEVENT_TRACE_EXECUTIVE_RESOURCE_INFORMATION;\n\ntypedef struct _EVENT_TRACE_HEAP_TRACING_INFORMATION\n{\n    EVENT_TRACE_INFORMATION_CLASS EventTraceInformationClass;\n    ULONG ProcessId;\n} EVENT_TRACE_HEAP_TRACING_INFORMATION, *PEVENT_TRACE_HEAP_TRACING_INFORMATION;\n\ntypedef struct _EVENT_TRACE_TAG_FILTER_INFORMATION\n{\n    EVENT_TRACE_INFORMATION_CLASS EventTraceInformationClass;\n    HANDLE TraceHandle;\n    ULONG Filter[1];\n} EVENT_TRACE_TAG_FILTER_INFORMATION, *PEVENT_TRACE_TAG_FILTER_INFORMATION;\n\ntypedef struct _EVENT_TRACE_PROFILE_COUNTER_INFORMATION\n{\n    EVENT_TRACE_INFORMATION_CLASS EventTraceInformationClass;\n    HANDLE TraceHandle;\n    ULONG ProfileSource[1];\n} EVENT_TRACE_PROFILE_COUNTER_INFORMATION, *PEVENT_TRACE_PROFILE_COUNTER_INFORMATION;\n\ntypedef struct _EVENT_TRACE_PROFILE_LIST_INFORMATION\n{\n    EVENT_TRACE_INFORMATION_CLASS EventTraceInformationClass;\n    ULONG Spare;\n    struct _PROFILE_SOURCE_INFO* Profile[1];\n} EVENT_TRACE_PROFILE_LIST_INFORMATION, *PEVENT_TRACE_PROFILE_LIST_INFORMATION;\n\ntypedef struct _EVENT_TRACE_STACK_CACHING_INFORMATION\n{\n    EVENT_TRACE_INFORMATION_CLASS EventTraceInformationClass;\n    HANDLE TraceHandle;\n    BOOLEAN Enabled;\n    UCHAR Reserved[3];\n    ULONG CacheSize;\n    ULONG BucketCount;\n} EVENT_TRACE_STACK_CACHING_INFORMATION, *PEVENT_TRACE_STACK_CACHING_INFORMATION;\n\ntypedef struct _EVENT_TRACE_SOFT_RESTART_INFORMATION\n{\n    EVENT_TRACE_INFORMATION_CLASS EventTraceInformationClass;\n    HANDLE TraceHandle;\n    BOOLEAN PersistTraceBuffers;\n    WCHAR FileName[1];\n} EVENT_TRACE_SOFT_RESTART_INFORMATION, *PEVENT_TRACE_SOFT_RESTART_INFORMATION;\n\ntypedef struct _SYSTEM_EXCEPTION_INFORMATION\n{\n    ULONG AlignmentFixupCount;\n    ULONG ExceptionDispatchCount;\n    ULONG FloatingEmulationCount;\n    ULONG ByteWordEmulationCount;\n} SYSTEM_EXCEPTION_INFORMATION, *PSYSTEM_EXCEPTION_INFORMATION;\n\ntypedef struct _SYSTEM_KERNEL_DEBUGGER_INFORMATION\n{\n    BOOLEAN KernelDebuggerEnabled;\n    BOOLEAN KernelDebuggerNotPresent;\n} SYSTEM_KERNEL_DEBUGGER_INFORMATION, *PSYSTEM_KERNEL_DEBUGGER_INFORMATION;\n\ntypedef struct _SYSTEM_CONTEXT_SWITCH_INFORMATION\n{\n    ULONG ContextSwitches;\n    ULONG FindAny;\n    ULONG FindLast;\n    ULONG FindIdeal;\n    ULONG IdleAny;\n    ULONG IdleCurrent;\n    ULONG IdleLast;\n    ULONG IdleIdeal;\n    ULONG PreemptAny;\n    ULONG PreemptCurrent;\n    ULONG PreemptLast;\n    ULONG SwitchToIdle;\n} SYSTEM_CONTEXT_SWITCH_INFORMATION, *PSYSTEM_CONTEXT_SWITCH_INFORMATION;\n\ntypedef struct _SYSTEM_REGISTRY_QUOTA_INFORMATION\n{\n    ULONG RegistryQuotaAllowed;\n    ULONG RegistryQuotaUsed;\n    SIZE_T PagedPoolSize;\n} SYSTEM_REGISTRY_QUOTA_INFORMATION, *PSYSTEM_REGISTRY_QUOTA_INFORMATION;\n\ntypedef struct _SYSTEM_PROCESSOR_IDLE_INFORMATION\n{\n    ULONGLONG IdleTime;\n    ULONGLONG C1Time;\n    ULONGLONG C2Time;\n    ULONGLONG C3Time;\n    ULONG C1Transitions;\n    ULONG C2Transitions;\n    ULONG C3Transitions;\n    ULONG Padding;\n} SYSTEM_PROCESSOR_IDLE_INFORMATION, *PSYSTEM_PROCESSOR_IDLE_INFORMATION;\n\ntypedef struct _SYSTEM_LEGACY_DRIVER_INFORMATION\n{\n    ULONG VetoType;\n    UNICODE_STRING VetoList;\n} SYSTEM_LEGACY_DRIVER_INFORMATION, *PSYSTEM_LEGACY_DRIVER_INFORMATION;\n\ntypedef struct _SYSTEM_LOOKASIDE_INFORMATION\n{\n    USHORT CurrentDepth;\n    USHORT MaximumDepth;\n    ULONG TotalAllocates;\n    ULONG AllocateMisses;\n    ULONG TotalFrees;\n    ULONG FreeMisses;\n    ULONG Type;\n    ULONG Tag;\n    ULONG Size;\n} SYSTEM_LOOKASIDE_INFORMATION, *PSYSTEM_LOOKASIDE_INFORMATION;\n\n// private\ntypedef struct _SYSTEM_RANGE_START_INFORMATION\n{\n    PVOID SystemRangeStart;\n} SYSTEM_RANGE_START_INFORMATION, *PSYSTEM_RANGE_START_INFORMATION;\n\ntypedef struct _SYSTEM_VERIFIER_INFORMATION\n{\n    ULONG NextEntryOffset;\n    ULONG Level;\n    UNICODE_STRING DriverName;\n\n    ULONG RaiseIrqls;\n    ULONG AcquireSpinLocks;\n    ULONG SynchronizeExecutions;\n    ULONG AllocationsAttempted;\n\n    ULONG AllocationsSucceeded;\n    ULONG AllocationsSucceededSpecialPool;\n    ULONG AllocationsWithNoTag;\n    ULONG TrimRequests;\n\n    ULONG Trims;\n    ULONG AllocationsFailed;\n    ULONG AllocationsFailedDeliberately;\n    ULONG Loads;\n\n    ULONG Unloads;\n    ULONG UnTrackedPool;\n    ULONG CurrentPagedPoolAllocations;\n    ULONG CurrentNonPagedPoolAllocations;\n\n    ULONG PeakPagedPoolAllocations;\n    ULONG PeakNonPagedPoolAllocations;\n\n    SIZE_T PagedPoolUsageInBytes;\n    SIZE_T NonPagedPoolUsageInBytes;\n    SIZE_T PeakPagedPoolUsageInBytes;\n    SIZE_T PeakNonPagedPoolUsageInBytes;\n} SYSTEM_VERIFIER_INFORMATION, *PSYSTEM_VERIFIER_INFORMATION;\n\ntypedef struct _SYSTEM_SESSION_PROCESS_INFORMATION\n{\n    ULONG SessionId;\n    ULONG SizeOfBuf;\n    PVOID Buffer;\n} SYSTEM_SESSION_PROCESS_INFORMATION, *PSYSTEM_SESSION_PROCESS_INFORMATION;\n\ntypedef struct _SYSTEM_PROCESSOR_POWER_INFORMATION\n{\n    UCHAR CurrentFrequency;\n    UCHAR ThermalLimitFrequency;\n    UCHAR ConstantThrottleFrequency;\n    UCHAR DegradedThrottleFrequency;\n    UCHAR LastBusyFrequency;\n    UCHAR LastC3Frequency;\n    UCHAR LastAdjustedBusyFrequency;\n    UCHAR ProcessorMinThrottle;\n    UCHAR ProcessorMaxThrottle;\n    ULONG NumberOfFrequencies;\n    ULONG PromotionCount;\n    ULONG DemotionCount;\n    ULONG ErrorCount;\n    ULONG RetryCount;\n    ULONGLONG CurrentFrequencyTime;\n    ULONGLONG CurrentProcessorTime;\n    ULONGLONG CurrentProcessorIdleTime;\n    ULONGLONG LastProcessorTime;\n    ULONGLONG LastProcessorIdleTime;\n    ULONGLONG Energy;\n} SYSTEM_PROCESSOR_POWER_INFORMATION, *PSYSTEM_PROCESSOR_POWER_INFORMATION;\n\ntypedef struct _SYSTEM_HANDLE_TABLE_ENTRY_INFO_EX\n{\n    PVOID Object;\n    ULONG_PTR UniqueProcessId;\n    ULONG_PTR HandleValue;\n    ULONG GrantedAccess;\n    USHORT CreatorBackTraceIndex;\n    USHORT ObjectTypeIndex;\n    ULONG HandleAttributes;\n    ULONG Reserved;\n} SYSTEM_HANDLE_TABLE_ENTRY_INFO_EX, *PSYSTEM_HANDLE_TABLE_ENTRY_INFO_EX;\n\ntypedef struct _SYSTEM_HANDLE_INFORMATION_EX\n{\n    ULONG_PTR NumberOfHandles;\n    ULONG_PTR Reserved;\n    SYSTEM_HANDLE_TABLE_ENTRY_INFO_EX Handles[1];\n} SYSTEM_HANDLE_INFORMATION_EX, *PSYSTEM_HANDLE_INFORMATION_EX;\n\ntypedef struct _SYSTEM_BIGPOOL_ENTRY\n{\n    union\n    {\n        PVOID VirtualAddress;\n        ULONG_PTR NonPaged : 1;\n    };\n    SIZE_T SizeInBytes;\n    union\n    {\n        UCHAR Tag[4];\n        ULONG TagUlong;\n    };\n} SYSTEM_BIGPOOL_ENTRY, *PSYSTEM_BIGPOOL_ENTRY;\n\ntypedef struct _SYSTEM_BIGPOOL_INFORMATION\n{\n    ULONG Count;\n    SYSTEM_BIGPOOL_ENTRY AllocatedInfo[1];\n} SYSTEM_BIGPOOL_INFORMATION, *PSYSTEM_BIGPOOL_INFORMATION;\n\ntypedef struct _SYSTEM_POOL_ENTRY\n{\n    BOOLEAN Allocated;\n    BOOLEAN Spare0;\n    USHORT AllocatorBackTraceIndex;\n    ULONG Size;\n    union\n    {\n        UCHAR Tag[4];\n        ULONG TagUlong;\n        PVOID ProcessChargedQuota;\n    };\n} SYSTEM_POOL_ENTRY, *PSYSTEM_POOL_ENTRY;\n\ntypedef struct _SYSTEM_POOL_INFORMATION\n{\n    SIZE_T TotalSize;\n    PVOID FirstEntry;\n    USHORT EntryOverhead;\n    BOOLEAN PoolTagPresent;\n    BOOLEAN Spare0;\n    ULONG NumberOfEntries;\n    SYSTEM_POOL_ENTRY Entries[1];\n} SYSTEM_POOL_INFORMATION, *PSYSTEM_POOL_INFORMATION;\n\ntypedef struct _SYSTEM_SESSION_POOLTAG_INFORMATION\n{\n    SIZE_T NextEntryOffset;\n    ULONG SessionId;\n    ULONG Count;\n    SYSTEM_POOLTAG TagInfo[1];\n} SYSTEM_SESSION_POOLTAG_INFORMATION, *PSYSTEM_SESSION_POOLTAG_INFORMATION;\n\ntypedef struct _SYSTEM_SESSION_MAPPED_VIEW_INFORMATION\n{\n    SIZE_T NextEntryOffset;\n    ULONG SessionId;\n    ULONG ViewFailures;\n    SIZE_T NumberOfBytesAvailable;\n    SIZE_T NumberOfBytesAvailableContiguous;\n} SYSTEM_SESSION_MAPPED_VIEW_INFORMATION, *PSYSTEM_SESSION_MAPPED_VIEW_INFORMATION;\n\n#if (PHNT_MODE != PHNT_MODE_KERNEL)\n// private\ntypedef enum _SYSTEM_FIRMWARE_TABLE_ACTION\n{\n    SystemFirmwareTableEnumerate,\n    SystemFirmwareTableGet,\n    SystemFirmwareTableMax\n} SYSTEM_FIRMWARE_TABLE_ACTION;\n\n// private\ntypedef struct _SYSTEM_FIRMWARE_TABLE_INFORMATION\n{\n    ULONG ProviderSignature; // (same as the GetSystemFirmwareTable function)\n    SYSTEM_FIRMWARE_TABLE_ACTION Action;\n    ULONG TableID;\n    ULONG TableBufferLength;\n    UCHAR TableBuffer[1];\n} SYSTEM_FIRMWARE_TABLE_INFORMATION, *PSYSTEM_FIRMWARE_TABLE_INFORMATION;\n#endif\n\n// private\ntypedef struct _SYSTEM_MEMORY_LIST_INFORMATION\n{\n    ULONG_PTR ZeroPageCount;\n    ULONG_PTR FreePageCount;\n    ULONG_PTR ModifiedPageCount;\n    ULONG_PTR ModifiedNoWritePageCount;\n    ULONG_PTR BadPageCount;\n    ULONG_PTR PageCountByPriority[8];\n    ULONG_PTR RepurposedPagesByPriority[8];\n    ULONG_PTR ModifiedPageCountPageFile;\n} SYSTEM_MEMORY_LIST_INFORMATION, *PSYSTEM_MEMORY_LIST_INFORMATION;\n\n// private\ntypedef enum _SYSTEM_MEMORY_LIST_COMMAND\n{\n    MemoryCaptureAccessedBits,\n    MemoryCaptureAndResetAccessedBits,\n    MemoryEmptyWorkingSets,\n    MemoryFlushModifiedList,\n    MemoryPurgeStandbyList,\n    MemoryPurgeLowPriorityStandbyList,\n    MemoryCommandMax\n} SYSTEM_MEMORY_LIST_COMMAND;\n\n// private\ntypedef struct _SYSTEM_THREAD_CID_PRIORITY_INFORMATION\n{\n    CLIENT_ID ClientId;\n    KPRIORITY Priority;\n} SYSTEM_THREAD_CID_PRIORITY_INFORMATION, *PSYSTEM_THREAD_CID_PRIORITY_INFORMATION;\n\n// private\ntypedef struct _SYSTEM_PROCESSOR_IDLE_CYCLE_TIME_INFORMATION\n{\n    ULONGLONG CycleTime;\n} SYSTEM_PROCESSOR_IDLE_CYCLE_TIME_INFORMATION, *PSYSTEM_PROCESSOR_IDLE_CYCLE_TIME_INFORMATION;\n\n// private\ntypedef struct _SYSTEM_REF_TRACE_INFORMATION\n{\n    BOOLEAN TraceEnable;\n    BOOLEAN TracePermanent;\n    UNICODE_STRING TraceProcessName;\n    UNICODE_STRING TracePoolTags;\n} SYSTEM_REF_TRACE_INFORMATION, *PSYSTEM_REF_TRACE_INFORMATION;\n\n// private\ntypedef struct _SYSTEM_PROCESS_ID_INFORMATION\n{\n    HANDLE ProcessId;\n    UNICODE_STRING ImageName;\n} SYSTEM_PROCESS_ID_INFORMATION, *PSYSTEM_PROCESS_ID_INFORMATION;\n\n// private\ntypedef struct _SYSTEM_BOOT_ENVIRONMENT_INFORMATION\n{\n    GUID BootIdentifier;\n    FIRMWARE_TYPE FirmwareType;\n    ULONGLONG BootFlags;\n} SYSTEM_BOOT_ENVIRONMENT_INFORMATION, *PSYSTEM_BOOT_ENVIRONMENT_INFORMATION;\n\n// private\ntypedef struct _SYSTEM_IMAGE_FILE_EXECUTION_OPTIONS_INFORMATION\n{\n    ULONG FlagsToEnable;\n    ULONG FlagsToDisable;\n} SYSTEM_IMAGE_FILE_EXECUTION_OPTIONS_INFORMATION, *PSYSTEM_IMAGE_FILE_EXECUTION_OPTIONS_INFORMATION;\n\n// private\ntypedef struct _SYSTEM_VERIFIER_INFORMATION_EX\n{\n    ULONG VerifyMode;\n    ULONG OptionChanges;\n    UNICODE_STRING PreviousBucketName;\n    ULONG IrpCancelTimeoutMsec;\n    ULONG VerifierExtensionEnabled;\n#ifdef _WIN64\n    ULONG Reserved[1];\n#else\n    ULONG Reserved[3];\n#endif\n} SYSTEM_VERIFIER_INFORMATION_EX, *PSYSTEM_VERIFIER_INFORMATION_EX;\n\n// private\ntypedef struct _SYSTEM_SYSTEM_PARTITION_INFORMATION\n{\n    UNICODE_STRING SystemPartition;\n} SYSTEM_SYSTEM_PARTITION_INFORMATION, *PSYSTEM_SYSTEM_PARTITION_INFORMATION;\n\n// private\ntypedef struct _SYSTEM_SYSTEM_DISK_INFORMATION\n{\n    UNICODE_STRING SystemDisk;\n} SYSTEM_SYSTEM_DISK_INFORMATION, *PSYSTEM_SYSTEM_DISK_INFORMATION;\n\n// private (Windows 8.1 and above)\ntypedef struct _SYSTEM_PROCESSOR_PERFORMANCE_HITCOUNT\n{\n    ULONGLONG Hits;\n    UCHAR PercentFrequency;\n} SYSTEM_PROCESSOR_PERFORMANCE_HITCOUNT, *PSYSTEM_PROCESSOR_PERFORMANCE_HITCOUNT;\n\n// private (Windows 7 and Windows 8)\ntypedef struct _SYSTEM_PROCESSOR_PERFORMANCE_HITCOUNT_WIN8\n{\n    ULONG Hits;\n    UCHAR PercentFrequency;\n} SYSTEM_PROCESSOR_PERFORMANCE_HITCOUNT_WIN8, *PSYSTEM_PROCESSOR_PERFORMANCE_HITCOUNT_WIN8;\n\n// private\ntypedef struct _SYSTEM_PROCESSOR_PERFORMANCE_STATE_DISTRIBUTION\n{\n    ULONG ProcessorNumber;\n    ULONG StateCount;\n    SYSTEM_PROCESSOR_PERFORMANCE_HITCOUNT States[1];\n} SYSTEM_PROCESSOR_PERFORMANCE_STATE_DISTRIBUTION, *PSYSTEM_PROCESSOR_PERFORMANCE_STATE_DISTRIBUTION;\n\n// private\ntypedef struct _SYSTEM_PROCESSOR_PERFORMANCE_DISTRIBUTION\n{\n    ULONG ProcessorCount;\n    ULONG Offsets[1];\n} SYSTEM_PROCESSOR_PERFORMANCE_DISTRIBUTION, *PSYSTEM_PROCESSOR_PERFORMANCE_DISTRIBUTION;\n\n// private\ntypedef struct _SYSTEM_CODEINTEGRITY_INFORMATION\n{\n    ULONG Length;\n    ULONG CodeIntegrityOptions;\n} SYSTEM_CODEINTEGRITY_INFORMATION, *PSYSTEM_CODEINTEGRITY_INFORMATION;\n\n// private\ntypedef enum _SYSTEM_VA_TYPE\n{\n    SystemVaTypeAll,\n    SystemVaTypeNonPagedPool,\n    SystemVaTypePagedPool,\n    SystemVaTypeSystemCache,\n    SystemVaTypeSystemPtes,\n    SystemVaTypeSessionSpace,\n    SystemVaTypeMax\n} SYSTEM_VA_TYPE, *PSYSTEM_VA_TYPE;\n\n// private\ntypedef struct _SYSTEM_VA_LIST_INFORMATION\n{\n    SIZE_T VirtualSize;\n    SIZE_T VirtualPeak;\n    SIZE_T VirtualLimit;\n    SIZE_T AllocationFailures;\n} SYSTEM_VA_LIST_INFORMATION, *PSYSTEM_VA_LIST_INFORMATION;\n\n// private\ntypedef struct _SYSTEM_REGISTRY_APPEND_STRING_PARAMETERS\n{\n    HANDLE KeyHandle;\n    PUNICODE_STRING ValueNamePointer;\n    PULONG RequiredLengthPointer;\n    PUCHAR Buffer;\n    ULONG BufferLength;\n    ULONG Type;\n    PUCHAR AppendBuffer;\n    ULONG AppendBufferLength;\n    BOOLEAN CreateIfDoesntExist;\n    BOOLEAN TruncateExistingValue;\n} SYSTEM_REGISTRY_APPEND_STRING_PARAMETERS, *PSYSTEM_REGISTRY_APPEND_STRING_PARAMETERS;\n\n// msdn\ntypedef struct _SYSTEM_VHD_BOOT_INFORMATION\n{\n    BOOLEAN OsDiskIsVhd;\n    ULONG OsVhdFilePathOffset;\n    WCHAR OsVhdParentVolume[ANYSIZE_ARRAY];\n} SYSTEM_VHD_BOOT_INFORMATION, *PSYSTEM_VHD_BOOT_INFORMATION;\n\n// private\ntypedef struct _SYSTEM_LOW_PRIORITY_IO_INFORMATION\n{\n    ULONG LowPriReadOperations;\n    ULONG LowPriWriteOperations;\n    ULONG KernelBumpedToNormalOperations;\n    ULONG LowPriPagingReadOperations;\n    ULONG KernelPagingReadsBumpedToNormal;\n    ULONG LowPriPagingWriteOperations;\n    ULONG KernelPagingWritesBumpedToNormal;\n    ULONG BoostedIrpCount;\n    ULONG BoostedPagingIrpCount;\n    ULONG BlanketBoostCount;\n} SYSTEM_LOW_PRIORITY_IO_INFORMATION, *PSYSTEM_LOW_PRIORITY_IO_INFORMATION;\n\n// symbols\ntypedef enum _TPM_BOOT_ENTROPY_RESULT_CODE\n{\n    TpmBootEntropyStructureUninitialized,\n    TpmBootEntropyDisabledByPolicy,\n    TpmBootEntropyNoTpmFound,\n    TpmBootEntropyTpmError,\n    TpmBootEntropySuccess\n} TPM_BOOT_ENTROPY_RESULT_CODE;\n\n// Contents of KeLoaderBlock->Extension->TpmBootEntropyResult (TPM_BOOT_ENTROPY_LDR_RESULT).\n// EntropyData is truncated to 40 bytes.\n\n// private\ntypedef struct _TPM_BOOT_ENTROPY_NT_RESULT\n{\n    ULONGLONG Policy;\n    TPM_BOOT_ENTROPY_RESULT_CODE ResultCode;\n    NTSTATUS ResultStatus;\n    ULONGLONG Time;\n    ULONG EntropyLength;\n    UCHAR EntropyData[40];\n} TPM_BOOT_ENTROPY_NT_RESULT, *PTPM_BOOT_ENTROPY_NT_RESULT;\n\n// private\ntypedef struct _SYSTEM_VERIFIER_COUNTERS_INFORMATION\n{\n    SYSTEM_VERIFIER_INFORMATION Legacy;\n    ULONG RaiseIrqls;\n    ULONG AcquireSpinLocks;\n    ULONG SynchronizeExecutions;\n    ULONG AllocationsWithNoTag;\n    ULONG AllocationsFailed;\n    ULONG AllocationsFailedDeliberately;\n    SIZE_T LockedBytes;\n    SIZE_T PeakLockedBytes;\n    SIZE_T MappedLockedBytes;\n    SIZE_T PeakMappedLockedBytes;\n    SIZE_T MappedIoSpaceBytes;\n    SIZE_T PeakMappedIoSpaceBytes;\n    SIZE_T PagesForMdlBytes;\n    SIZE_T PeakPagesForMdlBytes;\n    SIZE_T ContiguousMemoryBytes;\n    SIZE_T PeakContiguousMemoryBytes;\n    ULONG ExecutePoolTypes; // REDSTONE2\n    ULONG ExecutePageProtections;\n    ULONG ExecutePageMappings;\n    ULONG ExecuteWriteSections;\n    ULONG SectionAlignmentFailures;\n    ULONG UnsupportedRelocs;\n    ULONG IATInExecutableSection;\n} SYSTEM_VERIFIER_COUNTERS_INFORMATION, *PSYSTEM_VERIFIER_COUNTERS_INFORMATION;\n\n// private\ntypedef struct _SYSTEM_ACPI_AUDIT_INFORMATION\n{\n    ULONG RsdpCount;\n    ULONG SameRsdt : 1;\n    ULONG SlicPresent : 1;\n    ULONG SlicDifferent : 1;\n} SYSTEM_ACPI_AUDIT_INFORMATION, *PSYSTEM_ACPI_AUDIT_INFORMATION;\n\n// private\ntypedef struct _SYSTEM_BASIC_PERFORMANCE_INFORMATION\n{\n    SIZE_T AvailablePages;\n    SIZE_T CommittedPages;\n    SIZE_T CommitLimit;\n    SIZE_T PeakCommitment;\n} SYSTEM_BASIC_PERFORMANCE_INFORMATION, *PSYSTEM_BASIC_PERFORMANCE_INFORMATION;\n\n// begin_msdn\n\ntypedef struct _QUERY_PERFORMANCE_COUNTER_FLAGS\n{\n    union\n    {\n        struct\n        {\n            ULONG KernelTransition : 1;\n            ULONG Reserved : 31;\n        };\n        ULONG ul;\n    };\n} QUERY_PERFORMANCE_COUNTER_FLAGS;\n\ntypedef struct _SYSTEM_QUERY_PERFORMANCE_COUNTER_INFORMATION\n{\n    ULONG Version;\n    QUERY_PERFORMANCE_COUNTER_FLAGS Flags;\n    QUERY_PERFORMANCE_COUNTER_FLAGS ValidFlags;\n} SYSTEM_QUERY_PERFORMANCE_COUNTER_INFORMATION, *PSYSTEM_QUERY_PERFORMANCE_COUNTER_INFORMATION;\n\n// end_msdn\n\n// private\ntypedef enum _SYSTEM_PIXEL_FORMAT\n{\n    SystemPixelFormatUnknown,\n    SystemPixelFormatR8G8B8,\n    SystemPixelFormatR8G8B8X8,\n    SystemPixelFormatB8G8R8,\n    SystemPixelFormatB8G8R8X8\n} SYSTEM_PIXEL_FORMAT;\n\n// private\ntypedef struct _SYSTEM_BOOT_GRAPHICS_INFORMATION\n{\n    LARGE_INTEGER FrameBuffer;\n    ULONG Width;\n    ULONG Height;\n    ULONG PixelStride;\n    ULONG Flags;\n    SYSTEM_PIXEL_FORMAT Format;\n    ULONG DisplayRotation;\n} SYSTEM_BOOT_GRAPHICS_INFORMATION, *PSYSTEM_BOOT_GRAPHICS_INFORMATION;\n\n// private\ntypedef struct _MEMORY_SCRUB_INFORMATION\n{\n    HANDLE Handle;\n    ULONG PagesScrubbed;\n} MEMORY_SCRUB_INFORMATION, *PMEMORY_SCRUB_INFORMATION;\n\n// private\ntypedef struct _PEBS_DS_SAVE_AREA\n{\n    ULONGLONG BtsBufferBase;\n    ULONGLONG BtsIndex;\n    ULONGLONG BtsAbsoluteMaximum;\n    ULONGLONG BtsInterruptThreshold;\n    ULONGLONG PebsBufferBase;\n    ULONGLONG PebsIndex;\n    ULONGLONG PebsAbsoluteMaximum;\n    ULONGLONG PebsInterruptThreshold;\n    ULONGLONG PebsCounterReset0;\n    ULONGLONG PebsCounterReset1;\n    ULONGLONG PebsCounterReset2;\n    ULONGLONG PebsCounterReset3;\n} PEBS_DS_SAVE_AREA, *PPEBS_DS_SAVE_AREA;\n\n// private\ntypedef struct _PROCESSOR_PROFILE_CONTROL_AREA\n{\n    PEBS_DS_SAVE_AREA PebsDsSaveArea;\n} PROCESSOR_PROFILE_CONTROL_AREA, *PPROCESSOR_PROFILE_CONTROL_AREA;\n\n// private\ntypedef struct _SYSTEM_PROCESSOR_PROFILE_CONTROL_AREA\n{\n    PROCESSOR_PROFILE_CONTROL_AREA ProcessorProfileControlArea;\n    BOOLEAN Allocate;\n} SYSTEM_PROCESSOR_PROFILE_CONTROL_AREA, *PSYSTEM_PROCESSOR_PROFILE_CONTROL_AREA;\n\n// private\ntypedef struct _MEMORY_COMBINE_INFORMATION\n{\n    HANDLE Handle;\n    ULONG_PTR PagesCombined;\n} MEMORY_COMBINE_INFORMATION, *PMEMORY_COMBINE_INFORMATION;\n\n// rev\n#define MEMORY_COMBINE_FLAGS_COMMON_PAGES_ONLY 0x4\n\n// private\ntypedef struct _MEMORY_COMBINE_INFORMATION_EX\n{\n    HANDLE Handle;\n    ULONG_PTR PagesCombined;\n    ULONG Flags;\n} MEMORY_COMBINE_INFORMATION_EX, *PMEMORY_COMBINE_INFORMATION_EX;\n\n// private\ntypedef struct _MEMORY_COMBINE_INFORMATION_EX2\n{\n    HANDLE Handle;\n    ULONG_PTR PagesCombined;\n    ULONG Flags;\n    HANDLE ProcessHandle;\n} MEMORY_COMBINE_INFORMATION_EX2, *PMEMORY_COMBINE_INFORMATION_EX2;\n\n// private\ntypedef struct _SYSTEM_CONSOLE_INFORMATION\n{\n    ULONG DriverLoaded : 1;\n    ULONG Spare : 31;\n} SYSTEM_CONSOLE_INFORMATION, *PSYSTEM_CONSOLE_INFORMATION;\n\n// private\ntypedef struct _SYSTEM_PLATFORM_BINARY_INFORMATION\n{\n    ULONG64 PhysicalAddress;\n    PVOID HandoffBuffer;\n    PVOID CommandLineBuffer;\n    ULONG HandoffBufferSize;\n    ULONG CommandLineBufferSize;\n} SYSTEM_PLATFORM_BINARY_INFORMATION, *PSYSTEM_PLATFORM_BINARY_INFORMATION;\n\n// private\ntypedef struct _SYSTEM_HYPERVISOR_PROCESSOR_COUNT_INFORMATION\n{\n    ULONG NumberOfLogicalProcessors;\n    ULONG NumberOfCores;\n} SYSTEM_HYPERVISOR_PROCESSOR_COUNT_INFORMATION, *PSYSTEM_HYPERVISOR_PROCESSOR_COUNT_INFORMATION;\n\n// private\ntypedef struct _SYSTEM_DEVICE_DATA_INFORMATION\n{\n    UNICODE_STRING DeviceId;\n    UNICODE_STRING DataName;\n    ULONG DataType;\n    ULONG DataBufferLength;\n    PVOID DataBuffer;\n} SYSTEM_DEVICE_DATA_INFORMATION, *PSYSTEM_DEVICE_DATA_INFORMATION;\n\n// private\ntypedef struct _PHYSICAL_CHANNEL_RUN\n{\n    ULONG NodeNumber;\n    ULONG ChannelNumber;\n    ULONGLONG BasePage;\n    ULONGLONG PageCount;\n    ULONG Flags;\n} PHYSICAL_CHANNEL_RUN, *PPHYSICAL_CHANNEL_RUN;\n\n// private\ntypedef struct _SYSTEM_MEMORY_TOPOLOGY_INFORMATION\n{\n    ULONGLONG NumberOfRuns;\n    ULONG NumberOfNodes;\n    ULONG NumberOfChannels;\n    PHYSICAL_CHANNEL_RUN Run[1];\n} SYSTEM_MEMORY_TOPOLOGY_INFORMATION, *PSYSTEM_MEMORY_TOPOLOGY_INFORMATION;\n\n// private\ntypedef struct _SYSTEM_MEMORY_CHANNEL_INFORMATION\n{\n    ULONG ChannelNumber;\n    ULONG ChannelHeatIndex;\n    ULONGLONG TotalPageCount;\n    ULONGLONG ZeroPageCount;\n    ULONGLONG FreePageCount;\n    ULONGLONG StandbyPageCount;\n} SYSTEM_MEMORY_CHANNEL_INFORMATION, *PSYSTEM_MEMORY_CHANNEL_INFORMATION;\n\n// private\ntypedef struct _SYSTEM_BOOT_LOGO_INFORMATION\n{\n    ULONG Flags;\n    ULONG BitmapOffset;\n} SYSTEM_BOOT_LOGO_INFORMATION, *PSYSTEM_BOOT_LOGO_INFORMATION;\n\n// private\ntypedef struct _SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION_EX\n{\n    LARGE_INTEGER IdleTime;\n    LARGE_INTEGER KernelTime;\n    LARGE_INTEGER UserTime;\n    LARGE_INTEGER DpcTime;\n    LARGE_INTEGER InterruptTime;\n    ULONG InterruptCount;\n    ULONG Spare0;\n    LARGE_INTEGER AvailableTime;\n    LARGE_INTEGER Spare1;\n    LARGE_INTEGER Spare2;\n} SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION_EX, *PSYSTEM_PROCESSOR_PERFORMANCE_INFORMATION_EX;\n\n// private\ntypedef struct _SYSTEM_SECUREBOOT_POLICY_INFORMATION \n{\n    GUID PolicyPublisher;\n    ULONG PolicyVersion;\n    ULONG PolicyOptions;\n} SYSTEM_SECUREBOOT_POLICY_INFORMATION, *PSYSTEM_SECUREBOOT_POLICY_INFORMATION;\n\n// private\ntypedef struct _SYSTEM_PAGEFILE_INFORMATION_EX\n{\n    SYSTEM_PAGEFILE_INFORMATION Info;\n    ULONG MinimumSize;\n    ULONG MaximumSize;\n} SYSTEM_PAGEFILE_INFORMATION_EX, *PSYSTEM_PAGEFILE_INFORMATION_EX;\n\n// private\ntypedef struct _SYSTEM_SECUREBOOT_INFORMATION\n{\n    BOOLEAN SecureBootEnabled;\n    BOOLEAN SecureBootCapable;\n} SYSTEM_SECUREBOOT_INFORMATION, *PSYSTEM_SECUREBOOT_INFORMATION;\n\n// private\ntypedef struct _PROCESS_DISK_COUNTERS\n{\n    ULONGLONG BytesRead;\n    ULONGLONG BytesWritten;\n    ULONGLONG ReadOperationCount;\n    ULONGLONG WriteOperationCount;\n    ULONGLONG FlushOperationCount;\n} PROCESS_DISK_COUNTERS, *PPROCESS_DISK_COUNTERS;\n\n// private\ntypedef union _ENERGY_STATE_DURATION\n{\n    union\n    {\n        ULONGLONG Value;\n        ULONG LastChangeTime;\n    };\n\n    ULONG Duration : 31;\n    ULONG IsInState : 1;\n} ENERGY_STATE_DURATION, *PENERGY_STATE_DURATION;\n\ntypedef struct _PROCESS_ENERGY_VALUES\n{\n    ULONGLONG Cycles[2][4];\n    ULONGLONG DiskEnergy;\n    ULONGLONG NetworkTailEnergy;\n    ULONGLONG MBBTailEnergy;\n    ULONGLONG NetworkTxRxBytes;\n    ULONGLONG MBBTxRxBytes;\n    union\n    {\n        ENERGY_STATE_DURATION Durations[3];\n        struct\n        {\n            ENERGY_STATE_DURATION ForegroundDuration;\n            ENERGY_STATE_DURATION DesktopVisibleDuration;\n            ENERGY_STATE_DURATION PSMForegroundDuration;\n        };\n    };\n    ULONG CompositionRendered;\n    ULONG CompositionDirtyGenerated;\n    ULONG CompositionDirtyPropagated;\n    ULONG Reserved1;\n    ULONGLONG AttributedCycles[4][2];\n    ULONGLONG WorkOnBehalfCycles[4][2];\n} PROCESS_ENERGY_VALUES, *PPROCESS_ENERGY_VALUES;\n\ntypedef struct _TIMELINE_BITMAP\n{\n    ULONGLONG Value;\n    ULONG EndTime;\n    ULONG Bitmap;\n} TIMELINE_BITMAP, *PTIMELINE_BITMAP;\n\ntypedef struct _PROCESS_ENERGY_VALUES_EXTENSION\n{\n    union\n    {\n        TIMELINE_BITMAP Timelines[14]; // 9 for REDSTONE2, 14 for REDSTONE3\n        struct\n        {\n            TIMELINE_BITMAP CpuTimeline;\n            TIMELINE_BITMAP DiskTimeline;\n            TIMELINE_BITMAP NetworkTimeline;\n            TIMELINE_BITMAP MBBTimeline;\n            TIMELINE_BITMAP ForegroundTimeline;\n            TIMELINE_BITMAP DesktopVisibleTimeline;\n            TIMELINE_BITMAP CompositionRenderedTimeline;\n            TIMELINE_BITMAP CompositionDirtyGeneratedTimeline;\n            TIMELINE_BITMAP CompositionDirtyPropagatedTimeline;\n            TIMELINE_BITMAP InputTimeline; // REDSTONE3\n            TIMELINE_BITMAP AudioInTimeline;\n            TIMELINE_BITMAP AudioOutTimeline;\n            TIMELINE_BITMAP DisplayRequiredTimeline;\n            TIMELINE_BITMAP KeyboardInputTimeline;\n        };\n    };\n\n    union // REDSTONE3\n    {\n        ENERGY_STATE_DURATION Durations[5];\n        struct\n        {\n            ENERGY_STATE_DURATION InputDuration;\n            ENERGY_STATE_DURATION AudioInDuration;\n            ENERGY_STATE_DURATION AudioOutDuration;\n            ENERGY_STATE_DURATION DisplayRequiredDuration;\n            ENERGY_STATE_DURATION PSMBackgroundDuration;\n        };\n    };\n    \n    ULONG KeyboardInput;\n    ULONG MouseInput;\n} PROCESS_ENERGY_VALUES_EXTENSION, *PPROCESS_ENERGY_VALUES_EXTENSION;\n\ntypedef struct _PROCESS_EXTENDED_ENERGY_VALUES\n{\n    PROCESS_ENERGY_VALUES Base;\n    PROCESS_ENERGY_VALUES_EXTENSION Extension;\n} PROCESS_EXTENDED_ENERGY_VALUES, *PPROCESS_EXTENDED_ENERGY_VALUES;\n\n// private\ntypedef enum _SYSTEM_PROCESS_CLASSIFICATION\n{\n    SystemProcessClassificationNormal,\n    SystemProcessClassificationSystem,\n    SystemProcessClassificationSecureSystem,\n    SystemProcessClassificationMemCompression,\n    SystemProcessClassificationMaximum\n} SYSTEM_PROCESS_CLASSIFICATION;\n\n// private\ntypedef struct _SYSTEM_PROCESS_INFORMATION_EXTENSION\n{\n    PROCESS_DISK_COUNTERS DiskCounters;\n    ULONGLONG ContextSwitches;\n    union\n    {\n        ULONG Flags;\n        struct\n        {\n            ULONG HasStrongId : 1;\n            ULONG Classification : 4; // SYSTEM_PROCESS_CLASSIFICATION\n            ULONG BackgroundActivityModerated : 1;\n            ULONG Spare : 26;\n        };\n    };\n    ULONG UserSidOffset;\n    ULONG PackageFullNameOffset; // since THRESHOLD\n    PROCESS_ENERGY_VALUES EnergyValues; // since THRESHOLD\n    ULONG AppIdOffset; // since THRESHOLD\n    SIZE_T SharedCommitCharge; // since THRESHOLD2\n    ULONG JobObjectId; // since REDSTONE\n    ULONG SpareUlong; // since REDSTONE\n    ULONGLONG ProcessSequenceNumber;\n} SYSTEM_PROCESS_INFORMATION_EXTENSION, *PSYSTEM_PROCESS_INFORMATION_EXTENSION;\n\n// private\ntypedef struct _SYSTEM_PORTABLE_WORKSPACE_EFI_LAUNCHER_INFORMATION\n{\n    BOOLEAN EfiLauncherEnabled;\n} SYSTEM_PORTABLE_WORKSPACE_EFI_LAUNCHER_INFORMATION, *PSYSTEM_PORTABLE_WORKSPACE_EFI_LAUNCHER_INFORMATION;\n\n// private\ntypedef struct _SYSTEM_KERNEL_DEBUGGER_INFORMATION_EX\n{\n    BOOLEAN DebuggerAllowed;\n    BOOLEAN DebuggerEnabled;\n    BOOLEAN DebuggerPresent;\n} SYSTEM_KERNEL_DEBUGGER_INFORMATION_EX, *PSYSTEM_KERNEL_DEBUGGER_INFORMATION_EX;\n\n// private\ntypedef struct _SYSTEM_ELAM_CERTIFICATE_INFORMATION\n{\n    HANDLE ElamDriverFile;\n} SYSTEM_ELAM_CERTIFICATE_INFORMATION, *PSYSTEM_ELAM_CERTIFICATE_INFORMATION;\n\n// private\ntypedef struct _SYSTEM_PROCESSOR_FEATURES_INFORMATION\n{\n    ULONGLONG ProcessorFeatureBits;\n    ULONGLONG Reserved[3];\n} SYSTEM_PROCESSOR_FEATURES_INFORMATION, *PSYSTEM_PROCESSOR_FEATURES_INFORMATION;\n\n// private\ntypedef struct _SYSTEM_MANUFACTURING_INFORMATION\n{\n    ULONG Options;\n    UNICODE_STRING ProfileName;\n} SYSTEM_MANUFACTURING_INFORMATION, *PSYSTEM_MANUFACTURING_INFORMATION;\n\n// private\ntypedef struct _SYSTEM_ENERGY_ESTIMATION_CONFIG_INFORMATION\n{\n    BOOLEAN Enabled;\n} SYSTEM_ENERGY_ESTIMATION_CONFIG_INFORMATION, *PSYSTEM_ENERGY_ESTIMATION_CONFIG_INFORMATION;\n\n// private\ntypedef struct _HV_DETAILS\n{\n    ULONG Data[4];\n} HV_DETAILS, *PHV_DETAILS;\n\n// private\ntypedef struct _SYSTEM_HYPERVISOR_DETAIL_INFORMATION\n{\n    HV_DETAILS HvVendorAndMaxFunction;\n    HV_DETAILS HypervisorInterface;\n    HV_DETAILS HypervisorVersion;\n    HV_DETAILS HvFeatures;\n    HV_DETAILS HwFeatures;\n    HV_DETAILS EnlightenmentInfo;\n    HV_DETAILS ImplementationLimits;\n} SYSTEM_HYPERVISOR_DETAIL_INFORMATION, *PSYSTEM_HYPERVISOR_DETAIL_INFORMATION;\n\n// private\ntypedef struct _SYSTEM_PROCESSOR_CYCLE_STATS_INFORMATION\n{\n    ULONGLONG Cycles[2][4];\n} SYSTEM_PROCESSOR_CYCLE_STATS_INFORMATION, *PSYSTEM_PROCESSOR_CYCLE_STATS_INFORMATION;\n\n// private\ntypedef struct _SYSTEM_TPM_INFORMATION\n{\n    ULONG Flags;\n} SYSTEM_TPM_INFORMATION, *PSYSTEM_TPM_INFORMATION;\n\n// private\ntypedef struct _SYSTEM_DMA_PROTECTION_INFORMATION\n{\n    BOOLEAN DmaProtectionsAvailable;\n    BOOLEAN DmaProtectionsInUse;\n} SYSTEM_DMA_PROTECTION_INFORMATION, *PSYSTEM_DMA_PROTECTION_INFORMATION;\n\n// private\ntypedef struct _SYSTEM_CODEINTEGRITYPOLICY_INFORMATION\n{\n    ULONG Options;\n    ULONG HVCIOptions;\n    ULONGLONG Version;\n    GUID PolicyGuid;\n} SYSTEM_CODEINTEGRITYPOLICY_INFORMATION, *PSYSTEM_CODEINTEGRITYPOLICY_INFORMATION;\n\n// private\ntypedef struct _SYSTEM_ISOLATED_USER_MODE_INFORMATION\n{\n    BOOLEAN SecureKernelRunning : 1;\n    BOOLEAN HvciEnabled : 1;\n    BOOLEAN HvciStrictMode : 1;\n    BOOLEAN DebugEnabled : 1;\n    BOOLEAN FirmwarePageProtection : 1;\n    BOOLEAN SpareFlags : 1;\n    BOOLEAN TrustletRunning : 1;\n    BOOLEAN SpareFlags2 : 1;\n    BOOLEAN Spare0[6];\n    ULONGLONG Spare1;\n} SYSTEM_ISOLATED_USER_MODE_INFORMATION, *PSYSTEM_ISOLATED_USER_MODE_INFORMATION;\n\n// private\ntypedef struct _SYSTEM_SINGLE_MODULE_INFORMATION\n{\n    PVOID TargetModuleAddress;\n    RTL_PROCESS_MODULE_INFORMATION_EX ExInfo;\n} SYSTEM_SINGLE_MODULE_INFORMATION, *PSYSTEM_SINGLE_MODULE_INFORMATION;\n\n// private\ntypedef struct _SYSTEM_INTERRUPT_CPU_SET_INFORMATION\n{\n    ULONG Gsiv;\n    USHORT Group;\n    ULONGLONG CpuSets;\n} SYSTEM_INTERRUPT_CPU_SET_INFORMATION, *PSYSTEM_INTERRUPT_CPU_SET_INFORMATION;\n\n// private\ntypedef struct _SYSTEM_SECUREBOOT_POLICY_FULL_INFORMATION\n{\n    SYSTEM_SECUREBOOT_POLICY_INFORMATION PolicyInformation;\n    ULONG PolicySize;\n    UCHAR Policy[1];\n} SYSTEM_SECUREBOOT_POLICY_FULL_INFORMATION, *PSYSTEM_SECUREBOOT_POLICY_FULL_INFORMATION;\n\n// private\ntypedef struct _SYSTEM_ROOT_SILO_INFORMATION\n{\n    ULONG NumberOfSilos;\n    ULONG SiloIdList[1];\n} SYSTEM_ROOT_SILO_INFORMATION, *PSYSTEM_ROOT_SILO_INFORMATION;\n\n// private\ntypedef struct _SYSTEM_CPU_SET_TAG_INFORMATION\n{\n    ULONGLONG Tag;\n    ULONGLONG CpuSets[1];\n} SYSTEM_CPU_SET_TAG_INFORMATION, *PSYSTEM_CPU_SET_TAG_INFORMATION;\n\n// private\ntypedef struct _SYSTEM_SECURE_KERNEL_HYPERGUARD_PROFILE_INFORMATION\n{\n    ULONG ExtentCount;\n    ULONG ValidStructureSize;\n    ULONG NextExtentIndex;\n    ULONG ExtentRestart;\n    ULONG CycleCount;\n    ULONG TimeoutCount;\n    ULONGLONG CycleTime;\n    ULONGLONG CycleTimeMax;\n    ULONGLONG ExtentTime;\n    ULONG ExtentTimeIndex;\n    ULONG ExtentTimeMaxIndex;\n    ULONGLONG ExtentTimeMax;\n    ULONGLONG HyperFlushTimeMax;\n    ULONGLONG TranslateVaTimeMax;\n    ULONGLONG DebugExemptionCount;\n    ULONGLONG TbHitCount;\n    ULONGLONG TbMissCount;\n    ULONGLONG VinaPendingYield;\n    ULONGLONG HashCycles;\n    ULONG HistogramOffset;\n    ULONG HistogramBuckets;\n    ULONG HistogramShift;\n    ULONG Reserved1;\n    ULONGLONG PageNotPresentCount;\n} SYSTEM_SECURE_KERNEL_HYPERGUARD_PROFILE_INFORMATION, *PSYSTEM_SECURE_KERNEL_HYPERGUARD_PROFILE_INFORMATION;\n\n// private\ntypedef struct _SYSTEM_SECUREBOOT_PLATFORM_MANIFEST_INFORMATION\n{\n    ULONG PlatformManifestSize;\n    UCHAR PlatformManifest[1];\n} SYSTEM_SECUREBOOT_PLATFORM_MANIFEST_INFORMATION, *PSYSTEM_SECUREBOOT_PLATFORM_MANIFEST_INFORMATION;\n\n// private\ntypedef struct _SYSTEM_MEMORY_USAGE_INFORMATION\n{\n    ULONGLONG TotalPhysicalBytes;\n    ULONGLONG AvailableBytes;\n    LONGLONG ResidentAvailableBytes;\n    ULONGLONG CommittedBytes;\n    ULONGLONG SharedCommittedBytes;\n    ULONGLONG CommitLimitBytes;\n    ULONGLONG PeakCommitmentBytes;\n} SYSTEM_MEMORY_USAGE_INFORMATION, *PSYSTEM_MEMORY_USAGE_INFORMATION;\n\n// private\ntypedef struct _SYSTEM_CODEINTEGRITY_CERTIFICATE_INFORMATION\n{\n    HANDLE ImageFile;\n} SYSTEM_CODEINTEGRITY_CERTIFICATE_INFORMATION, *PSYSTEM_CODEINTEGRITY_CERTIFICATE_INFORMATION;\n\n// private\ntypedef struct _SYSTEM_PHYSICAL_MEMORY_INFORMATION\n{\n    ULONGLONG TotalPhysicalBytes;\n    ULONGLONG LowestPhysicalAddress;\n    ULONGLONG HighestPhysicalAddress;\n} SYSTEM_PHYSICAL_MEMORY_INFORMATION, *PSYSTEM_PHYSICAL_MEMORY_INFORMATION;\n\n// private\ntypedef enum _SYSTEM_ACTIVITY_MODERATION_STATE\n{\n    SystemActivityModerationStateSystemManaged,\n    SystemActivityModerationStateAlwaysThrottled,\n    SystemActivityModerationStateNeverThrottled,\n    MaxSystemActivityModerationState\n} SYSTEM_ACTIVITY_MODERATION_STATE;\n\n// private - REDSTONE2\ntypedef struct _SYSTEM_ACTIVITY_MODERATION_EXE_STATE // REDSTONE3: Renamed SYSTEM_ACTIVITY_MODERATION_INFO\n{\n    UNICODE_STRING ExePathNt;\n    SYSTEM_ACTIVITY_MODERATION_STATE ModerationState;\n} SYSTEM_ACTIVITY_MODERATION_EXE_STATE, *PSYSTEM_ACTIVITY_MODERATION_EXE_STATE;\n\ntypedef enum _SYSTEM_ACTIVITY_MODERATION_APP_TYPE\n{\n    SystemActivityModerationAppTypeClassic,\n    SystemActivityModerationAppTypePackaged,\n    MaxSystemActivityModerationAppType\n} SYSTEM_ACTIVITY_MODERATION_APP_TYPE;\n\n// private - REDSTONE3\ntypedef struct _SYSTEM_ACTIVITY_MODERATION_INFO\n{\n    UNICODE_STRING Identifier;\n    SYSTEM_ACTIVITY_MODERATION_STATE ModerationState;\n    SYSTEM_ACTIVITY_MODERATION_APP_TYPE AppType;\n} SYSTEM_ACTIVITY_MODERATION_INFO, *PSYSTEM_ACTIVITY_MODERATION_INFO;\n\n// private\ntypedef struct _SYSTEM_ACTIVITY_MODERATION_USER_SETTINGS\n{\n    HANDLE UserKeyHandle;\n} SYSTEM_ACTIVITY_MODERATION_USER_SETTINGS, *PSYSTEM_ACTIVITY_MODERATION_USER_SETTINGS;\n\n// private\ntypedef struct _SYSTEM_CODEINTEGRITY_UNLOCK_INFORMATION\n{\n    union\n    {\n        ULONG Flags;\n        struct\n        {\n            ULONG Locked : 1;\n            ULONG Unlockable : 1;\n            ULONG UnlockApplied : 1;\n            ULONG Reserved : 29;\n        };\n    };\n} SYSTEM_CODEINTEGRITY_UNLOCK_INFORMATION, *PSYSTEM_CODEINTEGRITY_UNLOCK_INFORMATION;\n\n// private\ntypedef struct _SYSTEM_FLUSH_INFORMATION\n{\n    ULONG SupportedFlushMethods;\n    ULONG ProcessorCacheFlushSize;\n    ULONGLONG SystemFlushCapabilities;\n    ULONGLONG Reserved[2];\n} SYSTEM_FLUSH_INFORMATION, *PSYSTEM_FLUSH_INFORMATION;\n\n// private\ntypedef struct _SYSTEM_WRITE_CONSTRAINT_INFORMATION\n{\n    ULONG WriteConstraintPolicy;\n    ULONG Reserved;\n} SYSTEM_WRITE_CONSTRAINT_INFORMATION, *PSYSTEM_WRITE_CONSTRAINT_INFORMATION;\n\n// private\ntypedef struct _SYSTEM_KERNEL_VA_SHADOW_INFORMATION\n{\n    union\n    {\n        ULONG Flags;\n        struct\n        {\n            ULONG KvaShadowEnabled : 1;\n            ULONG KvaShadowUserGlobal : 1;\n            ULONG KvaShadowPcid : 1;\n            ULONG KvaShadowInvpcid : 1;\n            ULONG Reserved : 28;\n        };\n    };\n} SYSTEM_KERNEL_VA_SHADOW_INFORMATION, *PSYSTEM_KERNEL_VA_SHADOW_INFORMATION;\n\n// private\ntypedef struct _SYSTEM_SPECULATION_CONTROL_INFORMATION\n{\n    union\n    {\n        ULONG Flags;\n        struct\n        {\n            ULONG BpbEnabled : 1;\n            ULONG BpbDisabledSystemPolicy : 1;\n            ULONG BpbDisabledNoHardwareSupport : 1;\n            ULONG SpecCtrlEnumerated : 1;\n            ULONG SpecCmdEnumerated : 1;\n            ULONG IbrsPresent : 1;\n            ULONG StibpPresent : 1;\n            ULONG SmepPresent : 1;\n            ULONG Reserved : 24;\n        };\n    };\n} SYSTEM_SPECULATION_CONTROL_INFORMATION, *PSYSTEM_SPECULATION_CONTROL_INFORMATION;\n\n#if (PHNT_MODE != PHNT_MODE_KERNEL)\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtQuerySystemInformation(\n    _In_ SYSTEM_INFORMATION_CLASS SystemInformationClass,\n    _Out_writes_bytes_opt_(SystemInformationLength) PVOID SystemInformation,\n    _In_ ULONG SystemInformationLength,\n    _Out_opt_ PULONG ReturnLength\n    );\n\n#if (PHNT_VERSION >= PHNT_WIN7)\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtQuerySystemInformationEx(\n    _In_ SYSTEM_INFORMATION_CLASS SystemInformationClass,\n    _In_reads_bytes_(InputBufferLength) PVOID InputBuffer,\n    _In_ ULONG InputBufferLength,\n    _Out_writes_bytes_opt_(SystemInformationLength) PVOID SystemInformation,\n    _In_ ULONG SystemInformationLength,\n    _Out_opt_ PULONG ReturnLength\n    );\n#endif\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtSetSystemInformation(\n    _In_ SYSTEM_INFORMATION_CLASS SystemInformationClass,\n    _In_reads_bytes_opt_(SystemInformationLength) PVOID SystemInformation,\n    _In_ ULONG SystemInformationLength\n    );\n\n// SysDbg APIs\n\n// private\ntypedef enum _SYSDBG_COMMAND\n{\n    SysDbgQueryModuleInformation,\n    SysDbgQueryTraceInformation,\n    SysDbgSetTracepoint,\n    SysDbgSetSpecialCall,\n    SysDbgClearSpecialCalls,\n    SysDbgQuerySpecialCalls,\n    SysDbgBreakPoint,\n    SysDbgQueryVersion,\n    SysDbgReadVirtual,\n    SysDbgWriteVirtual,\n    SysDbgReadPhysical,\n    SysDbgWritePhysical,\n    SysDbgReadControlSpace,\n    SysDbgWriteControlSpace,\n    SysDbgReadIoSpace,\n    SysDbgWriteIoSpace,\n    SysDbgReadMsr,\n    SysDbgWriteMsr,\n    SysDbgReadBusData,\n    SysDbgWriteBusData,\n    SysDbgCheckLowMemory,\n    SysDbgEnableKernelDebugger,\n    SysDbgDisableKernelDebugger,\n    SysDbgGetAutoKdEnable,\n    SysDbgSetAutoKdEnable,\n    SysDbgGetPrintBufferSize,\n    SysDbgSetPrintBufferSize,\n    SysDbgGetKdUmExceptionEnable,\n    SysDbgSetKdUmExceptionEnable,\n    SysDbgGetTriageDump,\n    SysDbgGetKdBlockEnable,\n    SysDbgSetKdBlockEnable,\n    SysDbgRegisterForUmBreakInfo,\n    SysDbgGetUmBreakPid,\n    SysDbgClearUmBreakPid,\n    SysDbgGetUmAttachPid,\n    SysDbgClearUmAttachPid,\n    SysDbgGetLiveKernelDump\n} SYSDBG_COMMAND, *PSYSDBG_COMMAND;\n\ntypedef struct _SYSDBG_VIRTUAL\n{\n    PVOID Address;\n    PVOID Buffer;\n    ULONG Request;\n} SYSDBG_VIRTUAL, *PSYSDBG_VIRTUAL;\n\ntypedef struct _SYSDBG_PHYSICAL\n{\n    PHYSICAL_ADDRESS Address;\n    PVOID Buffer;\n    ULONG Request;\n} SYSDBG_PHYSICAL, *PSYSDBG_PHYSICAL;\n\ntypedef struct _SYSDBG_CONTROL_SPACE\n{\n    ULONG64 Address;\n    PVOID Buffer;\n    ULONG Request;\n    ULONG Processor;\n} SYSDBG_CONTROL_SPACE, *PSYSDBG_CONTROL_SPACE;\n\nenum _INTERFACE_TYPE;\n\ntypedef struct _SYSDBG_IO_SPACE\n{\n    ULONG64 Address;\n    PVOID Buffer;\n    ULONG Request;\n    enum _INTERFACE_TYPE InterfaceType;\n    ULONG BusNumber;\n    ULONG AddressSpace;\n} SYSDBG_IO_SPACE, *PSYSDBG_IO_SPACE;\n\ntypedef struct _SYSDBG_MSR\n{\n    ULONG Msr;\n    ULONG64 Data;\n} SYSDBG_MSR, *PSYSDBG_MSR;\n\nenum _BUS_DATA_TYPE;\n\ntypedef struct _SYSDBG_BUS_DATA\n{\n    ULONG Address;\n    PVOID Buffer;\n    ULONG Request;\n    enum _BUS_DATA_TYPE BusDataType;\n    ULONG BusNumber;\n    ULONG SlotNumber;\n} SYSDBG_BUS_DATA, *PSYSDBG_BUS_DATA;\n\n// private\ntypedef struct _SYSDBG_TRIAGE_DUMP\n{\n    ULONG Flags;\n    ULONG BugCheckCode;\n    ULONG_PTR BugCheckParam1;\n    ULONG_PTR BugCheckParam2;\n    ULONG_PTR BugCheckParam3;\n    ULONG_PTR BugCheckParam4;\n    ULONG ProcessHandles;\n    ULONG ThreadHandles;\n    PHANDLE Handles;\n} SYSDBG_TRIAGE_DUMP, *PSYSDBG_TRIAGE_DUMP;\n\n// private\ntypedef union _SYSDBG_LIVEDUMP_CONTROL_FLAGS\n{\n    struct\n    {\n        ULONG UseDumpStorageStack : 1;\n        ULONG CompressMemoryPagesData : 1;\n        ULONG IncludeUserSpaceMemoryPages : 1;\n        ULONG Reserved : 29;\n    };\n    ULONG AsUlong;\n} SYSDBG_LIVEDUMP_CONTROL_FLAGS, *PSYSDBG_LIVEDUMP_CONTROL_FLAGS;\n\n// private\ntypedef union _SYSDBG_LIVEDUMP_CONTROL_ADDPAGES\n{\n    struct\n    {\n        ULONG HypervisorPages : 1;\n        ULONG Reserved : 31;\n    };\n    ULONG AsUlong;\n} SYSDBG_LIVEDUMP_CONTROL_ADDPAGES, *PSYSDBG_LIVEDUMP_CONTROL_ADDPAGES;\n\n#define SYSDBG_LIVEDUMP_CONTROL_VERSION 1\n\n// private\ntypedef struct _SYSDBG_LIVEDUMP_CONTROL\n{\n    ULONG Version;\n    ULONG BugCheckCode;\n    ULONG_PTR BugCheckParam1;\n    ULONG_PTR BugCheckParam2;\n    ULONG_PTR BugCheckParam3;\n    ULONG_PTR BugCheckParam4;\n    HANDLE DumpFileHandle;\n    HANDLE CancelEventHandle;\n    SYSDBG_LIVEDUMP_CONTROL_FLAGS Flags;\n    SYSDBG_LIVEDUMP_CONTROL_ADDPAGES AddPagesControl;\n} SYSDBG_LIVEDUMP_CONTROL, *PSYSDBG_LIVEDUMP_CONTROL;\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtSystemDebugControl(\n    _In_ SYSDBG_COMMAND Command,\n    _Inout_updates_bytes_opt_(InputBufferLength) PVOID InputBuffer,\n    _In_ ULONG InputBufferLength,\n    _Out_writes_bytes_opt_(OutputBufferLength) PVOID OutputBuffer,\n    _In_ ULONG OutputBufferLength,\n    _Out_opt_ PULONG ReturnLength\n    );\n\n// Hard errors\n\ntypedef enum _HARDERROR_RESPONSE_OPTION\n{\n    OptionAbortRetryIgnore,\n    OptionOk,\n    OptionOkCancel,\n    OptionRetryCancel,\n    OptionYesNo,\n    OptionYesNoCancel,\n    OptionShutdownSystem,\n    OptionOkNoWait,\n    OptionCancelTryContinue\n} HARDERROR_RESPONSE_OPTION;\n\ntypedef enum _HARDERROR_RESPONSE\n{\n    ResponseReturnToCaller,\n    ResponseNotHandled,\n    ResponseAbort,\n    ResponseCancel,\n    ResponseIgnore,\n    ResponseNo,\n    ResponseOk,\n    ResponseRetry,\n    ResponseYes,\n    ResponseTryAgain,\n    ResponseContinue\n} HARDERROR_RESPONSE;\n\n// HARDERROR_MSG not included\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtRaiseHardError(\n    _In_ NTSTATUS ErrorStatus,\n    _In_ ULONG NumberOfParameters,\n    _In_ ULONG UnicodeStringParameterMask,\n    _In_reads_(NumberOfParameters) PULONG_PTR Parameters,\n    _In_ ULONG ValidResponseOptions,\n    _Out_ PULONG Response\n    );\n\n// Kernel-user shared data\n\ntypedef enum _ALTERNATIVE_ARCHITECTURE_TYPE\n{\n    StandardDesign,\n    NEC98x86,\n    EndAlternatives\n} ALTERNATIVE_ARCHITECTURE_TYPE;\n\n#define PROCESSOR_FEATURE_MAX 64\n\n#define MAX_WOW64_SHARED_ENTRIES 16\n\n#define NX_SUPPORT_POLICY_ALWAYSOFF 0\n#define NX_SUPPORT_POLICY_ALWAYSON 1\n#define NX_SUPPORT_POLICY_OPTIN 2\n#define NX_SUPPORT_POLICY_OPTOUT 3\n\n#include <pshpack4.h>\ntypedef struct _KUSER_SHARED_DATA\n{\n    ULONG TickCountLowDeprecated;\n    ULONG TickCountMultiplier;\n\n    volatile KSYSTEM_TIME InterruptTime;\n    volatile KSYSTEM_TIME SystemTime;\n    volatile KSYSTEM_TIME TimeZoneBias;\n\n    USHORT ImageNumberLow;\n    USHORT ImageNumberHigh;\n\n    WCHAR NtSystemRoot[260];\n\n    ULONG MaxStackTraceDepth;\n\n    ULONG CryptoExponent;\n\n    ULONG TimeZoneId;\n    ULONG LargePageMinimum;\n    ULONG AitSamplingValue;\n    ULONG AppCompatFlag;\n    ULONGLONG RNGSeedVersion;\n    ULONG GlobalValidationRunlevel;\n    LONG TimeZoneBiasStamp;\n\n    ULONG NtBuildNumber;\n    NT_PRODUCT_TYPE NtProductType;\n    BOOLEAN ProductTypeIsValid;\n    UCHAR Reserved0[1];\n    USHORT NativeProcessorArchitecture;\n\n    ULONG NtMajorVersion;\n    ULONG NtMinorVersion;\n\n    BOOLEAN ProcessorFeatures[PROCESSOR_FEATURE_MAX];\n\n    ULONG Reserved1;\n    ULONG Reserved3;\n\n    volatile ULONG TimeSlip;\n\n    ALTERNATIVE_ARCHITECTURE_TYPE AlternativeArchitecture;\n    ULONG BootId;\n\n    LARGE_INTEGER SystemExpirationDate;\n\n    ULONG SuiteMask;\n\n    BOOLEAN KdDebuggerEnabled;\n    union\n    {\n        UCHAR MitigationPolicies;\n        struct\n        {\n            UCHAR NXSupportPolicy : 2;\n            UCHAR SEHValidationPolicy : 2;\n            UCHAR CurDirDevicesSkippedForDlls : 2;\n            UCHAR Reserved : 2;\n        };\n    };\n    UCHAR Reserved6[2];\n\n    volatile ULONG ActiveConsoleId;\n\n    volatile ULONG DismountCount;\n\n    ULONG ComPlusPackage;\n\n    ULONG LastSystemRITEventTickCount;\n\n    ULONG NumberOfPhysicalPages;\n\n    BOOLEAN SafeBootMode;\n    UCHAR VirtualizationFlags;\n    UCHAR Reserved12[2];\n\n    union\n    {\n        ULONG SharedDataFlags;\n        struct\n        {\n            ULONG DbgErrorPortPresent : 1;\n            ULONG DbgElevationEnabled : 1;\n            ULONG DbgVirtEnabled : 1;\n            ULONG DbgInstallerDetectEnabled : 1;\n            ULONG DbgLkgEnabled : 1;\n            ULONG DbgDynProcessorEnabled : 1;\n            ULONG DbgConsoleBrokerEnabled : 1;\n            ULONG DbgSecureBootEnabled : 1;\n            ULONG DbgMultiSessionSku : 1;\n            ULONG DbgMultiUsersInSessionSku : 1;\n            ULONG DbgStateSeparationEnabled : 1;\n            ULONG SpareBits : 21;\n        };\n    };\n    ULONG DataFlagsPad[1];\n\n    ULONGLONG TestRetInstruction;\n    LONGLONG QpcFrequency;\n    ULONG SystemCall;\n    ULONG SystemCallPad0;\n    ULONGLONG SystemCallPad[2];\n\n    union\n    {\n        volatile KSYSTEM_TIME TickCount;\n        volatile ULONG64 TickCountQuad;\n        ULONG ReservedTickCountOverlay[3];\n    };\n    ULONG TickCountPad[1];\n\n    ULONG Cookie;\n    ULONG CookiePad[1];\n\n    LONGLONG ConsoleSessionForegroundProcessId;\n    ULONGLONG TimeUpdateLock;\n    ULONGLONG BaselineSystemTimeQpc;\n    ULONGLONG BaselineInterruptTimeQpc;\n    ULONGLONG QpcSystemTimeIncrement;\n    ULONGLONG QpcInterruptTimeIncrement;\n    UCHAR QpcSystemTimeIncrementShift;\n    UCHAR QpcInterruptTimeIncrementShift;\n\n    USHORT UnparkedProcessorCount;\n    ULONG EnclaveFeatureMask[4];\n    \n    ULONG TelemetryCoverageRound;\n    \n    USHORT UserModeGlobalLogger[16];\n    ULONG ImageFileExecutionOptions;\n\n    ULONG LangGenerationCount;\n    ULONGLONG Reserved4;\n    volatile ULONG64 InterruptTimeBias;\n    volatile ULONG64 QpcBias;\n\n    ULONG ActiveProcessorCount;\n    volatile UCHAR ActiveGroupCount;\n    UCHAR Reserved9;\n    union\n    {\n        USHORT QpcData;\n        struct\n        {\n            UCHAR QpcBypassEnabled : 1;\n            UCHAR QpcShift : 1;\n        };\n    };\n\n    LARGE_INTEGER TimeZoneBiasEffectiveStart;\n    LARGE_INTEGER TimeZoneBiasEffectiveEnd;\n    XSTATE_CONFIGURATION XState;\n} KUSER_SHARED_DATA, *PKUSER_SHARED_DATA;\n#include <poppack.h>\n\nC_ASSERT(FIELD_OFFSET(KUSER_SHARED_DATA, TickCountMultiplier) == 0x4);\nC_ASSERT(FIELD_OFFSET(KUSER_SHARED_DATA, InterruptTime) == 0x8);\nC_ASSERT(FIELD_OFFSET(KUSER_SHARED_DATA, SystemTime) == 0x14);\nC_ASSERT(FIELD_OFFSET(KUSER_SHARED_DATA, TimeZoneBias) == 0x20);\nC_ASSERT(FIELD_OFFSET(KUSER_SHARED_DATA, ImageNumberLow) == 0x2c);\nC_ASSERT(FIELD_OFFSET(KUSER_SHARED_DATA, ImageNumberHigh) == 0x2e);\nC_ASSERT(FIELD_OFFSET(KUSER_SHARED_DATA, NtSystemRoot) == 0x30);\nC_ASSERT(FIELD_OFFSET(KUSER_SHARED_DATA, MaxStackTraceDepth) == 0x238);\nC_ASSERT(FIELD_OFFSET(KUSER_SHARED_DATA, CryptoExponent) == 0x23c);\nC_ASSERT(FIELD_OFFSET(KUSER_SHARED_DATA, TimeZoneId) == 0x240);\nC_ASSERT(FIELD_OFFSET(KUSER_SHARED_DATA, LargePageMinimum) == 0x244);\nC_ASSERT(FIELD_OFFSET(KUSER_SHARED_DATA, NtProductType) == 0x264);\nC_ASSERT(FIELD_OFFSET(KUSER_SHARED_DATA, ProductTypeIsValid) == 0x268);\nC_ASSERT(FIELD_OFFSET(KUSER_SHARED_DATA, NtMajorVersion) == 0x26c);\nC_ASSERT(FIELD_OFFSET(KUSER_SHARED_DATA, NtMinorVersion) == 0x270);\nC_ASSERT(FIELD_OFFSET(KUSER_SHARED_DATA, ProcessorFeatures) == 0x274);\nC_ASSERT(FIELD_OFFSET(KUSER_SHARED_DATA, Reserved1) == 0x2b4);\nC_ASSERT(FIELD_OFFSET(KUSER_SHARED_DATA, Reserved3) == 0x2b8);\nC_ASSERT(FIELD_OFFSET(KUSER_SHARED_DATA, TimeSlip) == 0x2bc);\nC_ASSERT(FIELD_OFFSET(KUSER_SHARED_DATA, AlternativeArchitecture) == 0x2c0);\nC_ASSERT(FIELD_OFFSET(KUSER_SHARED_DATA, SystemExpirationDate) == 0x2c8);\nC_ASSERT(FIELD_OFFSET(KUSER_SHARED_DATA, SuiteMask) == 0x2d0);\nC_ASSERT(FIELD_OFFSET(KUSER_SHARED_DATA, KdDebuggerEnabled) == 0x2d4);\nC_ASSERT(FIELD_OFFSET(KUSER_SHARED_DATA, ActiveConsoleId) == 0x2d8);\nC_ASSERT(FIELD_OFFSET(KUSER_SHARED_DATA, DismountCount) == 0x2dc);\nC_ASSERT(FIELD_OFFSET(KUSER_SHARED_DATA, ComPlusPackage) == 0x2e0);\nC_ASSERT(FIELD_OFFSET(KUSER_SHARED_DATA, LastSystemRITEventTickCount) == 0x2e4);\nC_ASSERT(FIELD_OFFSET(KUSER_SHARED_DATA, NumberOfPhysicalPages) == 0x2e8);\nC_ASSERT(FIELD_OFFSET(KUSER_SHARED_DATA, SafeBootMode) == 0x2ec);\nC_ASSERT(FIELD_OFFSET(KUSER_SHARED_DATA, TestRetInstruction) == 0x2f8);\nC_ASSERT(FIELD_OFFSET(KUSER_SHARED_DATA, SystemCallPad) == 0x310);\nC_ASSERT(FIELD_OFFSET(KUSER_SHARED_DATA, TickCount) == 0x320);\nC_ASSERT(FIELD_OFFSET(KUSER_SHARED_DATA, TickCountQuad) == 0x320);\nC_ASSERT(FIELD_OFFSET(KUSER_SHARED_DATA, XState) == 0x3d8);\n//C_ASSERT(sizeof(KUSER_SHARED_DATA) == 0x708);\n\n#define USER_SHARED_DATA ((KUSER_SHARED_DATA * const)0x7ffe0000)\n\n#if (PHNT_VERSION >= PHNT_WS03)\n\nFORCEINLINE ULONGLONG NtGetTickCount64()\n{\n    ULARGE_INTEGER tickCount;\n\n#ifdef _WIN64\n\n    tickCount.QuadPart = USER_SHARED_DATA->TickCountQuad;\n\n#else\n\n    while (TRUE)\n    {\n        tickCount.HighPart = (ULONG)USER_SHARED_DATA->TickCount.High1Time;\n        tickCount.LowPart = USER_SHARED_DATA->TickCount.LowPart;\n\n        if (tickCount.HighPart == (ULONG)USER_SHARED_DATA->TickCount.High2Time)\n            break;\n\n#ifndef _MANAGED\n\t\tYieldProcessor();\n#endif // !_MANAGED\n    }\n\n#endif\n\n    return (UInt32x32To64(tickCount.LowPart, USER_SHARED_DATA->TickCountMultiplier) >> 24) +\n        (UInt32x32To64(tickCount.HighPart, USER_SHARED_DATA->TickCountMultiplier) << 8);\n}\n\nFORCEINLINE ULONG NtGetTickCount()\n{\n#ifdef _WIN64\n\n    return (ULONG)((USER_SHARED_DATA->TickCountQuad * USER_SHARED_DATA->TickCountMultiplier) >> 24);\n\n#else\n\n    ULARGE_INTEGER tickCount;\n\n    while (TRUE)\n    {\n        tickCount.HighPart = (ULONG)USER_SHARED_DATA->TickCount.High1Time;\n        tickCount.LowPart = USER_SHARED_DATA->TickCount.LowPart;\n\n        if (tickCount.HighPart == (ULONG)USER_SHARED_DATA->TickCount.High2Time)\n            break;\n\n#ifndef _MANAGED\n\t\tYieldProcessor();\n#endif // !_MANAGED\n        \n    }\n\n    return (ULONG)((UInt32x32To64(tickCount.LowPart, USER_SHARED_DATA->TickCountMultiplier) >> 24) +\n        UInt32x32To64((tickCount.HighPart << 8) & 0xffffffff, USER_SHARED_DATA->TickCountMultiplier));\n\n#endif\n}\n\n#endif\n\n// Locale\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtQueryDefaultLocale(\n    _In_ BOOLEAN UserProfile,\n    _Out_ PLCID DefaultLocaleId\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtSetDefaultLocale(\n    _In_ BOOLEAN UserProfile,\n    _In_ LCID DefaultLocaleId\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtQueryInstallUILanguage(\n    _Out_ LANGID *InstallUILanguageId\n    );\n\n#if (PHNT_VERSION >= PHNT_VISTA)\n// private\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtFlushInstallUILanguage(\n    _In_ LANGID InstallUILanguage,\n    _In_ ULONG SetComittedFlag\n    );\n#endif\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtQueryDefaultUILanguage(\n    _Out_ LANGID *DefaultUILanguageId\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtSetDefaultUILanguage(\n    _In_ LANGID DefaultUILanguageId\n    );\n\n#if (PHNT_VERSION >= PHNT_VISTA)\n// private\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtIsUILanguageComitted(\n    VOID\n    );\n#endif\n\n// NLS\n\n// begin_private\n\n#if (PHNT_VERSION >= PHNT_VISTA)\n\n#if (PHNT_VERSION >= PHNT_WIN7)\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtInitializeNlsFiles(\n    _Out_ PVOID *BaseAddress,\n    _Out_ PLCID DefaultLocaleId,\n    _Out_ PLARGE_INTEGER DefaultCasingTableSize\n    );\n#else\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtInitializeNlsFiles(\n    _Out_ PVOID *BaseAddress,\n    _Out_ PLCID DefaultLocaleId,\n    _Out_ PLARGE_INTEGER DefaultCasingTableSize,\n    _Out_opt_ PULONG CurrentNLSVersion\n    );\n#endif\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtGetNlsSectionPtr(\n    _In_ ULONG SectionType,\n    _In_ ULONG SectionData,\n    _In_ PVOID ContextData,\n    _Out_ PVOID *SectionPointer,\n    _Out_ PULONG SectionSize\n    );\n\n#if (PHNT_VERSION < PHNT_WIN7)\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtAcquireCMFViewOwnership(\n    _Out_ PULONGLONG TimeStamp,\n    _Out_ PBOOLEAN tokenTaken,\n    _In_ BOOLEAN replaceExisting\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtReleaseCMFViewOwnership(\n    VOID\n    );\n\n#endif\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtMapCMFModule(\n    _In_ ULONG What,\n    _In_ ULONG Index,\n    _Out_opt_ PULONG CacheIndexOut,\n    _Out_opt_ PULONG CacheFlagsOut,\n    _Out_opt_ PULONG ViewSizeOut,\n    _Out_opt_ PVOID *BaseAddress\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtGetMUIRegistryInfo(\n    _In_ ULONG Flags,\n    _Inout_ PULONG DataSize,\n    _Out_ PVOID Data\n    );\n\n#endif\n\n// end_private\n\n// Global atoms\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtAddAtom(\n    _In_reads_bytes_opt_(Length) PWSTR AtomName,\n    _In_ ULONG Length,\n    _Out_opt_ PRTL_ATOM Atom\n    );\n\n#if (PHNT_VERSION >= PHNT_WIN8)\n// rev\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtAddAtomEx(\n    _In_reads_bytes_opt_(Length) PWSTR AtomName,\n    _In_ ULONG Length,\n    _Out_opt_ PRTL_ATOM Atom,\n    _In_ ULONG Flags\n    );\n#endif\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtFindAtom(\n    _In_reads_bytes_opt_(Length) PWSTR AtomName,\n    _In_ ULONG Length,\n    _Out_opt_ PRTL_ATOM Atom\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtDeleteAtom(\n    _In_ RTL_ATOM Atom\n    );\n\ntypedef enum _ATOM_INFORMATION_CLASS\n{\n    AtomBasicInformation,\n    AtomTableInformation\n} ATOM_INFORMATION_CLASS;\n\ntypedef struct _ATOM_BASIC_INFORMATION\n{\n    USHORT UsageCount;\n    USHORT Flags;\n    USHORT NameLength;\n    WCHAR Name[1];\n} ATOM_BASIC_INFORMATION, *PATOM_BASIC_INFORMATION;\n\ntypedef struct _ATOM_TABLE_INFORMATION\n{\n    ULONG NumberOfAtoms;\n    RTL_ATOM Atoms[1];\n} ATOM_TABLE_INFORMATION, *PATOM_TABLE_INFORMATION;\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtQueryInformationAtom(\n    _In_ RTL_ATOM Atom,\n    _In_ ATOM_INFORMATION_CLASS AtomInformationClass,\n    _Out_writes_bytes_(AtomInformationLength) PVOID AtomInformation,\n    _In_ ULONG AtomInformationLength,\n    _Out_opt_ PULONG ReturnLength\n    );\n\n// Global flags\n\n#define FLG_STOP_ON_EXCEPTION 0x00000001 // uk\n#define FLG_SHOW_LDR_SNAPS 0x00000002 // uk\n#define FLG_DEBUG_INITIAL_COMMAND 0x00000004 // k\n#define FLG_STOP_ON_HUNG_GUI 0x00000008 // k\n\n#define FLG_HEAP_ENABLE_TAIL_CHECK 0x00000010 // u\n#define FLG_HEAP_ENABLE_FREE_CHECK 0x00000020 // u\n#define FLG_HEAP_VALIDATE_PARAMETERS 0x00000040 // u\n#define FLG_HEAP_VALIDATE_ALL 0x00000080 // u\n\n#define FLG_APPLICATION_VERIFIER 0x00000100 // u\n#define FLG_POOL_ENABLE_TAGGING 0x00000400 // k\n#define FLG_HEAP_ENABLE_TAGGING 0x00000800 // u\n\n#define FLG_USER_STACK_TRACE_DB 0x00001000 // u,32\n#define FLG_KERNEL_STACK_TRACE_DB 0x00002000 // k,32\n#define FLG_MAINTAIN_OBJECT_TYPELIST 0x00004000 // k\n#define FLG_HEAP_ENABLE_TAG_BY_DLL 0x00008000 // u\n\n#define FLG_DISABLE_STACK_EXTENSION 0x00010000 // u\n#define FLG_ENABLE_CSRDEBUG 0x00020000 // k\n#define FLG_ENABLE_KDEBUG_SYMBOL_LOAD 0x00040000 // k\n#define FLG_DISABLE_PAGE_KERNEL_STACKS 0x00080000 // k\n\n#define FLG_ENABLE_SYSTEM_CRIT_BREAKS 0x00100000 // u\n#define FLG_HEAP_DISABLE_COALESCING 0x00200000 // u\n#define FLG_ENABLE_CLOSE_EXCEPTIONS 0x00400000 // k\n#define FLG_ENABLE_EXCEPTION_LOGGING 0x00800000 // k\n\n#define FLG_ENABLE_HANDLE_TYPE_TAGGING 0x01000000 // k\n#define FLG_HEAP_PAGE_ALLOCS 0x02000000 // u\n#define FLG_DEBUG_INITIAL_COMMAND_EX 0x04000000 // k\n#define FLG_DISABLE_DBGPRINT 0x08000000 // k\n\n#define FLG_CRITSEC_EVENT_CREATION 0x10000000 // u\n#define FLG_LDR_TOP_DOWN 0x20000000 // u,64\n#define FLG_ENABLE_HANDLE_EXCEPTIONS 0x40000000 // k\n#define FLG_DISABLE_PROTDLLS 0x80000000 // u\n\n#define FLG_VALID_BITS 0xfffffdff\n\n#define FLG_USERMODE_VALID_BITS (FLG_STOP_ON_EXCEPTION | \\\n    FLG_SHOW_LDR_SNAPS | \\\n    FLG_HEAP_ENABLE_TAIL_CHECK | \\\n    FLG_HEAP_ENABLE_FREE_CHECK | \\\n    FLG_HEAP_VALIDATE_PARAMETERS | \\\n    FLG_HEAP_VALIDATE_ALL | \\\n    FLG_APPLICATION_VERIFIER | \\\n    FLG_HEAP_ENABLE_TAGGING | \\\n    FLG_USER_STACK_TRACE_DB | \\\n    FLG_HEAP_ENABLE_TAG_BY_DLL | \\\n    FLG_DISABLE_STACK_EXTENSION | \\\n    FLG_ENABLE_SYSTEM_CRIT_BREAKS | \\\n    FLG_HEAP_DISABLE_COALESCING | \\\n    FLG_DISABLE_PROTDLLS | \\\n    FLG_HEAP_PAGE_ALLOCS | \\\n    FLG_CRITSEC_EVENT_CREATION | \\\n    FLG_LDR_TOP_DOWN)\n\n#define FLG_BOOTONLY_VALID_BITS (FLG_KERNEL_STACK_TRACE_DB | \\\n    FLG_MAINTAIN_OBJECT_TYPELIST | \\\n    FLG_ENABLE_CSRDEBUG | \\\n    FLG_DEBUG_INITIAL_COMMAND | \\\n    FLG_DEBUG_INITIAL_COMMAND_EX | \\\n    FLG_DISABLE_PAGE_KERNEL_STACKS)\n\n#define FLG_KERNELMODE_VALID_BITS (FLG_STOP_ON_EXCEPTION | \\\n    FLG_SHOW_LDR_SNAPS | \\\n    FLG_STOP_ON_HUNG_GUI | \\\n    FLG_POOL_ENABLE_TAGGING | \\\n    FLG_ENABLE_KDEBUG_SYMBOL_LOAD | \\\n    FLG_ENABLE_CLOSE_EXCEPTIONS | \\\n    FLG_ENABLE_EXCEPTION_LOGGING | \\\n    FLG_ENABLE_HANDLE_TYPE_TAGGING | \\\n    FLG_DISABLE_DBGPRINT | \\\n    FLG_ENABLE_HANDLE_EXCEPTIONS)\n\n// Licensing\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtQueryLicenseValue(\n    _In_ PUNICODE_STRING ValueName,\n    _Out_opt_ PULONG Type,\n    _Out_writes_bytes_to_opt_(DataSize, *ResultDataSize) PVOID Data,\n    _In_ ULONG DataSize,\n    _Out_ PULONG ResultDataSize\n    );\n\n// Misc.\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtSetDefaultHardErrorPort(\n    _In_ HANDLE DefaultHardErrorPort\n    );\n\ntypedef enum _SHUTDOWN_ACTION\n{\n    ShutdownNoReboot,\n    ShutdownReboot,\n    ShutdownPowerOff\n} SHUTDOWN_ACTION;\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtShutdownSystem(\n    _In_ SHUTDOWN_ACTION Action\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtDisplayString(\n    _In_ PUNICODE_STRING String\n    );\n\n#if (PHNT_VERSION >= PHNT_WIN7)\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtDrawText(\n    _In_ PUNICODE_STRING String\n    );\n#endif\n\n#endif // (PHNT_MODE != PHNT_MODE_KERNEL)\n\n#endif\n"
  },
  {
    "path": "third_party/phnt/include/ntgdi.h",
    "content": "#ifndef _NTGDI_H\n#define _NTGDI_H\n\n#define GDI_MAX_HANDLE_COUNT 0x4000\n\n#define GDI_HANDLE_INDEX_SHIFT 0\n#define GDI_HANDLE_INDEX_BITS 16\n#define GDI_HANDLE_INDEX_MASK 0xffff\n\n#define GDI_HANDLE_TYPE_SHIFT 16\n#define GDI_HANDLE_TYPE_BITS 5\n#define GDI_HANDLE_TYPE_MASK 0x1f\n\n#define GDI_HANDLE_ALTTYPE_SHIFT 21\n#define GDI_HANDLE_ALTTYPE_BITS 2\n#define GDI_HANDLE_ALTTYPE_MASK 0x3\n\n#define GDI_HANDLE_STOCK_SHIFT 23\n#define GDI_HANDLE_STOCK_BITS 1\n#define GDI_HANDLE_STOCK_MASK 0x1\n\n#define GDI_HANDLE_UNIQUE_SHIFT 24\n#define GDI_HANDLE_UNIQUE_BITS 8\n#define GDI_HANDLE_UNIQUE_MASK 0xff\n\n#define GDI_HANDLE_INDEX(Handle) ((ULONG)(Handle) & GDI_HANDLE_INDEX_MASK)\n#define GDI_HANDLE_TYPE(Handle) (((ULONG)(Handle) >> GDI_HANDLE_TYPE_SHIFT) & GDI_HANDLE_TYPE_MASK)\n#define GDI_HANDLE_ALTTYPE(Handle) (((ULONG)(Handle) >> GDI_HANDLE_ALTTYPE_SHIFT) & GDI_HANDLE_ALTTYPE_MASK)\n#define GDI_HANDLE_STOCK(Handle) (((ULONG)(Handle) >> GDI_HANDLE_STOCK_SHIFT)) & GDI_HANDLE_STOCK_MASK)\n\n#define GDI_MAKE_HANDLE(Index, Unique) ((ULONG)(((ULONG)(Unique) << GDI_HANDLE_INDEX_BITS) | (ULONG)(Index)))\n\n// GDI server-side types\n\n#define GDI_DEF_TYPE 0 // invalid handle\n#define GDI_DC_TYPE 1\n#define GDI_DD_DIRECTDRAW_TYPE 2\n#define GDI_DD_SURFACE_TYPE 3\n#define GDI_RGN_TYPE 4\n#define GDI_SURF_TYPE 5\n#define GDI_CLIENTOBJ_TYPE 6\n#define GDI_PATH_TYPE 7\n#define GDI_PAL_TYPE 8\n#define GDI_ICMLCS_TYPE 9\n#define GDI_LFONT_TYPE 10\n#define GDI_RFONT_TYPE 11\n#define GDI_PFE_TYPE 12\n#define GDI_PFT_TYPE 13\n#define GDI_ICMCXF_TYPE 14\n#define GDI_ICMDLL_TYPE 15\n#define GDI_BRUSH_TYPE 16\n#define GDI_PFF_TYPE 17 // unused\n#define GDI_CACHE_TYPE 18 // unused\n#define GDI_SPACE_TYPE 19\n#define GDI_DBRUSH_TYPE 20 // unused\n#define GDI_META_TYPE 21\n#define GDI_EFSTATE_TYPE 22\n#define GDI_BMFD_TYPE 23 // unused\n#define GDI_VTFD_TYPE 24 // unused\n#define GDI_TTFD_TYPE 25 // unused\n#define GDI_RC_TYPE 26 // unused\n#define GDI_TEMP_TYPE 27 // unused\n#define GDI_DRVOBJ_TYPE 28\n#define GDI_DCIOBJ_TYPE 29 // unused\n#define GDI_SPOOL_TYPE 30\n\n// GDI client-side types\n\n#define GDI_CLIENT_TYPE_FROM_HANDLE(Handle) ((ULONG)(Handle) & ((GDI_HANDLE_ALTTYPE_MASK << GDI_HANDLE_ALTTYPE_SHIFT) | \\\n    (GDI_HANDLE_TYPE_MASK << GDI_HANDLE_TYPE_SHIFT)))\n#define GDI_CLIENT_TYPE_FROM_UNIQUE(Unique) GDI_CLIENT_TYPE_FROM_HANDLE((ULONG)(Unique) << 16)\n\n#define GDI_ALTTYPE_1 (1 << GDI_HANDLE_ALTTYPE_SHIFT)\n#define GDI_ALTTYPE_2 (2 << GDI_HANDLE_ALTTYPE_SHIFT)\n#define GDI_ALTTYPE_3 (3 << GDI_HANDLE_ALTTYPE_SHIFT)\n\n#define GDI_CLIENT_BITMAP_TYPE (GDI_SURF_TYPE << GDI_HANDLE_TYPE_SHIFT)\n#define GDI_CLIENT_BRUSH_TYPE (GDI_BRUSH_TYPE << GDI_HANDLE_TYPE_SHIFT)\n#define GDI_CLIENT_CLIENTOBJ_TYPE (GDI_CLIENTOBJ_TYPE << GDI_HANDLE_TYPE_SHIFT)\n#define GDI_CLIENT_DC_TYPE (GDI_DC_TYPE << GDI_HANDLE_TYPE_SHIFT)\n#define GDI_CLIENT_FONT_TYPE (GDI_LFONT_TYPE << GDI_HANDLE_TYPE_SHIFT)\n#define GDI_CLIENT_PALETTE_TYPE (GDI_PAL_TYPE << GDI_HANDLE_TYPE_SHIFT)\n#define GDI_CLIENT_REGION_TYPE (GDI_RGN_TYPE << GDI_HANDLE_TYPE_SHIFT)\n\n#define GDI_CLIENT_ALTDC_TYPE (GDI_CLIENT_DC_TYPE | GDI_ALTTYPE_1)\n#define GDI_CLIENT_DIBSECTION_TYPE (GDI_CLIENT_BITMAP_TYPE | GDI_ALTTYPE_1)\n#define GDI_CLIENT_EXTPEN_TYPE (GDI_CLIENT_BRUSH_TYPE | GDI_ALTTYPE_2)\n#define GDI_CLIENT_METADC16_TYPE (GDI_CLIENT_CLIENTOBJ_TYPE | GDI_ALTTYPE_3)\n#define GDI_CLIENT_METAFILE_TYPE (GDI_CLIENT_CLIENTOBJ_TYPE | GDI_ALTTYPE_2)\n#define GDI_CLIENT_METAFILE16_TYPE (GDI_CLIENT_CLIENTOBJ_TYPE | GDI_ALTTYPE_1)\n#define GDI_CLIENT_PEN_TYPE (GDI_CLIENT_BRUSH_TYPE | GDI_ALTTYPE_1)\n\ntypedef struct _GDI_HANDLE_ENTRY\n{\n    union\n    {\n        PVOID Object;\n        PVOID NextFree;\n    };\n    union\n    {\n        struct\n        {\n            USHORT ProcessId;\n            USHORT Lock : 1;\n            USHORT Count : 15;\n        };\n        ULONG Value;\n    } Owner;\n    USHORT Unique;\n    UCHAR Type;\n    UCHAR Flags;\n    PVOID UserPointer;\n} GDI_HANDLE_ENTRY, *PGDI_HANDLE_ENTRY;\n\ntypedef struct _GDI_SHARED_MEMORY\n{\n    GDI_HANDLE_ENTRY Handles[GDI_MAX_HANDLE_COUNT];\n} GDI_SHARED_MEMORY, *PGDI_SHARED_MEMORY;\n\n#endif\n"
  },
  {
    "path": "third_party/phnt/include/ntioapi.h",
    "content": "#ifndef _NTIOAPI_H\n#define _NTIOAPI_H\n\n// Create disposition\n\n#define FILE_SUPERSEDE 0x00000000\n#define FILE_OPEN 0x00000001\n#define FILE_CREATE 0x00000002\n#define FILE_OPEN_IF 0x00000003\n#define FILE_OVERWRITE 0x00000004\n#define FILE_OVERWRITE_IF 0x00000005\n#define FILE_MAXIMUM_DISPOSITION 0x00000005\n\n// Create/open flags\n\n#define FILE_DIRECTORY_FILE 0x00000001\n#define FILE_WRITE_THROUGH 0x00000002\n#define FILE_SEQUENTIAL_ONLY 0x00000004\n#define FILE_NO_INTERMEDIATE_BUFFERING 0x00000008\n\n#define FILE_SYNCHRONOUS_IO_ALERT 0x00000010\n#define FILE_SYNCHRONOUS_IO_NONALERT 0x00000020\n#define FILE_NON_DIRECTORY_FILE 0x00000040\n#define FILE_CREATE_TREE_CONNECTION 0x00000080\n\n#define FILE_COMPLETE_IF_OPLOCKED 0x00000100\n#define FILE_NO_EA_KNOWLEDGE 0x00000200\n#define FILE_OPEN_FOR_RECOVERY 0x00000400\n#define FILE_RANDOM_ACCESS 0x00000800\n\n#define FILE_DELETE_ON_CLOSE 0x00001000\n#define FILE_OPEN_BY_FILE_ID 0x00002000\n#define FILE_OPEN_FOR_BACKUP_INTENT 0x00004000\n#define FILE_NO_COMPRESSION 0x00008000\n#if (PHNT_VERSION >= PHNT_WIN7)\n#define FILE_OPEN_REQUIRING_OPLOCK 0x00010000\n#define FILE_DISALLOW_EXCLUSIVE 0x00020000\n#endif\n#if (PHNT_VERSION >= PHNT_WIN8)\n#define FILE_SESSION_AWARE 0x00040000\n#endif\n\n#define FILE_RESERVE_OPFILTER 0x00100000\n#define FILE_OPEN_REPARSE_POINT 0x00200000\n#define FILE_OPEN_NO_RECALL 0x00400000\n#define FILE_OPEN_FOR_FREE_SPACE_QUERY 0x00800000\n\n#define FILE_COPY_STRUCTURED_STORAGE 0x00000041\n#define FILE_STRUCTURED_STORAGE 0x00000441\n\n// I/O status information values for NtCreateFile/NtOpenFile\n\n#define FILE_SUPERSEDED 0x00000000\n#define FILE_OPENED 0x00000001\n#define FILE_CREATED 0x00000002\n#define FILE_OVERWRITTEN 0x00000003\n#define FILE_EXISTS 0x00000004\n#define FILE_DOES_NOT_EXIST 0x00000005\n\n// Special ByteOffset parameters\n\n#define FILE_WRITE_TO_END_OF_FILE 0xffffffff\n#define FILE_USE_FILE_POINTER_POSITION 0xfffffffe\n\n// Alignment requirement values\n\n#define FILE_BYTE_ALIGNMENT 0x00000000\n#define FILE_WORD_ALIGNMENT 0x00000001\n#define FILE_LONG_ALIGNMENT 0x00000003\n#define FILE_QUAD_ALIGNMENT 0x00000007\n#define FILE_OCTA_ALIGNMENT 0x0000000f\n#define FILE_32_BYTE_ALIGNMENT 0x0000001f\n#define FILE_64_BYTE_ALIGNMENT 0x0000003f\n#define FILE_128_BYTE_ALIGNMENT 0x0000007f\n#define FILE_256_BYTE_ALIGNMENT 0x000000ff\n#define FILE_512_BYTE_ALIGNMENT 0x000001ff\n\n// Maximum length of a filename string\n\n#define MAXIMUM_FILENAME_LENGTH 256\n\n// Extended attributes\n\n#define FILE_NEED_EA 0x00000080\n\n#define FILE_EA_TYPE_BINARY 0xfffe\n#define FILE_EA_TYPE_ASCII 0xfffd\n#define FILE_EA_TYPE_BITMAP 0xfffb\n#define FILE_EA_TYPE_METAFILE 0xfffa\n#define FILE_EA_TYPE_ICON 0xfff9\n#define FILE_EA_TYPE_EA 0xffee\n#define FILE_EA_TYPE_MVMT 0xffdf\n#define FILE_EA_TYPE_MVST 0xffde\n#define FILE_EA_TYPE_ASN1 0xffdd\n#define FILE_EA_TYPE_FAMILY_IDS 0xff01\n\n// Device characteristics\n\n#define FILE_REMOVABLE_MEDIA 0x00000001\n#define FILE_READ_ONLY_DEVICE 0x00000002\n#define FILE_FLOPPY_DISKETTE 0x00000004\n#define FILE_WRITE_ONCE_MEDIA 0x00000008\n#define FILE_REMOTE_DEVICE 0x00000010\n#define FILE_DEVICE_IS_MOUNTED 0x00000020\n#define FILE_VIRTUAL_VOLUME 0x00000040\n#define FILE_AUTOGENERATED_DEVICE_NAME 0x00000080\n#define FILE_DEVICE_SECURE_OPEN 0x00000100\n#define FILE_CHARACTERISTIC_PNP_DEVICE 0x00000800\n#define FILE_CHARACTERISTIC_TS_DEVICE 0x00001000\n#define FILE_CHARACTERISTIC_WEBDAV_DEVICE 0x00002000\n#define FILE_CHARACTERISTIC_CSV 0x00010000\n#define FILE_DEVICE_ALLOW_APPCONTAINER_TRAVERSAL 0x00020000\n#define FILE_PORTABLE_DEVICE 0x00040000\n\n// Named pipe values\n\n// NamedPipeType for NtCreateNamedPipeFile\n#define FILE_PIPE_BYTE_STREAM_TYPE 0x00000000\n#define FILE_PIPE_MESSAGE_TYPE 0x00000001\n#define FILE_PIPE_ACCEPT_REMOTE_CLIENTS 0x00000000\n#define FILE_PIPE_REJECT_REMOTE_CLIENTS 0x00000002\n#define FILE_PIPE_TYPE_VALID_MASK 0x00000003\n\n// CompletionMode for NtCreateNamedPipeFile\n#define FILE_PIPE_QUEUE_OPERATION 0x00000000\n#define FILE_PIPE_COMPLETE_OPERATION 0x00000001\n\n// ReadMode for NtCreateNamedPipeFile\n#define FILE_PIPE_BYTE_STREAM_MODE 0x00000000\n#define FILE_PIPE_MESSAGE_MODE 0x00000001\n\n// NamedPipeConfiguration for NtQueryInformationFile\n#define FILE_PIPE_INBOUND 0x00000000\n#define FILE_PIPE_OUTBOUND 0x00000001\n#define FILE_PIPE_FULL_DUPLEX 0x00000002\n\n// NamedPipeState for NtQueryInformationFile\n#define FILE_PIPE_DISCONNECTED_STATE 0x00000001\n#define FILE_PIPE_LISTENING_STATE 0x00000002\n#define FILE_PIPE_CONNECTED_STATE 0x00000003\n#define FILE_PIPE_CLOSING_STATE 0x00000004\n\n// NamedPipeEnd for NtQueryInformationFile\n#define FILE_PIPE_CLIENT_END 0x00000000\n#define FILE_PIPE_SERVER_END 0x00000001\n\n// Mailslot values\n\n#define MAILSLOT_SIZE_AUTO 0\n\ntypedef struct _IO_STATUS_BLOCK\n{\n    union\n    {\n        NTSTATUS Status;\n        PVOID Pointer;\n    };\n    ULONG_PTR Information;\n} IO_STATUS_BLOCK, *PIO_STATUS_BLOCK;\n\ntypedef VOID (NTAPI *PIO_APC_ROUTINE)(\n    _In_ PVOID ApcContext,\n    _In_ PIO_STATUS_BLOCK IoStatusBlock,\n    _In_ ULONG Reserved\n    );\n\n// private\ntypedef struct _FILE_IO_COMPLETION_INFORMATION\n{\n    PVOID KeyContext;\n    PVOID ApcContext;\n    IO_STATUS_BLOCK IoStatusBlock;\n} FILE_IO_COMPLETION_INFORMATION, *PFILE_IO_COMPLETION_INFORMATION;\n\ntypedef enum _FILE_INFORMATION_CLASS\n{\n    FileDirectoryInformation = 1, // FILE_DIRECTORY_INFORMATION\n    FileFullDirectoryInformation, // FILE_FULL_DIR_INFORMATION\n    FileBothDirectoryInformation, // FILE_BOTH_DIR_INFORMATION\n    FileBasicInformation, // FILE_BASIC_INFORMATION\n    FileStandardInformation, // FILE_STANDARD_INFORMATION\n    FileInternalInformation, // FILE_INTERNAL_INFORMATION\n    FileEaInformation, // FILE_EA_INFORMATION\n    FileAccessInformation, // FILE_ACCESS_INFORMATION\n    FileNameInformation, // FILE_NAME_INFORMATION\n    FileRenameInformation, // FILE_RENAME_INFORMATION // 10\n    FileLinkInformation, // FILE_LINK_INFORMATION\n    FileNamesInformation, // FILE_NAMES_INFORMATION\n    FileDispositionInformation, // FILE_DISPOSITION_INFORMATION\n    FilePositionInformation, // FILE_POSITION_INFORMATION\n    FileFullEaInformation, // FILE_FULL_EA_INFORMATION\n    FileModeInformation, // FILE_MODE_INFORMATION\n    FileAlignmentInformation, // FILE_ALIGNMENT_INFORMATION\n    FileAllInformation, // FILE_ALL_INFORMATION\n    FileAllocationInformation, // FILE_ALLOCATION_INFORMATION\n    FileEndOfFileInformation, // FILE_END_OF_FILE_INFORMATION // 20\n    FileAlternateNameInformation, // FILE_NAME_INFORMATION\n    FileStreamInformation, // FILE_STREAM_INFORMATION\n    FilePipeInformation, // FILE_PIPE_INFORMATION\n    FilePipeLocalInformation, // FILE_PIPE_LOCAL_INFORMATION\n    FilePipeRemoteInformation, // FILE_PIPE_REMOTE_INFORMATION\n    FileMailslotQueryInformation, // FILE_MAILSLOT_QUERY_INFORMATION\n    FileMailslotSetInformation, // FILE_MAILSLOT_SET_INFORMATION\n    FileCompressionInformation, // FILE_COMPRESSION_INFORMATION\n    FileObjectIdInformation, // FILE_OBJECTID_INFORMATION\n    FileCompletionInformation, // FILE_COMPLETION_INFORMATION // 30\n    FileMoveClusterInformation, // FILE_MOVE_CLUSTER_INFORMATION\n    FileQuotaInformation, // FILE_QUOTA_INFORMATION\n    FileReparsePointInformation, // FILE_REPARSE_POINT_INFORMATION\n    FileNetworkOpenInformation, // FILE_NETWORK_OPEN_INFORMATION\n    FileAttributeTagInformation, // FILE_ATTRIBUTE_TAG_INFORMATION\n    FileTrackingInformation, // FILE_TRACKING_INFORMATION\n    FileIdBothDirectoryInformation, // FILE_ID_BOTH_DIR_INFORMATION\n    FileIdFullDirectoryInformation, // FILE_ID_FULL_DIR_INFORMATION\n    FileValidDataLengthInformation, // FILE_VALID_DATA_LENGTH_INFORMATION\n    FileShortNameInformation, // FILE_NAME_INFORMATION // 40\n    FileIoCompletionNotificationInformation, // FILE_IO_COMPLETION_NOTIFICATION_INFORMATION // since VISTA\n    FileIoStatusBlockRangeInformation, // FILE_IOSTATUSBLOCK_RANGE_INFORMATION\n    FileIoPriorityHintInformation, // FILE_IO_PRIORITY_HINT_INFORMATION\n    FileSfioReserveInformation, // FILE_SFIO_RESERVE_INFORMATION\n    FileSfioVolumeInformation, // FILE_SFIO_VOLUME_INFORMATION\n    FileHardLinkInformation, // FILE_LINKS_INFORMATION\n    FileProcessIdsUsingFileInformation, // FILE_PROCESS_IDS_USING_FILE_INFORMATION\n    FileNormalizedNameInformation, // FILE_NAME_INFORMATION\n    FileNetworkPhysicalNameInformation, // FILE_NETWORK_PHYSICAL_NAME_INFORMATION\n    FileIdGlobalTxDirectoryInformation, // FILE_ID_GLOBAL_TX_DIR_INFORMATION // since WIN7 // 50\n    FileIsRemoteDeviceInformation, // FILE_IS_REMOTE_DEVICE_INFORMATION\n    FileUnusedInformation,\n    FileNumaNodeInformation, // FILE_NUMA_NODE_INFORMATION\n    FileStandardLinkInformation, // FILE_STANDARD_LINK_INFORMATION\n    FileRemoteProtocolInformation, // FILE_REMOTE_PROTOCOL_INFORMATION\n    FileRenameInformationBypassAccessCheck, // (kernel-mode only); FILE_RENAME_INFORMATION // since WIN8\n    FileLinkInformationBypassAccessCheck, // (kernel-mode only); FILE_LINK_INFORMATION\n    FileVolumeNameInformation, // FILE_VOLUME_NAME_INFORMATION\n    FileIdInformation, // FILE_ID_INFORMATION\n    FileIdExtdDirectoryInformation, // FILE_ID_EXTD_DIR_INFORMATION\n    FileReplaceCompletionInformation, // FILE_COMPLETION_INFORMATION // since WINBLUE\n    FileHardLinkFullIdInformation, // FILE_LINK_ENTRY_FULL_ID_INFORMATION\n    FileIdExtdBothDirectoryInformation, // FILE_ID_EXTD_BOTH_DIR_INFORMATION // since THRESHOLD\n    FileDispositionInformationEx, // FILE_DISPOSITION_INFO_EX // since REDSTONE\n    FileRenameInformationEx,\n    FileRenameInformationExBypassAccessCheck,\n    FileDesiredStorageClassInformation, // FILE_DESIRED_STORAGE_CLASS_INFORMATION // since REDSTONE2\n    FileStatInformation, // FILE_STAT_INFORMATION\n    FileMemoryPartitionInformation, // FILE_MEMORY_PARTITION_INFORMATION // since REDSTONE3\n    FileMaximumInformation\n} FILE_INFORMATION_CLASS, *PFILE_INFORMATION_CLASS;\n\n// NtQueryInformationFile/NtSetInformationFile types\n\ntypedef struct _FILE_BASIC_INFORMATION\n{\n    LARGE_INTEGER CreationTime;\n    LARGE_INTEGER LastAccessTime;\n    LARGE_INTEGER LastWriteTime;\n    LARGE_INTEGER ChangeTime;\n    ULONG FileAttributes;\n} FILE_BASIC_INFORMATION, *PFILE_BASIC_INFORMATION;\n\ntypedef struct _FILE_STANDARD_INFORMATION\n{\n    LARGE_INTEGER AllocationSize;\n    LARGE_INTEGER EndOfFile;\n    ULONG NumberOfLinks;\n    BOOLEAN DeletePending;\n    BOOLEAN Directory;\n} FILE_STANDARD_INFORMATION, *PFILE_STANDARD_INFORMATION;\n\ntypedef struct _FILE_STANDARD_INFORMATION_EX\n{\n    LARGE_INTEGER AllocationSize;\n    LARGE_INTEGER EndOfFile;\n    ULONG NumberOfLinks;\n    BOOLEAN DeletePending;\n    BOOLEAN Directory;\n    BOOLEAN AlternateStream;\n    BOOLEAN MetadataAttribute;\n} FILE_STANDARD_INFORMATION_EX, *PFILE_STANDARD_INFORMATION_EX;\n\ntypedef struct _FILE_INTERNAL_INFORMATION\n{\n    LARGE_INTEGER IndexNumber;\n} FILE_INTERNAL_INFORMATION, *PFILE_INTERNAL_INFORMATION;\n\ntypedef struct _FILE_EA_INFORMATION\n{\n    ULONG EaSize;\n} FILE_EA_INFORMATION, *PFILE_EA_INFORMATION;\n\ntypedef struct _FILE_ACCESS_INFORMATION\n{\n    ACCESS_MASK AccessFlags;\n} FILE_ACCESS_INFORMATION, *PFILE_ACCESS_INFORMATION;\n\ntypedef struct _FILE_POSITION_INFORMATION\n{\n    LARGE_INTEGER CurrentByteOffset;\n} FILE_POSITION_INFORMATION, *PFILE_POSITION_INFORMATION;\n\ntypedef struct _FILE_MODE_INFORMATION\n{\n    ULONG Mode;\n} FILE_MODE_INFORMATION, *PFILE_MODE_INFORMATION;\n\ntypedef struct _FILE_ALIGNMENT_INFORMATION\n{\n    ULONG AlignmentRequirement;\n} FILE_ALIGNMENT_INFORMATION, *PFILE_ALIGNMENT_INFORMATION;\n\ntypedef struct _FILE_NAME_INFORMATION\n{\n    ULONG FileNameLength;\n    WCHAR FileName[1];\n} FILE_NAME_INFORMATION, *PFILE_NAME_INFORMATION;\n\ntypedef struct _FILE_ALL_INFORMATION\n{\n    FILE_BASIC_INFORMATION BasicInformation;\n    FILE_STANDARD_INFORMATION StandardInformation;\n    FILE_INTERNAL_INFORMATION InternalInformation;\n    FILE_EA_INFORMATION EaInformation;\n    FILE_ACCESS_INFORMATION AccessInformation;\n    FILE_POSITION_INFORMATION PositionInformation;\n    FILE_MODE_INFORMATION ModeInformation;\n    FILE_ALIGNMENT_INFORMATION AlignmentInformation;\n    FILE_NAME_INFORMATION NameInformation;\n} FILE_ALL_INFORMATION, *PFILE_ALL_INFORMATION;\n\ntypedef struct _FILE_NETWORK_OPEN_INFORMATION\n{\n    LARGE_INTEGER CreationTime;\n    LARGE_INTEGER LastAccessTime;\n    LARGE_INTEGER LastWriteTime;\n    LARGE_INTEGER ChangeTime;\n    LARGE_INTEGER AllocationSize;\n    LARGE_INTEGER EndOfFile;\n    ULONG FileAttributes;\n} FILE_NETWORK_OPEN_INFORMATION, *PFILE_NETWORK_OPEN_INFORMATION;\n\ntypedef struct _FILE_ATTRIBUTE_TAG_INFORMATION\n{\n    ULONG FileAttributes;\n    ULONG ReparseTag;\n} FILE_ATTRIBUTE_TAG_INFORMATION, *PFILE_ATTRIBUTE_TAG_INFORMATION;\n\ntypedef struct _FILE_ALLOCATION_INFORMATION\n{\n    LARGE_INTEGER AllocationSize;\n} FILE_ALLOCATION_INFORMATION, *PFILE_ALLOCATION_INFORMATION;\n\ntypedef struct _FILE_COMPRESSION_INFORMATION\n{\n    LARGE_INTEGER CompressedFileSize;\n    USHORT CompressionFormat;\n    UCHAR CompressionUnitShift;\n    UCHAR ChunkShift;\n    UCHAR ClusterShift;\n    UCHAR Reserved[3];\n} FILE_COMPRESSION_INFORMATION, *PFILE_COMPRESSION_INFORMATION;\n\ntypedef struct _FILE_DISPOSITION_INFORMATION\n{\n    BOOLEAN DeleteFile;\n} FILE_DISPOSITION_INFORMATION, *PFILE_DISPOSITION_INFORMATION;\n\ntypedef struct _FILE_END_OF_FILE_INFORMATION\n{\n    LARGE_INTEGER EndOfFile;\n} FILE_END_OF_FILE_INFORMATION, *PFILE_END_OF_FILE_INFORMATION;\n\ntypedef struct _FILE_VALID_DATA_LENGTH_INFORMATION\n{\n    LARGE_INTEGER ValidDataLength;\n} FILE_VALID_DATA_LENGTH_INFORMATION, *PFILE_VALID_DATA_LENGTH_INFORMATION;\n\ntypedef struct _FILE_LINK_INFORMATION\n{\n    BOOLEAN ReplaceIfExists;\n    HANDLE RootDirectory;\n    ULONG FileNameLength;\n    WCHAR FileName[1];\n} FILE_LINK_INFORMATION, *PFILE_LINK_INFORMATION;\n\ntypedef struct _FILE_MOVE_CLUSTER_INFORMATION\n{\n    ULONG ClusterCount;\n    HANDLE RootDirectory;\n    ULONG FileNameLength;\n    WCHAR FileName[1];\n} FILE_MOVE_CLUSTER_INFORMATION, *PFILE_MOVE_CLUSTER_INFORMATION;\n\ntypedef struct _FILE_RENAME_INFORMATION\n{\n    BOOLEAN ReplaceIfExists;\n    HANDLE RootDirectory;\n    ULONG FileNameLength;\n    WCHAR FileName[1];\n} FILE_RENAME_INFORMATION, *PFILE_RENAME_INFORMATION;\n\ntypedef struct _FILE_STREAM_INFORMATION\n{\n    ULONG NextEntryOffset;\n    ULONG StreamNameLength;\n    LARGE_INTEGER StreamSize;\n    LARGE_INTEGER StreamAllocationSize;\n    WCHAR StreamName[1];\n} FILE_STREAM_INFORMATION, *PFILE_STREAM_INFORMATION;\n\ntypedef struct _FILE_TRACKING_INFORMATION\n{\n    HANDLE DestinationFile;\n    ULONG ObjectInformationLength;\n    CHAR ObjectInformation[1];\n} FILE_TRACKING_INFORMATION, *PFILE_TRACKING_INFORMATION;\n\ntypedef struct _FILE_COMPLETION_INFORMATION\n{\n    HANDLE Port;\n    PVOID Key;\n} FILE_COMPLETION_INFORMATION, *PFILE_COMPLETION_INFORMATION;\n\ntypedef struct _FILE_PIPE_INFORMATION\n{\n     ULONG ReadMode;\n     ULONG CompletionMode;\n} FILE_PIPE_INFORMATION, *PFILE_PIPE_INFORMATION;\n\ntypedef struct _FILE_PIPE_LOCAL_INFORMATION\n{\n     ULONG NamedPipeType;\n     ULONG NamedPipeConfiguration;\n     ULONG MaximumInstances;\n     ULONG CurrentInstances;\n     ULONG InboundQuota;\n     ULONG ReadDataAvailable;\n     ULONG OutboundQuota;\n     ULONG WriteQuotaAvailable;\n     ULONG NamedPipeState;\n     ULONG NamedPipeEnd;\n} FILE_PIPE_LOCAL_INFORMATION, *PFILE_PIPE_LOCAL_INFORMATION;\n\ntypedef struct _FILE_PIPE_REMOTE_INFORMATION\n{\n     LARGE_INTEGER CollectDataTime;\n     ULONG MaximumCollectionCount;\n} FILE_PIPE_REMOTE_INFORMATION, *PFILE_PIPE_REMOTE_INFORMATION;\n\ntypedef struct _FILE_MAILSLOT_QUERY_INFORMATION\n{\n    ULONG MaximumMessageSize;\n    ULONG MailslotQuota;\n    ULONG NextMessageSize;\n    ULONG MessagesAvailable;\n    LARGE_INTEGER ReadTimeout;\n} FILE_MAILSLOT_QUERY_INFORMATION, *PFILE_MAILSLOT_QUERY_INFORMATION;\n\ntypedef struct _FILE_MAILSLOT_SET_INFORMATION\n{\n    PLARGE_INTEGER ReadTimeout;\n} FILE_MAILSLOT_SET_INFORMATION, *PFILE_MAILSLOT_SET_INFORMATION;\n\ntypedef struct _FILE_REPARSE_POINT_INFORMATION\n{\n    LONGLONG FileReference;\n    ULONG Tag;\n} FILE_REPARSE_POINT_INFORMATION, *PFILE_REPARSE_POINT_INFORMATION;\n\ntypedef struct _FILE_LINK_ENTRY_INFORMATION\n{\n    ULONG NextEntryOffset;\n    LONGLONG ParentFileId;\n    ULONG FileNameLength;\n    WCHAR FileName[1];\n} FILE_LINK_ENTRY_INFORMATION, *PFILE_LINK_ENTRY_INFORMATION;\n\ntypedef struct _FILE_LINKS_INFORMATION\n{\n    ULONG BytesNeeded;\n    ULONG EntriesReturned;\n    FILE_LINK_ENTRY_INFORMATION Entry;\n} FILE_LINKS_INFORMATION, *PFILE_LINKS_INFORMATION;\n\ntypedef struct _FILE_NETWORK_PHYSICAL_NAME_INFORMATION\n{\n    ULONG FileNameLength;\n    WCHAR FileName[1];\n} FILE_NETWORK_PHYSICAL_NAME_INFORMATION, *PFILE_NETWORK_PHYSICAL_NAME_INFORMATION;\n\ntypedef struct _FILE_STANDARD_LINK_INFORMATION\n{\n    ULONG NumberOfAccessibleLinks;\n    ULONG TotalNumberOfLinks;\n    BOOLEAN DeletePending;\n    BOOLEAN Directory;\n} FILE_STANDARD_LINK_INFORMATION, *PFILE_STANDARD_LINK_INFORMATION;\n\ntypedef struct _FILE_SFIO_RESERVE_INFORMATION\n{\n    ULONG RequestsPerPeriod;\n    ULONG Period;\n    BOOLEAN RetryFailures;\n    BOOLEAN Discardable;\n    ULONG RequestSize;\n    ULONG NumOutstandingRequests;\n} FILE_SFIO_RESERVE_INFORMATION, *PFILE_SFIO_RESERVE_INFORMATION;\n\ntypedef struct _FILE_SFIO_VOLUME_INFORMATION\n{\n    ULONG MaximumRequestsPerPeriod;\n    ULONG MinimumPeriod;\n    ULONG MinimumTransferSize;\n} FILE_SFIO_VOLUME_INFORMATION, *PFILE_SFIO_VOLUME_INFORMATION;\n\ntypedef enum _IO_PRIORITY_HINT\n{\n    IoPriorityVeryLow = 0, // Defragging, content indexing and other background I/Os.\n    IoPriorityLow, // Prefetching for applications.\n    IoPriorityNormal, // Normal I/Os.\n    IoPriorityHigh, // Used by filesystems for checkpoint I/O.\n    IoPriorityCritical, // Used by memory manager. Not available for applications.\n    MaxIoPriorityTypes\n} IO_PRIORITY_HINT;\n\ntypedef struct _FILE_IO_PRIORITY_HINT_INFORMATION\n{\n    IO_PRIORITY_HINT PriorityHint;\n} FILE_IO_PRIORITY_HINT_INFORMATION, *PFILE_IO_PRIORITY_HINT_INFORMATION;\n\ntypedef struct _FILE_IO_PRIORITY_HINT_INFORMATION_EX\n{\n    IO_PRIORITY_HINT PriorityHint;\n    BOOLEAN BoostOutstanding;\n} FILE_IO_PRIORITY_HINT_INFORMATION_EX, *PFILE_IO_PRIORITY_HINT_INFORMATION_EX;\n\n#define FILE_SKIP_COMPLETION_PORT_ON_SUCCESS 0x1\n#define FILE_SKIP_SET_EVENT_ON_HANDLE 0x2\n#define FILE_SKIP_SET_USER_EVENT_ON_FAST_IO 0x4\n\ntypedef struct _FILE_IO_COMPLETION_NOTIFICATION_INFORMATION\n{\n    ULONG Flags;\n} FILE_IO_COMPLETION_NOTIFICATION_INFORMATION, *PFILE_IO_COMPLETION_NOTIFICATION_INFORMATION;\n\ntypedef struct _FILE_PROCESS_IDS_USING_FILE_INFORMATION\n{\n    ULONG NumberOfProcessIdsInList;\n    ULONG_PTR ProcessIdList[1];\n} FILE_PROCESS_IDS_USING_FILE_INFORMATION, *PFILE_PROCESS_IDS_USING_FILE_INFORMATION;\n\ntypedef struct _FILE_IS_REMOTE_DEVICE_INFORMATION\n{\n    BOOLEAN IsRemote;\n} FILE_IS_REMOTE_DEVICE_INFORMATION, *PFILE_IS_REMOTE_DEVICE_INFORMATION;\n\ntypedef struct _FILE_NUMA_NODE_INFORMATION\n{\n    USHORT NodeNumber;\n} FILE_NUMA_NODE_INFORMATION, *PFILE_NUMA_NODE_INFORMATION;\n\ntypedef struct _FILE_IOSTATUSBLOCK_RANGE_INFORMATION\n{\n    PUCHAR IoStatusBlockRange;\n    ULONG Length;\n} FILE_IOSTATUSBLOCK_RANGE_INFORMATION, *PFILE_IOSTATUSBLOCK_RANGE_INFORMATION;\n\ntypedef struct _FILE_REMOTE_PROTOCOL_INFORMATION\n{\n    USHORT StructureVersion; // 1\n    USHORT StructureSize;\n\n    ULONG Protocol; // WNNC_NET_*\n\n    USHORT ProtocolMajorVersion;\n    USHORT ProtocolMinorVersion;\n    USHORT ProtocolRevision;\n\n    USHORT Reserved;\n\n    // Generic information\n\n    ULONG Flags;\n\n    struct\n    {\n        ULONG Reserved[8];\n    } GenericReserved;\n\n    // Specific information\n\n#if (PHNT_VERSION < PHNT_WIN8)\n    struct\n    {\n        ULONG Reserved[16];\n    } ProtocolSpecificReserved;\n#else\n    union\n    {\n        struct\n        {\n            struct\n            {\n                ULONG Capabilities;\n            } Server;\n            struct\n            {\n                ULONG Capabilities;\n                ULONG CachingFlags;\n            } Share;\n        } Smb2;\n        ULONG Reserved[16];\n    } ProtocolSpecific;\n#endif\n} FILE_REMOTE_PROTOCOL_INFORMATION, *PFILE_REMOTE_PROTOCOL_INFORMATION;\n\n#define CHECKSUM_ENFORCEMENT_OFF 0x00000001\n\ntypedef struct _FILE_INTEGRITY_STREAM_INFORMATION\n{\n    USHORT ChecksumAlgorithm;\n    UCHAR ChecksumChunkShift;\n    UCHAR ClusterShift;\n    ULONG Flags;\n} FILE_INTEGRITY_STREAM_INFORMATION, *PFILE_INTEGRITY_STREAM_INFORMATION;\n\ntypedef struct _FILE_VOLUME_NAME_INFORMATION\n{\n    ULONG DeviceNameLength;\n    WCHAR DeviceName[1];\n} FILE_VOLUME_NAME_INFORMATION, *PFILE_VOLUME_NAME_INFORMATION;\n\ntypedef struct _FILE_ID_INFORMATION\n{\n    ULONGLONG VolumeSerialNumber;\n    FILE_ID_128 FileId;\n} FILE_ID_INFORMATION, *PFILE_ID_INFORMATION;\n\ntypedef struct _FILE_ID_EXTD_DIR_INFORMATION\n{\n    ULONG NextEntryOffset;\n    ULONG FileIndex;\n    LARGE_INTEGER CreationTime;\n    LARGE_INTEGER LastAccessTime;\n    LARGE_INTEGER LastWriteTime;\n    LARGE_INTEGER ChangeTime;\n    LARGE_INTEGER EndOfFile;\n    LARGE_INTEGER AllocationSize;\n    ULONG FileAttributes;\n    ULONG FileNameLength;\n    ULONG EaSize;\n    ULONG ReparsePointTag;\n    FILE_ID_128 FileId;\n    WCHAR FileName[1];\n} FILE_ID_EXTD_DIR_INFORMATION, *PFILE_ID_EXTD_DIR_INFORMATION;\n\ntypedef struct _FILE_LINK_ENTRY_FULL_ID_INFORMATION\n{\n    ULONG NextEntryOffset;\n    FILE_ID_128 ParentFileId;\n    ULONG FileNameLength;\n    WCHAR FileName[1];\n} FILE_LINK_ENTRY_FULL_ID_INFORMATION, *PFILE_LINK_ENTRY_FULL_ID_INFORMATION;\n\ntypedef struct _FILE_ID_EXTD_BOTH_DIR_INFORMATION\n{\n    ULONG NextEntryOffset;\n    ULONG FileIndex;\n    LARGE_INTEGER CreationTime;\n    LARGE_INTEGER LastAccessTime;\n    LARGE_INTEGER LastWriteTime;\n    LARGE_INTEGER ChangeTime;\n    LARGE_INTEGER EndOfFile;\n    LARGE_INTEGER AllocationSize;\n    ULONG FileAttributes;\n    ULONG FileNameLength;\n    ULONG EaSize;\n    ULONG ReparsePointTag;\n    FILE_ID_128 FileId;\n    CCHAR ShortNameLength;\n    WCHAR ShortName[12];\n    WCHAR FileName[1];\n} FILE_ID_EXTD_BOTH_DIR_INFORMATION, *PFILE_ID_EXTD_BOTH_DIR_INFORMATION;\n\n// private\ntypedef struct _FILE_STAT_INFORMATION\n{\n    LARGE_INTEGER FileId;\n    LARGE_INTEGER CreationTime;\n    LARGE_INTEGER LastAccessTime;\n    LARGE_INTEGER LastWriteTime;\n    LARGE_INTEGER ChangeTime;\n    LARGE_INTEGER AllocationSize;\n    LARGE_INTEGER EndOfFile;\n    ULONG FileAttributes;\n    ULONG ReparseTag;\n    ULONG NumberOfLinks;\n    ULONG EffectiveAccess;\n} FILE_STAT_INFORMATION, *PFILE_STAT_INFORMATION;\n\n// private\ntypedef struct _FILE_MEMORY_PARTITION_INFORMATION\n{\n    HANDLE OwnerPartitionHandle;\n    union\n    {\n        struct\n        {\n            UCHAR NoCrossPartitionAccess;\n            UCHAR Spare[3];\n        };\n        ULONG AllFlags;\n    } Flags;\n} FILE_MEMORY_PARTITION_INFORMATION, *PFILE_MEMORY_PARTITION_INFORMATION;\n\n// NtQueryDirectoryFile types\n\ntypedef struct _FILE_DIRECTORY_INFORMATION\n{\n    ULONG NextEntryOffset;\n    ULONG FileIndex;\n    LARGE_INTEGER CreationTime;\n    LARGE_INTEGER LastAccessTime;\n    LARGE_INTEGER LastWriteTime;\n    LARGE_INTEGER ChangeTime;\n    LARGE_INTEGER EndOfFile;\n    LARGE_INTEGER AllocationSize;\n    ULONG FileAttributes;\n    ULONG FileNameLength;\n    WCHAR FileName[1];\n} FILE_DIRECTORY_INFORMATION, *PFILE_DIRECTORY_INFORMATION;\n\ntypedef struct _FILE_FULL_DIR_INFORMATION\n{\n    ULONG NextEntryOffset;\n    ULONG FileIndex;\n    LARGE_INTEGER CreationTime;\n    LARGE_INTEGER LastAccessTime;\n    LARGE_INTEGER LastWriteTime;\n    LARGE_INTEGER ChangeTime;\n    LARGE_INTEGER EndOfFile;\n    LARGE_INTEGER AllocationSize;\n    ULONG FileAttributes;\n    ULONG FileNameLength;\n    ULONG EaSize;\n    WCHAR FileName[1];\n} FILE_FULL_DIR_INFORMATION, *PFILE_FULL_DIR_INFORMATION;\n\ntypedef struct _FILE_ID_FULL_DIR_INFORMATION\n{\n    ULONG NextEntryOffset;\n    ULONG FileIndex;\n    LARGE_INTEGER CreationTime;\n    LARGE_INTEGER LastAccessTime;\n    LARGE_INTEGER LastWriteTime;\n    LARGE_INTEGER ChangeTime;\n    LARGE_INTEGER EndOfFile;\n    LARGE_INTEGER AllocationSize;\n    ULONG FileAttributes;\n    ULONG FileNameLength;\n    ULONG EaSize;\n    LARGE_INTEGER FileId;\n    WCHAR FileName[1];\n} FILE_ID_FULL_DIR_INFORMATION, *PFILE_ID_FULL_DIR_INFORMATION;\n\ntypedef struct _FILE_BOTH_DIR_INFORMATION\n{\n    ULONG NextEntryOffset;\n    ULONG FileIndex;\n    LARGE_INTEGER CreationTime;\n    LARGE_INTEGER LastAccessTime;\n    LARGE_INTEGER LastWriteTime;\n    LARGE_INTEGER ChangeTime;\n    LARGE_INTEGER EndOfFile;\n    LARGE_INTEGER AllocationSize;\n    ULONG FileAttributes;\n    ULONG FileNameLength;\n    ULONG EaSize;\n    CCHAR ShortNameLength;\n    WCHAR ShortName[12];\n    WCHAR FileName[1];\n} FILE_BOTH_DIR_INFORMATION, *PFILE_BOTH_DIR_INFORMATION;\n\ntypedef struct _FILE_ID_BOTH_DIR_INFORMATION\n{\n    ULONG NextEntryOffset;\n    ULONG FileIndex;\n    LARGE_INTEGER CreationTime;\n    LARGE_INTEGER LastAccessTime;\n    LARGE_INTEGER LastWriteTime;\n    LARGE_INTEGER ChangeTime;\n    LARGE_INTEGER EndOfFile;\n    LARGE_INTEGER AllocationSize;\n    ULONG FileAttributes;\n    ULONG FileNameLength;\n    ULONG EaSize;\n    CCHAR ShortNameLength;\n    WCHAR ShortName[12];\n    LARGE_INTEGER FileId;\n    WCHAR FileName[1];\n} FILE_ID_BOTH_DIR_INFORMATION, *PFILE_ID_BOTH_DIR_INFORMATION;\n\ntypedef struct _FILE_NAMES_INFORMATION\n{\n    ULONG NextEntryOffset;\n    ULONG FileIndex;\n    ULONG FileNameLength;\n    WCHAR FileName[1];\n} FILE_NAMES_INFORMATION, *PFILE_NAMES_INFORMATION;\n\ntypedef struct _FILE_ID_GLOBAL_TX_DIR_INFORMATION\n{\n    ULONG NextEntryOffset;\n    ULONG FileIndex;\n    LARGE_INTEGER CreationTime;\n    LARGE_INTEGER LastAccessTime;\n    LARGE_INTEGER LastWriteTime;\n    LARGE_INTEGER ChangeTime;\n    LARGE_INTEGER EndOfFile;\n    LARGE_INTEGER AllocationSize;\n    ULONG FileAttributes;\n    ULONG FileNameLength;\n    LARGE_INTEGER FileId;\n    GUID LockingTransactionId;\n    ULONG TxInfoFlags;\n    WCHAR FileName[1];\n} FILE_ID_GLOBAL_TX_DIR_INFORMATION, *PFILE_ID_GLOBAL_TX_DIR_INFORMATION;\n\n#define FILE_ID_GLOBAL_TX_DIR_INFO_FLAG_WRITELOCKED 0x00000001\n#define FILE_ID_GLOBAL_TX_DIR_INFO_FLAG_VISIBLE_TO_TX 0x00000002\n#define FILE_ID_GLOBAL_TX_DIR_INFO_FLAG_VISIBLE_OUTSIDE_TX 0x00000004\n\ntypedef struct _FILE_OBJECTID_INFORMATION\n{\n    LONGLONG FileReference;\n    UCHAR ObjectId[16];\n    union\n    {\n        struct\n        {\n            UCHAR BirthVolumeId[16];\n            UCHAR BirthObjectId[16];\n            UCHAR DomainId[16];\n        };\n        UCHAR ExtendedInfo[48];\n    };\n} FILE_OBJECTID_INFORMATION, *PFILE_OBJECTID_INFORMATION;\n\n// NtQueryEaFile/NtSetEaFile types\n\ntypedef struct _FILE_FULL_EA_INFORMATION\n{\n    ULONG NextEntryOffset;\n    UCHAR Flags;\n    UCHAR EaNameLength;\n    USHORT EaValueLength;\n    CHAR EaName[1];\n} FILE_FULL_EA_INFORMATION, *PFILE_FULL_EA_INFORMATION;\n\ntypedef struct _FILE_GET_EA_INFORMATION\n{\n    ULONG NextEntryOffset;\n    UCHAR EaNameLength;\n    CHAR EaName[1];\n} FILE_GET_EA_INFORMATION, *PFILE_GET_EA_INFORMATION;\n\n// NtQueryQuotaInformationFile/NtSetQuotaInformationFile types\n\ntypedef struct _FILE_GET_QUOTA_INFORMATION\n{\n    ULONG NextEntryOffset;\n    ULONG SidLength;\n    SID Sid;\n} FILE_GET_QUOTA_INFORMATION, *PFILE_GET_QUOTA_INFORMATION;\n\ntypedef struct _FILE_QUOTA_INFORMATION\n{\n    ULONG NextEntryOffset;\n    ULONG SidLength;\n    LARGE_INTEGER ChangeTime;\n    LARGE_INTEGER QuotaUsed;\n    LARGE_INTEGER QuotaThreshold;\n    LARGE_INTEGER QuotaLimit;\n    SID Sid;\n} FILE_QUOTA_INFORMATION, *PFILE_QUOTA_INFORMATION;\n\ntypedef enum _FSINFOCLASS\n{\n    FileFsVolumeInformation = 1, // FILE_FS_VOLUME_INFORMATION\n    FileFsLabelInformation, // FILE_FS_LABEL_INFORMATION\n    FileFsSizeInformation, // FILE_FS_SIZE_INFORMATION\n    FileFsDeviceInformation, // FILE_FS_DEVICE_INFORMATION\n    FileFsAttributeInformation, // FILE_FS_ATTRIBUTE_INFORMATION\n    FileFsControlInformation, // FILE_FS_CONTROL_INFORMATION\n    FileFsFullSizeInformation, // FILE_FS_FULL_SIZE_INFORMATION\n    FileFsObjectIdInformation, // FILE_FS_OBJECTID_INFORMATION\n    FileFsDriverPathInformation, // FILE_FS_DRIVER_PATH_INFORMATION\n    FileFsVolumeFlagsInformation, // FILE_FS_VOLUME_FLAGS_INFORMATION\n    FileFsSectorSizeInformation, // FILE_FS_SECTOR_SIZE_INFORMATION // since WIN8\n    FileFsDataCopyInformation, // FILE_FS_DATA_COPY_INFORMATION\n    FileFsMetadataSizeInformation, // FILE_FS_METADATA_SIZE_INFORMATION // since THRESHOLD\n    FileFsMaximumInformation\n} FSINFOCLASS, *PFSINFOCLASS;\n\n// NtQueryVolumeInformation/NtSetVolumeInformation types\n\ntypedef struct _FILE_FS_LABEL_INFORMATION\n{\n    ULONG VolumeLabelLength;\n    WCHAR VolumeLabel[1];\n} FILE_FS_LABEL_INFORMATION, *PFILE_FS_LABEL_INFORMATION;\n\ntypedef struct _FILE_FS_VOLUME_INFORMATION\n{\n    LARGE_INTEGER VolumeCreationTime;\n    ULONG VolumeSerialNumber;\n    ULONG VolumeLabelLength;\n    BOOLEAN SupportsObjects;\n    WCHAR VolumeLabel[1];\n} FILE_FS_VOLUME_INFORMATION, *PFILE_FS_VOLUME_INFORMATION;\n\ntypedef struct _FILE_FS_SIZE_INFORMATION\n{\n    LARGE_INTEGER TotalAllocationUnits;\n    LARGE_INTEGER AvailableAllocationUnits;\n    ULONG SectorsPerAllocationUnit;\n    ULONG BytesPerSector;\n} FILE_FS_SIZE_INFORMATION, *PFILE_FS_SIZE_INFORMATION;\n\n// private\ntypedef struct _FILE_FS_CONTROL_INFORMATION\n{\n    LARGE_INTEGER FreeSpaceStartFiltering;\n    LARGE_INTEGER FreeSpaceThreshold;\n    LARGE_INTEGER FreeSpaceStopFiltering;\n    LARGE_INTEGER DefaultQuotaThreshold;\n    LARGE_INTEGER DefaultQuotaLimit;\n    ULONG FileSystemControlFlags;\n} FILE_FS_CONTROL_INFORMATION, *PFILE_FS_CONTROL_INFORMATION;\n\ntypedef struct _FILE_FS_FULL_SIZE_INFORMATION\n{\n    LARGE_INTEGER TotalAllocationUnits;\n    LARGE_INTEGER CallerAvailableAllocationUnits;\n    LARGE_INTEGER ActualAvailableAllocationUnits;\n    ULONG SectorsPerAllocationUnit;\n    ULONG BytesPerSector;\n} FILE_FS_FULL_SIZE_INFORMATION, *PFILE_FS_FULL_SIZE_INFORMATION;\n\ntypedef struct _FILE_FS_OBJECTID_INFORMATION\n{\n    UCHAR ObjectId[16];\n    UCHAR ExtendedInfo[48];\n} FILE_FS_OBJECTID_INFORMATION, *PFILE_FS_OBJECTID_INFORMATION;\n\ntypedef struct _FILE_FS_DEVICE_INFORMATION\n{\n    DEVICE_TYPE DeviceType;\n    ULONG Characteristics;\n} FILE_FS_DEVICE_INFORMATION, *PFILE_FS_DEVICE_INFORMATION;\n\ntypedef struct _FILE_FS_ATTRIBUTE_INFORMATION\n{\n    ULONG FileSystemAttributes;\n    LONG MaximumComponentNameLength;\n    ULONG FileSystemNameLength;\n    WCHAR FileSystemName[1];\n} FILE_FS_ATTRIBUTE_INFORMATION, *PFILE_FS_ATTRIBUTE_INFORMATION;\n\ntypedef struct _FILE_FS_DRIVER_PATH_INFORMATION\n{\n    BOOLEAN DriverInPath;\n    ULONG DriverNameLength;\n    WCHAR DriverName[1];\n} FILE_FS_DRIVER_PATH_INFORMATION, *PFILE_FS_DRIVER_PATH_INFORMATION;\n\ntypedef struct _FILE_FS_VOLUME_FLAGS_INFORMATION\n{\n    ULONG Flags;\n} FILE_FS_VOLUME_FLAGS_INFORMATION, *PFILE_FS_VOLUME_FLAGS_INFORMATION;\n\n#define SSINFO_FLAGS_ALIGNED_DEVICE 0x00000001\n#define SSINFO_FLAGS_PARTITION_ALIGNED_ON_DEVICE 0x00000002\n\n// If set for Sector and Partition fields, alignment is not known.\n#define SSINFO_OFFSET_UNKNOWN 0xffffffff\n\ntypedef struct _FILE_FS_SECTOR_SIZE_INFORMATION\n{\n    ULONG LogicalBytesPerSector;\n    ULONG PhysicalBytesPerSectorForAtomicity;\n    ULONG PhysicalBytesPerSectorForPerformance;\n    ULONG FileSystemEffectivePhysicalBytesPerSectorForAtomicity;\n    ULONG Flags;\n    ULONG ByteOffsetForSectorAlignment;\n    ULONG ByteOffsetForPartitionAlignment;\n} FILE_FS_SECTOR_SIZE_INFORMATION, *PFILE_FS_SECTOR_SIZE_INFORMATION;\n\n// private\ntypedef struct _FILE_FS_DATA_COPY_INFORMATION\n{\n    ULONG NumberOfCopies;\n} FILE_FS_DATA_COPY_INFORMATION, *PFILE_FS_DATA_COPY_INFORMATION;\n\ntypedef struct _FILE_FS_METADATA_SIZE_INFORMATION\n{\n    LARGE_INTEGER TotalMetadataAllocationUnits;\n    ULONG SectorsPerAllocationUnit;\n    ULONG BytesPerSector;\n} FILE_FS_METADATA_SIZE_INFORMATION, *PFILE_FS_METADATA_SIZE_INFORMATION;\n\n// System calls\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtCreateFile(\n    _Out_ PHANDLE FileHandle,\n    _In_ ACCESS_MASK DesiredAccess,\n    _In_ POBJECT_ATTRIBUTES ObjectAttributes,\n    _Out_ PIO_STATUS_BLOCK IoStatusBlock,\n    _In_opt_ PLARGE_INTEGER AllocationSize,\n    _In_ ULONG FileAttributes,\n    _In_ ULONG ShareAccess,\n    _In_ ULONG CreateDisposition,\n    _In_ ULONG CreateOptions,\n    _In_reads_bytes_opt_(EaLength) PVOID EaBuffer,\n    _In_ ULONG EaLength\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtCreateNamedPipeFile(\n    _Out_ PHANDLE FileHandle,\n    _In_ ULONG DesiredAccess,\n    _In_ POBJECT_ATTRIBUTES ObjectAttributes,\n    _Out_ PIO_STATUS_BLOCK IoStatusBlock,\n    _In_ ULONG ShareAccess,\n    _In_ ULONG CreateDisposition,\n    _In_ ULONG CreateOptions,\n    _In_ ULONG NamedPipeType,\n    _In_ ULONG ReadMode,\n    _In_ ULONG CompletionMode,\n    _In_ ULONG MaximumInstances,\n    _In_ ULONG InboundQuota,\n    _In_ ULONG OutboundQuota,\n    _In_opt_ PLARGE_INTEGER DefaultTimeout\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtCreateMailslotFile(\n    _Out_ PHANDLE FileHandle,\n    _In_ ULONG DesiredAccess,\n    _In_ POBJECT_ATTRIBUTES ObjectAttributes,\n    _Out_ PIO_STATUS_BLOCK IoStatusBlock,\n    _In_ ULONG CreateOptions,\n    _In_ ULONG MailslotQuota,\n    _In_ ULONG MaximumMessageSize,\n    _In_ PLARGE_INTEGER ReadTimeout\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtOpenFile(\n    _Out_ PHANDLE FileHandle,\n    _In_ ACCESS_MASK DesiredAccess,\n    _In_ POBJECT_ATTRIBUTES ObjectAttributes,\n    _Out_ PIO_STATUS_BLOCK IoStatusBlock,\n    _In_ ULONG ShareAccess,\n    _In_ ULONG OpenOptions\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtDeleteFile(\n    _In_ POBJECT_ATTRIBUTES ObjectAttributes\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtFlushBuffersFile(\n    _In_ HANDLE FileHandle,\n    _Out_ PIO_STATUS_BLOCK IoStatusBlock\n    );\n\n#define FLUSH_FLAGS_FILE_DATA_ONLY 0x00000001\n#define FLUSH_FLAGS_NO_SYNC 0x00000002\n\n#if (PHNT_VERSION >= PHNT_WIN8)\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtFlushBuffersFileEx(\n    _In_ HANDLE FileHandle,\n    _In_ ULONG Flags,\n    _In_reads_bytes_(ParametersSize) PVOID Parameters,\n    _In_ ULONG ParametersSize,\n    _Out_ PIO_STATUS_BLOCK IoStatusBlock\n    );\n#endif\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtQueryInformationFile(\n    _In_ HANDLE FileHandle,\n    _Out_ PIO_STATUS_BLOCK IoStatusBlock,\n    _Out_writes_bytes_(Length) PVOID FileInformation,\n    _In_ ULONG Length,\n    _In_ FILE_INFORMATION_CLASS FileInformationClass\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtSetInformationFile(\n    _In_ HANDLE FileHandle,\n    _Out_ PIO_STATUS_BLOCK IoStatusBlock,\n    _In_reads_bytes_(Length) PVOID FileInformation,\n    _In_ ULONG Length,\n    _In_ FILE_INFORMATION_CLASS FileInformationClass\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtQueryDirectoryFile(\n    _In_ HANDLE FileHandle,\n    _In_opt_ HANDLE Event,\n    _In_opt_ PIO_APC_ROUTINE ApcRoutine,\n    _In_opt_ PVOID ApcContext,\n    _Out_ PIO_STATUS_BLOCK IoStatusBlock,\n    _Out_writes_bytes_(Length) PVOID FileInformation,\n    _In_ ULONG Length,\n    _In_ FILE_INFORMATION_CLASS FileInformationClass,\n    _In_ BOOLEAN ReturnSingleEntry,\n    _In_opt_ PUNICODE_STRING FileName,\n    _In_ BOOLEAN RestartScan\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtQueryEaFile(\n    _In_ HANDLE FileHandle,\n    _Out_ PIO_STATUS_BLOCK IoStatusBlock,\n    _Out_writes_bytes_(Length) PVOID Buffer,\n    _In_ ULONG Length,\n    _In_ BOOLEAN ReturnSingleEntry,\n    _In_reads_bytes_opt_(EaListLength) PVOID EaList,\n    _In_ ULONG EaListLength,\n    _In_opt_ PULONG EaIndex,\n    _In_ BOOLEAN RestartScan\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtSetEaFile(\n    _In_ HANDLE FileHandle,\n    _Out_ PIO_STATUS_BLOCK IoStatusBlock,\n    _In_reads_bytes_(Length) PVOID Buffer,\n    _In_ ULONG Length\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtQueryQuotaInformationFile(\n    _In_ HANDLE FileHandle,\n    _Out_ PIO_STATUS_BLOCK IoStatusBlock,\n    _Out_writes_bytes_(Length) PVOID Buffer,\n    _In_ ULONG Length,\n    _In_ BOOLEAN ReturnSingleEntry,\n    _In_reads_bytes_opt_(SidListLength) PVOID SidList,\n    _In_ ULONG SidListLength,\n    _In_opt_ PSID StartSid,\n    _In_ BOOLEAN RestartScan\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtSetQuotaInformationFile(\n    _In_ HANDLE FileHandle,\n    _Out_ PIO_STATUS_BLOCK IoStatusBlock,\n    _In_reads_bytes_(Length) PVOID Buffer,\n    _In_ ULONG Length\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtQueryVolumeInformationFile(\n    _In_ HANDLE FileHandle,\n    _Out_ PIO_STATUS_BLOCK IoStatusBlock,\n    _Out_writes_bytes_(Length) PVOID FsInformation,\n    _In_ ULONG Length,\n    _In_ FSINFOCLASS FsInformationClass\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtSetVolumeInformationFile(\n    _In_ HANDLE FileHandle,\n    _Out_ PIO_STATUS_BLOCK IoStatusBlock,\n    _In_reads_bytes_(Length) PVOID FsInformation,\n    _In_ ULONG Length,\n    _In_ FSINFOCLASS FsInformationClass\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtCancelIoFile(\n    _In_ HANDLE FileHandle,\n    _Out_ PIO_STATUS_BLOCK IoStatusBlock\n    );\n\n#if (PHNT_VERSION >= PHNT_VISTA)\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtCancelIoFileEx(\n    _In_ HANDLE FileHandle,\n    _In_opt_ PIO_STATUS_BLOCK IoRequestToCancel,\n    _Out_ PIO_STATUS_BLOCK IoStatusBlock\n    );\n#endif\n\n#if (PHNT_VERSION >= PHNT_VISTA)\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtCancelSynchronousIoFile(\n    _In_ HANDLE ThreadHandle,\n    _In_opt_ PIO_STATUS_BLOCK IoRequestToCancel,\n    _Out_ PIO_STATUS_BLOCK IoStatusBlock\n    );\n#endif\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtDeviceIoControlFile(\n    _In_ HANDLE FileHandle,\n    _In_opt_ HANDLE Event,\n    _In_opt_ PIO_APC_ROUTINE ApcRoutine,\n    _In_opt_ PVOID ApcContext,\n    _Out_ PIO_STATUS_BLOCK IoStatusBlock,\n    _In_ ULONG IoControlCode,\n    _In_reads_bytes_opt_(InputBufferLength) PVOID InputBuffer,\n    _In_ ULONG InputBufferLength,\n    _Out_writes_bytes_opt_(OutputBufferLength) PVOID OutputBuffer,\n    _In_ ULONG OutputBufferLength\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtFsControlFile(\n    _In_ HANDLE FileHandle,\n    _In_opt_ HANDLE Event,\n    _In_opt_ PIO_APC_ROUTINE ApcRoutine,\n    _In_opt_ PVOID ApcContext,\n    _Out_ PIO_STATUS_BLOCK IoStatusBlock,\n    _In_ ULONG FsControlCode,\n    _In_reads_bytes_opt_(InputBufferLength) PVOID InputBuffer,\n    _In_ ULONG InputBufferLength,\n    _Out_writes_bytes_opt_(OutputBufferLength) PVOID OutputBuffer,\n    _In_ ULONG OutputBufferLength\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtReadFile(\n    _In_ HANDLE FileHandle,\n    _In_opt_ HANDLE Event,\n    _In_opt_ PIO_APC_ROUTINE ApcRoutine,\n    _In_opt_ PVOID ApcContext,\n    _Out_ PIO_STATUS_BLOCK IoStatusBlock,\n    _Out_writes_bytes_(Length) PVOID Buffer,\n    _In_ ULONG Length,\n    _In_opt_ PLARGE_INTEGER ByteOffset,\n    _In_opt_ PULONG Key\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtWriteFile(\n    _In_ HANDLE FileHandle,\n    _In_opt_ HANDLE Event,\n    _In_opt_ PIO_APC_ROUTINE ApcRoutine,\n    _In_opt_ PVOID ApcContext,\n    _Out_ PIO_STATUS_BLOCK IoStatusBlock,\n    _In_reads_bytes_(Length) PVOID Buffer,\n    _In_ ULONG Length,\n    _In_opt_ PLARGE_INTEGER ByteOffset,\n    _In_opt_ PULONG Key\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtReadFileScatter(\n    _In_ HANDLE FileHandle,\n    _In_opt_ HANDLE Event,\n    _In_opt_ PIO_APC_ROUTINE ApcRoutine,\n    _In_opt_ PVOID ApcContext,\n    _Out_ PIO_STATUS_BLOCK IoStatusBlock,\n    _In_ PFILE_SEGMENT_ELEMENT SegmentArray,\n    _In_ ULONG Length,\n    _In_opt_ PLARGE_INTEGER ByteOffset,\n    _In_opt_ PULONG Key\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtWriteFileGather(\n    _In_ HANDLE FileHandle,\n    _In_opt_ HANDLE Event,\n    _In_opt_ PIO_APC_ROUTINE ApcRoutine,\n    _In_opt_ PVOID ApcContext,\n    _Out_ PIO_STATUS_BLOCK IoStatusBlock,\n    _In_ PFILE_SEGMENT_ELEMENT SegmentArray,\n    _In_ ULONG Length,\n    _In_opt_ PLARGE_INTEGER ByteOffset,\n    _In_opt_ PULONG Key\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtLockFile(\n    _In_ HANDLE FileHandle,\n    _In_opt_ HANDLE Event,\n    _In_opt_ PIO_APC_ROUTINE ApcRoutine,\n    _In_opt_ PVOID ApcContext,\n    _Out_ PIO_STATUS_BLOCK IoStatusBlock,\n    _In_ PLARGE_INTEGER ByteOffset,\n    _In_ PLARGE_INTEGER Length,\n    _In_ ULONG Key,\n    _In_ BOOLEAN FailImmediately,\n    _In_ BOOLEAN ExclusiveLock\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtUnlockFile(\n    _In_ HANDLE FileHandle,\n    _Out_ PIO_STATUS_BLOCK IoStatusBlock,\n    _In_ PLARGE_INTEGER ByteOffset,\n    _In_ PLARGE_INTEGER Length,\n    _In_ ULONG Key\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtQueryAttributesFile(\n    _In_ POBJECT_ATTRIBUTES ObjectAttributes,\n    _Out_ PFILE_BASIC_INFORMATION FileInformation\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtQueryFullAttributesFile(\n    _In_ POBJECT_ATTRIBUTES ObjectAttributes,\n    _Out_ PFILE_NETWORK_OPEN_INFORMATION FileInformation\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtNotifyChangeDirectoryFile(\n    _In_ HANDLE FileHandle,\n    _In_opt_ HANDLE Event,\n    _In_opt_ PIO_APC_ROUTINE ApcRoutine,\n    _In_opt_ PVOID ApcContext,\n    _Out_ PIO_STATUS_BLOCK IoStatusBlock,\n    _Out_writes_bytes_(Length) PVOID Buffer, // FILE_NOTIFY_INFORMATION\n    _In_ ULONG Length,\n    _In_ ULONG CompletionFilter,\n    _In_ BOOLEAN WatchTree\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtLoadDriver(\n    _In_ PUNICODE_STRING DriverServiceName\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtUnloadDriver(\n    _In_ PUNICODE_STRING DriverServiceName\n    );\n\n// I/O completion port\n\n#ifndef IO_COMPLETION_QUERY_STATE\n#define IO_COMPLETION_QUERY_STATE 0x0001\n#endif\n\ntypedef enum _IO_COMPLETION_INFORMATION_CLASS\n{\n    IoCompletionBasicInformation\n} IO_COMPLETION_INFORMATION_CLASS;\n\ntypedef struct _IO_COMPLETION_BASIC_INFORMATION\n{\n    LONG Depth;\n} IO_COMPLETION_BASIC_INFORMATION, *PIO_COMPLETION_BASIC_INFORMATION;\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtCreateIoCompletion(\n    _Out_ PHANDLE IoCompletionHandle,\n    _In_ ACCESS_MASK DesiredAccess,\n    _In_opt_ POBJECT_ATTRIBUTES ObjectAttributes,\n    _In_opt_ ULONG Count\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtOpenIoCompletion(\n    _Out_ PHANDLE IoCompletionHandle,\n    _In_ ACCESS_MASK DesiredAccess,\n    _In_ POBJECT_ATTRIBUTES ObjectAttributes\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtQueryIoCompletion(\n    _In_ HANDLE IoCompletionHandle,\n    _In_ IO_COMPLETION_INFORMATION_CLASS IoCompletionInformationClass,\n    _Out_writes_bytes_(IoCompletionInformation) PVOID IoCompletionInformation,\n    _In_ ULONG IoCompletionInformationLength,\n    _Out_opt_ PULONG ReturnLength\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtSetIoCompletion(\n    _In_ HANDLE IoCompletionHandle,\n    _In_opt_ PVOID KeyContext,\n    _In_opt_ PVOID ApcContext,\n    _In_ NTSTATUS IoStatus,\n    _In_ ULONG_PTR IoStatusInformation\n    );\n\n#if (PHNT_VERSION >= PHNT_WIN7)\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtSetIoCompletionEx(\n    _In_ HANDLE IoCompletionHandle,\n    _In_ HANDLE IoCompletionPacketHandle,\n    _In_opt_ PVOID KeyContext,\n    _In_opt_ PVOID ApcContext,\n    _In_ NTSTATUS IoStatus,\n    _In_ ULONG_PTR IoStatusInformation\n    );\n#endif\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtRemoveIoCompletion(\n    _In_ HANDLE IoCompletionHandle,\n    _Out_ PVOID *KeyContext,\n    _Out_ PVOID *ApcContext,\n    _Out_ PIO_STATUS_BLOCK IoStatusBlock,\n    _In_opt_ PLARGE_INTEGER Timeout\n    );\n\n#if (PHNT_VERSION >= PHNT_VISTA)\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtRemoveIoCompletionEx(\n    _In_ HANDLE IoCompletionHandle,\n    _Out_writes_to_(Count, *NumEntriesRemoved) PFILE_IO_COMPLETION_INFORMATION IoCompletionInformation,\n    _In_ ULONG Count,\n    _Out_ PULONG NumEntriesRemoved,\n    _In_opt_ PLARGE_INTEGER Timeout,\n    _In_ BOOLEAN Alertable\n    );\n#endif\n\n// Wait completion packet\n\n#if (PHNT_VERSION >= PHNT_WIN8)\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtCreateWaitCompletionPacket(\n    _Out_ PHANDLE WaitCompletionPacketHandle,\n    _In_ ACCESS_MASK DesiredAccess,\n    _In_opt_ POBJECT_ATTRIBUTES ObjectAttributes\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtAssociateWaitCompletionPacket(\n    _In_ HANDLE WaitCompletionPacketHandle,\n    _In_ HANDLE IoCompletionHandle,\n    _In_ HANDLE TargetObjectHandle,\n    _In_opt_ PVOID KeyContext,\n    _In_opt_ PVOID ApcContext,\n    _In_ NTSTATUS IoStatus,\n    _In_ ULONG_PTR IoStatusInformation,\n    _Out_opt_ PBOOLEAN AlreadySignaled\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtCancelWaitCompletionPacket(\n    _In_ HANDLE WaitCompletionPacketHandle,\n    _In_ BOOLEAN RemoveSignaledPacket\n    );\n\n#endif\n\n// Sessions\n\ntypedef enum _IO_SESSION_EVENT\n{\n    IoSessionEventIgnore,\n    IoSessionEventCreated,\n    IoSessionEventTerminated,\n    IoSessionEventConnected,\n    IoSessionEventDisconnected,\n    IoSessionEventLogon,\n    IoSessionEventLogoff,\n    IoSessionEventMax\n} IO_SESSION_EVENT;\n\ntypedef enum _IO_SESSION_STATE\n{\n    IoSessionStateCreated,\n    IoSessionStateInitialized,\n    IoSessionStateConnected,\n    IoSessionStateDisconnected,\n    IoSessionStateDisconnectedLoggedOn,\n    IoSessionStateLoggedOn,\n    IoSessionStateLoggedOff,\n    IoSessionStateTerminated,\n    IoSessionStateMax\n} IO_SESSION_STATE;\n\n#if (PHNT_VERSION >= PHNT_WIN7)\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtNotifyChangeSession(\n    _In_ HANDLE SessionHandle,\n    _In_ ULONG ChangeSequenceNumber,\n    _In_ PLARGE_INTEGER ChangeTimeStamp,\n    _In_ IO_SESSION_EVENT Event,\n    _In_ IO_SESSION_STATE NewState,\n    _In_ IO_SESSION_STATE PreviousState,\n    _In_reads_bytes_opt_(PayloadSize) PVOID Payload,\n    _In_ ULONG PayloadSize\n    );\n#endif\n\n// Other types\n\ntypedef enum _INTERFACE_TYPE\n{\n    InterfaceTypeUndefined = -1,\n    Internal,\n    Isa,\n    Eisa,\n    MicroChannel,\n    TurboChannel,\n    PCIBus,\n    VMEBus,\n    NuBus,\n    PCMCIABus,\n    CBus,\n    MPIBus,\n    MPSABus,\n    ProcessorInternal,\n    InternalPowerBus,\n    PNPISABus,\n    PNPBus,\n    Vmcs,\n    MaximumInterfaceType\n} INTERFACE_TYPE, *PINTERFACE_TYPE;\n\ntypedef enum _DMA_WIDTH\n{\n    Width8Bits,\n    Width16Bits,\n    Width32Bits,\n    MaximumDmaWidth\n} DMA_WIDTH, *PDMA_WIDTH;\n\ntypedef enum _DMA_SPEED\n{\n    Compatible,\n    TypeA,\n    TypeB,\n    TypeC,\n    TypeF,\n    MaximumDmaSpeed\n} DMA_SPEED, *PDMA_SPEED;\n\ntypedef enum _BUS_DATA_TYPE\n{\n    ConfigurationSpaceUndefined = -1,\n    Cmos,\n    EisaConfiguration,\n    Pos,\n    CbusConfiguration,\n    PCIConfiguration,\n    VMEConfiguration,\n    NuBusConfiguration,\n    PCMCIAConfiguration,\n    MPIConfiguration,\n    MPSAConfiguration,\n    PNPISAConfiguration,\n    SgiInternalConfiguration,\n    MaximumBusDataType\n} BUS_DATA_TYPE, *PBUS_DATA_TYPE;\n\n// Control structures\n\n// Reparse structure for FSCTL_SET_REPARSE_POINT, FSCTL_GET_REPARSE_POINT, FSCTL_DELETE_REPARSE_POINT\n\n#define SYMLINK_FLAG_RELATIVE 1\n\ntypedef struct _REPARSE_DATA_BUFFER\n{\n    ULONG ReparseTag;\n    USHORT ReparseDataLength;\n    USHORT Reserved;\n    union\n    {\n        struct\n        {\n            USHORT SubstituteNameOffset;\n            USHORT SubstituteNameLength;\n            USHORT PrintNameOffset;\n            USHORT PrintNameLength;\n            ULONG Flags;\n            WCHAR PathBuffer[1];\n        } SymbolicLinkReparseBuffer;\n        struct\n        {\n            USHORT SubstituteNameOffset;\n            USHORT SubstituteNameLength;\n            USHORT PrintNameOffset;\n            USHORT PrintNameLength;\n            WCHAR PathBuffer[1];\n        } MountPointReparseBuffer;\n        struct\n        {\n            UCHAR DataBuffer[1];\n        } GenericReparseBuffer;\n    };\n} REPARSE_DATA_BUFFER, *PREPARSE_DATA_BUFFER;\n\n// Named pipe FS control definitions\n\n#define DEVICE_NAMED_PIPE L\"\\\\Device\\\\NamedPipe\\\\\"\n\n#define FSCTL_PIPE_ASSIGN_EVENT             CTL_CODE(FILE_DEVICE_NAMED_PIPE, 0, METHOD_BUFFERED, FILE_ANY_ACCESS)\n#define FSCTL_PIPE_DISCONNECT               CTL_CODE(FILE_DEVICE_NAMED_PIPE, 1, METHOD_BUFFERED, FILE_ANY_ACCESS)\n#define FSCTL_PIPE_LISTEN                   CTL_CODE(FILE_DEVICE_NAMED_PIPE, 2, METHOD_BUFFERED, FILE_ANY_ACCESS)\n#define FSCTL_PIPE_PEEK                     CTL_CODE(FILE_DEVICE_NAMED_PIPE, 3, METHOD_BUFFERED, FILE_READ_DATA)\n#define FSCTL_PIPE_QUERY_EVENT              CTL_CODE(FILE_DEVICE_NAMED_PIPE, 4, METHOD_BUFFERED, FILE_ANY_ACCESS)\n#define FSCTL_PIPE_TRANSCEIVE               CTL_CODE(FILE_DEVICE_NAMED_PIPE, 5, METHOD_NEITHER,  FILE_READ_DATA | FILE_WRITE_DATA)\n#define FSCTL_PIPE_WAIT                     CTL_CODE(FILE_DEVICE_NAMED_PIPE, 6, METHOD_BUFFERED, FILE_ANY_ACCESS)\n#define FSCTL_PIPE_IMPERSONATE              CTL_CODE(FILE_DEVICE_NAMED_PIPE, 7, METHOD_BUFFERED, FILE_ANY_ACCESS)\n#define FSCTL_PIPE_SET_CLIENT_PROCESS       CTL_CODE(FILE_DEVICE_NAMED_PIPE, 8, METHOD_BUFFERED, FILE_ANY_ACCESS)\n#define FSCTL_PIPE_QUERY_CLIENT_PROCESS     CTL_CODE(FILE_DEVICE_NAMED_PIPE, 9, METHOD_BUFFERED, FILE_ANY_ACCESS)\n#define FSCTL_PIPE_GET_PIPE_ATTRIBUTE       CTL_CODE(FILE_DEVICE_NAMED_PIPE, 10, METHOD_BUFFERED, FILE_ANY_ACCESS)\n#define FSCTL_PIPE_SET_PIPE_ATTRIBUTE       CTL_CODE(FILE_DEVICE_NAMED_PIPE, 11, METHOD_BUFFERED, FILE_ANY_ACCESS)\n#define FSCTL_PIPE_GET_CONNECTION_ATTRIBUTE CTL_CODE(FILE_DEVICE_NAMED_PIPE, 12, METHOD_BUFFERED, FILE_ANY_ACCESS)\n#define FSCTL_PIPE_SET_CONNECTION_ATTRIBUTE CTL_CODE(FILE_DEVICE_NAMED_PIPE, 13, METHOD_BUFFERED, FILE_ANY_ACCESS)\n#define FSCTL_PIPE_GET_HANDLE_ATTRIBUTE     CTL_CODE(FILE_DEVICE_NAMED_PIPE, 14, METHOD_BUFFERED, FILE_ANY_ACCESS)\n#define FSCTL_PIPE_SET_HANDLE_ATTRIBUTE     CTL_CODE(FILE_DEVICE_NAMED_PIPE, 15, METHOD_BUFFERED, FILE_ANY_ACCESS)\n#define FSCTL_PIPE_FLUSH                    CTL_CODE(FILE_DEVICE_NAMED_PIPE, 16, METHOD_BUFFERED, FILE_WRITE_DATA)\n\n#define FSCTL_PIPE_INTERNAL_READ            CTL_CODE(FILE_DEVICE_NAMED_PIPE, 2045, METHOD_BUFFERED, FILE_READ_DATA)\n#define FSCTL_PIPE_INTERNAL_WRITE           CTL_CODE(FILE_DEVICE_NAMED_PIPE, 2046, METHOD_BUFFERED, FILE_WRITE_DATA)\n#define FSCTL_PIPE_INTERNAL_TRANSCEIVE      CTL_CODE(FILE_DEVICE_NAMED_PIPE, 2047, METHOD_NEITHER, FILE_READ_DATA | FILE_WRITE_DATA)\n#define FSCTL_PIPE_INTERNAL_READ_OVFLOW     CTL_CODE(FILE_DEVICE_NAMED_PIPE, 2048, METHOD_BUFFERED, FILE_READ_DATA)\n\n// Flags for query event\n\n#define FILE_PIPE_READ_DATA 0x00000000\n#define FILE_PIPE_WRITE_SPACE 0x00000001\n\n// Input for FSCTL_PIPE_ASSIGN_EVENT\ntypedef struct _FILE_PIPE_ASSIGN_EVENT_BUFFER\n{\n    HANDLE EventHandle;\n    ULONG KeyValue;\n} FILE_PIPE_ASSIGN_EVENT_BUFFER, *PFILE_PIPE_ASSIGN_EVENT_BUFFER;\n\n// Output for FILE_PIPE_PEEK_BUFFER\ntypedef struct _FILE_PIPE_PEEK_BUFFER\n{\n    ULONG NamedPipeState;\n    ULONG ReadDataAvailable;\n    ULONG NumberOfMessages;\n    ULONG MessageLength;\n    CHAR Data[1];\n} FILE_PIPE_PEEK_BUFFER, *PFILE_PIPE_PEEK_BUFFER;\n\n// Output for FSCTL_PIPE_QUERY_EVENT\ntypedef struct _FILE_PIPE_EVENT_BUFFER\n{\n    ULONG NamedPipeState;\n    ULONG EntryType;\n    ULONG ByteCount;\n    ULONG KeyValue;\n    ULONG NumberRequests;\n} FILE_PIPE_EVENT_BUFFER, *PFILE_PIPE_EVENT_BUFFER;\n\n// Input for FSCTL_PIPE_WAIT\ntypedef struct _FILE_PIPE_WAIT_FOR_BUFFER\n{\n    LARGE_INTEGER Timeout;\n    ULONG NameLength;\n    BOOLEAN TimeoutSpecified;\n    WCHAR Name[1];\n} FILE_PIPE_WAIT_FOR_BUFFER, *PFILE_PIPE_WAIT_FOR_BUFFER;\n\n// Input for FSCTL_PIPE_SET_CLIENT_PROCESS, Output for FSCTL_PIPE_QUERY_CLIENT_PROCESS\ntypedef struct _FILE_PIPE_CLIENT_PROCESS_BUFFER\n{\n#if !defined(BUILD_WOW6432)\n    PVOID ClientSession;\n    PVOID ClientProcess;\n#else\n    ULONGLONG ClientSession;\n    ULONGLONG ClientProcess;\n#endif\n} FILE_PIPE_CLIENT_PROCESS_BUFFER, *PFILE_PIPE_CLIENT_PROCESS_BUFFER;\n\n#define FILE_PIPE_COMPUTER_NAME_LENGTH 15\n\n// Input for FSCTL_PIPE_SET_CLIENT_PROCESS, Output for FSCTL_PIPE_QUERY_CLIENT_PROCESS\ntypedef struct _FILE_PIPE_CLIENT_PROCESS_BUFFER_EX\n{\n#if !defined(BUILD_WOW6432)\n    PVOID ClientSession;\n    PVOID ClientProcess;\n#else\n    ULONGLONG ClientSession;\n    ULONGLONG ClientProcess;\n#endif\n    USHORT ClientComputerNameLength; // in bytes\n    WCHAR ClientComputerBuffer[FILE_PIPE_COMPUTER_NAME_LENGTH + 1]; // null-terminated\n} FILE_PIPE_CLIENT_PROCESS_BUFFER_EX, *PFILE_PIPE_CLIENT_PROCESS_BUFFER_EX;\n\n// Mailslot FS control definitions\n\n#define MAILSLOT_CLASS_FIRSTCLASS 1\n#define MAILSLOT_CLASS_SECONDCLASS 2\n\n#define FSCTL_MAILSLOT_PEEK             CTL_CODE(FILE_DEVICE_MAILSLOT, 0, METHOD_NEITHER, FILE_READ_DATA)\n\n// Output for FSCTL_MAILSLOT_PEEK\ntypedef struct _FILE_MAILSLOT_PEEK_BUFFER\n{\n    ULONG ReadDataAvailable;\n    ULONG NumberOfMessages;\n    ULONG MessageLength;\n} FILE_MAILSLOT_PEEK_BUFFER, *PFILE_MAILSLOT_PEEK_BUFFER;\n\n#endif\n"
  },
  {
    "path": "third_party/phnt/include/ntkeapi.h",
    "content": "#ifndef _NTKEAPI_H\n#define _NTKEAPI_H\n\n#if (PHNT_MODE != PHNT_MODE_KERNEL)\n#define LOW_PRIORITY 0 // Lowest thread priority level\n#define LOW_REALTIME_PRIORITY 16 // Lowest realtime priority level\n#define HIGH_PRIORITY 31 // Highest thread priority level\n#define MAXIMUM_PRIORITY 32 // Number of thread priority levels\n#endif\n\ntypedef enum _KTHREAD_STATE\n{\n    Initialized,\n    Ready,\n    Running,\n    Standby,\n    Terminated,\n    Waiting,\n    Transition,\n    DeferredReady,\n    GateWaitObsolete,\n    WaitingForProcessInSwap,\n    MaximumThreadState\n} KTHREAD_STATE, *PKTHREAD_STATE;\n\n// private\ntypedef enum _KHETERO_CPU_POLICY\n{\n    KHeteroCpuPolicyAll,\n    KHeteroCpuPolicyLarge,\n    KHeteroCpuPolicyLargeOrIdle,\n    KHeteroCpuPolicySmall,\n    KHeteroCpuPolicySmallOrIdle,\n    KHeteroCpuPolicyDynamic,\n    KHeteroCpuPolicyStaticMax,\n    KHeteroCpuPolicyBiasedSmall,\n    KHeteroCpuPolicyBiasedLarge,\n    KHeteroCpuPolicyDefault,\n    KHeteroCpuPolicyMax\n} KHETERO_CPU_POLICY, *PKHETERO_CPU_POLICY;\n\n#if (PHNT_MODE != PHNT_MODE_KERNEL)\n\ntypedef enum _KWAIT_REASON\n{\n    Executive,\n    FreePage,\n    PageIn,\n    PoolAllocation,\n    DelayExecution,\n    Suspended,\n    UserRequest,\n    WrExecutive,\n    WrFreePage,\n    WrPageIn,\n    WrPoolAllocation,\n    WrDelayExecution,\n    WrSuspended,\n    WrUserRequest,\n    WrEventPair,\n    WrQueue,\n    WrLpcReceive,\n    WrLpcReply,\n    WrVirtualMemory,\n    WrPageOut,\n    WrRendezvous,\n    WrKeyedEvent,\n    WrTerminated,\n    WrProcessInSwap,\n    WrCpuRateControl,\n    WrCalloutStack,\n    WrKernel,\n    WrResource,\n    WrPushLock,\n    WrMutex,\n    WrQuantumEnd,\n    WrDispatchInt,\n    WrPreempted,\n    WrYieldExecution,\n    WrFastMutex,\n    WrGuardedMutex,\n    WrRundown,\n    WrAlertByThreadId,\n    WrDeferredPreempt,\n    MaximumWaitReason\n} KWAIT_REASON, *PKWAIT_REASON;\n\ntypedef enum _KPROFILE_SOURCE\n{\n    ProfileTime,\n    ProfileAlignmentFixup,\n    ProfileTotalIssues,\n    ProfilePipelineDry,\n    ProfileLoadInstructions,\n    ProfilePipelineFrozen,\n    ProfileBranchInstructions,\n    ProfileTotalNonissues,\n    ProfileDcacheMisses,\n    ProfileIcacheMisses,\n    ProfileCacheMisses,\n    ProfileBranchMispredictions,\n    ProfileStoreInstructions,\n    ProfileFpInstructions,\n    ProfileIntegerInstructions,\n    Profile2Issue,\n    Profile3Issue,\n    Profile4Issue,\n    ProfileSpecialInstructions,\n    ProfileTotalCycles,\n    ProfileIcacheIssues,\n    ProfileDcacheAccesses,\n    ProfileMemoryBarrierCycles,\n    ProfileLoadLinkedIssues,\n    ProfileMaximum\n} KPROFILE_SOURCE;\n\n#endif\n\n#if (PHNT_MODE != PHNT_MODE_KERNEL)\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtCallbackReturn(\n    _In_reads_bytes_opt_(OutputLength) PVOID OutputBuffer,\n    _In_ ULONG OutputLength,\n    _In_ NTSTATUS Status\n    );\n\n#if (PHNT_VERSION >= PHNT_VISTA)\nNTSYSCALLAPI\nVOID\nNTAPI\nNtFlushProcessWriteBuffers(\n    VOID\n    );\n#endif\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtQueryDebugFilterState(\n    _In_ ULONG ComponentId,\n    _In_ ULONG Level\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtSetDebugFilterState(\n    _In_ ULONG ComponentId,\n    _In_ ULONG Level,\n    _In_ BOOLEAN State\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtYieldExecution(\n    VOID\n    );\n\n#endif\n\n#endif\n"
  },
  {
    "path": "third_party/phnt/include/ntldr.h",
    "content": "#ifndef _NTLDR_H\n#define _NTLDR_H\n\n#if (PHNT_MODE != PHNT_MODE_KERNEL)\n\n// DLLs\n\n// symbols\ntypedef struct _LDR_SERVICE_TAG_RECORD\n{\n    struct _LDR_SERVICE_TAG_RECORD *Next;\n    ULONG ServiceTag;\n} LDR_SERVICE_TAG_RECORD, *PLDR_SERVICE_TAG_RECORD;\n\n// symbols\ntypedef struct _LDRP_CSLIST\n{\n    PSINGLE_LIST_ENTRY Tail;\n} LDRP_CSLIST, *PLDRP_CSLIST;\n\n// symbols\ntypedef enum _LDR_DDAG_STATE\n{\n    LdrModulesMerged = -5,\n    LdrModulesInitError = -4,\n    LdrModulesSnapError = -3,\n    LdrModulesUnloaded = -2,\n    LdrModulesUnloading = -1,\n    LdrModulesPlaceHolder = 0,\n    LdrModulesMapping = 1,\n    LdrModulesMapped = 2,\n    LdrModulesWaitingForDependencies = 3,\n    LdrModulesSnapping = 4,\n    LdrModulesSnapped = 5,\n    LdrModulesCondensed = 6,\n    LdrModulesReadyToInit = 7,\n    LdrModulesInitializing = 8,\n    LdrModulesReadyToRun = 9\n} LDR_DDAG_STATE;\n\n// symbols\ntypedef struct _LDR_DDAG_NODE\n{\n    LIST_ENTRY Modules;\n    PLDR_SERVICE_TAG_RECORD ServiceTagList;\n    ULONG LoadCount;\n    ULONG LoadWhileUnloadingCount;\n    ULONG LowestLink;\n    union\n    {\n        LDRP_CSLIST Dependencies;\n        SINGLE_LIST_ENTRY RemovalLink;\n    };\n    LDRP_CSLIST IncomingDependencies;\n    LDR_DDAG_STATE State;\n    SINGLE_LIST_ENTRY CondenseLink;\n    ULONG PreorderNumber;\n} LDR_DDAG_NODE, *PLDR_DDAG_NODE;\n\n// rev\ntypedef struct _LDR_DEPENDENCY_RECORD\n{\n    SINGLE_LIST_ENTRY DependencyLink;\n    PLDR_DDAG_NODE DependencyNode;\n    SINGLE_LIST_ENTRY IncomingDependencyLink;\n    PLDR_DDAG_NODE IncomingDependencyNode;\n} LDR_DEPENDENCY_RECORD, *PLDR_DEPENDENCY_RECORD;\n\n// symbols\ntypedef enum _LDR_DLL_LOAD_REASON\n{\n    LoadReasonStaticDependency,\n    LoadReasonStaticForwarderDependency,\n    LoadReasonDynamicForwarderDependency,\n    LoadReasonDelayloadDependency,\n    LoadReasonDynamicLoad,\n    LoadReasonAsImageLoad,\n    LoadReasonAsDataLoad,\n    LoadReasonEnclavePrimary, // REDSTONE3\n    LoadReasonEnclaveDependency,\n    LoadReasonUnknown = -1\n} LDR_DLL_LOAD_REASON, *PLDR_DLL_LOAD_REASON;\n\n#define LDRP_PACKAGED_BINARY 0x00000001\n#define LDRP_IMAGE_DLL 0x00000004\n#define LDRP_LOAD_IN_PROGRESS 0x00001000\n#define LDRP_ENTRY_PROCESSED 0x00004000\n#define LDRP_DONT_CALL_FOR_THREADS 0x00040000\n#define LDRP_PROCESS_ATTACH_CALLED 0x00080000\n#define LDRP_PROCESS_ATTACH_FAILED 0x00100000\n#define LDRP_IMAGE_NOT_AT_BASE 0x00200000 // Vista and below\n#define LDRP_COR_IMAGE 0x00400000\n#define LDRP_DONT_RELOCATE 0x00800000\n#define LDRP_REDIRECTED 0x10000000\n#define LDRP_COMPAT_DATABASE_PROCESSED 0x80000000\n\n// Use the size of the structure as it was in Windows XP.\n#define LDR_DATA_TABLE_ENTRY_SIZE_WINXP FIELD_OFFSET(LDR_DATA_TABLE_ENTRY, DdagNode)\n#define LDR_DATA_TABLE_ENTRY_SIZE_WIN7 FIELD_OFFSET(LDR_DATA_TABLE_ENTRY, BaseNameHashValue)\n#define LDR_DATA_TABLE_ENTRY_SIZE_WIN8 FIELD_OFFSET(LDR_DATA_TABLE_ENTRY, ImplicitPathOptions)\n\n// symbols\ntypedef struct _LDR_DATA_TABLE_ENTRY\n{\n    LIST_ENTRY InLoadOrderLinks;\n    LIST_ENTRY InMemoryOrderLinks;\n    union\n    {\n        LIST_ENTRY InInitializationOrderLinks;\n        LIST_ENTRY InProgressLinks;\n    };\n    PVOID DllBase;\n    PVOID EntryPoint;\n    ULONG SizeOfImage;\n    UNICODE_STRING FullDllName;\n    UNICODE_STRING BaseDllName;\n    union\n    {\n        UCHAR FlagGroup[4];\n        ULONG Flags;\n        struct\n        {\n            ULONG PackagedBinary : 1;\n            ULONG MarkedForRemoval : 1;\n            ULONG ImageDll : 1;\n            ULONG LoadNotificationsSent : 1;\n            ULONG TelemetryEntryProcessed : 1;\n            ULONG ProcessStaticImport : 1;\n            ULONG InLegacyLists : 1;\n            ULONG InIndexes : 1;\n            ULONG ShimDll : 1;\n            ULONG InExceptionTable : 1;\n            ULONG ReservedFlags1 : 2;\n            ULONG LoadInProgress : 1;\n            ULONG LoadConfigProcessed : 1;\n            ULONG EntryProcessed : 1;\n            ULONG ProtectDelayLoad : 1;\n            ULONG ReservedFlags3 : 2;\n            ULONG DontCallForThreads : 1;\n            ULONG ProcessAttachCalled : 1;\n            ULONG ProcessAttachFailed : 1;\n            ULONG CorDeferredValidate : 1;\n            ULONG CorImage : 1;\n            ULONG DontRelocate : 1;\n            ULONG CorILOnly : 1;\n            ULONG ReservedFlags5 : 3;\n            ULONG Redirected : 1;\n            ULONG ReservedFlags6 : 2;\n            ULONG CompatDatabaseProcessed : 1;\n        };\n    };\n    USHORT ObsoleteLoadCount;\n    USHORT TlsIndex;\n    LIST_ENTRY HashLinks;\n    ULONG TimeDateStamp;\n    struct _ACTIVATION_CONTEXT *EntryPointActivationContext;\n    PVOID Lock;\n    PLDR_DDAG_NODE DdagNode;\n    LIST_ENTRY NodeModuleLink;\n    struct _LDRP_LOAD_CONTEXT *LoadContext;\n    PVOID ParentDllBase;\n    PVOID SwitchBackContext;\n    RTL_BALANCED_NODE BaseAddressIndexNode;\n    RTL_BALANCED_NODE MappingInfoIndexNode;\n    ULONG_PTR OriginalBase;\n    LARGE_INTEGER LoadTime;\n    ULONG BaseNameHashValue;\n    LDR_DLL_LOAD_REASON LoadReason;\n    ULONG ImplicitPathOptions;\n    ULONG ReferenceCount;\n    ULONG DependentLoadFlags;\n    UCHAR SigningLevel; // since REDSTONE2\n} LDR_DATA_TABLE_ENTRY, *PLDR_DATA_TABLE_ENTRY;\n\ntypedef BOOLEAN (NTAPI *PDLL_INIT_ROUTINE)(\n    _In_ PVOID DllHandle,\n    _In_ ULONG Reason,\n    _In_opt_ PCONTEXT Context\n    );\n\nNTSYSAPI\nNTSTATUS\nNTAPI\nLdrLoadDll(\n    _In_opt_ PWSTR DllPath,\n    _In_opt_ PULONG DllCharacteristics,\n    _In_ PUNICODE_STRING DllName,\n    _Out_ PVOID *DllHandle\n    );\n\nNTSYSAPI\nNTSTATUS\nNTAPI\nLdrUnloadDll(\n    _In_ PVOID DllHandle\n    );\n\nNTSYSAPI\nNTSTATUS\nNTAPI\nLdrGetDllHandle(\n    _In_opt_ PWSTR DllPath,\n    _In_opt_ PULONG DllCharacteristics,\n    _In_ PUNICODE_STRING DllName,\n    _Out_ PVOID *DllHandle\n    );\n\n#define LDR_GET_DLL_HANDLE_EX_UNCHANGED_REFCOUNT 0x00000001\n#define LDR_GET_DLL_HANDLE_EX_PIN 0x00000002\n\nNTSYSAPI\nNTSTATUS\nNTAPI\nLdrGetDllHandleEx(\n    _In_ ULONG Flags,\n    _In_opt_ PCWSTR DllPath,\n    _In_opt_ PULONG DllCharacteristics,\n    _In_ PUNICODE_STRING DllName,\n    _Out_opt_ PVOID *DllHandle\n    );\n\n#if (PHNT_VERSION >= PHNT_WIN7)\n// rev\nNTSYSAPI\nNTSTATUS\nNTAPI\nLdrGetDllHandleByMapping(\n    _In_ PVOID Base,\n    _Out_ PVOID *DllHandle\n    );\n#endif\n\n#if (PHNT_VERSION >= PHNT_WIN7)\n// rev\nNTSYSAPI\nNTSTATUS\nNTAPI\nLdrGetDllHandleByName(\n    _In_opt_ PUNICODE_STRING BaseDllName,\n    _In_opt_ PUNICODE_STRING FullDllName,\n    _Out_ PVOID *DllHandle\n    );\n#endif\n\n#define LDR_ADDREF_DLL_PIN 0x00000001\n\nNTSYSAPI\nNTSTATUS\nNTAPI\nLdrAddRefDll(\n    _In_ ULONG Flags,\n    _In_ PVOID DllHandle\n    );\n\nNTSYSAPI\nNTSTATUS\nNTAPI\nLdrGetProcedureAddress(\n    _In_ PVOID DllHandle,\n    _In_opt_ PANSI_STRING ProcedureName,\n    _In_opt_ ULONG ProcedureNumber,\n    _Out_ PVOID *ProcedureAddress\n    );\n\n// rev\n#define LDR_GET_PROCEDURE_ADDRESS_DONT_RECORD_FORWARDER 0x00000001\n\n#if (PHNT_VERSION >= PHNT_VISTA)\n// private\nNTSYSAPI\nNTSTATUS\nNTAPI\nLdrGetProcedureAddressEx(\n    _In_ PVOID DllHandle,\n    _In_opt_ PANSI_STRING ProcedureName,\n    _In_opt_ ULONG ProcedureNumber,\n    _Out_ PVOID *ProcedureAddress,\n    _In_ ULONG Flags\n    );\n#endif\n\n#define LDR_LOCK_LOADER_LOCK_FLAG_RAISE_ON_ERRORS 0x00000001\n#define LDR_LOCK_LOADER_LOCK_FLAG_TRY_ONLY 0x00000002\n\n#define LDR_LOCK_LOADER_LOCK_DISPOSITION_INVALID 0\n#define LDR_LOCK_LOADER_LOCK_DISPOSITION_LOCK_ACQUIRED 1\n#define LDR_LOCK_LOADER_LOCK_DISPOSITION_LOCK_NOT_ACQUIRED 2\n\nNTSYSAPI\nNTSTATUS\nNTAPI\nLdrLockLoaderLock(\n    _In_ ULONG Flags,\n    _Out_opt_ ULONG *Disposition,\n    _Out_ PVOID *Cookie\n    );\n\n#define LDR_UNLOCK_LOADER_LOCK_FLAG_RAISE_ON_ERRORS 0x00000001\n\nNTSYSAPI\nNTSTATUS\nNTAPI\nLdrUnlockLoaderLock(\n    _In_ ULONG Flags,\n    _Inout_ PVOID Cookie\n    );\n\nNTSYSAPI\nNTSTATUS\nNTAPI\nLdrRelocateImage(\n    _In_ PVOID NewBase,\n    _In_ PSTR LoaderName,\n    _In_ NTSTATUS Success,\n    _In_ NTSTATUS Conflict,\n    _In_ NTSTATUS Invalid\n    );\n\nNTSYSAPI\nNTSTATUS\nNTAPI\nLdrRelocateImageWithBias(\n    _In_ PVOID NewBase,\n    _In_ LONGLONG Bias,\n    _In_ PSTR LoaderName,\n    _In_ NTSTATUS Success,\n    _In_ NTSTATUS Conflict,\n    _In_ NTSTATUS Invalid\n    );\n\nNTSYSAPI\nPIMAGE_BASE_RELOCATION\nNTAPI\nLdrProcessRelocationBlock(\n    _In_ ULONG_PTR VA,\n    _In_ ULONG SizeOfBlock,\n    _In_ PUSHORT NextOffset,\n    _In_ LONG_PTR Diff\n    );\n\nNTSYSAPI\nBOOLEAN\nNTAPI\nLdrVerifyMappedImageMatchesChecksum(\n    _In_ PVOID BaseAddress,\n    _In_ SIZE_T NumberOfBytes,\n    _In_ ULONG FileLength\n    );\n\ntypedef VOID (NTAPI *PLDR_IMPORT_MODULE_CALLBACK)(\n    _In_ PVOID Parameter,\n    _In_ PSTR ModuleName\n    );\n\nNTSYSAPI\nNTSTATUS\nNTAPI\nLdrVerifyImageMatchesChecksum(\n    _In_ HANDLE ImageFileHandle,\n    _In_opt_ PLDR_IMPORT_MODULE_CALLBACK ImportCallbackRoutine,\n    _In_ PVOID ImportCallbackParameter,\n    _Out_opt_ PUSHORT ImageCharacteristics\n    );\n\n// private\ntypedef struct _LDR_IMPORT_CALLBACK_INFO\n{\n    PLDR_IMPORT_MODULE_CALLBACK ImportCallbackRoutine;\n    PVOID ImportCallbackParameter;\n} LDR_IMPORT_CALLBACK_INFO, *PLDR_IMPORT_CALLBACK_INFO;\n\n// private\ntypedef struct _LDR_SECTION_INFO\n{\n    HANDLE SectionHandle;\n    ACCESS_MASK DesiredAccess;\n    POBJECT_ATTRIBUTES ObjA;\n    ULONG SectionPageProtection;\n    ULONG AllocationAttributes;\n} LDR_SECTION_INFO, *PLDR_SECTION_INFO;\n\n// private\ntypedef struct _LDR_VERIFY_IMAGE_INFO\n{\n    ULONG Size;\n    ULONG Flags;\n    LDR_IMPORT_CALLBACK_INFO CallbackInfo;\n    LDR_SECTION_INFO SectionInfo;\n    USHORT ImageCharacteristics;\n} LDR_VERIFY_IMAGE_INFO, *PLDR_VERIFY_IMAGE_INFO;\n\n#if (PHNT_VERSION >= PHNT_VISTA)\n// private\nNTSYSAPI\nNTSTATUS\nNTAPI\nLdrVerifyImageMatchesChecksumEx(\n    _In_ HANDLE ImageFileHandle,\n    _Inout_ PLDR_VERIFY_IMAGE_INFO VerifyInfo\n    );\n#endif\n\n#if (PHNT_VERSION >= PHNT_VISTA)\n// private\nNTSYSAPI\nNTSTATUS\nNTAPI\nLdrQueryModuleServiceTags(\n    _In_ PVOID DllHandle,\n    _Out_writes_(*BufferSize) PULONG ServiceTagBuffer,\n    _Inout_ PULONG BufferSize\n    );\n#endif\n\n// begin_msdn:\"DLL Load Notification\"\n\n#define LDR_DLL_NOTIFICATION_REASON_LOADED 1\n#define LDR_DLL_NOTIFICATION_REASON_UNLOADED 2\n\ntypedef struct _LDR_DLL_LOADED_NOTIFICATION_DATA\n{\n    ULONG Flags;\n    PUNICODE_STRING FullDllName;\n    PUNICODE_STRING BaseDllName;\n    PVOID DllBase;\n    ULONG SizeOfImage;\n} LDR_DLL_LOADED_NOTIFICATION_DATA, *PLDR_DLL_LOADED_NOTIFICATION_DATA;\n\ntypedef struct _LDR_DLL_UNLOADED_NOTIFICATION_DATA\n{\n    ULONG Flags;\n    PCUNICODE_STRING FullDllName;\n    PCUNICODE_STRING BaseDllName;\n    PVOID DllBase;\n    ULONG SizeOfImage;\n} LDR_DLL_UNLOADED_NOTIFICATION_DATA, *PLDR_DLL_UNLOADED_NOTIFICATION_DATA;\n\ntypedef union _LDR_DLL_NOTIFICATION_DATA\n{\n    LDR_DLL_LOADED_NOTIFICATION_DATA Loaded;\n    LDR_DLL_UNLOADED_NOTIFICATION_DATA Unloaded;\n} LDR_DLL_NOTIFICATION_DATA, *PLDR_DLL_NOTIFICATION_DATA;\n\ntypedef VOID (NTAPI *PLDR_DLL_NOTIFICATION_FUNCTION)(\n    _In_ ULONG NotificationReason,\n    _In_ PLDR_DLL_NOTIFICATION_DATA NotificationData,\n    _In_opt_ PVOID Context\n    );\n\n#if (PHNT_VERSION >= PHNT_VISTA)\n\nNTSYSAPI\nNTSTATUS\nNTAPI\nLdrRegisterDllNotification(\n    _In_ ULONG Flags,\n    _In_ PLDR_DLL_NOTIFICATION_FUNCTION NotificationFunction,\n    _In_ PVOID Context,\n    _Out_ PVOID *Cookie\n    );\n\nNTSYSAPI\nNTSTATUS\nNTAPI\nLdrUnregisterDllNotification(\n    _In_ PVOID Cookie\n    );\n\n#endif\n\n// end_msdn\n\n// private\ntypedef struct _PS_MITIGATION_OPTIONS_MAP\n{\n    union\n    {\n        ULONG_PTR Map[2]; // REDSTONE2\n        //struct\n        //{\n        //    ULONG_PTR Depth : 16; // REDSTONE3\n        //    ULONG_PTR Sequence : 48;\n        //    ULONG_PTR Reserved : 4;\n        //    ULONG_PTR NextEntry : 60;\n        //};\n    };\n} PS_MITIGATION_OPTIONS_MAP, *PPS_MITIGATION_OPTIONS_MAP;\n\n// private\ntypedef struct _PS_MITIGATION_AUDIT_OPTIONS_MAP\n{\n    ULONG_PTR Map[2];\n} PS_MITIGATION_AUDIT_OPTIONS_MAP, *PPS_MITIGATION_AUDIT_OPTIONS_MAP;\n\n// private\ntypedef struct _PS_SYSTEM_DLL_INIT_BLOCK\n{\n    ULONG Size;\n    ULONG_PTR SystemDllWowRelocation;\n    ULONG_PTR SystemDllNativeRelocation;\n    ULONG_PTR Wow64SharedInformation[16];\n    ULONG RngData;\n    union\n    {\n        ULONG Flags;\n        struct\n        {\n            ULONG CfgOverride : 1;\n            ULONG Reserved : 31;\n        };\n    };\n    PS_MITIGATION_OPTIONS_MAP MitigationOptionsMap;\n    ULONG_PTR CfgBitMap;\n    ULONG_PTR CfgBitMapSize;\n    ULONG_PTR Wow64CfgBitMap;\n    ULONG_PTR Wow64CfgBitMapSize;\n    PS_MITIGATION_AUDIT_OPTIONS_MAP MitigationAuditOptionsMap; // REDSTONE3\n} PS_SYSTEM_DLL_INIT_BLOCK, *PPS_SYSTEM_DLL_INIT_BLOCK;\n\n#if (PHNT_VERSION >= PHNT_THRESHOLD)\n// rev\nNTSYSAPI\nPPS_SYSTEM_DLL_INIT_BLOCK\nNTAPI\nLdrSystemDllInitBlock(\n    VOID\n    );\n#endif\n\n// Load as data table\n\n#if (PHNT_VERSION >= PHNT_VISTA)\n\n// private\nNTSYSAPI\nNTSTATUS\nNTAPI\nLdrAddLoadAsDataTable(\n    _In_ PVOID Module,\n    _In_ PWSTR FilePath,\n    _In_ SIZE_T Size,\n    _In_ HANDLE Handle\n    );\n\n// private\nNTSYSAPI\nNTSTATUS\nNTAPI\nLdrRemoveLoadAsDataTable(\n    _In_ PVOID InitModule,\n    _Out_opt_ PVOID *BaseModule,\n    _Out_opt_ PSIZE_T Size,\n    _In_ ULONG Flags\n    );\n\n// private\nNTSYSAPI\nNTSTATUS\nNTAPI\nLdrGetFileNameFromLoadAsDataTable(\n    _In_ PVOID Module,\n    _Out_ PVOID *pFileNamePrt\n    );\n\n#endif\n\nNTSYSAPI\nNTSTATUS \nNTAPI \nLdrDisableThreadCalloutsForDll(\n    _In_ PVOID DllImageBase\n    );\n    \n// Resources\n\nNTSYSAPI\nNTSTATUS\nNTAPI\nLdrAccessResource(\n    _In_ PVOID BaseAddress,\n    _In_ PIMAGE_RESOURCE_DATA_ENTRY ResourceDataEntry,\n    _Out_opt_ PVOID *ResourceBuffer,\n    _Out_opt_ ULONG *ResourceLength\n    );\n\ntypedef struct _LDR_RESOURCE_INFO\n{\n    ULONG_PTR Type;\n    ULONG_PTR Name;\n    ULONG_PTR Language;\n} LDR_RESOURCE_INFO, *PLDR_RESOURCE_INFO;\n\n#define RESOURCE_TYPE_LEVEL 0\n#define RESOURCE_NAME_LEVEL 1\n#define RESOURCE_LANGUAGE_LEVEL 2\n#define RESOURCE_DATA_LEVEL 3\n\nNTSYSAPI\nNTSTATUS\nNTAPI\nLdrFindResource_U(\n    _In_ PVOID BaseAddress,\n    _In_ PLDR_RESOURCE_INFO ResourceInfo,\n    _In_ ULONG Level,\n    _Out_ PIMAGE_RESOURCE_DATA_ENTRY *ResourceDataEntry\n    );\n\nNTSYSAPI\nNTSTATUS\nNTAPI\nLdrFindResourceDirectory_U(\n    _In_ PVOID BaseAddress,\n    _In_ PLDR_RESOURCE_INFO ResourceInfo,\n    _In_ ULONG Level,\n    _Out_ PIMAGE_RESOURCE_DIRECTORY *ResourceDirectory\n    );\n\n// private \ntypedef struct _LDR_ENUM_RESOURCE_ENTRY\n{\n    union\n    {\n        ULONG_PTR NameOrId;\n        PIMAGE_RESOURCE_DIRECTORY_STRING Name;\n        struct\n        {\n            USHORT Id;\n            USHORT NameIsPresent;\n        };\n    } Path[3];\n    PVOID Data;\n    ULONG Size;\n    ULONG Reserved;\n} LDR_ENUM_RESOURCE_ENTRY, *PLDR_ENUM_RESOURCE_ENTRY;\n\n#define NAME_FROM_RESOURCE_ENTRY(RootDirectory, Entry) \\\n    ((Entry)->NameIsString ? (ULONG_PTR)PTR_ADD_OFFSET((RootDirectory), (Entry)->NameOffset) : (Entry)->Id)\n\nNTSYSAPI\nNTSTATUS\nNTAPI\nLdrEnumResources(\n    _In_ PVOID BaseAddress,\n    _In_ PLDR_RESOURCE_INFO ResourceInfo,\n    _In_ ULONG Level,\n    _Inout_ ULONG *ResourceCount,\n    _Out_writes_to_opt_(*ResourceCount, *ResourceCount) PLDR_ENUM_RESOURCE_ENTRY Resources\n    );\n\nNTSYSAPI\nNTSTATUS\nNTAPI\nLdrFindEntryForAddress(\n    _In_ PVOID BaseAddress,\n    _Out_ PLDR_DATA_TABLE_ENTRY *Entry\n    );\n\n#endif // (PHNT_MODE != PHNT_MODE_KERNEL)\n\n// Module information\n\ntypedef struct _RTL_PROCESS_MODULE_INFORMATION\n{\n    HANDLE Section;\n    PVOID MappedBase;\n    PVOID ImageBase;\n    ULONG ImageSize;\n    ULONG Flags;\n    USHORT LoadOrderIndex;\n    USHORT InitOrderIndex;\n    USHORT LoadCount;\n    USHORT OffsetToFileName;\n    UCHAR FullPathName[256];\n} RTL_PROCESS_MODULE_INFORMATION, *PRTL_PROCESS_MODULE_INFORMATION;\n\ntypedef struct _RTL_PROCESS_MODULES\n{\n    ULONG NumberOfModules;\n    RTL_PROCESS_MODULE_INFORMATION Modules[1];\n} RTL_PROCESS_MODULES, *PRTL_PROCESS_MODULES;\n\n// private\ntypedef struct _RTL_PROCESS_MODULE_INFORMATION_EX\n{\n    USHORT NextOffset;\n    RTL_PROCESS_MODULE_INFORMATION BaseInfo;\n    ULONG ImageChecksum;\n    ULONG TimeDateStamp;\n    PVOID DefaultBase;\n} RTL_PROCESS_MODULE_INFORMATION_EX, *PRTL_PROCESS_MODULE_INFORMATION_EX;\n\n#if (PHNT_MODE != PHNT_MODE_KERNEL)\n\nNTSYSAPI\nNTSTATUS\nNTAPI\nLdrQueryProcessModuleInformation(\n    _In_opt_ PRTL_PROCESS_MODULES ModuleInformation,\n    _In_opt_ ULONG Size,\n    _Out_ PULONG ReturnedSize\n    );\n\ntypedef VOID (NTAPI *PLDR_ENUM_CALLBACK)(\n    _In_ PLDR_DATA_TABLE_ENTRY ModuleInformation, \n    _In_ PVOID Parameter, \n    _Out_ BOOLEAN *Stop\n    );\n\nNTSYSAPI\nNTSTATUS\nNTAPI\nLdrEnumerateLoadedModules(\n    _In_ BOOLEAN ReservedFlag,\n    _In_ PLDR_ENUM_CALLBACK EnumProc,\n    _In_ PVOID Context\n    );\n\nNTSTATUS\nNTAPI\nLdrOpenImageFileOptionsKey(\n    _In_ PUNICODE_STRING SubKey,\n    _In_ BOOLEAN Wow64,\n    _Out_ PHANDLE NewKeyHandle\n    );\n\nNTSTATUS\nNTAPI\nLdrQueryImageFileKeyOption(\n    _In_ HANDLE KeyHandle,\n    _In_ PCWSTR ValueName,\n    _In_ ULONG Type,\n    _Out_ PVOID Buffer,\n    _In_ ULONG BufferSize,\n    _Out_opt_ PULONG ReturnedLength\n    );\n\nNTSTATUS\nNTAPI\nLdrQueryImageFileExecutionOptions(\n    _In_ PUNICODE_STRING SubKey,\n    _In_ PCWSTR ValueName,\n    _In_ ULONG ValueSize,\n    _Out_ PVOID Buffer,\n    _In_ ULONG BufferSize,\n    _Out_opt_ PULONG RetunedLength\n    );\n\n#endif // (PHNT_MODE != PHNT_MODE_KERNEL)\n\n#endif\n"
  },
  {
    "path": "third_party/phnt/include/ntlpcapi.h",
    "content": "#ifndef _NTLPCAPI_H\n#define _NTLPCAPI_H\n\n// Local Inter-process Communication\n\n#define PORT_CONNECT 0x0001\n#define PORT_ALL_ACCESS (STANDARD_RIGHTS_REQUIRED | SYNCHRONIZE | 0x1)\n\ntypedef struct _PORT_MESSAGE\n{\n    union\n    {\n        struct\n        {\n            CSHORT DataLength;\n            CSHORT TotalLength;\n        } s1;\n        ULONG Length;\n    } u1;\n    union\n    {\n        struct\n        {\n            CSHORT Type;\n            CSHORT DataInfoOffset;\n        } s2;\n        ULONG ZeroInit;\n    } u2;\n    union\n    {\n        CLIENT_ID ClientId;\n        double DoNotUseThisField;\n    };\n    ULONG MessageId;\n    union\n    {\n        SIZE_T ClientViewSize; // only valid for LPC_CONNECTION_REQUEST messages\n        ULONG CallbackId; // only valid for LPC_REQUEST messages\n    };\n} PORT_MESSAGE, *PPORT_MESSAGE;\n\ntypedef struct _PORT_DATA_ENTRY\n{\n    PVOID Base;\n    ULONG Size;\n} PORT_DATA_ENTRY, *PPORT_DATA_ENTRY;\n\ntypedef struct _PORT_DATA_INFORMATION\n{\n    ULONG CountDataEntries;\n    PORT_DATA_ENTRY DataEntries[1];\n} PORT_DATA_INFORMATION, *PPORT_DATA_INFORMATION;\n\n#define LPC_REQUEST 1\n#define LPC_REPLY 2\n#define LPC_DATAGRAM 3\n#define LPC_LOST_REPLY 4\n#define LPC_PORT_CLOSED 5\n#define LPC_CLIENT_DIED 6\n#define LPC_EXCEPTION 7\n#define LPC_DEBUG_EVENT 8\n#define LPC_ERROR_EVENT 9\n#define LPC_CONNECTION_REQUEST 10\n\n#define LPC_KERNELMODE_MESSAGE (CSHORT)0x8000\n#define LPC_NO_IMPERSONATE (CSHORT)0x4000\n\n#define PORT_VALID_OBJECT_ATTRIBUTES OBJ_CASE_INSENSITIVE\n\n#ifdef _WIN64\n#define PORT_MAXIMUM_MESSAGE_LENGTH 512\n#else\n#define PORT_MAXIMUM_MESSAGE_LENGTH 256\n#endif\n\n#define LPC_MAX_CONNECTION_INFO_SIZE (16 * sizeof(ULONG_PTR))\n\n#define PORT_TOTAL_MAXIMUM_MESSAGE_LENGTH \\\n    ((PORT_MAXIMUM_MESSAGE_LENGTH + sizeof(PORT_MESSAGE) + LPC_MAX_CONNECTION_INFO_SIZE + 0xf) & ~0xf)\n\ntypedef struct _LPC_CLIENT_DIED_MSG\n{\n    PORT_MESSAGE PortMsg;\n    LARGE_INTEGER CreateTime;\n} LPC_CLIENT_DIED_MSG, *PLPC_CLIENT_DIED_MSG;\n\ntypedef struct _PORT_VIEW\n{\n    ULONG Length;\n    HANDLE SectionHandle;\n    ULONG SectionOffset;\n    SIZE_T ViewSize;\n    PVOID ViewBase;\n    PVOID ViewRemoteBase;\n} PORT_VIEW, *PPORT_VIEW;\n\ntypedef struct _REMOTE_PORT_VIEW\n{\n    ULONG Length;\n    SIZE_T ViewSize;\n    PVOID ViewBase;\n} REMOTE_PORT_VIEW, *PREMOTE_PORT_VIEW;\n\n// WOW64 definitions\n\n// Except in a small number of special cases, WOW64 programs using the LPC APIs must use the 64-bit versions of the\n// PORT_MESSAGE, PORT_VIEW and REMOTE_PORT_VIEW data structures. Note that we take a different approach than the\n// official NT headers, which produce 64-bit versions in a 32-bit environment when USE_LPC6432 is defined.\n\ntypedef struct _PORT_MESSAGE64\n{\n    union\n    {\n        struct\n        {\n            CSHORT DataLength;\n            CSHORT TotalLength;\n        } s1;\n        ULONG Length;\n    } u1;\n    union\n    {\n        struct\n        {\n            CSHORT Type;\n            CSHORT DataInfoOffset;\n        } s2;\n        ULONG ZeroInit;\n    } u2;\n    union\n    {\n        CLIENT_ID64 ClientId;\n        double DoNotUseThisField;\n    };\n    ULONG MessageId;\n    union\n    {\n        ULONGLONG ClientViewSize; // only valid for LPC_CONNECTION_REQUEST messages\n        ULONG CallbackId; // only valid for LPC_REQUEST messages\n    };\n} PORT_MESSAGE64, *PPORT_MESSAGE64;\n\ntypedef struct _LPC_CLIENT_DIED_MSG64\n{\n    PORT_MESSAGE64 PortMsg;\n    LARGE_INTEGER CreateTime;\n} LPC_CLIENT_DIED_MSG64, *PLPC_CLIENT_DIED_MSG64;\n\ntypedef struct _PORT_VIEW64\n{\n    ULONG Length;\n    ULONGLONG SectionHandle;\n    ULONG SectionOffset;\n    ULONGLONG ViewSize;\n    ULONGLONG ViewBase;\n    ULONGLONG ViewRemoteBase;\n} PORT_VIEW64, *PPORT_VIEW64;\n\ntypedef struct _REMOTE_PORT_VIEW64\n{\n    ULONG Length;\n    ULONGLONG ViewSize;\n    ULONGLONG ViewBase;\n} REMOTE_PORT_VIEW64, *PREMOTE_PORT_VIEW64;\n\n// Port creation\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtCreatePort(\n    _Out_ PHANDLE PortHandle,\n    _In_opt_ POBJECT_ATTRIBUTES ObjectAttributes,\n    _In_ ULONG MaxConnectionInfoLength,\n    _In_ ULONG MaxMessageLength,\n    _In_opt_ ULONG MaxPoolUsage\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtCreateWaitablePort(\n    _Out_ PHANDLE PortHandle,\n    _In_opt_ POBJECT_ATTRIBUTES ObjectAttributes,\n    _In_ ULONG MaxConnectionInfoLength,\n    _In_ ULONG MaxMessageLength,\n    _In_opt_ ULONG MaxPoolUsage\n    );\n\n// Port connection (client)\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtConnectPort(\n    _Out_ PHANDLE PortHandle,\n    _In_ PUNICODE_STRING PortName,\n    _In_ PSECURITY_QUALITY_OF_SERVICE SecurityQos,\n    _Inout_opt_ PPORT_VIEW ClientView,\n    _Inout_opt_ PREMOTE_PORT_VIEW ServerView,\n    _Out_opt_ PULONG MaxMessageLength,\n    _Inout_updates_bytes_to_opt_(*ConnectionInformationLength, *ConnectionInformationLength) PVOID ConnectionInformation,\n    _Inout_opt_ PULONG ConnectionInformationLength\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtSecureConnectPort(\n    _Out_ PHANDLE PortHandle,\n    _In_ PUNICODE_STRING PortName,\n    _In_ PSECURITY_QUALITY_OF_SERVICE SecurityQos,\n    _Inout_opt_ PPORT_VIEW ClientView,\n    _In_opt_ PSID RequiredServerSid,\n    _Inout_opt_ PREMOTE_PORT_VIEW ServerView,\n    _Out_opt_ PULONG MaxMessageLength,\n    _Inout_updates_bytes_to_opt_(*ConnectionInformationLength, *ConnectionInformationLength) PVOID ConnectionInformation,\n    _Inout_opt_ PULONG ConnectionInformationLength\n    );\n\n// Port connection (server)\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtListenPort(\n    _In_ HANDLE PortHandle,\n    _Out_ PPORT_MESSAGE ConnectionRequest\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtAcceptConnectPort(\n    _Out_ PHANDLE PortHandle,\n    _In_opt_ PVOID PortContext,\n    _In_ PPORT_MESSAGE ConnectionRequest,\n    _In_ BOOLEAN AcceptConnection,\n    _Inout_opt_ PPORT_VIEW ServerView,\n    _Out_opt_ PREMOTE_PORT_VIEW ClientView\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtCompleteConnectPort(\n    _In_ HANDLE PortHandle\n    );\n\n// General\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtRequestPort(\n    _In_ HANDLE PortHandle,\n    _In_reads_bytes_(RequestMessage->u1.s1.TotalLength) PPORT_MESSAGE RequestMessage\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtRequestWaitReplyPort(\n    _In_ HANDLE PortHandle,\n    _In_reads_bytes_(RequestMessage->u1.s1.TotalLength) PPORT_MESSAGE RequestMessage,\n    _Out_ PPORT_MESSAGE ReplyMessage\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtReplyPort(\n    _In_ HANDLE PortHandle,\n    _In_reads_bytes_(ReplyMessage->u1.s1.TotalLength) PPORT_MESSAGE ReplyMessage\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtReplyWaitReplyPort(\n    _In_ HANDLE PortHandle,\n    _Inout_ PPORT_MESSAGE ReplyMessage\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtReplyWaitReceivePort(\n    _In_ HANDLE PortHandle,\n    _Out_opt_ PVOID *PortContext,\n    _In_reads_bytes_opt_(ReplyMessage->u1.s1.TotalLength) PPORT_MESSAGE ReplyMessage,\n    _Out_ PPORT_MESSAGE ReceiveMessage\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtReplyWaitReceivePortEx(\n    _In_ HANDLE PortHandle,\n    _Out_opt_ PVOID *PortContext,\n    _In_reads_bytes_opt_(ReplyMessage->u1.s1.TotalLength) PPORT_MESSAGE ReplyMessage,\n    _Out_ PPORT_MESSAGE ReceiveMessage,\n    _In_opt_ PLARGE_INTEGER Timeout\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtImpersonateClientOfPort(\n    _In_ HANDLE PortHandle,\n    _In_ PPORT_MESSAGE Message\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtReadRequestData(\n    _In_ HANDLE PortHandle,\n    _In_ PPORT_MESSAGE Message,\n    _In_ ULONG DataEntryIndex,\n    _Out_writes_bytes_to_(BufferSize, *NumberOfBytesRead) PVOID Buffer,\n    _In_ SIZE_T BufferSize,\n    _Out_opt_ PSIZE_T NumberOfBytesRead\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtWriteRequestData(\n    _In_ HANDLE PortHandle,\n    _In_ PPORT_MESSAGE Message,\n    _In_ ULONG DataEntryIndex,\n    _In_reads_bytes_(BufferSize) PVOID Buffer,\n    _In_ SIZE_T BufferSize,\n    _Out_opt_ PSIZE_T NumberOfBytesWritten\n    );\n\ntypedef enum _PORT_INFORMATION_CLASS\n{\n    PortBasicInformation,\n    PortDumpInformation\n} PORT_INFORMATION_CLASS;\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtQueryInformationPort(\n    _In_ HANDLE PortHandle,\n    _In_ PORT_INFORMATION_CLASS PortInformationClass,\n    _Out_writes_bytes_to_(Length, *ReturnLength) PVOID PortInformation,\n    _In_ ULONG Length,\n    _Out_opt_ PULONG ReturnLength\n    );\n\n// Asynchronous Local Inter-process Communication\n\n// rev\ntypedef HANDLE ALPC_HANDLE, *PALPC_HANDLE;\n\n#define ALPC_PORFLG_ALLOW_LPC_REQUESTS 0x20000 // rev\n#define ALPC_PORFLG_WAITABLE_PORT 0x40000 // dbg\n#define ALPC_PORFLG_SYSTEM_PROCESS 0x100000 // dbg\n\n// symbols\ntypedef struct _ALPC_PORT_ATTRIBUTES\n{\n    ULONG Flags;\n    SECURITY_QUALITY_OF_SERVICE SecurityQos;\n    SIZE_T MaxMessageLength;\n    SIZE_T MemoryBandwidth;\n    SIZE_T MaxPoolUsage;\n    SIZE_T MaxSectionSize;\n    SIZE_T MaxViewSize;\n    SIZE_T MaxTotalSectionSize;\n    ULONG DupObjectTypes;\n#ifdef _WIN64\n    ULONG Reserved;\n#endif\n} ALPC_PORT_ATTRIBUTES, *PALPC_PORT_ATTRIBUTES;\n\n// begin_rev\n#define ALPC_MESSAGE_SECURITY_ATTRIBUTE 0x80000000\n#define ALPC_MESSAGE_VIEW_ATTRIBUTE 0x40000000\n#define ALPC_MESSAGE_CONTEXT_ATTRIBUTE 0x20000000\n#define ALPC_MESSAGE_HANDLE_ATTRIBUTE 0x10000000\n// end_rev\n\n// symbols\ntypedef struct _ALPC_MESSAGE_ATTRIBUTES\n{\n    ULONG AllocatedAttributes;\n    ULONG ValidAttributes;\n} ALPC_MESSAGE_ATTRIBUTES, *PALPC_MESSAGE_ATTRIBUTES;\n\n// symbols\ntypedef struct _ALPC_COMPLETION_LIST_STATE\n{\n    union\n    {\n        struct\n        {\n            ULONG64 Head : 24;\n            ULONG64 Tail : 24;\n            ULONG64 ActiveThreadCount : 16;\n        } s1;\n        ULONG64 Value;\n    } u1;\n} ALPC_COMPLETION_LIST_STATE, *PALPC_COMPLETION_LIST_STATE;\n\n#define ALPC_COMPLETION_LIST_BUFFER_GRANULARITY_MASK 0x3f // dbg\n\n// symbols\ntypedef struct DECLSPEC_ALIGN(128) _ALPC_COMPLETION_LIST_HEADER\n{\n    ULONG64 StartMagic;\n\n    ULONG TotalSize;\n    ULONG ListOffset;\n    ULONG ListSize;\n    ULONG BitmapOffset;\n    ULONG BitmapSize;\n    ULONG DataOffset;\n    ULONG DataSize;\n    ULONG AttributeFlags;\n    ULONG AttributeSize;\n\n    DECLSPEC_ALIGN(128) ALPC_COMPLETION_LIST_STATE State;\n    ULONG LastMessageId;\n    ULONG LastCallbackId;\n    DECLSPEC_ALIGN(128) ULONG PostCount;\n    DECLSPEC_ALIGN(128) ULONG ReturnCount;\n    DECLSPEC_ALIGN(128) ULONG LogSequenceNumber;\n    DECLSPEC_ALIGN(128) RTL_SRWLOCK UserLock;\n\n    ULONG64 EndMagic;\n} ALPC_COMPLETION_LIST_HEADER, *PALPC_COMPLETION_LIST_HEADER;\n\n// private\ntypedef struct _ALPC_CONTEXT_ATTR\n{\n    PVOID PortContext;\n    PVOID MessageContext;\n    ULONG Sequence;\n    ULONG MessageId;\n    ULONG CallbackId;\n} ALPC_CONTEXT_ATTR, *PALPC_CONTEXT_ATTR;\n\n// begin_rev\n#define ALPC_HANDLEFLG_DUPLICATE_SAME_ACCESS 0x10000\n#define ALPC_HANDLEFLG_DUPLICATE_SAME_ATTRIBUTES 0x20000\n#define ALPC_HANDLEFLG_DUPLICATE_INHERIT 0x80000\n// end_rev\n\n// private\ntypedef struct _ALPC_HANDLE_ATTR32\n{\n    ULONG Flags;\n    ULONG Reserved0;\n    ULONG SameAccess;\n    ULONG SameAttributes;\n    ULONG Indirect;\n    ULONG Inherit;\n    ULONG Reserved1;\n    ULONG Handle;\n    ULONG ObjectType; // ObjectTypeCode, not ObjectTypeIndex\n    ULONG DesiredAccess;\n    ULONG GrantedAccess;\n} ALPC_HANDLE_ATTR32, *PALPC_HANDLE_ATTR32;\n\n// private\ntypedef struct _ALPC_HANDLE_ATTR\n{\n    ULONG Flags;\n    ULONG Reserved0;\n    ULONG SameAccess;\n    ULONG SameAttributes;\n    ULONG Indirect;\n    ULONG Inherit;\n    ULONG Reserved1;\n    HANDLE Handle;\n    PALPC_HANDLE_ATTR32 HandleAttrArray;\n    ULONG ObjectType; // ObjectTypeCode, not ObjectTypeIndex\n    ULONG HandleCount;\n    ACCESS_MASK DesiredAccess;\n    ACCESS_MASK GrantedAccess;\n} ALPC_HANDLE_ATTR, *PALPC_HANDLE_ATTR;\n\n#define ALPC_SECFLG_CREATE_HANDLE 0x20000 // dbg\n\n// private\ntypedef struct _ALPC_SECURITY_ATTR\n{\n    ULONG Flags;\n    PSECURITY_QUALITY_OF_SERVICE QoS;\n    ALPC_HANDLE ContextHandle; // dbg\n} ALPC_SECURITY_ATTR, *PALPC_SECURITY_ATTR;\n\n// begin_rev\n#define ALPC_VIEWFLG_NOT_SECURE 0x40000\n// end_rev\n\n// private\ntypedef struct _ALPC_DATA_VIEW_ATTR\n{\n    ULONG Flags;\n    ALPC_HANDLE SectionHandle;\n    PVOID ViewBase; // must be zero on input\n    SIZE_T ViewSize;\n} ALPC_DATA_VIEW_ATTR, *PALPC_DATA_VIEW_ATTR;\n\n// private\ntypedef enum _ALPC_PORT_INFORMATION_CLASS\n{\n    AlpcBasicInformation, // q: out ALPC_BASIC_INFORMATION\n    AlpcPortInformation, // s: in ALPC_PORT_ATTRIBUTES\n    AlpcAssociateCompletionPortInformation, // s: in ALPC_PORT_ASSOCIATE_COMPLETION_PORT\n    AlpcConnectedSIDInformation, // q: in SID\n    AlpcServerInformation, // q: inout ALPC_SERVER_INFORMATION\n    AlpcMessageZoneInformation, // s: in ALPC_PORT_MESSAGE_ZONE_INFORMATION\n    AlpcRegisterCompletionListInformation, // s: in ALPC_PORT_COMPLETION_LIST_INFORMATION\n    AlpcUnregisterCompletionListInformation, // s: VOID\n    AlpcAdjustCompletionListConcurrencyCountInformation, // s: in ULONG\n    AlpcRegisterCallbackInformation, // kernel-mode only\n    AlpcCompletionListRundownInformation, // s: VOID\n    AlpcWaitForPortReferences\n} ALPC_PORT_INFORMATION_CLASS;\n\n// private\ntypedef struct _ALPC_BASIC_INFORMATION\n{\n    ULONG Flags;\n    ULONG SequenceNo;\n    PVOID PortContext;\n} ALPC_BASIC_INFORMATION, *PALPC_BASIC_INFORMATION;\n\n// private\ntypedef struct _ALPC_PORT_ASSOCIATE_COMPLETION_PORT\n{\n    PVOID CompletionKey;\n    HANDLE CompletionPort;\n} ALPC_PORT_ASSOCIATE_COMPLETION_PORT, *PALPC_PORT_ASSOCIATE_COMPLETION_PORT;\n\n// private\ntypedef struct _ALPC_SERVER_INFORMATION\n{\n    union\n    {\n        struct\n        {\n            HANDLE ThreadHandle;\n        } In;\n        struct\n        {\n            BOOLEAN ThreadBlocked;\n            HANDLE ConnectedProcessId;\n            UNICODE_STRING ConnectionPortName;\n        } Out;\n    };\n} ALPC_SERVER_INFORMATION, *PALPC_SERVER_INFORMATION;\n\n// private\ntypedef struct _ALPC_PORT_MESSAGE_ZONE_INFORMATION\n{\n    PVOID Buffer;\n    ULONG Size;\n} ALPC_PORT_MESSAGE_ZONE_INFORMATION, *PALPC_PORT_MESSAGE_ZONE_INFORMATION;\n\n// private\ntypedef struct _ALPC_PORT_COMPLETION_LIST_INFORMATION\n{\n    PVOID Buffer; // PALPC_COMPLETION_LIST_HEADER\n    ULONG Size;\n    ULONG ConcurrencyCount;\n    ULONG AttributeFlags;\n} ALPC_PORT_COMPLETION_LIST_INFORMATION, *PALPC_PORT_COMPLETION_LIST_INFORMATION;\n\n// private\ntypedef enum _ALPC_MESSAGE_INFORMATION_CLASS\n{\n    AlpcMessageSidInformation, // q: out SID\n    AlpcMessageTokenModifiedIdInformation,  // q: out LUID\n    AlpcMessageDirectStatusInformation,\n    AlpcMessageHandleInformation, // ALPC_MESSAGE_HANDLE_INFORMATION\n    MaxAlpcMessageInfoClass\n} ALPC_MESSAGE_INFORMATION_CLASS, *PALPC_MESSAGE_INFORMATION_CLASS;\n\ntypedef struct _ALPC_MESSAGE_HANDLE_INFORMATION\n{\n    ULONG Index;\n    ULONG Flags;\n    ULONG Handle;\n    ULONG ObjectType;\n    ACCESS_MASK GrantedAccess;\n} ALPC_MESSAGE_HANDLE_INFORMATION, *PALPC_MESSAGE_HANDLE_INFORMATION;\n\n// begin_private\n\n#if (PHNT_VERSION >= PHNT_VISTA)\n\n// System calls\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtAlpcCreatePort(\n    _Out_ PHANDLE PortHandle,\n    _In_opt_ POBJECT_ATTRIBUTES ObjectAttributes,\n    _In_opt_ PALPC_PORT_ATTRIBUTES PortAttributes\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtAlpcDisconnectPort(\n    _In_ HANDLE PortHandle,\n    _In_ ULONG Flags\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtAlpcQueryInformation(\n    _In_opt_ HANDLE PortHandle,\n    _In_ ALPC_PORT_INFORMATION_CLASS PortInformationClass,\n    _Inout_updates_bytes_to_(Length, *ReturnLength) PVOID PortInformation,\n    _In_ ULONG Length,\n    _Out_opt_ PULONG ReturnLength\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtAlpcSetInformation(\n    _In_ HANDLE PortHandle,\n    _In_ ALPC_PORT_INFORMATION_CLASS PortInformationClass,\n    _In_reads_bytes_opt_(Length) PVOID PortInformation,\n    _In_ ULONG Length\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtAlpcCreatePortSection(\n    _In_ HANDLE PortHandle,\n    _In_ ULONG Flags,\n    _In_opt_ HANDLE SectionHandle,\n    _In_ SIZE_T SectionSize,\n    _Out_ PALPC_HANDLE AlpcSectionHandle,\n    _Out_ PSIZE_T ActualSectionSize\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtAlpcDeletePortSection(\n    _In_ HANDLE PortHandle,\n    _Reserved_ ULONG Flags,\n    _In_ ALPC_HANDLE SectionHandle\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtAlpcCreateResourceReserve(\n    _In_ HANDLE PortHandle,\n    _Reserved_ ULONG Flags,\n    _In_ SIZE_T MessageSize,\n    _Out_ PALPC_HANDLE ResourceId\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtAlpcDeleteResourceReserve(\n    _In_ HANDLE PortHandle,\n    _Reserved_ ULONG Flags,\n    _In_ ALPC_HANDLE ResourceId\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtAlpcCreateSectionView(\n    _In_ HANDLE PortHandle,\n    _Reserved_ ULONG Flags,\n    _Inout_ PALPC_DATA_VIEW_ATTR ViewAttributes\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtAlpcDeleteSectionView(\n    _In_ HANDLE PortHandle,\n    _Reserved_ ULONG Flags,\n    _In_ PVOID ViewBase\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtAlpcCreateSecurityContext(\n    _In_ HANDLE PortHandle,\n    _Reserved_ ULONG Flags,\n    _Inout_ PALPC_SECURITY_ATTR SecurityAttribute\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtAlpcDeleteSecurityContext(\n    _In_ HANDLE PortHandle,\n    _Reserved_ ULONG Flags,\n    _In_ ALPC_HANDLE ContextHandle\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtAlpcRevokeSecurityContext(\n    _In_ HANDLE PortHandle,\n    _Reserved_ ULONG Flags,\n    _In_ ALPC_HANDLE ContextHandle\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtAlpcQueryInformationMessage(\n    _In_ HANDLE PortHandle,\n    _In_ PPORT_MESSAGE PortMessage,\n    _In_ ALPC_MESSAGE_INFORMATION_CLASS MessageInformationClass,\n    _Out_writes_bytes_to_opt_(Length, *ReturnLength) PVOID MessageInformation,\n    _In_ ULONG Length,\n    _Out_opt_ PULONG ReturnLength\n    );\n\n#define ALPC_MSGFLG_REPLY_MESSAGE 0x1\n#define ALPC_MSGFLG_LPC_MODE 0x2 // ?\n#define ALPC_MSGFLG_RELEASE_MESSAGE 0x10000 // dbg\n#define ALPC_MSGFLG_SYNC_REQUEST 0x20000 // dbg\n#define ALPC_MSGFLG_WAIT_USER_MODE 0x100000\n#define ALPC_MSGFLG_WAIT_ALERTABLE 0x200000\n#define ALPC_MSGFLG_WOW64_CALL 0x80000000 // dbg\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtAlpcConnectPort(\n    _Out_ PHANDLE PortHandle,\n    _In_ PUNICODE_STRING PortName,\n    _In_opt_ POBJECT_ATTRIBUTES ObjectAttributes,\n    _In_opt_ PALPC_PORT_ATTRIBUTES PortAttributes,\n    _In_ ULONG Flags,\n    _In_opt_ PSID RequiredServerSid,\n    _Inout_updates_bytes_to_opt_(*BufferLength, *BufferLength) PPORT_MESSAGE ConnectionMessage,\n    _Inout_opt_ PULONG BufferLength,\n    _Inout_opt_ PALPC_MESSAGE_ATTRIBUTES OutMessageAttributes,\n    _Inout_opt_ PALPC_MESSAGE_ATTRIBUTES InMessageAttributes,\n    _In_opt_ PLARGE_INTEGER Timeout\n    );\n\n#if (PHNT_VERSION >= PHNT_WIN8)\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtAlpcConnectPortEx(\n    _Out_ PHANDLE PortHandle,\n    _In_ POBJECT_ATTRIBUTES ConnectionPortObjectAttributes,\n    _In_opt_ POBJECT_ATTRIBUTES ClientPortObjectAttributes,\n    _In_opt_ PALPC_PORT_ATTRIBUTES PortAttributes,\n    _In_ ULONG Flags,\n    _In_opt_ PSECURITY_DESCRIPTOR ServerSecurityRequirements,\n    _Inout_updates_bytes_to_opt_(*BufferLength, *BufferLength) PPORT_MESSAGE ConnectionMessage,\n    _Inout_opt_ PSIZE_T BufferLength,\n    _Inout_opt_ PALPC_MESSAGE_ATTRIBUTES OutMessageAttributes,\n    _Inout_opt_ PALPC_MESSAGE_ATTRIBUTES InMessageAttributes,\n    _In_opt_ PLARGE_INTEGER Timeout\n    );\n#endif\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtAlpcAcceptConnectPort(\n    _Out_ PHANDLE PortHandle,\n    _In_ HANDLE ConnectionPortHandle,\n    _In_ ULONG Flags,\n    _In_opt_ POBJECT_ATTRIBUTES ObjectAttributes,\n    _In_opt_ PALPC_PORT_ATTRIBUTES PortAttributes,\n    _In_opt_ PVOID PortContext,\n    _In_reads_bytes_(ConnectionRequest->u1.s1.TotalLength) PPORT_MESSAGE ConnectionRequest,\n    _Inout_opt_ PALPC_MESSAGE_ATTRIBUTES ConnectionMessageAttributes,\n    _In_ BOOLEAN AcceptConnection\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtAlpcSendWaitReceivePort(\n    _In_ HANDLE PortHandle,\n    _In_ ULONG Flags,\n    _In_reads_bytes_opt_(SendMessage->u1.s1.TotalLength) PPORT_MESSAGE SendMessage,\n    _Inout_opt_ PALPC_MESSAGE_ATTRIBUTES SendMessageAttributes,\n    _Out_writes_bytes_to_opt_(*BufferLength, *BufferLength) PPORT_MESSAGE ReceiveMessage,\n    _Inout_opt_ PSIZE_T BufferLength,\n    _Inout_opt_ PALPC_MESSAGE_ATTRIBUTES ReceiveMessageAttributes,\n    _In_opt_ PLARGE_INTEGER Timeout\n    );\n\n#define ALPC_CANCELFLG_TRY_CANCEL 0x1 // dbg\n#define ALPC_CANCELFLG_NO_CONTEXT_CHECK 0x8\n#define ALPC_CANCELFLGP_FLUSH 0x10000 // dbg\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtAlpcCancelMessage(\n    _In_ HANDLE PortHandle,\n    _In_ ULONG Flags,\n    _In_ PALPC_CONTEXT_ATTR MessageContext\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtAlpcImpersonateClientOfPort(\n    _In_ HANDLE PortHandle,\n    _In_ PPORT_MESSAGE Message,\n    _In_ PVOID Flags\n    );\n\n#if (PHNT_VERSION >= PHNT_THRESHOLD)\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtAlpcImpersonateClientContainerOfPort(\n    _In_ HANDLE PortHandle,\n    _In_ PPORT_MESSAGE Message,\n    _In_ ULONG Flags\n    );\n#endif\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtAlpcOpenSenderProcess(\n    _Out_ PHANDLE ProcessHandle,\n    _In_ HANDLE PortHandle,\n    _In_ PPORT_MESSAGE PortMessage,\n    _In_ ULONG Flags,\n    _In_ ACCESS_MASK DesiredAccess,\n    _In_ POBJECT_ATTRIBUTES ObjectAttributes\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtAlpcOpenSenderThread(\n    _Out_ PHANDLE ThreadHandle,\n    _In_ HANDLE PortHandle,\n    _In_ PPORT_MESSAGE PortMessage,\n    _In_ ULONG Flags,\n    _In_ ACCESS_MASK DesiredAccess,\n    _In_ POBJECT_ATTRIBUTES ObjectAttributes\n    );\n\n// Support functions\n\nNTSYSAPI\nULONG\nNTAPI\nAlpcMaxAllowedMessageLength(\n    VOID\n    );\n\nNTSYSAPI\nULONG\nNTAPI\nAlpcGetHeaderSize(\n    _In_ ULONG Flags\n    );\n\nNTSYSAPI\nNTSTATUS\nNTAPI\nAlpcInitializeMessageAttribute(\n    _In_ ULONG AttributeFlags,\n    _Out_opt_ PALPC_MESSAGE_ATTRIBUTES Buffer,\n    _In_ ULONG BufferSize,\n    _Out_ PULONG RequiredBufferSize\n    );\n\nNTSYSAPI\nPVOID\nNTAPI\nAlpcGetMessageAttribute(\n    _In_ PALPC_MESSAGE_ATTRIBUTES Buffer,\n    _In_ ULONG AttributeFlag\n    );\n\nNTSYSAPI\nNTSTATUS\nNTAPI\nAlpcRegisterCompletionList(\n    _In_ HANDLE PortHandle,\n    _Out_ PALPC_COMPLETION_LIST_HEADER Buffer,\n    _In_ ULONG Size,\n    _In_ ULONG ConcurrencyCount,\n    _In_ ULONG AttributeFlags\n    );\n\nNTSYSAPI\nNTSTATUS\nNTAPI\nAlpcUnregisterCompletionList(\n    _In_ HANDLE PortHandle\n    );\n\n#if (PHNT_VERSION >= PHNT_WIN7)\n// rev\nNTSYSAPI\nNTSTATUS\nNTAPI\nAlpcRundownCompletionList(\n    _In_ HANDLE PortHandle\n    );\n#endif\n\nNTSYSAPI\nNTSTATUS\nNTAPI\nAlpcAdjustCompletionListConcurrencyCount(\n    _In_ HANDLE PortHandle,\n    _In_ ULONG ConcurrencyCount\n    );\n\nNTSYSAPI\nBOOLEAN\nNTAPI\nAlpcRegisterCompletionListWorkerThread(\n    _Inout_ PVOID CompletionList\n    );\n\nNTSYSAPI\nBOOLEAN\nNTAPI\nAlpcUnregisterCompletionListWorkerThread(\n    _Inout_ PVOID CompletionList\n    );\n\nNTSYSAPI\nVOID\nNTAPI\nAlpcGetCompletionListLastMessageInformation(\n    _In_ PVOID CompletionList,\n    _Out_ PULONG LastMessageId,\n    _Out_ PULONG LastCallbackId\n    );\n\nNTSYSAPI\nULONG\nNTAPI\nAlpcGetOutstandingCompletionListMessageCount(\n    _In_ PVOID CompletionList\n    );\n\nNTSYSAPI\nPPORT_MESSAGE\nNTAPI\nAlpcGetMessageFromCompletionList(\n    _In_ PVOID CompletionList,\n    _Out_opt_ PALPC_MESSAGE_ATTRIBUTES *MessageAttributes\n    );\n\nNTSYSAPI\nVOID\nNTAPI\nAlpcFreeCompletionListMessage(\n    _Inout_ PVOID CompletionList,\n    _In_ PPORT_MESSAGE Message\n    );\n\nNTSYSAPI\nPALPC_MESSAGE_ATTRIBUTES\nNTAPI\nAlpcGetCompletionListMessageAttributes(\n    _In_ PVOID CompletionList,\n    _In_ PPORT_MESSAGE Message\n    );\n\n#endif\n\n// end_private\n\n#endif\n"
  },
  {
    "path": "third_party/phnt/include/ntmisc.h",
    "content": "#ifndef _NTMISC_H\n#define _NTMISC_H\n\n// Boot graphics\n\n#if (PHNT_VERSION >= PHNT_WIN7)\n// rev\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtDrawText(\n    _In_ PUNICODE_STRING Text\n    );\n#endif\n\n// Filter manager\n\n#define FLT_PORT_CONNECT 0x0001\n#define FLT_PORT_ALL_ACCESS (FLT_PORT_CONNECT | STANDARD_RIGHTS_ALL)\n\n// VDM\n\ntypedef enum _VDMSERVICECLASS\n{\n    VdmStartExecution,\n    VdmQueueInterrupt,\n    VdmDelayInterrupt,\n    VdmInitialize,\n    VdmFeatures,\n    VdmSetInt21Handler,\n    VdmQueryDir,\n    VdmPrinterDirectIoOpen,\n    VdmPrinterDirectIoClose,\n    VdmPrinterInitialize,\n    VdmSetLdtEntries,\n    VdmSetProcessLdtInfo,\n    VdmAdlibEmulation,\n    VdmPMCliControl,\n    VdmQueryVdmProcess\n} VDMSERVICECLASS, *PVDMSERVICECLASS;\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtVdmControl(\n    _In_ VDMSERVICECLASS Service,\n    _Inout_ PVOID ServiceData\n    );\n\n// WMI/ETW\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtTraceEvent(\n    _In_ HANDLE TraceHandle,\n    _In_ ULONG Flags,\n    _In_ ULONG FieldSize,\n    _In_ PVOID Fields\n    );\n\n#if (PHNT_VERSION >= PHNT_VISTA)\n// private\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtTraceControl(\n    _In_ ULONG FunctionCode,\n    _In_reads_bytes_opt_(InBufferLen) PVOID InBuffer,\n    _In_ ULONG InBufferLen,\n    _Out_writes_bytes_opt_(OutBufferLen) PVOID OutBuffer,\n    _In_ ULONG OutBufferLen,\n    _Out_ PULONG ReturnLength\n    );\n#endif\n\n#endif\n"
  },
  {
    "path": "third_party/phnt/include/ntmmapi.h",
    "content": "#ifndef _NTMMAPI_H\n#define _NTMMAPI_H\n\n#if (PHNT_MODE == PHNT_MODE_KERNEL)\n\n// Protection constants\n\n#define PAGE_NOACCESS 0x01\n#define PAGE_READONLY 0x02\n#define PAGE_READWRITE 0x04\n#define PAGE_WRITECOPY 0x08\n#define PAGE_EXECUTE 0x10\n#define PAGE_EXECUTE_READ 0x20\n#define PAGE_EXECUTE_READWRITE 0x40\n#define PAGE_EXECUTE_WRITECOPY 0x80\n#define PAGE_GUARD 0x100\n#define PAGE_NOCACHE 0x200\n#define PAGE_WRITECOMBINE 0x400\n\n#define PAGE_REVERT_TO_FILE_MAP     0x80000000\n#define PAGE_ENCLAVE_THREAD_CONTROL 0x80000000\n#define PAGE_TARGETS_NO_UPDATE      0x40000000\n#define PAGE_TARGETS_INVALID        0x40000000\n#define PAGE_ENCLAVE_UNVALIDATED    0x20000000\n\n// Region and section constants\n#if (PHNT_MODE != PHNT_MODE_KERNEL)\n#define MEM_COMMIT 0x1000\n#define MEM_RESERVE 0x2000\n#define MEM_DECOMMIT 0x4000\n#define MEM_RELEASE 0x8000\n#define MEM_FREE 0x10000\n#define MEM_PRIVATE 0x20000\n#define MEM_MAPPED 0x40000\n#define MEM_RESET 0x80000\n#define MEM_TOP_DOWN 0x100000\n#endif\n#define MEM_WRITE_WATCH 0x200000\n#define MEM_PHYSICAL 0x400000\n#define MEM_ROTATE 0x800000\n#define MEM_DIFFERENT_IMAGE_BASE_OK 0x800000\n#if (PHNT_MODE != PHNT_MODE_KERNEL)\n#define MEM_RESET_UNDO 0x1000000\n#endif\n#define MEM_LARGE_PAGES 0x20000000\n#define MEM_4MB_PAGES 0x80000000\n\n#if (PHNT_MODE != PHNT_MODE_KERNEL)\n#define SEC_FILE 0x800000\n#endif\n#define SEC_IMAGE 0x1000000\n#define SEC_PROTECTED_IMAGE 0x2000000\n#if (PHNT_MODE != PHNT_MODE_KERNEL)\n#define SEC_RESERVE 0x4000000\n#define SEC_COMMIT 0x8000000\n#endif\n#define SEC_NOCACHE 0x10000000\n#define SEC_WRITECOMBINE 0x40000000\n#define SEC_LARGE_PAGES 0x80000000\n#define SEC_IMAGE_NO_EXECUTE (SEC_IMAGE | SEC_NOCACHE)\n#define MEM_IMAGE SEC_IMAGE\n\n#endif\n\n#if (PHNT_MODE != PHNT_MODE_KERNEL)\n// private\ntypedef enum _MEMORY_INFORMATION_CLASS\n{\n    MemoryBasicInformation, // MEMORY_BASIC_INFORMATION\n    MemoryWorkingSetInformation, // MEMORY_WORKING_SET_INFORMATION\n    MemoryMappedFilenameInformation, // UNICODE_STRING\n    MemoryRegionInformation, // MEMORY_REGION_INFORMATION\n    MemoryWorkingSetExInformation, // MEMORY_WORKING_SET_EX_INFORMATION\n    MemorySharedCommitInformation, // MEMORY_SHARED_COMMIT_INFORMATION\n    MemoryImageInformation, // MEMORY_IMAGE_INFORMATION\n    MemoryRegionInformationEx,\n    MemoryPrivilegedBasicInformation,\n    MemoryEnclaveImageInformation, // since REDSTONE3\n    MemoryBasicInformationCapped\n} MEMORY_INFORMATION_CLASS;\n#else\n#define MemoryBasicInformation 0x0\n#define MemoryWorkingSetInformation 0x1\n#define MemoryMappedFilenameInformation 0x2\n#define MemoryRegionInformation 0x3\n#define MemoryWorkingSetExInformation 0x4\n#define MemorySharedCommitInformation 0x5\n#define MemoryImageInformation 0x6\n#define MemoryRegionInformationEx 0x7\n#define MemoryPrivilegedBasicInformation 0x8\n#define MemoryEnclaveImageInformation 0x9\n#define MemoryBasicInformationCapped 0xA\n#endif\n\ntypedef struct _MEMORY_WORKING_SET_BLOCK\n{\n    ULONG_PTR Protection : 5;\n    ULONG_PTR ShareCount : 3;\n    ULONG_PTR Shared : 1;\n    ULONG_PTR Node : 3;\n#ifdef _WIN64\n    ULONG_PTR VirtualPage : 52;\n#else\n    ULONG VirtualPage : 20;\n#endif\n} MEMORY_WORKING_SET_BLOCK, *PMEMORY_WORKING_SET_BLOCK;\n\ntypedef struct _MEMORY_WORKING_SET_INFORMATION\n{\n    ULONG_PTR NumberOfEntries;\n    MEMORY_WORKING_SET_BLOCK WorkingSetInfo[1];\n} MEMORY_WORKING_SET_INFORMATION, *PMEMORY_WORKING_SET_INFORMATION;\n\n// private\ntypedef struct _MEMORY_REGION_INFORMATION\n{\n    PVOID AllocationBase;\n    ULONG AllocationProtect;\n    union\n    {\n        ULONG RegionType;\n        struct\n        {\n            ULONG Private : 1;\n            ULONG MappedDataFile : 1;\n            ULONG MappedImage : 1;\n            ULONG MappedPageFile : 1;\n            ULONG MappedPhysical : 1;\n            ULONG DirectMapped : 1;\n            ULONG SoftwareEnclave : 1; //REDSTONE3\n            ULONG PageSize64K : 1;\n            ULONG Reserved : 24;\n        };\n    };\n    SIZE_T RegionSize;\n    SIZE_T CommitSize;\n} MEMORY_REGION_INFORMATION, *PMEMORY_REGION_INFORMATION;\n\n// private\ntypedef struct _MEMORY_WORKING_SET_EX_BLOCK\n{\n    union\n    {\n        struct\n        {\n            ULONG_PTR Valid : 1;\n            ULONG_PTR ShareCount : 3;\n            ULONG_PTR Win32Protection : 11;\n            ULONG_PTR Shared : 1;\n            ULONG_PTR Node : 6;\n            ULONG_PTR Locked : 1;\n            ULONG_PTR LargePage : 1;\n            ULONG_PTR Priority : 3;\n            ULONG_PTR Reserved : 3;\n            ULONG_PTR SharedOriginal : 1;\n            ULONG_PTR Bad : 1;\n#ifdef _WIN64\n            ULONG_PTR ReservedUlong : 32;\n#endif\n        };\n        struct\n        {\n            ULONG_PTR Valid : 1;\n            ULONG_PTR Reserved0 : 14;\n            ULONG_PTR Shared : 1;\n            ULONG_PTR Reserved1 : 5;\n            ULONG_PTR PageTable : 1;\n            ULONG_PTR Location : 2;\n            ULONG_PTR Priority : 3;\n            ULONG_PTR ModifiedList : 1;\n            ULONG_PTR Reserved2 : 2;\n            ULONG_PTR SharedOriginal : 1;\n            ULONG_PTR Bad : 1;\n#ifdef _WIN64\n            ULONG_PTR ReservedUlong : 32;\n#endif\n        } Invalid;\n    };\n} MEMORY_WORKING_SET_EX_BLOCK, *PMEMORY_WORKING_SET_EX_BLOCK;\n\n// private\ntypedef struct _MEMORY_WORKING_SET_EX_INFORMATION\n{\n    PVOID VirtualAddress;\n    union\n    {\n        MEMORY_WORKING_SET_EX_BLOCK VirtualAttributes;\n        ULONG_PTR Long;\n    } u1;\n} MEMORY_WORKING_SET_EX_INFORMATION, *PMEMORY_WORKING_SET_EX_INFORMATION;\n\n// private\ntypedef struct _MEMORY_SHARED_COMMIT_INFORMATION\n{\n    SIZE_T CommitSize;\n} MEMORY_SHARED_COMMIT_INFORMATION, *PMEMORY_SHARED_COMMIT_INFORMATION;\n\n// private\ntypedef struct _MEMORY_IMAGE_INFORMATION\n{\n    PVOID ImageBase;\n    SIZE_T SizeOfImage;\n    union\n    {\n        ULONG ImageFlags;\n        struct\n        {\n            ULONG ImagePartialMap : 1;\n            ULONG ImageNotExecutable : 1;\n            ULONG ImageSigningLevel : 1; // REDSTONE3\n            ULONG Reserved : 30;\n        };\n    };\n} MEMORY_IMAGE_INFORMATION, *PMEMORY_IMAGE_INFORMATION;\n\n#define MMPFNLIST_ZERO 0\n#define MMPFNLIST_FREE 1\n#define MMPFNLIST_STANDBY 2\n#define MMPFNLIST_MODIFIED 3\n#define MMPFNLIST_MODIFIEDNOWRITE 4\n#define MMPFNLIST_BAD 5\n#define MMPFNLIST_ACTIVE 6\n#define MMPFNLIST_TRANSITION 7\n\n#define MMPFNUSE_PROCESSPRIVATE 0\n#define MMPFNUSE_FILE 1\n#define MMPFNUSE_PAGEFILEMAPPED 2\n#define MMPFNUSE_PAGETABLE 3\n#define MMPFNUSE_PAGEDPOOL 4\n#define MMPFNUSE_NONPAGEDPOOL 5\n#define MMPFNUSE_SYSTEMPTE 6\n#define MMPFNUSE_SESSIONPRIVATE 7\n#define MMPFNUSE_METAFILE 8\n#define MMPFNUSE_AWEPAGE 9\n#define MMPFNUSE_DRIVERLOCKPAGE 10\n#define MMPFNUSE_KERNELSTACK 11\n\n// private\ntypedef struct _MEMORY_FRAME_INFORMATION\n{\n    ULONGLONG UseDescription : 4; // MMPFNUSE_*\n    ULONGLONG ListDescription : 3; // MMPFNLIST_*\n    ULONGLONG Reserved0 : 1; // reserved for future expansion\n    ULONGLONG Pinned : 1; // 1 - pinned, 0 - not pinned\n    ULONGLONG DontUse : 48; // *_INFORMATION overlay\n    ULONGLONG Priority : 3; // rev\n    ULONGLONG Reserved : 4; // reserved for future expansion\n} MEMORY_FRAME_INFORMATION;\n\n// private\ntypedef struct _FILEOFFSET_INFORMATION\n{\n    ULONGLONG DontUse : 9; // MEMORY_FRAME_INFORMATION overlay\n    ULONGLONG Offset : 48; // mapped files\n    ULONGLONG Reserved : 7; // reserved for future expansion\n} FILEOFFSET_INFORMATION;\n\n// private\ntypedef struct _PAGEDIR_INFORMATION\n{\n    ULONGLONG DontUse : 9; // MEMORY_FRAME_INFORMATION overlay\n    ULONGLONG PageDirectoryBase : 48; // private pages\n    ULONGLONG Reserved : 7; // reserved for future expansion\n} PAGEDIR_INFORMATION;\n\n// private\ntypedef struct _UNIQUE_PROCESS_INFORMATION\n{\n    ULONGLONG DontUse : 9; // MEMORY_FRAME_INFORMATION overlay\n    ULONGLONG UniqueProcessKey : 48; // ProcessId\n    ULONGLONG Reserved  : 7; // reserved for future expansion\n} UNIQUE_PROCESS_INFORMATION, *PUNIQUE_PROCESS_INFORMATION;\n\n// private\ntypedef struct _MMPFN_IDENTITY\n{\n    union\n    {\n        MEMORY_FRAME_INFORMATION e1; // all\n        FILEOFFSET_INFORMATION e2; // mapped files\n        PAGEDIR_INFORMATION e3; // private pages\n        UNIQUE_PROCESS_INFORMATION e4; // owning process\n    } u1;\n    ULONG_PTR PageFrameIndex; // all\n    union\n    {\n        struct\n        {\n            ULONG_PTR Image : 1;\n            ULONG_PTR Mismatch : 1;\n        } e1;\n        struct\n        {\n            ULONG_PTR CombinedPage;\n        } e2;\n        ULONG_PTR FileObject; // mapped files\n        ULONG_PTR UniqueFileObjectKey;\n        ULONG_PTR ProtoPteAddress;\n        ULONG_PTR VirtualAddress;  // everything else\n    } u2;\n} MMPFN_IDENTITY, *PMMPFN_IDENTITY;\n\ntypedef struct _MMPFN_MEMSNAP_INFORMATION\n{\n    ULONG_PTR InitialPageFrameIndex;\n    ULONG_PTR Count;\n} MMPFN_MEMSNAP_INFORMATION, *PMMPFN_MEMSNAP_INFORMATION;\n\ntypedef enum _SECTION_INFORMATION_CLASS\n{\n    SectionBasicInformation, // q; SECTION_BASIC_INFORMATION\n    SectionImageInformation, // q; SECTION_IMAGE_INFORMATION\n    SectionRelocationInformation, // name:wow64:whNtQuerySection_SectionRelocationInformation\n    SectionOriginalBaseInformation, // PVOID BaseAddress\n    SectionInternalImageInformation, // SECTION_INTERNAL_IMAGE_INFORMATION // since REDSTONE2\n    MaxSectionInfoClass\n} SECTION_INFORMATION_CLASS;\n\ntypedef struct _SECTION_BASIC_INFORMATION\n{\n    PVOID BaseAddress;\n    ULONG AllocationAttributes;\n    LARGE_INTEGER MaximumSize;\n} SECTION_BASIC_INFORMATION, *PSECTION_BASIC_INFORMATION;\n\n// symbols\ntypedef struct _SECTION_IMAGE_INFORMATION\n{\n    PVOID TransferAddress;\n    ULONG ZeroBits;\n    SIZE_T MaximumStackSize;\n    SIZE_T CommittedStackSize;\n    ULONG SubSystemType;\n    union\n    {\n        struct\n        {\n            USHORT SubSystemMinorVersion;\n            USHORT SubSystemMajorVersion;\n        };\n        ULONG SubSystemVersion;\n    };\n    union\n    {\n        struct\n        {\n            USHORT MajorOperatingSystemVersion;\n            USHORT MinorOperatingSystemVersion;\n        };\n        ULONG OperatingSystemVersion;\n    };\n    USHORT ImageCharacteristics;\n    USHORT DllCharacteristics;\n    USHORT Machine;\n    BOOLEAN ImageContainsCode;\n    union\n    {\n        UCHAR ImageFlags;\n        struct\n        {\n            UCHAR ComPlusNativeReady : 1;\n            UCHAR ComPlusILOnly : 1;\n            UCHAR ImageDynamicallyRelocated : 1;\n            UCHAR ImageMappedFlat : 1;\n            UCHAR BaseBelow4gb : 1;\n            UCHAR ComPlusPrefer32bit : 1;\n            UCHAR Reserved : 2;\n        };\n    };\n    ULONG LoaderFlags;\n    ULONG ImageFileSize;\n    ULONG CheckSum;\n} SECTION_IMAGE_INFORMATION, *PSECTION_IMAGE_INFORMATION;\n\n// symbols\ntypedef struct _SECTION_INTERNAL_IMAGE_INFORMATION\n{\n    SECTION_IMAGE_INFORMATION SectionInformation;\n    union\n    {\n        ULONG ExtendedFlags;\n        struct\n        {\n            ULONG ImageExportSuppressionEnabled : 1;\n            ULONG Reserved : 31;\n        };\n    };\n} SECTION_INTERNAL_IMAGE_INFORMATION, *PSECTION_INTERNAL_IMAGE_INFORMATION;\n\n#if (PHNT_MODE != PHNT_MODE_KERNEL)\ntypedef enum _SECTION_INHERIT\n{\n    ViewShare = 1,\n    ViewUnmap = 2\n} SECTION_INHERIT;\n#endif\n\n#define SEC_BASED 0x200000\n#define SEC_NO_CHANGE 0x400000\n#define SEC_GLOBAL 0x20000000\n\n#define MEM_EXECUTE_OPTION_DISABLE 0x1\n#define MEM_EXECUTE_OPTION_ENABLE 0x2\n#define MEM_EXECUTE_OPTION_DISABLE_THUNK_EMULATION 0x4\n#define MEM_EXECUTE_OPTION_PERMANENT 0x8\n#define MEM_EXECUTE_OPTION_EXECUTE_DISPATCH_ENABLE 0x10\n#define MEM_EXECUTE_OPTION_IMAGE_DISPATCH_ENABLE 0x20\n#define MEM_EXECUTE_OPTION_VALID_FLAGS 0x3f\n\n// Virtual memory\n\n#if (PHNT_MODE != PHNT_MODE_KERNEL)\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtAllocateVirtualMemory(\n    _In_ HANDLE ProcessHandle,\n    _Inout_ _At_(*BaseAddress, _Readable_bytes_(*RegionSize) _Writable_bytes_(*RegionSize) _Post_readable_byte_size_(*RegionSize)) PVOID *BaseAddress,\n    _In_ ULONG_PTR ZeroBits,\n    _Inout_ PSIZE_T RegionSize,\n    _In_ ULONG AllocationType,\n    _In_ ULONG Protect\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtFreeVirtualMemory(\n    _In_ HANDLE ProcessHandle,\n    _Inout_ PVOID *BaseAddress,\n    _Inout_ PSIZE_T RegionSize,\n    _In_ ULONG FreeType\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtReadVirtualMemory(\n    _In_ HANDLE ProcessHandle,\n    _In_opt_ PVOID BaseAddress,\n    _Out_writes_bytes_(BufferSize) PVOID Buffer,\n    _In_ SIZE_T BufferSize,\n    _Out_opt_ PSIZE_T NumberOfBytesRead\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtWriteVirtualMemory(\n    _In_ HANDLE ProcessHandle,\n    _In_opt_ PVOID BaseAddress,\n    _In_reads_bytes_(BufferSize) PVOID Buffer,\n    _In_ SIZE_T BufferSize,\n    _Out_opt_ PSIZE_T NumberOfBytesWritten\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtProtectVirtualMemory(\n    _In_ HANDLE ProcessHandle,\n    _Inout_ PVOID *BaseAddress,\n    _Inout_ PSIZE_T RegionSize,\n    _In_ ULONG NewProtect,\n    _Out_ PULONG OldProtect\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtQueryVirtualMemory(\n    _In_ HANDLE ProcessHandle,\n    _In_ PVOID BaseAddress,\n    _In_ MEMORY_INFORMATION_CLASS MemoryInformationClass,\n    _Out_writes_bytes_(MemoryInformationLength) PVOID MemoryInformation,\n    _In_ SIZE_T MemoryInformationLength,\n    _Out_opt_ PSIZE_T ReturnLength\n    );\n\n#endif\n\n// begin_private\n#if (PHNT_MODE != PHNT_MODE_KERNEL)\ntypedef enum _VIRTUAL_MEMORY_INFORMATION_CLASS\n{\n    VmPrefetchInformation, // ULONG\n    VmPagePriorityInformation,\n    VmCfgCallTargetInformation, // CFG_CALL_TARGET_LIST_INFORMATION // REDSTONE2\n    VmPageDirtyStateInformation // REDSTONE3\n} VIRTUAL_MEMORY_INFORMATION_CLASS;\n\ntypedef struct _MEMORY_RANGE_ENTRY\n{\n    PVOID VirtualAddress;\n    SIZE_T NumberOfBytes;\n} MEMORY_RANGE_ENTRY, *PMEMORY_RANGE_ENTRY;\n\ntypedef struct _CFG_CALL_TARGET_LIST_INFORMATION\n{\n    ULONG NumberOfEntries;\n    ULONG Reserved;\n    PULONG NumberOfEntriesProcessed;\n    PCFG_CALL_TARGET_INFO CallTargetInfo;\n} CFG_CALL_TARGET_LIST_INFORMATION, *PCFG_CALL_TARGET_LIST_INFORMATION;\n#endif\n// end_private\n\n#if (PHNT_MODE != PHNT_MODE_KERNEL)\n\n#if (PHNT_VERSION >= PHNT_THRESHOLD)\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtSetInformationVirtualMemory(\n    _In_ HANDLE ProcessHandle,\n    _In_ VIRTUAL_MEMORY_INFORMATION_CLASS VmInformationClass,\n    _In_ ULONG_PTR NumberOfEntries,\n    _In_reads_ (NumberOfEntries) PMEMORY_RANGE_ENTRY VirtualAddresses,\n    _In_reads_bytes_ (VmInformationLength) PVOID VmInformation,\n    _In_ ULONG VmInformationLength\n    );\n\n#endif\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtLockVirtualMemory(\n    _In_ HANDLE ProcessHandle,\n    _Inout_ PVOID *BaseAddress,\n    _Inout_ PSIZE_T RegionSize,\n    _In_ ULONG MapType\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtUnlockVirtualMemory(\n    _In_ HANDLE ProcessHandle,\n    _Inout_ PVOID *BaseAddress,\n    _Inout_ PSIZE_T RegionSize,\n    _In_ ULONG MapType\n    );\n\n#endif\n\n// Sections\n\n#if (PHNT_MODE != PHNT_MODE_KERNEL)\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtCreateSection(\n    _Out_ PHANDLE SectionHandle,\n    _In_ ACCESS_MASK DesiredAccess,\n    _In_opt_ POBJECT_ATTRIBUTES ObjectAttributes,\n    _In_opt_ PLARGE_INTEGER MaximumSize,\n    _In_ ULONG SectionPageProtection,\n    _In_ ULONG AllocationAttributes,\n    _In_opt_ HANDLE FileHandle\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtOpenSection(\n    _Out_ PHANDLE SectionHandle,\n    _In_ ACCESS_MASK DesiredAccess,\n    _In_ POBJECT_ATTRIBUTES ObjectAttributes\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtMapViewOfSection(\n    _In_ HANDLE SectionHandle,\n    _In_ HANDLE ProcessHandle,\n    _Inout_ _At_(*BaseAddress, _Readable_bytes_(*ViewSize) _Writable_bytes_(*ViewSize) _Post_readable_byte_size_(*ViewSize)) PVOID *BaseAddress,\n    _In_ ULONG_PTR ZeroBits,\n    _In_ SIZE_T CommitSize,\n    _Inout_opt_ PLARGE_INTEGER SectionOffset,\n    _Inout_ PSIZE_T ViewSize,\n    _In_ SECTION_INHERIT InheritDisposition,\n    _In_ ULONG AllocationType,\n    _In_ ULONG Win32Protect\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtUnmapViewOfSection(\n    _In_ HANDLE ProcessHandle,\n    _In_opt_ PVOID BaseAddress\n    );\n\n#if (PHNT_VERSION >= PHNT_WIN8)\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtUnmapViewOfSectionEx(\n    _In_ HANDLE ProcessHandle,\n    _In_opt_ PVOID BaseAddress,\n    _In_ ULONG Flags\n    );\n#endif\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtExtendSection(\n    _In_ HANDLE SectionHandle,\n    _Inout_ PLARGE_INTEGER NewSectionSize\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtQuerySection(\n    _In_ HANDLE SectionHandle,\n    _In_ SECTION_INFORMATION_CLASS SectionInformationClass,\n    _Out_writes_bytes_(SectionInformationLength) PVOID SectionInformation,\n    _In_ SIZE_T SectionInformationLength,\n    _Out_opt_ PSIZE_T ReturnLength\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtAreMappedFilesTheSame(\n    _In_ PVOID File1MappedAsAnImage,\n    _In_ PVOID File2MappedAsFile\n    );\n\n#endif\n\n// Partitions\n\n#ifndef MEMORY_PARTITION_QUERY_ACCESS\n#define MEMORY_PARTITION_QUERY_ACCESS 0x0001\n#define MEMORY_PARTITION_MODIFY_ACCESS 0x0002\n#define MEMORY_PARTITION_ALL_ACCESS \\\n    (STANDARD_RIGHTS_REQUIRED | SYNCHRONIZE | \\\n     MEMORY_PARTITION_QUERY_ACCESS | MEMORY_PARTITION_MODIFY_ACCESS)\n#endif\n\n// private\ntypedef enum _MEMORY_PARTITION_INFORMATION_CLASS\n{\n    SystemMemoryPartitionInformation, // q: MEMORY_PARTITION_CONFIGURATION_INFORMATION\n    SystemMemoryPartitionMoveMemory, // s: MEMORY_PARTITION_TRANSFER_INFORMATION\n    SystemMemoryPartitionAddPagefile, // s: MEMORY_PARTITION_PAGEFILE_INFORMATION\n    SystemMemoryPartitionCombineMemory, // q; s: MEMORY_PARTITION_PAGE_COMBINE_INFORMATION\n    SystemMemoryPartitionInitialAddMemory, // q; s: MEMORY_PARTITION_INITIAL_ADD_INFORMATION\n    SystemMemoryPartitionGetMemoryEvents // MEMORY_PARTITION_MEMORY_EVENTS_INFORMATION // since REDSTONE2\n} MEMORY_PARTITION_INFORMATION_CLASS;\n\n// private\ntypedef struct _MEMORY_PARTITION_CONFIGURATION_INFORMATION\n{\n    ULONG Flags;\n    ULONG NumaNode;\n    ULONG Channel;\n    ULONG NumberOfNumaNodes;\n    ULONG_PTR ResidentAvailablePages;\n    ULONG_PTR CommittedPages;\n    ULONG_PTR CommitLimit;\n    ULONG_PTR PeakCommitment;\n    ULONG_PTR TotalNumberOfPages;\n    ULONG_PTR AvailablePages;\n    ULONG_PTR ZeroPages;\n    ULONG_PTR FreePages;\n    ULONG_PTR StandbyPages;\n    ULONG_PTR StandbyPageCountByPriority[8]; // since REDSTONE2\n    ULONG_PTR RepurposedPagesByPriority[8];\n    ULONG_PTR MaximumCommitLimit;\n    ULONG_PTR DonatedPagesToPartitions;\n    ULONG PartitionId; // since REDSTONE3\n} MEMORY_PARTITION_CONFIGURATION_INFORMATION, *PMEMORY_PARTITION_CONFIGURATION_INFORMATION;\n\n// private\ntypedef struct _MEMORY_PARTITION_TRANSFER_INFORMATION\n{\n    ULONG_PTR NumberOfPages;\n    ULONG NumaNode;\n    ULONG Flags;\n} MEMORY_PARTITION_TRANSFER_INFORMATION, *PMEMORY_PARTITION_TRANSFER_INFORMATION;\n\n// private\ntypedef struct _MEMORY_PARTITION_PAGEFILE_INFORMATION\n{\n    UNICODE_STRING PageFileName;\n    LARGE_INTEGER MinimumSize;\n    LARGE_INTEGER MaximumSize;\n    ULONG Flags;\n} MEMORY_PARTITION_PAGEFILE_INFORMATION, *PMEMORY_PARTITION_PAGEFILE_INFORMATION;\n\n// private\ntypedef struct _MEMORY_PARTITION_PAGE_COMBINE_INFORMATION\n{\n    HANDLE StopHandle;\n    ULONG Flags;\n    ULONG_PTR TotalNumberOfPages;\n} MEMORY_PARTITION_PAGE_COMBINE_INFORMATION, *PMEMORY_PARTITION_PAGE_COMBINE_INFORMATION;\n\n// private\ntypedef struct _MEMORY_PARTITION_PAGE_RANGE\n{\n    ULONG_PTR StartPage;\n    ULONG_PTR NumberOfPages;\n} MEMORY_PARTITION_PAGE_RANGE, *PMEMORY_PARTITION_PAGE_RANGE;\n\n// private\ntypedef struct _MEMORY_PARTITION_INITIAL_ADD_INFORMATION\n{\n    ULONG Flags;\n    ULONG NumberOfRanges;\n    ULONG_PTR NumberOfPagesAdded;\n    MEMORY_PARTITION_PAGE_RANGE PartitionRanges[1];\n} MEMORY_PARTITION_INITIAL_ADD_INFORMATION, *PMEMORY_PARTITION_INITIAL_ADD_INFORMATION;\n\n// private\ntypedef struct _MEMORY_PARTITION_MEMORY_EVENTS_INFORMATION\n{\n    union\n    {    \n        struct\n        {\n            ULONG CommitEvents : 1;\n            ULONG Spare : 31;\n        };\n        ULONG AllFlags;\n    } Flags;\n    \n    ULONG HandleAttributes;\n    ULONG DesiredAccess;\n    HANDLE LowCommitCondition; // \\KernelObjects\\LowCommitCondition\n    HANDLE HighCommitCondition; // \\KernelObjects\\HighCommitCondition\n    HANDLE MaximumCommitCondition; // \\KernelObjects\\MaximumCommitCondition\n} MEMORY_PARTITION_MEMORY_EVENTS_INFORMATION, *PMEMORY_PARTITION_MEMORY_EVENTS_INFORMATION;\n\n#if (PHNT_MODE != PHNT_MODE_KERNEL)\n\n#if (PHNT_VERSION >= PHNT_THRESHOLD)\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtCreatePartition(\n    _Out_ PHANDLE PartitionHandle,\n    _In_ ACCESS_MASK DesiredAccess,\n    _In_opt_ POBJECT_ATTRIBUTES ObjectAttributes,\n    _In_ ULONG PreferredNode\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtOpenPartition(\n    _Out_ PHANDLE PartitionHandle,\n    _In_ ACCESS_MASK DesiredAccess,\n    _In_ POBJECT_ATTRIBUTES ObjectAttributes\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtManagePartition(\n    _In_ MEMORY_PARTITION_INFORMATION_CLASS PartitionInformationClass,\n    _In_ PVOID PartitionInformation,\n    _In_ ULONG PartitionInformationLength\n    );\n\n#endif\n\n#endif\n\n// User physical pages\n\n#if (PHNT_MODE != PHNT_MODE_KERNEL)\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtMapUserPhysicalPages(\n    _In_ PVOID VirtualAddress,\n    _In_ ULONG_PTR NumberOfPages,\n    _In_reads_opt_(NumberOfPages) PULONG_PTR UserPfnArray\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtMapUserPhysicalPagesScatter(\n    _In_reads_(NumberOfPages) PVOID *VirtualAddresses,\n    _In_ ULONG_PTR NumberOfPages,\n    _In_reads_opt_(NumberOfPages) PULONG_PTR UserPfnArray\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtAllocateUserPhysicalPages(\n    _In_ HANDLE ProcessHandle,\n    _Inout_ PULONG_PTR NumberOfPages,\n    _Out_writes_(*NumberOfPages) PULONG_PTR UserPfnArray\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtFreeUserPhysicalPages(\n    _In_ HANDLE ProcessHandle,\n    _Inout_ PULONG_PTR NumberOfPages,\n    _In_reads_(*NumberOfPages) PULONG_PTR UserPfnArray\n    );\n\n#endif\n\n// Sessions\n\n#if (PHNT_MODE != PHNT_MODE_KERNEL)\n\n#if (PHNT_VERSION >= PHNT_VISTA)\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtOpenSession(\n    _Out_ PHANDLE SessionHandle,\n    _In_ ACCESS_MASK DesiredAccess,\n    _In_ POBJECT_ATTRIBUTES ObjectAttributes\n    );\n#endif\n\n#endif\n\n// Misc.\n\n#if (PHNT_MODE != PHNT_MODE_KERNEL)\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtGetWriteWatch(\n    _In_ HANDLE ProcessHandle,\n    _In_ ULONG Flags,\n    _In_ PVOID BaseAddress,\n    _In_ SIZE_T RegionSize,\n    _Out_writes_(*EntriesInUserAddressArray) PVOID *UserAddressArray,\n    _Inout_ PULONG_PTR EntriesInUserAddressArray,\n    _Out_ PULONG Granularity\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtResetWriteWatch(\n    _In_ HANDLE ProcessHandle,\n    _In_ PVOID BaseAddress,\n    _In_ SIZE_T RegionSize\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtCreatePagingFile(\n    _In_ PUNICODE_STRING PageFileName,\n    _In_ PLARGE_INTEGER MinimumSize,\n    _In_ PLARGE_INTEGER MaximumSize,\n    _In_ ULONG Priority\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtFlushInstructionCache(\n    _In_ HANDLE ProcessHandle,\n    _In_opt_ PVOID BaseAddress,\n    _In_ SIZE_T Length\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtFlushWriteBuffer(\n    VOID\n    );\n\n#endif\n\n#endif\n"
  },
  {
    "path": "third_party/phnt/include/ntnls.h",
    "content": "#ifndef _NTNLS_H\n#define _NTNLS_H\n\n#define MAXIMUM_LEADBYTES 12\n\ntypedef struct _CPTABLEINFO\n{\n    USHORT CodePage;\n    USHORT MaximumCharacterSize;\n    USHORT DefaultChar;\n    USHORT UniDefaultChar;\n    USHORT TransDefaultChar;\n    USHORT TransUniDefaultChar;\n    USHORT DBCSCodePage;\n    UCHAR LeadByte[MAXIMUM_LEADBYTES];\n    PUSHORT MultiByteTable;\n    PVOID WideCharTable;\n    PUSHORT DBCSRanges;\n    PUSHORT DBCSOffsets;\n} CPTABLEINFO, *PCPTABLEINFO;\n\ntypedef struct _NLSTABLEINFO\n{\n    CPTABLEINFO OemTableInfo;\n    CPTABLEINFO AnsiTableInfo;\n    PUSHORT UpperCaseTable;\n    PUSHORT LowerCaseTable;\n} NLSTABLEINFO, *PNLSTABLEINFO;\n\n#endif\n"
  },
  {
    "path": "third_party/phnt/include/ntobapi.h",
    "content": "#ifndef _NTOBAPI_H\n#define _NTOBAPI_H\n\n#if (PHNT_MODE != PHNT_MODE_KERNEL)\n#define OBJECT_TYPE_CREATE 0x0001\n#define OBJECT_TYPE_ALL_ACCESS (STANDARD_RIGHTS_REQUIRED | 0x1)\n#endif\n\n#if (PHNT_MODE != PHNT_MODE_KERNEL)\n#define DIRECTORY_QUERY 0x0001\n#define DIRECTORY_TRAVERSE 0x0002\n#define DIRECTORY_CREATE_OBJECT 0x0004\n#define DIRECTORY_CREATE_SUBDIRECTORY 0x0008\n#define DIRECTORY_ALL_ACCESS (STANDARD_RIGHTS_REQUIRED | 0xf)\n#endif\n\n#if (PHNT_MODE != PHNT_MODE_KERNEL)\n#define SYMBOLIC_LINK_QUERY 0x0001\n#define SYMBOLIC_LINK_ALL_ACCESS (STANDARD_RIGHTS_REQUIRED | 0x1)\n#endif\n\n#define OBJ_PROTECT_CLOSE 0x00000001\n#ifndef OBJ_INHERIT\n#define OBJ_INHERIT 0x00000002\n#endif\n#define OBJ_AUDIT_OBJECT_CLOSE 0x00000004\n\n#if (PHNT_MODE != PHNT_MODE_KERNEL)\ntypedef enum _OBJECT_INFORMATION_CLASS\n{\n    ObjectBasicInformation, // OBJECT_BASIC_INFORMATION\n    ObjectNameInformation, // OBJECT_NAME_INFORMATION\n    ObjectTypeInformation, // OBJECT_TYPE_INFORMATION\n    ObjectTypesInformation, // OBJECT_TYPES_INFORMATION\n    ObjectHandleFlagInformation, // OBJECT_HANDLE_FLAG_INFORMATION\n    ObjectSessionInformation,\n    ObjectSessionObjectInformation,\n    MaxObjectInfoClass\n} OBJECT_INFORMATION_CLASS;\n#else\n#define ObjectNameInformation 1\n#define ObjectTypesInformation 3\n#define ObjectHandleFlagInformation 4\n#define ObjectSessionInformation 5\n#endif\n\ntypedef struct _OBJECT_BASIC_INFORMATION\n{\n    ULONG Attributes;\n    ACCESS_MASK GrantedAccess;\n    ULONG HandleCount;\n    ULONG PointerCount;\n    ULONG PagedPoolCharge;\n    ULONG NonPagedPoolCharge;\n    ULONG Reserved[3];\n    ULONG NameInfoSize;\n    ULONG TypeInfoSize;\n    ULONG SecurityDescriptorSize;\n    LARGE_INTEGER CreationTime;\n} OBJECT_BASIC_INFORMATION, *POBJECT_BASIC_INFORMATION;\n\n#if (PHNT_MODE != PHNT_MODE_KERNEL)\ntypedef struct _OBJECT_NAME_INFORMATION\n{\n    UNICODE_STRING Name;\n} OBJECT_NAME_INFORMATION, *POBJECT_NAME_INFORMATION;\n#endif\n\ntypedef struct _OBJECT_TYPE_INFORMATION\n{\n    UNICODE_STRING TypeName;\n    ULONG TotalNumberOfObjects;\n    ULONG TotalNumberOfHandles;\n    ULONG TotalPagedPoolUsage;\n    ULONG TotalNonPagedPoolUsage;\n    ULONG TotalNamePoolUsage;\n    ULONG TotalHandleTableUsage;\n    ULONG HighWaterNumberOfObjects;\n    ULONG HighWaterNumberOfHandles;\n    ULONG HighWaterPagedPoolUsage;\n    ULONG HighWaterNonPagedPoolUsage;\n    ULONG HighWaterNamePoolUsage;\n    ULONG HighWaterHandleTableUsage;\n    ULONG InvalidAttributes;\n    GENERIC_MAPPING GenericMapping;\n    ULONG ValidAccessMask;\n    BOOLEAN SecurityRequired;\n    BOOLEAN MaintainHandleCount;\n    UCHAR TypeIndex; // since WINBLUE\n    CHAR ReservedByte;\n    ULONG PoolType;\n    ULONG DefaultPagedPoolCharge;\n    ULONG DefaultNonPagedPoolCharge;\n} OBJECT_TYPE_INFORMATION, *POBJECT_TYPE_INFORMATION;\n\ntypedef struct _OBJECT_TYPES_INFORMATION\n{\n    ULONG NumberOfTypes;\n} OBJECT_TYPES_INFORMATION, *POBJECT_TYPES_INFORMATION;\n\ntypedef struct _OBJECT_HANDLE_FLAG_INFORMATION\n{\n    BOOLEAN Inherit;\n    BOOLEAN ProtectFromClose;\n} OBJECT_HANDLE_FLAG_INFORMATION, *POBJECT_HANDLE_FLAG_INFORMATION;\n\n// Objects, handles\n\n#if (PHNT_MODE != PHNT_MODE_KERNEL)\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtQueryObject(\n    _In_ HANDLE Handle,\n    _In_ OBJECT_INFORMATION_CLASS ObjectInformationClass,\n    _Out_writes_bytes_opt_(ObjectInformationLength) PVOID ObjectInformation,\n    _In_ ULONG ObjectInformationLength,\n    _Out_opt_ PULONG ReturnLength\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtSetInformationObject(\n    _In_ HANDLE Handle,\n    _In_ OBJECT_INFORMATION_CLASS ObjectInformationClass,\n    _In_reads_bytes_(ObjectInformationLength) PVOID ObjectInformation,\n    _In_ ULONG ObjectInformationLength\n    );\n\n#define DUPLICATE_CLOSE_SOURCE 0x00000001\n#define DUPLICATE_SAME_ACCESS 0x00000002\n#define DUPLICATE_SAME_ATTRIBUTES 0x00000004\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtDuplicateObject(\n    _In_ HANDLE SourceProcessHandle,\n    _In_ HANDLE SourceHandle,\n    _In_opt_ HANDLE TargetProcessHandle,\n    _Out_opt_ PHANDLE TargetHandle,\n    _In_ ACCESS_MASK DesiredAccess,\n    _In_ ULONG HandleAttributes,\n    _In_ ULONG Options\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtMakeTemporaryObject(\n    _In_ HANDLE Handle\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtMakePermanentObject(\n    _In_ HANDLE Handle\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtSignalAndWaitForSingleObject(\n    _In_ HANDLE SignalHandle,\n    _In_ HANDLE WaitHandle,\n    _In_ BOOLEAN Alertable,\n    _In_opt_ PLARGE_INTEGER Timeout\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtWaitForSingleObject(\n    _In_ HANDLE Handle,\n    _In_ BOOLEAN Alertable,\n    _In_opt_ PLARGE_INTEGER Timeout\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtWaitForMultipleObjects(\n    _In_ ULONG Count,\n    _In_reads_(Count) HANDLE Handles[],\n    _In_ WAIT_TYPE WaitType,\n    _In_ BOOLEAN Alertable,\n    _In_opt_ PLARGE_INTEGER Timeout\n    );\n\n#if (PHNT_VERSION >= PHNT_WS03)\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtWaitForMultipleObjects32(\n    _In_ ULONG Count,\n    _In_reads_(Count) LONG Handles[],\n    _In_ WAIT_TYPE WaitType,\n    _In_ BOOLEAN Alertable,\n    _In_opt_ PLARGE_INTEGER Timeout\n    );\n#endif\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtSetSecurityObject(\n    _In_ HANDLE Handle,\n    _In_ SECURITY_INFORMATION SecurityInformation,\n    _In_ PSECURITY_DESCRIPTOR SecurityDescriptor\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtQuerySecurityObject(\n    _In_ HANDLE Handle,\n    _In_ SECURITY_INFORMATION SecurityInformation,\n    _Out_writes_bytes_opt_(Length) PSECURITY_DESCRIPTOR SecurityDescriptor,\n    _In_ ULONG Length,\n    _Out_ PULONG LengthNeeded\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtClose(\n    _In_ HANDLE Handle\n    );\n\n#if (PHNT_VERSION >= PHNT_THRESHOLD)\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtCompareObjects(\n    _In_ HANDLE FirstObjectHandle,\n    _In_ HANDLE SecondObjectHandle\n    );\n#endif\n\n#endif\n\n// Directory objects\n\n#if (PHNT_MODE != PHNT_MODE_KERNEL)\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtCreateDirectoryObject(\n    _Out_ PHANDLE DirectoryHandle,\n    _In_ ACCESS_MASK DesiredAccess,\n    _In_ POBJECT_ATTRIBUTES ObjectAttributes\n    );\n\n#if (PHNT_VERSION >= PHNT_WIN8)\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtCreateDirectoryObjectEx(\n    _Out_ PHANDLE DirectoryHandle,\n    _In_ ACCESS_MASK DesiredAccess,\n    _In_ POBJECT_ATTRIBUTES ObjectAttributes,\n    _In_ HANDLE ShadowDirectoryHandle,\n    _In_ ULONG Flags\n    );\n#endif\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtOpenDirectoryObject(\n    _Out_ PHANDLE DirectoryHandle,\n    _In_ ACCESS_MASK DesiredAccess,\n    _In_ POBJECT_ATTRIBUTES ObjectAttributes\n    );\n\ntypedef struct _OBJECT_DIRECTORY_INFORMATION\n{\n    UNICODE_STRING Name;\n    UNICODE_STRING TypeName;\n} OBJECT_DIRECTORY_INFORMATION, *POBJECT_DIRECTORY_INFORMATION;\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtQueryDirectoryObject(\n    _In_ HANDLE DirectoryHandle,\n    _Out_writes_bytes_opt_(Length) PVOID Buffer,\n    _In_ ULONG Length,\n    _In_ BOOLEAN ReturnSingleEntry,\n    _In_ BOOLEAN RestartScan,\n    _Inout_ PULONG Context,\n    _Out_opt_ PULONG ReturnLength\n    );\n\n#endif\n\n// Private namespaces\n\n#if (PHNT_MODE != PHNT_MODE_KERNEL)\n\n#if (PHNT_VERSION >= PHNT_VISTA)\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtCreatePrivateNamespace(\n    _Out_ PHANDLE NamespaceHandle,\n    _In_ ACCESS_MASK DesiredAccess,\n    _In_ POBJECT_ATTRIBUTES ObjectAttributes,\n    _In_ PVOID BoundaryDescriptor\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtOpenPrivateNamespace(\n    _Out_ PHANDLE NamespaceHandle,\n    _In_ ACCESS_MASK DesiredAccess,\n    _In_opt_ POBJECT_ATTRIBUTES ObjectAttributes,\n    _In_ PVOID BoundaryDescriptor\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtDeletePrivateNamespace(\n    _In_ HANDLE NamespaceHandle\n    );\n\n#endif\n\n#endif\n\n// Symbolic links\n\n#if (PHNT_MODE != PHNT_MODE_KERNEL)\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtCreateSymbolicLinkObject(\n    _Out_ PHANDLE LinkHandle,\n    _In_ ACCESS_MASK DesiredAccess,\n    _In_ POBJECT_ATTRIBUTES ObjectAttributes,\n    _In_ PUNICODE_STRING LinkTarget\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtOpenSymbolicLinkObject(\n    _Out_ PHANDLE LinkHandle,\n    _In_ ACCESS_MASK DesiredAccess,\n    _In_ POBJECT_ATTRIBUTES ObjectAttributes\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtQuerySymbolicLinkObject(\n    _In_ HANDLE LinkHandle,\n    _Inout_ PUNICODE_STRING LinkTarget,\n    _Out_opt_ PULONG ReturnedLength\n    );\n\n#endif\n\n#endif\n"
  },
  {
    "path": "third_party/phnt/include/ntpebteb.h",
    "content": "#ifndef _NTPEBTEB_H\n#define _NTPEBTEB_H\n\ntypedef struct _RTL_USER_PROCESS_PARAMETERS *PRTL_USER_PROCESS_PARAMETERS;\ntypedef struct _RTL_CRITICAL_SECTION *PRTL_CRITICAL_SECTION;\n\n// private\ntypedef struct _ACTIVATION_CONTEXT_STACK\n{\n    struct _RTL_ACTIVATION_CONTEXT_STACK_FRAME* ActiveFrame;\n    LIST_ENTRY FrameListCache;\n    ULONG Flags;\n    ULONG NextCookieSequenceNumber;\n    ULONG StackId;\n} ACTIVATION_CONTEXT_STACK, *PACTIVATION_CONTEXT_STACK;\n\n// symbols\ntypedef struct _PEB\n{\n    BOOLEAN InheritedAddressSpace;\n    BOOLEAN ReadImageFileExecOptions;\n    BOOLEAN BeingDebugged;\n    union\n    {\n        BOOLEAN BitField;\n        struct\n        {\n            BOOLEAN ImageUsesLargePages : 1;\n            BOOLEAN IsProtectedProcess : 1;\n            BOOLEAN IsImageDynamicallyRelocated : 1;\n            BOOLEAN SkipPatchingUser32Forwarders : 1;\n            BOOLEAN IsPackagedProcess : 1;\n            BOOLEAN IsAppContainer : 1;\n            BOOLEAN IsProtectedProcessLight : 1;\n            BOOLEAN IsLongPathAwareProcess : 1;\n        };\n    };\n\n    HANDLE Mutant;\n\n    PVOID ImageBaseAddress;\n    PPEB_LDR_DATA Ldr;\n    PRTL_USER_PROCESS_PARAMETERS ProcessParameters;\n    PVOID SubSystemData;\n    PVOID ProcessHeap;\n    PRTL_CRITICAL_SECTION FastPebLock;\n    PVOID AtlThunkSListPtr;\n    PVOID IFEOKey;\n    union\n    {\n        ULONG CrossProcessFlags;\n        struct\n        {\n            ULONG ProcessInJob : 1;\n            ULONG ProcessInitializing : 1;\n            ULONG ProcessUsingVEH : 1;\n            ULONG ProcessUsingVCH : 1;\n            ULONG ProcessUsingFTH : 1;\n            ULONG ProcessPreviouslyThrottled : 1;\n            ULONG ProcessCurrentlyThrottled : 1;\n            ULONG ReservedBits0 : 25;\n        };\n    };\n    union\n    {\n        PVOID KernelCallbackTable;\n        PVOID UserSharedInfoPtr;\n    };\n    ULONG SystemReserved[1];\n    ULONG AtlThunkSListPtr32;\n    PVOID ApiSetMap;\n    ULONG TlsExpansionCounter;\n    PVOID TlsBitmap;\n    ULONG TlsBitmapBits[2];\n    \n    PVOID ReadOnlySharedMemoryBase; \n    PVOID SharedData; // HotpatchInformation\n    PVOID *ReadOnlyStaticServerData;\n    \n    PVOID AnsiCodePageData; // PCPTABLEINFO\n    PVOID OemCodePageData; // PCPTABLEINFO\n    PVOID UnicodeCaseTableData; // PNLSTABLEINFO\n\n    ULONG NumberOfProcessors;\n    ULONG NtGlobalFlag;\n\n    LARGE_INTEGER CriticalSectionTimeout;\n    SIZE_T HeapSegmentReserve;\n    SIZE_T HeapSegmentCommit;\n    SIZE_T HeapDeCommitTotalFreeThreshold;\n    SIZE_T HeapDeCommitFreeBlockThreshold;\n\n    ULONG NumberOfHeaps;\n    ULONG MaximumNumberOfHeaps;\n    PVOID *ProcessHeaps; // PHEAP\n\n    PVOID GdiSharedHandleTable;\n    PVOID ProcessStarterHelper;\n    ULONG GdiDCAttributeList;\n\n    PRTL_CRITICAL_SECTION LoaderLock;\n\n    ULONG OSMajorVersion;\n    ULONG OSMinorVersion;\n    USHORT OSBuildNumber;\n    USHORT OSCSDVersion;\n    ULONG OSPlatformId;\n    ULONG ImageSubsystem;\n    ULONG ImageSubsystemMajorVersion;\n    ULONG ImageSubsystemMinorVersion;\n    ULONG_PTR ActiveProcessAffinityMask;\n    GDI_HANDLE_BUFFER GdiHandleBuffer;\n    PVOID PostProcessInitRoutine;\n\n    PVOID TlsExpansionBitmap;\n    ULONG TlsExpansionBitmapBits[32];\n\n    ULONG SessionId;\n\n    ULARGE_INTEGER AppCompatFlags;\n    ULARGE_INTEGER AppCompatFlagsUser;\n    PVOID pShimData;\n    PVOID AppCompatInfo; // APPCOMPAT_EXE_DATA\n\n    UNICODE_STRING CSDVersion;\n\n    PVOID ActivationContextData; // ACTIVATION_CONTEXT_DATA\n    PVOID ProcessAssemblyStorageMap; // ASSEMBLY_STORAGE_MAP\n    PVOID SystemDefaultActivationContextData; // ACTIVATION_CONTEXT_DATA\n    PVOID SystemAssemblyStorageMap; // ASSEMBLY_STORAGE_MAP\n\n    SIZE_T MinimumStackCommit;\n\n    PVOID *FlsCallback;\n    LIST_ENTRY FlsListHead;\n    PVOID FlsBitmap;\n    ULONG FlsBitmapBits[FLS_MAXIMUM_AVAILABLE_OLD / (sizeof(ULONG) * 8)];\n    ULONG FlsHighIndex;\n\n    PVOID WerRegistrationData;\n    PVOID WerShipAssertPtr;\n    PVOID pUnused; // pContextData\n    PVOID pImageHeaderHash;\n    union\n    {\n        ULONG TracingFlags;\n        struct\n        {\n            ULONG HeapTracingEnabled : 1;\n            ULONG CritSecTracingEnabled : 1;\n            ULONG LibLoaderTracingEnabled : 1;\n            ULONG SpareTracingBits : 29;\n        };\n    };\n    ULONGLONG CsrServerReadOnlySharedMemoryBase;\n    PVOID TppWorkerpListLock;\n    LIST_ENTRY TppWorkerpList;\n    PVOID WaitOnAddressHashTable[128];\n    PVOID TelemetryCoverageHeader; // REDSTONE3\n    ULONG CloudFileFlags;\n} PEB, *PPEB;\n\n#define GDI_BATCH_BUFFER_SIZE 310\n\ntypedef struct _GDI_TEB_BATCH\n{\n    ULONG Offset;\n    ULONG_PTR HDC;\n    ULONG Buffer[GDI_BATCH_BUFFER_SIZE];\n} GDI_TEB_BATCH, *PGDI_TEB_BATCH;\n\ntypedef struct _TEB_ACTIVE_FRAME_CONTEXT\n{\n    ULONG Flags;\n    PSTR FrameName;\n} TEB_ACTIVE_FRAME_CONTEXT, *PTEB_ACTIVE_FRAME_CONTEXT;\n\ntypedef struct _TEB_ACTIVE_FRAME\n{\n    ULONG Flags;\n    struct _TEB_ACTIVE_FRAME *Previous;\n    PTEB_ACTIVE_FRAME_CONTEXT Context;\n} TEB_ACTIVE_FRAME, *PTEB_ACTIVE_FRAME;\n\ntypedef struct _TEB\n{\n    NT_TIB NtTib;\n\n    PVOID EnvironmentPointer;\n    CLIENT_ID ClientId;\n    PVOID ActiveRpcHandle;\n    PVOID ThreadLocalStoragePointer;\n    PPEB ProcessEnvironmentBlock;\n\n    ULONG LastErrorValue;\n    ULONG CountOfOwnedCriticalSections;\n    PVOID CsrClientThread;\n    PVOID Win32ThreadInfo;\n    ULONG User32Reserved[26];\n    ULONG UserReserved[5];\n    PVOID WOW32Reserved;\n    LCID CurrentLocale;\n    ULONG FpSoftwareStatusRegister;\n    PVOID ReservedForDebuggerInstrumentation[16];\n#ifdef _WIN64\n    PVOID SystemReserved1[30];\n#else\n    PVOID SystemReserved1[26];\n#endif\n    \n    CHAR PlaceholderCompatibilityMode;\n    CHAR PlaceholderReserved[11];\n    ULONG ProxiedProcessId;\n    ACTIVATION_CONTEXT_STACK ActivationStack;\n    \n    UCHAR WorkingOnBehalfTicket[8];\n    NTSTATUS ExceptionCode;\n\n    PACTIVATION_CONTEXT_STACK ActivationContextStackPointer;\n    ULONG_PTR InstrumentationCallbackSp;\n    ULONG_PTR InstrumentationCallbackPreviousPc;\n    ULONG_PTR InstrumentationCallbackPreviousSp;\n#ifdef _WIN64\n    ULONG TxFsContext;\n#endif\n\n    BOOLEAN InstrumentationCallbackDisabled;\n#ifndef _WIN64\n    UCHAR SpareBytes[23];\n    ULONG TxFsContext;\n#endif\n    GDI_TEB_BATCH GdiTebBatch;\n    CLIENT_ID RealClientId;\n    HANDLE GdiCachedProcessHandle;\n    ULONG GdiClientPID;\n    ULONG GdiClientTID;\n    PVOID GdiThreadLocalInfo;\n    ULONG_PTR Win32ClientInfo[62];\n    PVOID glDispatchTable[233];\n    ULONG_PTR glReserved1[29];\n    PVOID glReserved2;\n    PVOID glSectionInfo;\n    PVOID glSection;\n    PVOID glTable;\n    PVOID glCurrentRC;\n    PVOID glContext;\n\n    NTSTATUS LastStatusValue;\n    UNICODE_STRING StaticUnicodeString;\n    WCHAR StaticUnicodeBuffer[261];\n\n    PVOID DeallocationStack;\n    PVOID TlsSlots[64];\n    LIST_ENTRY TlsLinks;\n\n    PVOID Vdm;\n    PVOID ReservedForNtRpc;\n    PVOID DbgSsReserved[2];\n\n    ULONG HardErrorMode;\n#ifdef _WIN64\n    PVOID Instrumentation[11];\n#else\n    PVOID Instrumentation[9];\n#endif\n    GUID ActivityId;\n\n    PVOID SubProcessTag;\n    PVOID PerflibData;\n    PVOID EtwTraceData;\n    PVOID WinSockData;\n    ULONG GdiBatchCount;\n\n    union\n    {\n        PROCESSOR_NUMBER CurrentIdealProcessor;\n        ULONG IdealProcessorValue;\n        struct\n        {\n            UCHAR ReservedPad0;\n            UCHAR ReservedPad1;\n            UCHAR ReservedPad2;\n            UCHAR IdealProcessor;\n        };\n    };\n\n    ULONG GuaranteedStackBytes;\n    PVOID ReservedForPerf;\n    PVOID ReservedForOle;\n    ULONG WaitingOnLoaderLock;\n    PVOID SavedPriorityState;\n    ULONG_PTR ReservedForCodeCoverage;\n    PVOID ThreadPoolData;\n    PVOID *TlsExpansionSlots;\n#ifdef _WIN64\n    PVOID DeallocationBStore;\n    PVOID BStoreLimit;\n#endif\n    ULONG MuiGeneration;\n    ULONG IsImpersonating;\n    PVOID NlsCache;\n    PVOID pShimData;\n    USHORT HeapVirtualAffinity;\n    USHORT LowFragHeapDataSlot;\n    HANDLE CurrentTransactionHandle;\n    PTEB_ACTIVE_FRAME ActiveFrame;\n    PVOID FlsData;\n\n    PVOID PreferredLanguages;\n    PVOID UserPrefLanguages;\n    PVOID MergedPrefLanguages;\n    ULONG MuiImpersonation;\n\n    union\n    {\n        USHORT CrossTebFlags;\n        USHORT SpareCrossTebBits : 16;\n    };\n    union\n    {\n        USHORT SameTebFlags;\n        struct\n        {\n            USHORT SafeThunkCall : 1;\n            USHORT InDebugPrint : 1;\n            USHORT HasFiberData : 1;\n            USHORT SkipThreadAttach : 1;\n            USHORT WerInShipAssertCode : 1;\n            USHORT RanProcessInit : 1;\n            USHORT ClonedThread : 1;\n            USHORT SuppressDebugMsg : 1;\n            USHORT DisableUserStackWalk : 1;\n            USHORT RtlExceptionAttached : 1;\n            USHORT InitialThread : 1;\n            USHORT SessionAware : 1;\n            USHORT LoadOwner : 1;\n            USHORT LoaderWorker : 1;\n            USHORT SkipLoaderInit : 1;\n            USHORT SpareSameTebBits : 1;\n        };\n    };\n\n    PVOID TxnScopeEnterCallback;\n    PVOID TxnScopeExitCallback;\n    PVOID TxnScopeContext;\n    ULONG LockCount;\n    LONG WowTebOffset;\n    PVOID ResourceRetValue;\n    PVOID ReservedForWdf;\n    ULONGLONG ReservedForCrt;\n    GUID EffectiveContainerId;\n} TEB, *PTEB;\n\n#endif\n"
  },
  {
    "path": "third_party/phnt/include/ntpfapi.h",
    "content": "#ifndef _NTPFAPI_H\n#define _NTPFAPI_H\n\n// begin_private\n\n// Prefetch\n\ntypedef enum _PF_BOOT_PHASE_ID\n{\n    PfKernelInitPhase = 0,\n    PfBootDriverInitPhase = 90,\n    PfSystemDriverInitPhase = 120,\n    PfSessionManagerInitPhase = 150,\n    PfSMRegistryInitPhase = 180,\n    PfVideoInitPhase = 210,\n    PfPostVideoInitPhase = 240,\n    PfBootAcceptedRegistryInitPhase = 270,\n    PfUserShellReadyPhase = 300,\n    PfMaxBootPhaseId = 900\n} PF_BOOT_PHASE_ID;\n\ntypedef enum _PF_ENABLE_STATUS\n{\n    PfSvNotSpecified,\n    PfSvEnabled,\n    PfSvDisabled,\n    PfSvMaxEnableStatus\n} PF_ENABLE_STATUS;\n\ntypedef struct _PF_TRACE_LIMITS\n{\n    ULONG MaxNumPages;\n    ULONG MaxNumSections;\n    LONGLONG TimerPeriod;\n} PF_TRACE_LIMITS, *PPF_TRACE_LIMITS;\n\ntypedef struct _PF_SYSTEM_PREFETCH_PARAMETERS\n{\n    PF_ENABLE_STATUS EnableStatus[2];\n    PF_TRACE_LIMITS TraceLimits[2];\n    ULONG MaxNumActiveTraces;\n    ULONG MaxNumSavedTraces;\n    WCHAR RootDirPath[32];\n    WCHAR HostingApplicationList[128];\n} PF_SYSTEM_PREFETCH_PARAMETERS, *PPF_SYSTEM_PREFETCH_PARAMETERS;\n\n#define PF_BOOT_CONTROL_VERSION 1\n\ntypedef struct _PF_BOOT_CONTROL\n{\n    ULONG Version;\n    ULONG DisableBootPrefetching;\n} PF_BOOT_CONTROL, *PPF_BOOT_CONTROL;\n\ntypedef enum _PREFETCHER_INFORMATION_CLASS\n{\n    PrefetcherRetrieveTrace = 1, // q: CHAR[]\n    PrefetcherSystemParameters, // q: PF_SYSTEM_PREFETCH_PARAMETERS\n    PrefetcherBootPhase, // s: PF_BOOT_PHASE_ID\n    PrefetcherRetrieveBootLoaderTrace, // q: CHAR[]\n    PrefetcherBootControl // s: PF_BOOT_CONTROL\n} PREFETCHER_INFORMATION_CLASS;\n\n#define PREFETCHER_INFORMATION_VERSION 23 // rev\n#define PREFETCHER_INFORMATION_MAGIC ('kuhC') // rev\n\ntypedef struct _PREFETCHER_INFORMATION\n{\n    ULONG Version;\n    ULONG Magic;\n    PREFETCHER_INFORMATION_CLASS PrefetcherInformationClass;\n    PVOID PrefetcherInformation;\n    ULONG PrefetcherInformationLength;\n} PREFETCHER_INFORMATION, *PPREFETCHER_INFORMATION;\n\n// Superfetch\n\ntypedef struct _PF_SYSTEM_SUPERFETCH_PARAMETERS\n{\n    ULONG EnabledComponents;\n    ULONG BootID;\n    ULONG SavedSectInfoTracesMax;\n    ULONG SavedPageAccessTracesMax;\n    ULONG ScenarioPrefetchTimeoutStandby;\n    ULONG ScenarioPrefetchTimeoutHibernate;\n} PF_SYSTEM_SUPERFETCH_PARAMETERS, *PPF_SYSTEM_SUPERFETCH_PARAMETERS;\n\n#define PF_PFN_PRIO_REQUEST_VERSION 1\n#define PF_PFN_PRIO_REQUEST_QUERY_MEMORY_LIST 0x1\n#define PF_PFN_PRIO_REQUEST_VALID_FLAGS 0x1\n\ntypedef struct _PF_PFN_PRIO_REQUEST\n{\n    ULONG Version;\n    ULONG RequestFlags;\n    ULONG_PTR PfnCount;\n    SYSTEM_MEMORY_LIST_INFORMATION MemInfo;\n    MMPFN_IDENTITY PageData[256];\n} PF_PFN_PRIO_REQUEST, *PPF_PFN_PRIO_REQUEST;\n\ntypedef enum _PFS_PRIVATE_PAGE_SOURCE_TYPE\n{\n    PfsPrivateSourceKernel,\n    PfsPrivateSourceSession,\n    PfsPrivateSourceProcess,\n    PfsPrivateSourceMax\n} PFS_PRIVATE_PAGE_SOURCE_TYPE;\n\ntypedef struct _PFS_PRIVATE_PAGE_SOURCE\n{\n    PFS_PRIVATE_PAGE_SOURCE_TYPE Type;\n    union\n    {\n        ULONG SessionId;\n        ULONG ProcessId;\n    };\n    ULONG ImagePathHash;\n    ULONG_PTR UniqueProcessHash;\n} PFS_PRIVATE_PAGE_SOURCE, *PPFS_PRIVATE_PAGE_SOURCE;\n\ntypedef struct _PF_PRIVSOURCE_INFO\n{\n    PFS_PRIVATE_PAGE_SOURCE DbInfo;\n    PVOID EProcess;\n    SIZE_T WsPrivatePages;\n    SIZE_T TotalPrivatePages;\n    ULONG SessionID;\n    CHAR ImageName[16];\n    union {\n        ULONG_PTR WsSwapPages;                 // process only PF_PRIVSOURCE_QUERY_WS_SWAP_PAGES.\n        ULONG_PTR SessionPagedPoolPages;       // session only.\n        ULONG_PTR StoreSizePages;              // process only PF_PRIVSOURCE_QUERY_STORE_INFO.\n    };\n    ULONG_PTR WsTotalPages;         // process/session only.\n    ULONG DeepFreezeTimeMs;         // process only.\n    ULONG ModernApp : 1;            // process only.\n    ULONG DeepFrozen : 1;           // process only. If set, DeepFreezeTimeMs contains the time at which the freeze occurred\n    ULONG Foreground : 1;           // process only.\n    ULONG PerProcessStore : 1;      // process only.\n    ULONG Spare : 28;\n} PF_PRIVSOURCE_INFO, *PPF_PRIVSOURCE_INFO;\n\n#define PF_PRIVSOURCE_QUERY_REQUEST_VERSION 3\n\ntypedef struct _PF_PRIVSOURCE_QUERY_REQUEST\n{\n    ULONG Version;\n    ULONG Flags;\n    ULONG InfoCount;\n    PF_PRIVSOURCE_INFO InfoArray[1];\n} PF_PRIVSOURCE_QUERY_REQUEST, *PPF_PRIVSOURCE_QUERY_REQUEST;\n\ntypedef enum _PF_PHASED_SCENARIO_TYPE\n{\n    PfScenarioTypeNone,\n    PfScenarioTypeStandby,\n    PfScenarioTypeHibernate,\n    PfScenarioTypeFUS,\n    PfScenarioTypeMax\n} PF_PHASED_SCENARIO_TYPE;\n\n#define PF_SCENARIO_PHASE_INFO_VERSION 4\n\ntypedef struct _PF_SCENARIO_PHASE_INFO\n{\n    ULONG Version;\n    PF_PHASED_SCENARIO_TYPE ScenType;\n    ULONG PhaseId;\n    ULONG SequenceNumber;\n    ULONG Flags;\n    ULONG FUSUserId;\n} PF_SCENARIO_PHASE_INFO, *PPF_SCENARIO_PHASE_INFO;\n\ntypedef struct _PF_MEMORY_LIST_NODE\n{\n    ULONGLONG Node : 8;\n    ULONGLONG Spare : 56;\n    ULONGLONG StandbyLowPageCount;\n    ULONGLONG StandbyMediumPageCount;\n    ULONGLONG StandbyHighPageCount;\n    ULONGLONG FreePageCount;\n    ULONGLONG ModifiedPageCount;\n} PF_MEMORY_LIST_NODE, *PPF_MEMORY_LIST_NODE;\n\n#define PF_MEMORY_LIST_INFO_VERSION 1\n\ntypedef struct _PF_MEMORY_LIST_INFO\n{\n    ULONG Version;\n    ULONG Size;\n    ULONG NodeCount;\n    PF_MEMORY_LIST_NODE Nodes[1];\n} PF_MEMORY_LIST_INFO, *PPF_MEMORY_LIST_INFO;\n\ntypedef struct _PF_PHYSICAL_MEMORY_RANGE\n{\n    ULONG_PTR BasePfn;\n    ULONG_PTR PageCount;\n} PF_PHYSICAL_MEMORY_RANGE, *PPF_PHYSICAL_MEMORY_RANGE;\n\n#define PF_PHYSICAL_MEMORY_RANGE_INFO_VERSION 1\n\ntypedef struct _PF_PHYSICAL_MEMORY_RANGE_INFO\n{\n    ULONG Version;\n    ULONG RangeCount;\n    PF_PHYSICAL_MEMORY_RANGE Ranges[1];\n} PF_PHYSICAL_MEMORY_RANGE_INFO, *PPF_PHYSICAL_MEMORY_RANGE_INFO;\n\n// begin_rev\n\n#define PF_REPURPOSED_BY_PREFETCH_INFO_VERSION 1\n\ntypedef struct _PF_REPURPOSED_BY_PREFETCH_INFO\n{\n    ULONG Version;\n    ULONG RepurposedByPrefetch;\n} PF_REPURPOSED_BY_PREFETCH_INFO, *PPF_REPURPOSED_BY_PREFETCH_INFO;\n\n// end_rev\n\ntypedef enum _SUPERFETCH_INFORMATION_CLASS\n{\n    SuperfetchRetrieveTrace = 1, // q: CHAR[]\n    SuperfetchSystemParameters, // q: PF_SYSTEM_SUPERFETCH_PARAMETERS\n    SuperfetchLogEvent,\n    SuperfetchGenerateTrace,\n    SuperfetchPrefetch,\n    SuperfetchPfnQuery, // q: PF_PFN_PRIO_REQUEST\n    SuperfetchPfnSetPriority,\n    SuperfetchPrivSourceQuery, // q: PF_PRIVSOURCE_QUERY_REQUEST\n    SuperfetchSequenceNumberQuery, // q: ULONG\n    SuperfetchScenarioPhase, // 10\n    SuperfetchWorkerPriority,\n    SuperfetchScenarioQuery, // q: PF_SCENARIO_PHASE_INFO\n    SuperfetchScenarioPrefetch,\n    SuperfetchRobustnessControl,\n    SuperfetchTimeControl,\n    SuperfetchMemoryListQuery, // q: PF_MEMORY_LIST_INFO\n    SuperfetchMemoryRangesQuery, // q: PF_PHYSICAL_MEMORY_RANGE_INFO\n    SuperfetchTracingControl,\n    SuperfetchTrimWhileAgingControl,\n    SuperfetchRepurposedByPrefetch, // q: PF_REPURPOSED_BY_PREFETCH_INFO // rev\n    SuperfetchInformationMax\n} SUPERFETCH_INFORMATION_CLASS;\n\n#define SUPERFETCH_INFORMATION_VERSION 45 // rev\n#define SUPERFETCH_INFORMATION_MAGIC ('kuhC') // rev\n\ntypedef struct _SUPERFETCH_INFORMATION\n{\n    _In_ ULONG Version;\n    _In_ ULONG Magic;\n    _In_ SUPERFETCH_INFORMATION_CLASS InfoClass;\n    _Inout_ PVOID Data;\n    _Inout_ ULONG Length;\n} SUPERFETCH_INFORMATION, *PSUPERFETCH_INFORMATION;\n\n// end_private\n\n#endif\n"
  },
  {
    "path": "third_party/phnt/include/ntpnpapi.h",
    "content": "#ifndef _NTPNPAPI_H\n#define _NTPNPAPI_H\n\ntypedef enum _PLUGPLAY_EVENT_CATEGORY\n{\n    HardwareProfileChangeEvent,\n    TargetDeviceChangeEvent,\n    DeviceClassChangeEvent,\n    CustomDeviceEvent,\n    DeviceInstallEvent,\n    DeviceArrivalEvent,\n    PowerEvent,\n    VetoEvent,\n    BlockedDriverEvent,\n    InvalidIDEvent,\n    MaxPlugEventCategory\n} PLUGPLAY_EVENT_CATEGORY, *PPLUGPLAY_EVENT_CATEGORY;\n\ntypedef struct _PLUGPLAY_EVENT_BLOCK\n{\n    GUID EventGuid;\n    PLUGPLAY_EVENT_CATEGORY EventCategory;\n    PULONG Result;\n    ULONG Flags;\n    ULONG TotalSize;\n    PVOID DeviceObject;\n\n    union\n    {\n        struct\n        {\n            GUID ClassGuid;\n            WCHAR SymbolicLinkName[1];\n        } DeviceClass;\n        struct\n        {\n            WCHAR DeviceIds[1];\n        } TargetDevice;\n        struct\n        {\n            WCHAR DeviceId[1];\n        } InstallDevice;\n        struct\n        {\n            PVOID NotificationStructure;\n            WCHAR DeviceIds[1];\n        } CustomNotification;\n        struct\n        {\n            PVOID Notification;\n        } ProfileNotification;\n        struct\n        {\n            ULONG NotificationCode;\n            ULONG NotificationData;\n        } PowerNotification;\n        struct\n        {\n            PNP_VETO_TYPE VetoType;\n            WCHAR DeviceIdVetoNameBuffer[1]; // DeviceId<null>VetoName<null><null>\n        } VetoNotification;\n        struct\n        {\n            GUID BlockedDriverGuid;\n        } BlockedDriverNotification;\n        struct\n        {\n            WCHAR ParentId[1];\n        } InvalidIDNotification;\n    } u;\n} PLUGPLAY_EVENT_BLOCK, *PPLUGPLAY_EVENT_BLOCK;\n\ntypedef enum _PLUGPLAY_CONTROL_CLASS\n{\n    PlugPlayControlEnumerateDevice,\n    PlugPlayControlRegisterNewDevice,\n    PlugPlayControlDeregisterDevice,\n    PlugPlayControlInitializeDevice,\n    PlugPlayControlStartDevice,\n    PlugPlayControlUnlockDevice,\n    PlugPlayControlQueryAndRemoveDevice,\n    PlugPlayControlUserResponse,\n    PlugPlayControlGenerateLegacyDevice,\n    PlugPlayControlGetInterfaceDeviceList,\n    PlugPlayControlProperty,\n    PlugPlayControlDeviceClassAssociation,\n    PlugPlayControlGetRelatedDevice,\n    PlugPlayControlGetInterfaceDeviceAlias,\n    PlugPlayControlDeviceStatus,\n    PlugPlayControlGetDeviceDepth,\n    PlugPlayControlQueryDeviceRelations,\n    PlugPlayControlTargetDeviceRelation,\n    PlugPlayControlQueryConflictList,\n    PlugPlayControlRetrieveDock,\n    PlugPlayControlResetDevice,\n    PlugPlayControlHaltDevice,\n    PlugPlayControlGetBlockedDriverList,\n    PlugPlayControlGetDeviceInterfaceEnabled,\n    MaxPlugPlayControl\n} PLUGPLAY_CONTROL_CLASS, *PPLUGPLAY_CONTROL_CLASS;\n\n#if (PHNT_VERSION < PHNT_WIN8)\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtGetPlugPlayEvent(\n    _In_ HANDLE EventHandle,\n    _In_opt_ PVOID Context,\n    _Out_writes_bytes_(EventBufferSize) PPLUGPLAY_EVENT_BLOCK EventBlock,\n    _In_ ULONG EventBufferSize\n    );\n#endif\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtPlugPlayControl(\n    _In_ PLUGPLAY_CONTROL_CLASS PnPControlClass,\n    _Inout_updates_bytes_(PnPControlDataLength) PVOID PnPControlData,\n    _In_ ULONG PnPControlDataLength\n    );\n\n#if (PHNT_VERSION >= PHNT_WIN7)\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtSerializeBoot(\n    VOID\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtEnableLastKnownGood(\n    VOID\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtDisableLastKnownGood(\n    VOID\n    );\n\n#endif\n\n#if (PHNT_VERSION >= PHNT_VISTA)\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtReplacePartitionUnit(\n    _In_ PUNICODE_STRING TargetInstancePath,\n    _In_ PUNICODE_STRING SpareInstancePath,\n    _In_ ULONG Flags\n    );\n#endif\n\n#endif\n"
  },
  {
    "path": "third_party/phnt/include/ntpoapi.h",
    "content": "#ifndef _NTPOAPI_H\n#define _NTPOAPI_H\n\ntypedef union _POWER_STATE\n{\n    SYSTEM_POWER_STATE SystemState;\n    DEVICE_POWER_STATE DeviceState;\n} POWER_STATE, *PPOWER_STATE;\n\ntypedef enum _POWER_STATE_TYPE\n{\n    SystemPowerState = 0,\n    DevicePowerState\n} POWER_STATE_TYPE, *PPOWER_STATE_TYPE;\n\n#if (PHNT_VERSION >= PHNT_VISTA)\n// wdm\ntypedef struct _SYSTEM_POWER_STATE_CONTEXT\n{\n    union\n    {\n        struct\n        {\n            ULONG Reserved1 : 8;\n            ULONG TargetSystemState : 4;\n            ULONG EffectiveSystemState : 4;\n            ULONG CurrentSystemState : 4;\n            ULONG IgnoreHibernationPath : 1;\n            ULONG PseudoTransition : 1;\n            ULONG Reserved2 : 10;\n        };\n        ULONG ContextAsUlong;\n    };\n} SYSTEM_POWER_STATE_CONTEXT, *PSYSTEM_POWER_STATE_CONTEXT;\n#endif\n\n#if (PHNT_VERSION >= PHNT_WIN7)\n/** \\cond NEVER */ // disable doxygen warning\n// wdm\ntypedef struct _COUNTED_REASON_CONTEXT\n{\n    ULONG Version;\n    ULONG Flags;\n    union\n    {\n        struct\n        {\n            UNICODE_STRING ResourceFileName;\n            USHORT ResourceReasonId;\n            ULONG StringCount;\n            PUNICODE_STRING _Field_size_(StringCount) ReasonStrings;\n        };\n        UNICODE_STRING SimpleString;\n    };\n} COUNTED_REASON_CONTEXT, *PCOUNTED_REASON_CONTEXT;\n/** \\endcond */\n#endif\n\ntypedef enum\n{\n    PowerStateSleeping1 = 0,\n    PowerStateSleeping2 = 1,\n    PowerStateSleeping3 = 2,\n    PowerStateSleeping4 = 3,\n    PowerStateShutdownOff = 4,\n    PowerStateShutdownReset = 5,\n    PowerStateSleeping4Firmware = 6,\n    PowerStateMaximum = 7\n} POWER_STATE_HANDLER_TYPE, *PPOWER_STATE_HANDLER_TYPE;\n\ntypedef NTSTATUS (NTAPI *PENTER_STATE_SYSTEM_HANDLER)(\n    _In_ PVOID SystemContext\n    );\n\ntypedef NTSTATUS (NTAPI *PENTER_STATE_HANDLER)(\n    _In_ PVOID Context,\n    _In_opt_ PENTER_STATE_SYSTEM_HANDLER SystemHandler,\n    _In_ PVOID SystemContext,\n    _In_ LONG NumberProcessors,\n    _In_ volatile PLONG Number\n    );\n\ntypedef struct _POWER_STATE_HANDLER\n{\n    POWER_STATE_HANDLER_TYPE Type;\n    BOOLEAN RtcWake;\n    UCHAR Spare[3];\n    PENTER_STATE_HANDLER Handler;\n    PVOID Context;\n} POWER_STATE_HANDLER, *PPOWER_STATE_HANDLER;\n\ntypedef NTSTATUS (NTAPI *PENTER_STATE_NOTIFY_HANDLER)(\n    _In_ POWER_STATE_HANDLER_TYPE State,\n    _In_ PVOID Context,\n    _In_ BOOLEAN Entering\n    );\n\ntypedef struct _POWER_STATE_NOTIFY_HANDLER\n{\n    PENTER_STATE_NOTIFY_HANDLER Handler;\n    PVOID Context;\n} POWER_STATE_NOTIFY_HANDLER, *PPOWER_STATE_NOTIFY_HANDLER;\n\ntypedef struct _PROCESSOR_POWER_INFORMATION\n{\n    ULONG Number;\n    ULONG MaxMhz;\n    ULONG CurrentMhz;\n    ULONG MhzLimit;\n    ULONG MaxIdleState;\n    ULONG CurrentIdleState;\n} PROCESSOR_POWER_INFORMATION, *PPROCESSOR_POWER_INFORMATION;\n\ntypedef struct _SYSTEM_POWER_INFORMATION\n{\n    ULONG MaxIdlenessAllowed;\n    ULONG Idleness;\n    ULONG TimeRemaining;\n    UCHAR CoolingMode;\n} SYSTEM_POWER_INFORMATION, *PSYSTEM_POWER_INFORMATION;\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtPowerInformation(\n    _In_ POWER_INFORMATION_LEVEL InformationLevel,\n    _In_reads_bytes_opt_(InputBufferLength) PVOID InputBuffer,\n    _In_ ULONG InputBufferLength,\n    _Out_writes_bytes_opt_(OutputBufferLength) PVOID OutputBuffer,\n    _In_ ULONG OutputBufferLength\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtSetThreadExecutionState(\n    _In_ EXECUTION_STATE NewFlags, // ES_* flags\n    _Out_ EXECUTION_STATE *PreviousFlags\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtRequestWakeupLatency(\n    _In_ LATENCY_TIME latency\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtInitiatePowerAction(\n    _In_ POWER_ACTION SystemAction,\n    _In_ SYSTEM_POWER_STATE LightestSystemState,\n    _In_ ULONG Flags, // POWER_ACTION_* flags\n    _In_ BOOLEAN Asynchronous\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtSetSystemPowerState(\n    _In_ POWER_ACTION SystemAction,\n    _In_ SYSTEM_POWER_STATE LightestSystemState,\n    _In_ ULONG Flags // POWER_ACTION_* flags\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtGetDevicePowerState(\n    _In_ HANDLE Device,\n    _Out_ PDEVICE_POWER_STATE State\n    );\n\nNTSYSCALLAPI\nBOOLEAN\nNTAPI\nNtIsSystemResumeAutomatic(\n    VOID\n    );\n\n#endif\n"
  },
  {
    "path": "third_party/phnt/include/ntpsapi.h",
    "content": "#ifndef _NTPSAPI_H\n#define _NTPSAPI_H\n\n#if (PHNT_MODE == PHNT_MODE_KERNEL)\n#define PROCESS_TERMINATE 0x0001\n#define PROCESS_CREATE_THREAD 0x0002\n#define PROCESS_SET_SESSIONID 0x0004\n#define PROCESS_VM_OPERATION 0x0008\n#define PROCESS_VM_READ 0x0010\n#define PROCESS_VM_WRITE 0x0020\n#define PROCESS_CREATE_PROCESS 0x0080\n#define PROCESS_SET_QUOTA 0x0100\n#define PROCESS_SET_INFORMATION 0x0200\n#define PROCESS_QUERY_INFORMATION 0x0400\n#define PROCESS_SET_PORT 0x0800\n#define PROCESS_SUSPEND_RESUME 0x0800\n#define PROCESS_QUERY_LIMITED_INFORMATION 0x1000\n#else\n#ifndef PROCESS_SET_PORT\n#define PROCESS_SET_PORT 0x0800\n#endif\n#endif\n\n#if (PHNT_MODE == PHNT_MODE_KERNEL)\n#define THREAD_QUERY_INFORMATION 0x0040\n#define THREAD_SET_THREAD_TOKEN 0x0080\n#define THREAD_IMPERSONATE 0x0100\n#define THREAD_DIRECT_IMPERSONATION 0x0200\n#else\n#ifndef THREAD_ALERT\n#define THREAD_ALERT 0x0004\n#endif\n#endif\n\n#if (PHNT_MODE == PHNT_MODE_KERNEL)\n#define JOB_OBJECT_ASSIGN_PROCESS 0x0001\n#define JOB_OBJECT_SET_ATTRIBUTES 0x0002\n#define JOB_OBJECT_QUERY 0x0004\n#define JOB_OBJECT_TERMINATE 0x0008\n#define JOB_OBJECT_SET_SECURITY_ATTRIBUTES 0x0010\n#define JOB_OBJECT_ALL_ACCESS (STANDARD_RIGHTS_REQUIRED | SYNCHRONIZE | 0x1f)\n#endif\n\n#define GDI_HANDLE_BUFFER_SIZE32 34\n#define GDI_HANDLE_BUFFER_SIZE64 60\n\n#ifndef WIN64\n#define GDI_HANDLE_BUFFER_SIZE GDI_HANDLE_BUFFER_SIZE32\n#else\n#define GDI_HANDLE_BUFFER_SIZE GDI_HANDLE_BUFFER_SIZE64\n#endif\n\ntypedef ULONG GDI_HANDLE_BUFFER[GDI_HANDLE_BUFFER_SIZE];\n\ntypedef ULONG GDI_HANDLE_BUFFER32[GDI_HANDLE_BUFFER_SIZE32];\ntypedef ULONG GDI_HANDLE_BUFFER64[GDI_HANDLE_BUFFER_SIZE64];\n\n#define FLS_MAXIMUM_AVAILABLE_OLD 128\n#define TLS_MINIMUM_AVAILABLE 64\n#define TLS_EXPANSION_SLOTS 1024\n\n// symbols\ntypedef struct _PEB_LDR_DATA\n{\n    ULONG Length;\n    BOOLEAN Initialized;\n    HANDLE SsHandle;\n    LIST_ENTRY InLoadOrderModuleList;\n    LIST_ENTRY InMemoryOrderModuleList;\n    LIST_ENTRY InInitializationOrderModuleList;\n    PVOID EntryInProgress;\n    BOOLEAN ShutdownInProgress;\n    HANDLE ShutdownThreadId;\n} PEB_LDR_DATA, *PPEB_LDR_DATA;\n\ntypedef struct _INITIAL_TEB\n{\n    struct\n    {\n        PVOID OldStackBase;\n        PVOID OldStackLimit;\n    } OldInitialTeb;\n    PVOID StackBase;\n    PVOID StackLimit;\n    PVOID StackAllocationBase;\n} INITIAL_TEB, *PINITIAL_TEB;\n\ntypedef struct _WOW64_PROCESS\n{\n    PVOID Wow64;\n} WOW64_PROCESS, *PWOW64_PROCESS;\n\n#include <ntpebteb.h>\n\n// source:http://www.microsoft.com/whdc/system/Sysinternals/MoreThan64proc.mspx\n\n#if (PHNT_MODE != PHNT_MODE_KERNEL)\ntypedef enum _PROCESSINFOCLASS\n{\n    ProcessBasicInformation, // q: PROCESS_BASIC_INFORMATION, PROCESS_EXTENDED_BASIC_INFORMATION\n    ProcessQuotaLimits, // qs: QUOTA_LIMITS, QUOTA_LIMITS_EX\n    ProcessIoCounters, // q: IO_COUNTERS\n    ProcessVmCounters, // q: VM_COUNTERS, VM_COUNTERS_EX, VM_COUNTERS_EX2\n    ProcessTimes, // q: KERNEL_USER_TIMES\n    ProcessBasePriority, // s: KPRIORITY\n    ProcessRaisePriority, // s: ULONG\n    ProcessDebugPort, // q: HANDLE\n    ProcessExceptionPort, // s: HANDLE\n    ProcessAccessToken, // s: PROCESS_ACCESS_TOKEN\n    ProcessLdtInformation, // qs: PROCESS_LDT_INFORMATION // 10\n    ProcessLdtSize, // s: PROCESS_LDT_SIZE\n    ProcessDefaultHardErrorMode, // qs: ULONG\n    ProcessIoPortHandlers, // (kernel-mode only)\n    ProcessPooledUsageAndLimits, // q: POOLED_USAGE_AND_LIMITS\n    ProcessWorkingSetWatch, // q: PROCESS_WS_WATCH_INFORMATION[]; s: void\n    ProcessUserModeIOPL,\n    ProcessEnableAlignmentFaultFixup, // s: BOOLEAN\n    ProcessPriorityClass, // qs: PROCESS_PRIORITY_CLASS\n    ProcessWx86Information,\n    ProcessHandleCount, // q: ULONG, PROCESS_HANDLE_INFORMATION // 20\n    ProcessAffinityMask, // s: KAFFINITY\n    ProcessPriorityBoost, // qs: ULONG\n    ProcessDeviceMap, // qs: PROCESS_DEVICEMAP_INFORMATION, PROCESS_DEVICEMAP_INFORMATION_EX\n    ProcessSessionInformation, // q: PROCESS_SESSION_INFORMATION\n    ProcessForegroundInformation, // s: PROCESS_FOREGROUND_BACKGROUND\n    ProcessWow64Information, // q: ULONG_PTR\n    ProcessImageFileName, // q: UNICODE_STRING\n    ProcessLUIDDeviceMapsEnabled, // q: ULONG\n    ProcessBreakOnTermination, // qs: ULONG\n    ProcessDebugObjectHandle, // q: HANDLE // 30\n    ProcessDebugFlags, // qs: ULONG\n    ProcessHandleTracing, // q: PROCESS_HANDLE_TRACING_QUERY; s: size 0 disables, otherwise enables\n    ProcessIoPriority, // qs: IO_PRIORITY_HINT\n    ProcessExecuteFlags, // qs: ULONG\n    ProcessResourceManagement,\n    ProcessCookie, // q: ULONG\n    ProcessImageInformation, // q: SECTION_IMAGE_INFORMATION\n    ProcessCycleTime, // q: PROCESS_CYCLE_TIME_INFORMATION // since VISTA\n    ProcessPagePriority, // q: ULONG\n    ProcessInstrumentationCallback, // 40\n    ProcessThreadStackAllocation, // s: PROCESS_STACK_ALLOCATION_INFORMATION, PROCESS_STACK_ALLOCATION_INFORMATION_EX\n    ProcessWorkingSetWatchEx, // q: PROCESS_WS_WATCH_INFORMATION_EX[]\n    ProcessImageFileNameWin32, // q: UNICODE_STRING\n    ProcessImageFileMapping, // q: HANDLE (input)\n    ProcessAffinityUpdateMode, // qs: PROCESS_AFFINITY_UPDATE_MODE\n    ProcessMemoryAllocationMode, // qs: PROCESS_MEMORY_ALLOCATION_MODE\n    ProcessGroupInformation, // q: USHORT[]\n    ProcessTokenVirtualizationEnabled, // s: ULONG\n    ProcessConsoleHostProcess, // q: ULONG_PTR\n    ProcessWindowInformation, // q: PROCESS_WINDOW_INFORMATION // 50\n    ProcessHandleInformation, // q: PROCESS_HANDLE_SNAPSHOT_INFORMATION // since WIN8\n    ProcessMitigationPolicy, // s: PROCESS_MITIGATION_POLICY_INFORMATION\n    ProcessDynamicFunctionTableInformation,\n    ProcessHandleCheckingMode,\n    ProcessKeepAliveCount, // q: PROCESS_KEEPALIVE_COUNT_INFORMATION\n    ProcessRevokeFileHandles, // s: PROCESS_REVOKE_FILE_HANDLES_INFORMATION\n    ProcessWorkingSetControl, // s: PROCESS_WORKING_SET_CONTROL\n    ProcessHandleTable, // since WINBLUE\n    ProcessCheckStackExtentsMode,\n    ProcessCommandLineInformation, // q: UNICODE_STRING // 60\n    ProcessProtectionInformation, // q: PS_PROTECTION\n    ProcessMemoryExhaustion, // PROCESS_MEMORY_EXHAUSTION_INFO // since THRESHOLD\n    ProcessFaultInformation, // PROCESS_FAULT_INFORMATION\n    ProcessTelemetryIdInformation, // PROCESS_TELEMETRY_ID_INFORMATION\n    ProcessCommitReleaseInformation, // PROCESS_COMMIT_RELEASE_INFORMATION\n    ProcessDefaultCpuSetsInformation,\n    ProcessAllowedCpuSetsInformation,\n    ProcessSubsystemProcess,\n    ProcessJobMemoryInformation, // PROCESS_JOB_MEMORY_INFO\n    ProcessInPrivate, // since THRESHOLD2 // 70\n    ProcessRaiseUMExceptionOnInvalidHandleClose,\n    ProcessIumChallengeResponse,\n    ProcessChildProcessInformation, // PROCESS_CHILD_PROCESS_INFORMATION\n    ProcessHighGraphicsPriorityInformation,\n    ProcessSubsystemInformation, // q: SUBSYSTEM_INFORMATION_TYPE // since REDSTONE2\n    ProcessEnergyValues, // PROCESS_ENERGY_VALUES, PROCESS_EXTENDED_ENERGY_VALUES\n    ProcessActivityThrottleState, // PROCESS_ACTIVITY_THROTTLE_STATE\n    ProcessActivityThrottlePolicy, // PROCESS_ACTIVITY_THROTTLE_POLICY\n    ProcessWin32kSyscallFilterInformation,\n    ProcessDisableSystemAllowedCpuSets,\n    ProcessWakeInformation, // PROCESS_WAKE_INFORMATION\n    ProcessEnergyTrackingState, // PROCESS_ENERGY_TRACKING_STATE\n    ProcessManageWritesToExecutableMemory, // MANAGE_WRITES_TO_EXECUTABLE_MEMORY // since REDSTONE3\n    ProcessCaptureTrustletLiveDump,\n    ProcessTelemetryCoverage,\n    ProcessEnclaveInformation,\n    ProcessEnableReadWriteVmLogging, // PROCESS_READWRITEVM_LOGGING_INFORMATION\n    ProcessUptimeInformation, // PROCESS_UPTIME_INFORMATION\n    ProcessImageSection,\n    MaxProcessInfoClass\n} PROCESSINFOCLASS;\n#endif\n\n#if (PHNT_MODE != PHNT_MODE_KERNEL)\ntypedef enum _THREADINFOCLASS\n{\n    ThreadBasicInformation, // q: THREAD_BASIC_INFORMATION\n    ThreadTimes, // q: KERNEL_USER_TIMES\n    ThreadPriority, // s: KPRIORITY\n    ThreadBasePriority, // s: LONG\n    ThreadAffinityMask, // s: KAFFINITY\n    ThreadImpersonationToken, // s: HANDLE\n    ThreadDescriptorTableEntry, // q: DESCRIPTOR_TABLE_ENTRY (or WOW64_DESCRIPTOR_TABLE_ENTRY)\n    ThreadEnableAlignmentFaultFixup, // s: BOOLEAN\n    ThreadEventPair,\n    ThreadQuerySetWin32StartAddress, // q: PVOID\n    ThreadZeroTlsCell, // 10\n    ThreadPerformanceCount, // q: LARGE_INTEGER\n    ThreadAmILastThread, // q: ULONG\n    ThreadIdealProcessor, // s: ULONG\n    ThreadPriorityBoost, // qs: ULONG\n    ThreadSetTlsArrayAddress,\n    ThreadIsIoPending, // q: ULONG\n    ThreadHideFromDebugger, // s: void\n    ThreadBreakOnTermination, // qs: ULONG\n    ThreadSwitchLegacyState,\n    ThreadIsTerminated, // q: ULONG // 20\n    ThreadLastSystemCall, // q: THREAD_LAST_SYSCALL_INFORMATION\n    ThreadIoPriority, // qs: IO_PRIORITY_HINT\n    ThreadCycleTime, // q: THREAD_CYCLE_TIME_INFORMATION\n    ThreadPagePriority, // q: ULONG\n    ThreadActualBasePriority,\n    ThreadTebInformation, // q: THREAD_TEB_INFORMATION (requires THREAD_GET_CONTEXT + THREAD_SET_CONTEXT)\n    ThreadCSwitchMon,\n    ThreadCSwitchPmu,\n    ThreadWow64Context, // q: WOW64_CONTEXT\n    ThreadGroupInformation, // q: GROUP_AFFINITY // 30\n    ThreadUmsInformation, // q: THREAD_UMS_INFORMATION\n    ThreadCounterProfiling,\n    ThreadIdealProcessorEx, // q: PROCESSOR_NUMBER\n    ThreadCpuAccountingInformation, // since WIN8\n    ThreadSuspendCount, // since WINBLUE\n    ThreadHeterogeneousCpuPolicy, // q: KHETERO_CPU_POLICY // since THRESHOLD\n    ThreadContainerId, // q: GUID\n    ThreadNameInformation, // qs: THREAD_NAME_INFORMATION\n    ThreadSelectedCpuSets,\n    ThreadSystemThreadInformation, // q: SYSTEM_THREAD_INFORMATION // 40\n    ThreadActualGroupAffinity, // since THRESHOLD2\n    ThreadDynamicCodePolicyInfo,\n    ThreadExplicitCaseSensitivity,\n    ThreadWorkOnBehalfTicket,\n    ThreadSubsystemInformation, // q: SUBSYSTEM_INFORMATION_TYPE // since REDSTONE2\n    ThreadDbgkWerReportActive,\n    ThreadAttachContainer,\n    ThreadManageWritesToExecutableMemory, // MANAGE_WRITES_TO_EXECUTABLE_MEMORY // since REDSTONE3\n    ThreadPowerThrottlingState, // THREAD_POWER_THROTTLING_STATE\n    MaxThreadInfoClass\n} THREADINFOCLASS;\n#endif\n\n#if (PHNT_MODE != PHNT_MODE_KERNEL)\n// Use with both ProcessPagePriority and ThreadPagePriority\ntypedef struct _PAGE_PRIORITY_INFORMATION\n{\n    ULONG PagePriority;\n} PAGE_PRIORITY_INFORMATION, *PPAGE_PRIORITY_INFORMATION;\n#endif\n\n// Process information structures\n\n#if (PHNT_MODE != PHNT_MODE_KERNEL)\n\ntypedef struct _PROCESS_BASIC_INFORMATION\n{\n    NTSTATUS ExitStatus;\n    PPEB PebBaseAddress;\n    ULONG_PTR AffinityMask;\n    KPRIORITY BasePriority;\n    HANDLE UniqueProcessId;\n    HANDLE InheritedFromUniqueProcessId;\n} PROCESS_BASIC_INFORMATION, *PPROCESS_BASIC_INFORMATION;\n\ntypedef struct _PROCESS_EXTENDED_BASIC_INFORMATION\n{\n    SIZE_T Size; // set to sizeof structure on input\n    PROCESS_BASIC_INFORMATION BasicInfo;\n    union\n    {\n        ULONG Flags;\n        struct\n        {\n            ULONG IsProtectedProcess : 1;\n            ULONG IsWow64Process : 1;\n            ULONG IsProcessDeleting : 1;\n            ULONG IsCrossSessionCreate : 1;\n            ULONG IsFrozen : 1;\n            ULONG IsBackground : 1;\n            ULONG IsStronglyNamed : 1;\n            ULONG IsSecureProcess : 1;\n            ULONG IsSubsystemProcess : 1;\n            ULONG SpareBits : 23;\n        };\n    };\n} PROCESS_EXTENDED_BASIC_INFORMATION, *PPROCESS_EXTENDED_BASIC_INFORMATION;\n\ntypedef struct _VM_COUNTERS\n{\n    SIZE_T PeakVirtualSize;\n    SIZE_T VirtualSize;\n    ULONG PageFaultCount;\n    SIZE_T PeakWorkingSetSize;\n    SIZE_T WorkingSetSize;\n    SIZE_T QuotaPeakPagedPoolUsage;\n    SIZE_T QuotaPagedPoolUsage;\n    SIZE_T QuotaPeakNonPagedPoolUsage;\n    SIZE_T QuotaNonPagedPoolUsage;\n    SIZE_T PagefileUsage;\n    SIZE_T PeakPagefileUsage;\n} VM_COUNTERS, *PVM_COUNTERS;\n\ntypedef struct _VM_COUNTERS_EX\n{\n    SIZE_T PeakVirtualSize;\n    SIZE_T VirtualSize;\n    ULONG PageFaultCount;\n    SIZE_T PeakWorkingSetSize;\n    SIZE_T WorkingSetSize;\n    SIZE_T QuotaPeakPagedPoolUsage;\n    SIZE_T QuotaPagedPoolUsage;\n    SIZE_T QuotaPeakNonPagedPoolUsage;\n    SIZE_T QuotaNonPagedPoolUsage;\n    SIZE_T PagefileUsage;\n    SIZE_T PeakPagefileUsage;\n    SIZE_T PrivateUsage;\n} VM_COUNTERS_EX, *PVM_COUNTERS_EX;\n\n// private\ntypedef struct _VM_COUNTERS_EX2\n{\n    VM_COUNTERS_EX CountersEx;\n    SIZE_T PrivateWorkingSetSize;\n    SIZE_T SharedCommitUsage;\n} VM_COUNTERS_EX2, *PVM_COUNTERS_EX2;\n\ntypedef struct _KERNEL_USER_TIMES\n{\n    LARGE_INTEGER CreateTime;\n    LARGE_INTEGER ExitTime;\n    LARGE_INTEGER KernelTime;\n    LARGE_INTEGER UserTime;\n} KERNEL_USER_TIMES, *PKERNEL_USER_TIMES;\n\ntypedef struct _POOLED_USAGE_AND_LIMITS\n{\n    SIZE_T PeakPagedPoolUsage;\n    SIZE_T PagedPoolUsage;\n    SIZE_T PagedPoolLimit;\n    SIZE_T PeakNonPagedPoolUsage;\n    SIZE_T NonPagedPoolUsage;\n    SIZE_T NonPagedPoolLimit;\n    SIZE_T PeakPagefileUsage;\n    SIZE_T PagefileUsage;\n    SIZE_T PagefileLimit;\n} POOLED_USAGE_AND_LIMITS, *PPOOLED_USAGE_AND_LIMITS;\n\ntypedef struct _PROCESS_ACCESS_TOKEN\n{\n    HANDLE Token; // needs TOKEN_ASSIGN_PRIMARY access\n    HANDLE Thread; // handle to initial/only thread; needs THREAD_QUERY_INFORMATION access\n} PROCESS_ACCESS_TOKEN, *PPROCESS_ACCESS_TOKEN;\n\ntypedef struct _PROCESS_LDT_INFORMATION\n{\n    ULONG Start;\n    ULONG Length;\n    LDT_ENTRY LdtEntries[1];\n} PROCESS_LDT_INFORMATION, *PPROCESS_LDT_INFORMATION;\n\ntypedef struct _PROCESS_LDT_SIZE\n{\n    ULONG Length;\n} PROCESS_LDT_SIZE, *PPROCESS_LDT_SIZE;\n\ntypedef struct _PROCESS_WS_WATCH_INFORMATION\n{\n    PVOID FaultingPc;\n    PVOID FaultingVa;\n} PROCESS_WS_WATCH_INFORMATION, *PPROCESS_WS_WATCH_INFORMATION;\n\n#endif\n\n// psapi:PSAPI_WS_WATCH_INFORMATION_EX\ntypedef struct _PROCESS_WS_WATCH_INFORMATION_EX\n{\n    PROCESS_WS_WATCH_INFORMATION BasicInfo;\n    ULONG_PTR FaultingThreadId;\n    ULONG_PTR Flags;\n} PROCESS_WS_WATCH_INFORMATION_EX, *PPROCESS_WS_WATCH_INFORMATION_EX;\n\n#define PROCESS_PRIORITY_CLASS_UNKNOWN 0\n#define PROCESS_PRIORITY_CLASS_IDLE 1\n#define PROCESS_PRIORITY_CLASS_NORMAL 2\n#define PROCESS_PRIORITY_CLASS_HIGH 3\n#define PROCESS_PRIORITY_CLASS_REALTIME 4\n#define PROCESS_PRIORITY_CLASS_BELOW_NORMAL 5\n#define PROCESS_PRIORITY_CLASS_ABOVE_NORMAL 6\n\ntypedef struct _PROCESS_PRIORITY_CLASS\n{\n    BOOLEAN Foreground;\n    UCHAR PriorityClass;\n} PROCESS_PRIORITY_CLASS, *PPROCESS_PRIORITY_CLASS;\n\ntypedef struct _PROCESS_FOREGROUND_BACKGROUND\n{\n    BOOLEAN Foreground;\n} PROCESS_FOREGROUND_BACKGROUND, *PPROCESS_FOREGROUND_BACKGROUND;\n\n#if (PHNT_MODE != PHNT_MODE_KERNEL)\n\ntypedef struct _PROCESS_DEVICEMAP_INFORMATION\n{\n    union\n    {\n        struct\n        {\n            HANDLE DirectoryHandle;\n        } Set;\n        struct\n        {\n            ULONG DriveMap;\n            UCHAR DriveType[32];\n        } Query;\n    };\n} PROCESS_DEVICEMAP_INFORMATION, *PPROCESS_DEVICEMAP_INFORMATION;\n\n#define PROCESS_LUID_DOSDEVICES_ONLY 0x00000001\n\ntypedef struct _PROCESS_DEVICEMAP_INFORMATION_EX\n{\n    union\n    {\n        struct\n        {\n            HANDLE DirectoryHandle;\n        } Set;\n        struct\n        {\n            ULONG DriveMap;\n            UCHAR DriveType[32];\n        } Query;\n    };\n    ULONG Flags; // PROCESS_LUID_DOSDEVICES_ONLY\n} PROCESS_DEVICEMAP_INFORMATION_EX, *PPROCESS_DEVICEMAP_INFORMATION_EX;\n\ntypedef struct _PROCESS_SESSION_INFORMATION\n{\n    ULONG SessionId;\n} PROCESS_SESSION_INFORMATION, *PPROCESS_SESSION_INFORMATION;\n\n#define PROCESS_HANDLE_RAISE_EXCEPTION_ON_INVALID_HANDLE_CLOSE_DISABLED 0x00000000\n#define PROCESS_HANDLE_RAISE_EXCEPTION_ON_INVALID_HANDLE_CLOSE_ENABLED 0x00000001\n\ntypedef struct _PROCESS_HANDLE_TRACING_ENABLE\n{\n    ULONG Flags;\n} PROCESS_HANDLE_TRACING_ENABLE, *PPROCESS_HANDLE_TRACING_ENABLE;\n\n#define PROCESS_HANDLE_TRACING_MAX_SLOTS 0x20000\n\ntypedef struct _PROCESS_HANDLE_TRACING_ENABLE_EX\n{\n    ULONG Flags;\n    ULONG TotalSlots;\n} PROCESS_HANDLE_TRACING_ENABLE_EX, *PPROCESS_HANDLE_TRACING_ENABLE_EX;\n\n#define PROCESS_HANDLE_TRACING_MAX_STACKS 16\n\n#define PROCESS_HANDLE_TRACE_TYPE_OPEN 1\n#define PROCESS_HANDLE_TRACE_TYPE_CLOSE 2\n#define PROCESS_HANDLE_TRACE_TYPE_BADREF 3\n\ntypedef struct _PROCESS_HANDLE_TRACING_ENTRY\n{\n    HANDLE Handle;\n    CLIENT_ID ClientId;\n    ULONG Type;\n    PVOID Stacks[PROCESS_HANDLE_TRACING_MAX_STACKS];\n} PROCESS_HANDLE_TRACING_ENTRY, *PPROCESS_HANDLE_TRACING_ENTRY;\n\ntypedef struct _PROCESS_HANDLE_TRACING_QUERY\n{\n    HANDLE Handle;\n    ULONG TotalTraces;\n    PROCESS_HANDLE_TRACING_ENTRY HandleTrace[1];\n} PROCESS_HANDLE_TRACING_QUERY, *PPROCESS_HANDLE_TRACING_QUERY;\n\n#endif\n\n// private\ntypedef struct _PROCESS_STACK_ALLOCATION_INFORMATION\n{\n    SIZE_T ReserveSize;\n    SIZE_T ZeroBits;\n    PVOID StackBase;\n} PROCESS_STACK_ALLOCATION_INFORMATION, *PPROCESS_STACK_ALLOCATION_INFORMATION;\n\n// private\ntypedef struct _PROCESS_STACK_ALLOCATION_INFORMATION_EX\n{\n    ULONG PreferredNode;\n    ULONG Reserved0;\n    ULONG Reserved1;\n    ULONG Reserved2;\n    PROCESS_STACK_ALLOCATION_INFORMATION AllocInfo;\n} PROCESS_STACK_ALLOCATION_INFORMATION_EX, *PPROCESS_STACK_ALLOCATION_INFORMATION_EX;\n\n// private\ntypedef union _PROCESS_AFFINITY_UPDATE_MODE\n{\n    ULONG Flags;\n    struct\n    {\n        ULONG EnableAutoUpdate : 1;\n        ULONG Permanent : 1;\n        ULONG Reserved : 30;\n    };\n} PROCESS_AFFINITY_UPDATE_MODE, *PPROCESS_AFFINITY_UPDATE_MODE;\n\n// private\ntypedef union _PROCESS_MEMORY_ALLOCATION_MODE\n{\n    ULONG Flags;\n    struct\n    {\n        ULONG TopDown : 1;\n        ULONG Reserved : 31;\n    };\n} PROCESS_MEMORY_ALLOCATION_MODE, *PPROCESS_MEMORY_ALLOCATION_MODE;\n\n// private\ntypedef struct _PROCESS_HANDLE_INFORMATION\n{\n    ULONG HandleCount;\n    ULONG HandleCountHighWatermark;\n} PROCESS_HANDLE_INFORMATION, *PPROCESS_HANDLE_INFORMATION;\n\n// private\ntypedef struct _PROCESS_CYCLE_TIME_INFORMATION\n{\n    ULONGLONG AccumulatedCycles;\n    ULONGLONG CurrentCycleCount;\n} PROCESS_CYCLE_TIME_INFORMATION, *PPROCESS_CYCLE_TIME_INFORMATION;\n\n// private\ntypedef struct _PROCESS_WINDOW_INFORMATION\n{\n    ULONG WindowFlags;\n    USHORT WindowTitleLength;\n    WCHAR WindowTitle[1];\n} PROCESS_WINDOW_INFORMATION, *PPROCESS_WINDOW_INFORMATION;\n\n// private\ntypedef struct _PROCESS_HANDLE_TABLE_ENTRY_INFO\n{\n    HANDLE HandleValue;\n    ULONG_PTR HandleCount;\n    ULONG_PTR PointerCount;\n    ULONG GrantedAccess;\n    ULONG ObjectTypeIndex;\n    ULONG HandleAttributes;\n    ULONG Reserved;\n} PROCESS_HANDLE_TABLE_ENTRY_INFO, *PPROCESS_HANDLE_TABLE_ENTRY_INFO;\n\n// private\ntypedef struct _PROCESS_HANDLE_SNAPSHOT_INFORMATION\n{\n    ULONG_PTR NumberOfHandles;\n    ULONG_PTR Reserved;\n    PROCESS_HANDLE_TABLE_ENTRY_INFO Handles[1];\n} PROCESS_HANDLE_SNAPSHOT_INFORMATION, *PPROCESS_HANDLE_SNAPSHOT_INFORMATION;\n\n#if (PHNT_MODE != PHNT_MODE_KERNEL)\n\n// private\ntypedef struct _PROCESS_MITIGATION_POLICY_INFORMATION\n{\n    PROCESS_MITIGATION_POLICY Policy;\n    union\n    {\n        PROCESS_MITIGATION_ASLR_POLICY ASLRPolicy;\n        PROCESS_MITIGATION_STRICT_HANDLE_CHECK_POLICY StrictHandleCheckPolicy;\n        PROCESS_MITIGATION_SYSTEM_CALL_DISABLE_POLICY SystemCallDisablePolicy;\n        PROCESS_MITIGATION_EXTENSION_POINT_DISABLE_POLICY ExtensionPointDisablePolicy;\n        PROCESS_MITIGATION_DYNAMIC_CODE_POLICY DynamicCodePolicy;\n        PROCESS_MITIGATION_CONTROL_FLOW_GUARD_POLICY ControlFlowGuardPolicy;\n        PROCESS_MITIGATION_BINARY_SIGNATURE_POLICY SignaturePolicy;\n        PROCESS_MITIGATION_FONT_DISABLE_POLICY FontDisablePolicy;\n        PROCESS_MITIGATION_IMAGE_LOAD_POLICY ImageLoadPolicy;\n        PROCESS_MITIGATION_SYSTEM_CALL_FILTER_POLICY SystemCallFilterPolicy;\n        PROCESS_MITIGATION_PAYLOAD_RESTRICTION_POLICY PayloadRestrictionPolicy;\n        PROCESS_MITIGATION_CHILD_PROCESS_POLICY ChildProcessPolicy;\n    };\n} PROCESS_MITIGATION_POLICY_INFORMATION, *PPROCESS_MITIGATION_POLICY_INFORMATION;\n\ntypedef struct _PROCESS_KEEPALIVE_COUNT_INFORMATION\n{\n    ULONG WakeCount;\n    ULONG NoWakeCount;\n} PROCESS_KEEPALIVE_COUNT_INFORMATION, *PPROCESS_KEEPALIVE_COUNT_INFORMATION;\n\ntypedef struct _PROCESS_REVOKE_FILE_HANDLES_INFORMATION\n{\n    UNICODE_STRING TargetDevicePath;\n} PROCESS_REVOKE_FILE_HANDLES_INFORMATION, *PPROCESS_REVOKE_FILE_HANDLES_INFORMATION;\n\n// begin_private\n\ntypedef enum _PROCESS_WORKING_SET_OPERATION\n{\n    ProcessWorkingSetSwap,\n    ProcessWorkingSetEmpty,\n    ProcessWorkingSetOperationMax\n} PROCESS_WORKING_SET_OPERATION;\n\ntypedef struct _PROCESS_WORKING_SET_CONTROL\n{\n    ULONG Version;\n    PROCESS_WORKING_SET_OPERATION Operation;\n    ULONG Flags;\n} PROCESS_WORKING_SET_CONTROL, *PPROCESS_WORKING_SET_CONTROL;\n\ntypedef enum _PS_PROTECTED_TYPE\n{\n    PsProtectedTypeNone,\n    PsProtectedTypeProtectedLight,\n    PsProtectedTypeProtected,\n    PsProtectedTypeMax\n} PS_PROTECTED_TYPE;\n\ntypedef enum _PS_PROTECTED_SIGNER\n{\n    PsProtectedSignerNone,\n    PsProtectedSignerAuthenticode,\n    PsProtectedSignerCodeGen,\n    PsProtectedSignerAntimalware,\n    PsProtectedSignerLsa,\n    PsProtectedSignerWindows,\n    PsProtectedSignerWinTcb,\n    PsProtectedSignerWinSystem,\n    PsProtectedSignerApp,\n    PsProtectedSignerMax\n} PS_PROTECTED_SIGNER;\n\n#define PS_PROTECTED_SIGNER_MASK 0xFF\n#define PS_PROTECTED_AUDIT_MASK 0x08\n#define PS_PROTECTED_TYPE_MASK 0x07\n\n// vProtectionLevel.Level = PsProtectedValue(PsProtectedSignerCodeGen, FALSE, PsProtectedTypeProtectedLight)\n#define PsProtectedValue(aSigner, aAudit, aType) ( \\\n    ((aSigner & PS_PROTECTED_SIGNER_MASK) << 4) | \\\n    ((aAudit & PS_PROTECTED_AUDIT_MASK) << 3) | \\\n    (aType & PS_PROTECTED_TYPE_MASK)\\\n    )\n\n// InitializePsProtection(&vProtectionLevel, PsProtectedSignerCodeGen, FALSE, PsProtectedTypeProtectedLight)\n#define InitializePsProtection(aProtectionLevelPtr, aSigner, aAudit, aType) { \\\n    (aProtectionLevelPtr)->Signer = aSigner; \\\n    (aProtectionLevelPtr)->Audit = aAudit; \\\n    (aProtectionLevelPtr)->Type = aType; \\\n    }\n\ntypedef struct _PS_PROTECTION\n{\n    union\n    {\n        UCHAR Level;\n        struct\n        {\n            UCHAR Type : 3;\n            UCHAR Audit : 1;\n            UCHAR Signer : 4;\n        };\n    };\n} PS_PROTECTION, *PPS_PROTECTION;\n\ntypedef struct _PROCESS_FAULT_INFORMATION\n{\n    ULONG FaultFlags;\n    ULONG AdditionalInfo;\n} PROCESS_FAULT_INFORMATION, *PPROCESS_FAULT_INFORMATION;\n\ntypedef struct _PROCESS_TELEMETRY_ID_INFORMATION\n{\n    ULONG HeaderSize;\n    ULONG ProcessId;\n    ULONGLONG ProcessStartKey;\n    ULONGLONG CreateTime;\n    ULONGLONG CreateInterruptTime;\n    ULONGLONG CreateUnbiasedInterruptTime;\n    ULONGLONG ProcessSequenceNumber;\n    ULONGLONG SessionCreateTime;\n    ULONG SessionId;\n    ULONG BootId;\n    ULONG ImageChecksum;\n    ULONG ImageTimeDateStamp;\n    ULONG UserSidOffset;\n    ULONG ImagePathOffset;\n    ULONG PackageNameOffset;\n    ULONG RelativeAppNameOffset;\n    ULONG CommandLineOffset;\n} PROCESS_TELEMETRY_ID_INFORMATION, *PPROCESS_TELEMETRY_ID_INFORMATION;\n\ntypedef struct _PROCESS_COMMIT_RELEASE_INFORMATION\n{\n    ULONG Version;\n    struct\n    {\n        ULONG Eligible : 1;\n        ULONG ReleaseRepurposedMemResetCommit : 1;\n        ULONG ForceReleaseMemResetCommit : 1;\n        ULONG Spare : 29;\n    };\n    SIZE_T CommitDebt;\n    SIZE_T CommittedMemResetSize;\n    SIZE_T RepurposedMemResetSize;\n} PROCESS_COMMIT_RELEASE_INFORMATION, *PPROCESS_COMMIT_RELEASE_INFORMATION;\n\ntypedef struct _PROCESS_JOB_MEMORY_INFO\n{\n    ULONGLONG SharedCommitUsage;\n    ULONGLONG PrivateCommitUsage;\n    ULONGLONG PeakPrivateCommitUsage;\n    ULONGLONG PrivateCommitLimit;\n    ULONGLONG TotalCommitLimit;\n} PROCESS_JOB_MEMORY_INFO, *PPROCESS_JOB_MEMORY_INFO;\n\ntypedef struct _PROCESS_CHILD_PROCESS_INFORMATION\n{\n    BOOLEAN ProhibitChildProcesses;\n    //BOOLEAN EnableAutomaticOverride; // REDSTONE2\n    BOOLEAN AlwaysAllowSecureChildProcess; // REDSTONE3\n    BOOLEAN AuditProhibitChildProcesses;\n} PROCESS_CHILD_PROCESS_INFORMATION, *PPROCESS_CHILD_PROCESS_INFORMATION;\n\ntypedef struct _PROCESS_WAKE_INFORMATION\n{\n    ULONGLONG NotificationChannel;\n    ULONG WakeCounters[7];\n    struct _JOBOBJECT_WAKE_FILTER* WakeFilter;\n} PROCESS_WAKE_INFORMATION, *PPROCESS_WAKE_INFORMATION;\n\ntypedef struct _PROCESS_ENERGY_TRACKING_STATE\n{\n    ULONG StateUpdateMask;\n    ULONG StateDesiredValue;\n    ULONG StateSequence;\n    ULONG UpdateTag : 1;\n    WCHAR Tag[64];\n} PROCESS_ENERGY_TRACKING_STATE, *PPROCESS_ENERGY_TRACKING_STATE;\n\ntypedef struct _MANAGE_WRITES_TO_EXECUTABLE_MEMORY\n{\n    ULONG Version : 8;\n    ULONG ProcessEnableWriteExceptions : 1;\n    ULONG ThreadAllowWrites : 1;\n    ULONG Spare : 22;\n} MANAGE_WRITES_TO_EXECUTABLE_MEMORY, *PMANAGE_WRITES_TO_EXECUTABLE_MEMORY;\n\ntypedef struct _PROCESS_READWRITEVM_LOGGING_INFORMATION\n{\n    union\n    {\n        BOOLEAN Flags;\n        struct\n        {\n            BOOLEAN EnableReadVmLogging : 1;\n            BOOLEAN EnableWriteVmLogging : 1;\n            BOOLEAN Unused : 6;\n        };\n    };\n} PROCESS_READWRITEVM_LOGGING_INFORMATION, *PPROCESS_READWRITEVM_LOGGING_INFORMATION;\n\ntypedef struct _PROCESS_UPTIME_INFORMATION\n{\n    ULONGLONG QueryInterruptTime;\n    ULONGLONG QueryUnbiasedTime;\n    ULONGLONG EndInterruptTime;\n    ULONGLONG TimeSinceCreation;\n    ULONGLONG Uptime;\n    ULONGLONG SuspendedTime;\n    union\n    {\n        ULONG HangCount : 4;\n        ULONG GhostCount : 4;\n        ULONG Crashed : 1;\n        ULONG Terminated : 1;       \n    };\n} PROCESS_UPTIME_INFORMATION, *PPROCESS_UPTIME_INFORMATION;\n\n// end_private\n\n#endif\n\n// Thread information structures\n\ntypedef struct _THREAD_BASIC_INFORMATION\n{\n    NTSTATUS ExitStatus;\n    PTEB TebBaseAddress;\n    CLIENT_ID ClientId;\n    ULONG_PTR AffinityMask;\n    KPRIORITY Priority;\n    LONG BasePriority;\n} THREAD_BASIC_INFORMATION, *PTHREAD_BASIC_INFORMATION;\n\n// private\ntypedef struct _THREAD_LAST_SYSCALL_INFORMATION\n{\n    PVOID FirstArgument;\n    USHORT SystemCallNumber;\n    //USHORT Reserved; // since REDSTONE2\n    //ULONG64 WaitTime;\n} THREAD_LAST_SYSCALL_INFORMATION, *PTHREAD_LAST_SYSCALL_INFORMATION;\n\n// private\ntypedef struct _THREAD_CYCLE_TIME_INFORMATION\n{\n    ULONGLONG AccumulatedCycles;\n    ULONGLONG CurrentCycleCount;\n} THREAD_CYCLE_TIME_INFORMATION, *PTHREAD_CYCLE_TIME_INFORMATION;\n\n// private\ntypedef struct _THREAD_TEB_INFORMATION\n{\n    PVOID TebInformation; // buffer to place data in\n    ULONG TebOffset; // offset in TEB to begin reading from\n    ULONG BytesToRead; // number of bytes to read\n} THREAD_TEB_INFORMATION, *PTHREAD_TEB_INFORMATION;\n\n// symbols\ntypedef struct _COUNTER_READING\n{\n    HARDWARE_COUNTER_TYPE Type;\n    ULONG Index;\n    ULONG64 Start;\n    ULONG64 Total;\n} COUNTER_READING, *PCOUNTER_READING;\n\n// symbols\ntypedef struct _THREAD_PERFORMANCE_DATA\n{\n    USHORT Size;\n    USHORT Version;\n    PROCESSOR_NUMBER ProcessorNumber;\n    ULONG ContextSwitches;\n    ULONG HwCountersCount;\n    ULONG64 UpdateCount;\n    ULONG64 WaitReasonBitMap;\n    ULONG64 HardwareCounters;\n    COUNTER_READING CycleTime;\n    COUNTER_READING HwCounters[MAX_HW_COUNTERS];\n} THREAD_PERFORMANCE_DATA, *PTHREAD_PERFORMANCE_DATA;\n\n// private\ntypedef struct _THREAD_PROFILING_INFORMATION\n{\n    ULONG64 HardwareCounters;\n    ULONG Flags;\n    ULONG Enable;\n    PTHREAD_PERFORMANCE_DATA PerformanceData;\n} THREAD_PROFILING_INFORMATION, *PTHREAD_PROFILING_INFORMATION;\n\n// private\ntypedef struct _RTL_UMS_CONTEXT\n{\n    SINGLE_LIST_ENTRY Link;\n    CONTEXT Context;\n    PVOID Teb;\n    PVOID UserContext;\n    volatile ULONG ScheduledThread;\n    volatile ULONG Suspended;\n    volatile ULONG VolatileContext;\n    volatile ULONG Terminated;\n    volatile ULONG DebugActive;\n    volatile ULONG RunningOnSelfThread;\n    volatile ULONG DenyRunningOnSelfThread;\n    volatile LONG Flags;\n    volatile ULONG64 KernelUpdateLock;\n    volatile ULONG64 PrimaryClientID;\n    volatile ULONG64 ContextLock;\n    struct _RTL_UMS_CONTEXT* PrimaryUmsContext;\n    ULONG SwitchCount;\n    ULONG KernelYieldCount;\n    ULONG MixedYieldCount;\n    ULONG YieldCount;\n} RTL_UMS_CONTEXT, *PRTL_UMS_CONTEXT;\n\n// private\ntypedef enum _THREAD_UMS_INFORMATION_COMMAND\n{\n    UmsInformationCommandInvalid,\n    UmsInformationCommandAttach,\n    UmsInformationCommandDetach,\n    UmsInformationCommandQuery\n} THREAD_UMS_INFORMATION_COMMAND;\n\n// private\ntypedef struct _RTL_UMS_COMPLETION_LIST\n{\n    PSINGLE_LIST_ENTRY ThreadListHead;\n    PVOID CompletionEvent;\n    ULONG CompletionFlags;\n    SINGLE_LIST_ENTRY InternalListHead;\n} RTL_UMS_COMPLETION_LIST, *PRTL_UMS_COMPLETION_LIST;\n\n// private\ntypedef struct _THREAD_UMS_INFORMATION\n{\n    THREAD_UMS_INFORMATION_COMMAND Command;\n    PRTL_UMS_COMPLETION_LIST CompletionList;\n    PRTL_UMS_CONTEXT UmsContext;\n    ULONG Flags;\n    ULONG IsUmsSchedulerThread;\n    ULONG IsUmsWorkerThread;\n} THREAD_UMS_INFORMATION, *PTHREAD_UMS_INFORMATION;\n\n// private\ntypedef struct _THREAD_NAME_INFORMATION\n{\n    UNICODE_STRING ThreadName;\n} THREAD_NAME_INFORMATION, *PTHREAD_NAME_INFORMATION;\n\n// Processes\n\n#if (PHNT_MODE != PHNT_MODE_KERNEL)\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtCreateProcess(\n    _Out_ PHANDLE ProcessHandle,\n    _In_ ACCESS_MASK DesiredAccess,\n    _In_opt_ POBJECT_ATTRIBUTES ObjectAttributes,\n    _In_ HANDLE ParentProcess,\n    _In_ BOOLEAN InheritObjectTable,\n    _In_opt_ HANDLE SectionHandle,\n    _In_opt_ HANDLE DebugPort,\n    _In_opt_ HANDLE ExceptionPort\n    );\n\n#define PROCESS_CREATE_FLAGS_BREAKAWAY 0x00000001\n#define PROCESS_CREATE_FLAGS_NO_DEBUG_INHERIT 0x00000002\n#define PROCESS_CREATE_FLAGS_INHERIT_HANDLES 0x00000004\n#define PROCESS_CREATE_FLAGS_OVERRIDE_ADDRESS_SPACE 0x00000008\n#define PROCESS_CREATE_FLAGS_LARGE_PAGES 0x00000010\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtCreateProcessEx(\n    _Out_ PHANDLE ProcessHandle,\n    _In_ ACCESS_MASK DesiredAccess,\n    _In_opt_ POBJECT_ATTRIBUTES ObjectAttributes,\n    _In_ HANDLE ParentProcess,\n    _In_ ULONG Flags,\n    _In_opt_ HANDLE SectionHandle,\n    _In_opt_ HANDLE DebugPort,\n    _In_opt_ HANDLE ExceptionPort,\n    _In_ ULONG JobMemberLevel\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtOpenProcess(\n    _Out_ PHANDLE ProcessHandle,\n    _In_ ACCESS_MASK DesiredAccess,\n    _In_ POBJECT_ATTRIBUTES ObjectAttributes,\n    _In_opt_ PCLIENT_ID ClientId\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtTerminateProcess(\n    _In_opt_ HANDLE ProcessHandle,\n    _In_ NTSTATUS ExitStatus\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtSuspendProcess(\n    _In_ HANDLE ProcessHandle\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtResumeProcess(\n    _In_ HANDLE ProcessHandle\n    );\n\n#define NtCurrentProcess() ((HANDLE)(LONG_PTR)-1)\n#define ZwCurrentProcess() NtCurrentProcess()\n#define NtCurrentThread() ((HANDLE)(LONG_PTR)-2)\n#define ZwCurrentThread() NtCurrentThread()\n#define NtCurrentSession() ((HANDLE)(LONG_PTR)-3)\n#define ZwCurrentSession() NtCurrentSession()\n#define NtCurrentPeb() (NtCurrentTeb()->ProcessEnvironmentBlock)\n\n// Not NT, but useful.\n#define NtCurrentProcessId() (NtCurrentTeb()->ClientId.UniqueProcess)\n#define NtCurrentThreadId() (NtCurrentTeb()->ClientId.UniqueThread)\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtQueryInformationProcess(\n    _In_ HANDLE ProcessHandle,\n    _In_ PROCESSINFOCLASS ProcessInformationClass,\n    _Out_writes_bytes_(ProcessInformationLength) PVOID ProcessInformation,\n    _In_ ULONG ProcessInformationLength,\n    _Out_opt_ PULONG ReturnLength\n    );\n\n#if (PHNT_VERSION >= PHNT_WS03)\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtGetNextProcess(\n    _In_ HANDLE ProcessHandle,\n    _In_ ACCESS_MASK DesiredAccess,\n    _In_ ULONG HandleAttributes,\n    _In_ ULONG Flags,\n    _Out_ PHANDLE NewProcessHandle\n    );\n#endif\n\n#if (PHNT_VERSION >= PHNT_WS03)\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtGetNextThread(\n    _In_ HANDLE ProcessHandle,\n    _In_ HANDLE ThreadHandle,\n    _In_ ACCESS_MASK DesiredAccess,\n    _In_ ULONG HandleAttributes,\n    _In_ ULONG Flags,\n    _Out_ PHANDLE NewThreadHandle\n    );\n#endif\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtSetInformationProcess(\n    _In_ HANDLE ProcessHandle,\n    _In_ PROCESSINFOCLASS ProcessInformationClass,\n    _In_reads_bytes_(ProcessInformationLength) PVOID ProcessInformation,\n    _In_ ULONG ProcessInformationLength\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtQueryPortInformationProcess(\n    VOID\n    );\n\n#endif\n\n// Threads\n\n#if (PHNT_MODE != PHNT_MODE_KERNEL)\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtCreateThread(\n    _Out_ PHANDLE ThreadHandle,\n    _In_ ACCESS_MASK DesiredAccess,\n    _In_opt_ POBJECT_ATTRIBUTES ObjectAttributes,\n    _In_ HANDLE ProcessHandle,\n    _Out_ PCLIENT_ID ClientId,\n    _In_ PCONTEXT ThreadContext,\n    _In_ PINITIAL_TEB InitialTeb,\n    _In_ BOOLEAN CreateSuspended\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtOpenThread(\n    _Out_ PHANDLE ThreadHandle,\n    _In_ ACCESS_MASK DesiredAccess,\n    _In_ POBJECT_ATTRIBUTES ObjectAttributes,\n    _In_opt_ PCLIENT_ID ClientId\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtTerminateThread(\n    _In_opt_ HANDLE ThreadHandle,\n    _In_ NTSTATUS ExitStatus\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtSuspendThread(\n    _In_ HANDLE ThreadHandle,\n    _Out_opt_ PULONG PreviousSuspendCount\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtResumeThread(\n    _In_ HANDLE ThreadHandle,\n    _Out_opt_ PULONG PreviousSuspendCount\n    );\n\nNTSYSCALLAPI\nULONG\nNTAPI\nNtGetCurrentProcessorNumber(\n    VOID\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtGetContextThread(\n    _In_ HANDLE ThreadHandle,\n    _Inout_ PCONTEXT ThreadContext\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtSetContextThread(\n    _In_ HANDLE ThreadHandle,\n    _In_ PCONTEXT ThreadContext\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtQueryInformationThread(\n    _In_ HANDLE ThreadHandle,\n    _In_ THREADINFOCLASS ThreadInformationClass,\n    _Out_writes_bytes_(ThreadInformationLength) PVOID ThreadInformation,\n    _In_ ULONG ThreadInformationLength,\n    _Out_opt_ PULONG ReturnLength\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtSetInformationThread(\n    _In_ HANDLE ThreadHandle,\n    _In_ THREADINFOCLASS ThreadInformationClass,\n    _In_reads_bytes_(ThreadInformationLength) PVOID ThreadInformation,\n    _In_ ULONG ThreadInformationLength\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtAlertThread(\n    _In_ HANDLE ThreadHandle\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtAlertResumeThread(\n    _In_ HANDLE ThreadHandle,\n    _Out_opt_ PULONG PreviousSuspendCount\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtTestAlert(\n    VOID\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtImpersonateThread(\n    _In_ HANDLE ServerThreadHandle,\n    _In_ HANDLE ClientThreadHandle,\n    _In_ PSECURITY_QUALITY_OF_SERVICE SecurityQos\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtRegisterThreadTerminatePort(\n    _In_ HANDLE PortHandle\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtSetLdtEntries(\n    _In_ ULONG Selector0,\n    _In_ ULONG Entry0Low,\n    _In_ ULONG Entry0Hi,\n    _In_ ULONG Selector1,\n    _In_ ULONG Entry1Low,\n    _In_ ULONG Entry1Hi\n    );\n\ntypedef VOID (*PPS_APC_ROUTINE)(\n    _In_opt_ PVOID ApcArgument1,\n    _In_opt_ PVOID ApcArgument2,\n    _In_opt_ PVOID ApcArgument3\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtQueueApcThread(\n    _In_ HANDLE ThreadHandle,\n    _In_ PPS_APC_ROUTINE ApcRoutine,\n    _In_opt_ PVOID ApcArgument1,\n    _In_opt_ PVOID ApcArgument2,\n    _In_opt_ PVOID ApcArgument3\n    );\n\n#if (PHNT_VERSION >= PHNT_WIN7)\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtQueueApcThreadEx(\n    _In_ HANDLE ThreadHandle,\n    _In_opt_ HANDLE UserApcReserveHandle,\n    _In_ PPS_APC_ROUTINE ApcRoutine,\n    _In_opt_ PVOID ApcArgument1,\n    _In_opt_ PVOID ApcArgument2,\n    _In_opt_ PVOID ApcArgument3\n    );\n#endif\n\n#if (PHNT_VERSION >= PHNT_WIN8)\n\n// rev\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtAlertThreadByThreadId(\n    _In_ HANDLE ThreadId\n    );\n\n// rev\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtWaitForAlertByThreadId(\n    _In_ PVOID Address,\n    _In_opt_ PLARGE_INTEGER Timeout\n    );\n\n#endif\n\n#endif\n\n// User processes and threads\n\n#if (PHNT_MODE != PHNT_MODE_KERNEL)\n\n// Attributes\n\n// private\n#define PS_ATTRIBUTE_NUMBER_MASK 0x0000ffff\n#define PS_ATTRIBUTE_THREAD 0x00010000 // may be used with thread creation\n#define PS_ATTRIBUTE_INPUT 0x00020000 // input only\n#define PS_ATTRIBUTE_ADDITIVE 0x00040000 // \"accumulated\" e.g. bitmasks, counters, etc.\n\n// private\ntypedef enum _PS_ATTRIBUTE_NUM\n{\n    PsAttributeParentProcess, // in HANDLE\n    PsAttributeDebugPort, // in HANDLE\n    PsAttributeToken, // in HANDLE\n    PsAttributeClientId, // out PCLIENT_ID\n    PsAttributeTebAddress, // out PTEB *\n    PsAttributeImageName, // in PWSTR\n    PsAttributeImageInfo, // out PSECTION_IMAGE_INFORMATION\n    PsAttributeMemoryReserve, // in PPS_MEMORY_RESERVE\n    PsAttributePriorityClass, // in UCHAR\n    PsAttributeErrorMode, // in ULONG\n    PsAttributeStdHandleInfo, // 10, in PPS_STD_HANDLE_INFO\n    PsAttributeHandleList, // in PHANDLE\n    PsAttributeGroupAffinity, // in PGROUP_AFFINITY\n    PsAttributePreferredNode, // in PUSHORT\n    PsAttributeIdealProcessor, // in PPROCESSOR_NUMBER\n    PsAttributeUmsThread, // ? in PUMS_CREATE_THREAD_ATTRIBUTES\n    PsAttributeMitigationOptions, // in UCHAR\n    PsAttributeProtectionLevel, // in ULONG\n    PsAttributeSecureProcess, // since THRESHOLD\n    PsAttributeJobList,\n    PsAttributeChildProcessPolicy, // since THRESHOLD2\n    PsAttributeAllApplicationPackagesPolicy, // since REDSTONE\n    PsAttributeWin32kFilter,\n    PsAttributeSafeOpenPromptOriginClaim,\n    PsAttributeBnoIsolation, // PS_BNO_ISOLATION_PARAMETERS\n    PsAttributeDesktopAppPolicy, // in ULONG\n    PsAttributeChpe, // since REDSTONE3\n    PsAttributeMax\n} PS_ATTRIBUTE_NUM;\n\n// begin_rev\n\n#define PsAttributeValue(Number, Thread, Input, Additive) \\\n    (((Number) & PS_ATTRIBUTE_NUMBER_MASK) | \\\n    ((Thread) ? PS_ATTRIBUTE_THREAD : 0) | \\\n    ((Input) ? PS_ATTRIBUTE_INPUT : 0) | \\\n    ((Additive) ? PS_ATTRIBUTE_ADDITIVE : 0))\n\n#define PS_ATTRIBUTE_PARENT_PROCESS \\\n    PsAttributeValue(PsAttributeParentProcess, FALSE, TRUE, TRUE)\n#define PS_ATTRIBUTE_DEBUG_PORT \\\n    PsAttributeValue(PsAttributeDebugPort, FALSE, TRUE, TRUE)\n#define PS_ATTRIBUTE_TOKEN \\\n    PsAttributeValue(PsAttributeToken, FALSE, TRUE, TRUE)\n#define PS_ATTRIBUTE_CLIENT_ID \\\n    PsAttributeValue(PsAttributeClientId, TRUE, FALSE, FALSE)\n#define PS_ATTRIBUTE_TEB_ADDRESS \\\n    PsAttributeValue(PsAttributeTebAddress, TRUE, FALSE, FALSE)\n#define PS_ATTRIBUTE_IMAGE_NAME \\\n    PsAttributeValue(PsAttributeImageName, FALSE, TRUE, FALSE)\n#define PS_ATTRIBUTE_IMAGE_INFO \\\n    PsAttributeValue(PsAttributeImageInfo, FALSE, FALSE, FALSE)\n#define PS_ATTRIBUTE_MEMORY_RESERVE \\\n    PsAttributeValue(PsAttributeMemoryReserve, FALSE, TRUE, FALSE)\n#define PS_ATTRIBUTE_PRIORITY_CLASS \\\n    PsAttributeValue(PsAttributePriorityClass, FALSE, TRUE, FALSE)\n#define PS_ATTRIBUTE_ERROR_MODE \\\n    PsAttributeValue(PsAttributeErrorMode, FALSE, TRUE, FALSE)\n#define PS_ATTRIBUTE_STD_HANDLE_INFO \\\n    PsAttributeValue(PsAttributeStdHandleInfo, FALSE, TRUE, FALSE)\n#define PS_ATTRIBUTE_HANDLE_LIST \\\n    PsAttributeValue(PsAttributeHandleList, FALSE, TRUE, FALSE)\n#define PS_ATTRIBUTE_GROUP_AFFINITY \\\n    PsAttributeValue(PsAttributeGroupAffinity, TRUE, TRUE, FALSE)\n#define PS_ATTRIBUTE_PREFERRED_NODE \\\n    PsAttributeValue(PsAttributePreferredNode, FALSE, TRUE, FALSE)\n#define PS_ATTRIBUTE_IDEAL_PROCESSOR \\\n    PsAttributeValue(PsAttributeIdealProcessor, TRUE, TRUE, FALSE)\n#define PS_ATTRIBUTE_UMS_THREAD \\\n    PsAttributeValue(PsAttributeUmsThread, TRUE, TRUE, FALSE)\n#define PS_ATTRIBUTE_MITIGATION_OPTIONS \\\n    PsAttributeValue(PsAttributeMitigationOptions, FALSE, TRUE, TRUE)\n#define PS_ATTRIBUTE_PROTECTION_LEVEL \\\n    PsAttributeValue(PsAttributeProtectionLevel, FALSE, TRUE, TRUE)\n#define PS_ATTRIBUTE_SECURE_PROCESS \\\n    PsAttributeValue(PsAttributeSecureProcess, FALSE, TRUE, FALSE)\n#define PS_ATTRIBUTE_JOB_LIST \\\n    PsAttributeValue(PsAttributeJobList, FALSE, TRUE, FALSE)\n#define PS_ATTRIBUTE_CHILD_PROCESS_POLICY \\\n    PsAttributeValue(PsAttributeChildProcessPolicy, FALSE, TRUE, FALSE)\n#define PS_ATTRIBUTE_ALL_APPLICATION_PACKAGES_POLICY \\\n    PsAttributeValue(PsAttributeAllApplicationPackagesPolicy, FALSE, TRUE, FALSE)\n#define PS_ATTRIBUTE_WIN32K_FILTER \\\n    PsAttributeValue(PsAttributeWin32kFilter, FALSE, TRUE, FALSE)\n#define PS_ATTRIBUTE_SAFE_OPEN_PROMPT_ORIGIN_CLAIM \\\n    PsAttributeValue(PsAttributeSafeOpenPromptOriginClaim, FALSE, TRUE, FALSE)\n#define PS_ATTRIBUTE_BNO_ISOLATION \\\n    PsAttributeValue(PsAttributeBnoIsolation, FALSE, TRUE, FALSE)\n#define PS_ATTRIBUTE_DESKTOP_APP_POLICY \\\n    PsAttributeValue(PsAttributeDesktopAppPolicy, FALSE, TRUE, FALSE)\n\n// end_rev\n\n// begin_private\n\ntypedef struct _PS_ATTRIBUTE\n{\n    ULONG_PTR Attribute;\n    SIZE_T Size;\n    union\n    {\n        ULONG_PTR Value;\n        PVOID ValuePtr;\n    };\n    PSIZE_T ReturnLength;\n} PS_ATTRIBUTE, *PPS_ATTRIBUTE;\n\ntypedef struct _PS_ATTRIBUTE_LIST\n{\n    SIZE_T TotalLength;\n    PS_ATTRIBUTE Attributes[1];\n} PS_ATTRIBUTE_LIST, *PPS_ATTRIBUTE_LIST;\n\ntypedef struct _PS_MEMORY_RESERVE\n{\n    PVOID ReserveAddress;\n    SIZE_T ReserveSize;\n} PS_MEMORY_RESERVE, *PPS_MEMORY_RESERVE;\n\ntypedef enum _PS_STD_HANDLE_STATE\n{\n    PsNeverDuplicate,\n    PsRequestDuplicate, // duplicate standard handles specified by PseudoHandleMask, and only if StdHandleSubsystemType matches the image subsystem\n    PsAlwaysDuplicate, // always duplicate standard handles\n    PsMaxStdHandleStates\n} PS_STD_HANDLE_STATE;\n\n// begin_rev\n#define PS_STD_INPUT_HANDLE 0x1\n#define PS_STD_OUTPUT_HANDLE 0x2\n#define PS_STD_ERROR_HANDLE 0x4\n// end_rev\n\ntypedef struct _PS_STD_HANDLE_INFO\n{\n    union\n    {\n        ULONG Flags;\n        struct\n        {\n            ULONG StdHandleState : 2; // PS_STD_HANDLE_STATE\n            ULONG PseudoHandleMask : 3; // PS_STD_*\n        };\n    };\n    ULONG StdHandleSubsystemType;\n} PS_STD_HANDLE_INFO, *PPS_STD_HANDLE_INFO;\n\n// private\ntypedef struct _PS_BNO_ISOLATION_PARAMETERS\n{\n    UNICODE_STRING IsolationPrefix;\n    ULONG HandleCount;\n    PVOID *Handles;\n    BOOLEAN IsolationEnabled;\n} PS_BNO_ISOLATION_PARAMETERS, *PPS_BNO_ISOLATION_PARAMETERS;\n\n// private\ntypedef enum _PS_MITIGATION_OPTION\n{\n    PS_MITIGATION_OPTION_NX,\n    PS_MITIGATION_OPTION_SEHOP,\n    PS_MITIGATION_OPTION_FORCE_RELOCATE_IMAGES,\n    PS_MITIGATION_OPTION_HEAP_TERMINATE,\n    PS_MITIGATION_OPTION_BOTTOM_UP_ASLR,\n    PS_MITIGATION_OPTION_HIGH_ENTROPY_ASLR,\n    PS_MITIGATION_OPTION_STRICT_HANDLE_CHECKS,\n    PS_MITIGATION_OPTION_WIN32K_SYSTEM_CALL_DISABLE,\n    PS_MITIGATION_OPTION_EXTENSION_POINT_DISABLE,\n    PS_MITIGATION_OPTION_PROHIBIT_DYNAMIC_CODE,\n    PS_MITIGATION_OPTION_CONTROL_FLOW_GUARD,\n    PS_MITIGATION_OPTION_BLOCK_NON_MICROSOFT_BINARIES,\n    PS_MITIGATION_OPTION_FONT_DISABLE,\n    PS_MITIGATION_OPTION_IMAGE_LOAD_NO_REMOTE,\n    PS_MITIGATION_OPTION_IMAGE_LOAD_NO_LOW_LABEL,\n    PS_MITIGATION_OPTION_IMAGE_LOAD_PREFER_SYSTEM32,\n    PS_MITIGATION_OPTION_RETURN_FLOW_GUARD,\n    PS_MITIGATION_OPTION_LOADER_INTEGRITY_CONTINUITY,\n    PS_MITIGATION_OPTION_STRICT_CONTROL_FLOW_GUARD,\n    PS_MITIGATION_OPTION_RESTRICT_SET_THREAD_CONTEXT,\n    PS_MITIGATION_OPTION_ROP_STACKPIVOT, // since REDSTONE3\n    PS_MITIGATION_OPTION_ROP_CALLER_CHECK,\n    PS_MITIGATION_OPTION_ROP_SIMEXEC,\n    PS_MITIGATION_OPTION_EXPORT_ADDRESS_FILTER,\n    PS_MITIGATION_OPTION_EXPORT_ADDRESS_FILTER_PLUS,\n    PS_MITIGATION_OPTION_RESTRICT_CHILD_PROCESS_CREATION,\n    PS_MITIGATION_OPTION_IMPORT_ADDRESS_FILTER,\n    PS_MITIGATION_OPTION_MODULE_TAMPERING_PROTECTION\n} PS_MITIGATION_OPTION;\n\n// windows-internals-book:\"Chapter 5\"\ntypedef enum _PS_CREATE_STATE\n{\n    PsCreateInitialState,\n    PsCreateFailOnFileOpen,\n    PsCreateFailOnSectionCreate,\n    PsCreateFailExeFormat,\n    PsCreateFailMachineMismatch,\n    PsCreateFailExeName, // Debugger specified\n    PsCreateSuccess,\n    PsCreateMaximumStates\n} PS_CREATE_STATE;\n\ntypedef struct _PS_CREATE_INFO\n{\n    SIZE_T Size;\n    PS_CREATE_STATE State;\n    union\n    {\n        // PsCreateInitialState\n        struct\n        {\n            union\n            {\n                ULONG InitFlags;\n                struct\n                {\n                    UCHAR WriteOutputOnExit : 1;\n                    UCHAR DetectManifest : 1;\n                    UCHAR IFEOSkipDebugger : 1;\n                    UCHAR IFEODoNotPropagateKeyState : 1;\n                    UCHAR SpareBits1 : 4;\n                    UCHAR SpareBits2 : 8;\n                    USHORT ProhibitedImageCharacteristics : 16;\n                };\n            };\n            ACCESS_MASK AdditionalFileAccess;\n        } InitState;\n\n        // PsCreateFailOnSectionCreate\n        struct\n        {\n            HANDLE FileHandle;\n        } FailSection;\n\n        // PsCreateFailExeFormat\n        struct\n        {\n            USHORT DllCharacteristics;\n        } ExeFormat;\n\n        // PsCreateFailExeName\n        struct\n        {\n            HANDLE IFEOKey;\n        } ExeName;\n\n        // PsCreateSuccess\n        struct\n        {\n            union\n            {\n                ULONG OutputFlags;\n                struct\n                {\n                    UCHAR ProtectedProcess : 1;\n                    UCHAR AddressSpaceOverride : 1;\n                    UCHAR DevOverrideEnabled : 1; // from Image File Execution Options\n                    UCHAR ManifestDetected : 1;\n                    UCHAR ProtectedProcessLight : 1;\n                    UCHAR SpareBits1 : 3;\n                    UCHAR SpareBits2 : 8;\n                    USHORT SpareBits3 : 16;\n                };\n            };\n            HANDLE FileHandle;\n            HANDLE SectionHandle;\n            ULONGLONG UserProcessParametersNative;\n            ULONG UserProcessParametersWow64;\n            ULONG CurrentParameterFlags;\n            ULONGLONG PebAddressNative;\n            ULONG PebAddressWow64;\n            ULONGLONG ManifestAddress;\n            ULONG ManifestSize;\n        } SuccessState;\n    };\n} PS_CREATE_INFO, *PPS_CREATE_INFO;\n\n// end_private\n\n// begin_rev\n#define PROCESS_CREATE_FLAGS_BREAKAWAY 0x00000001\n#define PROCESS_CREATE_FLAGS_NO_DEBUG_INHERIT 0x00000002\n#define PROCESS_CREATE_FLAGS_INHERIT_HANDLES 0x00000004\n#define PROCESS_CREATE_FLAGS_OVERRIDE_ADDRESS_SPACE 0x00000008\n#define PROCESS_CREATE_FLAGS_LARGE_PAGES 0x00000010\n#define PROCESS_CREATE_FLAGS_LARGE_PAGE_SYSTEM_DLL 0x00000020\n// Extended PROCESS_CREATE_FLAGS_*\n#define PROCESS_CREATE_FLAGS_PROTECTED_PROCESS 0x00000040\n#define PROCESS_CREATE_FLAGS_CREATE_SESSION 0x00000080 // ?\n#define PROCESS_CREATE_FLAGS_INHERIT_FROM_PARENT 0x00000100\n#define PROCESS_CREATE_FLAGS_SUSPENDED 0x00000200\n#define PROCESS_CREATE_FLAGS_EXTENDED_UNKNOWN 0x00000400\n// end_rev\n\n#if (PHNT_VERSION >= PHNT_VISTA)\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtCreateUserProcess(\n    _Out_ PHANDLE ProcessHandle,\n    _Out_ PHANDLE ThreadHandle,\n    _In_ ACCESS_MASK ProcessDesiredAccess,\n    _In_ ACCESS_MASK ThreadDesiredAccess,\n    _In_opt_ POBJECT_ATTRIBUTES ProcessObjectAttributes,\n    _In_opt_ POBJECT_ATTRIBUTES ThreadObjectAttributes,\n    _In_ ULONG ProcessFlags, // PROCESS_CREATE_FLAGS_*\n    _In_ ULONG ThreadFlags, // THREAD_CREATE_FLAGS_*\n    _In_opt_ PVOID ProcessParameters, // PRTL_USER_PROCESS_PARAMETERS\n    _Inout_ PPS_CREATE_INFO CreateInfo,\n    _In_opt_ PPS_ATTRIBUTE_LIST AttributeList\n    );\n#endif\n\n// begin_rev\n#define THREAD_CREATE_FLAGS_CREATE_SUSPENDED 0x00000001\n#define THREAD_CREATE_FLAGS_SKIP_THREAD_ATTACH 0x00000002 // ?\n#define THREAD_CREATE_FLAGS_HIDE_FROM_DEBUGGER 0x00000004\n#define THREAD_CREATE_FLAGS_HAS_SECURITY_DESCRIPTOR 0x00000010 // ?\n#define THREAD_CREATE_FLAGS_ACCESS_CHECK_IN_TARGET 0x00000020 // ?\n#define THREAD_CREATE_FLAGS_INITIAL_THREAD 0x00000080\n// end_rev\n\n#if (PHNT_VERSION >= PHNT_VISTA)\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtCreateThreadEx(\n    _Out_ PHANDLE ThreadHandle,\n    _In_ ACCESS_MASK DesiredAccess,\n    _In_opt_ POBJECT_ATTRIBUTES ObjectAttributes,\n    _In_ HANDLE ProcessHandle,\n    _In_ PVOID StartRoutine, // PUSER_THREAD_START_ROUTINE\n    _In_opt_ PVOID Argument,\n    _In_ ULONG CreateFlags, // THREAD_CREATE_FLAGS_*\n    _In_ SIZE_T ZeroBits,\n    _In_ SIZE_T StackSize,\n    _In_ SIZE_T MaximumStackSize,\n    _In_opt_ PPS_ATTRIBUTE_LIST AttributeList\n    );\n#endif\n\n#endif\n\n// Job objects\n\n#if (PHNT_MODE != PHNT_MODE_KERNEL)\n\n// JOBOBJECTINFOCLASS\n// Note: We don't use an enum since it conflicts with the Windows SDK.\n#define JobObjectBasicAccountingInformation 1 // JOBOBJECT_BASIC_ACCOUNTING_INFORMATION\n#define JobObjectBasicLimitInformation 2 // JOBOBJECT_BASIC_LIMIT_INFORMATION\n#define JobObjectBasicProcessIdList 3 // JOBOBJECT_BASIC_PROCESS_ID_LIST\n#define JobObjectBasicUIRestrictions 4 // JOBOBJECT_BASIC_UI_RESTRICTIONS\n#define JobObjectSecurityLimitInformation 5 // JOBOBJECT_SECURITY_LIMIT_INFORMATION\n#define JobObjectEndOfJobTimeInformation 6 // JOBOBJECT_END_OF_JOB_TIME_INFORMATION\n#define JobObjectAssociateCompletionPortInformation 7 // JOBOBJECT_ASSOCIATE_COMPLETION_PORT\n#define JobObjectBasicAndIoAccountingInformation 8 // JOBOBJECT_BASIC_AND_IO_ACCOUNTING_INFORMATION\n#define JobObjectExtendedLimitInformation 9 // JOBOBJECT_EXTENDED_LIMIT_INFORMATION\n#define JobObjectJobSetInformation 10 // JOBOBJECT_JOBSET_INFORMATION\n#define JobObjectGroupInformation 11 // USHORT\n#define JobObjectNotificationLimitInformation 12 // JOBOBJECT_NOTIFICATION_LIMIT_INFORMATION\n#define JobObjectLimitViolationInformation 13 // JOBOBJECT_LIMIT_VIOLATION_INFORMATION\n#define JobObjectGroupInformationEx 14 // GROUP_AFFINITY (ARRAY)\n#define JobObjectCpuRateControlInformation 15 // JOBOBJECT_CPU_RATE_CONTROL_INFORMATION\n#define JobObjectCompletionFilter 16\n#define JobObjectCompletionCounter 17\n#define JobObjectFreezeInformation 18 // JOBOBJECT_FREEZE_INFORMATION\n#define JobObjectExtendedAccountingInformation 19 // JOBOBJECT_EXTENDED_ACCOUNTING_INFORMATION\n#define JobObjectWakeInformation 20 // JOBOBJECT_WAKE_INFORMATION\n#define JobObjectBackgroundInformation 21\n#define JobObjectSchedulingRankBiasInformation 22\n#define JobObjectTimerVirtualizationInformation 23\n#define JobObjectCycleTimeNotification 24\n#define JobObjectClearEvent 25\n#define JobObjectInterferenceInformation 26 // JOBOBJECT_INTERFERENCE_INFORMATION\n#define JobObjectClearPeakJobMemoryUsed 27\n#define JobObjectMemoryUsageInformation 28 // JOBOBJECT_MEMORY_USAGE_INFORMATION // JOBOBJECT_MEMORY_USAGE_INFORMATION_V2\n#define JobObjectSharedCommit 29\n#define JobObjectContainerId 30\n#define JobObjectIoRateControlInformation 31\n#define JobObjectNetRateControlInformation 32 // JOBOBJECT_NET_RATE_CONTROL_INFORMATION\n#define JobObjectNotificationLimitInformation2 33 // JOBOBJECT_NOTIFICATION_LIMIT_INFORMATION_2\n#define JobObjectLimitViolationInformation2 34 // JOBOBJECT_LIMIT_VIOLATION_INFORMATION_2\n#define JobObjectCreateSilo 35\n#define JobObjectSiloBasicInformation 36 // SILOOBJECT_BASIC_INFORMATION\n#define JobObjectSiloRootDirectory 37 // SILOOBJECT_ROOT_DIRECTORY\n#define JobObjectServerSiloBasicInformation 38 // SERVERSILO_BASIC_INFORMATION\n#define JobObjectServerSiloUserSharedData 39 // SILO_USER_SHARED_DATA\n#define JobObjectServerSiloInitialize 40\n#define JobObjectServerSiloRunningState 41\n#define JobObjectIoAttribution 42\n#define JobObjectMemoryPartitionInformation 43\n#define JobObjectContainerTelemetryId 44\n#define JobObjectSiloSystemRoot 45\n#define JobObjectEnergyTrackingState 46 // JOBOBJECT_ENERGY_TRACKING_STATE\n#define JobObjectThreadImpersonationInformation 47\n#define MaxJobObjectInfoClass 48\n\n// private\ntypedef struct _JOBOBJECT_EXTENDED_ACCOUNTING_INFORMATION\n{\n    JOBOBJECT_BASIC_ACCOUNTING_INFORMATION BasicInfo;\n    IO_COUNTERS IoInfo;\n    PROCESS_DISK_COUNTERS DiskIoInfo;\n    ULONG64 ContextSwitches;\n    LARGE_INTEGER TotalCycleTime;\n    ULONG64 ReadyTime;\n    PROCESS_ENERGY_VALUES EnergyValues;\n} JOBOBJECT_EXTENDED_ACCOUNTING_INFORMATION, *PJOBOBJECT_EXTENDED_ACCOUNTING_INFORMATION;\n\n// private\ntypedef struct _JOBOBJECT_WAKE_INFORMATION\n{\n    HANDLE NotificationChannel;\n    ULONG64 WakeCounters[7];\n} JOBOBJECT_WAKE_INFORMATION, *PJOBOBJECT_WAKE_INFORMATION;\n\n// private\ntypedef struct _JOBOBJECT_WAKE_INFORMATION_V1\n{\n    HANDLE NotificationChannel;\n    ULONG64 WakeCounters[4];\n} JOBOBJECT_WAKE_INFORMATION_V1, *PJOBOBJECT_WAKE_INFORMATION_V1;\n\n// private\ntypedef struct _JOBOBJECT_INTERFERENCE_INFORMATION\n{\n    ULONG64 Count;\n} JOBOBJECT_INTERFERENCE_INFORMATION, *PJOBOBJECT_INTERFERENCE_INFORMATION;\n\n// private\ntypedef struct _JOBOBJECT_WAKE_FILTER\n{\n    ULONG HighEdgeFilter;\n    ULONG LowEdgeFilter;\n} JOBOBJECT_WAKE_FILTER, *PJOBOBJECT_WAKE_FILTER;\n\n// private\ntypedef struct _JOBOBJECT_FREEZE_INFORMATION\n{\n    union\n    {\n        ULONG Flags;\n        struct\n        {\n            ULONG FreezeOperation : 1;\n            ULONG FilterOperation : 1;\n            ULONG SwapOperation : 1;\n            ULONG Reserved : 29;\n        };\n    };\n    BOOLEAN Freeze;\n    BOOLEAN Swap;\n    UCHAR Reserved0[2];\n    JOBOBJECT_WAKE_FILTER WakeFilter;\n} JOBOBJECT_FREEZE_INFORMATION, *PJOBOBJECT_FREEZE_INFORMATION;\n\n// private\ntypedef struct _JOBOBJECT_MEMORY_USAGE_INFORMATION\n{\n    ULONG64 JobMemory;\n    ULONG64 PeakJobMemoryUsed;\n} JOBOBJECT_MEMORY_USAGE_INFORMATION, *PJOBOBJECT_MEMORY_USAGE_INFORMATION;\n\n// private\ntypedef struct _JOBOBJECT_MEMORY_USAGE_INFORMATION_V2\n{\n    JOBOBJECT_MEMORY_USAGE_INFORMATION BasicInfo;\n    ULONG64 JobSharedMemory;\n    ULONG64 Reserved[2];\n} JOBOBJECT_MEMORY_USAGE_INFORMATION_V2, *PJOBOBJECT_MEMORY_USAGE_INFORMATION_V2;\n\n// private\ntypedef struct _SILO_USER_SHARED_DATA\n{\n    ULONG64 ServiceSessionId;\n    ULONG ActiveConsoleId;\n    LONGLONG ConsoleSessionForegroundProcessId;\n    NT_PRODUCT_TYPE NtProductType;\n    ULONG SuiteMask;\n    ULONG SharedUserSessionId;\n    BOOLEAN IsMultiSessionSku;\n    WCHAR NtSystemRoot[260];\n    USHORT UserModeGlobalLogger[16];\n} SILO_USER_SHARED_DATA, *PSILO_USER_SHARED_DATA;\n\n// private\ntypedef struct _SILOOBJECT_ROOT_DIRECTORY\n{\n    ULONG ControlFlags;\n    UNICODE_STRING Path;\n} SILOOBJECT_ROOT_DIRECTORY, *PSILOOBJECT_ROOT_DIRECTORY;\n\n// private\ntypedef struct _JOBOBJECT_ENERGY_TRACKING_STATE\n{\n    ULONG64 Value;\n    ULONG UpdateMask;\n    ULONG DesiredState;\n} JOBOBJECT_ENERGY_TRACKING_STATE, *PJOBOBJECT_ENERGY_TRACKING_STATE;\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtCreateJobObject(\n    _Out_ PHANDLE JobHandle,\n    _In_ ACCESS_MASK DesiredAccess,\n    _In_opt_ POBJECT_ATTRIBUTES ObjectAttributes\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtOpenJobObject(\n    _Out_ PHANDLE JobHandle,\n    _In_ ACCESS_MASK DesiredAccess,\n    _In_ POBJECT_ATTRIBUTES ObjectAttributes\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtAssignProcessToJobObject(\n    _In_ HANDLE JobHandle,\n    _In_ HANDLE ProcessHandle\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtTerminateJobObject(\n    _In_ HANDLE JobHandle,\n    _In_ NTSTATUS ExitStatus\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtIsProcessInJob(\n    _In_ HANDLE ProcessHandle,\n    _In_opt_ HANDLE JobHandle\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtQueryInformationJobObject(\n    _In_opt_ HANDLE JobHandle,\n    _In_ JOBOBJECTINFOCLASS JobObjectInformationClass,\n    _Out_writes_bytes_(JobObjectInformationLength) PVOID JobObjectInformation,\n    _In_ ULONG JobObjectInformationLength,\n    _Out_opt_ PULONG ReturnLength\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtSetInformationJobObject(\n    _In_ HANDLE JobHandle,\n    _In_ JOBOBJECTINFOCLASS JobObjectInformationClass,\n    _In_reads_bytes_(JobObjectInformationLength) PVOID JobObjectInformation,\n    _In_ ULONG JobObjectInformationLength\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtCreateJobSet(\n    _In_ ULONG NumJob,\n    _In_reads_(NumJob) PJOB_SET_ARRAY UserJobSet,\n    _In_ ULONG Flags\n    );\n\n#if (PHNT_VERSION >= PHNT_THRESHOLD)\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtRevertContainerImpersonation(\n    VOID\n    );\n#endif\n\n#endif\n\n// Reserve objects\n\n#if (PHNT_MODE != PHNT_MODE_KERNEL)\n\n// private\ntypedef enum _MEMORY_RESERVE_TYPE\n{\n    MemoryReserveUserApc,\n    MemoryReserveIoCompletion,\n    MemoryReserveTypeMax\n} MEMORY_RESERVE_TYPE;\n\n#if (PHNT_VERSION >= PHNT_WIN7)\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtAllocateReserveObject(\n    _Out_ PHANDLE MemoryReserveHandle,\n    _In_ POBJECT_ATTRIBUTES ObjectAttributes,\n    _In_ MEMORY_RESERVE_TYPE Type\n    );\n#endif\n\n#endif\n\n#endif\n"
  },
  {
    "path": "third_party/phnt/include/ntregapi.h",
    "content": "#ifndef _NTREGAPI_H\n#define _NTREGAPI_H\n\n// Boot condition flags (NtInitializeRegistry)\n\n#define REG_INIT_BOOT_SM 0x0000\n#define REG_INIT_BOOT_SETUP 0x0001\n#define REG_INIT_BOOT_ACCEPTED_BASE 0x0002\n#define REG_INIT_BOOT_ACCEPTED_MAX REG_INIT_BOOT_ACCEPTED_BASE + 999\n\n#define REG_MAX_KEY_VALUE_NAME_LENGTH 32767\n#define REG_MAX_KEY_NAME_LENGTH 512\n\ntypedef enum _KEY_INFORMATION_CLASS\n{\n    KeyBasicInformation, // KEY_BASIC_INFORMATION\n    KeyNodeInformation, // KEY_NODE_INFORMATION\n    KeyFullInformation, // KEY_FULL_INFORMATION\n    KeyNameInformation, // KEY_NAME_INFORMATION\n    KeyCachedInformation, // KEY_CACHED_INFORMATION\n    KeyFlagsInformation, // KEY_FLAGS_INFORMATION\n    KeyVirtualizationInformation, // KEY_VIRTUALIZATION_INFORMATION\n    KeyHandleTagsInformation, // KEY_HANDLE_TAGS_INFORMATION\n    KeyTrustInformation, // KEY_TRUST_INFORMATION\n    KeyLayerInformation, // KEY_LAYER_INFORMATION\n    MaxKeyInfoClass\n} KEY_INFORMATION_CLASS;\n\ntypedef struct _KEY_BASIC_INFORMATION\n{\n    LARGE_INTEGER LastWriteTime;\n    ULONG TitleIndex;\n    ULONG NameLength;\n    WCHAR Name[1];\n} KEY_BASIC_INFORMATION, *PKEY_BASIC_INFORMATION;\n\ntypedef struct _KEY_NODE_INFORMATION\n{\n    LARGE_INTEGER LastWriteTime;\n    ULONG TitleIndex;\n    ULONG ClassOffset;\n    ULONG ClassLength;\n    ULONG NameLength;\n    WCHAR Name[1];\n    // ...\n    // WCHAR Class[1];\n} KEY_NODE_INFORMATION, *PKEY_NODE_INFORMATION;\n\ntypedef struct _KEY_FULL_INFORMATION\n{\n    LARGE_INTEGER LastWriteTime;\n    ULONG TitleIndex;\n    ULONG ClassOffset;\n    ULONG ClassLength;\n    ULONG SubKeys;\n    ULONG MaxNameLen;\n    ULONG MaxClassLen;\n    ULONG Values;\n    ULONG MaxValueNameLen;\n    ULONG MaxValueDataLen;\n    WCHAR Class[1];\n} KEY_FULL_INFORMATION, *PKEY_FULL_INFORMATION;\n\ntypedef struct _KEY_NAME_INFORMATION\n{\n    ULONG NameLength;\n    WCHAR Name[1];\n} KEY_NAME_INFORMATION, *PKEY_NAME_INFORMATION;\n\ntypedef struct _KEY_CACHED_INFORMATION\n{\n    LARGE_INTEGER LastWriteTime;\n    ULONG TitleIndex;\n    ULONG SubKeys;\n    ULONG MaxNameLen;\n    ULONG Values;\n    ULONG MaxValueNameLen;\n    ULONG MaxValueDataLen;\n    ULONG NameLength;\n    WCHAR Name[1];\n} KEY_CACHED_INFORMATION, *PKEY_CACHED_INFORMATION;\n\ntypedef struct _KEY_FLAGS_INFORMATION\n{\n    ULONG UserFlags;\n} KEY_FLAGS_INFORMATION, *PKEY_FLAGS_INFORMATION;\n\ntypedef struct _KEY_VIRTUALIZATION_INFORMATION\n{\n    ULONG VirtualizationCandidate : 1; // Tells whether the key is part of the virtualization namespace scope (only HKLM\\Software for now).\n    ULONG VirtualizationEnabled : 1; // Tells whether virtualization is enabled on this key. Can be 1 only if above flag is 1.\n    ULONG VirtualTarget : 1; // Tells if the key is a virtual key. Can be 1 only if above 2 are 0. Valid only on the virtual store key handles.\n    ULONG VirtualStore : 1; // Tells if the key is a part of the virtual store path. Valid only on the virtual store key handles.\n    ULONG VirtualSource : 1; // Tells if the key has ever been virtualized, can be 1 only if VirtualizationCandidate is 1.\n    ULONG Reserved : 27;\n} KEY_VIRTUALIZATION_INFORMATION, *PKEY_VIRTUALIZATION_INFORMATION;\n\n// private\ntypedef struct _KEY_TRUST_INFORMATION\n{\n    ULONG TrustedKey : 1;\n    ULONG Reserved : 31;\n} KEY_TRUST_INFORMATION, *PKEY_TRUST_INFORMATION;\n\n// private\ntypedef struct _KEY_LAYER_INFORMATION\n{\n    ULONG IsTombstone;\n    ULONG IsSupersedeLocal;\n    ULONG IsSupersedeTree;\n    ULONG ClassIsInherited;\n    ULONG Reserved;\n} KEY_LAYER_INFORMATION, *PKEY_LAYER_INFORMATION;\n\ntypedef enum _KEY_SET_INFORMATION_CLASS\n{\n    KeyWriteTimeInformation, // KEY_WRITE_TIME_INFORMATION\n    KeyWow64FlagsInformation, // KEY_WOW64_FLAGS_INFORMATION\n    KeyControlFlagsInformation, // KEY_CONTROL_FLAGS_INFORMATION\n    KeySetVirtualizationInformation, // KEY_SET_VIRTUALIZATION_INFORMATION\n    KeySetDebugInformation,\n    KeySetHandleTagsInformation, // KEY_HANDLE_TAGS_INFORMATION\n    KeySetLayerInformation, // KEY_SET_LAYER_INFORMATION\n    MaxKeySetInfoClass\n} KEY_SET_INFORMATION_CLASS;\n\ntypedef struct _KEY_WRITE_TIME_INFORMATION\n{\n    LARGE_INTEGER LastWriteTime;\n} KEY_WRITE_TIME_INFORMATION, *PKEY_WRITE_TIME_INFORMATION;\n\ntypedef struct _KEY_WOW64_FLAGS_INFORMATION\n{\n    ULONG UserFlags;\n} KEY_WOW64_FLAGS_INFORMATION, *PKEY_WOW64_FLAGS_INFORMATION;\n\ntypedef struct _KEY_HANDLE_TAGS_INFORMATION\n{\n    ULONG HandleTags;\n} KEY_HANDLE_TAGS_INFORMATION, *PKEY_HANDLE_TAGS_INFORMATION;\n\ntypedef struct _KEY_SET_LAYER_INFORMATION\n{\n    ULONG IsTombstone : 1;\n    ULONG IsSupersedeLocal : 1;\n    ULONG IsSupersedeTree : 1;\n    ULONG ClassIsInherited : 1;\n    ULONG Reserved : 28;\n} KEY_SET_LAYER_INFORMATION, *PKEY_SET_LAYER_INFORMATION;\n\ntypedef struct _KEY_CONTROL_FLAGS_INFORMATION\n{\n    ULONG ControlFlags;\n} KEY_CONTROL_FLAGS_INFORMATION, *PKEY_CONTROL_FLAGS_INFORMATION;\n\ntypedef struct _KEY_SET_VIRTUALIZATION_INFORMATION\n{\n    ULONG VirtualTarget : 1;\n    ULONG VirtualStore : 1;\n    ULONG VirtualSource : 1; // true if key has been virtualized at least once\n    ULONG Reserved : 29;\n} KEY_SET_VIRTUALIZATION_INFORMATION, *PKEY_SET_VIRTUALIZATION_INFORMATION;\n\ntypedef enum _KEY_VALUE_INFORMATION_CLASS\n{\n    KeyValueBasicInformation, // KEY_VALUE_BASIC_INFORMATION\n    KeyValueFullInformation, // KEY_VALUE_FULL_INFORMATION\n    KeyValuePartialInformation, // KEY_VALUE_PARTIAL_INFORMATION\n    KeyValueFullInformationAlign64,\n    KeyValuePartialInformationAlign64,  // KEY_VALUE_PARTIAL_INFORMATION_ALIGN64\n    KeyValueLayerInformation, // KEY_VALUE_LAYER_INFORMATION\n    MaxKeyValueInfoClass\n} KEY_VALUE_INFORMATION_CLASS;\n\ntypedef struct _KEY_VALUE_BASIC_INFORMATION\n{\n    ULONG TitleIndex;\n    ULONG Type;\n    ULONG NameLength;\n    WCHAR Name[1];\n} KEY_VALUE_BASIC_INFORMATION, *PKEY_VALUE_BASIC_INFORMATION;\n\ntypedef struct _KEY_VALUE_FULL_INFORMATION\n{\n    ULONG TitleIndex;\n    ULONG Type;\n    ULONG DataOffset;\n    ULONG DataLength;\n    ULONG NameLength;\n    WCHAR Name[1];\n    // ...\n    // UCHAR Data[1];\n} KEY_VALUE_FULL_INFORMATION, *PKEY_VALUE_FULL_INFORMATION;\n\ntypedef struct _KEY_VALUE_PARTIAL_INFORMATION\n{\n    ULONG TitleIndex;\n    ULONG Type;\n    ULONG DataLength;\n    UCHAR Data[1];\n} KEY_VALUE_PARTIAL_INFORMATION, *PKEY_VALUE_PARTIAL_INFORMATION;\n\ntypedef struct _KEY_VALUE_PARTIAL_INFORMATION_ALIGN64\n{\n    ULONG Type;\n    ULONG DataLength;\n    UCHAR Data[1];\n} KEY_VALUE_PARTIAL_INFORMATION_ALIGN64, *PKEY_VALUE_PARTIAL_INFORMATION_ALIGN64;\n\n// private\ntypedef struct _KEY_VALUE_LAYER_INFORMATION\n{\n    ULONG IsTombstone;\n    ULONG Reserved;\n} KEY_VALUE_LAYER_INFORMATION, *PKEY_VALUE_LAYER_INFORMATION;\n\ntypedef struct _KEY_VALUE_ENTRY\n{\n    PUNICODE_STRING ValueName;\n    ULONG DataLength;\n    ULONG DataOffset;\n    ULONG Type;\n} KEY_VALUE_ENTRY, *PKEY_VALUE_ENTRY;\n\ntypedef enum _REG_ACTION\n{\n    KeyAdded,\n    KeyRemoved,\n    KeyModified\n} REG_ACTION;\n\ntypedef struct _REG_NOTIFY_INFORMATION\n{\n    ULONG NextEntryOffset;\n    REG_ACTION Action;\n    ULONG KeyLength;\n    WCHAR Key[1];\n} REG_NOTIFY_INFORMATION, *PREG_NOTIFY_INFORMATION;\n\ntypedef struct _KEY_PID_ARRAY\n{\n    HANDLE PID;\n    UNICODE_STRING KeyName;\n} KEY_PID_ARRAY, *PKEY_PID_ARRAY;\n\ntypedef struct _KEY_OPEN_SUBKEYS_INFORMATION\n{\n    ULONG Count;\n    KEY_PID_ARRAY KeyArray[1];\n} KEY_OPEN_SUBKEYS_INFORMATION, *PKEY_OPEN_SUBKEYS_INFORMATION;\n\n// System calls\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtCreateKey(\n    _Out_ PHANDLE KeyHandle,\n    _In_ ACCESS_MASK DesiredAccess,\n    _In_ POBJECT_ATTRIBUTES ObjectAttributes,\n    _Reserved_ ULONG TitleIndex,\n    _In_opt_ PUNICODE_STRING Class,\n    _In_ ULONG CreateOptions,\n    _Out_opt_ PULONG Disposition\n    );\n\n#if (PHNT_VERSION >= PHNT_VISTA)\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtCreateKeyTransacted(\n    _Out_ PHANDLE KeyHandle,\n    _In_ ACCESS_MASK DesiredAccess,\n    _In_ POBJECT_ATTRIBUTES ObjectAttributes,\n    _Reserved_ ULONG TitleIndex,\n    _In_opt_ PUNICODE_STRING Class,\n    _In_ ULONG CreateOptions,\n    _In_ HANDLE TransactionHandle,\n    _Out_opt_ PULONG Disposition\n    );\n#endif\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtOpenKey(\n    _Out_ PHANDLE KeyHandle,\n    _In_ ACCESS_MASK DesiredAccess,\n    _In_ POBJECT_ATTRIBUTES ObjectAttributes\n    );\n\n#if (PHNT_VERSION >= PHNT_VISTA)\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtOpenKeyTransacted(\n    _Out_ PHANDLE KeyHandle,\n    _In_ ACCESS_MASK DesiredAccess,\n    _In_ POBJECT_ATTRIBUTES ObjectAttributes,\n    _In_ HANDLE TransactionHandle\n    );\n#endif\n\n#if (PHNT_VERSION >= PHNT_WIN7)\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtOpenKeyEx(\n    _Out_ PHANDLE KeyHandle,\n    _In_ ACCESS_MASK DesiredAccess,\n    _In_ POBJECT_ATTRIBUTES ObjectAttributes,\n    _In_ ULONG OpenOptions\n    );\n#endif\n\n#if (PHNT_VERSION >= PHNT_WIN7)\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtOpenKeyTransactedEx(\n    _Out_ PHANDLE KeyHandle,\n    _In_ ACCESS_MASK DesiredAccess,\n    _In_ POBJECT_ATTRIBUTES ObjectAttributes,\n    _In_ ULONG OpenOptions,\n    _In_ HANDLE TransactionHandle\n    );\n#endif\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtDeleteKey(\n    _In_ HANDLE KeyHandle\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtRenameKey(\n    _In_ HANDLE KeyHandle,\n    _In_ PUNICODE_STRING NewName\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtDeleteValueKey(\n    _In_ HANDLE KeyHandle,\n    _In_ PUNICODE_STRING ValueName\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtQueryKey(\n    _In_ HANDLE KeyHandle,\n    _In_ KEY_INFORMATION_CLASS KeyInformationClass,\n    _Out_writes_bytes_opt_(Length) PVOID KeyInformation,\n    _In_ ULONG Length,\n    _Out_ PULONG ResultLength\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtSetInformationKey(\n    _In_ HANDLE KeyHandle,\n    _In_ KEY_SET_INFORMATION_CLASS KeySetInformationClass,\n    _In_reads_bytes_(KeySetInformationLength) PVOID KeySetInformation,\n    _In_ ULONG KeySetInformationLength\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtQueryValueKey(\n    _In_ HANDLE KeyHandle,\n    _In_ PUNICODE_STRING ValueName,\n    _In_ KEY_VALUE_INFORMATION_CLASS KeyValueInformationClass,\n    _Out_writes_bytes_opt_(Length) PVOID KeyValueInformation,\n    _In_ ULONG Length,\n    _Out_ PULONG ResultLength\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtSetValueKey(\n    _In_ HANDLE KeyHandle,\n    _In_ PUNICODE_STRING ValueName,\n    _In_opt_ ULONG TitleIndex,\n    _In_ ULONG Type,\n    _In_reads_bytes_opt_(DataSize) PVOID Data,\n    _In_ ULONG DataSize\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtQueryMultipleValueKey(\n    _In_ HANDLE KeyHandle,\n    _Inout_updates_(EntryCount) PKEY_VALUE_ENTRY ValueEntries,\n    _In_ ULONG EntryCount,\n    _Out_writes_bytes_(*BufferLength) PVOID ValueBuffer,\n    _Inout_ PULONG BufferLength,\n    _Out_opt_ PULONG RequiredBufferLength\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtEnumerateKey(\n    _In_ HANDLE KeyHandle,\n    _In_ ULONG Index,\n    _In_ KEY_INFORMATION_CLASS KeyInformationClass,\n    _Out_writes_bytes_opt_(Length) PVOID KeyInformation,\n    _In_ ULONG Length,\n    _Out_ PULONG ResultLength\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtEnumerateValueKey(\n    _In_ HANDLE KeyHandle,\n    _In_ ULONG Index,\n    _In_ KEY_VALUE_INFORMATION_CLASS KeyValueInformationClass,\n    _Out_writes_bytes_opt_(Length) PVOID KeyValueInformation,\n    _In_ ULONG Length,\n    _Out_ PULONG ResultLength\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtFlushKey(\n    _In_ HANDLE KeyHandle\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtCompactKeys(\n    _In_ ULONG Count,\n    _In_reads_(Count) HANDLE KeyArray[]\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtCompressKey(\n    _In_ HANDLE Key\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtLoadKey(\n    _In_ POBJECT_ATTRIBUTES TargetKey,\n    _In_ POBJECT_ATTRIBUTES SourceFile\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtLoadKey2(\n    _In_ POBJECT_ATTRIBUTES TargetKey,\n    _In_ POBJECT_ATTRIBUTES SourceFile,\n    _In_ ULONG Flags\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtLoadKeyEx(\n    _In_ POBJECT_ATTRIBUTES TargetKey,\n    _In_ POBJECT_ATTRIBUTES SourceFile,\n    _In_ ULONG Flags,\n    _In_opt_ HANDLE TrustClassKey,\n    _In_opt_ HANDLE Event,\n    _In_opt_ ACCESS_MASK DesiredAccess,\n    _Out_opt_ PHANDLE RootHandle,\n    _Out_opt_ PIO_STATUS_BLOCK IoStatus\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtReplaceKey(\n    _In_ POBJECT_ATTRIBUTES NewFile,\n    _In_ HANDLE TargetHandle,\n    _In_ POBJECT_ATTRIBUTES OldFile\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtSaveKey(\n    _In_ HANDLE KeyHandle,\n    _In_ HANDLE FileHandle\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtSaveKeyEx(\n    _In_ HANDLE KeyHandle,\n    _In_ HANDLE FileHandle,\n    _In_ ULONG Format\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtSaveMergedKeys(\n    _In_ HANDLE HighPrecedenceKeyHandle,\n    _In_ HANDLE LowPrecedenceKeyHandle,\n    _In_ HANDLE FileHandle\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtRestoreKey(\n    _In_ HANDLE KeyHandle,\n    _In_ HANDLE FileHandle,\n    _In_ ULONG Flags\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtUnloadKey(\n    _In_ POBJECT_ATTRIBUTES TargetKey\n    );\n\n//\n// NtUnloadKey2 Flags (from winnt.h)\n//\n//#define REG_FORCE_UNLOAD            1\n//#define REG_UNLOAD_LEGAL_FLAGS      (REG_FORCE_UNLOAD)\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtUnloadKey2(\n    _In_ POBJECT_ATTRIBUTES TargetKey,\n    _In_ ULONG Flags\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtUnloadKeyEx(\n    _In_ POBJECT_ATTRIBUTES TargetKey,\n    _In_opt_ HANDLE Event\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtNotifyChangeKey(\n    _In_ HANDLE KeyHandle,\n    _In_opt_ HANDLE Event,\n    _In_opt_ PIO_APC_ROUTINE ApcRoutine,\n    _In_opt_ PVOID ApcContext,\n    _Out_ PIO_STATUS_BLOCK IoStatusBlock,\n    _In_ ULONG CompletionFilter,\n    _In_ BOOLEAN WatchTree,\n    _Out_writes_bytes_opt_(BufferSize) PVOID Buffer,\n    _In_ ULONG BufferSize,\n    _In_ BOOLEAN Asynchronous\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtNotifyChangeMultipleKeys(\n    _In_ HANDLE MasterKeyHandle,\n    _In_opt_ ULONG Count,\n    _In_reads_opt_(Count) OBJECT_ATTRIBUTES SubordinateObjects[],\n    _In_opt_ HANDLE Event,\n    _In_opt_ PIO_APC_ROUTINE ApcRoutine,\n    _In_opt_ PVOID ApcContext,\n    _Out_ PIO_STATUS_BLOCK IoStatusBlock,\n    _In_ ULONG CompletionFilter,\n    _In_ BOOLEAN WatchTree,\n    _Out_writes_bytes_opt_(BufferSize) PVOID Buffer,\n    _In_ ULONG BufferSize,\n    _In_ BOOLEAN Asynchronous\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtQueryOpenSubKeys(\n    _In_ POBJECT_ATTRIBUTES TargetKey,\n    _Out_ PULONG HandleCount\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtQueryOpenSubKeysEx(\n    _In_ POBJECT_ATTRIBUTES TargetKey,\n    _In_ ULONG BufferLength,\n    _Out_writes_bytes_(BufferLength) PVOID Buffer,\n    _Out_ PULONG RequiredSize\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtInitializeRegistry(\n    _In_ USHORT BootCondition\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtLockRegistryKey(\n    _In_ HANDLE KeyHandle\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtLockProductActivationKeys(\n    _Inout_opt_ ULONG *pPrivateVer,\n    _Out_opt_ ULONG *pSafeMode\n    );\n\n#if (PHNT_VERSION >= PHNT_VISTA)\n// private\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtFreezeRegistry(\n    _In_ ULONG TimeOutInSeconds\n    );\n#endif\n\n#if (PHNT_VERSION >= PHNT_VISTA)\n// private\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtThawRegistry(\n    VOID\n    );\n#endif\n\n#endif\n"
  },
  {
    "path": "third_party/phnt/include/ntrtl.h",
    "content": "#ifndef _NTRTL_H\n#define _NTRTL_H\n\n// Linked lists\n\nFORCEINLINE VOID InitializeListHead(\n    _Out_ PLIST_ENTRY ListHead\n    )\n{\n    ListHead->Flink = ListHead->Blink = ListHead;\n}\n\n_Check_return_ FORCEINLINE BOOLEAN IsListEmpty(\n    _In_ PLIST_ENTRY ListHead\n    )\n{\n    return ListHead->Flink == ListHead;\n}\n\nFORCEINLINE BOOLEAN RemoveEntryList(\n    _In_ PLIST_ENTRY Entry\n    )\n{\n    PLIST_ENTRY Blink;\n    PLIST_ENTRY Flink;\n\n    Flink = Entry->Flink;\n    Blink = Entry->Blink;\n    Blink->Flink = Flink;\n    Flink->Blink = Blink;\n\n    return Flink == Blink;\n}\n\nFORCEINLINE PLIST_ENTRY RemoveHeadList(\n    _Inout_ PLIST_ENTRY ListHead\n    )\n{\n    PLIST_ENTRY Flink;\n    PLIST_ENTRY Entry;\n\n    Entry = ListHead->Flink;\n    Flink = Entry->Flink;\n    ListHead->Flink = Flink;\n    Flink->Blink = ListHead;\n\n    return Entry;\n}\n\nFORCEINLINE PLIST_ENTRY RemoveTailList(\n    _Inout_ PLIST_ENTRY ListHead\n    )\n{\n    PLIST_ENTRY Blink;\n    PLIST_ENTRY Entry;\n\n    Entry = ListHead->Blink;\n    Blink = Entry->Blink;\n    ListHead->Blink = Blink;\n    Blink->Flink = ListHead;\n\n    return Entry;\n}\n\nFORCEINLINE VOID InsertTailList(\n    _Inout_ PLIST_ENTRY ListHead,\n    _Inout_ PLIST_ENTRY Entry\n    )\n{\n    PLIST_ENTRY Blink;\n\n    Blink = ListHead->Blink;\n    Entry->Flink = ListHead;\n    Entry->Blink = Blink;\n    Blink->Flink = Entry;\n    ListHead->Blink = Entry;\n}\n\nFORCEINLINE VOID InsertHeadList(\n    _Inout_ PLIST_ENTRY ListHead,\n    _Inout_ PLIST_ENTRY Entry\n    )\n{\n    PLIST_ENTRY Flink;\n\n    Flink = ListHead->Flink;\n    Entry->Flink = Flink;\n    Entry->Blink = ListHead;\n    Flink->Blink = Entry;\n    ListHead->Flink = Entry;\n}\n\nFORCEINLINE VOID AppendTailList(\n    _Inout_ PLIST_ENTRY ListHead,\n    _Inout_ PLIST_ENTRY ListToAppend\n    )\n{\n    PLIST_ENTRY ListEnd = ListHead->Blink;\n\n    ListHead->Blink->Flink = ListToAppend;\n    ListHead->Blink = ListToAppend->Blink;\n    ListToAppend->Blink->Flink = ListHead;\n    ListToAppend->Blink = ListEnd;\n}\n\nFORCEINLINE PSINGLE_LIST_ENTRY PopEntryList(\n    _Inout_ PSINGLE_LIST_ENTRY ListHead\n    )\n{\n    PSINGLE_LIST_ENTRY FirstEntry;\n\n    FirstEntry = ListHead->Next;\n\n    if (FirstEntry)\n        ListHead->Next = FirstEntry->Next;\n\n    return FirstEntry;\n}\n\nFORCEINLINE VOID PushEntryList(\n    _Inout_ PSINGLE_LIST_ENTRY ListHead,\n    _Inout_ PSINGLE_LIST_ENTRY Entry\n    )\n{\n    Entry->Next = ListHead->Next;\n    ListHead->Next = Entry;\n}\n\n// AVL and splay trees\n\ntypedef enum _TABLE_SEARCH_RESULT\n{\n    TableEmptyTree,\n    TableFoundNode,\n    TableInsertAsLeft,\n    TableInsertAsRight\n} TABLE_SEARCH_RESULT;\n\ntypedef enum _RTL_GENERIC_COMPARE_RESULTS\n{\n    GenericLessThan,\n    GenericGreaterThan,\n    GenericEqual\n} RTL_GENERIC_COMPARE_RESULTS;\n\ntypedef RTL_GENERIC_COMPARE_RESULTS (NTAPI *PRTL_AVL_COMPARE_ROUTINE)(\n    _In_ struct _RTL_AVL_TABLE *Table,\n    _In_ PVOID FirstStruct,\n    _In_ PVOID SecondStruct\n    );\n\ntypedef PVOID (NTAPI *PRTL_AVL_ALLOCATE_ROUTINE)(\n    _In_ struct _RTL_AVL_TABLE *Table,\n    _In_ CLONG ByteSize\n    );\n\ntypedef VOID (NTAPI *PRTL_AVL_FREE_ROUTINE)(\n    _In_ struct _RTL_AVL_TABLE *Table,\n    _In_ _Post_invalid_ PVOID Buffer\n    );\n\ntypedef NTSTATUS (NTAPI *PRTL_AVL_MATCH_FUNCTION)(\n    _In_ struct _RTL_AVL_TABLE *Table,\n    _In_ PVOID UserData,\n    _In_ PVOID MatchData\n    );\n\ntypedef struct _RTL_BALANCED_LINKS\n{\n    struct _RTL_BALANCED_LINKS *Parent;\n    struct _RTL_BALANCED_LINKS *LeftChild;\n    struct _RTL_BALANCED_LINKS *RightChild;\n    CHAR Balance;\n    UCHAR Reserved[3];\n} RTL_BALANCED_LINKS, *PRTL_BALANCED_LINKS;\n\ntypedef struct _RTL_AVL_TABLE\n{\n    RTL_BALANCED_LINKS BalancedRoot;\n    PVOID OrderedPointer;\n    ULONG WhichOrderedElement;\n    ULONG NumberGenericTableElements;\n    ULONG DepthOfTree;\n    PRTL_BALANCED_LINKS RestartKey;\n    ULONG DeleteCount;\n    PRTL_AVL_COMPARE_ROUTINE CompareRoutine;\n    PRTL_AVL_ALLOCATE_ROUTINE AllocateRoutine;\n    PRTL_AVL_FREE_ROUTINE FreeRoutine;\n    PVOID TableContext;\n} RTL_AVL_TABLE, *PRTL_AVL_TABLE;\n\nNTSYSAPI\nVOID\nNTAPI\nRtlInitializeGenericTableAvl(\n    _Out_ PRTL_AVL_TABLE Table,\n    _In_ PRTL_AVL_COMPARE_ROUTINE CompareRoutine,\n    _In_ PRTL_AVL_ALLOCATE_ROUTINE AllocateRoutine,\n    _In_ PRTL_AVL_FREE_ROUTINE FreeRoutine,\n    _In_opt_ PVOID TableContext\n    );\n\nNTSYSAPI\nPVOID\nNTAPI\nRtlInsertElementGenericTableAvl(\n    _In_ PRTL_AVL_TABLE Table,\n    _In_reads_bytes_(BufferSize) PVOID Buffer,\n    _In_ CLONG BufferSize,\n    _Out_opt_ PBOOLEAN NewElement\n    );\n\nNTSYSAPI\nPVOID\nNTAPI\nRtlInsertElementGenericTableFullAvl(\n    _In_ PRTL_AVL_TABLE Table,\n    _In_reads_bytes_(BufferSize) PVOID Buffer,\n    _In_ CLONG BufferSize,\n    _Out_opt_ PBOOLEAN NewElement,\n    _In_ PVOID NodeOrParent,\n    _In_ TABLE_SEARCH_RESULT SearchResult\n    );\n\nNTSYSAPI\nBOOLEAN\nNTAPI\nRtlDeleteElementGenericTableAvl(\n    _In_ PRTL_AVL_TABLE Table,\n    _In_ PVOID Buffer\n    );\n\n_Check_return_\nNTSYSAPI\nPVOID\nNTAPI\nRtlLookupElementGenericTableAvl(\n    _In_ PRTL_AVL_TABLE Table,\n    _In_ PVOID Buffer\n    );\n\nNTSYSAPI\nPVOID\nNTAPI\nRtlLookupElementGenericTableFullAvl(\n    _In_ PRTL_AVL_TABLE Table,\n    _In_ PVOID Buffer,\n    _Out_ PVOID *NodeOrParent,\n    _Out_ TABLE_SEARCH_RESULT *SearchResult\n    );\n\n_Check_return_\nNTSYSAPI\nPVOID\nNTAPI\nRtlEnumerateGenericTableAvl(\n    _In_ PRTL_AVL_TABLE Table,\n    _In_ BOOLEAN Restart\n    );\n\n_Check_return_\nNTSYSAPI\nPVOID\nNTAPI\nRtlEnumerateGenericTableWithoutSplayingAvl(\n    _In_ PRTL_AVL_TABLE Table,\n    _Inout_ PVOID *RestartKey\n    );\n\n_Check_return_\nNTSYSAPI\nPVOID\nNTAPI\nRtlLookupFirstMatchingElementGenericTableAvl(\n    _In_ PRTL_AVL_TABLE Table,\n    _In_ PVOID Buffer,\n    _Out_ PVOID *RestartKey\n    );\n\n_Check_return_\nNTSYSAPI\nPVOID\nNTAPI\nRtlEnumerateGenericTableLikeADirectory(\n    _In_ PRTL_AVL_TABLE Table,\n    _In_opt_ PRTL_AVL_MATCH_FUNCTION MatchFunction,\n    _In_opt_ PVOID MatchData,\n    _In_ ULONG NextFlag,\n    _Inout_ PVOID *RestartKey,\n    _Inout_ PULONG DeleteCount,\n    _In_ PVOID Buffer\n    );\n\n_Check_return_\nNTSYSAPI\nPVOID\nNTAPI\nRtlGetElementGenericTableAvl(\n    _In_ PRTL_AVL_TABLE Table,\n    _In_ ULONG I\n    );\n\nNTSYSAPI\nULONG\nNTAPI\nRtlNumberGenericTableElementsAvl(\n    _In_ PRTL_AVL_TABLE Table\n    );\n\n_Check_return_\nNTSYSAPI\nBOOLEAN\nNTAPI\nRtlIsGenericTableEmptyAvl(\n    _In_ PRTL_AVL_TABLE Table\n    );\n\ntypedef struct _RTL_SPLAY_LINKS\n{\n    struct _RTL_SPLAY_LINKS *Parent;\n    struct _RTL_SPLAY_LINKS *LeftChild;\n    struct _RTL_SPLAY_LINKS *RightChild;\n} RTL_SPLAY_LINKS, *PRTL_SPLAY_LINKS;\n\n#define RtlInitializeSplayLinks(Links) \\\n{ \\\n    PRTL_SPLAY_LINKS _SplayLinks; \\\n    _SplayLinks = (PRTL_SPLAY_LINKS)(Links); \\\n    _SplayLinks->Parent = _SplayLinks; \\\n    _SplayLinks->LeftChild = NULL; \\\n    _SplayLinks->RightChild = NULL; \\\n}\n\n#define RtlParent(Links) ((PRTL_SPLAY_LINKS)(Links)->Parent)\n#define RtlLeftChild(Links) ((PRTL_SPLAY_LINKS)(Links)->LeftChild)\n#define RtlRightChild(Links) ((PRTL_SPLAY_LINKS)(Links)->RightChild)\n#define RtlIsRoot(Links) ((RtlParent(Links) == (PRTL_SPLAY_LINKS)(Links)))\n#define RtlIsLeftChild(Links) ((RtlLeftChild(RtlParent(Links)) == (PRTL_SPLAY_LINKS)(Links)))\n#define RtlIsRightChild(Links) ((RtlRightChild(RtlParent(Links)) == (PRTL_SPLAY_LINKS)(Links)))\n\n#define RtlInsertAsLeftChild(ParentLinks, ChildLinks) \\\n{ \\\n    PRTL_SPLAY_LINKS _SplayParent; \\\n    PRTL_SPLAY_LINKS _SplayChild; \\\n    _SplayParent = (PRTL_SPLAY_LINKS)(ParentLinks); \\\n    _SplayChild = (PRTL_SPLAY_LINKS)(ChildLinks); \\\n    _SplayParent->LeftChild = _SplayChild; \\\n    _SplayChild->Parent = _SplayParent; \\\n}\n\n#define RtlInsertAsRightChild(ParentLinks, ChildLinks) \\\n{ \\\n    PRTL_SPLAY_LINKS _SplayParent; \\\n    PRTL_SPLAY_LINKS _SplayChild; \\\n    _SplayParent = (PRTL_SPLAY_LINKS)(ParentLinks); \\\n    _SplayChild = (PRTL_SPLAY_LINKS)(ChildLinks); \\\n    _SplayParent->RightChild = _SplayChild; \\\n    _SplayChild->Parent = _SplayParent; \\\n}\n\nNTSYSAPI\nPRTL_SPLAY_LINKS\nNTAPI\nRtlSplay(\n    _Inout_ PRTL_SPLAY_LINKS Links\n    );\n\nNTSYSAPI\nPRTL_SPLAY_LINKS\nNTAPI\nRtlDelete(\n    _In_ PRTL_SPLAY_LINKS Links\n    );\n\nNTSYSAPI\nVOID\nNTAPI\nRtlDeleteNoSplay(\n    _In_ PRTL_SPLAY_LINKS Links,\n    _Inout_ PRTL_SPLAY_LINKS *Root\n    );\n\n_Check_return_\nNTSYSAPI\nPRTL_SPLAY_LINKS\nNTAPI\nRtlSubtreeSuccessor(\n    _In_ PRTL_SPLAY_LINKS Links\n    );\n\n_Check_return_\nNTSYSAPI\nPRTL_SPLAY_LINKS\nNTAPI\nRtlSubtreePredecessor(\n    _In_ PRTL_SPLAY_LINKS Links\n    );\n\n_Check_return_\nNTSYSAPI\nPRTL_SPLAY_LINKS\nNTAPI\nRtlRealSuccessor(\n    _In_ PRTL_SPLAY_LINKS Links\n    );\n\n_Check_return_\nNTSYSAPI\nPRTL_SPLAY_LINKS\nNTAPI\nRtlRealPredecessor(\n    _In_ PRTL_SPLAY_LINKS Links\n    );\n\nstruct _RTL_GENERIC_TABLE;\n\ntypedef RTL_GENERIC_COMPARE_RESULTS (NTAPI *PRTL_GENERIC_COMPARE_ROUTINE)(\n    _In_ struct _RTL_GENERIC_TABLE *Table,\n    _In_ PVOID FirstStruct,\n    _In_ PVOID SecondStruct\n    );\n\ntypedef PVOID (NTAPI *PRTL_GENERIC_ALLOCATE_ROUTINE)(\n    _In_ struct _RTL_GENERIC_TABLE *Table,\n    _In_ CLONG ByteSize\n    );\n\ntypedef VOID (NTAPI *PRTL_GENERIC_FREE_ROUTINE)(\n    _In_ struct _RTL_GENERIC_TABLE *Table,\n    _In_ _Post_invalid_ PVOID Buffer\n    );\n\ntypedef struct _RTL_GENERIC_TABLE\n{\n    PRTL_SPLAY_LINKS TableRoot;\n    LIST_ENTRY InsertOrderList;\n    PLIST_ENTRY OrderedPointer;\n    ULONG WhichOrderedElement;\n    ULONG NumberGenericTableElements;\n    PRTL_GENERIC_COMPARE_ROUTINE CompareRoutine;\n    PRTL_GENERIC_ALLOCATE_ROUTINE AllocateRoutine;\n    PRTL_GENERIC_FREE_ROUTINE FreeRoutine;\n    PVOID TableContext;\n} RTL_GENERIC_TABLE, *PRTL_GENERIC_TABLE;\n\nNTSYSAPI\nVOID\nNTAPI\nRtlInitializeGenericTable(\n    _Out_ PRTL_GENERIC_TABLE Table,\n    _In_ PRTL_GENERIC_COMPARE_ROUTINE CompareRoutine,\n    _In_ PRTL_GENERIC_ALLOCATE_ROUTINE AllocateRoutine,\n    _In_ PRTL_GENERIC_FREE_ROUTINE FreeRoutine,\n    _In_opt_ PVOID TableContext\n    );\n\nNTSYSAPI\nPVOID\nNTAPI\nRtlInsertElementGenericTable(\n    _In_ PRTL_GENERIC_TABLE Table,\n    _In_reads_bytes_(BufferSize) PVOID Buffer,\n    _In_ CLONG BufferSize,\n    _Out_opt_ PBOOLEAN NewElement\n    );\n\nNTSYSAPI\nPVOID\nNTAPI\nRtlInsertElementGenericTableFull(\n    _In_ PRTL_GENERIC_TABLE Table,\n    _In_reads_bytes_(BufferSize) PVOID Buffer,\n    _In_ CLONG BufferSize,\n    _Out_opt_ PBOOLEAN NewElement,\n    _In_ PVOID NodeOrParent,\n    _In_ TABLE_SEARCH_RESULT SearchResult\n    );\n\nNTSYSAPI\nBOOLEAN\nNTAPI\nRtlDeleteElementGenericTable(\n    _In_ PRTL_GENERIC_TABLE Table,\n    _In_ PVOID Buffer\n    );\n\n_Check_return_\nNTSYSAPI\nPVOID\nNTAPI\nRtlLookupElementGenericTable(\n    _In_ PRTL_GENERIC_TABLE Table,\n    _In_ PVOID Buffer\n    );\n\nNTSYSAPI\nPVOID\nNTAPI\nRtlLookupElementGenericTableFull(\n    _In_ PRTL_GENERIC_TABLE Table,\n    _In_ PVOID Buffer,\n    _Out_ PVOID *NodeOrParent,\n    _Out_ TABLE_SEARCH_RESULT *SearchResult\n    );\n\n_Check_return_\nNTSYSAPI\nPVOID\nNTAPI\nRtlEnumerateGenericTable(\n    _In_ PRTL_GENERIC_TABLE Table,\n    _In_ BOOLEAN Restart\n    );\n\n_Check_return_\nNTSYSAPI\nPVOID\nNTAPI\nRtlEnumerateGenericTableWithoutSplaying(\n    _In_ PRTL_GENERIC_TABLE Table,\n    _Inout_ PVOID *RestartKey\n    );\n\n_Check_return_\nNTSYSAPI\nPVOID\nNTAPI\nRtlGetElementGenericTable(\n    _In_ PRTL_GENERIC_TABLE Table,\n    _In_ ULONG I\n    );\n\nNTSYSAPI\nULONG\nNTAPI\nRtlNumberGenericTableElements(\n    _In_ PRTL_GENERIC_TABLE Table\n    );\n\n_Check_return_\nNTSYSAPI\nBOOLEAN\nNTAPI\nRtlIsGenericTableEmpty(\n    _In_ PRTL_GENERIC_TABLE Table\n    );\n\n// RB trees\n\ntypedef struct _RTL_RB_TREE\n{\n    PRTL_BALANCED_NODE Root;\n    PRTL_BALANCED_NODE Min;\n} RTL_RB_TREE, *PRTL_RB_TREE;\n\n#if (PHNT_VERSION >= PHNT_WIN8)\n\n// rev\nNTSYSAPI\nVOID\nNTAPI\nRtlRbInsertNodeEx(\n    _In_ PRTL_RB_TREE Tree,\n    _In_opt_ PRTL_BALANCED_NODE Parent,\n    _In_ BOOLEAN Right,\n    _Out_ PRTL_BALANCED_NODE Node\n    );\n\n// rev\nNTSYSAPI\nVOID\nNTAPI\nRtlRbRemoveNode(\n    _In_ PRTL_RB_TREE Tree,\n    _In_ PRTL_BALANCED_NODE Node\n    );\n\n#endif\n\n// Hash tables\n\n// begin_ntddk\n\n#define RTL_HASH_ALLOCATED_HEADER 0x00000001\n#define RTL_HASH_RESERVED_SIGNATURE 0\n\ntypedef struct _RTL_DYNAMIC_HASH_TABLE_ENTRY\n{\n    LIST_ENTRY Linkage;\n    ULONG_PTR Signature;\n} RTL_DYNAMIC_HASH_TABLE_ENTRY, *PRTL_DYNAMIC_HASH_TABLE_ENTRY;\n\n#define HASH_ENTRY_KEY(x) ((x)->Signature)\n\ntypedef struct _RTL_DYNAMIC_HASH_TABLE_CONTEXT\n{\n    PLIST_ENTRY ChainHead;\n    PLIST_ENTRY PrevLinkage;\n    ULONG_PTR Signature;\n} RTL_DYNAMIC_HASH_TABLE_CONTEXT, *PRTL_DYNAMIC_HASH_TABLE_CONTEXT;\n\ntypedef struct _RTL_DYNAMIC_HASH_TABLE_ENUMERATOR\n{\n    RTL_DYNAMIC_HASH_TABLE_ENTRY HashEntry;\n    PLIST_ENTRY ChainHead;\n    ULONG BucketIndex;\n} RTL_DYNAMIC_HASH_TABLE_ENUMERATOR, *PRTL_DYNAMIC_HASH_TABLE_ENUMERATOR;\n\ntypedef struct _RTL_DYNAMIC_HASH_TABLE\n{\n    // Entries initialized at creation.\n    ULONG Flags;\n    ULONG Shift;\n\n    // Entries used in bucket computation.\n    ULONG TableSize;\n    ULONG Pivot;\n    ULONG DivisorMask;\n\n    // Counters.\n    ULONG NumEntries;\n    ULONG NonEmptyBuckets;\n    ULONG NumEnumerators;\n\n    // The directory. This field is for internal use only.\n    PVOID Directory;\n} RTL_DYNAMIC_HASH_TABLE, *PRTL_DYNAMIC_HASH_TABLE;\n\n#if (PHNT_VERSION >= PHNT_WIN7)\n\nFORCEINLINE\nVOID\nRtlInitHashTableContext(\n    _Inout_ PRTL_DYNAMIC_HASH_TABLE_CONTEXT Context\n    )\n{\n    Context->ChainHead = NULL;\n    Context->PrevLinkage = NULL;\n}\n\nFORCEINLINE\nVOID\nRtlInitHashTableContextFromEnumerator(\n    _Inout_ PRTL_DYNAMIC_HASH_TABLE_CONTEXT Context,\n    _In_ PRTL_DYNAMIC_HASH_TABLE_ENUMERATOR Enumerator\n    )\n{\n    Context->ChainHead = Enumerator->ChainHead;\n    Context->PrevLinkage = Enumerator->HashEntry.Linkage.Blink;\n}\n\nFORCEINLINE\nVOID\nRtlReleaseHashTableContext(\n    _Inout_ PRTL_DYNAMIC_HASH_TABLE_CONTEXT Context\n    )\n{\n    UNREFERENCED_PARAMETER(Context);\n    return;\n}\n\nFORCEINLINE\nULONG\nRtlTotalBucketsHashTable(\n    _In_ PRTL_DYNAMIC_HASH_TABLE HashTable\n    )\n{\n    return HashTable->TableSize;\n}\n\nFORCEINLINE\nULONG\nRtlNonEmptyBucketsHashTable(\n    _In_ PRTL_DYNAMIC_HASH_TABLE HashTable\n    )\n{\n    return HashTable->NonEmptyBuckets;\n}\n\nFORCEINLINE\nULONG\nRtlEmptyBucketsHashTable(\n    _In_ PRTL_DYNAMIC_HASH_TABLE HashTable\n    )\n{\n    return HashTable->TableSize - HashTable->NonEmptyBuckets;\n}\n\nFORCEINLINE\nULONG\nRtlTotalEntriesHashTable(\n    _In_ PRTL_DYNAMIC_HASH_TABLE HashTable\n    )\n{\n    return HashTable->NumEntries;\n}\n\nFORCEINLINE\nULONG\nRtlActiveEnumeratorsHashTable(\n    _In_ PRTL_DYNAMIC_HASH_TABLE HashTable\n    )\n{\n    return HashTable->NumEnumerators;\n}\n\n_Must_inspect_result_\nNTSYSAPI\nBOOLEAN\nNTAPI\nRtlCreateHashTable(\n    _Inout_ _When_(*HashTable == NULL, __drv_allocatesMem(Mem)) PRTL_DYNAMIC_HASH_TABLE *HashTable,\n    _In_ ULONG Shift,\n    _In_ _Reserved_ ULONG Flags\n    );\n\nNTSYSAPI\nVOID\nNTAPI\nRtlDeleteHashTable(\n    _In_ PRTL_DYNAMIC_HASH_TABLE HashTable\n    );\n\nNTSYSAPI\nBOOLEAN\nNTAPI\nRtlInsertEntryHashTable(\n    _In_ PRTL_DYNAMIC_HASH_TABLE HashTable,\n    _In_ PRTL_DYNAMIC_HASH_TABLE_ENTRY Entry,\n    _In_ ULONG_PTR Signature,\n    _Inout_opt_ PRTL_DYNAMIC_HASH_TABLE_CONTEXT Context\n    );\n\nNTSYSAPI\nBOOLEAN\nNTAPI\nRtlRemoveEntryHashTable(\n    _In_ PRTL_DYNAMIC_HASH_TABLE HashTable,\n    _In_ PRTL_DYNAMIC_HASH_TABLE_ENTRY Entry,\n    _Inout_opt_ PRTL_DYNAMIC_HASH_TABLE_CONTEXT Context\n    );\n\n_Must_inspect_result_\nNTSYSAPI\nPRTL_DYNAMIC_HASH_TABLE_ENTRY\nNTAPI\nRtlLookupEntryHashTable(\n    _In_ PRTL_DYNAMIC_HASH_TABLE HashTable,\n    _In_ ULONG_PTR Signature,\n    _Out_opt_ PRTL_DYNAMIC_HASH_TABLE_CONTEXT Context\n    );\n\n_Must_inspect_result_\nNTSYSAPI\nPRTL_DYNAMIC_HASH_TABLE_ENTRY\nNTAPI\nRtlGetNextEntryHashTable(\n    _In_ PRTL_DYNAMIC_HASH_TABLE HashTable,\n    _In_ PRTL_DYNAMIC_HASH_TABLE_CONTEXT Context\n    );\n\nNTSYSAPI\nBOOLEAN\nNTAPI\nRtlInitEnumerationHashTable(\n    _In_ PRTL_DYNAMIC_HASH_TABLE HashTable,\n    _Out_ PRTL_DYNAMIC_HASH_TABLE_ENUMERATOR Enumerator\n    );\n\n_Must_inspect_result_\nNTSYSAPI\nPRTL_DYNAMIC_HASH_TABLE_ENTRY\nNTAPI\nRtlEnumerateEntryHashTable(\n    _In_ PRTL_DYNAMIC_HASH_TABLE HashTable,\n    _Inout_ PRTL_DYNAMIC_HASH_TABLE_ENUMERATOR Enumerator\n    );\n\nNTSYSAPI\nVOID\nNTAPI\nRtlEndEnumerationHashTable(\n    _In_ PRTL_DYNAMIC_HASH_TABLE HashTable,\n    _Inout_ PRTL_DYNAMIC_HASH_TABLE_ENUMERATOR Enumerator\n    );\n\nNTSYSAPI\nBOOLEAN\nNTAPI\nRtlInitWeakEnumerationHashTable(\n    _In_ PRTL_DYNAMIC_HASH_TABLE HashTable,\n    _Out_ PRTL_DYNAMIC_HASH_TABLE_ENUMERATOR Enumerator\n    );\n\n_Must_inspect_result_\nNTSYSAPI\nPRTL_DYNAMIC_HASH_TABLE_ENTRY\nNTAPI\nRtlWeaklyEnumerateEntryHashTable(\n    _In_ PRTL_DYNAMIC_HASH_TABLE HashTable,\n    _Inout_ PRTL_DYNAMIC_HASH_TABLE_ENUMERATOR Enumerator\n    );\n\nNTSYSAPI\nVOID\nNTAPI\nRtlEndWeakEnumerationHashTable(\n    _In_ PRTL_DYNAMIC_HASH_TABLE HashTable,\n    _Inout_ PRTL_DYNAMIC_HASH_TABLE_ENUMERATOR Enumerator\n    );\n\nNTSYSAPI\nBOOLEAN\nNTAPI\nRtlExpandHashTable(\n    _In_ PRTL_DYNAMIC_HASH_TABLE HashTable\n    );\n\nNTSYSAPI\nBOOLEAN\nNTAPI\nRtlContractHashTable(\n    _In_ PRTL_DYNAMIC_HASH_TABLE HashTable\n    );\n\n#endif\n\n#if (PHNT_VERSION >= PHNT_THRESHOLD)\n\nNTSYSAPI\nBOOLEAN\nNTAPI\nRtlInitStrongEnumerationHashTable(\n    _In_ PRTL_DYNAMIC_HASH_TABLE HashTable,\n    _Out_ PRTL_DYNAMIC_HASH_TABLE_ENUMERATOR Enumerator\n    );\n\n_Must_inspect_result_\nNTSYSAPI\nPRTL_DYNAMIC_HASH_TABLE_ENTRY\nNTAPI\nRtlStronglyEnumerateEntryHashTable(\n    _In_ PRTL_DYNAMIC_HASH_TABLE HashTable,\n    _Inout_ PRTL_DYNAMIC_HASH_TABLE_ENUMERATOR Enumerator\n    );\n\nNTSYSAPI\nVOID\nNTAPI\nRtlEndStrongEnumerationHashTable(\n    _In_ PRTL_DYNAMIC_HASH_TABLE HashTable,\n    _Inout_ PRTL_DYNAMIC_HASH_TABLE_ENUMERATOR Enumerator\n    );\n\n#endif\n\n// end_ntddk\n\n// Critical sections\n\nNTSYSAPI\nNTSTATUS\nNTAPI\nRtlInitializeCriticalSection(\n    _Out_ PRTL_CRITICAL_SECTION CriticalSection\n    );\n\nNTSYSAPI\nNTSTATUS\nNTAPI\nRtlInitializeCriticalSectionAndSpinCount(\n    _Inout_ PRTL_CRITICAL_SECTION CriticalSection,\n    _In_ ULONG SpinCount\n    );\n\nNTSYSAPI\nNTSTATUS\nNTAPI\nRtlDeleteCriticalSection(\n    _Inout_ PRTL_CRITICAL_SECTION CriticalSection\n    );\n\nNTSYSAPI\nNTSTATUS\nNTAPI\nRtlEnterCriticalSection(\n    _Inout_ PRTL_CRITICAL_SECTION CriticalSection\n    );\n\nNTSYSAPI\nNTSTATUS\nNTAPI\nRtlLeaveCriticalSection(\n    _Inout_ PRTL_CRITICAL_SECTION CriticalSection\n    );\n\nNTSYSAPI\nLOGICAL\nNTAPI\nRtlTryEnterCriticalSection(\n    _Inout_ PRTL_CRITICAL_SECTION CriticalSection\n    );\n\nNTSYSAPI\nLOGICAL\nNTAPI\nRtlIsCriticalSectionLocked(\n    _In_ PRTL_CRITICAL_SECTION CriticalSection\n    );\n\nNTSYSAPI\nLOGICAL\nNTAPI\nRtlIsCriticalSectionLockedByThread(\n    _In_ PRTL_CRITICAL_SECTION CriticalSection\n    );\n\nNTSYSAPI\nULONG\nNTAPI\nRtlGetCriticalSectionRecursionCount(\n    _In_ PRTL_CRITICAL_SECTION CriticalSection\n    );\n\nNTSYSAPI\nULONG\nNTAPI\nRtlSetCriticalSectionSpinCount(\n    _Inout_ PRTL_CRITICAL_SECTION CriticalSection,\n    _In_ ULONG SpinCount\n    );\n\n#if (PHNT_VERSION >= PHNT_VISTA)\n// private\nNTSYSAPI\nHANDLE\nNTAPI\nRtlQueryCriticalSectionOwner(\n    _In_ HANDLE EventHandle\n    );\n#endif\n\nNTSYSAPI\nVOID\nNTAPI\nRtlCheckForOrphanedCriticalSections(\n    _In_ HANDLE hThread\n    );\n\n// Resources\n\ntypedef struct _RTL_RESOURCE\n{\n    RTL_CRITICAL_SECTION CriticalSection;\n\n    HANDLE SharedSemaphore;\n    volatile ULONG NumberOfWaitingShared;\n    HANDLE ExclusiveSemaphore;\n    volatile ULONG NumberOfWaitingExclusive;\n\n    volatile LONG NumberOfActive; // negative: exclusive acquire; zero: not acquired; positive: shared acquire(s)\n    HANDLE ExclusiveOwnerThread;\n\n    ULONG Flags; // RTL_RESOURCE_FLAG_*\n\n    PRTL_RESOURCE_DEBUG DebugInfo;\n} RTL_RESOURCE, *PRTL_RESOURCE;\n\n#define RTL_RESOURCE_FLAG_LONG_TERM ((ULONG)0x00000001)\n\nNTSYSAPI\nVOID\nNTAPI\nRtlInitializeResource(\n    _Out_ PRTL_RESOURCE Resource\n    );\n\nNTSYSAPI\nVOID\nNTAPI\nRtlDeleteResource(\n    _Inout_ PRTL_RESOURCE Resource\n    );\n\nNTSYSAPI\nBOOLEAN\nNTAPI\nRtlAcquireResourceShared(\n    _Inout_ PRTL_RESOURCE Resource,\n    _In_ BOOLEAN Wait\n    );\n\nNTSYSAPI\nBOOLEAN\nNTAPI\nRtlAcquireResourceExclusive(\n    _Inout_ PRTL_RESOURCE Resource,\n    _In_ BOOLEAN Wait\n    );\n\nNTSYSAPI\nVOID\nNTAPI\nRtlReleaseResource(\n    _Inout_ PRTL_RESOURCE Resource\n    );\n\nNTSYSAPI\nVOID\nNTAPI\nRtlConvertSharedToExclusive(\n    _Inout_ PRTL_RESOURCE Resource\n    );\n\nNTSYSAPI\nVOID\nNTAPI\nRtlConvertExclusiveToShared(\n    _Inout_ PRTL_RESOURCE Resource\n    );\n\n// Slim reader-writer locks, condition variables, and barriers\n\n#if (PHNT_VERSION >= PHNT_VISTA)\n\n// winbase:InitializeSRWLock\nNTSYSAPI\nVOID\nNTAPI\nRtlInitializeSRWLock(\n    _Out_ PRTL_SRWLOCK SRWLock\n    );\n\n// winbase:AcquireSRWLockExclusive\nNTSYSAPI\nVOID\nNTAPI\nRtlAcquireSRWLockExclusive(\n    _Inout_ PRTL_SRWLOCK SRWLock\n    );\n\n// winbase:AcquireSRWLockShared\nNTSYSAPI\nVOID\nNTAPI\nRtlAcquireSRWLockShared(\n    _Inout_ PRTL_SRWLOCK SRWLock\n    );\n\n// winbase:ReleaseSRWLockExclusive\nNTSYSAPI\nVOID\nNTAPI\nRtlReleaseSRWLockExclusive(\n    _Inout_ PRTL_SRWLOCK SRWLock\n    );\n\n// winbase:ReleaseSRWLockShared\nNTSYSAPI\nVOID\nNTAPI\nRtlReleaseSRWLockShared(\n    _Inout_ PRTL_SRWLOCK SRWLock\n    );\n\n// winbase:TryAcquireSRWLockExclusive\nNTSYSAPI\nBOOLEAN\nNTAPI\nRtlTryAcquireSRWLockExclusive(\n    _Inout_ PRTL_SRWLOCK SRWLock\n    );\n\n// winbase:TryAcquireSRWLockShared\nNTSYSAPI\nBOOLEAN\nNTAPI\nRtlTryAcquireSRWLockShared(\n    _Inout_ PRTL_SRWLOCK SRWLock\n    );\n\n#if (PHNT_VERSION >= PHNT_WIN7)\n// rev\nNTSYSAPI\nVOID\nNTAPI\nRtlAcquireReleaseSRWLockExclusive(\n    _Inout_ PRTL_SRWLOCK SRWLock\n    );\n#endif\n\n#endif\n\n#if (PHNT_VERSION >= PHNT_VISTA)\n\n// winbase:InitializeConditionVariable\nNTSYSAPI\nVOID\nNTAPI\nRtlInitializeConditionVariable(\n    _Out_ PRTL_CONDITION_VARIABLE ConditionVariable\n    );\n\n// private\nNTSYSAPI\nNTSTATUS\nNTAPI\nRtlSleepConditionVariableCS(\n    _Inout_ PRTL_CONDITION_VARIABLE ConditionVariable,\n    _Inout_ PRTL_CRITICAL_SECTION CriticalSection,\n    _In_opt_ PLARGE_INTEGER Timeout\n    );\n\n// private\nNTSYSAPI\nNTSTATUS\nNTAPI\nRtlSleepConditionVariableSRW(\n    _Inout_ PRTL_CONDITION_VARIABLE ConditionVariable,\n    _Inout_ PRTL_SRWLOCK SRWLock,\n    _In_opt_ PLARGE_INTEGER Timeout,\n    _In_ ULONG Flags\n    );\n\n// winbase:WakeConditionVariable\nNTSYSAPI\nVOID\nNTAPI\nRtlWakeConditionVariable(\n    _Inout_ PRTL_CONDITION_VARIABLE ConditionVariable\n    );\n\n// winbase:WakeAllConditionVariable\nNTSYSAPI\nVOID\nNTAPI\nRtlWakeAllConditionVariable(\n    _Inout_ PRTL_CONDITION_VARIABLE ConditionVariable\n    );\n\n#endif\n\n// begin_rev\n#define RTL_BARRIER_FLAGS_SPIN_ONLY 0x00000001 // never block on event - always spin\n#define RTL_BARRIER_FLAGS_BLOCK_ONLY 0x00000002 // always block on event - never spin\n#define RTL_BARRIER_FLAGS_NO_DELETE 0x00000004 // use if barrier will never be deleted\n// end_rev\n\n// begin_private\n\n#if (PHNT_VERSION >= PHNT_VISTA)\n\nNTSYSAPI\nNTSTATUS\nNTAPI\nRtlInitBarrier(\n    _Out_ PRTL_BARRIER Barrier,\n    _In_ ULONG TotalThreads,\n    _In_ ULONG SpinCount\n    );\n\nNTSYSAPI\nNTSTATUS\nNTAPI\nRtlDeleteBarrier(\n    _In_ PRTL_BARRIER Barrier\n    );\n\nNTSYSAPI\nBOOLEAN\nNTAPI\nRtlBarrier(\n    _Inout_ PRTL_BARRIER Barrier,\n    _In_ ULONG Flags\n    );\n\nNTSYSAPI\nBOOLEAN\nNTAPI\nRtlBarrierForDelete(\n    _Inout_ PRTL_BARRIER Barrier,\n    _In_ ULONG Flags\n    );\n\n#endif\n\n// end_private\n\n// Wait on address\n\n// begin_rev\n\n#if (PHNT_VERSION >= PHNT_WIN8)\n\nNTSYSAPI\nNTSTATUS\nNTAPI\nRtlWaitOnAddress(\n    _In_ volatile VOID *Address,\n    _In_ PVOID CompareAddress,\n    _In_ SIZE_T AddressSize,\n    _In_opt_ PLARGE_INTEGER Timeout\n    );\n\nNTSYSAPI\nVOID\nNTAPI\nRtlWakeAddressAll(\n    _In_ PVOID Address\n    );\n\nNTSYSAPI\nVOID\nNTAPI\nRtlWakeAddressSingle(\n    _In_ PVOID Address\n    );\n\n#endif\n\n// end_rev\n\n// Strings\n\n#ifndef PHNT_NO_INLINE_INIT_STRING\nFORCEINLINE VOID RtlInitString(\n    _Out_ PSTRING DestinationString,\n    _In_opt_ PSTR SourceString\n    )\n{\n    if (SourceString)\n        DestinationString->MaximumLength = (DestinationString->Length = (USHORT)strlen(SourceString)) + 1;\n    else\n        DestinationString->MaximumLength = DestinationString->Length = 0;\n\n    DestinationString->Buffer = SourceString;\n}\n#else\nNTSYSAPI\nVOID\nNTAPI\nRtlInitString(\n    _Out_ PSTRING DestinationString,\n    _In_opt_ PSTR SourceString\n    );\n#endif\n\n#if (PHNT_VERSION >= PHNT_THRESHOLD)\nNTSYSAPI\nNTSTATUS\nNTAPI\nRtlInitStringEx(\n    _Out_ PSTRING DestinationString,\n    _In_opt_z_ PCSZ SourceString\n    );\n#endif\n\n#ifndef PHNT_NO_INLINE_INIT_STRING\nFORCEINLINE VOID RtlInitAnsiString(\n    _Out_ PANSI_STRING DestinationString,\n    _In_opt_ PSTR SourceString\n    )\n{\n    if (SourceString)\n        DestinationString->MaximumLength = (DestinationString->Length = (USHORT)strlen(SourceString)) + 1;\n    else\n        DestinationString->MaximumLength = DestinationString->Length = 0;\n\n    DestinationString->Buffer = SourceString;\n}\n#else\nNTSYSAPI\nVOID\nNTAPI\nRtlInitAnsiString(\n    _Out_ PANSI_STRING DestinationString,\n    _In_opt_ PSTR SourceString\n    );\n#endif\n\n#if (PHNT_VERSION >= PHNT_WS03)\nNTSYSAPI\nNTSTATUS\nNTAPI\nRtlInitAnsiStringEx(\n    _Out_ PANSI_STRING DestinationString,\n    _In_opt_z_ PCSZ SourceString\n    );\n#endif\n\nNTSYSAPI\nVOID\nNTAPI\nRtlFreeAnsiString(\n    _In_ PANSI_STRING AnsiString\n    );\n\nNTSYSAPI\nVOID\nNTAPI\nRtlFreeOemString(\n    _In_ POEM_STRING OemString\n    );\n\nNTSYSAPI\nVOID\nNTAPI\nRtlCopyString(\n    _In_ PSTRING DestinationString,\n    _In_opt_ PSTRING SourceString\n    );\n\nNTSYSAPI\nCHAR\nNTAPI\nRtlUpperChar(\n    _In_ CHAR Character\n    );\n\n_Must_inspect_result_\nNTSYSAPI\nLONG\nNTAPI\nRtlCompareString(\n    _In_ PSTRING String1,\n    _In_ PSTRING String2,\n    _In_ BOOLEAN CaseInSensitive\n    );\n\n_Must_inspect_result_\nNTSYSAPI\nBOOLEAN\nNTAPI\nRtlEqualString(\n    _In_ PSTRING String1,\n    _In_ PSTRING String2,\n    _In_ BOOLEAN CaseInSensitive\n    );\n\n_Must_inspect_result_\nNTSYSAPI\nBOOLEAN\nNTAPI\nRtlPrefixString(\n    _In_ PSTRING String1,\n    _In_ PSTRING String2,\n    _In_ BOOLEAN CaseInSensitive\n    );\n\nNTSYSAPI\nNTSTATUS\nNTAPI\nRtlAppendStringToString(\n    _In_ PSTRING Destination,\n    _In_ PSTRING Source\n    );\n\nNTSYSAPI\nNTSTATUS\nNTAPI\nRtlAppendAsciizToString(\n    _In_ PSTRING Destination,\n    _In_opt_ PSTR Source\n    );\n\nNTSYSAPI\nVOID\nNTAPI\nRtlUpperString(\n    _In_ PSTRING DestinationString,\n    _In_ PSTRING SourceString\n    );\n\nFORCEINLINE\nVOID\nNTAPI\nRtlInitEmptyUnicodeString(\n    _Out_ PUNICODE_STRING DestinationString,\n    _In_ PWCHAR Buffer,\n    _In_ USHORT MaximumLength\n    )\n{\n    DestinationString->Buffer = Buffer;\n    DestinationString->MaximumLength = MaximumLength;\n    DestinationString->Length = 0;\n}\n\n#ifndef PHNT_NO_INLINE_INIT_STRING\nFORCEINLINE VOID RtlInitUnicodeString(\n    _Out_ PUNICODE_STRING DestinationString,\n    _In_opt_ PWSTR SourceString\n    )\n{\n    if (SourceString)\n        DestinationString->MaximumLength = (DestinationString->Length = (USHORT)(wcslen(SourceString) * sizeof(WCHAR))) + sizeof(WCHAR);\n    else\n        DestinationString->MaximumLength = DestinationString->Length = 0;\n\n    DestinationString->Buffer = SourceString;\n}\n#else\nNTSYSAPI\nVOID\nNTAPI\nRtlInitUnicodeString(\n    _Out_ PUNICODE_STRING DestinationString,\n    _In_opt_ PWSTR SourceString\n    );\n#endif\n\nNTSYSAPI\nNTSTATUS\nNTAPI\nRtlInitUnicodeStringEx(\n    _Out_ PUNICODE_STRING DestinationString,\n    _In_opt_ PWSTR SourceString\n    );\n\nNTSYSAPI\nBOOLEAN\nNTAPI\nRtlCreateUnicodeString(\n    _Out_ PUNICODE_STRING DestinationString,\n    _In_ PWSTR SourceString\n    );\n\nNTSYSAPI\nBOOLEAN\nNTAPI\nRtlCreateUnicodeStringFromAsciiz(\n    _Out_ PUNICODE_STRING DestinationString,\n    _In_ PSTR SourceString\n    );\n\nNTSYSAPI\nVOID\nNTAPI\nRtlFreeUnicodeString(\n    _In_ PUNICODE_STRING UnicodeString\n    );\n\n#define RTL_DUPLICATE_UNICODE_STRING_NULL_TERMINATE (0x00000001)\n#define RTL_DUPLICATE_UNICODE_STRING_ALLOCATE_NULL_STRING (0x00000002)\n\nNTSYSAPI\nNTSTATUS\nNTAPI\nRtlDuplicateUnicodeString(\n    _In_ ULONG Flags,\n    _In_ PUNICODE_STRING StringIn,\n    _Out_ PUNICODE_STRING StringOut\n    );\n\nNTSYSAPI\nVOID\nNTAPI\nRtlCopyUnicodeString(\n    _In_ PUNICODE_STRING DestinationString,\n    _In_ PUNICODE_STRING SourceString\n    );\n\nNTSYSAPI\nWCHAR\nNTAPI\nRtlUpcaseUnicodeChar(\n    _In_ WCHAR SourceCharacter\n    );\n\nNTSYSAPI\nWCHAR\nNTAPI\nRtlDowncaseUnicodeChar(\n    _In_ WCHAR SourceCharacter\n    );\n\n_Must_inspect_result_\nNTSYSAPI\nLONG\nNTAPI\nRtlCompareUnicodeString(\n    _In_ PUNICODE_STRING String1,\n    _In_ PUNICODE_STRING String2,\n    _In_ BOOLEAN CaseInSensitive\n    );\n\n#if (PHNT_VERSION >= PHNT_VISTA)\n_Must_inspect_result_\nNTSYSAPI\nLONG\nNTAPI\nRtlCompareUnicodeStrings(\n    _In_reads_(String1Length) PWCH String1,\n    _In_ SIZE_T String1Length,\n    _In_reads_(String2Length) PWCH String2,\n    _In_ SIZE_T String2Length,\n    _In_ BOOLEAN CaseInSensitive\n    );\n#endif\n\n_Must_inspect_result_\nNTSYSAPI\nBOOLEAN\nNTAPI\nRtlEqualUnicodeString(\n    _In_ PUNICODE_STRING String1,\n    _In_ PUNICODE_STRING String2,\n    _In_ BOOLEAN CaseInSensitive\n    );\n\n#define HASH_STRING_ALGORITHM_DEFAULT 0\n#define HASH_STRING_ALGORITHM_X65599 1\n#define HASH_STRING_ALGORITHM_INVALID 0xffffffff\n\nNTSYSAPI\nNTSTATUS\nNTAPI\nRtlHashUnicodeString(\n    _In_ PUNICODE_STRING String,\n    _In_ BOOLEAN CaseInSensitive,\n    _In_ ULONG HashAlgorithm,\n    _Out_ PULONG HashValue\n    );\n\nNTSYSAPI\nNTSTATUS\nNTAPI\nRtlValidateUnicodeString(\n    _In_ ULONG Flags,\n    _In_ PUNICODE_STRING String\n    );\n\n_Must_inspect_result_\nNTSYSAPI\nBOOLEAN\nNTAPI\nRtlPrefixUnicodeString(\n    _In_ PCUNICODE_STRING String1,\n    _In_ PCUNICODE_STRING String2,\n    _In_ BOOLEAN CaseInSensitive\n    );\n\n#if (PHNT_VERSION >= PHNT_THRESHOLD)\n_Must_inspect_result_\nNTSYSAPI\nBOOLEAN\nNTAPI\nRtlSuffixUnicodeString(\n    _In_ PCUNICODE_STRING String1,\n    _In_ PCUNICODE_STRING String2,\n    _In_ BOOLEAN CaseInSensitive\n    );\n#endif\n\n#define RTL_FIND_CHAR_IN_UNICODE_STRING_START_AT_END 0x00000001\n#define RTL_FIND_CHAR_IN_UNICODE_STRING_COMPLEMENT_CHAR_SET 0x00000002\n#define RTL_FIND_CHAR_IN_UNICODE_STRING_CASE_INSENSITIVE 0x00000004\n\nNTSYSAPI\nNTSTATUS\nNTAPI\nRtlFindCharInUnicodeString(\n    _In_ ULONG Flags,\n    _In_ PUNICODE_STRING StringToSearch,\n    _In_ PUNICODE_STRING CharSet,\n    _Out_ PUSHORT NonInclusivePrefixLength\n    );\n\nNTSYSAPI\nNTSTATUS\nNTAPI\nRtlAppendUnicodeStringToString(\n    _In_ PUNICODE_STRING Destination,\n    _In_ PUNICODE_STRING Source\n    );\n\nNTSYSAPI\nNTSTATUS\nNTAPI\nRtlAppendUnicodeToString(\n    _In_ PUNICODE_STRING Destination,\n    _In_opt_ PWSTR Source\n    );\n\nNTSYSAPI\nNTSTATUS\nNTAPI\nRtlUpcaseUnicodeString(\n    _Inout_ PUNICODE_STRING DestinationString,\n    _In_ PUNICODE_STRING SourceString,\n    _In_ BOOLEAN AllocateDestinationString\n    );\n\nNTSYSAPI\nNTSTATUS\nNTAPI\nRtlDowncaseUnicodeString(\n    _Inout_ PUNICODE_STRING DestinationString,\n    _In_ PUNICODE_STRING SourceString,\n    _In_ BOOLEAN AllocateDestinationString\n    );\n\nNTSYSAPI\nVOID\nNTAPI\nRtlEraseUnicodeString(\n    _Inout_ PUNICODE_STRING String\n    );\n\nNTSYSAPI\nNTSTATUS\nNTAPI\nRtlAnsiStringToUnicodeString(\n    _Inout_ PUNICODE_STRING DestinationString,\n    _In_ PANSI_STRING SourceString,\n    _In_ BOOLEAN AllocateDestinationString\n    );\n\nNTSYSAPI\nNTSTATUS\nNTAPI\nRtlUnicodeStringToAnsiString(\n    _Inout_ PANSI_STRING DestinationString,\n    _In_ PUNICODE_STRING SourceString,\n    _In_ BOOLEAN AllocateDestinationString\n    );\n\nNTSYSAPI\nWCHAR\nNTAPI\nRtlAnsiCharToUnicodeChar(\n    _Inout_ PUCHAR *SourceCharacter\n    );\n\nNTSYSAPI\nNTSTATUS\nNTAPI\nRtlUpcaseUnicodeStringToAnsiString(\n    _Inout_ PANSI_STRING DestinationString,\n    _In_ PUNICODE_STRING SourceString,\n    _In_ BOOLEAN AllocateDestinationString\n    );\n\nNTSYSAPI\nNTSTATUS\nNTAPI\nRtlOemStringToUnicodeString(\n    _Inout_ PUNICODE_STRING DestinationString,\n    _In_ POEM_STRING SourceString,\n    _In_ BOOLEAN AllocateDestinationString\n    );\n\nNTSYSAPI\nNTSTATUS\nNTAPI\nRtlUnicodeStringToOemString(\n    _Inout_ POEM_STRING DestinationString,\n    _In_ PUNICODE_STRING SourceString,\n    _In_ BOOLEAN AllocateDestinationString\n    );\n\nNTSYSAPI\nNTSTATUS\nNTAPI\nRtlUpcaseUnicodeStringToOemString(\n    _Inout_ POEM_STRING DestinationString,\n    _In_ PUNICODE_STRING SourceString,\n    _In_ BOOLEAN AllocateDestinationString\n    );\n\nNTSYSAPI\nNTSTATUS\nNTAPI\nRtlUnicodeStringToCountedOemString(\n    _Inout_ POEM_STRING DestinationString,\n    _In_ PUNICODE_STRING SourceString,\n    _In_ BOOLEAN AllocateDestinationString\n    );\n\nNTSYSAPI\nNTSTATUS\nNTAPI\nRtlUpcaseUnicodeStringToCountedOemString(\n    _Inout_ POEM_STRING DestinationString,\n    _In_ PUNICODE_STRING SourceString,\n    _In_ BOOLEAN AllocateDestinationString\n    );\n\nNTSYSAPI\nNTSTATUS\nNTAPI\nRtlMultiByteToUnicodeN(\n    _Out_writes_bytes_to_(MaxBytesInUnicodeString, *BytesInUnicodeString) PWCH UnicodeString,\n    _In_ ULONG MaxBytesInUnicodeString,\n    _Out_opt_ PULONG BytesInUnicodeString,\n    _In_reads_bytes_(BytesInMultiByteString) PSTR MultiByteString,\n    _In_ ULONG BytesInMultiByteString\n    );\n\nNTSYSAPI\nNTSTATUS\nNTAPI\nRtlMultiByteToUnicodeSize(\n    _Out_ PULONG BytesInUnicodeString,\n    _In_reads_bytes_(BytesInMultiByteString) PSTR MultiByteString,\n    _In_ ULONG BytesInMultiByteString\n    );\n\nNTSYSAPI\nNTSTATUS\nNTAPI\nRtlUnicodeToMultiByteN(\n    _Out_writes_bytes_to_(MaxBytesInMultiByteString, *BytesInMultiByteString) PCHAR MultiByteString,\n    _In_ ULONG MaxBytesInMultiByteString,\n    _Out_opt_ PULONG BytesInMultiByteString,\n    _In_reads_bytes_(BytesInUnicodeString) PWCH UnicodeString,\n    _In_ ULONG BytesInUnicodeString\n    );\n\nNTSYSAPI\nNTSTATUS\nNTAPI\nRtlUnicodeToMultiByteSize(\n    _Out_ PULONG BytesInMultiByteString,\n    _In_reads_bytes_(BytesInUnicodeString) PWCH UnicodeString,\n    _In_ ULONG BytesInUnicodeString\n    );\n\nNTSYSAPI\nNTSTATUS\nNTAPI\nRtlUpcaseUnicodeToMultiByteN(\n    _Out_writes_bytes_to_(MaxBytesInMultiByteString, *BytesInMultiByteString) PCHAR MultiByteString,\n    _In_ ULONG MaxBytesInMultiByteString,\n    _Out_opt_ PULONG BytesInMultiByteString,\n    _In_reads_bytes_(BytesInUnicodeString) PWCH UnicodeString,\n    _In_ ULONG BytesInUnicodeString\n    );\n\nNTSYSAPI\nNTSTATUS\nNTAPI\nRtlOemToUnicodeN(\n    _Out_writes_bytes_to_(MaxBytesInUnicodeString, *BytesInUnicodeString) PWSTR UnicodeString,\n    _In_ ULONG MaxBytesInUnicodeString,\n    _Out_opt_ PULONG BytesInUnicodeString,\n    _In_reads_bytes_(BytesInOemString) PCH OemString,\n    _In_ ULONG BytesInOemString\n    );\n\nNTSYSAPI\nNTSTATUS\nNTAPI\nRtlUnicodeToOemN(\n    _Out_writes_bytes_to_(MaxBytesInOemString, *BytesInOemString) PCHAR OemString,\n    _In_ ULONG MaxBytesInOemString,\n    _Out_opt_ PULONG BytesInOemString,\n    _In_reads_bytes_(BytesInUnicodeString) PWCH UnicodeString,\n    _In_ ULONG BytesInUnicodeString\n    );\n\nNTSYSAPI\nNTSTATUS\nNTAPI\nRtlUpcaseUnicodeToOemN(\n    _Out_writes_bytes_to_(MaxBytesInOemString, *BytesInOemString) PCHAR OemString,\n    _In_ ULONG MaxBytesInOemString,\n    _Out_opt_ PULONG BytesInOemString,\n    _In_reads_bytes_(BytesInUnicodeString) PWCH UnicodeString,\n    _In_ ULONG BytesInUnicodeString\n    );\n\nNTSYSAPI\nNTSTATUS\nNTAPI\nRtlConsoleMultiByteToUnicodeN(\n    _Out_writes_bytes_to_(MaxBytesInUnicodeString, *BytesInUnicodeString) PWCH UnicodeString,\n    _In_ ULONG MaxBytesInUnicodeString,\n    _Out_opt_ PULONG BytesInUnicodeString,\n    _In_reads_bytes_(BytesInMultiByteString) PCH MultiByteString,\n    _In_ ULONG BytesInMultiByteString,\n    _Out_ PULONG pdwSpecialChar\n    );\n\n#if (PHNT_VERSION >= PHNT_WIN7)\nNTSYSAPI\nNTSTATUS\nNTAPI\nRtlUTF8ToUnicodeN(\n    _Out_writes_bytes_to_(UnicodeStringMaxByteCount, *UnicodeStringActualByteCount) PWSTR UnicodeStringDestination,\n    _In_ ULONG UnicodeStringMaxByteCount,\n    _Out_ PULONG UnicodeStringActualByteCount,\n    _In_reads_bytes_(UTF8StringByteCount) PCH UTF8StringSource,\n    _In_ ULONG UTF8StringByteCount\n    );\n#endif\n\n#if (PHNT_VERSION >= PHNT_WIN7)\nNTSYSAPI\nNTSTATUS\nNTAPI\nRtlUnicodeToUTF8N(\n    _Out_writes_bytes_to_(UTF8StringMaxByteCount, *UTF8StringActualByteCount) PCHAR UTF8StringDestination,\n    _In_ ULONG UTF8StringMaxByteCount,\n    _Out_ PULONG UTF8StringActualByteCount,\n    _In_reads_bytes_(UnicodeStringByteCount) PWCH UnicodeStringSource,\n    _In_ ULONG UnicodeStringByteCount\n    );\n#endif\n\nNTSYSAPI\nNTSTATUS\nNTAPI\nRtlCustomCPToUnicodeN(\n    _In_ PCPTABLEINFO CustomCP,\n    _Out_writes_bytes_to_(MaxBytesInUnicodeString, *BytesInUnicodeString) PWCH UnicodeString,\n    _In_ ULONG MaxBytesInUnicodeString,\n    _Out_opt_ PULONG BytesInUnicodeString,\n    _In_reads_bytes_(BytesInCustomCPString) PCH CustomCPString,\n    _In_ ULONG BytesInCustomCPString\n    );\n\nNTSYSAPI\nNTSTATUS\nNTAPI\nRtlUnicodeToCustomCPN(\n    _In_ PCPTABLEINFO CustomCP,\n    _Out_writes_bytes_to_(MaxBytesInCustomCPString, *BytesInCustomCPString) PCH CustomCPString,\n    _In_ ULONG MaxBytesInCustomCPString,\n    _Out_opt_ PULONG BytesInCustomCPString,\n    _In_reads_bytes_(BytesInUnicodeString) PWCH UnicodeString,\n    _In_ ULONG BytesInUnicodeString\n    );\n\nNTSYSAPI\nNTSTATUS\nNTAPI\nRtlUpcaseUnicodeToCustomCPN(\n    _In_ PCPTABLEINFO CustomCP,\n    _Out_writes_bytes_to_(MaxBytesInCustomCPString, *BytesInCustomCPString) PCH CustomCPString,\n    _In_ ULONG MaxBytesInCustomCPString,\n    _Out_opt_ PULONG BytesInCustomCPString,\n    _In_reads_bytes_(BytesInUnicodeString) PWCH UnicodeString,\n    _In_ ULONG BytesInUnicodeString\n    );\n\nNTSYSAPI\nVOID\nNTAPI\nRtlInitCodePageTable(\n    _In_ PUSHORT TableBase,\n    _Out_ PCPTABLEINFO CodePageTable\n    );\n\nNTSYSAPI\nVOID\nNTAPI\nRtlInitNlsTables(\n    _In_ PUSHORT AnsiNlsBase,\n    _In_ PUSHORT OemNlsBase,\n    _In_ PUSHORT LanguageNlsBase,\n    _Out_ PNLSTABLEINFO TableInfo\n    );\n\nNTSYSAPI\nVOID\nNTAPI\nRtlResetRtlTranslations(\n    _In_ PNLSTABLEINFO TableInfo\n    );\n\nNTSYSAPI\nBOOLEAN\nNTAPI\nRtlIsTextUnicode(\n    _In_ PVOID Buffer,\n    _In_ ULONG Size,\n    _Inout_opt_ PULONG Result\n    );\n\ntypedef enum _RTL_NORM_FORM\n{\n    NormOther = 0x0,\n    NormC = 0x1,\n    NormD = 0x2,\n    NormKC = 0x5,\n    NormKD = 0x6,\n    NormIdna = 0xd,\n    DisallowUnassigned = 0x100,\n    NormCDisallowUnassigned = 0x101,\n    NormDDisallowUnassigned = 0x102,\n    NormKCDisallowUnassigned = 0x105,\n    NormKDDisallowUnassigned = 0x106,\n    NormIdnaDisallowUnassigned = 0x10d\n} RTL_NORM_FORM;\n\n#if (PHNT_VERSION >= PHNT_VISTA)\nNTSYSAPI\nNTSTATUS\nNTAPI\nRtlNormalizeString(\n    _In_ ULONG NormForm, // RTL_NORM_FORM\n    _In_ PCWSTR SourceString,\n    _In_ LONG SourceStringLength,\n    _Out_writes_to_(*DestinationStringLength, *DestinationStringLength) PWSTR DestinationString,\n    _Inout_ PLONG DestinationStringLength\n    );\n#endif\n\n#if (PHNT_VERSION >= PHNT_VISTA)\nNTSYSAPI\nNTSTATUS\nNTAPI\nRtlIsNormalizedString(\n    _In_ ULONG NormForm, // RTL_NORM_FORM\n    _In_ PCWSTR SourceString,\n    _In_ LONG SourceStringLength,\n    _Out_ PBOOLEAN Normalized\n    );\n#endif\n\n#if (PHNT_VERSION >= PHNT_WIN7)\n// ntifs:FsRtlIsNameInExpression\nNTSYSAPI\nBOOLEAN\nNTAPI\nRtlIsNameInExpression(\n    _In_ PUNICODE_STRING Expression,\n    _In_ PUNICODE_STRING Name,\n    _In_ BOOLEAN IgnoreCase,\n    _In_opt_ PWCH UpcaseTable\n    );\n#endif\n\nNTSYSAPI\nBOOLEAN\nNTAPI\nRtlEqualDomainName(\n    _In_ PUNICODE_STRING String1,\n    _In_ PUNICODE_STRING String2\n    );\n\nNTSYSAPI\nBOOLEAN\nNTAPI\nRtlEqualComputerName(\n    _In_ PUNICODE_STRING String1,\n    _In_ PUNICODE_STRING String2\n    );\n\nNTSYSAPI\nNTSTATUS\nNTAPI\nRtlDnsHostNameToComputerName(\n    _Out_ PUNICODE_STRING ComputerNameString,\n    _In_ PCUNICODE_STRING DnsHostNameString,\n    _In_ BOOLEAN AllocateComputerNameString\n    );\n\nNTSYSAPI\nNTSTATUS\nNTAPI\nRtlStringFromGUID(\n    _In_ PGUID Guid,\n    _Out_ PUNICODE_STRING GuidString\n    );\n\nNTSYSAPI\nNTSTATUS\nNTAPI\nRtlGUIDFromString(\n    _In_ PUNICODE_STRING GuidString,\n    _Out_ PGUID Guid\n    );\n\n#if (PHNT_VERSION >= PHNT_VISTA)\nNTSYSAPI\nLONG\nNTAPI\nRtlCompareAltitudes(\n    _In_ PUNICODE_STRING Altitude1,\n    _In_ PUNICODE_STRING Altitude2\n    );\n#endif\n\n// Prefix\n\ntypedef struct _PREFIX_TABLE_ENTRY\n{\n    CSHORT NodeTypeCode;\n    CSHORT NameLength;\n    struct _PREFIX_TABLE_ENTRY *NextPrefixTree;\n    RTL_SPLAY_LINKS Links;\n    PSTRING Prefix;\n} PREFIX_TABLE_ENTRY, *PPREFIX_TABLE_ENTRY;\n\ntypedef struct _PREFIX_TABLE\n{\n    CSHORT NodeTypeCode;\n    CSHORT NameLength;\n    PPREFIX_TABLE_ENTRY NextPrefixTree;\n} PREFIX_TABLE, *PPREFIX_TABLE;\n\nNTSYSAPI\nVOID\nNTAPI\nPfxInitialize(\n    _Out_ PPREFIX_TABLE PrefixTable\n    );\n\nNTSYSAPI\nBOOLEAN\nNTAPI\nPfxInsertPrefix(\n    _In_ PPREFIX_TABLE PrefixTable,\n    _In_ PSTRING Prefix,\n    _Out_ PPREFIX_TABLE_ENTRY PrefixTableEntry\n    );\n\nNTSYSAPI\nVOID\nNTAPI\nPfxRemovePrefix(\n    _In_ PPREFIX_TABLE PrefixTable,\n    _In_ PPREFIX_TABLE_ENTRY PrefixTableEntry\n    );\n\nNTSYSAPI\nPPREFIX_TABLE_ENTRY\nNTAPI\nPfxFindPrefix(\n    _In_ PPREFIX_TABLE PrefixTable,\n    _In_ PSTRING FullName\n    );\n\ntypedef struct _UNICODE_PREFIX_TABLE_ENTRY\n{\n    CSHORT NodeTypeCode;\n    CSHORT NameLength;\n    struct _UNICODE_PREFIX_TABLE_ENTRY *NextPrefixTree;\n    struct _UNICODE_PREFIX_TABLE_ENTRY *CaseMatch;\n    RTL_SPLAY_LINKS Links;\n    PUNICODE_STRING Prefix;\n} UNICODE_PREFIX_TABLE_ENTRY, *PUNICODE_PREFIX_TABLE_ENTRY;\n\ntypedef struct _UNICODE_PREFIX_TABLE\n{\n    CSHORT NodeTypeCode;\n    CSHORT NameLength;\n    PUNICODE_PREFIX_TABLE_ENTRY NextPrefixTree;\n    PUNICODE_PREFIX_TABLE_ENTRY LastNextEntry;\n} UNICODE_PREFIX_TABLE, *PUNICODE_PREFIX_TABLE;\n\nNTSYSAPI\nVOID\nNTAPI\nRtlInitializeUnicodePrefix(\n    _Out_ PUNICODE_PREFIX_TABLE PrefixTable\n    );\n\nNTSYSAPI\nBOOLEAN\nNTAPI\nRtlInsertUnicodePrefix(\n    _In_ PUNICODE_PREFIX_TABLE PrefixTable,\n    _In_ PUNICODE_STRING Prefix,\n    _Out_ PUNICODE_PREFIX_TABLE_ENTRY PrefixTableEntry\n    );\n\nNTSYSAPI\nVOID\nNTAPI\nRtlRemoveUnicodePrefix(\n    _In_ PUNICODE_PREFIX_TABLE PrefixTable,\n    _In_ PUNICODE_PREFIX_TABLE_ENTRY PrefixTableEntry\n    );\n\nNTSYSAPI\nPUNICODE_PREFIX_TABLE_ENTRY\nNTAPI\nRtlFindUnicodePrefix(\n    _In_ PUNICODE_PREFIX_TABLE PrefixTable,\n    _In_ PUNICODE_STRING FullName,\n    _In_ ULONG CaseInsensitiveIndex\n    );\n\nNTSYSAPI\nPUNICODE_PREFIX_TABLE_ENTRY\nNTAPI\nRtlNextUnicodePrefix(\n    _In_ PUNICODE_PREFIX_TABLE PrefixTable,\n    _In_ BOOLEAN Restart\n    );\n\n// Compression\n\ntypedef struct _COMPRESSED_DATA_INFO\n{\n    USHORT CompressionFormatAndEngine; // COMPRESSION_FORMAT_* and COMPRESSION_ENGINE_*\n\n    UCHAR CompressionUnitShift;\n    UCHAR ChunkShift;\n    UCHAR ClusterShift;\n    UCHAR Reserved;\n\n    USHORT NumberOfChunks;\n\n    ULONG CompressedChunkSizes[1];\n} COMPRESSED_DATA_INFO, *PCOMPRESSED_DATA_INFO;\n\nNTSYSAPI\nNTSTATUS\nNTAPI\nRtlGetCompressionWorkSpaceSize(\n    _In_ USHORT CompressionFormatAndEngine,\n    _Out_ PULONG CompressBufferWorkSpaceSize,\n    _Out_ PULONG CompressFragmentWorkSpaceSize\n    );\n\nNTSYSAPI\nNTSTATUS\nNTAPI\nRtlCompressBuffer(\n    _In_ USHORT CompressionFormatAndEngine,\n    _In_reads_bytes_(UncompressedBufferSize) PUCHAR UncompressedBuffer,\n    _In_ ULONG UncompressedBufferSize,\n    _Out_writes_bytes_to_(CompressedBufferSize, *FinalCompressedSize) PUCHAR CompressedBuffer,\n    _In_ ULONG CompressedBufferSize,\n    _In_ ULONG UncompressedChunkSize,\n    _Out_ PULONG FinalCompressedSize,\n    _In_ PVOID WorkSpace\n    );\n\nNTSYSAPI\nNTSTATUS\nNTAPI\nRtlDecompressBuffer(\n    _In_ USHORT CompressionFormat,\n    _Out_writes_bytes_to_(UncompressedBufferSize, *FinalUncompressedSize) PUCHAR UncompressedBuffer,\n    _In_ ULONG UncompressedBufferSize,\n    _In_reads_bytes_(CompressedBufferSize) PUCHAR CompressedBuffer,\n    _In_ ULONG CompressedBufferSize,\n    _Out_ PULONG FinalUncompressedSize\n    );\n\n#if (PHNT_VERSION >= PHNT_WIN8)\nNTSYSAPI\nNTSTATUS\nNTAPI\nRtlDecompressBufferEx(\n    _In_ USHORT CompressionFormat,\n    _Out_writes_bytes_to_(UncompressedBufferSize, *FinalUncompressedSize) PUCHAR UncompressedBuffer,\n    _In_ ULONG UncompressedBufferSize,\n    _In_reads_bytes_(CompressedBufferSize) PUCHAR CompressedBuffer,\n    _In_ ULONG CompressedBufferSize,\n    _Out_ PULONG FinalUncompressedSize,\n    _In_ PVOID WorkSpace\n    );\n#endif\n\nNTSYSAPI\nNTSTATUS\nNTAPI\nRtlDecompressFragment(\n    _In_ USHORT CompressionFormat,\n    _Out_writes_bytes_to_(UncompressedFragmentSize, *FinalUncompressedSize) PUCHAR UncompressedFragment,\n    _In_ ULONG UncompressedFragmentSize,\n    _In_reads_bytes_(CompressedBufferSize) PUCHAR CompressedBuffer,\n    _In_ ULONG CompressedBufferSize,\n    _In_range_(<, CompressedBufferSize) ULONG FragmentOffset,\n    _Out_ PULONG FinalUncompressedSize,\n    _In_ PVOID WorkSpace\n    );\n\nNTSYSAPI\nNTSTATUS\nNTAPI\nRtlDescribeChunk(\n    _In_ USHORT CompressionFormat,\n    _Inout_ PUCHAR *CompressedBuffer,\n    _In_ PUCHAR EndOfCompressedBufferPlus1,\n    _Out_ PUCHAR *ChunkBuffer,\n    _Out_ PULONG ChunkSize\n    );\n\nNTSYSAPI\nNTSTATUS\nNTAPI\nRtlReserveChunk(\n    _In_ USHORT CompressionFormat,\n    _Inout_ PUCHAR *CompressedBuffer,\n    _In_ PUCHAR EndOfCompressedBufferPlus1,\n    _Out_ PUCHAR *ChunkBuffer,\n    _In_ ULONG ChunkSize\n    );\n\nNTSYSAPI\nNTSTATUS\nNTAPI\nRtlDecompressChunks(\n    _Out_writes_bytes_(UncompressedBufferSize) PUCHAR UncompressedBuffer,\n    _In_ ULONG UncompressedBufferSize,\n    _In_reads_bytes_(CompressedBufferSize) PUCHAR CompressedBuffer,\n    _In_ ULONG CompressedBufferSize,\n    _In_reads_bytes_(CompressedTailSize) PUCHAR CompressedTail,\n    _In_ ULONG CompressedTailSize,\n    _In_ PCOMPRESSED_DATA_INFO CompressedDataInfo\n    );\n\nNTSYSAPI\nNTSTATUS\nNTAPI\nRtlCompressChunks(\n    _In_reads_bytes_(UncompressedBufferSize) PUCHAR UncompressedBuffer,\n    _In_ ULONG UncompressedBufferSize,\n    _Out_writes_bytes_(CompressedBufferSize) PUCHAR CompressedBuffer,\n    _In_range_(>=, (UncompressedBufferSize - (UncompressedBufferSize / 16))) ULONG CompressedBufferSize,\n    _Inout_updates_bytes_(CompressedDataInfoLength) PCOMPRESSED_DATA_INFO CompressedDataInfo,\n    _In_range_(>, sizeof(COMPRESSED_DATA_INFO)) ULONG CompressedDataInfoLength,\n    _In_ PVOID WorkSpace\n    );\n\n// Locale\n\n#if (PHNT_VERSION >= PHNT_VISTA)\n\n// private\nNTSYSAPI\nNTSTATUS\nNTAPI\nRtlConvertLCIDToString(\n    _In_ LCID LcidValue,\n    _In_ ULONG Base,\n    _In_ ULONG Padding, // string is padded to this width\n    _Out_writes_(Size) PWSTR pResultBuf,\n    _In_ ULONG Size\n    );\n\n// private\nNTSYSAPI\nBOOLEAN\nNTAPI\nRtlIsValidLocaleName(\n    _In_ PWSTR LocaleName,\n    _In_ ULONG Flags\n    );\n\n// private\nNTSYSAPI\nNTSTATUS\nNTAPI\nRtlGetParentLocaleName(\n    _In_ PWSTR LocaleName,\n    _Inout_ PUNICODE_STRING ParentLocaleName,\n    _In_ ULONG Flags,\n    _In_ BOOLEAN AllocateDestinationString\n    );\n\n// private\nNTSYSAPI\nNTSTATUS\nNTAPI\nRtlLcidToLocaleName(\n    _In_ LCID lcid, // sic\n    _Inout_ PUNICODE_STRING LocaleName,\n    _In_ ULONG Flags,\n    _In_ BOOLEAN AllocateDestinationString\n    );\n\n// private\nNTSYSAPI\nNTSTATUS\nNTAPI\nRtlLocaleNameToLcid(\n    _In_ PWSTR LocaleName,\n    _Out_ PLCID lcid,\n    _In_ ULONG Flags\n    );\n\n// private\nNTSYSAPI\nBOOLEAN\nNTAPI\nRtlLCIDToCultureName(\n    _In_ LCID Lcid,\n    _Inout_ PUNICODE_STRING String\n    );\n\n// private\nNTSYSAPI\nBOOLEAN\nNTAPI\nRtlCultureNameToLCID(\n    _In_ PUNICODE_STRING String,\n    _Out_ PLCID Lcid\n    );\n\n// private\nNTSYSAPI\nVOID\nNTAPI\nRtlCleanUpTEBLangLists(\n    VOID\n    );\n\n#endif\n\n#if (PHNT_VERSION >= PHNT_WIN7)\n\n// rev\nNTSYSAPI\nNTSTATUS\nNTAPI\nRtlGetLocaleFileMappingAddress(\n    _Out_ PVOID *BaseAddress,\n    _Out_ PLCID DefaultLocaleId,\n    _Out_ PLARGE_INTEGER DefaultCasingTableSize\n    );\n\n#endif\n\n// PEB\n\nNTSYSAPI\nVOID\nNTAPI\nRtlAcquirePebLock(\n    VOID\n    );\n\nNTSYSAPI\nVOID\nNTAPI\nRtlReleasePebLock(\n    VOID\n    );\n\n#if (PHNT_VERSION >= PHNT_VISTA)\n// private\nNTSYSAPI\nLOGICAL\nNTAPI\nRtlTryAcquirePebLock(\n    VOID\n    );\n#endif\n\nNTSYSAPI\nNTSTATUS\nNTAPI\nRtlAllocateFromPeb(\n    _In_ ULONG Size,\n    _Out_ PVOID *Block\n    );\n\nNTSYSAPI\nNTSTATUS\nNTAPI\nRtlFreeToPeb(\n    _In_ PVOID Block,\n    _In_ ULONG Size\n    );\n\n// Processes\n\n#define DOS_MAX_COMPONENT_LENGTH 255\n#define DOS_MAX_PATH_LENGTH (DOS_MAX_COMPONENT_LENGTH + 5)\n\ntypedef struct _CURDIR\n{\n    UNICODE_STRING DosPath;\n    HANDLE Handle;\n} CURDIR, *PCURDIR;\n\n#define RTL_USER_PROC_CURDIR_CLOSE 0x00000002\n#define RTL_USER_PROC_CURDIR_INHERIT 0x00000003\n\ntypedef struct _RTL_DRIVE_LETTER_CURDIR\n{\n    USHORT Flags;\n    USHORT Length;\n    ULONG TimeStamp;\n    STRING DosPath;\n} RTL_DRIVE_LETTER_CURDIR, *PRTL_DRIVE_LETTER_CURDIR;\n\n#define RTL_MAX_DRIVE_LETTERS 32\n#define RTL_DRIVE_LETTER_VALID (USHORT)0x0001\n\ntypedef struct _RTL_USER_PROCESS_PARAMETERS\n{\n    ULONG MaximumLength;\n    ULONG Length;\n\n    ULONG Flags;\n    ULONG DebugFlags;\n\n    HANDLE ConsoleHandle;\n    ULONG ConsoleFlags;\n    HANDLE StandardInput;\n    HANDLE StandardOutput;\n    HANDLE StandardError;\n\n    CURDIR CurrentDirectory;\n    UNICODE_STRING DllPath;\n    UNICODE_STRING ImagePathName;\n    UNICODE_STRING CommandLine;\n    PVOID Environment;\n\n    ULONG StartingX;\n    ULONG StartingY;\n    ULONG CountX;\n    ULONG CountY;\n    ULONG CountCharsX;\n    ULONG CountCharsY;\n    ULONG FillAttribute;\n\n    ULONG WindowFlags;\n    ULONG ShowWindowFlags;\n    UNICODE_STRING WindowTitle;\n    UNICODE_STRING DesktopInfo;\n    UNICODE_STRING ShellInfo;\n    UNICODE_STRING RuntimeData;\n    RTL_DRIVE_LETTER_CURDIR CurrentDirectories[RTL_MAX_DRIVE_LETTERS];\n\n    ULONG_PTR EnvironmentSize;\n    ULONG_PTR EnvironmentVersion;\n    PVOID PackageDependencyData;\n    ULONG ProcessGroupId;\n    ULONG LoaderThreads;\n} RTL_USER_PROCESS_PARAMETERS, *PRTL_USER_PROCESS_PARAMETERS;\n\n#define RTL_USER_PROC_PARAMS_NORMALIZED 0x00000001\n#define RTL_USER_PROC_PROFILE_USER 0x00000002\n#define RTL_USER_PROC_PROFILE_KERNEL 0x00000004\n#define RTL_USER_PROC_PROFILE_SERVER 0x00000008\n#define RTL_USER_PROC_RESERVE_1MB 0x00000020\n#define RTL_USER_PROC_RESERVE_16MB 0x00000040\n#define RTL_USER_PROC_CASE_SENSITIVE 0x00000080\n#define RTL_USER_PROC_DISABLE_HEAP_DECOMMIT 0x00000100\n#define RTL_USER_PROC_DLL_REDIRECTION_LOCAL 0x00001000\n#define RTL_USER_PROC_APP_MANIFEST_PRESENT 0x00002000\n#define RTL_USER_PROC_IMAGE_KEY_MISSING 0x00004000\n#define RTL_USER_PROC_OPTIN_PROCESS 0x00020000\n\nNTSYSAPI\nNTSTATUS\nNTAPI\nRtlCreateProcessParameters(\n    _Out_ PRTL_USER_PROCESS_PARAMETERS *pProcessParameters,\n    _In_ PUNICODE_STRING ImagePathName,\n    _In_opt_ PUNICODE_STRING DllPath,\n    _In_opt_ PUNICODE_STRING CurrentDirectory,\n    _In_opt_ PUNICODE_STRING CommandLine,\n    _In_opt_ PVOID Environment,\n    _In_opt_ PUNICODE_STRING WindowTitle,\n    _In_opt_ PUNICODE_STRING DesktopInfo,\n    _In_opt_ PUNICODE_STRING ShellInfo,\n    _In_opt_ PUNICODE_STRING RuntimeData\n    );\n\n#if (PHNT_VERSION >= PHNT_VISTA)\n// private\nNTSYSAPI\nNTSTATUS\nNTAPI\nRtlCreateProcessParametersEx(\n    _Out_ PRTL_USER_PROCESS_PARAMETERS *pProcessParameters,\n    _In_ PUNICODE_STRING ImagePathName,\n    _In_opt_ PUNICODE_STRING DllPath,\n    _In_opt_ PUNICODE_STRING CurrentDirectory,\n    _In_opt_ PUNICODE_STRING CommandLine,\n    _In_opt_ PVOID Environment,\n    _In_opt_ PUNICODE_STRING WindowTitle,\n    _In_opt_ PUNICODE_STRING DesktopInfo,\n    _In_opt_ PUNICODE_STRING ShellInfo,\n    _In_opt_ PUNICODE_STRING RuntimeData,\n    _In_ ULONG Flags // pass RTL_USER_PROC_PARAMS_NORMALIZED to keep parameters normalized\n    );\n#endif\n\nNTSYSAPI\nNTSTATUS\nNTAPI\nRtlDestroyProcessParameters(\n    _In_ _Post_invalid_ PRTL_USER_PROCESS_PARAMETERS ProcessParameters\n    );\n\nNTSYSAPI\nPRTL_USER_PROCESS_PARAMETERS\nNTAPI\nRtlNormalizeProcessParams(\n    _Inout_ PRTL_USER_PROCESS_PARAMETERS ProcessParameters\n    );\n\nNTSYSAPI\nPRTL_USER_PROCESS_PARAMETERS\nNTAPI\nRtlDeNormalizeProcessParams(\n    _Inout_ PRTL_USER_PROCESS_PARAMETERS ProcessParameters\n    );\n\ntypedef struct _RTL_USER_PROCESS_INFORMATION\n{\n    ULONG Length;\n    HANDLE Process;\n    HANDLE Thread;\n    CLIENT_ID ClientId;\n    SECTION_IMAGE_INFORMATION ImageInformation;\n} RTL_USER_PROCESS_INFORMATION, *PRTL_USER_PROCESS_INFORMATION;\n\n// private\nNTSYSAPI\nNTSTATUS\nNTAPI\nRtlCreateUserProcess(\n    _In_ PUNICODE_STRING NtImagePathName,\n    _In_ ULONG AttributesDeprecated,\n    _In_ PRTL_USER_PROCESS_PARAMETERS ProcessParameters,\n    _In_opt_ PSECURITY_DESCRIPTOR ProcessSecurityDescriptor,\n    _In_opt_ PSECURITY_DESCRIPTOR ThreadSecurityDescriptor,\n    _In_opt_ HANDLE ParentProcess,\n    _In_ BOOLEAN InheritHandles,\n    _In_opt_ HANDLE DebugPort,\n    _In_opt_ HANDLE TokenHandle, // used to be ExceptionPort\n    _Out_ PRTL_USER_PROCESS_INFORMATION ProcessInformation\n    );\n\n#if (PHNT_VERSION >= PHNT_VISTA)\nDECLSPEC_NORETURN\nNTSYSAPI\nVOID\nNTAPI\nRtlExitUserProcess(\n    _In_ NTSTATUS ExitStatus\n    );\n#else\n\n#define RtlExitUserProcess RtlExitUserProcess_R\n\nDECLSPEC_NORETURN\nFORCEINLINE VOID RtlExitUserProcess_R(\n    _In_ NTSTATUS ExitStatus\n    )\n{\n    ExitProcess(ExitStatus);\n}\n\n#endif\n\n#if (PHNT_VERSION >= PHNT_VISTA)\n\n// begin_rev\n#define RTL_CLONE_PROCESS_FLAGS_CREATE_SUSPENDED 0x00000001\n#define RTL_CLONE_PROCESS_FLAGS_INHERIT_HANDLES 0x00000002\n#define RTL_CLONE_PROCESS_FLAGS_NO_SYNCHRONIZE 0x00000004 // don't update synchronization objects\n// end_rev\n\n// private\nNTSYSAPI\nNTSTATUS\nNTAPI\nRtlCloneUserProcess(\n    _In_ ULONG ProcessFlags,\n    _In_opt_ PSECURITY_DESCRIPTOR ProcessSecurityDescriptor,\n    _In_opt_ PSECURITY_DESCRIPTOR ThreadSecurityDescriptor,\n    _In_opt_ HANDLE DebugPort,\n    _Out_ PRTL_USER_PROCESS_INFORMATION ProcessInformation\n    );\n\n// private\nNTSYSAPI\nVOID\nNTAPI\nRtlUpdateClonedCriticalSection(\n    _Inout_ PRTL_CRITICAL_SECTION CriticalSection\n    );\n\n// private\nNTSYSAPI\nVOID\nNTAPI\nRtlUpdateClonedSRWLock(\n    _Inout_ PRTL_SRWLOCK SRWLock,\n    _In_ LOGICAL Shared // TRUE to set to shared acquire\n    );\n\n// private\ntypedef struct _RTLP_PROCESS_REFLECTION_REFLECTION_INFORMATION\n{\n    HANDLE ReflectionProcessHandle;\n    HANDLE ReflectionThreadHandle;\n    CLIENT_ID ReflectionClientId;\n} RTLP_PROCESS_REFLECTION_REFLECTION_INFORMATION, *PRTLP_PROCESS_REFLECTION_REFLECTION_INFORMATION;\n\n#if (PHNT_VERSION >= PHNT_WIN7)\n// rev\nNTSYSAPI\nNTSTATUS\nNTAPI\nRtlCreateProcessReflection(\n    _In_ HANDLE ProcessHandle,\n    _In_ ULONG Flags,\n    _In_opt_ PVOID StartRoutine,\n    _In_opt_ PVOID StartContext,\n    _In_opt_ HANDLE EventHandle,\n    _Out_opt_ PRTLP_PROCESS_REFLECTION_REFLECTION_INFORMATION ReflectionInformation\n    );\n#endif\n\n#endif\n\nNTSYSAPI\nNTSTATUS\nSTDAPIVCALLTYPE\nRtlSetProcessIsCritical(\n    _In_ BOOLEAN NewValue,\n    _Out_opt_ PBOOLEAN OldValue,\n    _In_ BOOLEAN CheckFlag\n    );\n\nNTSYSAPI\nNTSTATUS\nSTDAPIVCALLTYPE\nRtlSetThreadIsCritical(\n    _In_ BOOLEAN NewValue,\n    _Out_opt_ PBOOLEAN OldValue,\n    _In_ BOOLEAN CheckFlag\n    );\n\n// Threads\n\ntypedef NTSTATUS (NTAPI *PUSER_THREAD_START_ROUTINE)(\n    _In_ PVOID ThreadParameter\n    );\n\nNTSYSAPI\nNTSTATUS\nNTAPI\nRtlCreateUserThread(\n    _In_ HANDLE Process,\n    _In_opt_ PSECURITY_DESCRIPTOR ThreadSecurityDescriptor,\n    _In_ BOOLEAN CreateSuspended,\n    _In_opt_ ULONG ZeroBits,\n    _In_opt_ SIZE_T MaximumStackSize,\n    _In_opt_ SIZE_T CommittedStackSize,\n    _In_ PUSER_THREAD_START_ROUTINE StartAddress,\n    _In_opt_ PVOID Parameter,\n    _Out_opt_ PHANDLE Thread,\n    _Out_opt_ PCLIENT_ID ClientId\n    );\n\n#if (PHNT_VERSION >= PHNT_VISTA) // should be PHNT_WINXP, but is PHNT_VISTA for consistency with RtlExitUserProcess\nDECLSPEC_NORETURN\nNTSYSAPI\nVOID\nNTAPI\nRtlExitUserThread(\n    _In_ NTSTATUS ExitStatus\n    );\n#else\n\n#define RtlExitUserThread RtlExitUserThread_R\n\nDECLSPEC_NORETURN\nFORCEINLINE VOID RtlExitUserThread_R(\n    _In_ NTSTATUS ExitStatus\n    )\n{\n    ExitThread(ExitStatus);\n}\n\n#endif\n\n#if (PHNT_VERSION >= PHNT_VISTA)\n\n// private\nNTSYSAPI\nNTSTATUS\nNTAPI\nRtlCreateUserStack(\n    _In_opt_ SIZE_T CommittedStackSize,\n    _In_opt_ SIZE_T MaximumStackSize,\n    _In_opt_ ULONG_PTR ZeroBits,\n    _In_ SIZE_T PageSize,\n    _In_ ULONG_PTR ReserveAlignment,\n    _Out_ PINITIAL_TEB InitialTeb\n    );\n\n// private\nNTSYSAPI\nNTSTATUS\nNTAPI\nRtlFreeUserStack(\n    _In_ PVOID AllocationBase\n    );\n\n#endif\n\nNTSYSAPI\nVOID\nNTAPI\nRtlInitializeContext(\n    _In_ HANDLE Process,\n    _Out_ PCONTEXT Context,\n    _In_opt_ PVOID Parameter,\n    _In_opt_ PVOID InitialPc,\n    _In_opt_ PVOID InitialSp\n    );\n\nNTSYSAPI\nNTSTATUS\nNTAPI\nRtlRemoteCall(\n    _In_ HANDLE Process,\n    _In_ HANDLE Thread,\n    _In_ PVOID CallSite,\n    _In_ ULONG ArgumentCount,\n    _In_opt_ PULONG_PTR Arguments,\n    _In_ BOOLEAN PassContext,\n    _In_ BOOLEAN AlreadySuspended\n    );\n\n#ifdef _WIN64\n// rev\nNTSYSAPI\nNTSTATUS\nNTAPI\nRtlWow64GetThreadContext(\n    _In_ HANDLE ThreadHandle,\n    _Inout_ PWOW64_CONTEXT ThreadContext\n    );\n#endif\n\n#ifdef _WIN64\n// rev\nNTSYSAPI\nNTSTATUS\nNTAPI\nRtlWow64SetThreadContext(\n    _In_ HANDLE ThreadHandle,\n    _In_ PWOW64_CONTEXT ThreadContext\n    );\n#endif\n\n// Vectored exception handlers\n\nNTSYSAPI\nPVOID\nNTAPI\nRtlAddVectoredExceptionHandler(\n    _In_ ULONG First,\n    _In_ PVECTORED_EXCEPTION_HANDLER Handler\n    );\n\nNTSYSAPI\nULONG\nNTAPI\nRtlRemoveVectoredExceptionHandler(\n    _In_ PVOID Handle\n    );\n\nNTSYSAPI\nPVOID\nNTAPI\nRtlAddVectoredContinueHandler(\n    _In_ ULONG First,\n    _In_ PVECTORED_EXCEPTION_HANDLER Handler\n    );\n\nNTSYSAPI\nULONG\nNTAPI\nRtlRemoveVectoredContinueHandler(\n    _In_ PVOID Handle\n    );\n\n// Runtime exception handling\n\n#ifdef _WIN64\n\n// private\ntypedef enum _FUNCTION_TABLE_TYPE\n{\n    RF_SORTED,\n    RF_UNSORTED,\n    RF_CALLBACK,\n    RF_KERNEL_DYNAMIC\n} FUNCTION_TABLE_TYPE;\n\n// private\ntypedef struct _DYNAMIC_FUNCTION_TABLE\n{\n    LIST_ENTRY ListEntry;\n    PRUNTIME_FUNCTION FunctionTable;\n    LARGE_INTEGER TimeStamp;\n    ULONG64 MinimumAddress;\n    ULONG64 MaximumAddress;\n    ULONG64 BaseAddress;\n    PGET_RUNTIME_FUNCTION_CALLBACK Callback;\n    PVOID Context;\n    PWSTR OutOfProcessCallbackDll;\n    FUNCTION_TABLE_TYPE Type;\n    ULONG EntryCount;\n    RTL_BALANCED_NODE TreeNode;\n} DYNAMIC_FUNCTION_TABLE, *PDYNAMIC_FUNCTION_TABLE;\n\n// rev\nNTSYSAPI\nPLIST_ENTRY\nNTAPI\nRtlGetFunctionTableListHead(\n    VOID\n    );\n\n#endif\n\n// Images\n\nNTSYSAPI\nPVOID\nNTAPI\nRtlPcToFileHeader(\n    _In_ PVOID PcValue,\n    _Out_ PVOID *BaseOfImage\n    );\n\nNTSYSAPI\nPIMAGE_NT_HEADERS\nNTAPI\nRtlImageNtHeader(\n    _In_ PVOID Base\n    );\n\n#define RTL_IMAGE_NT_HEADER_EX_FLAG_NO_RANGE_CHECK 0x00000001\n\nNTSYSAPI\nNTSTATUS\nNTAPI\nRtlImageNtHeaderEx(\n    _In_ ULONG Flags,\n    _In_ PVOID Base,\n    _In_ ULONG64 Size,\n    _Out_ PIMAGE_NT_HEADERS *OutHeaders\n    );\n\nNTSYSAPI\nPVOID\nNTAPI\nRtlAddressInSectionTable(\n    _In_ PIMAGE_NT_HEADERS NtHeaders,\n    _In_ PVOID BaseOfImage,\n    _In_ ULONG VirtualAddress\n    );\n\nNTSYSAPI\nPIMAGE_SECTION_HEADER\nNTAPI\nRtlSectionTableFromVirtualAddress(\n    _In_ PIMAGE_NT_HEADERS NtHeaders,\n    _In_ PVOID BaseOfImage,\n    _In_ ULONG VirtualAddress\n    );\n\nNTSYSAPI\nPVOID\nNTAPI\nRtlImageDirectoryEntryToData(\n    _In_ PVOID BaseOfImage,\n    _In_ BOOLEAN MappedAsImage,\n    _In_ USHORT DirectoryEntry,\n    _Out_ PULONG Size\n    );\n\nNTSYSAPI\nPIMAGE_SECTION_HEADER\nNTAPI\nRtlImageRvaToSection(\n    _In_ PIMAGE_NT_HEADERS NtHeaders,\n    _In_ PVOID Base,\n    _In_ ULONG Rva\n    );\n\nNTSYSAPI\nPVOID\nNTAPI\nRtlImageRvaToVa(\n    _In_ PIMAGE_NT_HEADERS NtHeaders,\n    _In_ PVOID Base,\n    _In_ ULONG Rva,\n    _Inout_opt_ PIMAGE_SECTION_HEADER *LastRvaSection\n    );\n\n// Memory\n\nNTSYSAPI\nSIZE_T\nNTAPI\nRtlCompareMemoryUlong(\n    _In_ PVOID Source,\n    _In_ SIZE_T Length,\n    _In_ ULONG Pattern\n    );\n\nNTSYSAPI\nVOID\nNTAPI\nRtlFillMemoryUlong(\n    _Out_ PVOID Destination,\n    _In_ SIZE_T Length,\n    _In_ ULONG Pattern\n    );\n\nNTSYSAPI\nVOID\nNTAPI\nRtlFillMemoryUlonglong(\n    _Out_ PVOID Destination,\n    _In_ SIZE_T Length,\n    _In_ ULONGLONG Pattern\n    );\n\n// Environment\n\nNTSYSAPI\nNTSTATUS\nNTAPI\nRtlCreateEnvironment(\n    _In_ BOOLEAN CloneCurrentEnvironment,\n    _Out_ PVOID *Environment\n    );\n\n// begin_rev\n#define RTL_CREATE_ENVIRONMENT_TRANSLATE 0x1 // translate from multi-byte to Unicode\n#define RTL_CREATE_ENVIRONMENT_TRANSLATE_FROM_OEM 0x2 // translate from OEM to Unicode (Translate flag must also be set)\n#define RTL_CREATE_ENVIRONMENT_EMPTY 0x4 // create empty environment block\n// end_rev\n\n#if (PHNT_VERSION >= PHNT_VISTA)\n// private\nNTSYSAPI\nNTSTATUS\nNTAPI\nRtlCreateEnvironmentEx(\n    _In_ PVOID SourceEnv,\n    _Out_ PVOID *Environment,\n    _In_ ULONG Flags\n    );\n#endif\n\nNTSYSAPI\nNTSTATUS\nNTAPI\nRtlDestroyEnvironment(\n    _In_ PVOID Environment\n    );\n\nNTSYSAPI\nNTSTATUS\nNTAPI\nRtlSetCurrentEnvironment(\n    _In_ PVOID Environment,\n    _Out_opt_ PVOID *PreviousEnvironment\n    );\n\n#if (PHNT_VERSION >= PHNT_VISTA)\n// private\nNTSYSAPI\nNTSTATUS\nNTAPI\nRtlSetEnvironmentVar(\n    _In_opt_ PWSTR *Environment,\n    _In_reads_(NameLength) PWSTR Name,\n    _In_ SIZE_T NameLength,\n    _In_reads_(ValueLength) PWSTR Value,\n    _In_ SIZE_T ValueLength\n    );\n#endif\n\nNTSYSAPI\nNTSTATUS\nNTAPI\nRtlSetEnvironmentVariable(\n    _In_opt_ PVOID *Environment,\n    _In_ PUNICODE_STRING Name,\n    _In_ PUNICODE_STRING Value\n    );\n\n#if (PHNT_VERSION >= PHNT_VISTA)\n// private\nNTSYSAPI\nNTSTATUS\nNTAPI\nRtlQueryEnvironmentVariable(\n    _In_opt_ PVOID Environment,\n    _In_reads_(NameLength) PWSTR Name,\n    _In_ SIZE_T NameLength,\n    _Out_writes_(ValueLength) PWSTR Value,\n    _In_ SIZE_T ValueLength,\n    _Out_ PSIZE_T ReturnLength\n    );\n#endif\n\nNTSYSAPI\nNTSTATUS\nNTAPI\nRtlQueryEnvironmentVariable_U(\n    _In_opt_ PVOID Environment,\n    _In_ PUNICODE_STRING Name,\n    _Out_ PUNICODE_STRING Value\n    );\n\n#if (PHNT_VERSION >= PHNT_VISTA)\n// private\nNTSYSAPI\nNTSTATUS\nNTAPI\nRtlExpandEnvironmentStrings(\n    _In_opt_ PVOID Environment,\n    _In_reads_(SrcLength) PWSTR Src,\n    _In_ SIZE_T SrcLength,\n    _Out_writes_(DstLength) PWSTR Dst,\n    _In_ SIZE_T DstLength,\n    _Out_opt_ PSIZE_T ReturnLength\n    );\n#endif\n\nNTSYSAPI\nNTSTATUS\nNTAPI\nRtlExpandEnvironmentStrings_U(\n    _In_opt_ PVOID Environment,\n    _In_ PUNICODE_STRING Source,\n    _Out_ PUNICODE_STRING Destination,\n    _Out_opt_ PULONG ReturnedLength\n    );\n\nNTSYSAPI\nNTSTATUS\nNTAPI\nRtlSetEnvironmentStrings(\n    _In_ PWCHAR NewEnvironment,\n    _In_ SIZE_T NewEnvironmentSize\n    );\n\n// Current directory and paths\n\ntypedef struct _RTLP_CURDIR_REF *PRTLP_CURDIR_REF;\n\ntypedef struct _RTL_RELATIVE_NAME_U\n{\n    UNICODE_STRING RelativeName;\n    HANDLE ContainingDirectory;\n    PRTLP_CURDIR_REF CurDirRef;\n} RTL_RELATIVE_NAME_U, *PRTL_RELATIVE_NAME_U;\n\ntypedef enum _RTL_PATH_TYPE\n{\n    RtlPathTypeUnknown,\n    RtlPathTypeUncAbsolute,\n    RtlPathTypeDriveAbsolute,\n    RtlPathTypeDriveRelative,\n    RtlPathTypeRooted,\n    RtlPathTypeRelative,\n    RtlPathTypeLocalDevice,\n    RtlPathTypeRootLocalDevice\n} RTL_PATH_TYPE;\n\nNTSYSAPI\nRTL_PATH_TYPE\nNTAPI\nRtlDetermineDosPathNameType_U(\n    _In_ PWSTR DosFileName\n    );\n\nNTSYSAPI\nULONG\nNTAPI\nRtlIsDosDeviceName_U(\n    _In_ PWSTR DosFileName\n    );\n\nNTSYSAPI\nULONG\nNTAPI\nRtlGetFullPathName_U(\n    _In_ PWSTR FileName,\n    _In_ ULONG BufferLength,\n    _Out_writes_bytes_(BufferLength) PWSTR Buffer,\n    _Out_opt_ PWSTR *FilePart\n    );\n\n#if (PHNT_VERSION >= PHNT_WIN7)\n// rev\nNTSYSAPI\nNTSTATUS\nNTAPI\nRtlGetFullPathName_UEx(\n    _In_ PWSTR FileName,\n    _In_ ULONG BufferLength,\n    _Out_writes_bytes_(BufferLength) PWSTR Buffer,\n    _Out_opt_ PWSTR *FilePart,\n    _Out_opt_ RTL_PATH_TYPE *InputPathType\n    );\n#endif\n\n#if (PHNT_VERSION >= PHNT_WS03)\nNTSYSAPI\nNTSTATUS\nNTAPI\nRtlGetFullPathName_UstrEx(\n    _In_ PUNICODE_STRING FileName,\n    _Inout_ PUNICODE_STRING StaticString,\n    _Out_opt_ PUNICODE_STRING DynamicString,\n    _Out_opt_ PUNICODE_STRING *StringUsed,\n    _Out_opt_ SIZE_T *FilePartPrefixCch,\n    _Out_opt_ PBOOLEAN NameInvalid,\n    _Out_ RTL_PATH_TYPE *InputPathType,\n    _Out_opt_ SIZE_T *BytesRequired\n    );\n#endif\n\nNTSYSAPI\nULONG\nNTAPI\nRtlGetCurrentDirectory_U(\n    _In_ ULONG BufferLength,\n    _Out_writes_bytes_(BufferLength) PWSTR Buffer\n    );\n\nNTSYSAPI\nNTSTATUS\nNTAPI\nRtlSetCurrentDirectory_U(\n    _In_ PUNICODE_STRING PathName\n    );\n\nNTSYSAPI\nULONG\nNTAPI\nRtlGetLongestNtPathLength(\n    VOID\n    );\n\nNTSYSAPI\nBOOLEAN\nNTAPI\nRtlDosPathNameToNtPathName_U(\n    _In_ PWSTR DosFileName,\n    _Out_ PUNICODE_STRING NtFileName,\n    _Out_opt_ PWSTR *FilePart,\n    _Out_opt_ PRTL_RELATIVE_NAME_U RelativeName\n    );\n\n#if (PHNT_VERSION >= PHNT_WS03)\nNTSYSAPI\nNTSTATUS\nNTAPI\nRtlDosPathNameToNtPathName_U_WithStatus(\n    _In_ PWSTR DosFileName,\n    _Out_ PUNICODE_STRING NtFileName,\n    _Out_opt_ PWSTR *FilePart,\n    _Out_opt_ PRTL_RELATIVE_NAME_U RelativeName\n    );\n#endif\n\n#if (PHNT_VERSION >= PHNT_WS03)\nNTSYSAPI\nBOOLEAN\nNTAPI\nRtlDosPathNameToRelativeNtPathName_U(\n    _In_ PWSTR DosFileName,\n    _Out_ PUNICODE_STRING NtFileName,\n    _Out_opt_ PWSTR *FilePart,\n    _Out_opt_ PRTL_RELATIVE_NAME_U RelativeName\n    );\n#endif\n\n#if (PHNT_VERSION >= PHNT_WS03)\nNTSYSAPI\nNTSTATUS\nNTAPI\nRtlDosPathNameToRelativeNtPathName_U_WithStatus(\n    _In_ PWSTR DosFileName,\n    _Out_ PUNICODE_STRING NtFileName,\n    _Out_opt_ PWSTR *FilePart,\n    _Out_opt_ PRTL_RELATIVE_NAME_U RelativeName\n    );\n#endif\n\n#if (PHNT_VERSION >= PHNT_WS03)\nNTSYSAPI\nVOID\nNTAPI\nRtlReleaseRelativeName(\n    _Inout_ PRTL_RELATIVE_NAME_U RelativeName\n    );\n#endif\n\nNTSYSAPI\nULONG\nNTAPI\nRtlDosSearchPath_U(\n    _In_ PWSTR Path,\n    _In_ PWSTR FileName,\n    _In_opt_ PWSTR Extension,\n    _In_ ULONG BufferLength,\n    _Out_writes_bytes_(BufferLength) PWSTR Buffer,\n    _Out_opt_ PWSTR *FilePart\n    );\n\n#define RTL_DOS_SEARCH_PATH_FLAG_APPLY_ISOLATION_REDIRECTION 0x00000001\n#define RTL_DOS_SEARCH_PATH_FLAG_DISALLOW_DOT_RELATIVE_PATH_SEARCH 0x00000002\n#define RTL_DOS_SEARCH_PATH_FLAG_APPLY_DEFAULT_EXTENSION_WHEN_NOT_RELATIVE_PATH_EVEN_IF_FILE_HAS_EXTENSION 0x00000004)\n\nNTSYSAPI\nNTSTATUS\nNTAPI\nRtlDosSearchPath_Ustr(\n    _In_ ULONG Flags,\n    _In_ PUNICODE_STRING Path,\n    _In_ PUNICODE_STRING FileName,\n    _In_opt_ PUNICODE_STRING DefaultExtension,\n    _Out_opt_ PUNICODE_STRING StaticString,\n    _Out_opt_ PUNICODE_STRING DynamicString,\n    _Out_opt_ PCUNICODE_STRING *FullFileNameOut,\n    _Out_opt_ SIZE_T *FilePartPrefixCch,\n    _Out_opt_ SIZE_T *BytesRequired\n    );\n\nNTSYSAPI\nBOOLEAN\nNTAPI\nRtlDoesFileExists_U(\n    _In_ PWSTR FileName\n    );\n\n// Heaps\n\ntypedef struct _RTL_HEAP_ENTRY\n{\n    SIZE_T Size;\n    USHORT Flags;\n    USHORT AllocatorBackTraceIndex;\n    union\n    {\n        struct\n        {\n            SIZE_T Settable;\n            ULONG Tag;\n        } s1;\n        struct\n        {\n            SIZE_T CommittedSize;\n            PVOID FirstBlock;\n        } s2;\n    } u;\n} RTL_HEAP_ENTRY, *PRTL_HEAP_ENTRY;\n\n#define RTL_HEAP_BUSY (USHORT)0x0001\n#define RTL_HEAP_SEGMENT (USHORT)0x0002\n#define RTL_HEAP_SETTABLE_VALUE (USHORT)0x0010\n#define RTL_HEAP_SETTABLE_FLAG1 (USHORT)0x0020\n#define RTL_HEAP_SETTABLE_FLAG2 (USHORT)0x0040\n#define RTL_HEAP_SETTABLE_FLAG3 (USHORT)0x0080\n#define RTL_HEAP_SETTABLE_FLAGS (USHORT)0x00e0\n#define RTL_HEAP_UNCOMMITTED_RANGE (USHORT)0x0100\n#define RTL_HEAP_PROTECTED_ENTRY (USHORT)0x0200\n\ntypedef struct _RTL_HEAP_TAG\n{\n    ULONG NumberOfAllocations;\n    ULONG NumberOfFrees;\n    SIZE_T BytesAllocated;\n    USHORT TagIndex;\n    USHORT CreatorBackTraceIndex;\n    WCHAR TagName[24];\n} RTL_HEAP_TAG, *PRTL_HEAP_TAG;\n\ntypedef struct _RTL_HEAP_INFORMATION\n{\n    PVOID BaseAddress;\n    ULONG Flags;\n    USHORT EntryOverhead;\n    USHORT CreatorBackTraceIndex;\n    SIZE_T BytesAllocated;\n    SIZE_T BytesCommitted;\n    ULONG NumberOfTags;\n    ULONG NumberOfEntries;\n    ULONG NumberOfPseudoTags;\n    ULONG PseudoTagGranularity;\n    ULONG Reserved[5];\n    PRTL_HEAP_TAG Tags;\n    PRTL_HEAP_ENTRY Entries;\n} RTL_HEAP_INFORMATION, *PRTL_HEAP_INFORMATION;\n\ntypedef struct _RTL_PROCESS_HEAPS\n{\n    ULONG NumberOfHeaps;\n    RTL_HEAP_INFORMATION Heaps[1];\n} RTL_PROCESS_HEAPS, *PRTL_PROCESS_HEAPS;\n\ntypedef NTSTATUS (NTAPI *PRTL_HEAP_COMMIT_ROUTINE)(\n    _In_ PVOID Base,\n    _Inout_ PVOID *CommitAddress,\n    _Inout_ PSIZE_T CommitSize\n    );\n\ntypedef struct _RTL_HEAP_PARAMETERS\n{\n    ULONG Length;\n    SIZE_T SegmentReserve;\n    SIZE_T SegmentCommit;\n    SIZE_T DeCommitFreeBlockThreshold;\n    SIZE_T DeCommitTotalFreeThreshold;\n    SIZE_T MaximumAllocationSize;\n    SIZE_T VirtualMemoryThreshold;\n    SIZE_T InitialCommit;\n    SIZE_T InitialReserve;\n    PRTL_HEAP_COMMIT_ROUTINE CommitRoutine;\n    SIZE_T Reserved[2];\n} RTL_HEAP_PARAMETERS, *PRTL_HEAP_PARAMETERS;\n\n#define HEAP_SETTABLE_USER_VALUE 0x00000100\n#define HEAP_SETTABLE_USER_FLAG1 0x00000200\n#define HEAP_SETTABLE_USER_FLAG2 0x00000400\n#define HEAP_SETTABLE_USER_FLAG3 0x00000800\n#define HEAP_SETTABLE_USER_FLAGS 0x00000e00\n\n#define HEAP_CLASS_0 0x00000000 // Process heap\n#define HEAP_CLASS_1 0x00001000 // Private heap\n#define HEAP_CLASS_2 0x00002000 // Kernel heap\n#define HEAP_CLASS_3 0x00003000 // GDI heap\n#define HEAP_CLASS_4 0x00004000 // User heap\n#define HEAP_CLASS_5 0x00005000 // Console heap\n#define HEAP_CLASS_6 0x00006000 // User desktop heap\n#define HEAP_CLASS_7 0x00007000 // CSR shared heap\n#define HEAP_CLASS_8 0x00008000 // CSR port heap\n#define HEAP_CLASS_MASK 0x0000f000\n\nNTSYSAPI\nPVOID\nNTAPI\nRtlCreateHeap(\n    _In_ ULONG Flags,\n    _In_opt_ PVOID HeapBase,\n    _In_opt_ SIZE_T ReserveSize,\n    _In_opt_ SIZE_T CommitSize,\n    _In_opt_ PVOID Lock,\n    _In_opt_ PRTL_HEAP_PARAMETERS Parameters\n    );\n\nNTSYSAPI\nPVOID\nNTAPI\nRtlDestroyHeap(\n    _Frees_ptr_ PVOID HeapHandle\n    );\n\nNTSYSAPI\nPVOID\nNTAPI\nRtlAllocateHeap(\n    _In_ PVOID HeapHandle,\n    _In_opt_ ULONG Flags,\n    _In_ SIZE_T Size\n    );\n\nNTSYSAPI\nBOOLEAN\nNTAPI\nRtlFreeHeap(\n    _In_ PVOID HeapHandle,\n    _In_opt_ ULONG Flags,\n    _Frees_ptr_opt_ PVOID BaseAddress\n    );\n\nNTSYSAPI\nSIZE_T\nNTAPI\nRtlSizeHeap(\n    _In_ PVOID HeapHandle,\n    _In_ ULONG Flags,\n    _In_ PVOID BaseAddress\n    );\n\nNTSYSAPI\nNTSTATUS\nNTAPI\nRtlZeroHeap(\n    _In_ PVOID HeapHandle,\n    _In_ ULONG Flags\n    );\n\nNTSYSAPI\nVOID\nNTAPI\nRtlProtectHeap(\n    _In_ PVOID HeapHandle,\n    _In_ BOOLEAN MakeReadOnly\n    );\n\n#define RtlProcessHeap() (NtCurrentPeb()->ProcessHeap)\n\nNTSYSAPI\nBOOLEAN\nNTAPI\nRtlLockHeap(\n    _In_ PVOID HeapHandle\n    );\n\nNTSYSAPI\nBOOLEAN\nNTAPI\nRtlUnlockHeap(\n    _In_ PVOID HeapHandle\n    );\n\nNTSYSAPI\nPVOID\nNTAPI\nRtlReAllocateHeap(\n    _In_ PVOID HeapHandle,\n    _In_ ULONG Flags,\n    _Frees_ptr_opt_ PVOID BaseAddress,\n    _In_ SIZE_T Size\n    );\n\nNTSYSAPI\nBOOLEAN\nNTAPI\nRtlGetUserInfoHeap(\n    _In_ PVOID HeapHandle,\n    _In_ ULONG Flags,\n    _In_ PVOID BaseAddress,\n    _Out_opt_ PVOID *UserValue,\n    _Out_opt_ PULONG UserFlags\n    );\n\nNTSYSAPI\nBOOLEAN\nNTAPI\nRtlSetUserValueHeap(\n    _In_ PVOID HeapHandle,\n    _In_ ULONG Flags,\n    _In_ PVOID BaseAddress,\n    _In_ PVOID UserValue\n    );\n\nNTSYSAPI\nBOOLEAN\nNTAPI\nRtlSetUserFlagsHeap(\n    _In_ PVOID HeapHandle,\n    _In_ ULONG Flags,\n    _In_ PVOID BaseAddress,\n    _In_ ULONG UserFlagsReset,\n    _In_ ULONG UserFlagsSet\n    );\n\ntypedef struct _RTL_HEAP_TAG_INFO\n{\n    ULONG NumberOfAllocations;\n    ULONG NumberOfFrees;\n    SIZE_T BytesAllocated;\n} RTL_HEAP_TAG_INFO, *PRTL_HEAP_TAG_INFO;\n\n#define RTL_HEAP_MAKE_TAG HEAP_MAKE_TAG_FLAGS\n\nNTSYSAPI\nULONG\nNTAPI\nRtlCreateTagHeap(\n    _In_ PVOID HeapHandle,\n    _In_ ULONG Flags,\n    _In_opt_ PWSTR TagPrefix,\n    _In_ PWSTR TagNames\n    );\n\nNTSYSAPI\nPWSTR\nNTAPI\nRtlQueryTagHeap(\n    _In_ PVOID HeapHandle,\n    _In_ ULONG Flags,\n    _In_ USHORT TagIndex,\n    _In_ BOOLEAN ResetCounters,\n    _Out_opt_ PRTL_HEAP_TAG_INFO TagInfo\n    );\n\nNTSYSAPI\nNTSTATUS\nNTAPI\nRtlExtendHeap(\n    _In_ PVOID HeapHandle,\n    _In_ ULONG Flags,\n    _In_ PVOID Base,\n    _In_ SIZE_T Size\n    );\n\nNTSYSAPI\nSIZE_T\nNTAPI\nRtlCompactHeap(\n    _In_ PVOID HeapHandle,\n    _In_ ULONG Flags\n    );\n\nNTSYSAPI\nBOOLEAN\nNTAPI\nRtlValidateHeap(\n    _In_ PVOID HeapHandle,\n    _In_ ULONG Flags,\n    _In_ PVOID BaseAddress\n    );\n\nNTSYSAPI\nBOOLEAN\nNTAPI\nRtlValidateProcessHeaps(\n    VOID\n    );\n\nNTSYSAPI\nULONG\nNTAPI\nRtlGetProcessHeaps(\n    _In_ ULONG NumberOfHeaps,\n    _Out_ PVOID *ProcessHeaps\n    );\n\ntypedef NTSTATUS (NTAPI *PRTL_ENUM_HEAPS_ROUTINE)(\n    _In_ PVOID HeapHandle,\n    _In_ PVOID Parameter\n    );\n\nNTSYSAPI\nNTSTATUS\nNTAPI\nRtlEnumProcessHeaps(\n    _In_ PRTL_ENUM_HEAPS_ROUTINE EnumRoutine,\n    _In_ PVOID Parameter\n    );\n\ntypedef struct _RTL_HEAP_USAGE_ENTRY\n{\n    struct _RTL_HEAP_USAGE_ENTRY *Next;\n    PVOID Address;\n    SIZE_T Size;\n    USHORT AllocatorBackTraceIndex;\n    USHORT TagIndex;\n} RTL_HEAP_USAGE_ENTRY, *PRTL_HEAP_USAGE_ENTRY;\n\ntypedef struct _RTL_HEAP_USAGE\n{\n    ULONG Length;\n    SIZE_T BytesAllocated;\n    SIZE_T BytesCommitted;\n    SIZE_T BytesReserved;\n    SIZE_T BytesReservedMaximum;\n    PRTL_HEAP_USAGE_ENTRY Entries;\n    PRTL_HEAP_USAGE_ENTRY AddedEntries;\n    PRTL_HEAP_USAGE_ENTRY RemovedEntries;\n    ULONG_PTR Reserved[8];\n} RTL_HEAP_USAGE, *PRTL_HEAP_USAGE;\n\n#define HEAP_USAGE_ALLOCATED_BLOCKS HEAP_REALLOC_IN_PLACE_ONLY\n#define HEAP_USAGE_FREE_BUFFER HEAP_ZERO_MEMORY\n\nNTSYSAPI\nNTSTATUS\nNTAPI\nRtlUsageHeap(\n    _In_ PVOID HeapHandle,\n    _In_ ULONG Flags,\n    _Inout_ PRTL_HEAP_USAGE Usage\n    );\n\ntypedef struct _RTL_HEAP_WALK_ENTRY\n{\n    PVOID DataAddress;\n    SIZE_T DataSize;\n    UCHAR OverheadBytes;\n    UCHAR SegmentIndex;\n    USHORT Flags;\n    union\n    {\n        struct\n        {\n            SIZE_T Settable;\n            USHORT TagIndex;\n            USHORT AllocatorBackTraceIndex;\n            ULONG Reserved[2];\n        } Block;\n        struct\n        {\n            ULONG CommittedSize;\n            ULONG UnCommittedSize;\n            PVOID FirstEntry;\n            PVOID LastEntry;\n        } Segment;\n    };\n} RTL_HEAP_WALK_ENTRY, *PRTL_HEAP_WALK_ENTRY;\n\nNTSYSAPI\nNTSTATUS\nNTAPI\nRtlWalkHeap(\n    _In_ PVOID HeapHandle,\n    _Inout_ PRTL_HEAP_WALK_ENTRY Entry\n    );\n\n// HEAP_INFORMATION_CLASS\n#define HeapCompatibilityInformation 0x0 // q; s: ULONG\n#define HeapEnableTerminationOnCorruption 0x1 // q; s: NULL\n#define HeapExtendedInformation 0x2 // q; s: HEAP_EXTENDED_INFORMATION\n#define HeapOptimizeResources 0x3 // q; s: HEAP_OPTIMIZE_RESOURCES_INFORMATION \n#define HeapTaggingInformation 0x4\n#define HeapStackDatabase 0x5\n#define HeapDetailedFailureInformation 0x80000001\n#define HeapSetDebuggingInformation 0x80000002 // q; s: HEAP_DEBUGGING_INFORMATION\n\ntypedef struct _PROCESS_HEAP_INFORMATION\n{\n    ULONG_PTR ReserveSize;\n    ULONG_PTR CommitSize;\n    ULONG NumberOfHeaps;\n    ULONG_PTR FirstHeapInformationOffset;\n} PROCESS_HEAP_INFORMATION, *PPROCESS_HEAP_INFORMATION;\n\ntypedef struct _HEAP_INFORMATION\n{\n    ULONG_PTR Address;\n    ULONG Mode;\n    ULONG_PTR ReserveSize;\n    ULONG_PTR CommitSize;\n    ULONG_PTR FirstRegionInformationOffset;\n    ULONG_PTR NextHeapInformationOffset;\n} HEAP_INFORMATION, *PHEAP_INFORMATION;\n\ntypedef struct _HEAP_EXTENDED_INFORMATION\n{\n    HANDLE Process;\n    ULONG_PTR Heap;\n    ULONG Level;\n    PVOID CallbackRoutine;\n    PVOID CallbackContext;\n    PROCESS_HEAP_INFORMATION ProcessHeapInformation;\n    HEAP_INFORMATION HeapInformation;\n} HEAP_EXTENDED_INFORMATION, *PHEAP_EXTENDED_INFORMATION;\n\n// rev\ntypedef NTSTATUS (NTAPI *PRTL_HEAP_LEAK_ENUMERATION_ROUTINE)(\n    _In_ LONG Reserved,\n    _In_ PVOID HeapHandle,\n    _In_ PVOID BaseAddress,\n    _In_ SIZE_T BlockSize,\n    _In_ ULONG StackTraceDepth,\n    _In_ PVOID *StackTrace\n    );\n\n// symbols\ntypedef struct _HEAP_DEBUGGING_INFORMATION\n{\n    PVOID InterceptorFunction;\n    USHORT InterceptorValue;\n    ULONG ExtendedOptions;\n    ULONG StackTraceDepth;\n    SIZE_T MinTotalBlockSize;\n    SIZE_T MaxTotalBlockSize;\n    PRTL_HEAP_LEAK_ENUMERATION_ROUTINE HeapLeakEnumerationRoutine;\n} HEAP_DEBUGGING_INFORMATION, *PHEAP_DEBUGGING_INFORMATION;\n\nNTSYSAPI\nNTSTATUS\nNTAPI\nRtlQueryHeapInformation(\n    _In_ PVOID HeapHandle,\n    _In_ HEAP_INFORMATION_CLASS HeapInformationClass,\n    _Out_opt_ PVOID HeapInformation,\n    _In_opt_ SIZE_T HeapInformationLength,\n    _Out_opt_ PSIZE_T ReturnLength\n    );\n\nNTSYSAPI\nNTSTATUS\nNTAPI\nRtlSetHeapInformation(\n    _In_ PVOID HeapHandle,\n    _In_ HEAP_INFORMATION_CLASS HeapInformationClass,\n    _In_opt_ PVOID HeapInformation,\n    _In_opt_ SIZE_T HeapInformationLength\n    );\n\nNTSYSAPI\nULONG\nNTAPI\nRtlMultipleAllocateHeap(\n    _In_ PVOID HeapHandle,\n    _In_ ULONG Flags,\n    _In_ SIZE_T Size,\n    _In_ ULONG Count,\n    _Out_ PVOID *Array\n    );\n\nNTSYSAPI\nULONG\nNTAPI\nRtlMultipleFreeHeap(\n    _In_ PVOID HeapHandle,\n    _In_ ULONG Flags,\n    _In_ ULONG Count,\n    _In_ PVOID *Array\n    );\n\n#if (PHNT_VERSION >= PHNT_WIN7)\nNTSYSAPI\nVOID\nNTAPI\nRtlDetectHeapLeaks(\n    VOID\n    );\n#endif\n\n// Memory zones\n\n// begin_private\n\ntypedef struct _RTL_MEMORY_ZONE_SEGMENT\n{\n    struct _RTL_MEMORY_ZONE_SEGMENT *NextSegment;\n    SIZE_T Size;\n    PVOID Next;\n    PVOID Limit;\n} RTL_MEMORY_ZONE_SEGMENT, *PRTL_MEMORY_ZONE_SEGMENT;\n\ntypedef struct _RTL_MEMORY_ZONE\n{\n    RTL_MEMORY_ZONE_SEGMENT Segment;\n    RTL_SRWLOCK Lock;\n    ULONG LockCount;\n    PRTL_MEMORY_ZONE_SEGMENT FirstSegment;\n} RTL_MEMORY_ZONE, *PRTL_MEMORY_ZONE;\n\n#if (PHNT_VERSION >= PHNT_VISTA)\n\nNTSYSAPI\nNTSTATUS\nNTAPI\nRtlCreateMemoryZone(\n    _Out_ PVOID *MemoryZone,\n    _In_ SIZE_T InitialSize,\n    _Reserved_ ULONG Flags\n    );\n\nNTSYSAPI\nNTSTATUS\nNTAPI\nRtlDestroyMemoryZone(\n    _In_ _Post_invalid_ PVOID MemoryZone\n    );\n\nNTSYSAPI\nNTSTATUS\nNTAPI\nRtlAllocateMemoryZone(\n    _In_ PVOID MemoryZone,\n    _In_ SIZE_T BlockSize,\n    _Out_ PVOID *Block\n    );\n\nNTSYSAPI\nNTSTATUS\nNTAPI\nRtlResetMemoryZone(\n    _In_ PVOID MemoryZone\n    );\n\nNTSYSAPI\nNTSTATUS\nNTAPI\nRtlLockMemoryZone(\n    _In_ PVOID MemoryZone\n    );\n\nNTSYSAPI\nNTSTATUS\nNTAPI\nRtlUnlockMemoryZone(\n    _In_ PVOID MemoryZone\n    );\n\n#endif\n\n// end_private\n\n// Memory block lookaside lists\n\n// begin_private\n\n#if (PHNT_VERSION >= PHNT_VISTA)\n\nNTSYSAPI\nNTSTATUS\nNTAPI\nRtlCreateMemoryBlockLookaside(\n    _Out_ PVOID *MemoryBlockLookaside,\n    _Reserved_ ULONG Flags,\n    _In_ ULONG InitialSize,\n    _In_ ULONG MinimumBlockSize,\n    _In_ ULONG MaximumBlockSize\n    );\n\nNTSYSAPI\nNTSTATUS\nNTAPI\nRtlDestroyMemoryBlockLookaside(\n    _In_ PVOID MemoryBlockLookaside\n    );\n\nNTSYSAPI\nNTSTATUS\nNTAPI\nRtlAllocateMemoryBlockLookaside(\n    _In_ PVOID MemoryBlockLookaside,\n    _In_ ULONG BlockSize,\n    _Out_ PVOID *Block\n    );\n\nNTSYSAPI\nNTSTATUS\nNTAPI\nRtlFreeMemoryBlockLookaside(\n    _In_ PVOID MemoryBlockLookaside,\n    _In_ PVOID Block\n    );\n\nNTSYSAPI\nNTSTATUS\nNTAPI\nRtlExtendMemoryBlockLookaside(\n    _In_ PVOID MemoryBlockLookaside,\n    _In_ ULONG Increment\n    );\n\nNTSYSAPI\nNTSTATUS\nNTAPI\nRtlResetMemoryBlockLookaside(\n    _In_ PVOID MemoryBlockLookaside\n    );\n\nNTSYSAPI\nNTSTATUS\nNTAPI\nRtlLockMemoryBlockLookaside(\n    _In_ PVOID MemoryBlockLookaside\n    );\n\nNTSYSAPI\nNTSTATUS\nNTAPI\nRtlUnlockMemoryBlockLookaside(\n    _In_ PVOID MemoryBlockLookaside\n    );\n\n#endif\n\n// end_private\n\n// Transactions\n\n#if (PHNT_VERSION >= PHNT_VISTA)\n// private\nNTSYSAPI\nHANDLE\nNTAPI\nRtlGetCurrentTransaction(\n    VOID\n    );\n#endif\n\n#if (PHNT_VERSION >= PHNT_VISTA)\n// private\nNTSYSAPI\nLOGICAL\nNTAPI\nRtlSetCurrentTransaction(\n    _In_ HANDLE TransactionHandle\n    );\n#endif\n\n// LUIDs\n\nFORCEINLINE BOOLEAN RtlIsEqualLuid(\n    _In_ PLUID L1,\n    _In_ PLUID L2\n    )\n{\n    return L1->LowPart == L2->LowPart &&\n        L1->HighPart == L2->HighPart;\n}\n\nFORCEINLINE BOOLEAN RtlIsZeroLuid(\n    _In_ PLUID L1\n    )\n{\n    return (L1->LowPart | L1->HighPart) == 0;\n}\n\nFORCEINLINE LUID RtlConvertLongToLuid(\n    _In_ LONG Long\n    )\n{\n    LUID tempLuid;\n    LARGE_INTEGER tempLi;\n\n    tempLi.QuadPart = Long;\n    tempLuid.LowPart = tempLi.LowPart;\n    tempLuid.HighPart = tempLi.HighPart;\n\n    return tempLuid;\n}\n\nFORCEINLINE LUID RtlConvertUlongToLuid(\n    _In_ ULONG Ulong\n    )\n{\n    LUID tempLuid;\n\n    tempLuid.LowPart = Ulong;\n    tempLuid.HighPart = 0;\n\n    return tempLuid;\n}\n\nNTSYSAPI\nVOID\nNTAPI\nRtlCopyLuid(\n    _Out_ PLUID DestinationLuid,\n    _In_ PLUID SourceLuid\n    );\n\n// Debugging\n\n// private\ntypedef struct _RTL_PROCESS_VERIFIER_OPTIONS\n{\n    ULONG SizeStruct;\n    ULONG Option;\n    UCHAR OptionData[1];\n} RTL_PROCESS_VERIFIER_OPTIONS, *PRTL_PROCESS_VERIFIER_OPTIONS;\n\n// private\ntypedef struct _RTL_DEBUG_INFORMATION\n{\n    HANDLE SectionHandleClient;\n    PVOID ViewBaseClient;\n    PVOID ViewBaseTarget;\n    ULONG_PTR ViewBaseDelta;\n    HANDLE EventPairClient;\n    HANDLE EventPairTarget;\n    HANDLE TargetProcessId;\n    HANDLE TargetThreadHandle;\n    ULONG Flags;\n    SIZE_T OffsetFree;\n    SIZE_T CommitSize;\n    SIZE_T ViewSize;\n    union\n    {\n        struct _RTL_PROCESS_MODULES *Modules;\n        struct _RTL_PROCESS_MODULE_INFORMATION_EX *ModulesEx;\n    };\n    struct _RTL_PROCESS_BACKTRACES *BackTraces;\n    struct _RTL_PROCESS_HEAPS *Heaps;\n    struct _RTL_PROCESS_LOCKS *Locks;\n    PVOID SpecificHeap;\n    HANDLE TargetProcessHandle;\n    PRTL_PROCESS_VERIFIER_OPTIONS VerifierOptions;\n    PVOID ProcessHeap;\n    HANDLE CriticalSectionHandle;\n    HANDLE CriticalSectionOwnerThread;\n    PVOID Reserved[4];\n} RTL_DEBUG_INFORMATION, *PRTL_DEBUG_INFORMATION;\n\nNTSYSAPI\nPRTL_DEBUG_INFORMATION\nNTAPI\nRtlCreateQueryDebugBuffer(\n    _In_opt_ ULONG MaximumCommit,\n    _In_ BOOLEAN UseEventPair\n    );\n\nNTSYSAPI\nNTSTATUS\nNTAPI\nRtlDestroyQueryDebugBuffer(\n    _In_ PRTL_DEBUG_INFORMATION Buffer\n    );\n\n#if (PHNT_VERSION >= PHNT_VISTA)\n\n// private\nNTSYSAPI\nPVOID\nNTAPI\nRtlCommitDebugInfo(\n    _Inout_ PRTL_DEBUG_INFORMATION Buffer,\n    _In_ SIZE_T Size\n    );\n\n// private\nNTSYSAPI\nVOID\nNTAPI\nRtlDeCommitDebugInfo(\n    _Inout_ PRTL_DEBUG_INFORMATION Buffer,\n    _In_ PVOID p,\n    _In_ SIZE_T Size\n    );\n\n#endif\n\n#define RTL_QUERY_PROCESS_MODULES 0x00000001\n#define RTL_QUERY_PROCESS_BACKTRACES 0x00000002\n#define RTL_QUERY_PROCESS_HEAP_SUMMARY 0x00000004\n#define RTL_QUERY_PROCESS_HEAP_TAGS 0x00000008\n#define RTL_QUERY_PROCESS_HEAP_ENTRIES 0x00000010\n#define RTL_QUERY_PROCESS_LOCKS 0x00000020\n#define RTL_QUERY_PROCESS_MODULES32 0x00000040\n#define RTL_QUERY_PROCESS_VERIFIER_OPTIONS 0x00000080 // rev\n#define RTL_QUERY_PROCESS_MODULESEX 0x00000100 // rev\n#define RTL_QUERY_PROCESS_HEAP_ENTRIES_EX 0x00000200 // ?\n#define RTL_QUERY_PROCESS_CS_OWNER 0x00000400 // rev\n#define RTL_QUERY_PROCESS_NONINVASIVE 0x80000000\n\nNTSYSAPI\nNTSTATUS\nNTAPI\nRtlQueryProcessDebugInformation(\n    _In_ HANDLE UniqueProcessId,\n    _In_ ULONG Flags,\n    _Inout_ PRTL_DEBUG_INFORMATION Buffer\n    );\n\n// Messages\n\nNTSYSAPI\nNTSTATUS\nNTAPI\nRtlFindMessage(\n    _In_ PVOID DllHandle,\n    _In_ ULONG MessageTableId,\n    _In_ ULONG MessageLanguageId,\n    _In_ ULONG MessageId,\n    _Out_ PMESSAGE_RESOURCE_ENTRY *MessageEntry\n    );\n\nNTSYSAPI\nNTSTATUS\nNTAPI\nRtlFormatMessage(\n    _In_ PWSTR MessageFormat,\n    _In_ ULONG MaximumWidth,\n    _In_ BOOLEAN IgnoreInserts,\n    _In_ BOOLEAN ArgumentsAreAnsi,\n    _In_ BOOLEAN ArgumentsAreAnArray,\n    _In_ va_list *Arguments,\n    _Out_writes_bytes_to_(Length, *ReturnLength) PWSTR Buffer,\n    _In_ ULONG Length,\n    _Out_opt_ PULONG ReturnLength\n    );\n\ntypedef struct _PARSE_MESSAGE_CONTEXT\n{\n    ULONG fFlags;\n    ULONG cwSavColumn;\n    SIZE_T iwSrc;\n    SIZE_T iwDst;\n    SIZE_T iwDstSpace;\n    va_list lpvArgStart;\n} PARSE_MESSAGE_CONTEXT, *PPARSE_MESSAGE_CONTEXT;\n\n#define INIT_PARSE_MESSAGE_CONTEXT(ctx) \\\n    { \\\n        (ctx)->fFlags = 0; \\\n    }\n\n#define TEST_PARSE_MESSAGE_CONTEXT_FLAG(ctx, flag) ((ctx)->fFlags & (flag))\n#define SET_PARSE_MESSAGE_CONTEXT_FLAG(ctx, flag) ((ctx)->fFlags |= (flag))\n#define CLEAR_PARSE_MESSAGE_CONTEXT_FLAG(ctx, flag) ((ctx)->fFlags &= ~(flag))\n\nNTSYSAPI\nNTSTATUS\nNTAPI\nRtlFormatMessageEx(\n    _In_ PWSTR MessageFormat,\n    _In_ ULONG MaximumWidth,\n    _In_ BOOLEAN IgnoreInserts,\n    _In_ BOOLEAN ArgumentsAreAnsi,\n    _In_ BOOLEAN ArgumentsAreAnArray,\n    _In_ va_list *Arguments,\n    _Out_writes_bytes_to_(Length, *ReturnLength) PWSTR Buffer,\n    _In_ ULONG Length,\n    _Out_opt_ PULONG ReturnLength,\n    _Out_opt_ PPARSE_MESSAGE_CONTEXT ParseContext\n    );\n\n// Errors\n\nNTSYSAPI\nULONG\nNTAPI\nRtlNtStatusToDosError(\n    _In_ NTSTATUS Status\n    );\n\nNTSYSAPI\nULONG\nNTAPI\nRtlNtStatusToDosErrorNoTeb(\n    _In_ NTSTATUS Status\n    );\n\nNTSYSAPI\nNTSTATUS\nNTAPI\nRtlGetLastNtStatus(\n    VOID\n    );\n\nNTSYSAPI\nLONG\nNTAPI\nRtlGetLastWin32Error(\n    VOID\n    );\n\nNTSYSAPI\nVOID\nNTAPI\nRtlSetLastWin32ErrorAndNtStatusFromNtStatus(\n    _In_ NTSTATUS Status\n    );\n\nNTSYSAPI\nVOID\nNTAPI\nRtlSetLastWin32Error(\n    _In_ LONG Win32Error\n    );\n\nNTSYSAPI\nVOID\nNTAPI\nRtlRestoreLastWin32Error(\n    _In_ LONG Win32Error\n    );\n\n#define RTL_ERRORMODE_NOGPFAULTERRORBOX 0x0020\n#define RTL_ERRORMODE_NOOPENFILEERRORBOX 0x0040\n\nNTSYSAPI\nULONG\nNTAPI\nRtlGetThreadErrorMode(\n    VOID\n    );\n\nNTSYSAPI\nNTSTATUS\nNTAPI\nRtlSetThreadErrorMode(\n    _In_ ULONG NewMode,\n    _Out_opt_ PULONG OldMode\n    );\n\n// Windows Error Reporting\n\n#if (PHNT_VERSION >= PHNT_VISTA)\n// private\nNTSYSAPI\nNTSTATUS\nNTAPI\nRtlReportException(\n    _In_ PEXCEPTION_RECORD ExceptionRecord,\n    _In_ PCONTEXT ContextRecord,\n    _In_ ULONG Flags\n    );\n#endif\n\n#if (PHNT_VERSION >= PHNT_VISTA)\n// private\nNTSYSAPI\nNTSTATUS\nNTAPI\nRtlWerpReportException(\n    _In_ ULONG ProcessId,\n    _In_ HANDLE CrashReportSharedMem,\n    _In_ ULONG Flags,\n    _Out_ PHANDLE CrashVerticalProcessHandle\n    );\n#endif\n\n#if (PHNT_VERSION >= PHNT_WIN7)\n// rev\nNTSYSAPI\nNTSTATUS\nNTAPI\nRtlReportSilentProcessExit(\n    _In_ HANDLE ProcessHandle,\n    _In_ NTSTATUS ExitStatus\n    );\n#endif\n\n// Vectored Exception Handlers\n\nNTSYSAPI\nPVOID\nNTAPI\nRtlAddVectoredExceptionHandler(\n    _In_ ULONG First,\n    _In_ PVECTORED_EXCEPTION_HANDLER Handler\n    );\n\nNTSYSAPI\nULONG\nNTAPI\nRtlRemoveVectoredExceptionHandler(\n    _In_ PVOID Handle\n    );\n\nNTSYSAPI\nPVOID\nNTAPI\nRtlAddVectoredContinueHandler(\n    _In_ ULONG First,\n    _In_ PVECTORED_EXCEPTION_HANDLER Handler\n    );\n\nNTSYSAPI\nULONG\nNTAPI\nRtlRemoveVectoredContinueHandler(\n    _In_ PVOID Handle\n    );\n\n// Random\n\nNTSYSAPI\nULONG\nNTAPI\nRtlUniform(\n    _Inout_ PULONG Seed\n    );\n\nNTSYSAPI\nULONG\nNTAPI\nRtlRandom(\n    _Inout_ PULONG Seed\n    );\n\nNTSYSAPI\nULONG\nNTAPI\nRtlRandomEx(\n    _Inout_ PULONG Seed\n    );\n\nNTSYSAPI\nNTSTATUS\nNTAPI\nRtlComputeImportTableHash(\n    _In_ HANDLE hFile,\n    _Out_writes_bytes_(16) PCHAR Hash,\n    _In_ ULONG ImportTableHashRevision // must be 1\n    );\n\n// Integer conversion\n\nNTSYSAPI\nNTSTATUS\nNTAPI\nRtlIntegerToChar(\n    _In_ ULONG Value,\n    _In_opt_ ULONG Base,\n    _In_ LONG OutputLength, // negative to pad to width\n    _Out_ PSTR String\n    );\n\nNTSYSAPI\nNTSTATUS\nNTAPI\nRtlCharToInteger(\n    _In_ PSTR String,\n    _In_opt_ ULONG Base,\n    _Out_ PULONG Value\n    );\n\nNTSYSAPI\nNTSTATUS\nNTAPI\nRtlLargeIntegerToChar(\n    _In_ PLARGE_INTEGER Value,\n    _In_opt_ ULONG Base,\n    _In_ LONG OutputLength,\n    _Out_ PSTR String\n    );\n\nNTSYSAPI\nNTSTATUS\nNTAPI\nRtlIntegerToUnicodeString(\n    _In_ ULONG Value,\n    _In_opt_ ULONG Base,\n    _Inout_ PUNICODE_STRING String\n    );\n\nNTSYSAPI\nNTSTATUS\nNTAPI\nRtlInt64ToUnicodeString(\n    _In_ ULONGLONG Value,\n    _In_opt_ ULONG Base,\n    _Inout_ PUNICODE_STRING String\n    );\n\n#ifdef _WIN64\n#define RtlIntPtrToUnicodeString(Value, Base, String) RtlInt64ToUnicodeString(Value, Base, String)\n#else\n#define RtlIntPtrToUnicodeString(Value, Base, String) RtlIntegerToUnicodeString(Value, Base, String)\n#endif\n\nNTSYSAPI\nNTSTATUS\nNTAPI\nRtlUnicodeStringToInteger(\n    _In_ PUNICODE_STRING String,\n    _In_opt_ ULONG Base,\n    _Out_ PULONG Value\n    );\n\n// IPv4/6 conversion\n\nstruct in_addr;\nstruct in6_addr;\n\nNTSYSAPI\nPWSTR\nNTAPI\nRtlIpv4AddressToStringW(\n    _In_ struct in_addr *Addr,\n    _Out_writes_(16) PWSTR S\n    );\n\nNTSYSAPI\nNTSTATUS\nNTAPI\nRtlIpv4AddressToStringExW(\n    _In_ struct in_addr *Address,\n    _In_ USHORT Port,\n    _Out_writes_to_(*AddressStringLength, *AddressStringLength) PWSTR AddressString,\n    _Inout_ PULONG AddressStringLength\n    );\n\nNTSYSAPI\nPWSTR\nNTAPI\nRtlIpv6AddressToStringW(\n    _In_ struct in6_addr *Addr,\n    _Out_writes_(65) PWSTR S\n    );\n\nNTSYSAPI\nNTSTATUS\nNTAPI\nRtlIpv6AddressToStringExW(\n    _In_ struct in6_addr *Address,\n    _In_ ULONG ScopeId,\n    _In_ USHORT Port,\n    _Out_writes_to_(*AddressStringLength, *AddressStringLength) PWSTR AddressString,\n    _Inout_ PULONG AddressStringLength\n    );\n\nNTSYSAPI\nNTSTATUS\nNTAPI\nRtlIpv4StringToAddressW(\n    _In_ PWSTR S,\n    _In_ BOOLEAN Strict,\n    _Out_ PWSTR *Terminator,\n    _Out_ struct in_addr *Addr\n    );\n\nNTSYSAPI\nNTSTATUS\nNTAPI\nRtlIpv4StringToAddressExW(\n    _In_ PWSTR AddressString,\n    _In_ BOOLEAN Strict,\n    _Out_ struct in_addr *Address,\n    _Out_ PUSHORT Port\n    );\n\nNTSYSAPI\nNTSTATUS\nNTAPI\nRtlIpv6StringToAddressW(\n    _In_ PWSTR S,\n    _Out_ PWSTR *Terminator,\n    _Out_ struct in6_addr *Addr\n    );\n\nNTSYSAPI\nNTSTATUS\nNTAPI\nRtlIpv6StringToAddressExW(\n    _In_ PWSTR AddressString,\n    _Out_ struct in6_addr *Address,\n    _Out_ PULONG ScopeId,\n    _Out_ PUSHORT Port\n    );\n\n#define RtlIpv4AddressToString RtlIpv4AddressToStringW\n#define RtlIpv4AddressToStringEx RtlIpv4AddressToStringExW\n#define RtlIpv6AddressToString RtlIpv6AddressToStringW\n#define RtlIpv6AddressToStringEx RtlIpv6AddressToStringExW\n#define RtlIpv4StringToAddress RtlIpv4StringToAddressW\n#define RtlIpv4StringToAddressEx RtlIpv4StringToAddressExW\n#define RtlIpv6StringToAddress RtlIpv6StringToAddressW\n#define RtlIpv6StringToAddressEx RtlIpv6StringToAddressExW\n\n// Time\n\ntypedef struct _TIME_FIELDS\n{\n    CSHORT Year; // 1601...\n    CSHORT Month; // 1..12\n    CSHORT Day; // 1..31\n    CSHORT Hour; // 0..23\n    CSHORT Minute; // 0..59\n    CSHORT Second; // 0..59\n    CSHORT Milliseconds; // 0..999\n    CSHORT Weekday; // 0..6 = Sunday..Saturday\n} TIME_FIELDS, *PTIME_FIELDS;\n\nNTSYSAPI\nBOOLEAN\nNTAPI\nRtlCutoverTimeToSystemTime(\n    _In_ PTIME_FIELDS CutoverTime,\n    _Out_ PLARGE_INTEGER SystemTime,\n    _In_ PLARGE_INTEGER CurrentSystemTime,\n    _In_ BOOLEAN ThisYear\n    );\n\nNTSYSAPI\nNTSTATUS\nNTAPI\nRtlSystemTimeToLocalTime(\n    _In_ PLARGE_INTEGER SystemTime,\n    _Out_ PLARGE_INTEGER LocalTime\n    );\n\nNTSYSAPI\nNTSTATUS\nNTAPI\nRtlLocalTimeToSystemTime(\n    _In_ PLARGE_INTEGER LocalTime,\n    _Out_ PLARGE_INTEGER SystemTime\n    );\n\nNTSYSAPI\nVOID\nNTAPI\nRtlTimeToElapsedTimeFields(\n    _In_ PLARGE_INTEGER Time,\n    _Out_ PTIME_FIELDS TimeFields\n    );\n\nNTSYSAPI\nVOID\nNTAPI\nRtlTimeToTimeFields(\n    _In_ PLARGE_INTEGER Time,\n    _Out_ PTIME_FIELDS TimeFields\n    );\n\nNTSYSAPI\nBOOLEAN\nNTAPI\nRtlTimeFieldsToTime(\n    _In_ PTIME_FIELDS TimeFields, // Weekday is ignored\n    _Out_ PLARGE_INTEGER Time\n    );\n\nNTSYSAPI\nBOOLEAN\nNTAPI\nRtlTimeToSecondsSince1980(\n    _In_ PLARGE_INTEGER Time,\n    _Out_ PULONG ElapsedSeconds\n    );\n\nNTSYSAPI\nVOID\nNTAPI\nRtlSecondsSince1980ToTime(\n    _In_ ULONG ElapsedSeconds,\n    _Out_ PLARGE_INTEGER Time\n    );\n\nNTSYSAPI\nBOOLEAN\nNTAPI\nRtlTimeToSecondsSince1970(\n    _In_ PLARGE_INTEGER Time,\n    _Out_ PULONG ElapsedSeconds\n    );\n\nNTSYSAPI\nVOID\nNTAPI\nRtlSecondsSince1970ToTime(\n    _In_ ULONG ElapsedSeconds,\n    _Out_ PLARGE_INTEGER Time\n    );\n\n// Time zones\n\ntypedef struct _RTL_TIME_ZONE_INFORMATION\n{\n    LONG Bias;\n    WCHAR StandardName[32];\n    TIME_FIELDS StandardStart;\n    LONG StandardBias;\n    WCHAR DaylightName[32];\n    TIME_FIELDS DaylightStart;\n    LONG DaylightBias;\n} RTL_TIME_ZONE_INFORMATION, *PRTL_TIME_ZONE_INFORMATION;\n\nNTSYSAPI\nNTSTATUS\nNTAPI\nRtlQueryTimeZoneInformation(\n    _Out_ PRTL_TIME_ZONE_INFORMATION TimeZoneInformation\n    );\n\nNTSYSAPI\nNTSTATUS\nNTAPI\nRtlSetTimeZoneInformation(\n    _In_ PRTL_TIME_ZONE_INFORMATION TimeZoneInformation\n    );\n\n// Bitmaps\n\ntypedef struct _RTL_BITMAP\n{\n    ULONG SizeOfBitMap;\n    PULONG Buffer;\n} RTL_BITMAP, *PRTL_BITMAP;\n\ntypedef struct _RTL_BITMAP_EX\n{\n    ULONG64 SizeOfBitMap;\n    PULONG64 Buffer;\n} RTL_BITMAP_EX, *PRTL_BITMAP_EX;\n\nNTSYSAPI\nVOID\nNTAPI\nRtlInitializeBitMap(\n    _Out_ PRTL_BITMAP BitMapHeader,\n    _In_ PULONG BitMapBuffer,\n    _In_ ULONG SizeOfBitMap\n    );\n\n#if (PHNT_MODE == PHNT_MODE_KERNEL || PHNT_VERSION >= PHNT_WIN8)\nNTSYSAPI\nVOID\nNTAPI\nRtlClearBit(\n    _In_ PRTL_BITMAP BitMapHeader,\n    _In_range_(<, BitMapHeader->SizeOfBitMap) ULONG BitNumber\n    );\n#endif\n\n#if (PHNT_MODE == PHNT_MODE_KERNEL || PHNT_VERSION >= PHNT_WIN8)\nNTSYSAPI\nVOID\nNTAPI\nRtlSetBit(\n    _In_ PRTL_BITMAP BitMapHeader,\n    _In_range_(<, BitMapHeader->SizeOfBitMap) ULONG BitNumber\n    );\n#endif\n\n_Check_return_\nNTSYSAPI\nBOOLEAN\nNTAPI\nRtlTestBit(\n    _In_ PRTL_BITMAP BitMapHeader,\n    _In_range_(<, BitMapHeader->SizeOfBitMap) ULONG BitNumber\n    );\n\nNTSYSAPI\nVOID\nNTAPI\nRtlClearAllBits(\n    _In_ PRTL_BITMAP BitMapHeader\n    );\n\nNTSYSAPI\nVOID\nNTAPI\nRtlSetAllBits(\n    _In_ PRTL_BITMAP BitMapHeader\n    );\n\n_Success_(return != -1)\n_Check_return_\nNTSYSAPI\nULONG\nNTAPI\nRtlFindClearBits(\n    _In_ PRTL_BITMAP BitMapHeader,\n    _In_ ULONG NumberToFind,\n    _In_ ULONG HintIndex\n    );\n\n_Success_(return != -1)\n_Check_return_\nNTSYSAPI\nULONG\nNTAPI\nRtlFindSetBits(\n    _In_ PRTL_BITMAP BitMapHeader,\n    _In_ ULONG NumberToFind,\n    _In_ ULONG HintIndex\n    );\n\n_Success_(return != -1)\nNTSYSAPI\nULONG\nNTAPI\nRtlFindClearBitsAndSet(\n    _In_ PRTL_BITMAP BitMapHeader,\n    _In_ ULONG NumberToFind,\n    _In_ ULONG HintIndex\n    );\n\n_Success_(return != -1)\nNTSYSAPI\nULONG\nNTAPI\nRtlFindSetBitsAndClear(\n    _In_ PRTL_BITMAP BitMapHeader,\n    _In_ ULONG NumberToFind,\n    _In_ ULONG HintIndex\n    );\n\nNTSYSAPI\nVOID\nNTAPI\nRtlClearBits(\n    _In_ PRTL_BITMAP BitMapHeader,\n    _In_range_(0, BitMapHeader->SizeOfBitMap - NumberToClear) ULONG StartingIndex,\n    _In_range_(0, BitMapHeader->SizeOfBitMap - StartingIndex) ULONG NumberToClear\n    );\n\nNTSYSAPI\nVOID\nNTAPI\nRtlSetBits(\n    _In_ PRTL_BITMAP BitMapHeader,\n    _In_range_(0, BitMapHeader->SizeOfBitMap - NumberToSet) ULONG StartingIndex,\n    _In_range_(0, BitMapHeader->SizeOfBitMap - StartingIndex) ULONG NumberToSet\n    );\n\ntypedef struct _RTL_BITMAP_RUN\n{\n    ULONG StartingIndex;\n    ULONG NumberOfBits;\n} RTL_BITMAP_RUN, *PRTL_BITMAP_RUN;\n\nNTSYSAPI\nULONG\nNTAPI\nRtlFindClearRuns(\n    _In_ PRTL_BITMAP BitMapHeader,\n    _Out_writes_to_(SizeOfRunArray, return) PRTL_BITMAP_RUN RunArray,\n    _In_range_(>, 0) ULONG SizeOfRunArray,\n    _In_ BOOLEAN LocateLongestRuns\n    );\n\nNTSYSAPI\nULONG\nNTAPI\nRtlFindLongestRunClear(\n    _In_ PRTL_BITMAP BitMapHeader,\n    _Out_ PULONG StartingIndex\n    );\n\nNTSYSAPI\nULONG\nNTAPI\nRtlFindFirstRunClear(\n    _In_ PRTL_BITMAP BitMapHeader,\n    _Out_ PULONG StartingIndex\n    );\n\n_Check_return_\nFORCEINLINE\nBOOLEAN\nRtlCheckBit(\n    _In_ PRTL_BITMAP BitMapHeader,\n    _In_range_(<, BitMapHeader->SizeOfBitMap) ULONG BitPosition\n    )\n{\n#ifdef _WIN64\n    return BitTest64((LONG64 const *)BitMapHeader->Buffer, (LONG64)BitPosition);\n#else\n    return (((PLONG)BitMapHeader->Buffer)[BitPosition / 32] >> (BitPosition % 32)) & 0x1;\n#endif\n}\n\nNTSYSAPI\nULONG\nNTAPI\nRtlNumberOfClearBits(\n    _In_ PRTL_BITMAP BitMapHeader\n    );\n\nNTSYSAPI\nULONG\nNTAPI\nRtlNumberOfSetBits(\n    _In_ PRTL_BITMAP BitMapHeader\n    );\n\n_Check_return_\nNTSYSAPI\nBOOLEAN\nNTAPI\nRtlAreBitsClear(\n    _In_ PRTL_BITMAP BitMapHeader,\n    _In_ ULONG StartingIndex,\n    _In_ ULONG Length\n    );\n\n_Check_return_\nNTSYSAPI\nBOOLEAN\nNTAPI\nRtlAreBitsSet(\n    _In_ PRTL_BITMAP BitMapHeader,\n    _In_ ULONG StartingIndex,\n    _In_ ULONG Length\n    );\n\nNTSYSAPI\nULONG\nNTAPI\nRtlFindNextForwardRunClear(\n    _In_ PRTL_BITMAP BitMapHeader,\n    _In_ ULONG FromIndex,\n    _Out_ PULONG StartingRunIndex\n    );\n\nNTSYSAPI\nULONG\nNTAPI\nRtlFindLastBackwardRunClear(\n    _In_ PRTL_BITMAP BitMapHeader,\n    _In_ ULONG FromIndex,\n    _Out_ PULONG StartingRunIndex\n    );\n\n#if (PHNT_VERSION >= PHNT_WIN7)\n\n// rev\nNTSYSAPI\nVOID\nNTAPI\nRtlInterlockedClearBitRun(\n    _In_ PRTL_BITMAP BitMapHeader,\n    _In_range_(0, BitMapHeader->SizeOfBitMap - NumberToClear) ULONG StartingIndex,\n    _In_range_(0, BitMapHeader->SizeOfBitMap - StartingIndex) ULONG NumberToClear\n    );\n\n// rev\nNTSYSAPI\nVOID\nNTAPI\nRtlInterlockedSetBitRun(\n    _In_ PRTL_BITMAP BitMapHeader,\n    _In_range_(0, BitMapHeader->SizeOfBitMap - NumberToSet) ULONG StartingIndex,\n    _In_range_(0, BitMapHeader->SizeOfBitMap - StartingIndex) ULONG NumberToSet\n    );\n\n#endif\n\n// Handle tables\n\ntypedef struct _RTL_HANDLE_TABLE_ENTRY\n{\n    union\n    {\n        ULONG Flags; // allocated entries have the low bit set\n        struct _RTL_HANDLE_TABLE_ENTRY *NextFree;\n    };\n} RTL_HANDLE_TABLE_ENTRY, *PRTL_HANDLE_TABLE_ENTRY;\n\n#define RTL_HANDLE_ALLOCATED (USHORT)0x0001\n\ntypedef struct _RTL_HANDLE_TABLE\n{\n    ULONG MaximumNumberOfHandles;\n    ULONG SizeOfHandleTableEntry;\n    ULONG Reserved[2];\n    PRTL_HANDLE_TABLE_ENTRY FreeHandles;\n    PRTL_HANDLE_TABLE_ENTRY CommittedHandles;\n    PRTL_HANDLE_TABLE_ENTRY UnCommittedHandles;\n    PRTL_HANDLE_TABLE_ENTRY MaxReservedHandles;\n} RTL_HANDLE_TABLE, *PRTL_HANDLE_TABLE;\n\nNTSYSAPI\nVOID\nNTAPI\nRtlInitializeHandleTable(\n    _In_ ULONG MaximumNumberOfHandles,\n    _In_ ULONG SizeOfHandleTableEntry,\n    _Out_ PRTL_HANDLE_TABLE HandleTable\n    );\n\nNTSYSAPI\nNTSTATUS\nNTAPI\nRtlDestroyHandleTable(\n    _Inout_ PRTL_HANDLE_TABLE HandleTable\n    );\n\nNTSYSAPI\nPRTL_HANDLE_TABLE_ENTRY\nNTAPI\nRtlAllocateHandle(\n    _In_ PRTL_HANDLE_TABLE HandleTable,\n    _Out_opt_ PULONG HandleIndex\n    );\n\nNTSYSAPI\nBOOLEAN\nNTAPI\nRtlFreeHandle(\n    _In_ PRTL_HANDLE_TABLE HandleTable,\n    _In_ PRTL_HANDLE_TABLE_ENTRY Handle\n    );\n\nNTSYSAPI\nBOOLEAN\nNTAPI\nRtlIsValidHandle(\n    _In_ PRTL_HANDLE_TABLE HandleTable,\n    _In_ PRTL_HANDLE_TABLE_ENTRY Handle\n    );\n\nNTSYSAPI\nBOOLEAN\nNTAPI\nRtlIsValidIndexHandle(\n    _In_ PRTL_HANDLE_TABLE HandleTable,\n    _In_ ULONG HandleIndex,\n    _Out_ PRTL_HANDLE_TABLE_ENTRY *Handle\n    );\n\n// Atom tables\n\n#define RTL_ATOM_MAXIMUM_INTEGER_ATOM (RTL_ATOM)0xc000\n#define RTL_ATOM_INVALID_ATOM (RTL_ATOM)0x0000\n#define RTL_ATOM_TABLE_DEFAULT_NUMBER_OF_BUCKETS 37\n#define RTL_ATOM_MAXIMUM_NAME_LENGTH 255\n#define RTL_ATOM_PINNED 0x01\n\nNTSYSAPI\nNTSTATUS\nNTAPI\nRtlCreateAtomTable(\n    _In_ ULONG NumberOfBuckets,\n    _Out_ PVOID *AtomTableHandle\n    );\n\nNTSYSAPI\nNTSTATUS\nNTAPI\nRtlDestroyAtomTable(\n    _In_ _Post_invalid_ PVOID AtomTableHandle\n    );\n\nNTSYSAPI\nNTSTATUS\nNTAPI\nRtlEmptyAtomTable(\n    _In_ PVOID AtomTableHandle,\n    _In_ BOOLEAN IncludePinnedAtoms\n    );\n\nNTSYSAPI\nNTSTATUS\nNTAPI\nRtlAddAtomToAtomTable(\n    _In_ PVOID AtomTableHandle,\n    _In_ PWSTR AtomName,\n    _Inout_opt_ PRTL_ATOM Atom\n    );\n\nNTSYSAPI\nNTSTATUS\nNTAPI\nRtlLookupAtomInAtomTable(\n    _In_ PVOID AtomTableHandle,\n    _In_ PWSTR AtomName,\n    _Out_opt_ PRTL_ATOM Atom\n    );\n\nNTSYSAPI\nNTSTATUS\nNTAPI\nRtlDeleteAtomFromAtomTable(\n    _In_ PVOID AtomTableHandle,\n    _In_ RTL_ATOM Atom\n    );\n\nNTSYSAPI\nNTSTATUS\nNTAPI\nRtlPinAtomInAtomTable(\n    _In_ PVOID AtomTableHandle,\n    _In_ RTL_ATOM Atom\n    );\n\nNTSYSAPI\nNTSTATUS\nNTAPI\nRtlQueryAtomInAtomTable(\n    _In_ PVOID AtomTableHandle,\n    _In_ RTL_ATOM Atom,\n    _Out_opt_ PULONG AtomUsage,\n    _Out_opt_ PULONG AtomFlags,\n    _Inout_updates_bytes_to_opt_(*AtomNameLength, *AtomNameLength) PWSTR AtomName,\n    _Inout_opt_ PULONG AtomNameLength\n    );\n\n#if (PHNT_VERSION >= PHNT_VISTA)\n// rev\nNTSYSAPI\nBOOLEAN\nNTAPI\nRtlGetIntegerAtom(\n    _In_ PWSTR AtomName,\n    _Out_opt_ PUSHORT IntegerAtom\n    );\n#endif\n\n// SIDs\n\n_Check_return_\nNTSYSAPI\nBOOLEAN\nNTAPI\nRtlValidSid(\n    _In_ PSID Sid\n    );\n\n_Check_return_\nNTSYSAPI\nBOOLEAN\nNTAPI\nRtlEqualSid(\n    _In_ PSID Sid1,\n    _In_ PSID Sid2\n    );\n\nNTSYSAPI\nULONG\nNTAPI\nRtlLengthRequiredSid(\n    _In_ ULONG SubAuthorityCount\n    );\n\nNTSYSAPI\nPVOID\nNTAPI\nRtlFreeSid(\n    _In_ _Post_invalid_ PSID Sid\n    );\n\n_Check_return_\nNTSYSAPI\nNTSTATUS\nNTAPI\nRtlAllocateAndInitializeSid(\n    _In_ PSID_IDENTIFIER_AUTHORITY IdentifierAuthority,\n    _In_ UCHAR SubAuthorityCount,\n    _In_ ULONG SubAuthority0,\n    _In_ ULONG SubAuthority1,\n    _In_ ULONG SubAuthority2,\n    _In_ ULONG SubAuthority3,\n    _In_ ULONG SubAuthority4,\n    _In_ ULONG SubAuthority5,\n    _In_ ULONG SubAuthority6,\n    _In_ ULONG SubAuthority7,\n    _Outptr_ PSID *Sid\n    );\n\nNTSYSAPI\nNTSTATUS\nNTAPI\nRtlInitializeSid(\n    _Out_ PSID Sid,\n    _In_ PSID_IDENTIFIER_AUTHORITY IdentifierAuthority,\n    _In_ UCHAR SubAuthorityCount\n    );\n\n#if (PHNT_VERSION >= PHNT_THRESHOLD)\nNTSYSAPI\nNTSTATUS\nNTAPI\nRtlInitializeSidEx(\n    _Out_writes_bytes_(SECURITY_SID_SIZE(SubAuthorityCount)) PSID Sid,\n    _In_ PSID_IDENTIFIER_AUTHORITY IdentifierAuthority,\n    _In_ UCHAR SubAuthorityCount,\n    ...\n    );\n#endif\n\nNTSYSAPI\nPSID_IDENTIFIER_AUTHORITY\nNTAPI\nRtlIdentifierAuthoritySid(\n    _In_ PSID Sid\n    );\n\nNTSYSAPI\nPULONG\nNTAPI\nRtlSubAuthoritySid(\n    _In_ PSID Sid,\n    _In_ ULONG SubAuthority\n    );\n\nNTSYSAPI\nPUCHAR\nNTAPI\nRtlSubAuthorityCountSid(\n    _In_ PSID Sid\n    );\n\nNTSYSAPI\nULONG\nNTAPI\nRtlLengthSid(\n    _In_ PSID Sid\n    );\n\nNTSYSAPI\nNTSTATUS\nNTAPI\nRtlCopySid(\n    _In_ ULONG DestinationSidLength,\n    _In_reads_bytes_(DestinationSidLength) PSID DestinationSid,\n    _In_ PSID SourceSid\n    );\n\n#if (PHNT_VERSION >= PHNT_VISTA)\nNTSYSAPI\nNTSTATUS\nNTAPI\nRtlCreateServiceSid(\n    _In_ PUNICODE_STRING ServiceName,\n    _Out_writes_bytes_opt_(*ServiceSidLength) PSID ServiceSid,\n    _Inout_ PULONG ServiceSidLength\n    );\n#endif\n\n#if (PHNT_VERSION >= PHNT_VISTA)\n// private\nNTSYSAPI\nNTSTATUS\nNTAPI\nRtlSidDominates(\n    _In_ PSID Sid1,\n    _In_ PSID Sid2,\n    _Out_ PBOOLEAN pbDominate\n    );\n#endif\n\n#if (PHNT_VERSION >= PHNT_VISTA)\n// private\nNTSYSAPI\nNTSTATUS\nNTAPI\nRtlSidEqualLevel(\n    _In_ PSID Sid1,\n    _In_ PSID Sid2,\n    _Out_ PBOOLEAN pbEqual\n    );\n#endif\n\n#if (PHNT_VERSION >= PHNT_VISTA)\n// private\nNTSYSAPI\nNTSTATUS\nNTAPI\nRtlSidIsHigherLevel(\n    _In_ PSID Sid1,\n    _In_ PSID Sid2,\n    _Out_ PBOOLEAN pbHigher\n    );\n#endif\n\n#if (PHNT_VERSION >= PHNT_WIN7)\nNTSYSAPI\nNTSTATUS\nNTAPI\nRtlCreateVirtualAccountSid(\n    _In_ PUNICODE_STRING Name,\n    _In_ ULONG BaseSubAuthority,\n    _Out_writes_bytes_(*SidLength) PSID Sid,\n    _Inout_ PULONG SidLength\n    );\n#endif\n\n#if (PHNT_VERSION >= PHNT_WIN7)\nNTSYSAPI\nNTSTATUS\nNTAPI\nRtlReplaceSidInSd(\n    _Inout_ PSECURITY_DESCRIPTOR SecurityDescriptor,\n    _In_ PSID OldSid,\n    _In_ PSID NewSid,\n    _Out_ ULONG *NumChanges\n    );\n#endif\n\n#define MAX_UNICODE_STACK_BUFFER_LENGTH 256\n\nNTSYSAPI\nNTSTATUS\nNTAPI\nRtlConvertSidToUnicodeString(\n    _Inout_ PUNICODE_STRING UnicodeString,\n    _In_ PSID Sid,\n    _In_ BOOLEAN AllocateDestinationString\n    );\n\n#if (PHNT_VERSION >= PHNT_VISTA)\n// private\nNTSYSAPI\nNTSTATUS\nNTAPI\nRtlSidHashInitialize(\n    _In_reads_(SidCount) PSID_AND_ATTRIBUTES SidAttr,\n    _In_ ULONG SidCount,\n    _Out_ PSID_AND_ATTRIBUTES_HASH SidAttrHash\n    );\n#endif\n\n#if (PHNT_VERSION >= PHNT_VISTA)\n// private\nNTSYSAPI\nPSID_AND_ATTRIBUTES\nNTAPI\nRtlSidHashLookup(\n    _In_ PSID_AND_ATTRIBUTES_HASH SidAttrHash,\n    _In_ PSID Sid\n    );\n#endif\n\n#if (PHNT_VERSION >= PHNT_REDSTONE2)\nNTSYSAPI\nNTSTATUS\nNTAPI\nRtlDeriveCapabilitySidsFromName(\n    _Inout_ PUNICODE_STRING UnicodeString,\n    _Out_ PSID CapabilityGroupSid,\n    _Out_ PSID CapabilitySid,\n    );\n#endif\n\n// Security Descriptors\n\nNTSYSAPI\nNTSTATUS\nNTAPI\nRtlCreateSecurityDescriptor(\n    _Out_ PSECURITY_DESCRIPTOR SecurityDescriptor,\n    _In_ ULONG Revision\n    );\n\n_Check_return_\nNTSYSAPI\nBOOLEAN\nNTAPI\nRtlValidSecurityDescriptor(\n    _In_ PSECURITY_DESCRIPTOR SecurityDescriptor\n    );\n\nNTSYSAPI\nULONG\nNTAPI\nRtlLengthSecurityDescriptor(\n    _In_ PSECURITY_DESCRIPTOR SecurityDescriptor\n    );\n\n_Check_return_\nNTSYSAPI\nBOOLEAN\nNTAPI\nRtlValidRelativeSecurityDescriptor(\n    _In_reads_bytes_(SecurityDescriptorLength) PSECURITY_DESCRIPTOR SecurityDescriptorInput,\n    _In_ ULONG SecurityDescriptorLength,\n    _In_ SECURITY_INFORMATION RequiredInformation\n    );\n\nNTSYSAPI\nNTSTATUS\nNTAPI\nRtlGetControlSecurityDescriptor(\n    _In_ PSECURITY_DESCRIPTOR SecurityDescriptor,\n    _Out_ PSECURITY_DESCRIPTOR_CONTROL Control,\n    _Out_ PULONG Revision\n    );\n\nNTSYSAPI\nNTSTATUS\nNTAPI\nRtlSetControlSecurityDescriptor(\n     _Inout_ PSECURITY_DESCRIPTOR SecurityDescriptor,\n     _In_ SECURITY_DESCRIPTOR_CONTROL ControlBitsOfInterest,\n     _In_ SECURITY_DESCRIPTOR_CONTROL ControlBitsToSet\n     );\n\nNTSYSAPI\nNTSTATUS\nNTAPI\nRtlSetAttributesSecurityDescriptor(\n    _Inout_ PSECURITY_DESCRIPTOR SecurityDescriptor,\n    _In_ SECURITY_DESCRIPTOR_CONTROL Control,\n    _Out_ PULONG Revision\n    );\n\nNTSYSAPI\nBOOLEAN\nNTAPI\nRtlGetSecurityDescriptorRMControl(\n    _In_ PSECURITY_DESCRIPTOR SecurityDescriptor,\n    _Out_ PUCHAR RMControl\n    );\n\nNTSYSAPI\nVOID\nNTAPI\nRtlSetSecurityDescriptorRMControl(\n    _Inout_ PSECURITY_DESCRIPTOR SecurityDescriptor,\n    _In_opt_ PUCHAR RMControl\n    );\n\nNTSYSAPI\nNTSTATUS\nNTAPI\nRtlSetDaclSecurityDescriptor(\n    _Inout_ PSECURITY_DESCRIPTOR SecurityDescriptor,\n    _In_ BOOLEAN DaclPresent,\n    _In_opt_ PACL Dacl,\n    _In_opt_ BOOLEAN DaclDefaulted\n    );\n\nNTSYSAPI\nNTSTATUS\nNTAPI\nRtlGetDaclSecurityDescriptor(\n    _In_ PSECURITY_DESCRIPTOR SecurityDescriptor,\n    _Out_ PBOOLEAN DaclPresent,\n    _Out_ PACL *Dacl,\n    _Out_ PBOOLEAN DaclDefaulted\n    );\n\nNTSYSAPI\nNTSTATUS\nNTAPI\nRtlSetSaclSecurityDescriptor(\n    _Inout_ PSECURITY_DESCRIPTOR SecurityDescriptor,\n    _In_ BOOLEAN SaclPresent,\n    _In_opt_ PACL Sacl,\n    _In_opt_ BOOLEAN SaclDefaulted\n    );\n\nNTSYSAPI\nNTSTATUS\nNTAPI\nRtlGetSaclSecurityDescriptor(\n    _In_ PSECURITY_DESCRIPTOR SecurityDescriptor,\n    _Out_ PBOOLEAN SaclPresent,\n    _Out_ PACL *Sacl,\n    _Out_ PBOOLEAN SaclDefaulted\n    );\n\nNTSYSAPI\nNTSTATUS\nNTAPI\nRtlGetSaclSecurityDescriptor(\n    _In_ PSECURITY_DESCRIPTOR SecurityDescriptor,\n    _Out_ PBOOLEAN SaclPresent,\n    _Out_ PACL *Sacl,\n    _Out_ PBOOLEAN SaclDefaulted\n    );\n\nNTSYSAPI\nNTSTATUS\nNTAPI\nRtlSetOwnerSecurityDescriptor(\n    _Inout_ PSECURITY_DESCRIPTOR SecurityDescriptor,\n    _In_opt_ PSID Owner,\n    _In_opt_ BOOLEAN OwnerDefaulted\n    );\n\nNTSYSAPI\nNTSTATUS\nNTAPI\nRtlGetOwnerSecurityDescriptor(\n    _In_ PSECURITY_DESCRIPTOR SecurityDescriptor,\n    _Out_ PSID *Owner,\n    _Out_ PBOOLEAN OwnerDefaulted\n    );\n\nNTSYSAPI\nNTSTATUS\nNTAPI\nRtlSetGroupSecurityDescriptor(\n    _Inout_ PSECURITY_DESCRIPTOR SecurityDescriptor,\n    _In_opt_ PSID Group,\n    _In_opt_ BOOLEAN GroupDefaulted\n    );\n\nNTSYSAPI\nNTSTATUS\nNTAPI\nRtlGetGroupSecurityDescriptor(\n    _In_ PSECURITY_DESCRIPTOR SecurityDescriptor,\n    _Out_ PSID *Group,\n    _Out_ PBOOLEAN GroupDefaulted\n    );\n\nNTSYSAPI\nNTSTATUS\nNTAPI\nRtlMakeSelfRelativeSD(\n    _In_ PSECURITY_DESCRIPTOR AbsoluteSecurityDescriptor,\n    _Out_writes_bytes_(*BufferLength) PSECURITY_DESCRIPTOR SelfRelativeSecurityDescriptor,\n    _Inout_ PULONG BufferLength\n    );\n\nNTSYSAPI\nNTSTATUS\nNTAPI\nRtlAbsoluteToSelfRelativeSD(\n    _In_ PSECURITY_DESCRIPTOR AbsoluteSecurityDescriptor,\n    _Out_writes_bytes_to_opt_(*BufferLength, *BufferLength) PSECURITY_DESCRIPTOR SelfRelativeSecurityDescriptor,\n    _Inout_ PULONG BufferLength\n    );\n\nNTSYSAPI\nNTSTATUS\nNTAPI\nRtlSelfRelativeToAbsoluteSD(\n    _In_ PSECURITY_DESCRIPTOR SelfRelativeSecurityDescriptor,\n    _Out_writes_bytes_to_opt_(*AbsoluteSecurityDescriptorSize, *AbsoluteSecurityDescriptorSize) PSECURITY_DESCRIPTOR AbsoluteSecurityDescriptor,\n    _Inout_ PULONG AbsoluteSecurityDescriptorSize,\n    _Out_writes_bytes_to_opt_(*DaclSize, *DaclSize) PACL Dacl,\n    _Inout_ PULONG DaclSize,\n    _Out_writes_bytes_to_opt_(*SaclSize, *SaclSize) PACL Sacl,\n    _Inout_ PULONG SaclSize,\n    _Out_writes_bytes_to_opt_(*OwnerSize, *OwnerSize) PSID Owner,\n    _Inout_ PULONG OwnerSize,\n    _Out_writes_bytes_to_opt_(*PrimaryGroupSize, *PrimaryGroupSize) PSID PrimaryGroup,\n    _Inout_ PULONG PrimaryGroupSize\n    );\n\n// private\nNTSYSAPI\nNTSTATUS\nNTAPI\nRtlSelfRelativeToAbsoluteSD2(\n    _Inout_ PSECURITY_DESCRIPTOR pSelfRelativeSecurityDescriptor,\n    _Inout_ PULONG pBufferSize\n    );\n\n// Access masks\n\nNTSYSAPI\nBOOLEAN\nNTAPI\nRtlAreAllAccessesGranted(\n    _In_ ACCESS_MASK GrantedAccess,\n    _In_ ACCESS_MASK DesiredAccess\n    );\n\nNTSYSAPI\nBOOLEAN\nNTAPI\nRtlAreAnyAccessesGranted(\n    _In_ ACCESS_MASK GrantedAccess,\n    _In_ ACCESS_MASK DesiredAccess\n    );\n\nNTSYSAPI\nVOID\nNTAPI\nRtlMapGenericMask(\n    _Inout_ PACCESS_MASK AccessMask,\n    _In_ PGENERIC_MAPPING GenericMapping\n    );\n\n// ACLs\n\nNTSYSAPI\nNTSTATUS\nNTAPI\nRtlCreateAcl(\n    _Out_writes_bytes_(AclLength) PACL Acl,\n    _In_ ULONG AclLength,\n    _In_ ULONG AclRevision\n    );\n\nNTSYSAPI\nNTSTATUS\nNTAPI\nRtlDefaultNpAcl(\n    _Out_ PACL *Acl\n    );\n\nNTSYSAPI\nBOOLEAN\nNTAPI\nRtlValidAcl(\n    _In_ PACL Acl\n    );\n\nNTSYSAPI\nNTSTATUS\nNTAPI\nRtlQueryInformationAcl(\n    _In_ PACL Acl,\n    _Out_writes_bytes_(AclInformationLength) PVOID AclInformation,\n    _In_ ULONG AclInformationLength,\n    _In_ ACL_INFORMATION_CLASS AclInformationClass\n    );\n\nNTSYSAPI\nNTSTATUS\nNTAPI\nRtlSetInformationAcl(\n    _Inout_ PACL Acl,\n    _In_reads_bytes_(AclInformationLength) PVOID AclInformation,\n    _In_ ULONG AclInformationLength,\n    _In_ ACL_INFORMATION_CLASS AclInformationClass\n    );\n\nNTSYSAPI\nNTSTATUS\nNTAPI\nRtlAddAce(\n    _Inout_ PACL Acl,\n    _In_ ULONG AceRevision,\n    _In_ ULONG StartingAceIndex,\n    _In_reads_bytes_(AceListLength) PVOID AceList,\n    _In_ ULONG AceListLength\n    );\n\nNTSYSAPI\nNTSTATUS\nNTAPI\nRtlDeleteAce(\n    _Inout_ PACL Acl,\n    _In_ ULONG AceIndex\n    );\n\nNTSYSAPI\nNTSTATUS\nNTAPI\nRtlGetAce(\n    _In_ PACL Acl,\n    _In_ ULONG AceIndex,\n    _Outptr_ PVOID *Ace\n    );\n\nNTSYSAPI\nBOOLEAN\nNTAPI\nRtlFirstFreeAce(\n    _In_ PACL Acl,\n    _Out_ PVOID *FirstFree\n    );\n\n#if (PHNT_VERSION >= PHNT_VISTA)\n// private\nNTSYSAPI\nPVOID\nNTAPI\nRtlFindAceByType(\n    _In_ PACL pAcl,\n    _In_ UCHAR AceType,\n    _Out_opt_ PULONG pIndex\n    );\n#endif\n\n#if (PHNT_VERSION >= PHNT_VISTA)\n// private\nNTSYSAPI\nBOOLEAN\nNTAPI\nRtlOwnerAcesPresent(\n    _In_ PACL pAcl\n    );\n#endif\n\nNTSYSAPI\nNTSTATUS\nNTAPI\nRtlAddAccessAllowedAce(\n    _Inout_ PACL Acl,\n    _In_ ULONG AceRevision,\n    _In_ ACCESS_MASK AccessMask,\n    _In_ PSID Sid\n    );\n\nNTSYSAPI\nNTSTATUS\nNTAPI\nRtlAddAccessAllowedAceEx(\n    _Inout_ PACL Acl,\n    _In_ ULONG AceRevision,\n    _In_ ULONG AceFlags,\n    _In_ ACCESS_MASK AccessMask,\n    _In_ PSID Sid\n    );\n\nNTSYSAPI\nNTSTATUS\nNTAPI\nRtlAddAccessDeniedAce(\n    _Inout_ PACL Acl,\n    _In_ ULONG AceRevision,\n    _In_ ACCESS_MASK AccessMask,\n    _In_ PSID Sid\n    );\n\nNTSYSAPI\nNTSTATUS\nNTAPI\nRtlAddAccessDeniedAceEx(\n    _Inout_ PACL Acl,\n    _In_ ULONG AceRevision,\n    _In_ ULONG AceFlags,\n    _In_ ACCESS_MASK AccessMask,\n    _In_ PSID Sid\n    );\n\nNTSYSAPI\nNTSTATUS\nNTAPI\nRtlAddAuditAccessAce(\n    _Inout_ PACL Acl,\n    _In_ ULONG AceRevision,\n    _In_ ACCESS_MASK AccessMask,\n    _In_ PSID Sid,\n    _In_ BOOLEAN AuditSuccess,\n    _In_ BOOLEAN AuditFailure\n    );\n\nNTSYSAPI\nNTSTATUS\nNTAPI\nRtlAddAuditAccessAceEx(\n    _Inout_ PACL Acl,\n    _In_ ULONG AceRevision,\n    _In_ ULONG AceFlags,\n    _In_ ACCESS_MASK AccessMask,\n    _In_ PSID Sid,\n    _In_ BOOLEAN AuditSuccess,\n    _In_ BOOLEAN AuditFailure\n    );\n\nNTSYSAPI\nNTSTATUS\nNTAPI\nRtlAddAccessAllowedObjectAce(\n    _Inout_ PACL Acl,\n    _In_ ULONG AceRevision,\n    _In_ ULONG AceFlags,\n    _In_ ACCESS_MASK AccessMask,\n    _In_opt_ PGUID ObjectTypeGuid,\n    _In_opt_ PGUID InheritedObjectTypeGuid,\n    _In_ PSID Sid\n    );\n\nNTSYSAPI\nNTSTATUS\nNTAPI\nRtlAddAccessDeniedObjectAce(\n    _Inout_ PACL Acl,\n    _In_ ULONG AceRevision,\n    _In_ ULONG AceFlags,\n    _In_ ACCESS_MASK AccessMask,\n    _In_opt_ PGUID ObjectTypeGuid,\n    _In_opt_ PGUID InheritedObjectTypeGuid,\n    _In_ PSID Sid\n    );\n\nNTSYSAPI\nNTSTATUS\nNTAPI\nRtlAddAuditAccessObjectAce(\n    _Inout_ PACL Acl,\n    _In_ ULONG AceRevision,\n    _In_ ULONG AceFlags,\n    _In_ ACCESS_MASK AccessMask,\n    _In_opt_ PGUID ObjectTypeGuid,\n    _In_opt_ PGUID InheritedObjectTypeGuid,\n    _In_ PSID Sid,\n    _In_ BOOLEAN AuditSuccess,\n    _In_ BOOLEAN AuditFailure\n    );\n\nNTSYSAPI\nNTSTATUS\nNTAPI\nRtlAddCompoundAce(\n    _Inout_ PACL Acl,\n    _In_ ULONG AceRevision,\n    _In_ UCHAR AceType,\n    _In_ ACCESS_MASK AccessMask,\n    _In_ PSID ServerSid,\n    _In_ PSID ClientSid\n    );\n\n#if (PHNT_VERSION >= PHNT_VISTA)\n// private\nNTSYSAPI\nNTSTATUS\nNTAPI\nRtlAddMandatoryAce(\n    _Inout_ PACL Acl,\n    _In_ ULONG AceRevision,\n    _In_ ULONG AceFlags,\n    _In_ PSID Sid,\n    _In_ UCHAR AceType,\n    _In_ ACCESS_MASK AccessMask\n    );\n#endif\n\n// Security objects\n\nNTSYSAPI\nNTSTATUS\nNTAPI\nRtlNewSecurityObject(\n    _In_opt_ PSECURITY_DESCRIPTOR ParentDescriptor,\n    _In_opt_ PSECURITY_DESCRIPTOR CreatorDescriptor,\n    _Out_ PSECURITY_DESCRIPTOR *NewDescriptor,\n    _In_ BOOLEAN IsDirectoryObject,\n    _In_opt_ HANDLE Token,\n    _In_ PGENERIC_MAPPING GenericMapping\n    );\n\nNTSYSAPI\nNTSTATUS\nNTAPI\nRtlNewSecurityObjectEx(\n    _In_opt_ PSECURITY_DESCRIPTOR ParentDescriptor,\n    _In_opt_ PSECURITY_DESCRIPTOR CreatorDescriptor,\n    _Out_ PSECURITY_DESCRIPTOR *NewDescriptor,\n    _In_opt_ GUID *ObjectType,\n    _In_ BOOLEAN IsDirectoryObject,\n    _In_ ULONG AutoInheritFlags, // SEF_*\n    _In_opt_ HANDLE Token,\n    _In_ PGENERIC_MAPPING GenericMapping\n    );\n\nNTSYSAPI\nNTSTATUS\nNTAPI\nRtlNewSecurityObjectWithMultipleInheritance(\n    _In_opt_ PSECURITY_DESCRIPTOR ParentDescriptor,\n    _In_opt_ PSECURITY_DESCRIPTOR CreatorDescriptor,\n    _Out_ PSECURITY_DESCRIPTOR *NewDescriptor,\n    _In_opt_ GUID **ObjectType,\n    _In_ ULONG GuidCount,\n    _In_ BOOLEAN IsDirectoryObject,\n    _In_ ULONG AutoInheritFlags, // SEF_*\n    _In_opt_ HANDLE Token,\n    _In_ PGENERIC_MAPPING GenericMapping\n    );\n\nNTSYSAPI\nNTSTATUS\nNTAPI\nRtlDeleteSecurityObject(\n    _Inout_ PSECURITY_DESCRIPTOR *ObjectDescriptor\n    );\n\nNTSYSAPI\nNTSTATUS\nNTAPI\nRtlQuerySecurityObject(\n     _In_ PSECURITY_DESCRIPTOR ObjectDescriptor,\n     _In_ SECURITY_INFORMATION SecurityInformation,\n     _Out_opt_ PSECURITY_DESCRIPTOR ResultantDescriptor,\n     _In_ ULONG DescriptorLength,\n     _Out_ PULONG ReturnLength\n     );\n\nNTSYSAPI\nNTSTATUS\nNTAPI\nRtlSetSecurityObject(\n    _In_ SECURITY_INFORMATION SecurityInformation,\n    _In_ PSECURITY_DESCRIPTOR ModificationDescriptor,\n    _Inout_ PSECURITY_DESCRIPTOR *ObjectsSecurityDescriptor,\n    _In_ PGENERIC_MAPPING GenericMapping,\n    _In_opt_ HANDLE Token\n    );\n\nNTSYSAPI\nNTSTATUS\nNTAPI\nRtlSetSecurityObjectEx(\n    _In_ SECURITY_INFORMATION SecurityInformation,\n    _In_ PSECURITY_DESCRIPTOR ModificationDescriptor,\n    _Inout_ PSECURITY_DESCRIPTOR *ObjectsSecurityDescriptor,\n    _In_ ULONG AutoInheritFlags, // SEF_*\n    _In_ PGENERIC_MAPPING GenericMapping,\n    _In_opt_ HANDLE Token\n    );\n\nNTSYSAPI\nNTSTATUS\nNTAPI\nRtlConvertToAutoInheritSecurityObject(\n    _In_opt_ PSECURITY_DESCRIPTOR ParentDescriptor,\n    _In_ PSECURITY_DESCRIPTOR CurrentSecurityDescriptor,\n    _Out_ PSECURITY_DESCRIPTOR *NewSecurityDescriptor,\n    _In_opt_ GUID *ObjectType,\n    _In_ BOOLEAN IsDirectoryObject,\n    _In_ PGENERIC_MAPPING GenericMapping\n    );\n\nNTSYSAPI\nNTSTATUS\nNTAPI\nRtlNewInstanceSecurityObject(\n    _In_ BOOLEAN ParentDescriptorChanged,\n    _In_ BOOLEAN CreatorDescriptorChanged,\n    _In_ PLUID OldClientTokenModifiedId,\n    _Out_ PLUID NewClientTokenModifiedId,\n    _In_opt_ PSECURITY_DESCRIPTOR ParentDescriptor,\n    _In_opt_ PSECURITY_DESCRIPTOR CreatorDescriptor,\n    _Out_ PSECURITY_DESCRIPTOR *NewDescriptor,\n    _In_ BOOLEAN IsDirectoryObject,\n    _In_ HANDLE Token,\n    _In_ PGENERIC_MAPPING GenericMapping\n    );\n\nNTSYSAPI\nNTSTATUS\nNTAPI\nRtlCopySecurityDescriptor(\n    _In_ PSECURITY_DESCRIPTOR InputSecurityDescriptor,\n    _Out_ PSECURITY_DESCRIPTOR *OutputSecurityDescriptor\n    );\n\n// Misc. security\n\nNTSYSAPI\nVOID\nNTAPI\nRtlRunEncodeUnicodeString(\n    _Inout_ PUCHAR Seed,\n    _In_ PUNICODE_STRING String\n    );\n\nNTSYSAPI\nVOID\nNTAPI\nRtlRunDecodeUnicodeString(\n    _In_ UCHAR Seed,\n    _In_ PUNICODE_STRING String\n    );\n\nNTSYSAPI\nNTSTATUS\nNTAPI\nRtlImpersonateSelf(\n    _In_ SECURITY_IMPERSONATION_LEVEL ImpersonationLevel\n    );\n\n#if (PHNT_VERSION >= PHNT_VISTA)\n// private\nNTSYSAPI\nNTSTATUS\nNTAPI\nRtlImpersonateSelfEx(\n    _In_ SECURITY_IMPERSONATION_LEVEL ImpersonationLevel,\n    _In_opt_ ACCESS_MASK AdditionalAccess,\n    _Out_opt_ PHANDLE ThreadToken\n    );\n#endif\n\nNTSYSAPI\nNTSTATUS\nNTAPI\nRtlAdjustPrivilege(\n    _In_ ULONG Privilege,\n    _In_ BOOLEAN Enable,\n    _In_ BOOLEAN Client,\n    _Out_ PBOOLEAN WasEnabled\n    );\n\n#define RTL_ACQUIRE_PRIVILEGE_REVERT 0x00000001\n#define RTL_ACQUIRE_PRIVILEGE_PROCESS 0x00000002\n\nNTSYSAPI\nNTSTATUS\nNTAPI\nRtlAcquirePrivilege(\n    _In_ PULONG Privilege,\n    _In_ ULONG NumPriv,\n    _In_ ULONG Flags,\n    _Out_ PVOID *ReturnedState\n    );\n\nNTSYSAPI\nVOID\nNTAPI\nRtlReleasePrivilege(\n    _In_ PVOID StatePointer\n    );\n\n#if (PHNT_VERSION >= PHNT_VISTA)\n// private\nNTSYSAPI\nNTSTATUS\nNTAPI\nRtlRemovePrivileges(\n    _In_ HANDLE hToken,\n    _In_ PULONG PrivilegesToKeep,\n    _In_ ULONG PrivilegeCount\n    );\n#endif\n\n#if (PHNT_VERSION >= PHNT_WIN8)\n\nNTSYSAPI\nNTSTATUS\nNTAPI\nRtlIsUntrustedObject(\n    _In_opt_ HANDLE Handle,\n    _In_opt_ PVOID Object,\n    _Out_ PBOOLEAN UntrustedObject\n    );\n\nNTSYSAPI\nULONG\nNTAPI\nRtlQueryValidationRunlevel(\n    _In_opt_ PCUNICODE_STRING ComponentName\n    );\n\n#endif\n\n// Private namespaces\n\n#if (PHNT_VERSION >= PHNT_VISTA)\n\n// begin_private\n\nNTSYSAPI\nPVOID\nNTAPI\nRtlCreateBoundaryDescriptor(\n    _In_ PUNICODE_STRING Name,\n    _In_ ULONG Flags\n    );\n\nNTSYSAPI\nVOID\nNTAPI\nRtlDeleteBoundaryDescriptor(\n    _In_ PVOID BoundaryDescriptor\n    );\n\nNTSYSAPI\nNTSTATUS\nNTAPI\nRtlAddSIDToBoundaryDescriptor(\n    _Inout_ PVOID *BoundaryDescriptor,\n    _In_ PSID RequiredSid\n    );\n\n#if (PHNT_VERSION >= PHNT_WIN7)\n// rev\nNTSYSAPI\nNTSTATUS\nNTAPI\nRtlAddIntegrityLabelToBoundaryDescriptor(\n    _Inout_ PVOID *BoundaryDescriptor,\n    _In_ PSID IntegrityLabel\n    );\n#endif\n\n// end_private\n\n#endif\n\n// Version\n\nNTSYSAPI\nNTSTATUS\nNTAPI\nRtlGetVersion(\n    _Out_ PRTL_OSVERSIONINFOW lpVersionInformation\n    );\n\nNTSYSAPI\nNTSTATUS\nNTAPI\nRtlVerifyVersionInfo(\n    _In_ PRTL_OSVERSIONINFOEXW VersionInfo,\n    _In_ ULONG TypeMask,\n    _In_ ULONGLONG ConditionMask\n    );\n\n// System information\n\nNTSYSAPI\nULONG\nNTAPI\nRtlGetNtGlobalFlags(\n    VOID\n    );\n\nNTSYSAPI\nBOOLEAN\nNTAPI\nRtlGetNtProductType(\n    _Out_ PNT_PRODUCT_TYPE NtProductType\n    );\n\n// rev\nNTSYSAPI\nVOID\nNTAPI\nRtlGetNtVersionNumbers(\n    _Out_opt_ PULONG pNtMajorVersion,\n    _Out_opt_ PULONG pNtMinorVersion,\n    _Out_opt_ PULONG pNtBuildNumber\n    );\n\n// Thread pool (old)\n\nNTSYSAPI\nNTSTATUS\nNTAPI\nRtlRegisterWait(\n    _Out_ PHANDLE WaitHandle,\n    _In_ HANDLE Handle,\n    _In_ WAITORTIMERCALLBACKFUNC Function,\n    _In_ PVOID Context,\n    _In_ ULONG Milliseconds,\n    _In_ ULONG Flags\n    );\n\nNTSYSAPI\nNTSTATUS\nNTAPI\nRtlDeregisterWait(\n    _In_ HANDLE WaitHandle\n    );\n\nNTSYSAPI\nNTSTATUS\nNTAPI\nRtlDeregisterWaitEx(\n    _In_ HANDLE WaitHandle,\n    _In_ HANDLE Event\n    );\n\nNTSYSAPI\nNTSTATUS\nNTAPI\nRtlQueueWorkItem(\n    _In_ WORKERCALLBACKFUNC Function,\n    _In_ PVOID Context,\n    _In_ ULONG Flags\n    );\n\nNTSYSAPI\nNTSTATUS\nNTAPI\nRtlSetIoCompletionCallback(\n    _In_ HANDLE FileHandle,\n    _In_ APC_CALLBACK_FUNCTION CompletionProc,\n    _In_ ULONG Flags\n    );\n\nNTSYSAPI\nNTSTATUS\nNTAPI\nRtlCreateTimerQueue(\n    _Out_ PHANDLE TimerQueueHandle\n    );\n\nNTSYSAPI\nNTSTATUS\nNTAPI\nRtlCreateTimer(\n    _In_ HANDLE TimerQueueHandle,\n    _Out_ PHANDLE Handle,\n    _In_ WAITORTIMERCALLBACKFUNC Function,\n    _In_ PVOID Context,\n    _In_ ULONG DueTime,\n    _In_ ULONG Period,\n    _In_ ULONG Flags\n    );\n\nNTSYSAPI\nNTSTATUS\nNTAPI\nRtlUpdateTimer(\n    _In_ HANDLE TimerQueueHandle,\n    _In_ HANDLE TimerHandle,\n    _In_ ULONG DueTime,\n    _In_ ULONG Period\n    );\n\nNTSYSAPI\nNTSTATUS\nNTAPI\nRtlDeleteTimer(\n    _In_ HANDLE TimerQueueHandle,\n    _In_ HANDLE TimerToCancel,\n    _In_ HANDLE Event\n    );\n\nNTSYSAPI\nNTSTATUS\nNTAPI\nRtlDeleteTimerQueue(\n    _In_ HANDLE TimerQueueHandle\n    );\n\nNTSYSAPI\nNTSTATUS\nNTAPI\nRtlDeleteTimerQueueEx(\n    _In_ HANDLE TimerQueueHandle,\n    _In_ HANDLE Event\n    );\n\n// Registry access\n\nNTSYSAPI\nNTSTATUS\nNTAPI\nRtlFormatCurrentUserKeyPath(\n    _Out_ PUNICODE_STRING CurrentUserKeyPath\n    );\n\nNTSYSAPI\nNTSTATUS\nNTAPI\nRtlOpenCurrentUser(\n    _In_ ACCESS_MASK DesiredAccess,\n    _Out_ PHANDLE CurrentUserKey\n    );\n\n#define RTL_REGISTRY_ABSOLUTE 0\n#define RTL_REGISTRY_SERVICES 1 // \\Registry\\Machine\\System\\CurrentControlSet\\Services\n#define RTL_REGISTRY_CONTROL 2 // \\Registry\\Machine\\System\\CurrentControlSet\\Control\n#define RTL_REGISTRY_WINDOWS_NT 3 // \\Registry\\Machine\\Software\\Microsoft\\Windows NT\\CurrentVersion\n#define RTL_REGISTRY_DEVICEMAP 4 // \\Registry\\Machine\\Hardware\\DeviceMap\n#define RTL_REGISTRY_USER 5 // \\Registry\\User\\CurrentUser\n#define RTL_REGISTRY_MAXIMUM 6\n#define RTL_REGISTRY_HANDLE 0x40000000\n#define RTL_REGISTRY_OPTIONAL 0x80000000\n\nNTSYSAPI\nNTSTATUS\nNTAPI\nRtlCreateRegistryKey(\n    _In_ ULONG RelativeTo,\n    _In_ PWSTR Path\n    );\n\nNTSYSAPI\nNTSTATUS\nNTAPI\nRtlCheckRegistryKey(\n    _In_ ULONG RelativeTo,\n    _In_ PWSTR Path\n    );\n\ntypedef NTSTATUS (NTAPI *PRTL_QUERY_REGISTRY_ROUTINE)(\n    _In_ PWSTR ValueName,\n    _In_ ULONG ValueType,\n    _In_ PVOID ValueData,\n    _In_ ULONG ValueLength,\n    _In_ PVOID Context,\n    _In_ PVOID EntryContext\n    );\n\ntypedef struct _RTL_QUERY_REGISTRY_TABLE\n{\n    PRTL_QUERY_REGISTRY_ROUTINE QueryRoutine;\n    ULONG Flags;\n    PWSTR Name;\n    PVOID EntryContext;\n    ULONG DefaultType;\n    PVOID DefaultData;\n    ULONG DefaultLength;\n} RTL_QUERY_REGISTRY_TABLE, *PRTL_QUERY_REGISTRY_TABLE;\n\n#define RTL_QUERY_REGISTRY_SUBKEY 0x00000001\n#define RTL_QUERY_REGISTRY_TOPKEY 0x00000002\n#define RTL_QUERY_REGISTRY_REQUIRED 0x00000004\n#define RTL_QUERY_REGISTRY_NOVALUE 0x00000008\n#define RTL_QUERY_REGISTRY_NOEXPAND 0x00000010\n#define RTL_QUERY_REGISTRY_DIRECT 0x00000020\n#define RTL_QUERY_REGISTRY_DELETE 0x00000040\n\nNTSYSAPI\nNTSTATUS\nNTAPI\nRtlQueryRegistryValues(\n    _In_ ULONG RelativeTo,\n    _In_ PWSTR Path,\n    _In_ PRTL_QUERY_REGISTRY_TABLE QueryTable,\n    _In_ PVOID Context,\n    _In_opt_ PVOID Environment\n    );\n\nNTSYSAPI\nNTSTATUS\nNTAPI\nRtlWriteRegistryValue(\n    _In_ ULONG RelativeTo,\n    _In_ PWSTR Path,\n    _In_ PWSTR ValueName,\n    _In_ ULONG ValueType,\n    _In_ PVOID ValueData,\n    _In_ ULONG ValueLength\n    );\n\nNTSYSAPI\nNTSTATUS\nNTAPI\nRtlDeleteRegistryValue(\n    _In_ ULONG RelativeTo,\n    _In_ PWSTR Path,\n    _In_ PWSTR ValueName\n    );\n\n// Debugging\n\nNTSYSAPI\nVOID\nNTAPI\nDbgUserBreakPoint(\n    VOID\n    );\n\nNTSYSAPI\nVOID\nNTAPI\nDbgBreakPoint(\n    VOID\n    );\n\nNTSYSAPI\nVOID\nNTAPI\nDbgBreakPointWithStatus(\n    _In_ ULONG Status\n    );\n\n#define DBG_STATUS_CONTROL_C 1\n#define DBG_STATUS_SYSRQ 2\n#define DBG_STATUS_BUGCHECK_FIRST 3\n#define DBG_STATUS_BUGCHECK_SECOND 4\n#define DBG_STATUS_FATAL 5\n#define DBG_STATUS_DEBUG_CONTROL 6\n#define DBG_STATUS_WORKER 7\n\nNTSYSAPI\nULONG\n__cdecl\nDbgPrint(\n    _In_z_ _Printf_format_string_ PSTR Format,\n    ...\n    );\n\nNTSYSAPI\nULONG\n__cdecl\nDbgPrintEx(\n    _In_ ULONG ComponentId,\n    _In_ ULONG Level,\n    _In_z_ _Printf_format_string_ PSTR Format,\n    ...\n    );\n\nNTSYSAPI\nULONG\nNTAPI\nvDbgPrintEx(\n    _In_ ULONG ComponentId,\n    _In_ ULONG Level,\n    _In_z_ PCH Format,\n    _In_ va_list arglist\n    );\n\nNTSYSAPI\nULONG\nNTAPI\nvDbgPrintExWithPrefix(\n    _In_z_ PCH Prefix,\n    _In_ ULONG ComponentId,\n    _In_ ULONG Level,\n    _In_z_ PCH Format,\n    _In_ va_list arglist\n    );\n\nNTSYSAPI\nNTSTATUS\nNTAPI\nDbgQueryDebugFilterState(\n    _In_ ULONG ComponentId,\n    _In_ ULONG Level\n    );\n\nNTSYSAPI\nNTSTATUS\nNTAPI\nDbgSetDebugFilterState(\n    _In_ ULONG ComponentId,\n    _In_ ULONG Level,\n    _In_ BOOLEAN State\n    );\n\nNTSYSAPI\nULONG\nNTAPI\nDbgPrompt(\n    _In_ PCH Prompt,\n    _Out_writes_bytes_(Length) PCH Response,\n    _In_ ULONG Length\n    );\n\n// Thread profiling\n\n#if (PHNT_VERSION >= PHNT_WIN7)\n\n// begin_rev\n\nNTSYSAPI\nNTSTATUS\nNTAPI\nRtlEnableThreadProfiling(\n    _In_ HANDLE ThreadHandle,\n    _In_ ULONG Flags,\n    _In_ ULONG64 HardwareCounters,\n    _Out_ PVOID *PerformanceDataHandle\n    );\n\nNTSYSAPI\nNTSTATUS\nNTAPI\nRtlDisableThreadProfiling(\n    _In_ PVOID PerformanceDataHandle\n    );\n\nNTSYSAPI\nNTSTATUS\nNTAPI\nRtlQueryThreadProfiling(\n    _In_ HANDLE ThreadHandle,\n    _Out_ PBOOLEAN Enabled\n    );\n\nNTSYSAPI\nNTSTATUS\nNTAPI\nRtlReadThreadProfilingData(\n    _In_ HANDLE PerformanceDataHandle,\n    _In_ ULONG Flags,\n    _Out_ PPERFORMANCE_DATA PerformanceData\n    );\n\n// end_rev\n\n#endif\n\n// WOW64\n\nNTSYSAPI\nNTSTATUS\nNTAPI\nRtlGetNativeSystemInformation(\n    _In_ ULONG SystemInformationClass,\n    _In_ PVOID NativeSystemInformation,\n    _In_ ULONG InformationLength,\n    _Out_opt_ PULONG ReturnLength\n    );\n\nNTSYSAPI\nNTSTATUS\nNTAPI\nRtlQueueApcWow64Thread(\n    _In_ HANDLE ThreadHandle,\n    _In_ PPS_APC_ROUTINE ApcRoutine,\n    _In_ PVOID ApcArgument1,\n    _In_ PVOID ApcArgument2,\n    _In_ PVOID ApcArgument3\n    );\n\nNTSYSAPI\nNTSTATUS\nNTAPI\nRtlWow64EnableFsRedirection(\n    _In_ BOOLEAN Wow64FsEnableRedirection\n    );\n\nNTSYSAPI\nNTSTATUS\nNTAPI\nRtlWow64EnableFsRedirectionEx(\n    _In_ PVOID Wow64FsEnableRedirection,\n    _Out_ PVOID *OldFsRedirectionLevel\n    );\n\n// Misc.\n\nNTSYSAPI\nULONG\nNTAPI\nRtlGetCurrentProcessorNumber(\n    VOID\n    );\n\nNTSYSAPI\nULONG32\nNTAPI\nRtlComputeCrc32(\n    _In_ ULONG32 PartialCrc,\n    _In_ PVOID Buffer,\n    _In_ ULONG Length\n    );\n\nNTSYSAPI\nPVOID\nNTAPI\nRtlEncodePointer(\n    _In_ PVOID Ptr\n    );\n\nNTSYSAPI\nPVOID\nNTAPI\nRtlDecodePointer(\n    _In_ PVOID Ptr\n    );\n\nNTSYSAPI\nPVOID\nNTAPI\nRtlEncodeSystemPointer(\n    _In_ PVOID Ptr\n    );\n\nNTSYSAPI\nPVOID\nNTAPI\nRtlDecodeSystemPointer(\n    _In_ PVOID Ptr\n    );\n\nNTSYSAPI\nBOOLEAN\nNTAPI\nRtlIsThreadWithinLoaderCallout(\n    VOID\n    );\n\nNTSYSAPI\nVOID\nNTAPI\nRtlPushFrame(\n    _In_ PTEB_ACTIVE_FRAME Frame\n    );\n\nNTSYSAPI\nVOID\nNTAPI\nRtlPopFrame(\n    _In_ PTEB_ACTIVE_FRAME Frame\n    );\n\nNTSYSAPI\nPTEB_ACTIVE_FRAME\nNTAPI\nRtlGetFrame(\n    VOID\n    );\n\ntypedef ULONG (NTAPI *PRTLP_UNHANDLED_EXCEPTION_FILTER)(\n    struct _EXCEPTION_POINTERS *ExceptionInfo\n    );\n\nNTSYSAPI\nVOID\nNTAPI\nRtlSetUnhandledExceptionFilter(\n    _In_ PRTLP_UNHANDLED_EXCEPTION_FILTER UnhandledExceptionFilter\n    );\n\n// begin_private\n\ntypedef union _RTL_ELEVATION_FLAGS\n{\n    ULONG Flags;\n    struct\n    {\n        ULONG ElevationEnabled : 1;\n        ULONG VirtualizationEnabled : 1;\n        ULONG InstallerDetectEnabled : 1;\n        ULONG ReservedBits : 29;\n    };\n} RTL_ELEVATION_FLAGS, *PRTL_ELEVATION_FLAGS;\n\n#if (PHNT_VERSION >= PHNT_VISTA)\nNTSYSAPI\nNTSTATUS\nNTAPI\nRtlQueryElevationFlags(\n    _Out_ PRTL_ELEVATION_FLAGS Flags\n    );\n#endif\n\n// end_private\n\n#if (PHNT_VERSION >= PHNT_VISTA)\n// private\nNTSYSAPI\nNTSTATUS\nNTAPI\nRtlRegisterThreadWithCsrss(\n    VOID\n    );\n#endif\n\n#if (PHNT_VERSION >= PHNT_VISTA)\n// private\nNTSYSAPI\nNTSTATUS\nNTAPI\nRtlLockCurrentThread(\n    VOID\n    );\n#endif\n\n#if (PHNT_VERSION >= PHNT_VISTA)\n// private\nNTSYSAPI\nNTSTATUS\nNTAPI\nRtlUnlockCurrentThread(\n    VOID\n    );\n#endif\n\n#if (PHNT_VERSION >= PHNT_VISTA)\n// private\nNTSYSAPI\nNTSTATUS\nNTAPI\nRtlLockModuleSection(\n    _In_ PVOID Address\n    );\n#endif\n\n#if (PHNT_VERSION >= PHNT_VISTA)\n// private\nNTSYSAPI\nNTSTATUS\nNTAPI\nRtlUnlockModuleSection(\n    _In_ PVOID Address\n    );\n#endif\n\n// begin_msdn:\"Winternl\"\n\n#define RTL_UNLOAD_EVENT_TRACE_NUMBER 64\n\n// private\ntypedef struct _RTL_UNLOAD_EVENT_TRACE\n{\n    PVOID BaseAddress;\n    SIZE_T SizeOfImage;\n    ULONG Sequence;\n    ULONG TimeDateStamp;\n    ULONG CheckSum;\n    WCHAR ImageName[32];\n    ULONG Version[2];\n} RTL_UNLOAD_EVENT_TRACE, *PRTL_UNLOAD_EVENT_TRACE;\n\nNTSYSAPI\nPRTL_UNLOAD_EVENT_TRACE\nNTAPI\nRtlGetUnloadEventTrace(\n    VOID\n    );\n\n#if (PHNT_VERSION >= PHNT_VISTA)\nNTSYSAPI\nVOID\nNTAPI\nRtlGetUnloadEventTraceEx(\n    _Out_ PULONG *ElementSize,\n    _Out_ PULONG *ElementCount,\n    _Out_ PVOID *EventTrace // works across all processes\n    );\n#endif\n\n// end_msdn\n\n#if (PHNT_VERSION >= PHNT_WIN7)\n// rev\nNTSYSAPI\nLOGICAL\nNTAPI\nRtlQueryPerformanceCounter(\n    _Out_ PLARGE_INTEGER PerformanceCounter\n    );\n#endif\n\n#if (PHNT_VERSION >= PHNT_WIN7)\n// rev\nNTSYSAPI\nLOGICAL\nNTAPI\nRtlQueryPerformanceFrequency(\n    _Out_ PLARGE_INTEGER PerformanceFrequency\n    );\n#endif\n\n#if (PHNT_VERSION >= PHNT_WIN8)\n\nNTSYSAPI\nULONG\nNTAPI\nRtlCrc32(\n    _In_reads_bytes_(Size) const void *Buffer,\n    _In_ size_t Size,\n    _In_ ULONG InitialCrc\n    );\n\nNTSYSAPI\nULONGLONG\nNTAPI\nRtlCrc64(\n    _In_reads_bytes_(Size) const void *Buffer,\n    _In_ size_t Size,\n    _In_ ULONGLONG InitialCrc\n    );\n\n#endif\n\n// Image Mitigation\n\n// rev\ntypedef enum _IMAGE_MITIGATION_POLICY\n{\n    ImageDepPolicy, // RTL_IMAGE_MITIGATION_DEP_POLICY\n    ImageAslrPolicy, // RTL_IMAGE_MITIGATION_ASLR_POLICY\n    ImageDynamicCodePolicy, // RTL_IMAGE_MITIGATION_DYNAMIC_CODE_POLICY\n    ImageStrictHandleCheckPolicy, // RTL_IMAGE_MITIGATION_STRICT_HANDLE_CHECK_POLICY\n    ImageSystemCallDisablePolicy, // RTL_IMAGE_MITIGATION_SYSTEM_CALL_DISABLE_POLICY\n    ImageMitigationOptionsMask,\n    ImageExtensionPointDisablePolicy, // RTL_IMAGE_MITIGATION_EXTENSION_POINT_DISABLE_POLICY\n    ImageControlFlowGuardPolicy, // RTL_IMAGE_MITIGATION_CONTROL_FLOW_GUARD_POLICY\n    ImageSignaturePolicy, // RTL_IMAGE_MITIGATION_BINARY_SIGNATURE_POLICY\n    ImageFontDisablePolicy, // RTL_IMAGE_MITIGATION_FONT_DISABLE_POLICY\n    ImageImageLoadPolicy, // RTL_IMAGE_MITIGATION_IMAGE_LOAD_POLICY\n    ImagePayloadRestrictionPolicy, // RTL_IMAGE_MITIGATION_PAYLOAD_RESTRICTION_POLICY\n    ImageChildProcessPolicy, // RTL_IMAGE_MITIGATION_CHILD_PROCESS_POLICY\n    ImageSehopPolicy, // RTL_IMAGE_MITIGATION_SEHOP_POLICY\n    ImageHeapPolicy, // RTL_IMAGE_MITIGATION_HEAP_POLICY\n    MaxImageMitigationPolicy\n} IMAGE_MITIGATION_POLICY;\n\n// rev\ntypedef union _RTL_IMAGE_MITIGATION_POLICY\n{\n    struct\n    {\n        ULONG64 AuditState : 2;\n        ULONG64 AuditFlag : 1;\n        ULONG64 EnableAdditionalAuditingOption : 1;\n        ULONG64 Reserved : 60;\n    };\n    struct\n    {\n        ULONG64 PolicyState : 2;\n        ULONG64 AlwaysInherit : 1;\n        ULONG64 EnableAdditionalPolicyOption : 1;\n        ULONG64 AuditReserved : 60;\n    };\n} RTL_IMAGE_MITIGATION_POLICY, *PRTL_IMAGE_MITIGATION_POLICY;\n\n// rev\ntypedef struct _RTL_IMAGE_MITIGATION_DEP_POLICY\n{\n    RTL_IMAGE_MITIGATION_POLICY Dep;\n} RTL_IMAGE_MITIGATION_DEP_POLICY, *PRTL_IMAGE_MITIGATION_DEP_POLICY;\n\n// rev\ntypedef struct _RTL_IMAGE_MITIGATION_ASLR_POLICY\n{\n    RTL_IMAGE_MITIGATION_POLICY ForceRelocateImages;\n    RTL_IMAGE_MITIGATION_POLICY BottomUpRandomization;\n    RTL_IMAGE_MITIGATION_POLICY HighEntropyRandomization;\n} RTL_IMAGE_MITIGATION_ASLR_POLICY, *PRTL_IMAGE_MITIGATION_ASLR_POLICY;\n\n// rev\ntypedef struct _RTL_IMAGE_MITIGATION_DYNAMIC_CODE_POLICY\n{\n    RTL_IMAGE_MITIGATION_POLICY BlockDynamicCode;\n} RTL_IMAGE_MITIGATION_DYNAMIC_CODE_POLICY, *PRTL_IMAGE_MITIGATION_DYNAMIC_CODE_POLICY;\n\n// rev\ntypedef struct _RTL_IMAGE_MITIGATION_STRICT_HANDLE_CHECK_POLICY\n{\n    RTL_IMAGE_MITIGATION_POLICY StrictHandleChecks;\n} RTL_IMAGE_MITIGATION_STRICT_HANDLE_CHECK_POLICY, *PRTL_IMAGE_MITIGATION_STRICT_HANDLE_CHECK_POLICY;\n\n// rev\ntypedef struct _RTL_IMAGE_MITIGATION_SYSTEM_CALL_DISABLE_POLICY\n{\n    RTL_IMAGE_MITIGATION_POLICY BlockWin32kSystemCalls;\n} RTL_IMAGE_MITIGATION_SYSTEM_CALL_DISABLE_POLICY, *PRTL_IMAGE_MITIGATION_SYSTEM_CALL_DISABLE_POLICY;\n\n// rev\ntypedef struct _RTL_IMAGE_MITIGATION_EXTENSION_POINT_DISABLE_POLICY\n{\n    RTL_IMAGE_MITIGATION_POLICY DisableExtensionPoints;\n} RTL_IMAGE_MITIGATION_EXTENSION_POINT_DISABLE_POLICY, *PRTL_IMAGE_MITIGATION_EXTENSION_POINT_DISABLE_POLICY;\n\n// rev\ntypedef struct _RTL_IMAGE_MITIGATION_CONTROL_FLOW_GUARD_POLICY\n{\n    RTL_IMAGE_MITIGATION_POLICY ControlFlowGuard;\n    RTL_IMAGE_MITIGATION_POLICY StrictControlFlowGuard;\n} RTL_IMAGE_MITIGATION_CONTROL_FLOW_GUARD_POLICY, *PRTL_IMAGE_MITIGATION_CONTROL_FLOW_GUARD_POLICY;\n\n// rev\ntypedef struct _RTL_IMAGE_MITIGATION_BINARY_SIGNATURE_POLICY\n{\n    RTL_IMAGE_MITIGATION_POLICY BlockNonMicrosoftSignedBinaries;\n    RTL_IMAGE_MITIGATION_POLICY EnforceSigningOnModuleDependencies;\n} RTL_IMAGE_MITIGATION_BINARY_SIGNATURE_POLICY, *PRTL_IMAGE_MITIGATION_BINARY_SIGNATURE_POLICY;\n\n// rev\ntypedef struct _RTL_IMAGE_MITIGATION_FONT_DISABLE_POLICY\n{\n    RTL_IMAGE_MITIGATION_POLICY DisableNonSystemFonts;\n} RTL_IMAGE_MITIGATION_FONT_DISABLE_POLICY, *PRTL_IMAGE_MITIGATION_FONT_DISABLE_POLICY;\n\n// rev\ntypedef struct _RTL_IMAGE_MITIGATION_IMAGE_LOAD_POLICY\n{\n    RTL_IMAGE_MITIGATION_POLICY BlockRemoteImageLoads;\n    RTL_IMAGE_MITIGATION_POLICY BlockLowLabelImageLoads;\n    RTL_IMAGE_MITIGATION_POLICY PreferSystem32;\n} RTL_IMAGE_MITIGATION_IMAGE_LOAD_POLICY, *PRTL_IMAGE_MITIGATION_IMAGE_LOAD_POLICY;\n\n// rev\ntypedef struct _RTL_IMAGE_MITIGATION_PAYLOAD_RESTRICTION_POLICY\n{\n    RTL_IMAGE_MITIGATION_POLICY EnableExportAddressFilter;\n    RTL_IMAGE_MITIGATION_POLICY EnableExportAddressFilterPlus;\n    RTL_IMAGE_MITIGATION_POLICY EnableImportAddressFilter;\n    RTL_IMAGE_MITIGATION_POLICY EnableRopStackPivot;\n    RTL_IMAGE_MITIGATION_POLICY EnableRopCallerCheck;\n    RTL_IMAGE_MITIGATION_POLICY EnableRopSimExec;\n} RTL_IMAGE_MITIGATION_PAYLOAD_RESTRICTION_POLICY, *PRTL_IMAGE_MITIGATION_PAYLOAD_RESTRICTION_POLICY;\n\n// rev\ntypedef struct _RTL_IMAGE_MITIGATION_CHILD_PROCESS_POLICY\n{\n    RTL_IMAGE_MITIGATION_POLICY DisallowChildProcessCreation;\n} RTL_IMAGE_MITIGATION_CHILD_PROCESS_POLICY, *PRTL_IMAGE_MITIGATION_CHILD_PROCESS_POLICY;\n\n// rev\ntypedef struct _RTL_IMAGE_MITIGATION_SEHOP_POLICY\n{\n    RTL_IMAGE_MITIGATION_POLICY Sehop;\n} RTL_IMAGE_MITIGATION_SEHOP_POLICY, *PRTL_IMAGE_MITIGATION_SEHOP_POLICY;\n\n// rev\ntypedef struct _RTL_IMAGE_MITIGATION_HEAP_POLICY\n{\n    RTL_IMAGE_MITIGATION_POLICY TerminateOnHeapErrors;\n} RTL_IMAGE_MITIGATION_HEAP_POLICY, *PRTL_IMAGE_MITIGATION_HEAP_POLICY;\n\ntypedef enum _RTL_IMAGE_MITIGATION_OPTION_STATE\n{\n    RtlMitigationOptionStateNotConfigured,\n    RtlMitigationOptionStateOn,\n    RtlMitigationOptionStateOff\n} RTL_IMAGE_MITIGATION_OPTION_STATE;\n\n// rev from PROCESS_MITIGATION_FLAGS\n#define RTL_IMAGE_MITIGATION_FLAG_RESET 0x1\n#define RTL_IMAGE_MITIGATION_FLAG_REMOVE 0x2\n#define RTL_IMAGE_MITIGATION_FLAG_OSDEFAULT 0x4\n#define RTL_IMAGE_MITIGATION_FLAG_AUDIT 0x8\n\n#if (PHNT_VERSION >= PHNT_REDSTONE3)\n\n// rev\nNTSYSAPI\nNTSTATUS\nNTAPI\nRtlQueryImageMitigationPolicy(\n    _In_opt_ PWSTR ImagePath, // NULL for system-wide defaults\n    _In_ IMAGE_MITIGATION_POLICY Policy,\n    _In_ ULONG Flags,\n    _Inout_ PVOID Buffer,\n    _In_ ULONG BufferSize\n    );\n\n// rev\nNTSYSAPI\nNTSTATUS\nNTAPI\nRtlSetImageMitigationPolicy(\n    _In_opt_ PWSTR ImagePath, // NULL for system-wide defaults\n    _In_ IMAGE_MITIGATION_POLICY Policy,\n    _In_ ULONG Flags,\n    _Inout_ PVOID Buffer,\n    _In_ ULONG BufferSize\n    );\n\n#endif\n\n#endif\n"
  },
  {
    "path": "third_party/phnt/include/ntsam.h",
    "content": "#ifndef _NTSAM_H\n#define _NTSAM_H\n\n#define SAM_MAXIMUM_LOOKUP_COUNT (1000)\n#define SAM_MAXIMUM_LOOKUP_LENGTH (32000)\n#define SAM_MAX_PASSWORD_LENGTH (256)\n#define SAM_PASSWORD_ENCRYPTION_SALT_LEN (16)\n\ntypedef PVOID SAM_HANDLE, *PSAM_HANDLE;\ntypedef ULONG SAM_ENUMERATE_HANDLE, *PSAM_ENUMERATE_HANDLE;\n\ntypedef struct _SAM_RID_ENUMERATION\n{\n    ULONG RelativeId;\n    UNICODE_STRING Name;\n} SAM_RID_ENUMERATION, *PSAM_RID_ENUMERATION;\n\ntypedef struct _SAM_SID_ENUMERATION\n{\n    PSID Sid;\n    UNICODE_STRING Name;\n} SAM_SID_ENUMERATION, *PSAM_SID_ENUMERATION;\n\ntypedef struct _SAM_BYTE_ARRAY\n{\n    ULONG Size;\n    _Field_size_bytes_(Size) PUCHAR Data;\n} SAM_BYTE_ARRAY, *PSAM_BYTE_ARRAY;\n\ntypedef struct _SAM_BYTE_ARRAY_32K\n{\n    ULONG Size;\n    _Field_size_bytes_(Size) PUCHAR Data;\n} SAM_BYTE_ARRAY_32K, *PSAM_BYTE_ARRAY_32K;\n\ntypedef SAM_BYTE_ARRAY_32K SAM_SHELL_OBJECT_PROPERTIES, *PSAM_SHELL_OBJECT_PROPERTIES;\n\n// Basic\n\nNTSTATUS\nNTAPI\nSamFreeMemory(\n    _In_ PVOID Buffer\n    );\n\nNTSTATUS\nNTAPI\nSamCloseHandle(\n    _In_ SAM_HANDLE SamHandle\n    );\n\n_Check_return_\nNTSTATUS\nNTAPI\nSamSetSecurityObject(\n    _In_ SAM_HANDLE ObjectHandle,\n    _In_ SECURITY_INFORMATION SecurityInformation,\n    _In_ PSECURITY_DESCRIPTOR SecurityDescriptor\n    );\n\n_Check_return_\nNTSTATUS\nNTAPI\nSamQuerySecurityObject(\n    _In_ SAM_HANDLE ObjectHandle,\n    _In_ SECURITY_INFORMATION SecurityInformation,\n    _Outptr_ PSECURITY_DESCRIPTOR *SecurityDescriptor\n    );\n\n_Check_return_\nNTSTATUS\nNTAPI\nSamRidToSid(\n    _In_ SAM_HANDLE ObjectHandle,\n    _In_ ULONG Rid,\n    _Outptr_ PSID *Sid\n    );\n\n// Server\n\n#define SAM_SERVER_CONNECT 0x0001\n#define SAM_SERVER_SHUTDOWN 0x0002\n#define SAM_SERVER_INITIALIZE 0x0004\n#define SAM_SERVER_CREATE_DOMAIN 0x0008\n#define SAM_SERVER_ENUMERATE_DOMAINS 0x0010\n#define SAM_SERVER_LOOKUP_DOMAIN 0x0020\n\n#define SAM_SERVER_ALL_ACCESS (STANDARD_RIGHTS_REQUIRED     | \\\n    SAM_SERVER_CONNECT | \\\n    SAM_SERVER_INITIALIZE | \\\n    SAM_SERVER_CREATE_DOMAIN | \\\n    SAM_SERVER_SHUTDOWN | \\\n    SAM_SERVER_ENUMERATE_DOMAINS | \\\n    SAM_SERVER_LOOKUP_DOMAIN)\n\n#define SAM_SERVER_READ (STANDARD_RIGHTS_READ | \\\n    SAM_SERVER_ENUMERATE_DOMAINS)\n\n#define SAM_SERVER_WRITE (STANDARD_RIGHTS_WRITE | \\\n    SAM_SERVER_INITIALIZE | \\\n    SAM_SERVER_CREATE_DOMAIN | \\\n    SAM_SERVER_SHUTDOWN)\n\n#define SAM_SERVER_EXECUTE (STANDARD_RIGHTS_EXECUTE | \\\n    SAM_SERVER_CONNECT | \\\n    SAM_SERVER_LOOKUP_DOMAIN)\n\n// Functions\n\n_Check_return_\nNTSTATUS\nNTAPI\nSamConnect(\n    _In_opt_ PUNICODE_STRING ServerName,\n    _Out_ PSAM_HANDLE ServerHandle,\n    _In_ ACCESS_MASK DesiredAccess,\n    _In_ POBJECT_ATTRIBUTES ObjectAttributes\n    );\n\n_Check_return_\nNTSTATUS\nNTAPI\nSamShutdownSamServer(\n    _In_ SAM_HANDLE ServerHandle\n    );\n\n// Domain\n\n#define DOMAIN_READ_PASSWORD_PARAMETERS 0x0001\n#define DOMAIN_WRITE_PASSWORD_PARAMS 0x0002\n#define DOMAIN_READ_OTHER_PARAMETERS 0x0004\n#define DOMAIN_WRITE_OTHER_PARAMETERS 0x0008\n#define DOMAIN_CREATE_USER 0x0010\n#define DOMAIN_CREATE_GROUP 0x0020\n#define DOMAIN_CREATE_ALIAS 0x0040\n#define DOMAIN_GET_ALIAS_MEMBERSHIP 0x0080\n#define DOMAIN_LIST_ACCOUNTS 0x0100\n#define DOMAIN_LOOKUP 0x0200\n#define DOMAIN_ADMINISTER_SERVER 0x0400\n\n#define DOMAIN_ALL_ACCESS (STANDARD_RIGHTS_REQUIRED | \\\n    DOMAIN_READ_OTHER_PARAMETERS | \\\n    DOMAIN_WRITE_OTHER_PARAMETERS | \\\n    DOMAIN_WRITE_PASSWORD_PARAMS | \\\n    DOMAIN_CREATE_USER | \\\n    DOMAIN_CREATE_GROUP | \\\n    DOMAIN_CREATE_ALIAS | \\\n    DOMAIN_GET_ALIAS_MEMBERSHIP | \\\n    DOMAIN_LIST_ACCOUNTS | \\\n    DOMAIN_READ_PASSWORD_PARAMETERS | \\\n    DOMAIN_LOOKUP | \\\n    DOMAIN_ADMINISTER_SERVER)\n\n#define DOMAIN_READ (STANDARD_RIGHTS_READ | \\\n    DOMAIN_GET_ALIAS_MEMBERSHIP | \\\n    DOMAIN_READ_OTHER_PARAMETERS)\n\n#define DOMAIN_WRITE (STANDARD_RIGHTS_WRITE | \\\n    DOMAIN_WRITE_OTHER_PARAMETERS | \\\n    DOMAIN_WRITE_PASSWORD_PARAMS | \\\n    DOMAIN_CREATE_USER | \\\n    DOMAIN_CREATE_GROUP | \\\n    DOMAIN_CREATE_ALIAS | \\\n    DOMAIN_ADMINISTER_SERVER)\n\n#define DOMAIN_EXECUTE (STANDARD_RIGHTS_EXECUTE | \\\n    DOMAIN_READ_PASSWORD_PARAMETERS | \\\n    DOMAIN_LIST_ACCOUNTS | \\\n    DOMAIN_LOOKUP)\n\n#define DOMAIN_PROMOTION_INCREMENT { 0x0, 0x10 }\n#define DOMAIN_PROMOTION_MASK { 0x0, 0xfffffff0 }\n\n// SamQueryInformationDomain/SamSetInformationDomain types\n\ntypedef enum _DOMAIN_INFORMATION_CLASS\n{\n    DomainPasswordInformation = 1,\n    DomainGeneralInformation,\n    DomainLogoffInformation,\n    DomainOemInformation,\n    DomainNameInformation,\n    DomainReplicationInformation,\n    DomainServerRoleInformation,\n    DomainModifiedInformation,\n    DomainStateInformation,\n    DomainUasInformation,\n    DomainGeneralInformation2,\n    DomainLockoutInformation,\n    DomainModifiedInformation2\n} DOMAIN_INFORMATION_CLASS;\n\ntypedef enum _DOMAIN_SERVER_ENABLE_STATE\n{\n    DomainServerEnabled = 1,\n    DomainServerDisabled\n} DOMAIN_SERVER_ENABLE_STATE, *PDOMAIN_SERVER_ENABLE_STATE;\n\ntypedef enum _DOMAIN_SERVER_ROLE\n{\n    DomainServerRoleBackup = 2,\n    DomainServerRolePrimary\n} DOMAIN_SERVER_ROLE, *PDOMAIN_SERVER_ROLE;\n\n#include <pshpack4.h>\ntypedef struct _DOMAIN_GENERAL_INFORMATION\n{\n    LARGE_INTEGER ForceLogoff;\n    UNICODE_STRING OemInformation;\n    UNICODE_STRING DomainName;\n    UNICODE_STRING ReplicaSourceNodeName;\n    LARGE_INTEGER DomainModifiedCount;\n    DOMAIN_SERVER_ENABLE_STATE DomainServerState;\n    DOMAIN_SERVER_ROLE DomainServerRole;\n    BOOLEAN UasCompatibilityRequired;\n    ULONG UserCount;\n    ULONG GroupCount;\n    ULONG AliasCount;\n} DOMAIN_GENERAL_INFORMATION, *PDOMAIN_GENERAL_INFORMATION;\n#include <poppack.h>\n\n#include <pshpack4.h>\ntypedef struct _DOMAIN_GENERAL_INFORMATION2\n{\n    DOMAIN_GENERAL_INFORMATION I1;\n    LARGE_INTEGER LockoutDuration; // delta time\n    LARGE_INTEGER LockoutObservationWindow; // delta time\n    USHORT LockoutThreshold;\n} DOMAIN_GENERAL_INFORMATION2, *PDOMAIN_GENERAL_INFORMATION2;\n#include <poppack.h>\n\ntypedef struct _DOMAIN_UAS_INFORMATION\n{\n    BOOLEAN UasCompatibilityRequired;\n} DOMAIN_UAS_INFORMATION;\n\n#ifndef _DOMAIN_PASSWORD_INFORMATION_DEFINED // defined in ntsecapi.h\n#define _DOMAIN_PASSWORD_INFORMATION_DEFINED\n\ntypedef struct _DOMAIN_PASSWORD_INFORMATION\n{\n    USHORT MinPasswordLength;\n    USHORT PasswordHistoryLength;\n    ULONG PasswordProperties;\n    LARGE_INTEGER MaxPasswordAge;\n    LARGE_INTEGER MinPasswordAge;\n} DOMAIN_PASSWORD_INFORMATION, *PDOMAIN_PASSWORD_INFORMATION;\n\n// PasswordProperties flags\n\n#define DOMAIN_PASSWORD_COMPLEX 0x00000001L\n#define DOMAIN_PASSWORD_NO_ANON_CHANGE 0x00000002L\n#define DOMAIN_PASSWORD_NO_CLEAR_CHANGE 0x00000004L\n#define DOMAIN_LOCKOUT_ADMINS 0x00000008L\n#define DOMAIN_PASSWORD_STORE_CLEARTEXT 0x00000010L\n#define DOMAIN_REFUSE_PASSWORD_CHANGE 0x00000020L\n#define DOMAIN_NO_LM_OWF_CHANGE 0x00000040L\n\n#endif\n\ntypedef enum _DOMAIN_PASSWORD_CONSTRUCTION\n{\n    DomainPasswordSimple = 1,\n    DomainPasswordComplex\n} DOMAIN_PASSWORD_CONSTRUCTION;\n\ntypedef struct _DOMAIN_LOGOFF_INFORMATION\n{\n    LARGE_INTEGER ForceLogoff;\n} DOMAIN_LOGOFF_INFORMATION, *PDOMAIN_LOGOFF_INFORMATION;\n\ntypedef struct _DOMAIN_OEM_INFORMATION\n{\n    UNICODE_STRING OemInformation;\n} DOMAIN_OEM_INFORMATION, *PDOMAIN_OEM_INFORMATION;\n\ntypedef struct _DOMAIN_NAME_INFORMATION\n{\n    UNICODE_STRING DomainName;\n} DOMAIN_NAME_INFORMATION, *PDOMAIN_NAME_INFORMATION;\n\ntypedef struct _DOMAIN_SERVER_ROLE_INFORMATION\n{\n    DOMAIN_SERVER_ROLE DomainServerRole;\n} DOMAIN_SERVER_ROLE_INFORMATION, *PDOMAIN_SERVER_ROLE_INFORMATION;\n\ntypedef struct _DOMAIN_REPLICATION_INFORMATION\n{\n    UNICODE_STRING ReplicaSourceNodeName;\n} DOMAIN_REPLICATION_INFORMATION, *PDOMAIN_REPLICATION_INFORMATION;\n\ntypedef struct _DOMAIN_MODIFIED_INFORMATION\n{\n    LARGE_INTEGER DomainModifiedCount;\n    LARGE_INTEGER CreationTime;\n} DOMAIN_MODIFIED_INFORMATION, *PDOMAIN_MODIFIED_INFORMATION;\n\ntypedef struct _DOMAIN_MODIFIED_INFORMATION2\n{\n    LARGE_INTEGER DomainModifiedCount;\n    LARGE_INTEGER CreationTime;\n    LARGE_INTEGER ModifiedCountAtLastPromotion;\n} DOMAIN_MODIFIED_INFORMATION2, *PDOMAIN_MODIFIED_INFORMATION2;\n\ntypedef struct _DOMAIN_STATE_INFORMATION\n{\n    DOMAIN_SERVER_ENABLE_STATE DomainServerState;\n} DOMAIN_STATE_INFORMATION, *PDOMAIN_STATE_INFORMATION;\n\ntypedef struct _DOMAIN_LOCKOUT_INFORMATION\n{\n    LARGE_INTEGER LockoutDuration; // delta time\n    LARGE_INTEGER LockoutObservationWindow; // delta time\n    USHORT LockoutThreshold; // zero means no lockout\n} DOMAIN_LOCKOUT_INFORMATION, *PDOMAIN_LOCKOUT_INFORMATION;\n\n// SamQueryDisplayInformation types\n\ntypedef enum _DOMAIN_DISPLAY_INFORMATION\n{\n    DomainDisplayUser = 1,\n    DomainDisplayMachine,\n    DomainDisplayGroup,\n    DomainDisplayOemUser,\n    DomainDisplayOemGroup,\n    DomainDisplayServer\n} DOMAIN_DISPLAY_INFORMATION, *PDOMAIN_DISPLAY_INFORMATION;\n\ntypedef struct _DOMAIN_DISPLAY_USER\n{\n    ULONG Index;\n    ULONG Rid;\n    ULONG AccountControl;\n    UNICODE_STRING LogonName;\n    UNICODE_STRING AdminComment;\n    UNICODE_STRING FullName;\n} DOMAIN_DISPLAY_USER, *PDOMAIN_DISPLAY_USER;\n\ntypedef struct _DOMAIN_DISPLAY_MACHINE\n{\n    ULONG Index;\n    ULONG Rid;\n    ULONG AccountControl;\n    UNICODE_STRING Machine;\n    UNICODE_STRING Comment;\n} DOMAIN_DISPLAY_MACHINE, *PDOMAIN_DISPLAY_MACHINE;\n\ntypedef struct _DOMAIN_DISPLAY_GROUP\n{\n    ULONG Index;\n    ULONG Rid;\n    ULONG Attributes;\n    UNICODE_STRING Group;\n    UNICODE_STRING Comment;\n} DOMAIN_DISPLAY_GROUP, *PDOMAIN_DISPLAY_GROUP;\n\ntypedef struct _DOMAIN_DISPLAY_OEM_USER\n{\n    ULONG Index;\n    OEM_STRING User;\n} DOMAIN_DISPLAY_OEM_USER, *PDOMAIN_DISPLAY_OEM_USER;\n\ntypedef struct _DOMAIN_DISPLAY_OEM_GROUP\n{\n    ULONG Index;\n    OEM_STRING Group;\n} DOMAIN_DISPLAY_OEM_GROUP, *PDOMAIN_DISPLAY_OEM_GROUP;\n\n// SamQueryLocalizableAccountsInDomain types\n\ntypedef enum _DOMAIN_LOCALIZABLE_ACCOUNTS_INFORMATION\n{\n    DomainLocalizableAccountsBasic = 1,\n} DOMAIN_LOCALIZABLE_ACCOUNTS_INFORMATION, *PDOMAIN_LOCALIZABLE_ACCOUNTS_INFORMATION;\n\ntypedef struct _DOMAIN_LOCALIZABLE_ACCOUNTS_ENTRY\n{\n    ULONG Rid;\n    SID_NAME_USE Use;\n    UNICODE_STRING Name;\n    UNICODE_STRING AdminComment;\n} DOMAIN_LOCALIZABLE_ACCOUNT_ENTRY, *PDOMAIN_LOCALIZABLE_ACCOUNT_ENTRY;\n\ntypedef struct _DOMAIN_LOCALIZABLE_ACCOUNTS\n{\n    ULONG Count;\n    _Field_size_(Count) DOMAIN_LOCALIZABLE_ACCOUNT_ENTRY *Entries;\n} DOMAIN_LOCALIZABLE_ACCOUNTS_BASIC, *PDOMAIN_LOCALIZABLE_ACCOUNTS_BASIC;\n\ntypedef union _DOMAIN_LOCALIZABLE_INFO_BUFFER\n{\n    DOMAIN_LOCALIZABLE_ACCOUNTS_BASIC Basic;\n} DOMAIN_LOCALIZABLE_ACCOUNTS_INFO_BUFFER, *PDOMAIN_LOCALIZABLE_ACCOUNTS_INFO_BUFFER;\n\n// Functions\n\n_Check_return_\nNTSTATUS\nNTAPI\nSamLookupDomainInSamServer(\n    _In_ SAM_HANDLE ServerHandle,\n    _In_ PUNICODE_STRING Name,\n    _Outptr_ PSID *DomainId\n    );\n\n_Check_return_\nNTSTATUS\nNTAPI\nSamEnumerateDomainsInSamServer(\n    _In_ SAM_HANDLE ServerHandle,\n    _Inout_ PSAM_ENUMERATE_HANDLE EnumerationContext,\n    _Outptr_ PVOID *Buffer, // PSAM_SID_ENUMERATION *Buffer\n    _In_ ULONG PreferedMaximumLength,\n    _Out_ PULONG CountReturned\n    );\n\n_Check_return_\nNTSTATUS\nNTAPI\nSamOpenDomain(\n    _In_ SAM_HANDLE ServerHandle,\n    _In_ ACCESS_MASK DesiredAccess,\n    _In_ PSID DomainId,\n    _Out_ PSAM_HANDLE DomainHandle\n    );\n\n_Check_return_\nNTSTATUS\nNTAPI\nSamQueryInformationDomain(\n    _In_ SAM_HANDLE DomainHandle,\n    _In_ DOMAIN_INFORMATION_CLASS DomainInformationClass,\n    _Outptr_ PVOID *Buffer\n    );\n\n_Check_return_\nNTSTATUS\nNTAPI\nSamSetInformationDomain(\n    _In_ SAM_HANDLE DomainHandle,\n    _In_ DOMAIN_INFORMATION_CLASS DomainInformationClass,\n    _In_ PVOID DomainInformation\n    );\n\n_Check_return_\nNTSTATUS\nNTAPI\nSamLookupNamesInDomain(\n    _In_ SAM_HANDLE DomainHandle,\n    _In_ ULONG Count,\n    _In_reads_(Count) PUNICODE_STRING Names,\n    _Out_ _Deref_post_count_(Count) PULONG *RelativeIds,\n    _Out_ _Deref_post_count_(Count) PSID_NAME_USE *Use\n    );\n\n_Check_return_\nNTSTATUS\nNTAPI\nSamLookupIdsInDomain(\n    _In_ SAM_HANDLE DomainHandle,\n    _In_ ULONG Count,\n    _In_reads_(Count) PULONG RelativeIds,\n    _Out_ _Deref_post_count_(Count) PUNICODE_STRING *Names,\n    _Out_ _Deref_post_opt_count_(Count) PSID_NAME_USE *Use\n    );\n\n_Check_return_\nNTSTATUS\nNTAPI\nSamRemoveMemberFromForeignDomain(\n    _In_ SAM_HANDLE DomainHandle,\n    _In_ PSID MemberId\n    );\n\n_Check_return_\nNTSTATUS\nNTAPI\nSamQueryLocalizableAccountsInDomain(\n    _In_ SAM_HANDLE Domain,\n    _In_ ULONG Flags,\n    _In_ ULONG LanguageId,\n    _In_ DOMAIN_LOCALIZABLE_ACCOUNTS_INFORMATION Class,\n    _Outptr_ PVOID *Buffer\n    );\n\n// Group\n\n#define GROUP_READ_INFORMATION 0x0001\n#define GROUP_WRITE_ACCOUNT 0x0002\n#define GROUP_ADD_MEMBER 0x0004\n#define GROUP_REMOVE_MEMBER 0x0008\n#define GROUP_LIST_MEMBERS 0x0010\n\n#define GROUP_ALL_ACCESS (STANDARD_RIGHTS_REQUIRED | \\\n    GROUP_LIST_MEMBERS | \\\n    GROUP_WRITE_ACCOUNT | \\\n    GROUP_ADD_MEMBER | \\\n    GROUP_REMOVE_MEMBER | \\\n    GROUP_READ_INFORMATION)\n\n#define GROUP_READ (STANDARD_RIGHTS_READ | \\\n    GROUP_LIST_MEMBERS)\n\n#define GROUP_WRITE (STANDARD_RIGHTS_WRITE | \\\n    GROUP_WRITE_ACCOUNT | \\\n    GROUP_ADD_MEMBER | \\\n    GROUP_REMOVE_MEMBER)\n\n#define GROUP_EXECUTE (STANDARD_RIGHTS_EXECUTE | \\\n    GROUP_READ_INFORMATION)\n\ntypedef struct _GROUP_MEMBERSHIP\n{\n    ULONG RelativeId;\n    ULONG Attributes;\n} GROUP_MEMBERSHIP, *PGROUP_MEMBERSHIP;\n\n// SamQueryInformationGroup/SamSetInformationGroup types\n\ntypedef enum _GROUP_INFORMATION_CLASS\n{\n    GroupGeneralInformation = 1,\n    GroupNameInformation,\n    GroupAttributeInformation,\n    GroupAdminCommentInformation,\n    GroupReplicationInformation\n} GROUP_INFORMATION_CLASS;\n\ntypedef struct _GROUP_GENERAL_INFORMATION\n{\n    UNICODE_STRING Name;\n    ULONG Attributes;\n    ULONG MemberCount;\n    UNICODE_STRING AdminComment;\n} GROUP_GENERAL_INFORMATION, *PGROUP_GENERAL_INFORMATION;\n\ntypedef struct _GROUP_NAME_INFORMATION\n{\n    UNICODE_STRING Name;\n} GROUP_NAME_INFORMATION, *PGROUP_NAME_INFORMATION;\n\ntypedef struct _GROUP_ATTRIBUTE_INFORMATION\n{\n    ULONG Attributes;\n} GROUP_ATTRIBUTE_INFORMATION, *PGROUP_ATTRIBUTE_INFORMATION;\n\ntypedef struct _GROUP_ADM_COMMENT_INFORMATION\n{\n    UNICODE_STRING AdminComment;\n} GROUP_ADM_COMMENT_INFORMATION, *PGROUP_ADM_COMMENT_INFORMATION;\n\n// Functions\n\n_Check_return_\nNTSTATUS\nNTAPI\nSamEnumerateGroupsInDomain(\n    _In_ SAM_HANDLE DomainHandle,\n    _Inout_ PSAM_ENUMERATE_HANDLE EnumerationContext,\n    _Outptr_ PVOID *Buffer, // PSAM_RID_ENUMERATION *\n    _In_ ULONG PreferedMaximumLength,\n    _Out_ PULONG CountReturned\n    );\n\n_Check_return_\nNTSTATUS\nNTAPI\nSamCreateGroupInDomain(\n    _In_ SAM_HANDLE DomainHandle,\n    _In_ PUNICODE_STRING AccountName,\n    _In_ ACCESS_MASK DesiredAccess,\n    _Out_ PSAM_HANDLE GroupHandle,\n    _Out_ PULONG RelativeId\n    );\n\n_Check_return_\nNTSTATUS\nNTAPI\nSamOpenGroup(\n    _In_ SAM_HANDLE DomainHandle,\n    _In_ ACCESS_MASK DesiredAccess,\n    _In_ ULONG GroupId,\n    _Out_ PSAM_HANDLE GroupHandle\n    );\n\n_Check_return_\nNTSTATUS\nNTAPI\nSamDeleteGroup(\n    _In_ SAM_HANDLE GroupHandle\n    );\n\n_Check_return_\nNTSTATUS\nNTAPI\nSamQueryInformationGroup(\n    _In_ SAM_HANDLE GroupHandle,\n    _In_ GROUP_INFORMATION_CLASS GroupInformationClass,\n    _Outptr_ PVOID *Buffer\n    );\n\n_Check_return_\nNTSTATUS\nNTAPI\nSamSetInformationGroup(\n    _In_ SAM_HANDLE GroupHandle,\n    _In_ GROUP_INFORMATION_CLASS GroupInformationClass,\n    _In_ PVOID Buffer\n    );\n\n_Check_return_\nNTSTATUS\nNTAPI\nSamAddMemberToGroup(\n    _In_ SAM_HANDLE GroupHandle,\n    _In_ ULONG MemberId,\n    _In_ ULONG Attributes\n    );\n\n_Check_return_\nNTSTATUS\nNTAPI\nSamRemoveMemberFromGroup(\n    _In_ SAM_HANDLE GroupHandle,\n    _In_ ULONG MemberId\n    );\n\n_Check_return_\nNTSTATUS\nNTAPI\nSamGetMembersInGroup(\n    _In_ SAM_HANDLE GroupHandle,\n    _Out_ _Deref_post_count_(*MemberCount) PULONG *MemberIds,\n    _Out_ _Deref_post_count_(*MemberCount) PULONG *Attributes,\n    _Out_ PULONG MemberCount\n    );\n\n_Check_return_\nNTSTATUS\nNTAPI\nSamSetMemberAttributesOfGroup(\n    _In_ SAM_HANDLE GroupHandle,\n    _In_ ULONG MemberId,\n    _In_ ULONG Attributes\n    );\n\n// Alias\n\n#define ALIAS_ADD_MEMBER 0x0001\n#define ALIAS_REMOVE_MEMBER 0x0002\n#define ALIAS_LIST_MEMBERS 0x0004\n#define ALIAS_READ_INFORMATION 0x0008\n#define ALIAS_WRITE_ACCOUNT 0x0010\n\n#define ALIAS_ALL_ACCESS (STANDARD_RIGHTS_REQUIRED | \\\n    ALIAS_READ_INFORMATION | \\\n    ALIAS_WRITE_ACCOUNT | \\\n    ALIAS_LIST_MEMBERS | \\\n    ALIAS_ADD_MEMBER | \\\n    ALIAS_REMOVE_MEMBER)\n\n#define ALIAS_READ (STANDARD_RIGHTS_READ | \\\n    ALIAS_LIST_MEMBERS)\n\n#define ALIAS_WRITE (STANDARD_RIGHTS_WRITE | \\\n    ALIAS_WRITE_ACCOUNT | \\\n    ALIAS_ADD_MEMBER | \\\n    ALIAS_REMOVE_MEMBER)\n\n#define ALIAS_EXECUTE (STANDARD_RIGHTS_EXECUTE | \\\n    ALIAS_READ_INFORMATION)\n\n// SamQueryInformationAlias/SamSetInformationAlias types\n\ntypedef enum _ALIAS_INFORMATION_CLASS\n{\n    AliasGeneralInformation = 1,\n    AliasNameInformation,\n    AliasAdminCommentInformation,\n    AliasReplicationInformation,\n    AliasExtendedInformation,\n} ALIAS_INFORMATION_CLASS;\n\ntypedef struct _ALIAS_GENERAL_INFORMATION\n{\n    UNICODE_STRING Name;\n    ULONG MemberCount;\n    UNICODE_STRING AdminComment;\n} ALIAS_GENERAL_INFORMATION,  *PALIAS_GENERAL_INFORMATION;\n\ntypedef struct _ALIAS_NAME_INFORMATION\n{\n    UNICODE_STRING Name;\n} ALIAS_NAME_INFORMATION, *PALIAS_NAME_INFORMATION;\n\ntypedef struct _ALIAS_ADM_COMMENT_INFORMATION\n{\n    UNICODE_STRING AdminComment;\n} ALIAS_ADM_COMMENT_INFORMATION, *PALIAS_ADM_COMMENT_INFORMATION;\n\n#define ALIAS_ALL_NAME (0x00000001L)\n#define ALIAS_ALL_MEMBER_COUNT (0x00000002L)\n#define ALIAS_ALL_ADMIN_COMMENT (0x00000004L)\n#define ALIAS_ALL_SHELL_ADMIN_OBJECT_PROPERTIES (0x00000008L)\n\ntypedef struct _ALIAS_EXTENDED_INFORMATION\n{\n    ULONG WhichFields;\n    SAM_SHELL_OBJECT_PROPERTIES ShellAdminObjectProperties;\n} ALIAS_EXTENDED_INFORMATION, *PALIAS_EXTENDED_INFORMATION;\n\n// Functions\n\n_Check_return_\nNTSTATUS\nNTAPI\nSamEnumerateAliasesInDomain(\n    _In_ SAM_HANDLE DomainHandle,\n    _Inout_ PSAM_ENUMERATE_HANDLE EnumerationContext,\n    _Outptr_ PVOID *Buffer, // PSAM_RID_ENUMERATION *Buffer\n    _In_ ULONG PreferedMaximumLength,\n    _Out_ PULONG CountReturned\n    );\n\n_Check_return_\nNTSTATUS\nNTAPI\nSamCreateAliasInDomain(\n    _In_ SAM_HANDLE DomainHandle,\n    _In_ PUNICODE_STRING AccountName,\n    _In_ ACCESS_MASK DesiredAccess,\n    _Out_ PSAM_HANDLE AliasHandle,\n    _Out_ PULONG RelativeId\n    );\n\n_Check_return_\nNTSTATUS\nNTAPI\nSamOpenAlias(\n    _In_ SAM_HANDLE DomainHandle,\n    _In_ ACCESS_MASK DesiredAccess,\n    _In_ ULONG AliasId,\n    _Out_ PSAM_HANDLE AliasHandle\n    );\n\n_Check_return_\nNTSTATUS\nNTAPI\nSamDeleteAlias(\n    _In_ SAM_HANDLE AliasHandle\n    );\n\n_Check_return_\nNTSTATUS\nNTAPI\nSamQueryInformationAlias(\n    _In_ SAM_HANDLE AliasHandle,\n    _In_ ALIAS_INFORMATION_CLASS AliasInformationClass,\n    _Outptr_ PVOID *Buffer\n    );\n\n_Check_return_\nNTSTATUS\nNTAPI\nSamSetInformationAlias(\n    _In_ SAM_HANDLE AliasHandle,\n    _In_ ALIAS_INFORMATION_CLASS AliasInformationClass,\n    _In_ PVOID Buffer\n    );\n\n_Check_return_\nNTSTATUS\nNTAPI\nSamAddMemberToAlias(\n    _In_ SAM_HANDLE AliasHandle,\n    _In_ PSID MemberId\n    );\n\n_Check_return_\nNTSTATUS\nNTAPI\nSamAddMultipleMembersToAlias(\n    _In_ SAM_HANDLE AliasHandle,\n    _In_reads_(MemberCount) PSID *MemberIds,\n    _In_ ULONG MemberCount\n    );\n\n_Check_return_\nNTSTATUS\nNTAPI\nSamRemoveMemberFromAlias(\n    _In_ SAM_HANDLE AliasHandle,\n    _In_ PSID MemberId\n    );\n\n_Check_return_\nNTSTATUS\nNTAPI\nSamRemoveMultipleMembersFromAlias(\n    _In_ SAM_HANDLE AliasHandle,\n    _In_reads_(MemberCount) PSID *MemberIds,\n    _In_ ULONG MemberCount\n    );\n\n_Check_return_\nNTSTATUS\nNTAPI\nSamGetMembersInAlias(\n    _In_ SAM_HANDLE AliasHandle,\n    _Out_ _Deref_post_count_(*MemberCount) PSID **MemberIds,\n    _Out_ PULONG MemberCount\n    );\n\n_Check_return_\nNTSTATUS\nNTAPI\nSamGetAliasMembership(\n    _In_ SAM_HANDLE DomainHandle,\n    _In_ ULONG PassedCount,\n    _In_reads_(PassedCount) PSID *Sids,\n    _Out_ PULONG MembershipCount,\n    _Out_ _Deref_post_count_(*MembershipCount) PULONG *Aliases\n    );\n\n// Group types\n\n#define GROUP_TYPE_BUILTIN_LOCAL_GROUP 0x00000001\n#define GROUP_TYPE_ACCOUNT_GROUP 0x00000002\n#define GROUP_TYPE_RESOURCE_GROUP 0x00000004\n#define GROUP_TYPE_UNIVERSAL_GROUP 0x00000008\n#define GROUP_TYPE_APP_BASIC_GROUP 0x00000010\n#define GROUP_TYPE_APP_QUERY_GROUP 0x00000020\n#define GROUP_TYPE_SECURITY_ENABLED 0x80000000\n\n#define GROUP_TYPE_RESOURCE_BEHAVOIR (GROUP_TYPE_RESOURCE_GROUP | \\\n    GROUP_TYPE_APP_BASIC_GROUP | \\\n    GROUP_TYPE_APP_QUERY_GROUP)\n\n// User\n\n#define USER_READ_GENERAL 0x0001\n#define USER_READ_PREFERENCES 0x0002\n#define USER_WRITE_PREFERENCES 0x0004\n#define USER_READ_LOGON 0x0008\n#define USER_READ_ACCOUNT 0x0010\n#define USER_WRITE_ACCOUNT 0x0020\n#define USER_CHANGE_PASSWORD 0x0040\n#define USER_FORCE_PASSWORD_CHANGE 0x0080\n#define USER_LIST_GROUPS 0x0100\n#define USER_READ_GROUP_INFORMATION 0x0200\n#define USER_WRITE_GROUP_INFORMATION 0x0400\n\n#define USER_ALL_ACCESS (STANDARD_RIGHTS_REQUIRED | \\\n    USER_READ_PREFERENCES | \\\n    USER_READ_LOGON | \\\n    USER_LIST_GROUPS | \\\n    USER_READ_GROUP_INFORMATION | \\\n    USER_WRITE_PREFERENCES | \\\n    USER_CHANGE_PASSWORD | \\\n    USER_FORCE_PASSWORD_CHANGE | \\\n    USER_READ_GENERAL | \\\n    USER_READ_ACCOUNT | \\\n    USER_WRITE_ACCOUNT | \\\n    USER_WRITE_GROUP_INFORMATION)\n\n#define USER_READ (STANDARD_RIGHTS_READ | \\\n    USER_READ_PREFERENCES | \\\n    USER_READ_LOGON | \\\n    USER_READ_ACCOUNT | \\\n    USER_LIST_GROUPS | \\\n    USER_READ_GROUP_INFORMATION)\n\n#define USER_WRITE (STANDARD_RIGHTS_WRITE | \\\n    USER_WRITE_PREFERENCES | \\\n    USER_CHANGE_PASSWORD)\n\n#define USER_EXECUTE (STANDARD_RIGHTS_EXECUTE | \\\n    USER_READ_GENERAL | \\\n    USER_CHANGE_PASSWORD)\n\n// User account control flags\n\n#define USER_ACCOUNT_DISABLED (0x00000001)\n#define USER_HOME_DIRECTORY_REQUIRED (0x00000002)\n#define USER_PASSWORD_NOT_REQUIRED (0x00000004)\n#define USER_TEMP_DUPLICATE_ACCOUNT (0x00000008)\n#define USER_NORMAL_ACCOUNT (0x00000010)\n#define USER_MNS_LOGON_ACCOUNT (0x00000020)\n#define USER_INTERDOMAIN_TRUST_ACCOUNT (0x00000040)\n#define USER_WORKSTATION_TRUST_ACCOUNT (0x00000080)\n#define USER_SERVER_TRUST_ACCOUNT (0x00000100)\n#define USER_DONT_EXPIRE_PASSWORD (0x00000200)\n#define USER_ACCOUNT_AUTO_LOCKED (0x00000400)\n#define USER_ENCRYPTED_TEXT_PASSWORD_ALLOWED (0x00000800)\n#define USER_SMARTCARD_REQUIRED (0x00001000)\n#define USER_TRUSTED_FOR_DELEGATION (0x00002000)\n#define USER_NOT_DELEGATED (0x00004000)\n#define USER_USE_DES_KEY_ONLY (0x00008000)\n#define USER_DONT_REQUIRE_PREAUTH (0x00010000)\n#define USER_PASSWORD_EXPIRED (0x00020000)\n#define USER_TRUSTED_TO_AUTHENTICATE_FOR_DELEGATION (0x00040000)\n#define USER_NO_AUTH_DATA_REQUIRED (0x00080000)\n#define USER_PARTIAL_SECRETS_ACCOUNT (0x00100000)\n#define USER_USE_AES_KEYS (0x00200000) // not used\n\n#define NEXT_FREE_ACCOUNT_CONTROL_BIT (USER_USE_AES_KEYS << 1)\n\n#define USER_MACHINE_ACCOUNT_MASK ( \\\n    USER_INTERDOMAIN_TRUST_ACCOUNT | \\\n    USER_WORKSTATION_TRUST_ACCOUNT | \\\n    USER_SERVER_TRUST_ACCOUNT \\\n    )\n\n#define USER_ACCOUNT_TYPE_MASK ( \\\n    USER_TEMP_DUPLICATE_ACCOUNT | \\\n    USER_NORMAL_ACCOUNT | \\\n    USER_MACHINE_ACCOUNT_MASK \\\n    )\n\n#define USER_COMPUTED_ACCOUNT_CONTROL_BITS ( \\\n    USER_ACCOUNT_AUTO_LOCKED | \\\n    USER_PASSWORD_EXPIRED \\\n    )\n\n// Logon times may be expressed in day, hour, or minute granularity.\n\n#define SAM_DAYS_PER_WEEK (7)\n#define SAM_HOURS_PER_WEEK (24 * SAM_DAYS_PER_WEEK)\n#define SAM_MINUTES_PER_WEEK (60 * SAM_HOURS_PER_WEEK)\n\ntypedef struct _LOGON_HOURS\n{\n    USHORT UnitsPerWeek;\n\n    // UnitsPerWeek is the number of equal length time units the week is\n    // divided into. This value is used to compute the length of the bit\n    // string in logon_hours. Must be less than or equal to\n    // SAM_UNITS_PER_WEEK (10080) for this release.\n    //\n    // LogonHours is a bit map of valid logon times. Each bit represents\n    // a unique division in a week. The largest bit map supported is 1260\n    // bytes (10080 bits), which represents minutes per week. In this case\n    // the first bit (bit 0, byte 0) is Sunday, 00:00:00 - 00-00:59; bit 1,\n    // byte 0 is Sunday, 00:01:00 - 00:01:59, etc. A NULL pointer means\n    // DONT_CHANGE for SamSetInformationUser() calls.\n\n    PUCHAR LogonHours;\n} LOGON_HOURS, *PLOGON_HOURS;\n\ntypedef struct _SR_SECURITY_DESCRIPTOR\n{\n    ULONG Length;\n    PUCHAR SecurityDescriptor;\n} SR_SECURITY_DESCRIPTOR, *PSR_SECURITY_DESCRIPTOR;\n\n// SamQueryInformationUser/SamSetInformationUser types\n\ntypedef enum _USER_INFORMATION_CLASS\n{\n    UserGeneralInformation = 1,\n    UserPreferencesInformation,\n    UserLogonInformation,\n    UserLogonHoursInformation,\n    UserAccountInformation,\n    UserNameInformation,\n    UserAccountNameInformation,\n    UserFullNameInformation,\n    UserPrimaryGroupInformation,\n    UserHomeInformation,\n    UserScriptInformation,\n    UserProfileInformation,\n    UserAdminCommentInformation,\n    UserWorkStationsInformation,\n    UserSetPasswordInformation,\n    UserControlInformation,\n    UserExpiresInformation,\n    UserInternal1Information,\n    UserInternal2Information,\n    UserParametersInformation,\n    UserAllInformation,\n    UserInternal3Information,\n    UserInternal4Information,\n    UserInternal5Information,\n    UserInternal4InformationNew,\n    UserInternal5InformationNew,\n    UserInternal6Information,\n    UserExtendedInformation,\n    UserLogonUIInformation\n} USER_INFORMATION_CLASS, *PUSER_INFORMATION_CLASS;\n\n#include <pshpack4.h>\ntypedef struct _USER_ALL_INFORMATION\n{\n    LARGE_INTEGER LastLogon;\n    LARGE_INTEGER LastLogoff;\n    LARGE_INTEGER PasswordLastSet;\n    LARGE_INTEGER AccountExpires;\n    LARGE_INTEGER PasswordCanChange;\n    LARGE_INTEGER PasswordMustChange;\n    UNICODE_STRING UserName;\n    UNICODE_STRING FullName;\n    UNICODE_STRING HomeDirectory;\n    UNICODE_STRING HomeDirectoryDrive;\n    UNICODE_STRING ScriptPath;\n    UNICODE_STRING ProfilePath;\n    UNICODE_STRING AdminComment;\n    UNICODE_STRING WorkStations;\n    UNICODE_STRING UserComment;\n    UNICODE_STRING Parameters;\n    UNICODE_STRING LmPassword;\n    UNICODE_STRING NtPassword;\n    UNICODE_STRING PrivateData;\n    SR_SECURITY_DESCRIPTOR SecurityDescriptor;\n    ULONG UserId;\n    ULONG PrimaryGroupId;\n    ULONG UserAccountControl;\n    ULONG WhichFields;\n    LOGON_HOURS LogonHours;\n    USHORT BadPasswordCount;\n    USHORT LogonCount;\n    USHORT CountryCode;\n    USHORT CodePage;\n    BOOLEAN LmPasswordPresent;\n    BOOLEAN NtPasswordPresent;\n    BOOLEAN PasswordExpired;\n    BOOLEAN PrivateDataSensitive;\n} USER_ALL_INFORMATION, *PUSER_ALL_INFORMATION;\n#include <poppack.h>\n\n// Flags for WhichFields in USER_ALL_INFORMATION\n\n#define USER_ALL_USERNAME 0x00000001\n#define USER_ALL_FULLNAME 0x00000002\n#define USER_ALL_USERID 0x00000004\n#define USER_ALL_PRIMARYGROUPID 0x00000008\n#define USER_ALL_ADMINCOMMENT 0x00000010\n#define USER_ALL_USERCOMMENT 0x00000020\n#define USER_ALL_HOMEDIRECTORY 0x00000040\n#define USER_ALL_HOMEDIRECTORYDRIVE 0x00000080\n#define USER_ALL_SCRIPTPATH 0x00000100\n#define USER_ALL_PROFILEPATH 0x00000200\n#define USER_ALL_WORKSTATIONS 0x00000400\n#define USER_ALL_LASTLOGON 0x00000800\n#define USER_ALL_LASTLOGOFF 0x00001000\n#define USER_ALL_LOGONHOURS 0x00002000\n#define USER_ALL_BADPASSWORDCOUNT 0x00004000\n#define USER_ALL_LOGONCOUNT 0x00008000\n#define USER_ALL_PASSWORDCANCHANGE 0x00010000\n#define USER_ALL_PASSWORDMUSTCHANGE 0x00020000\n#define USER_ALL_PASSWORDLASTSET 0x00040000\n#define USER_ALL_ACCOUNTEXPIRES 0x00080000\n#define USER_ALL_USERACCOUNTCONTROL 0x00100000\n#define USER_ALL_PARAMETERS 0x00200000\n#define USER_ALL_COUNTRYCODE 0x00400000\n#define USER_ALL_CODEPAGE 0x00800000\n#define USER_ALL_NTPASSWORDPRESENT 0x01000000 // field AND boolean\n#define USER_ALL_LMPASSWORDPRESENT 0x02000000 // field AND boolean\n#define USER_ALL_PRIVATEDATA 0x04000000 // field AND boolean\n#define USER_ALL_PASSWORDEXPIRED 0x08000000\n#define USER_ALL_SECURITYDESCRIPTOR 0x10000000\n#define USER_ALL_OWFPASSWORD 0x20000000 // boolean\n\n#define USER_ALL_UNDEFINED_MASK 0xc0000000\n\n// Fields that require USER_READ_GENERAL access to read.\n\n#define USER_ALL_READ_GENERAL_MASK (USER_ALL_USERNAME | \\\n    USER_ALL_FULLNAME | \\\n    USER_ALL_USERID | \\\n    USER_ALL_PRIMARYGROUPID | \\\n    USER_ALL_ADMINCOMMENT | \\\n    USER_ALL_USERCOMMENT)\n\n// Fields that require USER_READ_LOGON access to read.\n\n#define USER_ALL_READ_LOGON_MASK (USER_ALL_HOMEDIRECTORY | \\\n    USER_ALL_HOMEDIRECTORYDRIVE | \\\n    USER_ALL_SCRIPTPATH | \\\n    USER_ALL_PROFILEPATH | \\\n    USER_ALL_WORKSTATIONS | \\\n    USER_ALL_LASTLOGON | \\\n    USER_ALL_LASTLOGOFF | \\\n    USER_ALL_LOGONHOURS | \\\n    USER_ALL_BADPASSWORDCOUNT | \\\n    USER_ALL_LOGONCOUNT | \\\n    USER_ALL_PASSWORDCANCHANGE | \\\n    USER_ALL_PASSWORDMUSTCHANGE)\n\n// Fields that require USER_READ_ACCOUNT access to read.\n\n#define USER_ALL_READ_ACCOUNT_MASK (USER_ALL_PASSWORDLASTSET | \\\n    USER_ALL_ACCOUNTEXPIRES | \\\n    USER_ALL_USERACCOUNTCONTROL | \\\n    USER_ALL_PARAMETERS)\n\n// Fields that require USER_READ_PREFERENCES access to read.\n\n#define USER_ALL_READ_PREFERENCES_MASK (USER_ALL_COUNTRYCODE | \\\n    USER_ALL_CODEPAGE)\n\n// Fields that can only be read by trusted clients.\n\n#define USER_ALL_READ_TRUSTED_MASK (USER_ALL_NTPASSWORDPRESENT | \\\n    USER_ALL_LMPASSWORDPRESENT | \\\n    USER_ALL_PASSWORDEXPIRED | \\\n    USER_ALL_SECURITYDESCRIPTOR | \\\n    USER_ALL_PRIVATEDATA)\n\n// Fields that can't be read.\n\n#define USER_ALL_READ_CANT_MASK USER_ALL_UNDEFINED_MASK\n\n// Fields that require USER_WRITE_ACCOUNT access to write.\n\n#define USER_ALL_WRITE_ACCOUNT_MASK (USER_ALL_USERNAME | \\\n    USER_ALL_FULLNAME | \\\n    USER_ALL_PRIMARYGROUPID | \\\n    USER_ALL_HOMEDIRECTORY | \\\n    USER_ALL_HOMEDIRECTORYDRIVE | \\\n    USER_ALL_SCRIPTPATH | \\\n    USER_ALL_PROFILEPATH | \\\n    USER_ALL_ADMINCOMMENT | \\\n    USER_ALL_WORKSTATIONS | \\\n    USER_ALL_LOGONHOURS | \\\n    USER_ALL_ACCOUNTEXPIRES | \\\n    USER_ALL_USERACCOUNTCONTROL | \\\n    USER_ALL_PARAMETERS)\n\n// Fields that require USER_WRITE_PREFERENCES access to write.\n\n#define USER_ALL_WRITE_PREFERENCES_MASK (USER_ALL_USERCOMMENT | \\\n    USER_ALL_COUNTRYCODE | \\\n    USER_ALL_CODEPAGE)\n\n// Fields that require USER_FORCE_PASSWORD_CHANGE access to write.\n//\n// Note that non-trusted clients only set the NT password as a\n// UNICODE string. The wrapper will convert it to an LM password,\n// OWF and encrypt both versions. Trusted clients can pass in OWF\n// versions of either or both.\n\n#define USER_ALL_WRITE_FORCE_PASSWORD_CHANGE_MASK \\\n    (USER_ALL_NTPASSWORDPRESENT | \\\n    USER_ALL_LMPASSWORDPRESENT | \\\n    USER_ALL_PASSWORDEXPIRED)\n\n// Fields that can only be written by trusted clients.\n\n#define USER_ALL_WRITE_TRUSTED_MASK (USER_ALL_LASTLOGON | \\\n    USER_ALL_LASTLOGOFF | \\\n    USER_ALL_BADPASSWORDCOUNT | \\\n    USER_ALL_LOGONCOUNT | \\\n    USER_ALL_PASSWORDLASTSET | \\\n    USER_ALL_SECURITYDESCRIPTOR | \\\n    USER_ALL_PRIVATEDATA)\n\n// Fields that can't be written.\n\n#define USER_ALL_WRITE_CANT_MASK (USER_ALL_USERID | \\\n    USER_ALL_PASSWORDCANCHANGE | \\\n    USER_ALL_PASSWORDMUSTCHANGE | \\\n    USER_ALL_UNDEFINED_MASK)\n\ntypedef struct _USER_GENERAL_INFORMATION\n{\n    UNICODE_STRING UserName;\n    UNICODE_STRING FullName;\n    ULONG PrimaryGroupId;\n    UNICODE_STRING AdminComment;\n    UNICODE_STRING UserComment;\n} USER_GENERAL_INFORMATION, *PUSER_GENERAL_INFORMATION;\n\ntypedef struct _USER_PREFERENCES_INFORMATION\n{\n    UNICODE_STRING UserComment;\n    UNICODE_STRING Reserved1;\n    USHORT CountryCode;\n    USHORT CodePage;\n} USER_PREFERENCES_INFORMATION, *PUSER_PREFERENCES_INFORMATION;\n\ntypedef struct _USER_PARAMETERS_INFORMATION\n{\n    UNICODE_STRING Parameters;\n} USER_PARAMETERS_INFORMATION, *PUSER_PARAMETERS_INFORMATION;\n\n#include <pshpack4.h>\ntypedef struct _USER_LOGON_INFORMATION\n{\n    UNICODE_STRING UserName;\n    UNICODE_STRING FullName;\n    ULONG UserId;\n    ULONG PrimaryGroupId;\n    UNICODE_STRING HomeDirectory;\n    UNICODE_STRING HomeDirectoryDrive;\n    UNICODE_STRING ScriptPath;\n    UNICODE_STRING ProfilePath;\n    UNICODE_STRING WorkStations;\n    LARGE_INTEGER LastLogon;\n    LARGE_INTEGER LastLogoff;\n    LARGE_INTEGER PasswordLastSet;\n    LARGE_INTEGER PasswordCanChange;\n    LARGE_INTEGER PasswordMustChange;\n    LOGON_HOURS LogonHours;\n    USHORT BadPasswordCount;\n    USHORT LogonCount;\n    ULONG UserAccountControl;\n} USER_LOGON_INFORMATION, *PUSER_LOGON_INFORMATION;\n#include <poppack.h>\n\n#include <pshpack4.h>\ntypedef struct _USER_ACCOUNT_INFORMATION\n{\n    UNICODE_STRING UserName;\n    UNICODE_STRING FullName;\n    ULONG UserId;\n    ULONG PrimaryGroupId;\n    UNICODE_STRING HomeDirectory;\n    UNICODE_STRING HomeDirectoryDrive;\n    UNICODE_STRING ScriptPath;\n    UNICODE_STRING ProfilePath;\n    UNICODE_STRING AdminComment;\n    UNICODE_STRING WorkStations;\n    LARGE_INTEGER LastLogon;\n    LARGE_INTEGER LastLogoff;\n    LOGON_HOURS LogonHours;\n    USHORT BadPasswordCount;\n    USHORT LogonCount;\n    LARGE_INTEGER PasswordLastSet;\n    LARGE_INTEGER AccountExpires;\n    ULONG UserAccountControl;\n} USER_ACCOUNT_INFORMATION, *PUSER_ACCOUNT_INFORMATION;\n#include <poppack.h>\n\ntypedef struct _USER_ACCOUNT_NAME_INFORMATION\n{\n    UNICODE_STRING UserName;\n} USER_ACCOUNT_NAME_INFORMATION, *PUSER_ACCOUNT_NAME_INFORMATION;\n\ntypedef struct _USER_FULL_NAME_INFORMATION\n{\n    UNICODE_STRING FullName;\n} USER_FULL_NAME_INFORMATION, *PUSER_FULL_NAME_INFORMATION;\n\ntypedef struct _USER_NAME_INFORMATION\n{\n    UNICODE_STRING UserName;\n    UNICODE_STRING FullName;\n} USER_NAME_INFORMATION, *PUSER_NAME_INFORMATION;\n\ntypedef struct _USER_PRIMARY_GROUP_INFORMATION\n{\n    ULONG PrimaryGroupId;\n} USER_PRIMARY_GROUP_INFORMATION, *PUSER_PRIMARY_GROUP_INFORMATION;\n\ntypedef struct _USER_HOME_INFORMATION\n{\n    UNICODE_STRING HomeDirectory;\n    UNICODE_STRING HomeDirectoryDrive;\n} USER_HOME_INFORMATION, *PUSER_HOME_INFORMATION;\n\ntypedef struct _USER_SCRIPT_INFORMATION\n{\n    UNICODE_STRING ScriptPath;\n} USER_SCRIPT_INFORMATION, *PUSER_SCRIPT_INFORMATION;\n\ntypedef struct _USER_PROFILE_INFORMATION\n{\n    UNICODE_STRING ProfilePath;\n} USER_PROFILE_INFORMATION, *PUSER_PROFILE_INFORMATION;\n\ntypedef struct _USER_ADMIN_COMMENT_INFORMATION\n{\n    UNICODE_STRING AdminComment;\n} USER_ADMIN_COMMENT_INFORMATION, *PUSER_ADMIN_COMMENT_INFORMATION;\n\ntypedef struct _USER_WORKSTATIONS_INFORMATION\n{\n    UNICODE_STRING WorkStations;\n} USER_WORKSTATIONS_INFORMATION, *PUSER_WORKSTATIONS_INFORMATION;\n\ntypedef struct _USER_SET_PASSWORD_INFORMATION\n{\n    UNICODE_STRING Password;\n    BOOLEAN PasswordExpired;\n} USER_SET_PASSWORD_INFORMATION, *PUSER_SET_PASSWORD_INFORMATION;\n\ntypedef struct _USER_CONTROL_INFORMATION\n{\n    ULONG UserAccountControl;\n} USER_CONTROL_INFORMATION, *PUSER_CONTROL_INFORMATION;\n\ntypedef struct _USER_EXPIRES_INFORMATION\n{\n    LARGE_INTEGER AccountExpires;\n} USER_EXPIRES_INFORMATION, *PUSER_EXPIRES_INFORMATION;\n\ntypedef struct _USER_LOGON_HOURS_INFORMATION\n{\n    LOGON_HOURS LogonHours;\n} USER_LOGON_HOURS_INFORMATION, *PUSER_LOGON_HOURS_INFORMATION;\n\ntypedef SAM_BYTE_ARRAY_32K SAM_USER_TILE, *PSAM_USER_TILE;\n\n// 0xff000fff is reserved for internal callers and implementation.\n\n#define USER_EXTENDED_FIELD_USER_TILE (0x00001000L)\n#define USER_EXTENDED_FIELD_PASSWORD_HINT (0x00002000L)\n#define USER_EXTENDED_FIELD_DONT_SHOW_IN_LOGON_UI (0x00004000L)\n#define USER_EXTENDED_FIELD_SHELL_ADMIN_OBJECT_PROPERTIES (0x00008000L)\n\ntypedef struct _USER_EXTENDED_INFORMATION\n{\n    ULONG ExtendedWhichFields;\n    SAM_USER_TILE UserTile;\n    UNICODE_STRING PasswordHint;\n    BOOLEAN DontShowInLogonUI;\n    SAM_SHELL_OBJECT_PROPERTIES ShellAdminObjectProperties;\n} USER_EXTENDED_INFORMATION, *PUSER_EXTENDED_INFORMATION;\n\n// For local callers only.\ntypedef struct _USER_LOGON_UI_INFORMATION\n{\n    BOOLEAN PasswordIsBlank;\n    BOOLEAN AccountIsDisabled;\n} USER_LOGON_UI_INFORMATION, *PUSER_LOGON_UI_INFORMATION;\n\n// SamChangePasswordUser3 types\n\n// Error values:\n// * SAM_PWD_CHANGE_NO_ERROR\n// * SAM_PWD_CHANGE_PASSWORD_TOO_SHORT\n// * SAM_PWD_CHANGE_PWD_IN_HISTORY\n// * SAM_PWD_CHANGE_USERNAME_IN_PASSWORD\n// * SAM_PWD_CHANGE_FULLNAME_IN_PASSWORD\n// * SAM_PWD_CHANGE_MACHINE_PASSWORD_NOT_DEFAULT\n// * SAM_PWD_CHANGE_FAILED_BY_FILTER\n\ntypedef struct _USER_PWD_CHANGE_FAILURE_INFORMATION\n{\n    ULONG ExtendedFailureReason;\n    UNICODE_STRING FilterModuleName;\n} USER_PWD_CHANGE_FAILURE_INFORMATION,*PUSER_PWD_CHANGE_FAILURE_INFORMATION;\n\n// ExtendedFailureReason values\n\n#define SAM_PWD_CHANGE_NO_ERROR 0\n#define SAM_PWD_CHANGE_PASSWORD_TOO_SHORT 1\n#define SAM_PWD_CHANGE_PWD_IN_HISTORY 2\n#define SAM_PWD_CHANGE_USERNAME_IN_PASSWORD 3\n#define SAM_PWD_CHANGE_FULLNAME_IN_PASSWORD 4\n#define SAM_PWD_CHANGE_NOT_COMPLEX 5\n#define SAM_PWD_CHANGE_MACHINE_PASSWORD_NOT_DEFAULT 6\n#define SAM_PWD_CHANGE_FAILED_BY_FILTER 7\n#define SAM_PWD_CHANGE_PASSWORD_TOO_LONG 8\n#define SAM_PWD_CHANGE_FAILURE_REASON_MAX 8\n\n// Functions\n\n_Check_return_\nNTSTATUS\nNTAPI\nSamEnumerateUsersInDomain(\n    _In_ SAM_HANDLE DomainHandle,\n    _Inout_ PSAM_ENUMERATE_HANDLE EnumerationContext,\n    _In_ ULONG UserAccountControl,\n    _Outptr_ PVOID *Buffer, // PSAM_RID_ENUMERATION *\n    _In_ ULONG PreferedMaximumLength,\n    _Out_ PULONG CountReturned\n    );\n\n_Check_return_\nNTSTATUS\nNTAPI\nSamCreateUserInDomain(\n    _In_ SAM_HANDLE DomainHandle,\n    _In_ PUNICODE_STRING AccountName,\n    _In_ ACCESS_MASK DesiredAccess,\n    _Out_ PSAM_HANDLE UserHandle,\n    _Out_ PULONG RelativeId\n    );\n\n_Check_return_\nNTSTATUS\nNTAPI\nSamCreateUser2InDomain(\n    _In_ SAM_HANDLE DomainHandle,\n    _In_ PUNICODE_STRING AccountName,\n    _In_ ULONG AccountType,\n    _In_ ACCESS_MASK DesiredAccess,\n    _Out_ PSAM_HANDLE UserHandle,\n    _Out_ PULONG GrantedAccess,\n    _Out_ PULONG RelativeId\n    );\n\n_Check_return_\nNTSTATUS\nNTAPI\nSamOpenUser(\n    _In_ SAM_HANDLE DomainHandle,\n    _In_ ACCESS_MASK DesiredAccess,\n    _In_ ULONG UserId,\n    _Out_ PSAM_HANDLE UserHandle\n    );\n\n_Check_return_\nNTSTATUS\nNTAPI\nSamDeleteUser(\n    _In_ SAM_HANDLE UserHandle\n    );\n\n_Check_return_\nNTSTATUS\nNTAPI\nSamQueryInformationUser(\n    _In_ SAM_HANDLE UserHandle,\n    _In_ USER_INFORMATION_CLASS UserInformationClass,\n    _Outptr_ PVOID *Buffer\n    );\n\n_Check_return_\nNTSTATUS\nNTAPI\nSamSetInformationUser(\n    _In_ SAM_HANDLE UserHandle,\n    _In_ USER_INFORMATION_CLASS UserInformationClass,\n    _In_ PVOID Buffer\n    );\n\n_Check_return_\nNTSTATUS\nNTAPI\nSamGetGroupsForUser(\n    _In_ SAM_HANDLE UserHandle,\n    _Out_ _Deref_post_count_(*MembershipCount) PGROUP_MEMBERSHIP *Groups,\n    _Out_ PULONG MembershipCount\n    );\n\n_Check_return_\nNTSTATUS\nNTAPI\nSamChangePasswordUser(\n    _In_ SAM_HANDLE UserHandle,\n    _In_ PUNICODE_STRING OldPassword,\n    _In_ PUNICODE_STRING NewPassword\n    );\n\n_Check_return_\nNTSTATUS\nNTAPI\nSamChangePasswordUser2(\n    _In_ PUNICODE_STRING ServerName,\n    _In_ PUNICODE_STRING UserName,\n    _In_ PUNICODE_STRING OldPassword,\n    _In_ PUNICODE_STRING NewPassword\n    );\n\n_Check_return_\nNTSTATUS\nNTAPI\nSamChangePasswordUser3(\n    _In_ PUNICODE_STRING ServerName,\n    _In_ PUNICODE_STRING UserName,\n    _In_ PUNICODE_STRING OldPassword,\n    _In_ PUNICODE_STRING NewPassword,\n    _Outptr_ PDOMAIN_PASSWORD_INFORMATION *EffectivePasswordPolicy,\n    _Outptr_ PUSER_PWD_CHANGE_FAILURE_INFORMATION *PasswordChangeFailureInfo\n    );\n\n_Check_return_\nNTSTATUS\nNTAPI\nSamQueryDisplayInformation(\n    _In_ SAM_HANDLE DomainHandle,\n    _In_ DOMAIN_DISPLAY_INFORMATION DisplayInformation,\n    _In_ ULONG Index,\n    _In_ ULONG EntryCount,\n    _In_ ULONG PreferredMaximumLength,\n    _In_ PULONG TotalAvailable,\n    _Out_ PULONG TotalReturned,\n    _Out_ PULONG ReturnedEntryCount,\n    _Outptr_ PVOID *SortedBuffer\n    );\n\n_Check_return_\nNTSTATUS\nNTAPI\nSamGetDisplayEnumerationIndex(\n    _In_ SAM_HANDLE DomainHandle,\n    _In_ DOMAIN_DISPLAY_INFORMATION DisplayInformation,\n    _In_ PUNICODE_STRING Prefix,\n    _Out_ PULONG Index\n    );\n\n// Database replication\n\ntypedef enum _SECURITY_DB_DELTA_TYPE\n{\n    SecurityDbNew = 1,\n    SecurityDbRename,\n    SecurityDbDelete,\n    SecurityDbChangeMemberAdd,\n    SecurityDbChangeMemberSet,\n    SecurityDbChangeMemberDel,\n    SecurityDbChange,\n    SecurityDbChangePassword\n} SECURITY_DB_DELTA_TYPE, *PSECURITY_DB_DELTA_TYPE;\n\ntypedef enum _SECURITY_DB_OBJECT_TYPE\n{\n    SecurityDbObjectSamDomain = 1,\n    SecurityDbObjectSamUser,\n    SecurityDbObjectSamGroup,\n    SecurityDbObjectSamAlias,\n    SecurityDbObjectLsaPolicy,\n    SecurityDbObjectLsaTDomain,\n    SecurityDbObjectLsaAccount,\n    SecurityDbObjectLsaSecret\n} SECURITY_DB_OBJECT_TYPE, *PSECURITY_DB_OBJECT_TYPE;\n\ntypedef enum _SAM_ACCOUNT_TYPE\n{\n    SamObjectUser = 1,\n    SamObjectGroup,\n    SamObjectAlias\n} SAM_ACCOUNT_TYPE, *PSAM_ACCOUNT_TYPE;\n\n#define SAM_USER_ACCOUNT (0x00000001)\n#define SAM_GLOBAL_GROUP_ACCOUNT (0x00000002)\n#define SAM_LOCAL_GROUP_ACCOUNT (0x00000004)\n\ntypedef struct _SAM_GROUP_MEMBER_ID\n{\n    ULONG MemberRid;\n} SAM_GROUP_MEMBER_ID, *PSAM_GROUP_MEMBER_ID;\n\ntypedef struct _SAM_ALIAS_MEMBER_ID\n{\n    PSID MemberSid;\n} SAM_ALIAS_MEMBER_ID, *PSAM_ALIAS_MEMBER_ID;\n\ntypedef union _SAM_DELTA_DATA\n{\n    SAM_GROUP_MEMBER_ID GroupMemberId;\n    SAM_ALIAS_MEMBER_ID AliasMemberId;\n    ULONG AccountControl;\n} SAM_DELTA_DATA, *PSAM_DELTA_DATA;\n\ntypedef NTSTATUS (NTAPI *PSAM_DELTA_NOTIFICATION_ROUTINE)(\n    _In_ PSID DomainSid,\n    _In_ SECURITY_DB_DELTA_TYPE DeltaType,\n    _In_ SECURITY_DB_OBJECT_TYPE ObjectType,\n    _In_ ULONG ObjectRid,\n    _In_opt_ PUNICODE_STRING ObjectName,\n    _In_ PLARGE_INTEGER ModifiedCount,\n    _In_opt_ PSAM_DELTA_DATA DeltaData\n    );\n\n#define SAM_DELTA_NOTIFY_ROUTINE \"DeltaNotify\"\n\n_Check_return_\nNTSTATUS\nNTAPI\nSamRegisterObjectChangeNotification(\n    _In_ SECURITY_DB_OBJECT_TYPE ObjectType,\n    _In_ HANDLE NotificationEventHandle\n    );\n\nNTSTATUS\nNTAPI\nSamUnregisterObjectChangeNotification(\n    _In_ SECURITY_DB_OBJECT_TYPE ObjectType,\n    _In_ HANDLE NotificationEventHandle\n    );\n\n// Compatibility mode\n\n#define SAM_SID_COMPATIBILITY_ALL 0\n#define SAM_SID_COMPATIBILITY_LAX 1\n#define SAM_SID_COMPATIBILITY_STRICT 2\n\n_Check_return_\nNTSTATUS\nNTAPI\nSamGetCompatibilityMode(\n    _In_ SAM_HANDLE ObjectHandle,\n    _Out_ ULONG *Mode\n    );\n\n// Password validation\n\ntypedef enum _PASSWORD_POLICY_VALIDATION_TYPE\n{\n    SamValidateAuthentication = 1,\n    SamValidatePasswordChange,\n    SamValidatePasswordReset\n} PASSWORD_POLICY_VALIDATION_TYPE;\n\ntypedef struct _SAM_VALIDATE_PASSWORD_HASH\n{\n    ULONG Length;\n    _Field_size_bytes_(Length) PUCHAR Hash;\n} SAM_VALIDATE_PASSWORD_HASH, *PSAM_VALIDATE_PASSWORD_HASH;\n\n// Flags for PresentFields in SAM_VALIDATE_PERSISTED_FIELDS\n\n#define SAM_VALIDATE_PASSWORD_LAST_SET 0x00000001\n#define SAM_VALIDATE_BAD_PASSWORD_TIME 0x00000002\n#define SAM_VALIDATE_LOCKOUT_TIME 0x00000004\n#define SAM_VALIDATE_BAD_PASSWORD_COUNT 0x00000008\n#define SAM_VALIDATE_PASSWORD_HISTORY_LENGTH 0x00000010\n#define SAM_VALIDATE_PASSWORD_HISTORY 0x00000020\n\ntypedef struct _SAM_VALIDATE_PERSISTED_FIELDS\n{\n    ULONG PresentFields;\n    LARGE_INTEGER PasswordLastSet;\n    LARGE_INTEGER BadPasswordTime;\n    LARGE_INTEGER LockoutTime;\n    ULONG BadPasswordCount;\n    ULONG PasswordHistoryLength;\n    _Field_size_bytes_(PasswordHistoryLength) PSAM_VALIDATE_PASSWORD_HASH PasswordHistory;\n} SAM_VALIDATE_PERSISTED_FIELDS, *PSAM_VALIDATE_PERSISTED_FIELDS;\n\ntypedef enum _SAM_VALIDATE_VALIDATION_STATUS\n{\n    SamValidateSuccess = 0,\n    SamValidatePasswordMustChange,\n    SamValidateAccountLockedOut,\n    SamValidatePasswordExpired,\n    SamValidatePasswordIncorrect,\n    SamValidatePasswordIsInHistory,\n    SamValidatePasswordTooShort,\n    SamValidatePasswordTooLong,\n    SamValidatePasswordNotComplexEnough,\n    SamValidatePasswordTooRecent,\n    SamValidatePasswordFilterError\n} SAM_VALIDATE_VALIDATION_STATUS, *PSAM_VALIDATE_VALIDATION_STATUS;\n\ntypedef struct _SAM_VALIDATE_STANDARD_OUTPUT_ARG\n{\n    SAM_VALIDATE_PERSISTED_FIELDS ChangedPersistedFields;\n    SAM_VALIDATE_VALIDATION_STATUS ValidationStatus;\n} SAM_VALIDATE_STANDARD_OUTPUT_ARG, *PSAM_VALIDATE_STANDARD_OUTPUT_ARG;\n\ntypedef struct _SAM_VALIDATE_AUTHENTICATION_INPUT_ARG\n{\n    SAM_VALIDATE_PERSISTED_FIELDS InputPersistedFields;\n    BOOLEAN PasswordMatched;\n} SAM_VALIDATE_AUTHENTICATION_INPUT_ARG, *PSAM_VALIDATE_AUTHENTICATION_INPUT_ARG;\n\ntypedef struct _SAM_VALIDATE_PASSWORD_CHANGE_INPUT_ARG\n{\n    SAM_VALIDATE_PERSISTED_FIELDS InputPersistedFields;\n    UNICODE_STRING ClearPassword;\n    UNICODE_STRING UserAccountName;\n    SAM_VALIDATE_PASSWORD_HASH HashedPassword;\n    BOOLEAN PasswordMatch; // denotes if the old password supplied by user matched or not\n} SAM_VALIDATE_PASSWORD_CHANGE_INPUT_ARG, *PSAM_VALIDATE_PASSWORD_CHANGE_INPUT_ARG;\n\ntypedef struct _SAM_VALIDATE_PASSWORD_RESET_INPUT_ARG\n{\n    SAM_VALIDATE_PERSISTED_FIELDS InputPersistedFields;\n    UNICODE_STRING ClearPassword;\n    UNICODE_STRING UserAccountName;\n    SAM_VALIDATE_PASSWORD_HASH HashedPassword;\n    BOOLEAN PasswordMustChangeAtNextLogon; // looked at only for password reset\n    BOOLEAN ClearLockout; // can be used clear user account lockout\n}SAM_VALIDATE_PASSWORD_RESET_INPUT_ARG, *PSAM_VALIDATE_PASSWORD_RESET_INPUT_ARG;\n\ntypedef union _SAM_VALIDATE_INPUT_ARG\n{\n    SAM_VALIDATE_AUTHENTICATION_INPUT_ARG ValidateAuthenticationInput;\n    SAM_VALIDATE_PASSWORD_CHANGE_INPUT_ARG ValidatePasswordChangeInput;\n    SAM_VALIDATE_PASSWORD_RESET_INPUT_ARG ValidatePasswordResetInput;\n} SAM_VALIDATE_INPUT_ARG, *PSAM_VALIDATE_INPUT_ARG;\n\ntypedef union _SAM_VALIDATE_OUTPUT_ARG\n{\n    SAM_VALIDATE_STANDARD_OUTPUT_ARG ValidateAuthenticationOutput;\n    SAM_VALIDATE_STANDARD_OUTPUT_ARG ValidatePasswordChangeOutput;\n    SAM_VALIDATE_STANDARD_OUTPUT_ARG ValidatePasswordResetOutput;\n} SAM_VALIDATE_OUTPUT_ARG, *PSAM_VALIDATE_OUTPUT_ARG;\n\n_Check_return_\nNTSTATUS\nNTAPI\nSamValidatePassword(\n    _In_opt_ PUNICODE_STRING ServerName,\n    _In_ PASSWORD_POLICY_VALIDATION_TYPE ValidationType,\n    _In_ PSAM_VALIDATE_INPUT_ARG InputArg,\n    _Out_ PSAM_VALIDATE_OUTPUT_ARG *OutputArg\n    );\n\n// Generic operation\n\ntypedef enum _SAM_GENERIC_OPERATION_TYPE\n{\n    SamObjectChangeNotificationOperation\n} SAM_GENERIC_OPERATION_TYPE, *PSAM_GENERIC_OPERATION_TYPE;\n\ntypedef struct _SAM_OPERATION_OBJCHG_INPUT\n{\n    BOOLEAN Register;\n    ULONG64 EventHandle;\n    SECURITY_DB_OBJECT_TYPE ObjectType;\n    ULONG ProcessID;\n} SAM_OPERATION_OBJCHG_INPUT, *PSAM_OPERATION_OBJCHG_INPUT;\n\ntypedef struct _SAM_OPERATION_OBJCHG_OUTPUT\n{\n    ULONG Reserved;\n} SAM_OPERATION_OBJCHG_OUTPUT, *PSAM_OPERATION_OBJCHG_OUTPUT;\n\ntypedef union _SAM_GENERIC_OPERATION_INPUT\n{\n    SAM_OPERATION_OBJCHG_INPUT ObjChangeIn;\n} SAM_GENERIC_OPERATION_INPUT, *PSAM_GENERIC_OPERATION_INPUT;\n\ntypedef union _SAM_GENERIC_OPERATION_OUTPUT\n{\n    SAM_OPERATION_OBJCHG_OUTPUT ObjChangeOut;\n} SAM_GENERIC_OPERATION_OUTPUT, *PSAM_GENERIC_OPERATION_OUTPUT;\n\n_Check_return_\nNTSTATUS\nNTAPI\nSamPerformGenericOperation(\n    _In_opt_ PWSTR ServerName,\n    _In_ SAM_GENERIC_OPERATION_TYPE OperationType,\n    _In_ PSAM_GENERIC_OPERATION_INPUT OperationIn,\n    _Out_ PSAM_GENERIC_OPERATION_OUTPUT *OperationOut\n    );\n\n#endif\n"
  },
  {
    "path": "third_party/phnt/include/ntseapi.h",
    "content": "#ifndef _NTSEAPI_H\n#define _NTSEAPI_H\n\n// Privileges\n\n#define SE_MIN_WELL_KNOWN_PRIVILEGE (2L)\n#define SE_CREATE_TOKEN_PRIVILEGE (2L)\n#define SE_ASSIGNPRIMARYTOKEN_PRIVILEGE (3L)\n#define SE_LOCK_MEMORY_PRIVILEGE (4L)\n#define SE_INCREASE_QUOTA_PRIVILEGE (5L)\n\n#define SE_MACHINE_ACCOUNT_PRIVILEGE (6L)\n#define SE_TCB_PRIVILEGE (7L)\n#define SE_SECURITY_PRIVILEGE (8L)\n#define SE_TAKE_OWNERSHIP_PRIVILEGE (9L)\n#define SE_LOAD_DRIVER_PRIVILEGE (10L)\n#define SE_SYSTEM_PROFILE_PRIVILEGE (11L)\n#define SE_SYSTEMTIME_PRIVILEGE (12L)\n#define SE_PROF_SINGLE_PROCESS_PRIVILEGE (13L)\n#define SE_INC_BASE_PRIORITY_PRIVILEGE (14L)\n#define SE_CREATE_PAGEFILE_PRIVILEGE (15L)\n#define SE_CREATE_PERMANENT_PRIVILEGE (16L)\n#define SE_BACKUP_PRIVILEGE (17L)\n#define SE_RESTORE_PRIVILEGE (18L)\n#define SE_SHUTDOWN_PRIVILEGE (19L)\n#define SE_DEBUG_PRIVILEGE (20L)\n#define SE_AUDIT_PRIVILEGE (21L)\n#define SE_SYSTEM_ENVIRONMENT_PRIVILEGE (22L)\n#define SE_CHANGE_NOTIFY_PRIVILEGE (23L)\n#define SE_REMOTE_SHUTDOWN_PRIVILEGE (24L)\n#define SE_UNDOCK_PRIVILEGE (25L)\n#define SE_SYNC_AGENT_PRIVILEGE (26L)\n#define SE_ENABLE_DELEGATION_PRIVILEGE (27L)\n#define SE_MANAGE_VOLUME_PRIVILEGE (28L)\n#define SE_IMPERSONATE_PRIVILEGE (29L)\n#define SE_CREATE_GLOBAL_PRIVILEGE (30L)\n#define SE_TRUSTED_CREDMAN_ACCESS_PRIVILEGE (31L)\n#define SE_RELABEL_PRIVILEGE (32L)\n#define SE_INC_WORKING_SET_PRIVILEGE (33L)\n#define SE_TIME_ZONE_PRIVILEGE (34L)\n#define SE_CREATE_SYMBOLIC_LINK_PRIVILEGE (35L)\n#define SE_MAX_WELL_KNOWN_PRIVILEGE SE_CREATE_SYMBOLIC_LINK_PRIVILEGE\n\n\n// Authz\n\n// begin_rev\n\n// Types\n\n#define TOKEN_SECURITY_ATTRIBUTE_TYPE_INVALID 0x00\n#define TOKEN_SECURITY_ATTRIBUTE_TYPE_INT64 0x01\n#define TOKEN_SECURITY_ATTRIBUTE_TYPE_UINT64 0x02\n#define TOKEN_SECURITY_ATTRIBUTE_TYPE_STRING 0x03\n#define TOKEN_SECURITY_ATTRIBUTE_TYPE_FQBN 0x04\n#define TOKEN_SECURITY_ATTRIBUTE_TYPE_SID 0x05\n#define TOKEN_SECURITY_ATTRIBUTE_TYPE_BOOLEAN 0x06\n#define TOKEN_SECURITY_ATTRIBUTE_TYPE_OCTET_STRING 0x10\n\n// Flags\n\n#define TOKEN_SECURITY_ATTRIBUTE_NON_INHERITABLE 0x0001\n#define TOKEN_SECURITY_ATTRIBUTE_VALUE_CASE_SENSITIVE 0x0002\n#define TOKEN_SECURITY_ATTRIBUTE_USE_FOR_DENY_ONLY 0x0004\n#define TOKEN_SECURITY_ATTRIBUTE_DISABLED_BY_DEFAULT 0x0008\n#define TOKEN_SECURITY_ATTRIBUTE_DISABLED 0x0010\n#define TOKEN_SECURITY_ATTRIBUTE_MANDATORY 0x0020\n\n#define TOKEN_SECURITY_ATTRIBUTE_VALID_FLAGS ( \\\n    TOKEN_SECURITY_ATTRIBUTE_NON_INHERITABLE | \\\n    TOKEN_SECURITY_ATTRIBUTE_VALUE_CASE_SENSITIVE | \\\n    TOKEN_SECURITY_ATTRIBUTE_USE_FOR_DENY_ONLY | \\\n    TOKEN_SECURITY_ATTRIBUTE_DISABLED_BY_DEFAULT | \\\n    TOKEN_SECURITY_ATTRIBUTE_DISABLED | \\\n    TOKEN_SECURITY_ATTRIBUTE_MANDATORY)\n\n#define TOKEN_SECURITY_ATTRIBUTE_CUSTOM_FLAGS 0xffff0000\n\n// end_rev\n\n// private\ntypedef struct _TOKEN_SECURITY_ATTRIBUTE_FQBN_VALUE\n{\n    ULONG64 Version;\n    UNICODE_STRING Name;\n} TOKEN_SECURITY_ATTRIBUTE_FQBN_VALUE, *PTOKEN_SECURITY_ATTRIBUTE_FQBN_VALUE;\n\n// private\ntypedef struct _TOKEN_SECURITY_ATTRIBUTE_OCTET_STRING_VALUE\n{\n    PVOID pValue;\n    ULONG ValueLength;\n} TOKEN_SECURITY_ATTRIBUTE_OCTET_STRING_VALUE, *PTOKEN_SECURITY_ATTRIBUTE_OCTET_STRING_VALUE;\n\n// private\ntypedef struct _TOKEN_SECURITY_ATTRIBUTE_V1\n{\n    UNICODE_STRING Name;\n    USHORT ValueType;\n    USHORT Reserved;\n    ULONG Flags;\n    ULONG ValueCount;\n    union\n    {\n        PLONG64 pInt64;\n        PULONG64 pUint64;\n        PUNICODE_STRING pString;\n        PTOKEN_SECURITY_ATTRIBUTE_FQBN_VALUE pFqbn;\n        PTOKEN_SECURITY_ATTRIBUTE_OCTET_STRING_VALUE pOctetString;\n    } Values;\n} TOKEN_SECURITY_ATTRIBUTE_V1, *PTOKEN_SECURITY_ATTRIBUTE_V1;\n\n// rev\n#define TOKEN_SECURITY_ATTRIBUTES_INFORMATION_VERSION_V1 1\n// rev\n#define TOKEN_SECURITY_ATTRIBUTES_INFORMATION_VERSION TOKEN_SECURITY_ATTRIBUTES_INFORMATION_VERSION_V1\n\n// private\ntypedef struct _TOKEN_SECURITY_ATTRIBUTES_INFORMATION\n{\n    USHORT Version;\n    USHORT Reserved;\n    ULONG AttributeCount;\n    union\n    {\n        PTOKEN_SECURITY_ATTRIBUTE_V1 pAttributeV1;\n    } Attribute;\n} TOKEN_SECURITY_ATTRIBUTES_INFORMATION, *PTOKEN_SECURITY_ATTRIBUTES_INFORMATION;\n\n// Tokens\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtCreateToken(\n    _Out_ PHANDLE TokenHandle,\n    _In_ ACCESS_MASK DesiredAccess,\n    _In_opt_ POBJECT_ATTRIBUTES ObjectAttributes,\n    _In_ TOKEN_TYPE TokenType,\n    _In_ PLUID AuthenticationId,\n    _In_ PLARGE_INTEGER ExpirationTime,\n    _In_ PTOKEN_USER User,\n    _In_ PTOKEN_GROUPS Groups,\n    _In_ PTOKEN_PRIVILEGES Privileges,\n    _In_opt_ PTOKEN_OWNER Owner,\n    _In_ PTOKEN_PRIMARY_GROUP PrimaryGroup,\n    _In_opt_ PTOKEN_DEFAULT_DACL DefaultDacl,\n    _In_ PTOKEN_SOURCE TokenSource\n    );\n\n#if (PHNT_VERSION >= PHNT_WIN8)\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtCreateLowBoxToken(\n    _Out_ PHANDLE TokenHandle,\n    _In_ HANDLE ExistingTokenHandle,\n    _In_ ACCESS_MASK DesiredAccess,\n    _In_opt_ POBJECT_ATTRIBUTES ObjectAttributes,\n    _In_ PSID PackageSid,\n    _In_ ULONG CapabilityCount,\n    _In_reads_opt_(CapabilityCount) PSID_AND_ATTRIBUTES Capabilities,\n    _In_ ULONG HandleCount,\n    _In_reads_opt_(HandleCount) HANDLE *Handles\n    );\n#endif\n\n#if (PHNT_VERSION >= PHNT_WIN8)\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtCreateTokenEx(\n    _Out_ PHANDLE TokenHandle,\n    _In_ ACCESS_MASK DesiredAccess,\n    _In_opt_ POBJECT_ATTRIBUTES ObjectAttributes,\n    _In_ TOKEN_TYPE TokenType,\n    _In_ PLUID AuthenticationId,\n    _In_ PLARGE_INTEGER ExpirationTime,\n    _In_ PTOKEN_USER User,\n    _In_ PTOKEN_GROUPS Groups,\n    _In_ PTOKEN_PRIVILEGES Privileges,\n    _In_opt_ PTOKEN_SECURITY_ATTRIBUTES_INFORMATION UserAttributes,\n    _In_opt_ PTOKEN_SECURITY_ATTRIBUTES_INFORMATION DeviceAttributes,\n    _In_opt_ PTOKEN_GROUPS DeviceGroups,\n    _In_opt_ PTOKEN_MANDATORY_POLICY TokenMandatoryPolicy,\n    _In_opt_ PTOKEN_OWNER Owner,\n    _In_ PTOKEN_PRIMARY_GROUP PrimaryGroup,\n    _In_opt_ PTOKEN_DEFAULT_DACL DefaultDacl,\n    _In_ PTOKEN_SOURCE TokenSource\n    );\n#endif\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtOpenProcessToken(\n    _In_ HANDLE ProcessHandle,\n    _In_ ACCESS_MASK DesiredAccess,\n    _Out_ PHANDLE TokenHandle\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtOpenProcessTokenEx(\n    _In_ HANDLE ProcessHandle,\n    _In_ ACCESS_MASK DesiredAccess,\n    _In_ ULONG HandleAttributes,\n    _Out_ PHANDLE TokenHandle\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtOpenThreadToken(\n    _In_ HANDLE ThreadHandle,\n    _In_ ACCESS_MASK DesiredAccess,\n    _In_ BOOLEAN OpenAsSelf,\n    _Out_ PHANDLE TokenHandle\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtOpenThreadTokenEx(\n    _In_ HANDLE ThreadHandle,\n    _In_ ACCESS_MASK DesiredAccess,\n    _In_ BOOLEAN OpenAsSelf,\n    _In_ ULONG HandleAttributes,\n    _Out_ PHANDLE TokenHandle\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtDuplicateToken(\n    _In_ HANDLE ExistingTokenHandle,\n    _In_ ACCESS_MASK DesiredAccess,\n    _In_ POBJECT_ATTRIBUTES ObjectAttributes,\n    _In_ BOOLEAN EffectiveOnly,\n    _In_ TOKEN_TYPE TokenType,\n    _Out_ PHANDLE NewTokenHandle\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtQueryInformationToken(\n    _In_ HANDLE TokenHandle,\n    _In_ TOKEN_INFORMATION_CLASS TokenInformationClass,\n    _Out_writes_bytes_(TokenInformationLength) PVOID TokenInformation,\n    _In_ ULONG TokenInformationLength,\n    _Out_ PULONG ReturnLength\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtSetInformationToken(\n    _In_ HANDLE TokenHandle,\n    _In_ TOKEN_INFORMATION_CLASS TokenInformationClass,\n    _In_reads_bytes_(TokenInformationLength) PVOID TokenInformation,\n    _In_ ULONG TokenInformationLength\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtAdjustPrivilegesToken(\n    _In_ HANDLE TokenHandle,\n    _In_ BOOLEAN DisableAllPrivileges,\n    _In_opt_ PTOKEN_PRIVILEGES NewState,\n    _In_ ULONG BufferLength,\n    _Out_writes_bytes_to_opt_(BufferLength, *ReturnLength) PTOKEN_PRIVILEGES PreviousState,\n    _Out_ _When_(PreviousState == NULL, _Out_opt_) PULONG ReturnLength\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtAdjustGroupsToken(\n    _In_ HANDLE TokenHandle,\n    _In_ BOOLEAN ResetToDefault,\n    _In_opt_ PTOKEN_GROUPS NewState,\n    _In_opt_ ULONG BufferLength,\n    _Out_writes_bytes_to_opt_(BufferLength, *ReturnLength) PTOKEN_GROUPS PreviousState,\n    _Out_ PULONG ReturnLength\n    );\n\n#if (PHNT_VERSION >= PHNT_WIN8)\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtAdjustTokenClaimsAndDeviceGroups(\n    _In_ HANDLE TokenHandle,\n    _In_ BOOLEAN UserResetToDefault,\n    _In_ BOOLEAN DeviceResetToDefault,\n    _In_ BOOLEAN DeviceGroupsResetToDefault,\n    _In_opt_ PTOKEN_SECURITY_ATTRIBUTES_INFORMATION NewUserState,\n    _In_opt_ PTOKEN_SECURITY_ATTRIBUTES_INFORMATION NewDeviceState,\n    _In_opt_ PTOKEN_GROUPS NewDeviceGroupsState,\n    _In_ ULONG UserBufferLength,\n    _Out_writes_bytes_to_opt_(UserBufferLength, *UserReturnLength) PTOKEN_SECURITY_ATTRIBUTES_INFORMATION PreviousUserState,\n    _In_ ULONG DeviceBufferLength,\n    _Out_writes_bytes_to_opt_(DeviceBufferLength, *DeviceReturnLength) PTOKEN_SECURITY_ATTRIBUTES_INFORMATION PreviousDeviceState,\n    _In_ ULONG DeviceGroupsBufferLength,\n    _Out_writes_bytes_to_opt_(DeviceGroupsBufferLength, *DeviceGroupsReturnBufferLength) PTOKEN_GROUPS PreviousDeviceGroups,\n    _Out_opt_ PULONG UserReturnLength,\n    _Out_opt_ PULONG DeviceReturnLength,\n    _Out_opt_ PULONG DeviceGroupsReturnBufferLength\n    );\n#endif\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtFilterToken(\n    _In_ HANDLE ExistingTokenHandle,\n    _In_ ULONG Flags,\n    _In_opt_ PTOKEN_GROUPS SidsToDisable,\n    _In_opt_ PTOKEN_PRIVILEGES PrivilegesToDelete,\n    _In_opt_ PTOKEN_GROUPS RestrictedSids,\n    _Out_ PHANDLE NewTokenHandle\n    );\n\n#if (PHNT_VERSION >= PHNT_WIN8)\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtFilterTokenEx(\n    _In_ HANDLE ExistingTokenHandle,\n    _In_ ULONG Flags,\n    _In_opt_ PTOKEN_GROUPS SidsToDisable,\n    _In_opt_ PTOKEN_PRIVILEGES PrivilegesToDelete,\n    _In_opt_ PTOKEN_GROUPS RestrictedSids,\n    _In_ ULONG DisableUserClaimsCount,\n    _In_opt_ PUNICODE_STRING UserClaimsToDisable,\n    _In_ ULONG DisableDeviceClaimsCount,\n    _In_opt_ PUNICODE_STRING DeviceClaimsToDisable,\n    _In_opt_ PTOKEN_GROUPS DeviceGroupsToDisable,\n    _In_opt_ PTOKEN_SECURITY_ATTRIBUTES_INFORMATION RestrictedUserAttributes,\n    _In_opt_ PTOKEN_SECURITY_ATTRIBUTES_INFORMATION RestrictedDeviceAttributes,\n    _In_opt_ PTOKEN_GROUPS RestrictedDeviceGroups,\n    _Out_ PHANDLE NewTokenHandle\n    );\n#endif\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtCompareTokens(\n    _In_ HANDLE FirstTokenHandle,\n    _In_ HANDLE SecondTokenHandle,\n    _Out_ PBOOLEAN Equal\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtPrivilegeCheck(\n    _In_ HANDLE ClientToken,\n    _Inout_ PPRIVILEGE_SET RequiredPrivileges,\n    _Out_ PBOOLEAN Result\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtImpersonateAnonymousToken(\n    _In_ HANDLE ThreadHandle\n    );\n\n#if (PHNT_VERSION >= PHNT_WIN7)\n// rev\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtQuerySecurityAttributesToken(\n    _In_ HANDLE TokenHandle,\n    _In_reads_opt_(NumberOfAttributes) PUNICODE_STRING Attributes,\n    _In_ ULONG NumberOfAttributes,\n    _Out_writes_bytes_(Length) PVOID Buffer, // PTOKEN_SECURITY_ATTRIBUTES_INFORMATION\n    _In_ ULONG Length,\n    _Out_ PULONG ReturnLength\n    );\n#endif\n\n// Access checking\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtAccessCheck(\n    _In_ PSECURITY_DESCRIPTOR SecurityDescriptor,\n    _In_ HANDLE ClientToken,\n    _In_ ACCESS_MASK DesiredAccess,\n    _In_ PGENERIC_MAPPING GenericMapping,\n    _Out_writes_bytes_(*PrivilegeSetLength) PPRIVILEGE_SET PrivilegeSet,\n    _Inout_ PULONG PrivilegeSetLength,\n    _Out_ PACCESS_MASK GrantedAccess,\n    _Out_ PNTSTATUS AccessStatus\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtAccessCheckByType(\n    _In_ PSECURITY_DESCRIPTOR SecurityDescriptor,\n    _In_opt_ PSID PrincipalSelfSid,\n    _In_ HANDLE ClientToken,\n    _In_ ACCESS_MASK DesiredAccess,\n    _In_reads_(ObjectTypeListLength) POBJECT_TYPE_LIST ObjectTypeList,\n    _In_ ULONG ObjectTypeListLength,\n    _In_ PGENERIC_MAPPING GenericMapping,\n    _Out_writes_bytes_(*PrivilegeSetLength) PPRIVILEGE_SET PrivilegeSet,\n    _Inout_ PULONG PrivilegeSetLength,\n    _Out_ PACCESS_MASK GrantedAccess,\n    _Out_ PNTSTATUS AccessStatus\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtAccessCheckByTypeResultList(\n    _In_ PSECURITY_DESCRIPTOR SecurityDescriptor,\n    _In_opt_ PSID PrincipalSelfSid,\n    _In_ HANDLE ClientToken,\n    _In_ ACCESS_MASK DesiredAccess,\n    _In_reads_(ObjectTypeListLength) POBJECT_TYPE_LIST ObjectTypeList,\n    _In_ ULONG ObjectTypeListLength,\n    _In_ PGENERIC_MAPPING GenericMapping,\n    _Out_writes_bytes_(*PrivilegeSetLength) PPRIVILEGE_SET PrivilegeSet,\n    _Inout_ PULONG PrivilegeSetLength,\n    _Out_writes_(ObjectTypeListLength) PACCESS_MASK GrantedAccess,\n    _Out_writes_(ObjectTypeListLength) PNTSTATUS AccessStatus\n    );\n\n// Signing\n\n#if (PHNT_VERSION >= PHNT_THRESHOLD)\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtSetCachedSigningLevel(\n    _In_ ULONG Flags,\n    _In_ SE_SIGNING_LEVEL InputSigningLevel,\n    _In_reads_(SourceFileCount) PHANDLE SourceFiles,\n    _In_ ULONG SourceFileCount,\n    _In_opt_ HANDLE TargetFile\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtGetCachedSigningLevel(\n    _In_ HANDLE File,\n    _Out_ PULONG Flags,\n    _Out_ PSE_SIGNING_LEVEL SigningLevel,\n    _Out_writes_bytes_to_opt_(*ThumbprintSize, *ThumbprintSize) PUCHAR Thumbprint,\n    _Inout_opt_ PULONG ThumbprintSize,\n    _Out_opt_ PULONG ThumbprintAlgorithm\n    );\n\n#endif\n\n// Audit alarm\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtAccessCheckAndAuditAlarm(\n    _In_ PUNICODE_STRING SubsystemName,\n    _In_opt_ PVOID HandleId,\n    _In_ PUNICODE_STRING ObjectTypeName,\n    _In_ PUNICODE_STRING ObjectName,\n    _In_ PSECURITY_DESCRIPTOR SecurityDescriptor,\n    _In_ ACCESS_MASK DesiredAccess,\n    _In_ PGENERIC_MAPPING GenericMapping,\n    _In_ BOOLEAN ObjectCreation,\n    _Out_ PACCESS_MASK GrantedAccess,\n    _Out_ PNTSTATUS AccessStatus,\n    _Out_ PBOOLEAN GenerateOnClose\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtAccessCheckByTypeAndAuditAlarm(\n    _In_ PUNICODE_STRING SubsystemName,\n    _In_opt_ PVOID HandleId,\n    _In_ PUNICODE_STRING ObjectTypeName,\n    _In_ PUNICODE_STRING ObjectName,\n    _In_ PSECURITY_DESCRIPTOR SecurityDescriptor,\n    _In_opt_ PSID PrincipalSelfSid,\n    _In_ ACCESS_MASK DesiredAccess,\n    _In_ AUDIT_EVENT_TYPE AuditType,\n    _In_ ULONG Flags,\n    _In_reads_opt_(ObjectTypeListLength) POBJECT_TYPE_LIST ObjectTypeList,\n    _In_ ULONG ObjectTypeListLength,\n    _In_ PGENERIC_MAPPING GenericMapping,\n    _In_ BOOLEAN ObjectCreation,\n    _Out_ PACCESS_MASK GrantedAccess,\n    _Out_ PNTSTATUS AccessStatus,\n    _Out_ PBOOLEAN GenerateOnClose\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtAccessCheckByTypeResultListAndAuditAlarm(\n    _In_ PUNICODE_STRING SubsystemName,\n    _In_opt_ PVOID HandleId,\n    _In_ PUNICODE_STRING ObjectTypeName,\n    _In_ PUNICODE_STRING ObjectName,\n    _In_ PSECURITY_DESCRIPTOR SecurityDescriptor,\n    _In_opt_ PSID PrincipalSelfSid,\n    _In_ ACCESS_MASK DesiredAccess,\n    _In_ AUDIT_EVENT_TYPE AuditType,\n    _In_ ULONG Flags,\n    _In_reads_opt_(ObjectTypeListLength) POBJECT_TYPE_LIST ObjectTypeList,\n    _In_ ULONG ObjectTypeListLength,\n    _In_ PGENERIC_MAPPING GenericMapping,\n    _In_ BOOLEAN ObjectCreation,\n    _Out_writes_(ObjectTypeListLength) PACCESS_MASK GrantedAccess,\n    _Out_writes_(ObjectTypeListLength) PNTSTATUS AccessStatus,\n    _Out_ PBOOLEAN GenerateOnClose\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtAccessCheckByTypeResultListAndAuditAlarmByHandle(\n    _In_ PUNICODE_STRING SubsystemName,\n    _In_opt_ PVOID HandleId,\n    _In_ HANDLE ClientToken,\n    _In_ PUNICODE_STRING ObjectTypeName,\n    _In_ PUNICODE_STRING ObjectName,\n    _In_ PSECURITY_DESCRIPTOR SecurityDescriptor,\n    _In_opt_ PSID PrincipalSelfSid,\n    _In_ ACCESS_MASK DesiredAccess,\n    _In_ AUDIT_EVENT_TYPE AuditType,\n    _In_ ULONG Flags,\n    _In_reads_opt_(ObjectTypeListLength) POBJECT_TYPE_LIST ObjectTypeList,\n    _In_ ULONG ObjectTypeListLength,\n    _In_ PGENERIC_MAPPING GenericMapping,\n    _In_ BOOLEAN ObjectCreation,\n    _Out_writes_(ObjectTypeListLength) PACCESS_MASK GrantedAccess,\n    _Out_writes_(ObjectTypeListLength) PNTSTATUS AccessStatus,\n    _Out_ PBOOLEAN GenerateOnClose\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtOpenObjectAuditAlarm(\n    _In_ PUNICODE_STRING SubsystemName,\n    _In_opt_ PVOID HandleId,\n    _In_ PUNICODE_STRING ObjectTypeName,\n    _In_ PUNICODE_STRING ObjectName,\n    _In_opt_ PSECURITY_DESCRIPTOR SecurityDescriptor,\n    _In_ HANDLE ClientToken,\n    _In_ ACCESS_MASK DesiredAccess,\n    _In_ ACCESS_MASK GrantedAccess,\n    _In_opt_ PPRIVILEGE_SET Privileges,\n    _In_ BOOLEAN ObjectCreation,\n    _In_ BOOLEAN AccessGranted,\n    _Out_ PBOOLEAN GenerateOnClose\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtPrivilegeObjectAuditAlarm(\n    _In_ PUNICODE_STRING SubsystemName,\n    _In_opt_ PVOID HandleId,\n    _In_ HANDLE ClientToken,\n    _In_ ACCESS_MASK DesiredAccess,\n    _In_ PPRIVILEGE_SET Privileges,\n    _In_ BOOLEAN AccessGranted\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtCloseObjectAuditAlarm(\n    _In_ PUNICODE_STRING SubsystemName,\n    _In_opt_ PVOID HandleId,\n    _In_ BOOLEAN GenerateOnClose\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtDeleteObjectAuditAlarm(\n    _In_ PUNICODE_STRING SubsystemName,\n    _In_opt_ PVOID HandleId,\n    _In_ BOOLEAN GenerateOnClose\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtPrivilegedServiceAuditAlarm(\n    _In_ PUNICODE_STRING SubsystemName,\n    _In_ PUNICODE_STRING ServiceName,\n    _In_ HANDLE ClientToken,\n    _In_ PPRIVILEGE_SET Privileges,\n    _In_ BOOLEAN AccessGranted\n    );\n\n// Misc.\n\ntypedef enum _FILTER_BOOT_OPTION_OPERATION\n{\n    FilterBootOptionOperationOpenSystemStore,\n    FilterBootOptionOperationSetElement,\n    FilterBootOptionOperationDeleteElement,\n    FilterBootOptionOperationMax\n} FILTER_BOOT_OPTION_OPERATION;\n\n#if (PHNT_VERSION >= PHNT_THRESHOLD)\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtFilterBootOption(\n    _In_ FILTER_BOOT_OPTION_OPERATION FilterOperation,\n    _In_ ULONG ObjectType,\n    _In_ ULONG ElementType,\n    _In_reads_bytes_opt_(DataSize) PVOID Data,\n    _In_ ULONG DataSize\n    );\n#endif\n\n#endif\n"
  },
  {
    "path": "third_party/phnt/include/ntsmss.h",
    "content": "#ifndef _NTSMSS_H\n#define _NTSMSS_H\n\nNTSYSAPI\nNTSTATUS\nNTAPI\nRtlConnectToSm(\n    _In_ PUNICODE_STRING ApiPortName,\n    _In_ HANDLE ApiPortHandle,\n    _In_ DWORD ProcessImageType,\n    _Out_ PHANDLE SmssConnection\n    );\n\nNTSYSAPI\nNTSTATUS\nNTAPI\nRtlSendMsgToSm(\n    _In_ HANDLE ApiPortHandle,\n    _In_ PPORT_MESSAGE MessageData\n    );\n\n#endif\n"
  },
  {
    "path": "third_party/phnt/include/nttmapi.h",
    "content": "#ifndef _NTTMAPI_H\n#define _NTTMAPI_H\n\n#if (PHNT_VERSION >= PHNT_VISTA)\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtCreateTransactionManager(\n    _Out_ PHANDLE TmHandle,\n    _In_ ACCESS_MASK DesiredAccess,\n    _In_opt_ POBJECT_ATTRIBUTES ObjectAttributes,\n    _In_opt_ PUNICODE_STRING LogFileName,\n    _In_opt_ ULONG CreateOptions,\n    _In_opt_ ULONG CommitStrength\n    );\n#endif\n\n#if (PHNT_VERSION >= PHNT_VISTA)\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtOpenTransactionManager(\n    _Out_ PHANDLE TmHandle,\n    _In_ ACCESS_MASK DesiredAccess,\n    _In_opt_ POBJECT_ATTRIBUTES ObjectAttributes,\n    _In_opt_ PUNICODE_STRING LogFileName,\n    _In_opt_ LPGUID TmIdentity,\n    _In_opt_ ULONG OpenOptions\n    );\n#endif\n\n#if (PHNT_VERSION >= PHNT_VISTA)\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtRenameTransactionManager(\n    _In_ PUNICODE_STRING LogFileName,\n    _In_ LPGUID ExistingTransactionManagerGuid\n    );\n#endif\n\n#if (PHNT_VERSION >= PHNT_VISTA)\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtRollforwardTransactionManager(\n    _In_ HANDLE TransactionManagerHandle,\n    _In_opt_ PLARGE_INTEGER TmVirtualClock\n    );\n#endif\n\n#if (PHNT_VERSION >= PHNT_VISTA)\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtRecoverTransactionManager(\n    _In_ HANDLE TransactionManagerHandle\n    );\n#endif\n\n#if (PHNT_VERSION >= PHNT_VISTA)\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtQueryInformationTransactionManager(\n    _In_ HANDLE TransactionManagerHandle,\n    _In_ TRANSACTIONMANAGER_INFORMATION_CLASS TransactionManagerInformationClass,\n    _Out_writes_bytes_(TransactionManagerInformationLength) PVOID TransactionManagerInformation,\n    _In_ ULONG TransactionManagerInformationLength,\n    _Out_opt_ PULONG ReturnLength\n    );\n#endif\n\n#if (PHNT_VERSION >= PHNT_VISTA)\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtSetInformationTransactionManager(\n    _In_opt_ HANDLE TmHandle,\n    _In_ TRANSACTIONMANAGER_INFORMATION_CLASS TransactionManagerInformationClass,\n    _In_reads_bytes_(TransactionManagerInformationLength) PVOID TransactionManagerInformation,\n    _In_ ULONG TransactionManagerInformationLength\n    );\n#endif\n\n#if (PHNT_VERSION >= PHNT_VISTA)\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtEnumerateTransactionObject(\n    _In_opt_ HANDLE RootObjectHandle,\n    _In_ KTMOBJECT_TYPE QueryType,\n    _Inout_updates_bytes_(ObjectCursorLength) PKTMOBJECT_CURSOR ObjectCursor,\n    _In_ ULONG ObjectCursorLength,\n    _Out_ PULONG ReturnLength\n    );\n#endif\n\n#if (PHNT_VERSION >= PHNT_VISTA)\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtCreateTransaction(\n    _Out_ PHANDLE TransactionHandle,\n    _In_ ACCESS_MASK DesiredAccess,\n    _In_opt_ POBJECT_ATTRIBUTES ObjectAttributes,\n    _In_opt_ LPGUID Uow,\n    _In_opt_ HANDLE TmHandle,\n    _In_opt_ ULONG CreateOptions,\n    _In_opt_ ULONG IsolationLevel,\n    _In_opt_ ULONG IsolationFlags,\n    _In_opt_ PLARGE_INTEGER Timeout,\n    _In_opt_ PUNICODE_STRING Description\n    );\n#endif\n\n#if (PHNT_VERSION >= PHNT_VISTA)\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtOpenTransaction(\n    _Out_ PHANDLE TransactionHandle,\n    _In_ ACCESS_MASK DesiredAccess,\n    _In_ POBJECT_ATTRIBUTES ObjectAttributes,\n    _In_ LPGUID Uow,\n    _In_opt_ HANDLE TmHandle\n    );\n#endif\n\n#if (PHNT_VERSION >= PHNT_VISTA)\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtQueryInformationTransaction(\n    _In_ HANDLE TransactionHandle,\n    _In_ TRANSACTION_INFORMATION_CLASS TransactionInformationClass,\n    _Out_writes_bytes_(TransactionInformationLength) PVOID TransactionInformation,\n    _In_ ULONG TransactionInformationLength,\n    _Out_opt_ PULONG ReturnLength\n    );\n#endif\n\n#if (PHNT_VERSION >= PHNT_VISTA)\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtSetInformationTransaction(\n    _In_ HANDLE TransactionHandle,\n    _In_ TRANSACTION_INFORMATION_CLASS TransactionInformationClass,\n    _In_reads_bytes_(TransactionInformationLength) PVOID TransactionInformation,\n    _In_ ULONG TransactionInformationLength\n    );\n#endif\n\n#if (PHNT_VERSION >= PHNT_VISTA)\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtCommitTransaction(\n    _In_ HANDLE TransactionHandle,\n    _In_ BOOLEAN Wait\n    );\n#endif\n\n#if (PHNT_VERSION >= PHNT_VISTA)\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtRollbackTransaction(\n    _In_ HANDLE TransactionHandle,\n    _In_ BOOLEAN Wait\n    );\n#endif\n\n#if (PHNT_VERSION >= PHNT_VISTA)\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtCreateEnlistment(\n    _Out_ PHANDLE EnlistmentHandle,\n    _In_ ACCESS_MASK DesiredAccess,\n    _In_ HANDLE ResourceManagerHandle,\n    _In_ HANDLE TransactionHandle,\n    _In_opt_ POBJECT_ATTRIBUTES ObjectAttributes,\n    _In_opt_ ULONG CreateOptions,\n    _In_ NOTIFICATION_MASK NotificationMask,\n    _In_opt_ PVOID EnlistmentKey\n    );\n#endif\n\n#if (PHNT_VERSION >= PHNT_VISTA)\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtOpenEnlistment(\n    _Out_ PHANDLE EnlistmentHandle,\n    _In_ ACCESS_MASK DesiredAccess,\n    _In_ HANDLE ResourceManagerHandle,\n    _In_ LPGUID EnlistmentGuid,\n    _In_opt_ POBJECT_ATTRIBUTES ObjectAttributes\n    );\n#endif\n\n#if (PHNT_VERSION >= PHNT_VISTA)\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtQueryInformationEnlistment(\n    _In_ HANDLE EnlistmentHandle,\n    _In_ ENLISTMENT_INFORMATION_CLASS EnlistmentInformationClass,\n    _Out_writes_bytes_(EnlistmentInformationLength) PVOID EnlistmentInformation,\n    _In_ ULONG EnlistmentInformationLength,\n    _Out_opt_ PULONG ReturnLength\n    );\n#endif\n\n#if (PHNT_VERSION >= PHNT_VISTA)\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtSetInformationEnlistment(\n    _In_opt_ HANDLE EnlistmentHandle,\n    _In_ ENLISTMENT_INFORMATION_CLASS EnlistmentInformationClass,\n    _In_reads_bytes_(EnlistmentInformationLength) PVOID EnlistmentInformation,\n    _In_ ULONG EnlistmentInformationLength\n    );\n#endif\n\n#if (PHNT_VERSION >= PHNT_VISTA)\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtRecoverEnlistment(\n    _In_ HANDLE EnlistmentHandle,\n    _In_opt_ PVOID EnlistmentKey\n    );\n#endif\n\n#if (PHNT_VERSION >= PHNT_VISTA)\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtPrePrepareEnlistment(\n    _In_ HANDLE EnlistmentHandle,\n    _In_opt_ PLARGE_INTEGER TmVirtualClock\n    );\n#endif\n\n#if (PHNT_VERSION >= PHNT_VISTA)\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtPrepareEnlistment(\n    _In_ HANDLE EnlistmentHandle,\n    _In_opt_ PLARGE_INTEGER TmVirtualClock\n    );\n#endif\n\n#if (PHNT_VERSION >= PHNT_VISTA)\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtCommitEnlistment(\n    _In_ HANDLE EnlistmentHandle,\n    _In_opt_ PLARGE_INTEGER TmVirtualClock\n    );\n#endif\n\n#if (PHNT_VERSION >= PHNT_VISTA)\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtRollbackEnlistment(\n    _In_ HANDLE EnlistmentHandle,\n    _In_opt_ PLARGE_INTEGER TmVirtualClock\n    );\n#endif\n\n#if (PHNT_VERSION >= PHNT_VISTA)\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtPrePrepareComplete(\n    _In_ HANDLE EnlistmentHandle,\n    _In_opt_ PLARGE_INTEGER TmVirtualClock\n    );\n#endif\n\n#if (PHNT_VERSION >= PHNT_VISTA)\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtPrepareComplete(\n    _In_ HANDLE EnlistmentHandle,\n    _In_opt_ PLARGE_INTEGER TmVirtualClock\n    );\n#endif\n\n#if (PHNT_VERSION >= PHNT_VISTA)\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtCommitComplete(\n    _In_ HANDLE EnlistmentHandle,\n    _In_opt_ PLARGE_INTEGER TmVirtualClock\n    );\n#endif\n\n#if (PHNT_VERSION >= PHNT_VISTA)\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtReadOnlyEnlistment(\n    _In_ HANDLE EnlistmentHandle,\n    _In_opt_ PLARGE_INTEGER TmVirtualClock\n    );\n#endif\n\n#if (PHNT_VERSION >= PHNT_VISTA)\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtRollbackComplete(\n    _In_ HANDLE EnlistmentHandle,\n    _In_opt_ PLARGE_INTEGER TmVirtualClock\n    );\n#endif\n\n#if (PHNT_VERSION >= PHNT_VISTA)\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtSinglePhaseReject(\n    _In_ HANDLE EnlistmentHandle,\n    _In_opt_ PLARGE_INTEGER TmVirtualClock\n    );\n#endif\n\n#if (PHNT_VERSION >= PHNT_VISTA)\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtCreateResourceManager(\n    _Out_ PHANDLE ResourceManagerHandle,\n    _In_ ACCESS_MASK DesiredAccess,\n    _In_ HANDLE TmHandle,\n    _In_ LPGUID RmGuid,\n    _In_opt_ POBJECT_ATTRIBUTES ObjectAttributes,\n    _In_opt_ ULONG CreateOptions,\n    _In_opt_ PUNICODE_STRING Description\n    );\n#endif\n\n#if (PHNT_VERSION >= PHNT_VISTA)\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtOpenResourceManager(\n    _Out_ PHANDLE ResourceManagerHandle,\n    _In_ ACCESS_MASK DesiredAccess,\n    _In_ HANDLE TmHandle,\n    _In_opt_ LPGUID ResourceManagerGuid,\n    _In_opt_ POBJECT_ATTRIBUTES ObjectAttributes\n    );\n#endif\n\n#if (PHNT_VERSION >= PHNT_VISTA)\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtRecoverResourceManager(\n    _In_ HANDLE ResourceManagerHandle\n    );\n#endif\n\n#if (PHNT_VERSION >= PHNT_VISTA)\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtGetNotificationResourceManager(\n    _In_ HANDLE ResourceManagerHandle,\n    _Out_ PTRANSACTION_NOTIFICATION TransactionNotification,\n    _In_ ULONG NotificationLength,\n    _In_opt_ PLARGE_INTEGER Timeout,\n    _Out_opt_ PULONG ReturnLength,\n    _In_ ULONG Asynchronous,\n    _In_opt_ ULONG_PTR AsynchronousContext\n    );\n#endif\n\n#if (PHNT_VERSION >= PHNT_VISTA)\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtQueryInformationResourceManager(\n    _In_ HANDLE ResourceManagerHandle,\n    _In_ RESOURCEMANAGER_INFORMATION_CLASS ResourceManagerInformationClass,\n    _Out_writes_bytes_(ResourceManagerInformationLength) PVOID ResourceManagerInformation,\n    _In_ ULONG ResourceManagerInformationLength,\n    _Out_opt_ PULONG ReturnLength\n    );\n#endif\n\n#if (PHNT_VERSION >= PHNT_VISTA)\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtSetInformationResourceManager(\n    _In_ HANDLE ResourceManagerHandle,\n    _In_ RESOURCEMANAGER_INFORMATION_CLASS ResourceManagerInformationClass,\n    _In_reads_bytes_(ResourceManagerInformationLength) PVOID ResourceManagerInformation,\n    _In_ ULONG ResourceManagerInformationLength\n    );\n#endif\n\n#if (PHNT_VERSION >= PHNT_VISTA)\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtRegisterProtocolAddressInformation(\n    _In_ HANDLE ResourceManager,\n    _In_ PCRM_PROTOCOL_ID ProtocolId,\n    _In_ ULONG ProtocolInformationSize,\n    _In_ PVOID ProtocolInformation,\n    _In_opt_ ULONG CreateOptions\n    );\n#endif\n\n#if (PHNT_VERSION >= PHNT_VISTA)\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtPropagationComplete(\n    _In_ HANDLE ResourceManagerHandle,\n    _In_ ULONG RequestCookie,\n    _In_ ULONG BufferLength,\n    _In_ PVOID Buffer\n    );\n#endif\n\n#if (PHNT_VERSION >= PHNT_VISTA)\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtPropagationFailed(\n    _In_ HANDLE ResourceManagerHandle,\n    _In_ ULONG RequestCookie,\n    _In_ NTSTATUS PropStatus\n    );\n#endif\n\n#if (PHNT_VERSION >= PHNT_VISTA)\n// private\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtFreezeTransactions(\n    _In_ PLARGE_INTEGER FreezeTimeout,\n    _In_ PLARGE_INTEGER ThawTimeout\n    );\n#endif\n\n#if (PHNT_VERSION >= PHNT_VISTA)\n// private\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtThawTransactions(\n    VOID\n    );\n#endif\n\n#endif\n"
  },
  {
    "path": "third_party/phnt/include/nttp.h",
    "content": "#ifndef _NTTP_H\n#define _NTTP_H\n\n// Some types are already defined in winnt.h.\n\ntypedef struct _TP_ALPC TP_ALPC, *PTP_ALPC;\n\n// private\ntypedef VOID (NTAPI *PTP_ALPC_CALLBACK)(\n    _Inout_ PTP_CALLBACK_INSTANCE Instance,\n    _Inout_opt_ PVOID Context,\n    _In_ PTP_ALPC Alpc\n    );\n\n// rev\ntypedef VOID (NTAPI *PTP_ALPC_CALLBACK_EX)(\n    _Inout_ PTP_CALLBACK_INSTANCE Instance,\n    _Inout_opt_ PVOID Context,\n    _In_ PTP_ALPC Alpc,\n    _In_ PVOID ApcContext\n    );\n\n#if (PHNT_VERSION >= PHNT_VISTA)\n\n// private\n_Check_return_\nNTSYSAPI\nNTSTATUS\nNTAPI\nTpAllocPool(\n    _Out_ PTP_POOL *PoolReturn,\n    _Reserved_ PVOID Reserved\n    );\n\n// winbase:CloseThreadpool\nNTSYSAPI\nVOID\nNTAPI\nTpReleasePool(\n    _Inout_ PTP_POOL Pool\n    );\n\n// winbase:SetThreadpoolThreadMaximum\nNTSYSAPI\nVOID\nNTAPI\nTpSetPoolMaxThreads(\n    _Inout_ PTP_POOL Pool,\n    _In_ LONG MaxThreads\n    );\n\n// private\nNTSYSAPI\nNTSTATUS\nNTAPI\nTpSetPoolMinThreads(\n    _Inout_ PTP_POOL Pool,\n    _In_ LONG MinThreads\n    );\n\n#if (PHNT_VERSION >= PHNT_WIN7)\n// rev\nNTSYSAPI\nNTSTATUS\nNTAPI\nTpQueryPoolStackInformation(\n    _In_ PTP_POOL Pool,\n    _Out_ PTP_POOL_STACK_INFORMATION PoolStackInformation\n    );\n#endif\n\n#if (PHNT_VERSION >= PHNT_WIN7)\n// rev\nNTSYSAPI\nNTSTATUS\nNTAPI\nTpSetPoolStackInformation(\n    _Inout_ PTP_POOL Pool,\n    _In_ PTP_POOL_STACK_INFORMATION PoolStackInformation\n    );\n#endif\n\n// private\n_Check_return_\nNTSYSAPI\nNTSTATUS\nNTAPI\nTpAllocCleanupGroup(\n    _Out_ PTP_CLEANUP_GROUP *CleanupGroupReturn\n    );\n\n// winbase:CloseThreadpoolCleanupGroup\nNTSYSAPI\nVOID\nNTAPI\nTpReleaseCleanupGroup(\n    _Inout_ PTP_CLEANUP_GROUP CleanupGroup\n    );\n\n// winbase:CloseThreadpoolCleanupGroupMembers\nNTSYSAPI\nVOID\nNTAPI\nTpReleaseCleanupGroupMembers(\n    _Inout_ PTP_CLEANUP_GROUP CleanupGroup,\n    _In_ LOGICAL CancelPendingCallbacks,\n    _Inout_opt_ PVOID CleanupParameter\n    );\n\n// winbase:SetEventWhenCallbackReturns\nNTSYSAPI\nVOID\nNTAPI\nTpCallbackSetEventOnCompletion(\n    _Inout_ PTP_CALLBACK_INSTANCE Instance,\n    _In_ HANDLE Event\n    );\n\n// winbase:ReleaseSemaphoreWhenCallbackReturns\nNTSYSAPI\nVOID\nNTAPI\nTpCallbackReleaseSemaphoreOnCompletion(\n    _Inout_ PTP_CALLBACK_INSTANCE Instance,\n    _In_ HANDLE Semaphore,\n    _In_ LONG ReleaseCount\n    );\n\n// winbase:ReleaseMutexWhenCallbackReturns\nNTSYSAPI\nVOID\nNTAPI\nTpCallbackReleaseMutexOnCompletion(\n    _Inout_ PTP_CALLBACK_INSTANCE Instance,\n    _In_ HANDLE Mutex\n    );\n\n// winbase:LeaveCriticalSectionWhenCallbackReturns\nNTSYSAPI\nVOID\nNTAPI\nTpCallbackLeaveCriticalSectionOnCompletion(\n    _Inout_ PTP_CALLBACK_INSTANCE Instance,\n    _Inout_ PRTL_CRITICAL_SECTION CriticalSection\n    );\n\n// winbase:FreeLibraryWhenCallbackReturns\nNTSYSAPI\nVOID\nNTAPI\nTpCallbackUnloadDllOnCompletion(\n    _Inout_ PTP_CALLBACK_INSTANCE Instance,\n    _In_ PVOID DllHandle\n    );\n\n// winbase:CallbackMayRunLong\nNTSYSAPI\nNTSTATUS\nNTAPI\nTpCallbackMayRunLong(\n    _Inout_ PTP_CALLBACK_INSTANCE Instance\n    );\n\n// winbase:DisassociateCurrentThreadFromCallback\nNTSYSAPI\nVOID\nNTAPI\nTpDisassociateCallback(\n    _Inout_ PTP_CALLBACK_INSTANCE Instance\n    );\n\n// winbase:TrySubmitThreadpoolCallback\n_Check_return_\nNTSYSAPI\nNTSTATUS\nNTAPI\nTpSimpleTryPost(\n    _In_ PTP_SIMPLE_CALLBACK Callback,\n    _Inout_opt_ PVOID Context,\n    _In_opt_ PTP_CALLBACK_ENVIRON CallbackEnviron\n    );\n\n// private\n_Check_return_\nNTSYSAPI\nNTSTATUS\nNTAPI\nTpAllocWork(\n    _Out_ PTP_WORK *WorkReturn,\n    _In_ PTP_WORK_CALLBACK Callback,\n    _Inout_opt_ PVOID Context,\n    _In_opt_ PTP_CALLBACK_ENVIRON CallbackEnviron\n    );\n\n// winbase:CloseThreadpoolWork\nNTSYSAPI\nVOID\nNTAPI\nTpReleaseWork(\n    _Inout_ PTP_WORK Work\n    );\n\n// winbase:SubmitThreadpoolWork\nNTSYSAPI\nVOID\nNTAPI\nTpPostWork(\n    _Inout_ PTP_WORK Work\n    );\n\n// winbase:WaitForThreadpoolWorkCallbacks\nNTSYSAPI\nVOID\nNTAPI\nTpWaitForWork(\n    _Inout_ PTP_WORK Work,\n    _In_ LOGICAL CancelPendingCallbacks\n    );\n\n// private\n_Check_return_\nNTSYSAPI\nNTSTATUS\nNTAPI\nTpAllocTimer(\n    _Out_ PTP_TIMER *Timer,\n    _In_ PTP_TIMER_CALLBACK Callback,\n    _Inout_opt_ PVOID Context,\n    _In_opt_ PTP_CALLBACK_ENVIRON CallbackEnviron\n    );\n\n// winbase:CloseThreadpoolTimer\nNTSYSAPI\nVOID\nNTAPI\nTpReleaseTimer(\n    _Inout_ PTP_TIMER Timer\n    );\n\n// winbase:SetThreadpoolTimer\nNTSYSAPI\nVOID\nNTAPI\nTpSetTimer(\n    _Inout_ PTP_TIMER Timer,\n    _In_opt_ PLARGE_INTEGER DueTime,\n    _In_ LONG Period,\n    _In_opt_ LONG WindowLength\n    );\n\n// winbase:IsThreadpoolTimerSet\nNTSYSAPI\nLOGICAL\nNTAPI\nTpIsTimerSet(\n    _In_ PTP_TIMER Timer\n    );\n\n// winbase:WaitForThreadpoolTimerCallbacks\nNTSYSAPI\nVOID\nNTAPI\nTpWaitForTimer(\n    _Inout_ PTP_TIMER Timer,\n    _In_ LOGICAL CancelPendingCallbacks\n    );\n\n// private\n_Check_return_\nNTSYSAPI\nNTSTATUS\nNTAPI\nTpAllocWait(\n    _Out_ PTP_WAIT *WaitReturn,\n    _In_ PTP_WAIT_CALLBACK Callback,\n    _Inout_opt_ PVOID Context,\n    _In_opt_ PTP_CALLBACK_ENVIRON CallbackEnviron\n    );\n\n// winbase:CloseThreadpoolWait\nNTSYSAPI\nVOID\nNTAPI\nTpReleaseWait(\n    _Inout_ PTP_WAIT Wait\n    );\n\n// winbase:SetThreadpoolWait\nNTSYSAPI\nVOID\nNTAPI\nTpSetWait(\n    _Inout_ PTP_WAIT Wait,\n    _In_opt_ HANDLE Handle,\n    _In_opt_ PLARGE_INTEGER Timeout\n    );\n\n// winbase:WaitForThreadpoolWaitCallbacks\nNTSYSAPI\nVOID\nNTAPI\nTpWaitForWait(\n    _Inout_ PTP_WAIT Wait,\n    _In_ LOGICAL CancelPendingCallbacks\n    );\n\n// private\ntypedef VOID (NTAPI *PTP_IO_CALLBACK)(\n    _Inout_ PTP_CALLBACK_INSTANCE Instance,\n    _Inout_opt_ PVOID Context,\n    _In_ PVOID ApcContext,\n    _In_ PIO_STATUS_BLOCK IoSB,\n    _In_ PTP_IO Io\n    );\n\n// private\n_Check_return_\nNTSYSAPI\nNTSTATUS\nNTAPI\nTpAllocIoCompletion(\n    _Out_ PTP_IO *IoReturn,\n    _In_ HANDLE File,\n    _In_ PTP_IO_CALLBACK Callback,\n    _Inout_opt_ PVOID Context,\n    _In_opt_ PTP_CALLBACK_ENVIRON CallbackEnviron\n    );\n\n// winbase:CloseThreadpoolIo\nNTSYSAPI\nVOID\nNTAPI\nTpReleaseIoCompletion(\n    _Inout_ PTP_IO Io\n    );\n\n// winbase:StartThreadpoolIo\nNTSYSAPI\nVOID\nNTAPI\nTpStartAsyncIoOperation(\n    _Inout_ PTP_IO Io\n    );\n\n// winbase:CancelThreadpoolIo\nNTSYSAPI\nVOID\nNTAPI\nTpCancelAsyncIoOperation(\n    _Inout_ PTP_IO Io\n    );\n\n// winbase:WaitForThreadpoolIoCallbacks\nNTSYSAPI\nVOID\nNTAPI\nTpWaitForIoCompletion(\n    _Inout_ PTP_IO Io,\n    _In_ LOGICAL CancelPendingCallbacks\n    );\n\n// private\nNTSYSAPI\nNTSTATUS\nNTAPI\nTpAllocAlpcCompletion(\n    _Out_ PTP_ALPC *AlpcReturn,\n    _In_ HANDLE AlpcPort,\n    _In_ PTP_ALPC_CALLBACK Callback,\n    _Inout_opt_ PVOID Context,\n    _In_opt_ PTP_CALLBACK_ENVIRON CallbackEnviron\n    );\n\n#if (PHNT_VERSION >= PHNT_WIN7)\n// rev\nNTSYSAPI\nNTSTATUS\nNTAPI\nTpAllocAlpcCompletionEx(\n    _Out_ PTP_ALPC *AlpcReturn,\n    _In_ HANDLE AlpcPort,\n    _In_ PTP_ALPC_CALLBACK_EX Callback,\n    _Inout_opt_ PVOID Context,\n    _In_opt_ PTP_CALLBACK_ENVIRON CallbackEnviron\n    );\n#endif\n\n// private\nNTSYSAPI\nVOID\nNTAPI\nTpReleaseAlpcCompletion(\n    _Inout_ PTP_ALPC Alpc\n    );\n\n// private\nNTSYSAPI\nVOID\nNTAPI\nTpWaitForAlpcCompletion(\n    _Inout_ PTP_ALPC Alpc\n    );\n\n// private\ntypedef enum _TP_TRACE_TYPE\n{\n    TpTraceThreadPriority = 1,\n    TpTraceThreadAffinity,\n    MaxTpTraceType\n} TP_TRACE_TYPE;\n\n// private\nNTSYSAPI\nVOID\nNTAPI\nTpCaptureCaller(\n    _In_ TP_TRACE_TYPE Type\n    );\n\n// private\nNTSYSAPI\nVOID\nNTAPI\nTpCheckTerminateWorker(\n    _In_ HANDLE Thread\n    );\n\n#endif\n\n#endif\n"
  },
  {
    "path": "third_party/phnt/include/ntwow64.h",
    "content": "#ifndef _NTWOW64_H\n#define _NTWOW64_H\n\n#define WOW64_SYSTEM_DIRECTORY \"SysWOW64\"\n#define WOW64_SYSTEM_DIRECTORY_U L\"SysWOW64\"\n#define WOW64_X86_TAG \" (x86)\"\n#define WOW64_X86_TAG_U L\" (x86)\"\n\n// In USER_SHARED_DATA\ntypedef enum _WOW64_SHARED_INFORMATION\n{\n    SharedNtdll32LdrInitializeThunk,\n    SharedNtdll32KiUserExceptionDispatcher,\n    SharedNtdll32KiUserApcDispatcher,\n    SharedNtdll32KiUserCallbackDispatcher,\n    SharedNtdll32ExpInterlockedPopEntrySListFault,\n    SharedNtdll32ExpInterlockedPopEntrySListResume,\n    SharedNtdll32ExpInterlockedPopEntrySListEnd,\n    SharedNtdll32RtlUserThreadStart,\n    SharedNtdll32pQueryProcessDebugInformationRemote,\n    SharedNtdll32BaseAddress,\n    SharedNtdll32LdrSystemDllInitBlock,\n    Wow64SharedPageEntriesCount\n} WOW64_SHARED_INFORMATION;\n\n// 32-bit definitions\n\n#define WOW64_POINTER(Type) ULONG\n\ntypedef struct _RTL_BALANCED_NODE32\n{\n    union\n    {\n        WOW64_POINTER(struct _RTL_BALANCED_NODE *) Children[2];\n        struct\n        {\n            WOW64_POINTER(struct _RTL_BALANCED_NODE *) Left;\n            WOW64_POINTER(struct _RTL_BALANCED_NODE *) Right;\n        };\n    };\n    union\n    {\n        WOW64_POINTER(UCHAR) Red : 1;\n        WOW64_POINTER(UCHAR) Balance : 2;\n        WOW64_POINTER(ULONG_PTR) ParentValue;\n    };\n} RTL_BALANCED_NODE32, *PRTL_BALANCED_NODE32;\n\ntypedef struct _RTL_RB_TREE32\n{\n    WOW64_POINTER(PRTL_BALANCED_NODE) Root;\n    WOW64_POINTER(PRTL_BALANCED_NODE) Min;\n} RTL_RB_TREE32, *PRTL_RB_TREE32;\n\ntypedef struct _PEB_LDR_DATA32\n{\n    ULONG Length;\n    BOOLEAN Initialized;\n    WOW64_POINTER(HANDLE) SsHandle;\n    LIST_ENTRY32 InLoadOrderModuleList;\n    LIST_ENTRY32 InMemoryOrderModuleList;\n    LIST_ENTRY32 InInitializationOrderModuleList;\n    WOW64_POINTER(PVOID) EntryInProgress;\n    BOOLEAN ShutdownInProgress;\n    WOW64_POINTER(HANDLE) ShutdownThreadId;\n} PEB_LDR_DATA32, *PPEB_LDR_DATA32;\n\ntypedef struct _LDR_SERVICE_TAG_RECORD32\n{\n    WOW64_POINTER(struct _LDR_SERVICE_TAG_RECORD *) Next;\n    ULONG ServiceTag;\n} LDR_SERVICE_TAG_RECORD32, *PLDR_SERVICE_TAG_RECORD32;\n\ntypedef struct _LDRP_CSLIST32\n{\n    WOW64_POINTER(PSINGLE_LIST_ENTRY) Tail;\n} LDRP_CSLIST32, *PLDRP_CSLIST32;\n\ntypedef struct _LDR_DDAG_NODE32\n{\n    LIST_ENTRY32 Modules;\n    WOW64_POINTER(PLDR_SERVICE_TAG_RECORD) ServiceTagList;\n    ULONG LoadCount;\n    ULONG LoadWhileUnloadingCount;\n    ULONG LowestLink;\n    union\n    {\n        LDRP_CSLIST32 Dependencies;\n        SINGLE_LIST_ENTRY32 RemovalLink;\n    };\n    LDRP_CSLIST32 IncomingDependencies;\n    LDR_DDAG_STATE State;\n    SINGLE_LIST_ENTRY32 CondenseLink;\n    ULONG PreorderNumber;\n} LDR_DDAG_NODE32, *PLDR_DDAG_NODE32;\n\n#define LDR_DATA_TABLE_ENTRY_SIZE_WINXP_32 FIELD_OFFSET(LDR_DATA_TABLE_ENTRY32, DdagNode)\n#define LDR_DATA_TABLE_ENTRY_SIZE_WIN7_32 FIELD_OFFSET(LDR_DATA_TABLE_ENTRY32, BaseNameHashValue)\n#define LDR_DATA_TABLE_ENTRY_SIZE_WIN8_32 FIELD_OFFSET(LDR_DATA_TABLE_ENTRY32, ImplicitPathOptions)\n\ntypedef struct _LDR_DATA_TABLE_ENTRY32\n{\n    LIST_ENTRY32 InLoadOrderLinks;\n    LIST_ENTRY32 InMemoryOrderLinks;\n    union\n    {\n        LIST_ENTRY32 InInitializationOrderLinks;\n        LIST_ENTRY32 InProgressLinks;\n    };\n    WOW64_POINTER(PVOID) DllBase;\n    WOW64_POINTER(PVOID) EntryPoint;\n    ULONG SizeOfImage;\n    UNICODE_STRING32 FullDllName;\n    UNICODE_STRING32 BaseDllName;\n    union\n    {\n        UCHAR FlagGroup[4];\n        ULONG Flags;\n        struct\n        {\n            ULONG PackagedBinary : 1;\n            ULONG MarkedForRemoval : 1;\n            ULONG ImageDll : 1;\n            ULONG LoadNotificationsSent : 1;\n            ULONG TelemetryEntryProcessed : 1;\n            ULONG ProcessStaticImport : 1;\n            ULONG InLegacyLists : 1;\n            ULONG InIndexes : 1;\n            ULONG ShimDll : 1;\n            ULONG InExceptionTable : 1;\n            ULONG ReservedFlags1 : 2;\n            ULONG LoadInProgress : 1;\n            ULONG LoadConfigProcessed : 1;\n            ULONG EntryProcessed : 1;\n            ULONG ProtectDelayLoad : 1;\n            ULONG ReservedFlags3 : 2;\n            ULONG DontCallForThreads : 1;\n            ULONG ProcessAttachCalled : 1;\n            ULONG ProcessAttachFailed : 1;\n            ULONG CorDeferredValidate : 1;\n            ULONG CorImage : 1;\n            ULONG DontRelocate : 1;\n            ULONG CorILOnly : 1;\n            ULONG ReservedFlags5 : 3;\n            ULONG Redirected : 1;\n            ULONG ReservedFlags6 : 2;\n            ULONG CompatDatabaseProcessed : 1;\n        };\n    };\n    USHORT ObsoleteLoadCount;\n    USHORT TlsIndex;\n    LIST_ENTRY32 HashLinks;\n    ULONG TimeDateStamp;\n    WOW64_POINTER(struct _ACTIVATION_CONTEXT *) EntryPointActivationContext;\n    WOW64_POINTER(PVOID) Lock;\n    WOW64_POINTER(PLDR_DDAG_NODE) DdagNode;\n    LIST_ENTRY32 NodeModuleLink;\n    WOW64_POINTER(struct _LDRP_LOAD_CONTEXT *) LoadContext;\n    WOW64_POINTER(PVOID) ParentDllBase;\n    WOW64_POINTER(PVOID) SwitchBackContext;\n    RTL_BALANCED_NODE32 BaseAddressIndexNode;\n    RTL_BALANCED_NODE32 MappingInfoIndexNode;\n    WOW64_POINTER(ULONG_PTR) OriginalBase;\n    LARGE_INTEGER LoadTime;\n    ULONG BaseNameHashValue;\n    LDR_DLL_LOAD_REASON LoadReason;\n    ULONG ImplicitPathOptions;\n    ULONG ReferenceCount;\n    ULONG DependentLoadFlags;\n    UCHAR SigningLevel; // since REDSTONE2\n} LDR_DATA_TABLE_ENTRY32, *PLDR_DATA_TABLE_ENTRY32;\n\ntypedef struct _CURDIR32\n{\n    UNICODE_STRING32 DosPath;\n    WOW64_POINTER(HANDLE) Handle;\n} CURDIR32, *PCURDIR32;\n\ntypedef struct _RTL_DRIVE_LETTER_CURDIR32\n{\n    USHORT Flags;\n    USHORT Length;\n    ULONG TimeStamp;\n    STRING32 DosPath;\n} RTL_DRIVE_LETTER_CURDIR32, *PRTL_DRIVE_LETTER_CURDIR32;\n\ntypedef struct _RTL_USER_PROCESS_PARAMETERS32\n{\n    ULONG MaximumLength;\n    ULONG Length;\n\n    ULONG Flags;\n    ULONG DebugFlags;\n\n    WOW64_POINTER(HANDLE) ConsoleHandle;\n    ULONG ConsoleFlags;\n    WOW64_POINTER(HANDLE) StandardInput;\n    WOW64_POINTER(HANDLE) StandardOutput;\n    WOW64_POINTER(HANDLE) StandardError;\n\n    CURDIR32 CurrentDirectory;\n    UNICODE_STRING32 DllPath;\n    UNICODE_STRING32 ImagePathName;\n    UNICODE_STRING32 CommandLine;\n    WOW64_POINTER(PVOID) Environment;\n\n    ULONG StartingX;\n    ULONG StartingY;\n    ULONG CountX;\n    ULONG CountY;\n    ULONG CountCharsX;\n    ULONG CountCharsY;\n    ULONG FillAttribute;\n\n    ULONG WindowFlags;\n    ULONG ShowWindowFlags;\n    UNICODE_STRING32 WindowTitle;\n    UNICODE_STRING32 DesktopInfo;\n    UNICODE_STRING32 ShellInfo;\n    UNICODE_STRING32 RuntimeData;\n    RTL_DRIVE_LETTER_CURDIR32 CurrentDirectories[RTL_MAX_DRIVE_LETTERS];\n\n    WOW64_POINTER(ULONG_PTR) EnvironmentSize;\n    WOW64_POINTER(ULONG_PTR) EnvironmentVersion;\n    WOW64_POINTER(PVOID) PackageDependencyData;\n    ULONG ProcessGroupId;\n    ULONG LoaderThreads;\n} RTL_USER_PROCESS_PARAMETERS32, *PRTL_USER_PROCESS_PARAMETERS32;\n\ntypedef struct _PEB32\n{\n    BOOLEAN InheritedAddressSpace;\n    BOOLEAN ReadImageFileExecOptions;\n    BOOLEAN BeingDebugged;\n    union\n    {\n        BOOLEAN BitField;\n        struct\n        {\n            BOOLEAN ImageUsesLargePages : 1;\n            BOOLEAN IsProtectedProcess : 1;\n            BOOLEAN IsImageDynamicallyRelocated : 1;\n            BOOLEAN SkipPatchingUser32Forwarders : 1;\n            BOOLEAN IsPackagedProcess : 1;\n            BOOLEAN IsAppContainer : 1;\n            BOOLEAN IsProtectedProcessLight : 1;\n            BOOLEAN IsLongPathAwareProcess : 1;\n        };\n    };\n    WOW64_POINTER(HANDLE) Mutant;\n\n    WOW64_POINTER(PVOID) ImageBaseAddress;\n    WOW64_POINTER(PPEB_LDR_DATA) Ldr;\n    WOW64_POINTER(PRTL_USER_PROCESS_PARAMETERS) ProcessParameters;\n    WOW64_POINTER(PVOID) SubSystemData;\n    WOW64_POINTER(PVOID) ProcessHeap;\n    WOW64_POINTER(PRTL_CRITICAL_SECTION) FastPebLock;\n    WOW64_POINTER(PVOID) AtlThunkSListPtr;\n    WOW64_POINTER(PVOID) IFEOKey;\n    union\n    {\n        ULONG CrossProcessFlags;\n        struct\n        {\n            ULONG ProcessInJob : 1;\n            ULONG ProcessInitializing : 1;\n            ULONG ProcessUsingVEH : 1;\n            ULONG ProcessUsingVCH : 1;\n            ULONG ProcessUsingFTH : 1;\n            ULONG ReservedBits0 : 27;\n        };\n    };\n    union\n    {\n        WOW64_POINTER(PVOID) KernelCallbackTable;\n        WOW64_POINTER(PVOID) UserSharedInfoPtr;\n    };\n    ULONG SystemReserved[1];\n    ULONG AtlThunkSListPtr32;\n    WOW64_POINTER(PVOID) ApiSetMap;\n    ULONG TlsExpansionCounter;\n    WOW64_POINTER(PVOID) TlsBitmap;\n    ULONG TlsBitmapBits[2];\n    WOW64_POINTER(PVOID) ReadOnlySharedMemoryBase;\n    WOW64_POINTER(PVOID) HotpatchInformation;\n    WOW64_POINTER(PVOID *) ReadOnlyStaticServerData;\n    WOW64_POINTER(PVOID) AnsiCodePageData;\n    WOW64_POINTER(PVOID) OemCodePageData;\n    WOW64_POINTER(PVOID) UnicodeCaseTableData;\n\n    ULONG NumberOfProcessors;\n    ULONG NtGlobalFlag;\n\n    LARGE_INTEGER CriticalSectionTimeout;\n    WOW64_POINTER(SIZE_T) HeapSegmentReserve;\n    WOW64_POINTER(SIZE_T) HeapSegmentCommit;\n    WOW64_POINTER(SIZE_T) HeapDeCommitTotalFreeThreshold;\n    WOW64_POINTER(SIZE_T) HeapDeCommitFreeBlockThreshold;\n\n    ULONG NumberOfHeaps;\n    ULONG MaximumNumberOfHeaps;\n    WOW64_POINTER(PVOID *) ProcessHeaps;\n\n    WOW64_POINTER(PVOID) GdiSharedHandleTable;\n    WOW64_POINTER(PVOID) ProcessStarterHelper;\n    ULONG GdiDCAttributeList;\n\n    WOW64_POINTER(PRTL_CRITICAL_SECTION) LoaderLock;\n\n    ULONG OSMajorVersion;\n    ULONG OSMinorVersion;\n    USHORT OSBuildNumber;\n    USHORT OSCSDVersion;\n    ULONG OSPlatformId;\n    ULONG ImageSubsystem;\n    ULONG ImageSubsystemMajorVersion;\n    ULONG ImageSubsystemMinorVersion;\n    WOW64_POINTER(ULONG_PTR) ActiveProcessAffinityMask;\n    GDI_HANDLE_BUFFER32 GdiHandleBuffer;\n    WOW64_POINTER(PVOID) PostProcessInitRoutine;\n\n    WOW64_POINTER(PVOID) TlsExpansionBitmap;\n    ULONG TlsExpansionBitmapBits[32];\n\n    ULONG SessionId;\n\n    ULARGE_INTEGER AppCompatFlags;\n    ULARGE_INTEGER AppCompatFlagsUser;\n    WOW64_POINTER(PVOID) pShimData;\n    WOW64_POINTER(PVOID) AppCompatInfo;\n\n    UNICODE_STRING32 CSDVersion;\n\n    WOW64_POINTER(PVOID) ActivationContextData;\n    WOW64_POINTER(PVOID) ProcessAssemblyStorageMap;\n    WOW64_POINTER(PVOID) SystemDefaultActivationContextData;\n    WOW64_POINTER(PVOID) SystemAssemblyStorageMap;\n\n    WOW64_POINTER(SIZE_T) MinimumStackCommit;\n\n    WOW64_POINTER(PVOID *) FlsCallback;\n    LIST_ENTRY32 FlsListHead;\n    WOW64_POINTER(PVOID) FlsBitmap;\n    ULONG FlsBitmapBits[FLS_MAXIMUM_AVAILABLE_OLD / (sizeof(ULONG) * 8)];\n    ULONG FlsHighIndex;\n\n    WOW64_POINTER(PVOID) WerRegistrationData;\n    WOW64_POINTER(PVOID) WerShipAssertPtr;\n    WOW64_POINTER(PVOID) pContextData;\n    WOW64_POINTER(PVOID) pImageHeaderHash;\n    union\n    {\n        ULONG TracingFlags;\n        struct\n        {\n            ULONG HeapTracingEnabled : 1;\n            ULONG CritSecTracingEnabled : 1;\n            ULONG LibLoaderTracingEnabled : 1;\n            ULONG SpareTracingBits : 29;\n        };\n    };\n    ULONGLONG CsrServerReadOnlySharedMemoryBase;\n    WOW64_POINTER(PVOID) TppWorkerpListLock;\n    LIST_ENTRY32 TppWorkerpList;\n    WOW64_POINTER(PVOID) WaitOnAddressHashTable[128];\n} PEB32, *PPEB32;\n\nC_ASSERT(FIELD_OFFSET(PEB32, IFEOKey) == 0x024);\nC_ASSERT(FIELD_OFFSET(PEB32, UnicodeCaseTableData) == 0x060);\nC_ASSERT(FIELD_OFFSET(PEB32, SystemAssemblyStorageMap) == 0x204);\nC_ASSERT(FIELD_OFFSET(PEB32, pImageHeaderHash) == 0x23c);\nC_ASSERT(FIELD_OFFSET(PEB32, WaitOnAddressHashTable) == 0x25c);\nC_ASSERT(sizeof(PEB32) == 0x460);\n\n#define GDI_BATCH_BUFFER_SIZE 310\n\ntypedef struct _GDI_TEB_BATCH32\n{\n    ULONG Offset;\n    WOW64_POINTER(ULONG_PTR) HDC;\n    ULONG Buffer[GDI_BATCH_BUFFER_SIZE];\n} GDI_TEB_BATCH32, *PGDI_TEB_BATCH32;\n\ntypedef struct _TEB32\n{\n    NT_TIB32 NtTib;\n\n    WOW64_POINTER(PVOID) EnvironmentPointer;\n    CLIENT_ID32 ClientId;\n    WOW64_POINTER(PVOID) ActiveRpcHandle;\n    WOW64_POINTER(PVOID) ThreadLocalStoragePointer;\n    WOW64_POINTER(PPEB) ProcessEnvironmentBlock;\n\n    ULONG LastErrorValue;\n    ULONG CountOfOwnedCriticalSections;\n    WOW64_POINTER(PVOID) CsrClientThread;\n    WOW64_POINTER(PVOID) Win32ThreadInfo;\n    ULONG User32Reserved[26];\n    ULONG UserReserved[5];\n    WOW64_POINTER(PVOID) WOW32Reserved;\n    LCID CurrentLocale;\n    ULONG FpSoftwareStatusRegister;\n    WOW64_POINTER(PVOID) ReservedForDebuggerInstrumentation[16];\n    WOW64_POINTER(PVOID) SystemReserved1[36];\n    UCHAR WorkingOnBehalfTicket[8];\n    NTSTATUS ExceptionCode;\n\n    WOW64_POINTER(PVOID) ActivationContextStackPointer;\n    WOW64_POINTER(ULONG_PTR) InstrumentationCallbackSp;\n    WOW64_POINTER(ULONG_PTR) InstrumentationCallbackPreviousPc;\n    WOW64_POINTER(ULONG_PTR) InstrumentationCallbackPreviousSp;\n    BOOLEAN InstrumentationCallbackDisabled;\n    UCHAR SpareBytes[23];\n    ULONG TxFsContext;\n\n    GDI_TEB_BATCH32 GdiTebBatch;\n    CLIENT_ID32 RealClientId;\n    WOW64_POINTER(HANDLE) GdiCachedProcessHandle;\n    ULONG GdiClientPID;\n    ULONG GdiClientTID;\n    WOW64_POINTER(PVOID) GdiThreadLocalInfo;\n    WOW64_POINTER(ULONG_PTR) Win32ClientInfo[62];\n    WOW64_POINTER(PVOID) glDispatchTable[233];\n    WOW64_POINTER(ULONG_PTR) glReserved1[29];\n    WOW64_POINTER(PVOID) glReserved2;\n    WOW64_POINTER(PVOID) glSectionInfo;\n    WOW64_POINTER(PVOID) glSection;\n    WOW64_POINTER(PVOID) glTable;\n    WOW64_POINTER(PVOID) glCurrentRC;\n    WOW64_POINTER(PVOID) glContext;\n\n    NTSTATUS LastStatusValue;\n    UNICODE_STRING32 StaticUnicodeString;\n    WCHAR StaticUnicodeBuffer[261];\n\n    WOW64_POINTER(PVOID) DeallocationStack;\n    WOW64_POINTER(PVOID) TlsSlots[64];\n    LIST_ENTRY32 TlsLinks;\n\n    WOW64_POINTER(PVOID) Vdm;\n    WOW64_POINTER(PVOID) ReservedForNtRpc;\n    WOW64_POINTER(PVOID) DbgSsReserved[2];\n\n    ULONG HardErrorMode;\n    WOW64_POINTER(PVOID) Instrumentation[9];\n    GUID ActivityId;\n\n    WOW64_POINTER(PVOID) SubProcessTag;\n    WOW64_POINTER(PVOID) PerflibData;\n    WOW64_POINTER(PVOID) EtwTraceData;\n    WOW64_POINTER(PVOID) WinSockData;\n    ULONG GdiBatchCount;\n\n    union\n    {\n        PROCESSOR_NUMBER CurrentIdealProcessor;\n        ULONG IdealProcessorValue;\n        struct\n        {\n            UCHAR ReservedPad0;\n            UCHAR ReservedPad1;\n            UCHAR ReservedPad2;\n            UCHAR IdealProcessor;\n        };\n    };\n\n    ULONG GuaranteedStackBytes;\n    WOW64_POINTER(PVOID) ReservedForPerf;\n    WOW64_POINTER(PVOID) ReservedForOle;\n    ULONG WaitingOnLoaderLock;\n    WOW64_POINTER(PVOID) SavedPriorityState;\n    WOW64_POINTER(ULONG_PTR) ReservedForCodeCoverage;\n    WOW64_POINTER(PVOID) ThreadPoolData;\n    WOW64_POINTER(PVOID *) TlsExpansionSlots;\n\n    ULONG MuiGeneration;\n    ULONG IsImpersonating;\n    WOW64_POINTER(PVOID) NlsCache;\n    WOW64_POINTER(PVOID) pShimData;\n    USHORT HeapVirtualAffinity;\n    USHORT LowFragHeapDataSlot;\n    WOW64_POINTER(HANDLE) CurrentTransactionHandle;\n    WOW64_POINTER(PTEB_ACTIVE_FRAME) ActiveFrame;\n    WOW64_POINTER(PVOID) FlsData;\n\n    WOW64_POINTER(PVOID) PreferredLanguages;\n    WOW64_POINTER(PVOID) UserPrefLanguages;\n    WOW64_POINTER(PVOID) MergedPrefLanguages;\n    ULONG MuiImpersonation;\n\n    union\n    {\n        USHORT CrossTebFlags;\n        USHORT SpareCrossTebBits : 16;\n    };\n    union\n    {\n        USHORT SameTebFlags;\n        struct\n        {\n            USHORT SafeThunkCall : 1;\n            USHORT InDebugPrint : 1;\n            USHORT HasFiberData : 1;\n            USHORT SkipThreadAttach : 1;\n            USHORT WerInShipAssertCode : 1;\n            USHORT RanProcessInit : 1;\n            USHORT ClonedThread : 1;\n            USHORT SuppressDebugMsg : 1;\n            USHORT DisableUserStackWalk : 1;\n            USHORT RtlExceptionAttached : 1;\n            USHORT InitialThread : 1;\n            USHORT SessionAware : 1;\n            USHORT LoadOwner : 1;\n            USHORT LoaderWorker : 1;\n            USHORT SpareSameTebBits : 2;\n        };\n    };\n\n    WOW64_POINTER(PVOID) TxnScopeEnterCallback;\n    WOW64_POINTER(PVOID) TxnScopeExitCallback;\n    WOW64_POINTER(PVOID) TxnScopeContext;\n    ULONG LockCount;\n    LONG WowTebOffset;\n    WOW64_POINTER(PVOID) ResourceRetValue;\n    WOW64_POINTER(PVOID) ReservedForWdf;\n    ULONGLONG ReservedForCrt;\n    GUID EffectiveContainerId;\n} TEB32, *PTEB32;\n\nC_ASSERT(FIELD_OFFSET(TEB32, ProcessEnvironmentBlock) == 0x030);\nC_ASSERT(FIELD_OFFSET(TEB32, ExceptionCode) == 0x1a4);\nC_ASSERT(FIELD_OFFSET(TEB32, TxFsContext) == 0x1d0);\nC_ASSERT(FIELD_OFFSET(TEB32, glContext) == 0xbf0);\nC_ASSERT(FIELD_OFFSET(TEB32, StaticUnicodeBuffer) == 0xc00);\nC_ASSERT(FIELD_OFFSET(TEB32, TlsLinks) == 0xf10);\nC_ASSERT(FIELD_OFFSET(TEB32, DbgSsReserved) == 0xf20);\nC_ASSERT(FIELD_OFFSET(TEB32, ActivityId) == 0xf50);\nC_ASSERT(FIELD_OFFSET(TEB32, GdiBatchCount) == 0xf70);\nC_ASSERT(FIELD_OFFSET(TEB32, TlsExpansionSlots) == 0xf94);\nC_ASSERT(FIELD_OFFSET(TEB32, FlsData) == 0xfb4);\nC_ASSERT(FIELD_OFFSET(TEB32, MuiImpersonation) == 0xfc4);\nC_ASSERT(FIELD_OFFSET(TEB32, ReservedForCrt) == 0xfe8);\nC_ASSERT(FIELD_OFFSET(TEB32, EffectiveContainerId) == 0xff0);\nC_ASSERT(sizeof(TEB32) == 0x1000);\n\n// Conversion\n\nFORCEINLINE VOID UStr32ToUStr(\n    _Out_ PUNICODE_STRING Destination,\n    _In_ PUNICODE_STRING32 Source\n    )\n{\n    Destination->Length = Source->Length;\n    Destination->MaximumLength = Source->MaximumLength;\n    Destination->Buffer = (PWCH)UlongToPtr(Source->Buffer);\n}\n\nFORCEINLINE VOID UStrToUStr32(\n    _Out_ PUNICODE_STRING32 Destination,\n    _In_ PUNICODE_STRING Source\n    )\n{\n    Destination->Length = Source->Length;\n    Destination->MaximumLength = Source->MaximumLength;\n    Destination->Buffer = PtrToUlong(Source->Buffer);\n}\n\n#endif\n"
  },
  {
    "path": "third_party/phnt/include/ntxcapi.h",
    "content": "#ifndef _NTXCAPI_H\n#define _NTXCAPI_H\n\nNTSYSAPI\nBOOLEAN\nNTAPI\nRtlDispatchException(\n    _In_ PEXCEPTION_RECORD ExceptionRecord,\n    _In_ PCONTEXT ContextRecord\n    );\n\nNTSYSAPI\nDECLSPEC_NORETURN\nVOID\nNTAPI\nRtlRaiseStatus(\n    _In_ NTSTATUS Status\n    );\n\nNTSYSAPI\nVOID\nNTAPI\nRtlRaiseException(\n    _In_ PEXCEPTION_RECORD ExceptionRecord\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtContinue(\n    _In_ PCONTEXT ContextRecord,\n    _In_ BOOLEAN TestAlert\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nNtRaiseException(\n    _In_ PEXCEPTION_RECORD ExceptionRecord,\n    _In_ PCONTEXT ContextRecord,\n    _In_ BOOLEAN FirstChance\n    );\n\n#endif\n"
  },
  {
    "path": "third_party/phnt/include/ntzwapi.h",
    "content": "#ifndef _NTZWAPI_H\n#define _NTZWAPI_H\n\n// This file was automatically generated. Do not edit.\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nZwAcceptConnectPort(\n    _Out_ PHANDLE PortHandle,\n    _In_opt_ PVOID PortContext,\n    _In_ PPORT_MESSAGE ConnectionRequest,\n    _In_ BOOLEAN AcceptConnection,\n    _Inout_opt_ PPORT_VIEW ServerView,\n    _Out_opt_ PREMOTE_PORT_VIEW ClientView\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nZwAccessCheck(\n    _In_ PSECURITY_DESCRIPTOR SecurityDescriptor,\n    _In_ HANDLE ClientToken,\n    _In_ ACCESS_MASK DesiredAccess,\n    _In_ PGENERIC_MAPPING GenericMapping,\n    _Out_writes_bytes_(*PrivilegeSetLength) PPRIVILEGE_SET PrivilegeSet,\n    _Inout_ PULONG PrivilegeSetLength,\n    _Out_ PACCESS_MASK GrantedAccess,\n    _Out_ PNTSTATUS AccessStatus\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nZwAccessCheckAndAuditAlarm(\n    _In_ PUNICODE_STRING SubsystemName,\n    _In_opt_ PVOID HandleId,\n    _In_ PUNICODE_STRING ObjectTypeName,\n    _In_ PUNICODE_STRING ObjectName,\n    _In_ PSECURITY_DESCRIPTOR SecurityDescriptor,\n    _In_ ACCESS_MASK DesiredAccess,\n    _In_ PGENERIC_MAPPING GenericMapping,\n    _In_ BOOLEAN ObjectCreation,\n    _Out_ PACCESS_MASK GrantedAccess,\n    _Out_ PNTSTATUS AccessStatus,\n    _Out_ PBOOLEAN GenerateOnClose\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nZwAccessCheckByType(\n    _In_ PSECURITY_DESCRIPTOR SecurityDescriptor,\n    _In_opt_ PSID PrincipalSelfSid,\n    _In_ HANDLE ClientToken,\n    _In_ ACCESS_MASK DesiredAccess,\n    _In_reads_(ObjectTypeListLength) POBJECT_TYPE_LIST ObjectTypeList,\n    _In_ ULONG ObjectTypeListLength,\n    _In_ PGENERIC_MAPPING GenericMapping,\n    _Out_writes_bytes_(*PrivilegeSetLength) PPRIVILEGE_SET PrivilegeSet,\n    _Inout_ PULONG PrivilegeSetLength,\n    _Out_ PACCESS_MASK GrantedAccess,\n    _Out_ PNTSTATUS AccessStatus\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nZwAccessCheckByTypeAndAuditAlarm(\n    _In_ PUNICODE_STRING SubsystemName,\n    _In_opt_ PVOID HandleId,\n    _In_ PUNICODE_STRING ObjectTypeName,\n    _In_ PUNICODE_STRING ObjectName,\n    _In_ PSECURITY_DESCRIPTOR SecurityDescriptor,\n    _In_opt_ PSID PrincipalSelfSid,\n    _In_ ACCESS_MASK DesiredAccess,\n    _In_ AUDIT_EVENT_TYPE AuditType,\n    _In_ ULONG Flags,\n    _In_reads_opt_(ObjectTypeListLength) POBJECT_TYPE_LIST ObjectTypeList,\n    _In_ ULONG ObjectTypeListLength,\n    _In_ PGENERIC_MAPPING GenericMapping,\n    _In_ BOOLEAN ObjectCreation,\n    _Out_ PACCESS_MASK GrantedAccess,\n    _Out_ PNTSTATUS AccessStatus,\n    _Out_ PBOOLEAN GenerateOnClose\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nZwAccessCheckByTypeResultList(\n    _In_ PSECURITY_DESCRIPTOR SecurityDescriptor,\n    _In_opt_ PSID PrincipalSelfSid,\n    _In_ HANDLE ClientToken,\n    _In_ ACCESS_MASK DesiredAccess,\n    _In_reads_(ObjectTypeListLength) POBJECT_TYPE_LIST ObjectTypeList,\n    _In_ ULONG ObjectTypeListLength,\n    _In_ PGENERIC_MAPPING GenericMapping,\n    _Out_writes_bytes_(*PrivilegeSetLength) PPRIVILEGE_SET PrivilegeSet,\n    _Inout_ PULONG PrivilegeSetLength,\n    _Out_writes_(ObjectTypeListLength) PACCESS_MASK GrantedAccess,\n    _Out_writes_(ObjectTypeListLength) PNTSTATUS AccessStatus\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nZwAccessCheckByTypeResultListAndAuditAlarm(\n    _In_ PUNICODE_STRING SubsystemName,\n    _In_opt_ PVOID HandleId,\n    _In_ PUNICODE_STRING ObjectTypeName,\n    _In_ PUNICODE_STRING ObjectName,\n    _In_ PSECURITY_DESCRIPTOR SecurityDescriptor,\n    _In_opt_ PSID PrincipalSelfSid,\n    _In_ ACCESS_MASK DesiredAccess,\n    _In_ AUDIT_EVENT_TYPE AuditType,\n    _In_ ULONG Flags,\n    _In_reads_opt_(ObjectTypeListLength) POBJECT_TYPE_LIST ObjectTypeList,\n    _In_ ULONG ObjectTypeListLength,\n    _In_ PGENERIC_MAPPING GenericMapping,\n    _In_ BOOLEAN ObjectCreation,\n    _Out_writes_(ObjectTypeListLength) PACCESS_MASK GrantedAccess,\n    _Out_writes_(ObjectTypeListLength) PNTSTATUS AccessStatus,\n    _Out_ PBOOLEAN GenerateOnClose\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nZwAccessCheckByTypeResultListAndAuditAlarmByHandle(\n    _In_ PUNICODE_STRING SubsystemName,\n    _In_opt_ PVOID HandleId,\n    _In_ HANDLE ClientToken,\n    _In_ PUNICODE_STRING ObjectTypeName,\n    _In_ PUNICODE_STRING ObjectName,\n    _In_ PSECURITY_DESCRIPTOR SecurityDescriptor,\n    _In_opt_ PSID PrincipalSelfSid,\n    _In_ ACCESS_MASK DesiredAccess,\n    _In_ AUDIT_EVENT_TYPE AuditType,\n    _In_ ULONG Flags,\n    _In_reads_opt_(ObjectTypeListLength) POBJECT_TYPE_LIST ObjectTypeList,\n    _In_ ULONG ObjectTypeListLength,\n    _In_ PGENERIC_MAPPING GenericMapping,\n    _In_ BOOLEAN ObjectCreation,\n    _Out_writes_(ObjectTypeListLength) PACCESS_MASK GrantedAccess,\n    _Out_writes_(ObjectTypeListLength) PNTSTATUS AccessStatus,\n    _Out_ PBOOLEAN GenerateOnClose\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nZwAcquireCMFViewOwnership(\n    _Out_ PULONGLONG TimeStamp,\n    _Out_ PBOOLEAN tokenTaken,\n    _In_ BOOLEAN replaceExisting\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nZwAddAtom(\n    _In_reads_bytes_opt_(Length) PWSTR AtomName,\n    _In_ ULONG Length,\n    _Out_opt_ PRTL_ATOM Atom\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nZwAddAtomEx(\n    _In_reads_bytes_opt_(Length) PWSTR AtomName,\n    _In_ ULONG Length,\n    _Out_opt_ PRTL_ATOM Atom,\n    _In_ ULONG Flags\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nZwAddBootEntry(\n    _In_ PBOOT_ENTRY BootEntry,\n    _Out_opt_ PULONG Id\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nZwAddDriverEntry(\n    _In_ PEFI_DRIVER_ENTRY DriverEntry,\n    _Out_opt_ PULONG Id\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nZwAdjustGroupsToken(\n    _In_ HANDLE TokenHandle,\n    _In_ BOOLEAN ResetToDefault,\n    _In_opt_ PTOKEN_GROUPS NewState,\n    _In_opt_ ULONG BufferLength,\n    _Out_writes_bytes_to_opt_(BufferLength, *ReturnLength) PTOKEN_GROUPS PreviousState,\n    _Out_ PULONG ReturnLength\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nZwAdjustPrivilegesToken(\n    _In_ HANDLE TokenHandle,\n    _In_ BOOLEAN DisableAllPrivileges,\n    _In_opt_ PTOKEN_PRIVILEGES NewState,\n    _In_ ULONG BufferLength,\n    _Out_writes_bytes_to_opt_(BufferLength, *ReturnLength) PTOKEN_PRIVILEGES PreviousState,\n    _Out_ _When_(PreviousState == NULL, _Out_opt_) PULONG ReturnLength\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nZwAdjustTokenClaimsAndDeviceGroups(\n    _In_ HANDLE TokenHandle,\n    _In_ BOOLEAN UserResetToDefault,\n    _In_ BOOLEAN DeviceResetToDefault,\n    _In_ BOOLEAN DeviceGroupsResetToDefault,\n    _In_opt_ PTOKEN_SECURITY_ATTRIBUTES_INFORMATION NewUserState,\n    _In_opt_ PTOKEN_SECURITY_ATTRIBUTES_INFORMATION NewDeviceState,\n    _In_opt_ PTOKEN_GROUPS NewDeviceGroupsState,\n    _In_ ULONG UserBufferLength,\n    _Out_writes_bytes_to_opt_(UserBufferLength, *UserReturnLength) PTOKEN_SECURITY_ATTRIBUTES_INFORMATION PreviousUserState,\n    _In_ ULONG DeviceBufferLength,\n    _Out_writes_bytes_to_opt_(DeviceBufferLength, *DeviceReturnLength) PTOKEN_SECURITY_ATTRIBUTES_INFORMATION PreviousDeviceState,\n    _In_ ULONG DeviceGroupsBufferLength,\n    _Out_writes_bytes_to_opt_(DeviceGroupsBufferLength, *DeviceGroupsReturnBufferLength) PTOKEN_GROUPS PreviousDeviceGroups,\n    _Out_opt_ PULONG UserReturnLength,\n    _Out_opt_ PULONG DeviceReturnLength,\n    _Out_opt_ PULONG DeviceGroupsReturnBufferLength\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nZwAlertResumeThread(\n    _In_ HANDLE ThreadHandle,\n    _Out_opt_ PULONG PreviousSuspendCount\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nZwAlertThread(\n    _In_ HANDLE ThreadHandle\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nZwAlertThreadByThreadId(\n    _In_ HANDLE ThreadId\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nZwAllocateLocallyUniqueId(\n    _Out_ PLUID Luid\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nZwAllocateReserveObject(\n    _Out_ PHANDLE MemoryReserveHandle,\n    _In_ POBJECT_ATTRIBUTES ObjectAttributes,\n    _In_ MEMORY_RESERVE_TYPE Type\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nZwAllocateUserPhysicalPages(\n    _In_ HANDLE ProcessHandle,\n    _Inout_ PULONG_PTR NumberOfPages,\n    _Out_writes_(*NumberOfPages) PULONG_PTR UserPfnArray\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nZwAllocateUuids(\n    _Out_ PULARGE_INTEGER Time,\n    _Out_ PULONG Range,\n    _Out_ PULONG Sequence,\n    _Out_ PCHAR Seed\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nZwAllocateVirtualMemory(\n    _In_ HANDLE ProcessHandle,\n    _Inout_ _At_(*BaseAddress, _Readable_bytes_(*RegionSize) _Writable_bytes_(*RegionSize) _Post_readable_byte_size_(*RegionSize)) PVOID *BaseAddress,\n    _In_ ULONG_PTR ZeroBits,\n    _Inout_ PSIZE_T RegionSize,\n    _In_ ULONG AllocationType,\n    _In_ ULONG Protect\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nZwAlpcAcceptConnectPort(\n    _Out_ PHANDLE PortHandle,\n    _In_ HANDLE ConnectionPortHandle,\n    _In_ ULONG Flags,\n    _In_opt_ POBJECT_ATTRIBUTES ObjectAttributes,\n    _In_opt_ PALPC_PORT_ATTRIBUTES PortAttributes,\n    _In_opt_ PVOID PortContext,\n    _In_reads_bytes_(ConnectionRequest->u1.s1.TotalLength) PPORT_MESSAGE ConnectionRequest,\n    _Inout_opt_ PALPC_MESSAGE_ATTRIBUTES ConnectionMessageAttributes,\n    _In_ BOOLEAN AcceptConnection\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nZwAlpcCancelMessage(\n    _In_ HANDLE PortHandle,\n    _In_ ULONG Flags,\n    _In_ PALPC_CONTEXT_ATTR MessageContext\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nZwAlpcConnectPort(\n    _Out_ PHANDLE PortHandle,\n    _In_ PUNICODE_STRING PortName,\n    _In_opt_ POBJECT_ATTRIBUTES ObjectAttributes,\n    _In_opt_ PALPC_PORT_ATTRIBUTES PortAttributes,\n    _In_ ULONG Flags,\n    _In_opt_ PSID RequiredServerSid,\n    _Inout_updates_bytes_to_opt_(*BufferLength, *BufferLength) PPORT_MESSAGE ConnectionMessage,\n    _Inout_opt_ PULONG BufferLength,\n    _Inout_opt_ PALPC_MESSAGE_ATTRIBUTES OutMessageAttributes,\n    _Inout_opt_ PALPC_MESSAGE_ATTRIBUTES InMessageAttributes,\n    _In_opt_ PLARGE_INTEGER Timeout\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nZwAlpcConnectPortEx(\n    _Out_ PHANDLE PortHandle,\n    _In_ POBJECT_ATTRIBUTES ConnectionPortObjectAttributes,\n    _In_opt_ POBJECT_ATTRIBUTES ClientPortObjectAttributes,\n    _In_opt_ PALPC_PORT_ATTRIBUTES PortAttributes,\n    _In_ ULONG Flags,\n    _In_opt_ PSECURITY_DESCRIPTOR ServerSecurityRequirements,\n    _Inout_updates_bytes_to_opt_(*BufferLength, *BufferLength) PPORT_MESSAGE ConnectionMessage,\n    _Inout_opt_ PSIZE_T BufferLength,\n    _Inout_opt_ PALPC_MESSAGE_ATTRIBUTES OutMessageAttributes,\n    _Inout_opt_ PALPC_MESSAGE_ATTRIBUTES InMessageAttributes,\n    _In_opt_ PLARGE_INTEGER Timeout\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nZwAlpcCreatePort(\n    _Out_ PHANDLE PortHandle,\n    _In_opt_ POBJECT_ATTRIBUTES ObjectAttributes,\n    _In_opt_ PALPC_PORT_ATTRIBUTES PortAttributes\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nZwAlpcCreatePortSection(\n    _In_ HANDLE PortHandle,\n    _In_ ULONG Flags,\n    _In_opt_ HANDLE SectionHandle,\n    _In_ SIZE_T SectionSize,\n    _Out_ PALPC_HANDLE AlpcSectionHandle,\n    _Out_ PSIZE_T ActualSectionSize\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nZwAlpcCreateResourceReserve(\n    _In_ HANDLE PortHandle,\n    _Reserved_ ULONG Flags,\n    _In_ SIZE_T MessageSize,\n    _Out_ PALPC_HANDLE ResourceId\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nZwAlpcCreateSectionView(\n    _In_ HANDLE PortHandle,\n    _Reserved_ ULONG Flags,\n    _Inout_ PALPC_DATA_VIEW_ATTR ViewAttributes\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nZwAlpcCreateSecurityContext(\n    _In_ HANDLE PortHandle,\n    _Reserved_ ULONG Flags,\n    _Inout_ PALPC_SECURITY_ATTR SecurityAttribute\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nZwAlpcDeletePortSection(\n    _In_ HANDLE PortHandle,\n    _Reserved_ ULONG Flags,\n    _In_ ALPC_HANDLE SectionHandle\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nZwAlpcDeleteResourceReserve(\n    _In_ HANDLE PortHandle,\n    _Reserved_ ULONG Flags,\n    _In_ ALPC_HANDLE ResourceId\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nZwAlpcDeleteSectionView(\n    _In_ HANDLE PortHandle,\n    _Reserved_ ULONG Flags,\n    _In_ PVOID ViewBase\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nZwAlpcDeleteSecurityContext(\n    _In_ HANDLE PortHandle,\n    _Reserved_ ULONG Flags,\n    _In_ ALPC_HANDLE ContextHandle\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nZwAlpcDisconnectPort(\n    _In_ HANDLE PortHandle,\n    _In_ ULONG Flags\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nZwAlpcImpersonateClientContainerOfPort(\n    _In_ HANDLE PortHandle,\n    _In_ PPORT_MESSAGE Message,\n    _In_ ULONG Flags\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nZwAlpcImpersonateClientOfPort(\n    _In_ HANDLE PortHandle,\n    _In_ PPORT_MESSAGE Message,\n    _In_ PVOID Flags\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nZwAlpcOpenSenderProcess(\n    _Out_ PHANDLE ProcessHandle,\n    _In_ HANDLE PortHandle,\n    _In_ PPORT_MESSAGE PortMessage,\n    _In_ ULONG Flags,\n    _In_ ACCESS_MASK DesiredAccess,\n    _In_ POBJECT_ATTRIBUTES ObjectAttributes\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nZwAlpcOpenSenderThread(\n    _Out_ PHANDLE ThreadHandle,\n    _In_ HANDLE PortHandle,\n    _In_ PPORT_MESSAGE PortMessage,\n    _In_ ULONG Flags,\n    _In_ ACCESS_MASK DesiredAccess,\n    _In_ POBJECT_ATTRIBUTES ObjectAttributes\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nZwAlpcQueryInformation(\n    _In_opt_ HANDLE PortHandle,\n    _In_ ALPC_PORT_INFORMATION_CLASS PortInformationClass,\n    _Inout_updates_bytes_to_(Length, *ReturnLength) PVOID PortInformation,\n    _In_ ULONG Length,\n    _Out_opt_ PULONG ReturnLength\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nZwAlpcQueryInformationMessage(\n    _In_ HANDLE PortHandle,\n    _In_ PPORT_MESSAGE PortMessage,\n    _In_ ALPC_MESSAGE_INFORMATION_CLASS MessageInformationClass,\n    _Out_writes_bytes_to_opt_(Length, *ReturnLength) PVOID MessageInformation,\n    _In_ ULONG Length,\n    _Out_opt_ PULONG ReturnLength\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nZwAlpcRevokeSecurityContext(\n    _In_ HANDLE PortHandle,\n    _Reserved_ ULONG Flags,\n    _In_ ALPC_HANDLE ContextHandle\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nZwAlpcSendWaitReceivePort(\n    _In_ HANDLE PortHandle,\n    _In_ ULONG Flags,\n    _In_reads_bytes_opt_(SendMessage->u1.s1.TotalLength) PPORT_MESSAGE SendMessage,\n    _Inout_opt_ PALPC_MESSAGE_ATTRIBUTES SendMessageAttributes,\n    _Out_writes_bytes_to_opt_(*BufferLength, *BufferLength) PPORT_MESSAGE ReceiveMessage,\n    _Inout_opt_ PSIZE_T BufferLength,\n    _Inout_opt_ PALPC_MESSAGE_ATTRIBUTES ReceiveMessageAttributes,\n    _In_opt_ PLARGE_INTEGER Timeout\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nZwAlpcSetInformation(\n    _In_ HANDLE PortHandle,\n    _In_ ALPC_PORT_INFORMATION_CLASS PortInformationClass,\n    _In_reads_bytes_opt_(Length) PVOID PortInformation,\n    _In_ ULONG Length\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nZwAreMappedFilesTheSame(\n    _In_ PVOID File1MappedAsAnImage,\n    _In_ PVOID File2MappedAsFile\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nZwAssignProcessToJobObject(\n    _In_ HANDLE JobHandle,\n    _In_ HANDLE ProcessHandle\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nZwAssociateWaitCompletionPacket(\n    _In_ HANDLE WaitCompletionPacketHandle,\n    _In_ HANDLE IoCompletionHandle,\n    _In_ HANDLE TargetObjectHandle,\n    _In_opt_ PVOID KeyContext,\n    _In_opt_ PVOID ApcContext,\n    _In_ NTSTATUS IoStatus,\n    _In_ ULONG_PTR IoStatusInformation,\n    _Out_opt_ PBOOLEAN AlreadySignaled\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nZwCallbackReturn(\n    _In_reads_bytes_opt_(OutputLength) PVOID OutputBuffer,\n    _In_ ULONG OutputLength,\n    _In_ NTSTATUS Status\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nZwCancelIoFile(\n    _In_ HANDLE FileHandle,\n    _Out_ PIO_STATUS_BLOCK IoStatusBlock\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nZwCancelIoFileEx(\n    _In_ HANDLE FileHandle,\n    _In_opt_ PIO_STATUS_BLOCK IoRequestToCancel,\n    _Out_ PIO_STATUS_BLOCK IoStatusBlock\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nZwCancelSynchronousIoFile(\n    _In_ HANDLE ThreadHandle,\n    _In_opt_ PIO_STATUS_BLOCK IoRequestToCancel,\n    _Out_ PIO_STATUS_BLOCK IoStatusBlock\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nZwCancelTimer(\n    _In_ HANDLE TimerHandle,\n    _Out_opt_ PBOOLEAN CurrentState\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nZwCancelTimer2(\n    _In_ HANDLE TimerHandle,\n    _In_ PT2_CANCEL_PARAMETERS Parameters\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nZwCancelWaitCompletionPacket(\n    _In_ HANDLE WaitCompletionPacketHandle,\n    _In_ BOOLEAN RemoveSignaledPacket\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nZwClearEvent(\n    _In_ HANDLE EventHandle\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nZwClose(\n    _In_ HANDLE Handle\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nZwCloseObjectAuditAlarm(\n    _In_ PUNICODE_STRING SubsystemName,\n    _In_opt_ PVOID HandleId,\n    _In_ BOOLEAN GenerateOnClose\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nZwCommitComplete(\n    _In_ HANDLE EnlistmentHandle,\n    _In_opt_ PLARGE_INTEGER TmVirtualClock\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nZwCommitEnlistment(\n    _In_ HANDLE EnlistmentHandle,\n    _In_opt_ PLARGE_INTEGER TmVirtualClock\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nZwCommitTransaction(\n    _In_ HANDLE TransactionHandle,\n    _In_ BOOLEAN Wait\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nZwCompactKeys(\n    _In_ ULONG Count,\n    _In_reads_(Count) HANDLE KeyArray[]\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nZwCompareObjects(\n    _In_ HANDLE FirstObjectHandle,\n    _In_ HANDLE SecondObjectHandle\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nZwCompareTokens(\n    _In_ HANDLE FirstTokenHandle,\n    _In_ HANDLE SecondTokenHandle,\n    _Out_ PBOOLEAN Equal\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nZwCompleteConnectPort(\n    _In_ HANDLE PortHandle\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nZwCompressKey(\n    _In_ HANDLE Key\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nZwConnectPort(\n    _Out_ PHANDLE PortHandle,\n    _In_ PUNICODE_STRING PortName,\n    _In_ PSECURITY_QUALITY_OF_SERVICE SecurityQos,\n    _Inout_opt_ PPORT_VIEW ClientView,\n    _Inout_opt_ PREMOTE_PORT_VIEW ServerView,\n    _Out_opt_ PULONG MaxMessageLength,\n    _Inout_updates_bytes_to_opt_(*ConnectionInformationLength, *ConnectionInformationLength) PVOID ConnectionInformation,\n    _Inout_opt_ PULONG ConnectionInformationLength\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nZwContinue(\n    _In_ PCONTEXT ContextRecord,\n    _In_ BOOLEAN TestAlert\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nZwCreateDebugObject(\n    _Out_ PHANDLE DebugObjectHandle,\n    _In_ ACCESS_MASK DesiredAccess,\n    _In_ POBJECT_ATTRIBUTES ObjectAttributes,\n    _In_ ULONG Flags\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nZwCreateDirectoryObject(\n    _Out_ PHANDLE DirectoryHandle,\n    _In_ ACCESS_MASK DesiredAccess,\n    _In_ POBJECT_ATTRIBUTES ObjectAttributes\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nZwCreateDirectoryObjectEx(\n    _Out_ PHANDLE DirectoryHandle,\n    _In_ ACCESS_MASK DesiredAccess,\n    _In_ POBJECT_ATTRIBUTES ObjectAttributes,\n    _In_ HANDLE ShadowDirectoryHandle,\n    _In_ ULONG Flags\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nZwCreateEnlistment(\n    _Out_ PHANDLE EnlistmentHandle,\n    _In_ ACCESS_MASK DesiredAccess,\n    _In_ HANDLE ResourceManagerHandle,\n    _In_ HANDLE TransactionHandle,\n    _In_opt_ POBJECT_ATTRIBUTES ObjectAttributes,\n    _In_opt_ ULONG CreateOptions,\n    _In_ NOTIFICATION_MASK NotificationMask,\n    _In_opt_ PVOID EnlistmentKey\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nZwCreateEvent(\n    _Out_ PHANDLE EventHandle,\n    _In_ ACCESS_MASK DesiredAccess,\n    _In_opt_ POBJECT_ATTRIBUTES ObjectAttributes,\n    _In_ EVENT_TYPE EventType,\n    _In_ BOOLEAN InitialState\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nZwCreateEventPair(\n    _Out_ PHANDLE EventPairHandle,\n    _In_ ACCESS_MASK DesiredAccess,\n    _In_opt_ POBJECT_ATTRIBUTES ObjectAttributes\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nZwCreateFile(\n    _Out_ PHANDLE FileHandle,\n    _In_ ACCESS_MASK DesiredAccess,\n    _In_ POBJECT_ATTRIBUTES ObjectAttributes,\n    _Out_ PIO_STATUS_BLOCK IoStatusBlock,\n    _In_opt_ PLARGE_INTEGER AllocationSize,\n    _In_ ULONG FileAttributes,\n    _In_ ULONG ShareAccess,\n    _In_ ULONG CreateDisposition,\n    _In_ ULONG CreateOptions,\n    _In_reads_bytes_opt_(EaLength) PVOID EaBuffer,\n    _In_ ULONG EaLength\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nZwCreateIRTimer(\n    _Out_ PHANDLE TimerHandle,\n    _In_ ACCESS_MASK DesiredAccess\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nZwCreateIoCompletion(\n    _Out_ PHANDLE IoCompletionHandle,\n    _In_ ACCESS_MASK DesiredAccess,\n    _In_opt_ POBJECT_ATTRIBUTES ObjectAttributes,\n    _In_opt_ ULONG Count\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nZwCreateJobObject(\n    _Out_ PHANDLE JobHandle,\n    _In_ ACCESS_MASK DesiredAccess,\n    _In_opt_ POBJECT_ATTRIBUTES ObjectAttributes\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nZwCreateJobSet(\n    _In_ ULONG NumJob,\n    _In_reads_(NumJob) PJOB_SET_ARRAY UserJobSet,\n    _In_ ULONG Flags\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nZwCreateKey(\n    _Out_ PHANDLE KeyHandle,\n    _In_ ACCESS_MASK DesiredAccess,\n    _In_ POBJECT_ATTRIBUTES ObjectAttributes,\n    _Reserved_ ULONG TitleIndex,\n    _In_opt_ PUNICODE_STRING Class,\n    _In_ ULONG CreateOptions,\n    _Out_opt_ PULONG Disposition\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nZwCreateKeyTransacted(\n    _Out_ PHANDLE KeyHandle,\n    _In_ ACCESS_MASK DesiredAccess,\n    _In_ POBJECT_ATTRIBUTES ObjectAttributes,\n    _Reserved_ ULONG TitleIndex,\n    _In_opt_ PUNICODE_STRING Class,\n    _In_ ULONG CreateOptions,\n    _In_ HANDLE TransactionHandle,\n    _Out_opt_ PULONG Disposition\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nZwCreateKeyedEvent(\n    _Out_ PHANDLE KeyedEventHandle,\n    _In_ ACCESS_MASK DesiredAccess,\n    _In_opt_ POBJECT_ATTRIBUTES ObjectAttributes,\n    _In_ ULONG Flags\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nZwCreateLowBoxToken(\n    _Out_ PHANDLE TokenHandle,\n    _In_ HANDLE ExistingTokenHandle,\n    _In_ ACCESS_MASK DesiredAccess,\n    _In_opt_ POBJECT_ATTRIBUTES ObjectAttributes,\n    _In_ PSID PackageSid,\n    _In_ ULONG CapabilityCount,\n    _In_reads_opt_(CapabilityCount) PSID_AND_ATTRIBUTES Capabilities,\n    _In_ ULONG HandleCount,\n    _In_reads_opt_(HandleCount) HANDLE *Handles\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nZwCreateMailslotFile(\n    _Out_ PHANDLE FileHandle,\n    _In_ ULONG DesiredAccess,\n    _In_ POBJECT_ATTRIBUTES ObjectAttributes,\n    _Out_ PIO_STATUS_BLOCK IoStatusBlock,\n    _In_ ULONG CreateOptions,\n    _In_ ULONG MailslotQuota,\n    _In_ ULONG MaximumMessageSize,\n    _In_ PLARGE_INTEGER ReadTimeout\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nZwCreateMutant(\n    _Out_ PHANDLE MutantHandle,\n    _In_ ACCESS_MASK DesiredAccess,\n    _In_opt_ POBJECT_ATTRIBUTES ObjectAttributes,\n    _In_ BOOLEAN InitialOwner\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nZwCreateNamedPipeFile(\n    _Out_ PHANDLE FileHandle,\n    _In_ ULONG DesiredAccess,\n    _In_ POBJECT_ATTRIBUTES ObjectAttributes,\n    _Out_ PIO_STATUS_BLOCK IoStatusBlock,\n    _In_ ULONG ShareAccess,\n    _In_ ULONG CreateDisposition,\n    _In_ ULONG CreateOptions,\n    _In_ ULONG NamedPipeType,\n    _In_ ULONG ReadMode,\n    _In_ ULONG CompletionMode,\n    _In_ ULONG MaximumInstances,\n    _In_ ULONG InboundQuota,\n    _In_ ULONG OutboundQuota,\n    _In_opt_ PLARGE_INTEGER DefaultTimeout\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nZwCreatePagingFile(\n    _In_ PUNICODE_STRING PageFileName,\n    _In_ PLARGE_INTEGER MinimumSize,\n    _In_ PLARGE_INTEGER MaximumSize,\n    _In_ ULONG Priority\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nZwCreatePartition(\n    _Out_ PHANDLE PartitionHandle,\n    _In_ ACCESS_MASK DesiredAccess,\n    _In_opt_ POBJECT_ATTRIBUTES ObjectAttributes,\n    _In_ ULONG PreferredNode\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nZwCreatePort(\n    _Out_ PHANDLE PortHandle,\n    _In_opt_ POBJECT_ATTRIBUTES ObjectAttributes,\n    _In_ ULONG MaxConnectionInfoLength,\n    _In_ ULONG MaxMessageLength,\n    _In_opt_ ULONG MaxPoolUsage\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nZwCreatePrivateNamespace(\n    _Out_ PHANDLE NamespaceHandle,\n    _In_ ACCESS_MASK DesiredAccess,\n    _In_ POBJECT_ATTRIBUTES ObjectAttributes,\n    _In_ PVOID BoundaryDescriptor\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nZwCreateProcess(\n    _Out_ PHANDLE ProcessHandle,\n    _In_ ACCESS_MASK DesiredAccess,\n    _In_opt_ POBJECT_ATTRIBUTES ObjectAttributes,\n    _In_ HANDLE ParentProcess,\n    _In_ BOOLEAN InheritObjectTable,\n    _In_opt_ HANDLE SectionHandle,\n    _In_opt_ HANDLE DebugPort,\n    _In_opt_ HANDLE ExceptionPort\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nZwCreateProcessEx(\n    _Out_ PHANDLE ProcessHandle,\n    _In_ ACCESS_MASK DesiredAccess,\n    _In_opt_ POBJECT_ATTRIBUTES ObjectAttributes,\n    _In_ HANDLE ParentProcess,\n    _In_ ULONG Flags,\n    _In_opt_ HANDLE SectionHandle,\n    _In_opt_ HANDLE DebugPort,\n    _In_opt_ HANDLE ExceptionPort,\n    _In_ ULONG JobMemberLevel\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nZwCreateProfile(\n    _Out_ PHANDLE ProfileHandle,\n    _In_opt_ HANDLE Process,\n    _In_ PVOID ProfileBase,\n    _In_ SIZE_T ProfileSize,\n    _In_ ULONG BucketSize,\n    _In_reads_bytes_(BufferSize) PULONG Buffer,\n    _In_ ULONG BufferSize,\n    _In_ KPROFILE_SOURCE ProfileSource,\n    _In_ KAFFINITY Affinity\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nZwCreateProfileEx(\n    _Out_ PHANDLE ProfileHandle,\n    _In_opt_ HANDLE Process,\n    _In_ PVOID ProfileBase,\n    _In_ SIZE_T ProfileSize,\n    _In_ ULONG BucketSize,\n    _In_reads_bytes_(BufferSize) PULONG Buffer,\n    _In_ ULONG BufferSize,\n    _In_ KPROFILE_SOURCE ProfileSource,\n    _In_ USHORT GroupCount,\n    _In_reads_(GroupCount) PGROUP_AFFINITY GroupAffinity\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nZwCreateResourceManager(\n    _Out_ PHANDLE ResourceManagerHandle,\n    _In_ ACCESS_MASK DesiredAccess,\n    _In_ HANDLE TmHandle,\n    _In_ LPGUID RmGuid,\n    _In_opt_ POBJECT_ATTRIBUTES ObjectAttributes,\n    _In_opt_ ULONG CreateOptions,\n    _In_opt_ PUNICODE_STRING Description\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nZwCreateSection(\n    _Out_ PHANDLE SectionHandle,\n    _In_ ACCESS_MASK DesiredAccess,\n    _In_opt_ POBJECT_ATTRIBUTES ObjectAttributes,\n    _In_opt_ PLARGE_INTEGER MaximumSize,\n    _In_ ULONG SectionPageProtection,\n    _In_ ULONG AllocationAttributes,\n    _In_opt_ HANDLE FileHandle\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nZwCreateSemaphore(\n    _Out_ PHANDLE SemaphoreHandle,\n    _In_ ACCESS_MASK DesiredAccess,\n    _In_opt_ POBJECT_ATTRIBUTES ObjectAttributes,\n    _In_ LONG InitialCount,\n    _In_ LONG MaximumCount\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nZwCreateSymbolicLinkObject(\n    _Out_ PHANDLE LinkHandle,\n    _In_ ACCESS_MASK DesiredAccess,\n    _In_ POBJECT_ATTRIBUTES ObjectAttributes,\n    _In_ PUNICODE_STRING LinkTarget\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nZwCreateThread(\n    _Out_ PHANDLE ThreadHandle,\n    _In_ ACCESS_MASK DesiredAccess,\n    _In_opt_ POBJECT_ATTRIBUTES ObjectAttributes,\n    _In_ HANDLE ProcessHandle,\n    _Out_ PCLIENT_ID ClientId,\n    _In_ PCONTEXT ThreadContext,\n    _In_ PINITIAL_TEB InitialTeb,\n    _In_ BOOLEAN CreateSuspended\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nZwCreateThreadEx(\n    _Out_ PHANDLE ThreadHandle,\n    _In_ ACCESS_MASK DesiredAccess,\n    _In_opt_ POBJECT_ATTRIBUTES ObjectAttributes,\n    _In_ HANDLE ProcessHandle,\n    _In_ PVOID StartRoutine, // PUSER_THREAD_START_ROUTINE\n    _In_opt_ PVOID Argument,\n    _In_ ULONG CreateFlags, // THREAD_CREATE_FLAGS_*\n    _In_ SIZE_T ZeroBits,\n    _In_ SIZE_T StackSize,\n    _In_ SIZE_T MaximumStackSize,\n    _In_opt_ PPS_ATTRIBUTE_LIST AttributeList\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nZwCreateTimer(\n    _Out_ PHANDLE TimerHandle,\n    _In_ ACCESS_MASK DesiredAccess,\n    _In_opt_ POBJECT_ATTRIBUTES ObjectAttributes,\n    _In_ TIMER_TYPE TimerType\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nZwCreateTimer2(\n    _Out_ PHANDLE TimerHandle,\n    _In_opt_ PVOID Reserved1,\n    _In_opt_ PVOID Reserved2,\n    _In_ ULONG Attributes,\n    _In_ ACCESS_MASK DesiredAccess\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nZwCreateToken(\n    _Out_ PHANDLE TokenHandle,\n    _In_ ACCESS_MASK DesiredAccess,\n    _In_opt_ POBJECT_ATTRIBUTES ObjectAttributes,\n    _In_ TOKEN_TYPE TokenType,\n    _In_ PLUID AuthenticationId,\n    _In_ PLARGE_INTEGER ExpirationTime,\n    _In_ PTOKEN_USER User,\n    _In_ PTOKEN_GROUPS Groups,\n    _In_ PTOKEN_PRIVILEGES Privileges,\n    _In_opt_ PTOKEN_OWNER Owner,\n    _In_ PTOKEN_PRIMARY_GROUP PrimaryGroup,\n    _In_opt_ PTOKEN_DEFAULT_DACL DefaultDacl,\n    _In_ PTOKEN_SOURCE TokenSource\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nZwCreateTokenEx(\n    _Out_ PHANDLE TokenHandle,\n    _In_ ACCESS_MASK DesiredAccess,\n    _In_opt_ POBJECT_ATTRIBUTES ObjectAttributes,\n    _In_ TOKEN_TYPE TokenType,\n    _In_ PLUID AuthenticationId,\n    _In_ PLARGE_INTEGER ExpirationTime,\n    _In_ PTOKEN_USER User,\n    _In_ PTOKEN_GROUPS Groups,\n    _In_ PTOKEN_PRIVILEGES Privileges,\n    _In_opt_ PTOKEN_SECURITY_ATTRIBUTES_INFORMATION UserAttributes,\n    _In_opt_ PTOKEN_SECURITY_ATTRIBUTES_INFORMATION DeviceAttributes,\n    _In_opt_ PTOKEN_GROUPS DeviceGroups,\n    _In_opt_ PTOKEN_MANDATORY_POLICY TokenMandatoryPolicy,\n    _In_opt_ PTOKEN_OWNER Owner,\n    _In_ PTOKEN_PRIMARY_GROUP PrimaryGroup,\n    _In_opt_ PTOKEN_DEFAULT_DACL DefaultDacl,\n    _In_ PTOKEN_SOURCE TokenSource\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nZwCreateTransaction(\n    _Out_ PHANDLE TransactionHandle,\n    _In_ ACCESS_MASK DesiredAccess,\n    _In_opt_ POBJECT_ATTRIBUTES ObjectAttributes,\n    _In_opt_ LPGUID Uow,\n    _In_opt_ HANDLE TmHandle,\n    _In_opt_ ULONG CreateOptions,\n    _In_opt_ ULONG IsolationLevel,\n    _In_opt_ ULONG IsolationFlags,\n    _In_opt_ PLARGE_INTEGER Timeout,\n    _In_opt_ PUNICODE_STRING Description\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nZwCreateTransactionManager(\n    _Out_ PHANDLE TmHandle,\n    _In_ ACCESS_MASK DesiredAccess,\n    _In_opt_ POBJECT_ATTRIBUTES ObjectAttributes,\n    _In_opt_ PUNICODE_STRING LogFileName,\n    _In_opt_ ULONG CreateOptions,\n    _In_opt_ ULONG CommitStrength\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nZwCreateUserProcess(\n    _Out_ PHANDLE ProcessHandle,\n    _Out_ PHANDLE ThreadHandle,\n    _In_ ACCESS_MASK ProcessDesiredAccess,\n    _In_ ACCESS_MASK ThreadDesiredAccess,\n    _In_opt_ POBJECT_ATTRIBUTES ProcessObjectAttributes,\n    _In_opt_ POBJECT_ATTRIBUTES ThreadObjectAttributes,\n    _In_ ULONG ProcessFlags, // PROCESS_CREATE_FLAGS_*\n    _In_ ULONG ThreadFlags, // THREAD_CREATE_FLAGS_*\n    _In_opt_ PVOID ProcessParameters, // PRTL_USER_PROCESS_PARAMETERS\n    _Inout_ PPS_CREATE_INFO CreateInfo,\n    _In_opt_ PPS_ATTRIBUTE_LIST AttributeList\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nZwCreateWaitCompletionPacket(\n    _Out_ PHANDLE WaitCompletionPacketHandle,\n    _In_ ACCESS_MASK DesiredAccess,\n    _In_opt_ POBJECT_ATTRIBUTES ObjectAttributes\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nZwCreateWaitablePort(\n    _Out_ PHANDLE PortHandle,\n    _In_opt_ POBJECT_ATTRIBUTES ObjectAttributes,\n    _In_ ULONG MaxConnectionInfoLength,\n    _In_ ULONG MaxMessageLength,\n    _In_opt_ ULONG MaxPoolUsage\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nZwCreateWnfStateName(\n    _Out_ PWNF_STATE_NAME StateName,\n    _In_ WNF_STATE_NAME_LIFETIME NameLifetime,\n    _In_ WNF_DATA_SCOPE DataScope,\n    _In_ BOOLEAN PersistData,\n    _In_opt_ PCWNF_TYPE_ID TypeId,\n    _In_ ULONG MaximumStateSize,\n    _In_ PSECURITY_DESCRIPTOR SecurityDescriptor\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nZwCreateWorkerFactory(\n    _Out_ PHANDLE WorkerFactoryHandleReturn,\n    _In_ ACCESS_MASK DesiredAccess,\n    _In_opt_ POBJECT_ATTRIBUTES ObjectAttributes,\n    _In_ HANDLE CompletionPortHandle,\n    _In_ HANDLE WorkerProcessHandle,\n    _In_ PVOID StartRoutine,\n    _In_opt_ PVOID StartParameter,\n    _In_opt_ ULONG MaxThreadCount,\n    _In_opt_ SIZE_T StackReserve,\n    _In_opt_ SIZE_T StackCommit\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nZwDebugActiveProcess(\n    _In_ HANDLE ProcessHandle,\n    _In_ HANDLE DebugObjectHandle\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nZwDebugContinue(\n    _In_ HANDLE DebugObjectHandle,\n    _In_ PCLIENT_ID ClientId,\n    _In_ NTSTATUS ContinueStatus\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nZwDelayExecution(\n    _In_ BOOLEAN Alertable,\n    _In_ PLARGE_INTEGER DelayInterval\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nZwDeleteAtom(\n    _In_ RTL_ATOM Atom\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nZwDeleteBootEntry(\n    _In_ ULONG Id\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nZwDeleteDriverEntry(\n    _In_ ULONG Id\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nZwDeleteFile(\n    _In_ POBJECT_ATTRIBUTES ObjectAttributes\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nZwDeleteKey(\n    _In_ HANDLE KeyHandle\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nZwDeleteObjectAuditAlarm(\n    _In_ PUNICODE_STRING SubsystemName,\n    _In_opt_ PVOID HandleId,\n    _In_ BOOLEAN GenerateOnClose\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nZwDeletePrivateNamespace(\n    _In_ HANDLE NamespaceHandle\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nZwDeleteValueKey(\n    _In_ HANDLE KeyHandle,\n    _In_ PUNICODE_STRING ValueName\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nZwDeleteWnfStateData(\n    _In_ PCWNF_STATE_NAME StateName,\n    _In_opt_ const VOID *ExplicitScope\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nZwDeleteWnfStateName(\n    _In_ PCWNF_STATE_NAME StateName\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nZwDeviceIoControlFile(\n    _In_ HANDLE FileHandle,\n    _In_opt_ HANDLE Event,\n    _In_opt_ PIO_APC_ROUTINE ApcRoutine,\n    _In_opt_ PVOID ApcContext,\n    _Out_ PIO_STATUS_BLOCK IoStatusBlock,\n    _In_ ULONG IoControlCode,\n    _In_reads_bytes_opt_(InputBufferLength) PVOID InputBuffer,\n    _In_ ULONG InputBufferLength,\n    _Out_writes_bytes_opt_(OutputBufferLength) PVOID OutputBuffer,\n    _In_ ULONG OutputBufferLength\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nZwDisableLastKnownGood(\n    VOID\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nZwDisplayString(\n    _In_ PUNICODE_STRING String\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nZwDrawText(\n    _In_ PUNICODE_STRING String\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nZwDuplicateObject(\n    _In_ HANDLE SourceProcessHandle,\n    _In_ HANDLE SourceHandle,\n    _In_opt_ HANDLE TargetProcessHandle,\n    _Out_opt_ PHANDLE TargetHandle,\n    _In_ ACCESS_MASK DesiredAccess,\n    _In_ ULONG HandleAttributes,\n    _In_ ULONG Options\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nZwDuplicateToken(\n    _In_ HANDLE ExistingTokenHandle,\n    _In_ ACCESS_MASK DesiredAccess,\n    _In_ POBJECT_ATTRIBUTES ObjectAttributes,\n    _In_ BOOLEAN EffectiveOnly,\n    _In_ TOKEN_TYPE TokenType,\n    _Out_ PHANDLE NewTokenHandle\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nZwEnableLastKnownGood(\n    VOID\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nZwEnumerateBootEntries(\n    _Out_writes_bytes_opt_(*BufferLength) PVOID Buffer,\n    _Inout_ PULONG BufferLength\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nZwEnumerateDriverEntries(\n    _Out_writes_bytes_opt_(*BufferLength) PVOID Buffer,\n    _Inout_ PULONG BufferLength\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nZwEnumerateKey(\n    _In_ HANDLE KeyHandle,\n    _In_ ULONG Index,\n    _In_ KEY_INFORMATION_CLASS KeyInformationClass,\n    _Out_writes_bytes_opt_(Length) PVOID KeyInformation,\n    _In_ ULONG Length,\n    _Out_ PULONG ResultLength\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nZwEnumerateSystemEnvironmentValuesEx(\n    _In_ ULONG InformationClass,\n    _Out_ PVOID Buffer,\n    _Inout_ PULONG BufferLength\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nZwEnumerateTransactionObject(\n    _In_opt_ HANDLE RootObjectHandle,\n    _In_ KTMOBJECT_TYPE QueryType,\n    _Inout_updates_bytes_(ObjectCursorLength) PKTMOBJECT_CURSOR ObjectCursor,\n    _In_ ULONG ObjectCursorLength,\n    _Out_ PULONG ReturnLength\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nZwEnumerateValueKey(\n    _In_ HANDLE KeyHandle,\n    _In_ ULONG Index,\n    _In_ KEY_VALUE_INFORMATION_CLASS KeyValueInformationClass,\n    _Out_writes_bytes_opt_(Length) PVOID KeyValueInformation,\n    _In_ ULONG Length,\n    _Out_ PULONG ResultLength\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nZwExtendSection(\n    _In_ HANDLE SectionHandle,\n    _Inout_ PLARGE_INTEGER NewSectionSize\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nZwFilterToken(\n    _In_ HANDLE ExistingTokenHandle,\n    _In_ ULONG Flags,\n    _In_opt_ PTOKEN_GROUPS SidsToDisable,\n    _In_opt_ PTOKEN_PRIVILEGES PrivilegesToDelete,\n    _In_opt_ PTOKEN_GROUPS RestrictedSids,\n    _Out_ PHANDLE NewTokenHandle\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nZwFilterTokenEx(\n    _In_ HANDLE ExistingTokenHandle,\n    _In_ ULONG Flags,\n    _In_opt_ PTOKEN_GROUPS SidsToDisable,\n    _In_opt_ PTOKEN_PRIVILEGES PrivilegesToDelete,\n    _In_opt_ PTOKEN_GROUPS RestrictedSids,\n    _In_ ULONG DisableUserClaimsCount,\n    _In_opt_ PUNICODE_STRING UserClaimsToDisable,\n    _In_ ULONG DisableDeviceClaimsCount,\n    _In_opt_ PUNICODE_STRING DeviceClaimsToDisable,\n    _In_opt_ PTOKEN_GROUPS DeviceGroupsToDisable,\n    _In_opt_ PTOKEN_SECURITY_ATTRIBUTES_INFORMATION RestrictedUserAttributes,\n    _In_opt_ PTOKEN_SECURITY_ATTRIBUTES_INFORMATION RestrictedDeviceAttributes,\n    _In_opt_ PTOKEN_GROUPS RestrictedDeviceGroups,\n    _Out_ PHANDLE NewTokenHandle\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nZwFindAtom(\n    _In_reads_bytes_opt_(Length) PWSTR AtomName,\n    _In_ ULONG Length,\n    _Out_opt_ PRTL_ATOM Atom\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nZwFlushBuffersFile(\n    _In_ HANDLE FileHandle,\n    _Out_ PIO_STATUS_BLOCK IoStatusBlock\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nZwFlushBuffersFileEx(\n    _In_ HANDLE FileHandle,\n    _In_ ULONG Flags,\n    _In_reads_bytes_(ParametersSize) PVOID Parameters,\n    _In_ ULONG ParametersSize,\n    _Out_ PIO_STATUS_BLOCK IoStatusBlock\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nZwFlushInstallUILanguage(\n    _In_ LANGID InstallUILanguage,\n    _In_ ULONG SetComittedFlag\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nZwFlushInstructionCache(\n    _In_ HANDLE ProcessHandle,\n    _In_opt_ PVOID BaseAddress,\n    _In_ SIZE_T Length\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nZwFlushKey(\n    _In_ HANDLE KeyHandle\n    );\n\nNTSYSCALLAPI\nVOID\nNTAPI\nZwFlushProcessWriteBuffers(\n    VOID\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nZwFlushWriteBuffer(\n    VOID\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nZwFreeUserPhysicalPages(\n    _In_ HANDLE ProcessHandle,\n    _Inout_ PULONG_PTR NumberOfPages,\n    _In_reads_(*NumberOfPages) PULONG_PTR UserPfnArray\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nZwFreeVirtualMemory(\n    _In_ HANDLE ProcessHandle,\n    _Inout_ PVOID *BaseAddress,\n    _Inout_ PSIZE_T RegionSize,\n    _In_ ULONG FreeType\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nZwFreezeRegistry(\n    _In_ ULONG TimeOutInSeconds\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nZwFreezeTransactions(\n    _In_ PLARGE_INTEGER FreezeTimeout,\n    _In_ PLARGE_INTEGER ThawTimeout\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nZwFsControlFile(\n    _In_ HANDLE FileHandle,\n    _In_opt_ HANDLE Event,\n    _In_opt_ PIO_APC_ROUTINE ApcRoutine,\n    _In_opt_ PVOID ApcContext,\n    _Out_ PIO_STATUS_BLOCK IoStatusBlock,\n    _In_ ULONG FsControlCode,\n    _In_reads_bytes_opt_(InputBufferLength) PVOID InputBuffer,\n    _In_ ULONG InputBufferLength,\n    _Out_writes_bytes_opt_(OutputBufferLength) PVOID OutputBuffer,\n    _In_ ULONG OutputBufferLength\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nZwGetCachedSigningLevel(\n    _In_ HANDLE File,\n    _Out_ PULONG Flags,\n    _Out_ PSE_SIGNING_LEVEL SigningLevel,\n    _Out_writes_bytes_to_opt_(*ThumbprintSize, *ThumbprintSize) PUCHAR Thumbprint,\n    _Inout_opt_ PULONG ThumbprintSize,\n    _Out_opt_ PULONG ThumbprintAlgorithm\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nZwGetCompleteWnfStateSubscription(\n    _In_opt_ PWNF_STATE_NAME OldDescriptorStateName,\n    _In_opt_ ULONG64 *OldSubscriptionId,\n    _In_opt_ ULONG OldDescriptorEventMask,\n    _In_opt_ ULONG OldDescriptorStatus,\n    _Out_writes_bytes_(DescriptorSize) PWNF_DELIVERY_DESCRIPTOR NewDeliveryDescriptor,\n    _In_ ULONG DescriptorSize\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nZwGetContextThread(\n    _In_ HANDLE ThreadHandle,\n    _Inout_ PCONTEXT ThreadContext\n    );\n\nNTSYSCALLAPI\nULONG\nNTAPI\nZwGetCurrentProcessorNumber(\n    VOID\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nZwGetDevicePowerState(\n    _In_ HANDLE Device,\n    _Out_ PDEVICE_POWER_STATE State\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nZwGetMUIRegistryInfo(\n    _In_ ULONG Flags,\n    _Inout_ PULONG DataSize,\n    _Out_ PVOID Data\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nZwGetNextProcess(\n    _In_ HANDLE ProcessHandle,\n    _In_ ACCESS_MASK DesiredAccess,\n    _In_ ULONG HandleAttributes,\n    _In_ ULONG Flags,\n    _Out_ PHANDLE NewProcessHandle\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nZwGetNextThread(\n    _In_ HANDLE ProcessHandle,\n    _In_ HANDLE ThreadHandle,\n    _In_ ACCESS_MASK DesiredAccess,\n    _In_ ULONG HandleAttributes,\n    _In_ ULONG Flags,\n    _Out_ PHANDLE NewThreadHandle\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nZwGetNlsSectionPtr(\n    _In_ ULONG SectionType,\n    _In_ ULONG SectionData,\n    _In_ PVOID ContextData,\n    _Out_ PVOID *SectionPointer,\n    _Out_ PULONG SectionSize\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nZwGetNotificationResourceManager(\n    _In_ HANDLE ResourceManagerHandle,\n    _Out_ PTRANSACTION_NOTIFICATION TransactionNotification,\n    _In_ ULONG NotificationLength,\n    _In_opt_ PLARGE_INTEGER Timeout,\n    _Out_opt_ PULONG ReturnLength,\n    _In_ ULONG Asynchronous,\n    _In_opt_ ULONG_PTR AsynchronousContext\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nZwGetPlugPlayEvent(\n    _In_ HANDLE EventHandle,\n    _In_opt_ PVOID Context,\n    _Out_writes_bytes_(EventBufferSize) PPLUGPLAY_EVENT_BLOCK EventBlock,\n    _In_ ULONG EventBufferSize\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nZwGetWriteWatch(\n    _In_ HANDLE ProcessHandle,\n    _In_ ULONG Flags,\n    _In_ PVOID BaseAddress,\n    _In_ SIZE_T RegionSize,\n    _Out_writes_(*EntriesInUserAddressArray) PVOID *UserAddressArray,\n    _Inout_ PULONG_PTR EntriesInUserAddressArray,\n    _Out_ PULONG Granularity\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nZwImpersonateAnonymousToken(\n    _In_ HANDLE ThreadHandle\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nZwImpersonateClientOfPort(\n    _In_ HANDLE PortHandle,\n    _In_ PPORT_MESSAGE Message\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nZwImpersonateThread(\n    _In_ HANDLE ServerThreadHandle,\n    _In_ HANDLE ClientThreadHandle,\n    _In_ PSECURITY_QUALITY_OF_SERVICE SecurityQos\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nZwInitializeNlsFiles(\n    _Out_ PVOID *BaseAddress,\n    _Out_ PLCID DefaultLocaleId,\n    _Out_ PLARGE_INTEGER DefaultCasingTableSize\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nZwInitializeRegistry(\n    _In_ USHORT BootCondition\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nZwInitiatePowerAction(\n    _In_ POWER_ACTION SystemAction,\n    _In_ SYSTEM_POWER_STATE LightestSystemState,\n    _In_ ULONG Flags, // POWER_ACTION_* flags\n    _In_ BOOLEAN Asynchronous\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nZwIsProcessInJob(\n    _In_ HANDLE ProcessHandle,\n    _In_opt_ HANDLE JobHandle\n    );\n\nNTSYSCALLAPI\nBOOLEAN\nNTAPI\nZwIsSystemResumeAutomatic(\n    VOID\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nZwIsUILanguageComitted(\n    VOID\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nZwListenPort(\n    _In_ HANDLE PortHandle,\n    _Out_ PPORT_MESSAGE ConnectionRequest\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nZwLoadDriver(\n    _In_ PUNICODE_STRING DriverServiceName\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nZwLoadKey(\n    _In_ POBJECT_ATTRIBUTES TargetKey,\n    _In_ POBJECT_ATTRIBUTES SourceFile\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nZwLoadKey2(\n    _In_ POBJECT_ATTRIBUTES TargetKey,\n    _In_ POBJECT_ATTRIBUTES SourceFile,\n    _In_ ULONG Flags\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nZwLoadKeyEx(\n    _In_ POBJECT_ATTRIBUTES TargetKey,\n    _In_ POBJECT_ATTRIBUTES SourceFile,\n    _In_ ULONG Flags,\n    _In_opt_ HANDLE TrustClassKey,\n    _In_opt_ HANDLE Event,\n    _In_opt_ ACCESS_MASK DesiredAccess,\n    _Out_opt_ PHANDLE RootHandle,\n    _Out_opt_ PIO_STATUS_BLOCK IoStatus\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nZwLockFile(\n    _In_ HANDLE FileHandle,\n    _In_opt_ HANDLE Event,\n    _In_opt_ PIO_APC_ROUTINE ApcRoutine,\n    _In_opt_ PVOID ApcContext,\n    _Out_ PIO_STATUS_BLOCK IoStatusBlock,\n    _In_ PLARGE_INTEGER ByteOffset,\n    _In_ PLARGE_INTEGER Length,\n    _In_ ULONG Key,\n    _In_ BOOLEAN FailImmediately,\n    _In_ BOOLEAN ExclusiveLock\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nZwLockProductActivationKeys(\n    _Inout_opt_ ULONG *pPrivateVer,\n    _Out_opt_ ULONG *pSafeMode\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nZwLockRegistryKey(\n    _In_ HANDLE KeyHandle\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nZwLockVirtualMemory(\n    _In_ HANDLE ProcessHandle,\n    _Inout_ PVOID *BaseAddress,\n    _Inout_ PSIZE_T RegionSize,\n    _In_ ULONG MapType\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nZwMakePermanentObject(\n    _In_ HANDLE Handle\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nZwMakeTemporaryObject(\n    _In_ HANDLE Handle\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nZwManagePartition(\n    _In_ MEMORY_PARTITION_INFORMATION_CLASS PartitionInformationClass,\n    _In_ PVOID PartitionInformation,\n    _In_ ULONG PartitionInformationLength\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nZwMapCMFModule(\n    _In_ ULONG What,\n    _In_ ULONG Index,\n    _Out_opt_ PULONG CacheIndexOut,\n    _Out_opt_ PULONG CacheFlagsOut,\n    _Out_opt_ PULONG ViewSizeOut,\n    _Out_opt_ PVOID *BaseAddress\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nZwMapUserPhysicalPages(\n    _In_ PVOID VirtualAddress,\n    _In_ ULONG_PTR NumberOfPages,\n    _In_reads_opt_(NumberOfPages) PULONG_PTR UserPfnArray\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nZwMapUserPhysicalPagesScatter(\n    _In_reads_(NumberOfPages) PVOID *VirtualAddresses,\n    _In_ ULONG_PTR NumberOfPages,\n    _In_reads_opt_(NumberOfPages) PULONG_PTR UserPfnArray\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nZwMapViewOfSection(\n    _In_ HANDLE SectionHandle,\n    _In_ HANDLE ProcessHandle,\n    _Inout_ _At_(*BaseAddress, _Readable_bytes_(*ViewSize) _Writable_bytes_(*ViewSize) _Post_readable_byte_size_(*ViewSize)) PVOID *BaseAddress,\n    _In_ ULONG_PTR ZeroBits,\n    _In_ SIZE_T CommitSize,\n    _Inout_opt_ PLARGE_INTEGER SectionOffset,\n    _Inout_ PSIZE_T ViewSize,\n    _In_ SECTION_INHERIT InheritDisposition,\n    _In_ ULONG AllocationType,\n    _In_ ULONG Win32Protect\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nZwModifyBootEntry(\n    _In_ PBOOT_ENTRY BootEntry\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nZwModifyDriverEntry(\n    _In_ PEFI_DRIVER_ENTRY DriverEntry\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nZwNotifyChangeDirectoryFile(\n    _In_ HANDLE FileHandle,\n    _In_opt_ HANDLE Event,\n    _In_opt_ PIO_APC_ROUTINE ApcRoutine,\n    _In_opt_ PVOID ApcContext,\n    _Out_ PIO_STATUS_BLOCK IoStatusBlock,\n    _Out_writes_bytes_(Length) PVOID Buffer, // FILE_NOTIFY_INFORMATION\n    _In_ ULONG Length,\n    _In_ ULONG CompletionFilter,\n    _In_ BOOLEAN WatchTree\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nZwNotifyChangeKey(\n    _In_ HANDLE KeyHandle,\n    _In_opt_ HANDLE Event,\n    _In_opt_ PIO_APC_ROUTINE ApcRoutine,\n    _In_opt_ PVOID ApcContext,\n    _Out_ PIO_STATUS_BLOCK IoStatusBlock,\n    _In_ ULONG CompletionFilter,\n    _In_ BOOLEAN WatchTree,\n    _Out_writes_bytes_opt_(BufferSize) PVOID Buffer,\n    _In_ ULONG BufferSize,\n    _In_ BOOLEAN Asynchronous\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nZwNotifyChangeMultipleKeys(\n    _In_ HANDLE MasterKeyHandle,\n    _In_opt_ ULONG Count,\n    _In_reads_opt_(Count) OBJECT_ATTRIBUTES SubordinateObjects[],\n    _In_opt_ HANDLE Event,\n    _In_opt_ PIO_APC_ROUTINE ApcRoutine,\n    _In_opt_ PVOID ApcContext,\n    _Out_ PIO_STATUS_BLOCK IoStatusBlock,\n    _In_ ULONG CompletionFilter,\n    _In_ BOOLEAN WatchTree,\n    _Out_writes_bytes_opt_(BufferSize) PVOID Buffer,\n    _In_ ULONG BufferSize,\n    _In_ BOOLEAN Asynchronous\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nZwNotifyChangeSession(\n    _In_ HANDLE SessionHandle,\n    _In_ ULONG ChangeSequenceNumber,\n    _In_ PLARGE_INTEGER ChangeTimeStamp,\n    _In_ IO_SESSION_EVENT Event,\n    _In_ IO_SESSION_STATE NewState,\n    _In_ IO_SESSION_STATE PreviousState,\n    _In_reads_bytes_opt_(PayloadSize) PVOID Payload,\n    _In_ ULONG PayloadSize\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nZwOpenDirectoryObject(\n    _Out_ PHANDLE DirectoryHandle,\n    _In_ ACCESS_MASK DesiredAccess,\n    _In_ POBJECT_ATTRIBUTES ObjectAttributes\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nZwOpenEnlistment(\n    _Out_ PHANDLE EnlistmentHandle,\n    _In_ ACCESS_MASK DesiredAccess,\n    _In_ HANDLE ResourceManagerHandle,\n    _In_ LPGUID EnlistmentGuid,\n    _In_opt_ POBJECT_ATTRIBUTES ObjectAttributes\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nZwOpenEvent(\n    _Out_ PHANDLE EventHandle,\n    _In_ ACCESS_MASK DesiredAccess,\n    _In_ POBJECT_ATTRIBUTES ObjectAttributes\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nZwOpenEventPair(\n    _Out_ PHANDLE EventPairHandle,\n    _In_ ACCESS_MASK DesiredAccess,\n    _In_ POBJECT_ATTRIBUTES ObjectAttributes\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nZwOpenFile(\n    _Out_ PHANDLE FileHandle,\n    _In_ ACCESS_MASK DesiredAccess,\n    _In_ POBJECT_ATTRIBUTES ObjectAttributes,\n    _Out_ PIO_STATUS_BLOCK IoStatusBlock,\n    _In_ ULONG ShareAccess,\n    _In_ ULONG OpenOptions\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nZwOpenIoCompletion(\n    _Out_ PHANDLE IoCompletionHandle,\n    _In_ ACCESS_MASK DesiredAccess,\n    _In_ POBJECT_ATTRIBUTES ObjectAttributes\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nZwOpenJobObject(\n    _Out_ PHANDLE JobHandle,\n    _In_ ACCESS_MASK DesiredAccess,\n    _In_ POBJECT_ATTRIBUTES ObjectAttributes\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nZwOpenKey(\n    _Out_ PHANDLE KeyHandle,\n    _In_ ACCESS_MASK DesiredAccess,\n    _In_ POBJECT_ATTRIBUTES ObjectAttributes\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nZwOpenKeyEx(\n    _Out_ PHANDLE KeyHandle,\n    _In_ ACCESS_MASK DesiredAccess,\n    _In_ POBJECT_ATTRIBUTES ObjectAttributes,\n    _In_ ULONG OpenOptions\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nZwOpenKeyTransacted(\n    _Out_ PHANDLE KeyHandle,\n    _In_ ACCESS_MASK DesiredAccess,\n    _In_ POBJECT_ATTRIBUTES ObjectAttributes,\n    _In_ HANDLE TransactionHandle\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nZwOpenKeyTransactedEx(\n    _Out_ PHANDLE KeyHandle,\n    _In_ ACCESS_MASK DesiredAccess,\n    _In_ POBJECT_ATTRIBUTES ObjectAttributes,\n    _In_ ULONG OpenOptions,\n    _In_ HANDLE TransactionHandle\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nZwOpenKeyedEvent(\n    _Out_ PHANDLE KeyedEventHandle,\n    _In_ ACCESS_MASK DesiredAccess,\n    _In_ POBJECT_ATTRIBUTES ObjectAttributes\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nZwOpenMutant(\n    _Out_ PHANDLE MutantHandle,\n    _In_ ACCESS_MASK DesiredAccess,\n    _In_ POBJECT_ATTRIBUTES ObjectAttributes\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nZwOpenObjectAuditAlarm(\n    _In_ PUNICODE_STRING SubsystemName,\n    _In_opt_ PVOID HandleId,\n    _In_ PUNICODE_STRING ObjectTypeName,\n    _In_ PUNICODE_STRING ObjectName,\n    _In_opt_ PSECURITY_DESCRIPTOR SecurityDescriptor,\n    _In_ HANDLE ClientToken,\n    _In_ ACCESS_MASK DesiredAccess,\n    _In_ ACCESS_MASK GrantedAccess,\n    _In_opt_ PPRIVILEGE_SET Privileges,\n    _In_ BOOLEAN ObjectCreation,\n    _In_ BOOLEAN AccessGranted,\n    _Out_ PBOOLEAN GenerateOnClose\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nZwOpenPartition(\n    _Out_ PHANDLE PartitionHandle,\n    _In_ ACCESS_MASK DesiredAccess,\n    _In_ POBJECT_ATTRIBUTES ObjectAttributes\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nZwOpenPrivateNamespace(\n    _Out_ PHANDLE NamespaceHandle,\n    _In_ ACCESS_MASK DesiredAccess,\n    _In_opt_ POBJECT_ATTRIBUTES ObjectAttributes,\n    _In_ PVOID BoundaryDescriptor\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nZwOpenProcess(\n    _Out_ PHANDLE ProcessHandle,\n    _In_ ACCESS_MASK DesiredAccess,\n    _In_ POBJECT_ATTRIBUTES ObjectAttributes,\n    _In_opt_ PCLIENT_ID ClientId\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nZwOpenProcessToken(\n    _In_ HANDLE ProcessHandle,\n    _In_ ACCESS_MASK DesiredAccess,\n    _Out_ PHANDLE TokenHandle\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nZwOpenProcessTokenEx(\n    _In_ HANDLE ProcessHandle,\n    _In_ ACCESS_MASK DesiredAccess,\n    _In_ ULONG HandleAttributes,\n    _Out_ PHANDLE TokenHandle\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nZwOpenResourceManager(\n    _Out_ PHANDLE ResourceManagerHandle,\n    _In_ ACCESS_MASK DesiredAccess,\n    _In_ HANDLE TmHandle,\n    _In_opt_ LPGUID ResourceManagerGuid,\n    _In_opt_ POBJECT_ATTRIBUTES ObjectAttributes\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nZwOpenSection(\n    _Out_ PHANDLE SectionHandle,\n    _In_ ACCESS_MASK DesiredAccess,\n    _In_ POBJECT_ATTRIBUTES ObjectAttributes\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nZwOpenSemaphore(\n    _Out_ PHANDLE SemaphoreHandle,\n    _In_ ACCESS_MASK DesiredAccess,\n    _In_ POBJECT_ATTRIBUTES ObjectAttributes\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nZwOpenSession(\n    _Out_ PHANDLE SessionHandle,\n    _In_ ACCESS_MASK DesiredAccess,\n    _In_ POBJECT_ATTRIBUTES ObjectAttributes\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nZwOpenSymbolicLinkObject(\n    _Out_ PHANDLE LinkHandle,\n    _In_ ACCESS_MASK DesiredAccess,\n    _In_ POBJECT_ATTRIBUTES ObjectAttributes\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nZwOpenThread(\n    _Out_ PHANDLE ThreadHandle,\n    _In_ ACCESS_MASK DesiredAccess,\n    _In_ POBJECT_ATTRIBUTES ObjectAttributes,\n    _In_opt_ PCLIENT_ID ClientId\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nZwOpenThreadToken(\n    _In_ HANDLE ThreadHandle,\n    _In_ ACCESS_MASK DesiredAccess,\n    _In_ BOOLEAN OpenAsSelf,\n    _Out_ PHANDLE TokenHandle\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nZwOpenThreadTokenEx(\n    _In_ HANDLE ThreadHandle,\n    _In_ ACCESS_MASK DesiredAccess,\n    _In_ BOOLEAN OpenAsSelf,\n    _In_ ULONG HandleAttributes,\n    _Out_ PHANDLE TokenHandle\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nZwOpenTimer(\n    _Out_ PHANDLE TimerHandle,\n    _In_ ACCESS_MASK DesiredAccess,\n    _In_ POBJECT_ATTRIBUTES ObjectAttributes\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nZwOpenTransaction(\n    _Out_ PHANDLE TransactionHandle,\n    _In_ ACCESS_MASK DesiredAccess,\n    _In_ POBJECT_ATTRIBUTES ObjectAttributes,\n    _In_ LPGUID Uow,\n    _In_opt_ HANDLE TmHandle\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nZwOpenTransactionManager(\n    _Out_ PHANDLE TmHandle,\n    _In_ ACCESS_MASK DesiredAccess,\n    _In_opt_ POBJECT_ATTRIBUTES ObjectAttributes,\n    _In_opt_ PUNICODE_STRING LogFileName,\n    _In_opt_ LPGUID TmIdentity,\n    _In_opt_ ULONG OpenOptions\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nZwPlugPlayControl(\n    _In_ PLUGPLAY_CONTROL_CLASS PnPControlClass,\n    _Inout_updates_bytes_(PnPControlDataLength) PVOID PnPControlData,\n    _In_ ULONG PnPControlDataLength\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nZwPowerInformation(\n    _In_ POWER_INFORMATION_LEVEL InformationLevel,\n    _In_reads_bytes_opt_(InputBufferLength) PVOID InputBuffer,\n    _In_ ULONG InputBufferLength,\n    _Out_writes_bytes_opt_(OutputBufferLength) PVOID OutputBuffer,\n    _In_ ULONG OutputBufferLength\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nZwPrePrepareComplete(\n    _In_ HANDLE EnlistmentHandle,\n    _In_opt_ PLARGE_INTEGER TmVirtualClock\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nZwPrePrepareEnlistment(\n    _In_ HANDLE EnlistmentHandle,\n    _In_opt_ PLARGE_INTEGER TmVirtualClock\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nZwPrepareComplete(\n    _In_ HANDLE EnlistmentHandle,\n    _In_opt_ PLARGE_INTEGER TmVirtualClock\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nZwPrepareEnlistment(\n    _In_ HANDLE EnlistmentHandle,\n    _In_opt_ PLARGE_INTEGER TmVirtualClock\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nZwPrivilegeCheck(\n    _In_ HANDLE ClientToken,\n    _Inout_ PPRIVILEGE_SET RequiredPrivileges,\n    _Out_ PBOOLEAN Result\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nZwPrivilegeObjectAuditAlarm(\n    _In_ PUNICODE_STRING SubsystemName,\n    _In_opt_ PVOID HandleId,\n    _In_ HANDLE ClientToken,\n    _In_ ACCESS_MASK DesiredAccess,\n    _In_ PPRIVILEGE_SET Privileges,\n    _In_ BOOLEAN AccessGranted\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nZwPrivilegedServiceAuditAlarm(\n    _In_ PUNICODE_STRING SubsystemName,\n    _In_ PUNICODE_STRING ServiceName,\n    _In_ HANDLE ClientToken,\n    _In_ PPRIVILEGE_SET Privileges,\n    _In_ BOOLEAN AccessGranted\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nZwPropagationComplete(\n    _In_ HANDLE ResourceManagerHandle,\n    _In_ ULONG RequestCookie,\n    _In_ ULONG BufferLength,\n    _In_ PVOID Buffer\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nZwPropagationFailed(\n    _In_ HANDLE ResourceManagerHandle,\n    _In_ ULONG RequestCookie,\n    _In_ NTSTATUS PropStatus\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nZwProtectVirtualMemory(\n    _In_ HANDLE ProcessHandle,\n    _Inout_ PVOID *BaseAddress,\n    _Inout_ PSIZE_T RegionSize,\n    _In_ ULONG NewProtect,\n    _Out_ PULONG OldProtect\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nZwPulseEvent(\n    _In_ HANDLE EventHandle,\n    _Out_opt_ PLONG PreviousState\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nZwQueryAttributesFile(\n    _In_ POBJECT_ATTRIBUTES ObjectAttributes,\n    _Out_ PFILE_BASIC_INFORMATION FileInformation\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nZwQueryBootEntryOrder(\n    _Out_writes_opt_(*Count) PULONG Ids,\n    _Inout_ PULONG Count\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nZwQueryBootOptions(\n    _Out_writes_bytes_opt_(*BootOptionsLength) PBOOT_OPTIONS BootOptions,\n    _Inout_ PULONG BootOptionsLength\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nZwQueryDebugFilterState(\n    _In_ ULONG ComponentId,\n    _In_ ULONG Level\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nZwQueryDefaultLocale(\n    _In_ BOOLEAN UserProfile,\n    _Out_ PLCID DefaultLocaleId\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nZwQueryDefaultUILanguage(\n    _Out_ LANGID *DefaultUILanguageId\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nZwQueryDirectoryFile(\n    _In_ HANDLE FileHandle,\n    _In_opt_ HANDLE Event,\n    _In_opt_ PIO_APC_ROUTINE ApcRoutine,\n    _In_opt_ PVOID ApcContext,\n    _Out_ PIO_STATUS_BLOCK IoStatusBlock,\n    _Out_writes_bytes_(Length) PVOID FileInformation,\n    _In_ ULONG Length,\n    _In_ FILE_INFORMATION_CLASS FileInformationClass,\n    _In_ BOOLEAN ReturnSingleEntry,\n    _In_opt_ PUNICODE_STRING FileName,\n    _In_ BOOLEAN RestartScan\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nZwQueryDirectoryObject(\n    _In_ HANDLE DirectoryHandle,\n    _Out_writes_bytes_opt_(Length) PVOID Buffer,\n    _In_ ULONG Length,\n    _In_ BOOLEAN ReturnSingleEntry,\n    _In_ BOOLEAN RestartScan,\n    _Inout_ PULONG Context,\n    _Out_opt_ PULONG ReturnLength\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nZwQueryDriverEntryOrder(\n    _Out_writes_opt_(*Count) PULONG Ids,\n    _Inout_ PULONG Count\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nZwQueryEaFile(\n    _In_ HANDLE FileHandle,\n    _Out_ PIO_STATUS_BLOCK IoStatusBlock,\n    _Out_writes_bytes_(Length) PVOID Buffer,\n    _In_ ULONG Length,\n    _In_ BOOLEAN ReturnSingleEntry,\n    _In_reads_bytes_opt_(EaListLength) PVOID EaList,\n    _In_ ULONG EaListLength,\n    _In_opt_ PULONG EaIndex,\n    _In_ BOOLEAN RestartScan\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nZwQueryEvent(\n    _In_ HANDLE EventHandle,\n    _In_ EVENT_INFORMATION_CLASS EventInformationClass,\n    _Out_writes_bytes_(EventInformationLength) PVOID EventInformation,\n    _In_ ULONG EventInformationLength,\n    _Out_opt_ PULONG ReturnLength\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nZwQueryFullAttributesFile(\n    _In_ POBJECT_ATTRIBUTES ObjectAttributes,\n    _Out_ PFILE_NETWORK_OPEN_INFORMATION FileInformation\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nZwQueryInformationAtom(\n    _In_ RTL_ATOM Atom,\n    _In_ ATOM_INFORMATION_CLASS AtomInformationClass,\n    _Out_writes_bytes_(AtomInformationLength) PVOID AtomInformation,\n    _In_ ULONG AtomInformationLength,\n    _Out_opt_ PULONG ReturnLength\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nZwQueryInformationEnlistment(\n    _In_ HANDLE EnlistmentHandle,\n    _In_ ENLISTMENT_INFORMATION_CLASS EnlistmentInformationClass,\n    _Out_writes_bytes_(EnlistmentInformationLength) PVOID EnlistmentInformation,\n    _In_ ULONG EnlistmentInformationLength,\n    _Out_opt_ PULONG ReturnLength\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nZwQueryInformationFile(\n    _In_ HANDLE FileHandle,\n    _Out_ PIO_STATUS_BLOCK IoStatusBlock,\n    _Out_writes_bytes_(Length) PVOID FileInformation,\n    _In_ ULONG Length,\n    _In_ FILE_INFORMATION_CLASS FileInformationClass\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nZwQueryInformationJobObject(\n    _In_opt_ HANDLE JobHandle,\n    _In_ JOBOBJECTINFOCLASS JobObjectInformationClass,\n    _Out_writes_bytes_(JobObjectInformationLength) PVOID JobObjectInformation,\n    _In_ ULONG JobObjectInformationLength,\n    _Out_opt_ PULONG ReturnLength\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nZwQueryInformationPort(\n    _In_ HANDLE PortHandle,\n    _In_ PORT_INFORMATION_CLASS PortInformationClass,\n    _Out_writes_bytes_to_(Length, *ReturnLength) PVOID PortInformation,\n    _In_ ULONG Length,\n    _Out_opt_ PULONG ReturnLength\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nZwQueryInformationProcess(\n    _In_ HANDLE ProcessHandle,\n    _In_ PROCESSINFOCLASS ProcessInformationClass,\n    _Out_writes_bytes_(ProcessInformationLength) PVOID ProcessInformation,\n    _In_ ULONG ProcessInformationLength,\n    _Out_opt_ PULONG ReturnLength\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nZwQueryInformationResourceManager(\n    _In_ HANDLE ResourceManagerHandle,\n    _In_ RESOURCEMANAGER_INFORMATION_CLASS ResourceManagerInformationClass,\n    _Out_writes_bytes_(ResourceManagerInformationLength) PVOID ResourceManagerInformation,\n    _In_ ULONG ResourceManagerInformationLength,\n    _Out_opt_ PULONG ReturnLength\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nZwQueryInformationThread(\n    _In_ HANDLE ThreadHandle,\n    _In_ THREADINFOCLASS ThreadInformationClass,\n    _Out_writes_bytes_(ThreadInformationLength) PVOID ThreadInformation,\n    _In_ ULONG ThreadInformationLength,\n    _Out_opt_ PULONG ReturnLength\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nZwQueryInformationToken(\n    _In_ HANDLE TokenHandle,\n    _In_ TOKEN_INFORMATION_CLASS TokenInformationClass,\n    _Out_writes_bytes_(TokenInformationLength) PVOID TokenInformation,\n    _In_ ULONG TokenInformationLength,\n    _Out_ PULONG ReturnLength\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nZwQueryInformationTransaction(\n    _In_ HANDLE TransactionHandle,\n    _In_ TRANSACTION_INFORMATION_CLASS TransactionInformationClass,\n    _Out_writes_bytes_(TransactionInformationLength) PVOID TransactionInformation,\n    _In_ ULONG TransactionInformationLength,\n    _Out_opt_ PULONG ReturnLength\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nZwQueryInformationTransactionManager(\n    _In_ HANDLE TransactionManagerHandle,\n    _In_ TRANSACTIONMANAGER_INFORMATION_CLASS TransactionManagerInformationClass,\n    _Out_writes_bytes_(TransactionManagerInformationLength) PVOID TransactionManagerInformation,\n    _In_ ULONG TransactionManagerInformationLength,\n    _Out_opt_ PULONG ReturnLength\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nZwQueryInformationWorkerFactory(\n    _In_ HANDLE WorkerFactoryHandle,\n    _In_ WORKERFACTORYINFOCLASS WorkerFactoryInformationClass,\n    _Out_writes_bytes_(WorkerFactoryInformationLength) PVOID WorkerFactoryInformation,\n    _In_ ULONG WorkerFactoryInformationLength,\n    _Out_opt_ PULONG ReturnLength\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nZwQueryInstallUILanguage(\n    _Out_ LANGID *InstallUILanguageId\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nZwQueryIntervalProfile(\n    _In_ KPROFILE_SOURCE ProfileSource,\n    _Out_ PULONG Interval\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nZwQueryIoCompletion(\n    _In_ HANDLE IoCompletionHandle,\n    _In_ IO_COMPLETION_INFORMATION_CLASS IoCompletionInformationClass,\n    _Out_writes_bytes_(IoCompletionInformation) PVOID IoCompletionInformation,\n    _In_ ULONG IoCompletionInformationLength,\n    _Out_opt_ PULONG ReturnLength\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nZwQueryKey(\n    _In_ HANDLE KeyHandle,\n    _In_ KEY_INFORMATION_CLASS KeyInformationClass,\n    _Out_writes_bytes_opt_(Length) PVOID KeyInformation,\n    _In_ ULONG Length,\n    _Out_ PULONG ResultLength\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nZwQueryLicenseValue(\n    _In_ PUNICODE_STRING ValueName,\n    _Out_opt_ PULONG Type,\n    _Out_writes_bytes_to_opt_(DataSize, *ResultDataSize) PVOID Data,\n    _In_ ULONG DataSize,\n    _Out_ PULONG ResultDataSize\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nZwQueryMultipleValueKey(\n    _In_ HANDLE KeyHandle,\n    _Inout_updates_(EntryCount) PKEY_VALUE_ENTRY ValueEntries,\n    _In_ ULONG EntryCount,\n    _Out_writes_bytes_(*BufferLength) PVOID ValueBuffer,\n    _Inout_ PULONG BufferLength,\n    _Out_opt_ PULONG RequiredBufferLength\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nZwQueryMutant(\n    _In_ HANDLE MutantHandle,\n    _In_ MUTANT_INFORMATION_CLASS MutantInformationClass,\n    _Out_writes_bytes_(MutantInformationLength) PVOID MutantInformation,\n    _In_ ULONG MutantInformationLength,\n    _Out_opt_ PULONG ReturnLength\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nZwQueryObject(\n    _In_ HANDLE Handle,\n    _In_ OBJECT_INFORMATION_CLASS ObjectInformationClass,\n    _Out_writes_bytes_opt_(ObjectInformationLength) PVOID ObjectInformation,\n    _In_ ULONG ObjectInformationLength,\n    _Out_opt_ PULONG ReturnLength\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nZwQueryOpenSubKeys(\n    _In_ POBJECT_ATTRIBUTES TargetKey,\n    _Out_ PULONG HandleCount\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nZwQueryOpenSubKeysEx(\n    _In_ POBJECT_ATTRIBUTES TargetKey,\n    _In_ ULONG BufferLength,\n    _Out_writes_bytes_(BufferLength) PVOID Buffer,\n    _Out_ PULONG RequiredSize\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nZwQueryPerformanceCounter(\n    _Out_ PLARGE_INTEGER PerformanceCounter,\n    _Out_opt_ PLARGE_INTEGER PerformanceFrequency\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nZwQueryPortInformationProcess(\n    VOID\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nZwQueryQuotaInformationFile(\n    _In_ HANDLE FileHandle,\n    _Out_ PIO_STATUS_BLOCK IoStatusBlock,\n    _Out_writes_bytes_(Length) PVOID Buffer,\n    _In_ ULONG Length,\n    _In_ BOOLEAN ReturnSingleEntry,\n    _In_reads_bytes_opt_(SidListLength) PVOID SidList,\n    _In_ ULONG SidListLength,\n    _In_opt_ PSID StartSid,\n    _In_ BOOLEAN RestartScan\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nZwQuerySection(\n    _In_ HANDLE SectionHandle,\n    _In_ SECTION_INFORMATION_CLASS SectionInformationClass,\n    _Out_writes_bytes_(SectionInformationLength) PVOID SectionInformation,\n    _In_ SIZE_T SectionInformationLength,\n    _Out_opt_ PSIZE_T ReturnLength\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nZwQuerySecurityAttributesToken(\n    _In_ HANDLE TokenHandle,\n    _In_reads_opt_(NumberOfAttributes) PUNICODE_STRING Attributes,\n    _In_ ULONG NumberOfAttributes,\n    _Out_writes_bytes_(Length) PVOID Buffer, // PTOKEN_SECURITY_ATTRIBUTES_INFORMATION\n    _In_ ULONG Length,\n    _Out_ PULONG ReturnLength\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nZwQuerySecurityObject(\n    _In_ HANDLE Handle,\n    _In_ SECURITY_INFORMATION SecurityInformation,\n    _Out_writes_bytes_opt_(Length) PSECURITY_DESCRIPTOR SecurityDescriptor,\n    _In_ ULONG Length,\n    _Out_ PULONG LengthNeeded\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nZwQuerySemaphore(\n    _In_ HANDLE SemaphoreHandle,\n    _In_ SEMAPHORE_INFORMATION_CLASS SemaphoreInformationClass,\n    _Out_writes_bytes_(SemaphoreInformationLength) PVOID SemaphoreInformation,\n    _In_ ULONG SemaphoreInformationLength,\n    _Out_opt_ PULONG ReturnLength\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nZwQuerySymbolicLinkObject(\n    _In_ HANDLE LinkHandle,\n    _Inout_ PUNICODE_STRING LinkTarget,\n    _Out_opt_ PULONG ReturnedLength\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nZwQuerySystemEnvironmentValue(\n    _In_ PUNICODE_STRING VariableName,\n    _Out_writes_bytes_(ValueLength) PWSTR VariableValue,\n    _In_ USHORT ValueLength,\n    _Out_opt_ PUSHORT ReturnLength\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nZwQuerySystemEnvironmentValueEx(\n    _In_ PUNICODE_STRING VariableName,\n    _In_ LPGUID VendorGuid,\n    _Out_writes_bytes_opt_(*ValueLength) PVOID Value,\n    _Inout_ PULONG ValueLength,\n    _Out_opt_ PULONG Attributes\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nZwQuerySystemInformation(\n    _In_ SYSTEM_INFORMATION_CLASS SystemInformationClass,\n    _Out_writes_bytes_opt_(SystemInformationLength) PVOID SystemInformation,\n    _In_ ULONG SystemInformationLength,\n    _Out_opt_ PULONG ReturnLength\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nZwQuerySystemInformationEx(\n    _In_ SYSTEM_INFORMATION_CLASS SystemInformationClass,\n    _In_reads_bytes_(InputBufferLength) PVOID InputBuffer,\n    _In_ ULONG InputBufferLength,\n    _Out_writes_bytes_opt_(SystemInformationLength) PVOID SystemInformation,\n    _In_ ULONG SystemInformationLength,\n    _Out_opt_ PULONG ReturnLength\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nZwQuerySystemTime(\n    _Out_ PLARGE_INTEGER SystemTime\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nZwQueryTimer(\n    _In_ HANDLE TimerHandle,\n    _In_ TIMER_INFORMATION_CLASS TimerInformationClass,\n    _Out_writes_bytes_(TimerInformationLength) PVOID TimerInformation,\n    _In_ ULONG TimerInformationLength,\n    _Out_opt_ PULONG ReturnLength\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nZwQueryTimerResolution(\n    _Out_ PULONG MaximumTime,\n    _Out_ PULONG MinimumTime,\n    _Out_ PULONG CurrentTime\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nZwQueryValueKey(\n    _In_ HANDLE KeyHandle,\n    _In_ PUNICODE_STRING ValueName,\n    _In_ KEY_VALUE_INFORMATION_CLASS KeyValueInformationClass,\n    _Out_writes_bytes_opt_(Length) PVOID KeyValueInformation,\n    _In_ ULONG Length,\n    _Out_ PULONG ResultLength\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nZwQueryVirtualMemory(\n    _In_ HANDLE ProcessHandle,\n    _In_ PVOID BaseAddress,\n    _In_ MEMORY_INFORMATION_CLASS MemoryInformationClass,\n    _Out_writes_bytes_(MemoryInformationLength) PVOID MemoryInformation,\n    _In_ SIZE_T MemoryInformationLength,\n    _Out_opt_ PSIZE_T ReturnLength\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nZwQueryVolumeInformationFile(\n    _In_ HANDLE FileHandle,\n    _Out_ PIO_STATUS_BLOCK IoStatusBlock,\n    _Out_writes_bytes_(Length) PVOID FsInformation,\n    _In_ ULONG Length,\n    _In_ FSINFOCLASS FsInformationClass\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nZwQueryWnfStateData(\n    _In_ PCWNF_STATE_NAME StateName,\n    _In_opt_ PCWNF_TYPE_ID TypeId,\n    _In_opt_ const VOID *ExplicitScope,\n    _Out_ PWNF_CHANGE_STAMP ChangeStamp,\n    _Out_writes_bytes_to_opt_(*BufferSize, *BufferSize) PVOID Buffer,\n    _Inout_ PULONG BufferSize\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nZwQueryWnfStateNameInformation(\n    _In_ PCWNF_STATE_NAME StateName,\n    _In_ WNF_STATE_NAME_INFORMATION NameInfoClass,\n    _In_opt_ const VOID *ExplicitScope,\n    _Out_writes_bytes_(InfoBufferSize) PVOID InfoBuffer,\n    _In_ ULONG InfoBufferSize\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nZwQueueApcThread(\n    _In_ HANDLE ThreadHandle,\n    _In_ PPS_APC_ROUTINE ApcRoutine,\n    _In_opt_ PVOID ApcArgument1,\n    _In_opt_ PVOID ApcArgument2,\n    _In_opt_ PVOID ApcArgument3\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nZwQueueApcThreadEx(\n    _In_ HANDLE ThreadHandle,\n    _In_opt_ HANDLE UserApcReserveHandle,\n    _In_ PPS_APC_ROUTINE ApcRoutine,\n    _In_opt_ PVOID ApcArgument1,\n    _In_opt_ PVOID ApcArgument2,\n    _In_opt_ PVOID ApcArgument3\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nZwRaiseException(\n    _In_ PEXCEPTION_RECORD ExceptionRecord,\n    _In_ PCONTEXT ContextRecord,\n    _In_ BOOLEAN FirstChance\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nZwRaiseHardError(\n    _In_ NTSTATUS ErrorStatus,\n    _In_ ULONG NumberOfParameters,\n    _In_ ULONG UnicodeStringParameterMask,\n    _In_reads_(NumberOfParameters) PULONG_PTR Parameters,\n    _In_ ULONG ValidResponseOptions,\n    _Out_ PULONG Response\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nZwReadFile(\n    _In_ HANDLE FileHandle,\n    _In_opt_ HANDLE Event,\n    _In_opt_ PIO_APC_ROUTINE ApcRoutine,\n    _In_opt_ PVOID ApcContext,\n    _Out_ PIO_STATUS_BLOCK IoStatusBlock,\n    _Out_writes_bytes_(Length) PVOID Buffer,\n    _In_ ULONG Length,\n    _In_opt_ PLARGE_INTEGER ByteOffset,\n    _In_opt_ PULONG Key\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nZwReadFileScatter(\n    _In_ HANDLE FileHandle,\n    _In_opt_ HANDLE Event,\n    _In_opt_ PIO_APC_ROUTINE ApcRoutine,\n    _In_opt_ PVOID ApcContext,\n    _Out_ PIO_STATUS_BLOCK IoStatusBlock,\n    _In_ PFILE_SEGMENT_ELEMENT SegmentArray,\n    _In_ ULONG Length,\n    _In_opt_ PLARGE_INTEGER ByteOffset,\n    _In_opt_ PULONG Key\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nZwReadOnlyEnlistment(\n    _In_ HANDLE EnlistmentHandle,\n    _In_opt_ PLARGE_INTEGER TmVirtualClock\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nZwReadRequestData(\n    _In_ HANDLE PortHandle,\n    _In_ PPORT_MESSAGE Message,\n    _In_ ULONG DataEntryIndex,\n    _Out_writes_bytes_to_(BufferSize, *NumberOfBytesRead) PVOID Buffer,\n    _In_ SIZE_T BufferSize,\n    _Out_opt_ PSIZE_T NumberOfBytesRead\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nZwReadVirtualMemory(\n    _In_ HANDLE ProcessHandle,\n    _In_opt_ PVOID BaseAddress,\n    _Out_writes_bytes_(BufferSize) PVOID Buffer,\n    _In_ SIZE_T BufferSize,\n    _Out_opt_ PSIZE_T NumberOfBytesRead\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nZwRecoverEnlistment(\n    _In_ HANDLE EnlistmentHandle,\n    _In_opt_ PVOID EnlistmentKey\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nZwRecoverResourceManager(\n    _In_ HANDLE ResourceManagerHandle\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nZwRecoverTransactionManager(\n    _In_ HANDLE TransactionManagerHandle\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nZwRegisterProtocolAddressInformation(\n    _In_ HANDLE ResourceManager,\n    _In_ PCRM_PROTOCOL_ID ProtocolId,\n    _In_ ULONG ProtocolInformationSize,\n    _In_ PVOID ProtocolInformation,\n    _In_opt_ ULONG CreateOptions\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nZwRegisterThreadTerminatePort(\n    _In_ HANDLE PortHandle\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nZwReleaseCMFViewOwnership(\n    VOID\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nZwReleaseKeyedEvent(\n    _In_ HANDLE KeyedEventHandle,\n    _In_ PVOID KeyValue,\n    _In_ BOOLEAN Alertable,\n    _In_opt_ PLARGE_INTEGER Timeout\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nZwReleaseMutant(\n    _In_ HANDLE MutantHandle,\n    _Out_opt_ PLONG PreviousCount\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nZwReleaseSemaphore(\n    _In_ HANDLE SemaphoreHandle,\n    _In_ LONG ReleaseCount,\n    _Out_opt_ PLONG PreviousCount\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nZwReleaseWorkerFactoryWorker(\n    _In_ HANDLE WorkerFactoryHandle\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nZwRemoveIoCompletion(\n    _In_ HANDLE IoCompletionHandle,\n    _Out_ PVOID *KeyContext,\n    _Out_ PVOID *ApcContext,\n    _Out_ PIO_STATUS_BLOCK IoStatusBlock,\n    _In_opt_ PLARGE_INTEGER Timeout\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nZwRemoveIoCompletionEx(\n    _In_ HANDLE IoCompletionHandle,\n    _Out_writes_to_(Count, *NumEntriesRemoved) PFILE_IO_COMPLETION_INFORMATION IoCompletionInformation,\n    _In_ ULONG Count,\n    _Out_ PULONG NumEntriesRemoved,\n    _In_opt_ PLARGE_INTEGER Timeout,\n    _In_ BOOLEAN Alertable\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nZwRemoveProcessDebug(\n    _In_ HANDLE ProcessHandle,\n    _In_ HANDLE DebugObjectHandle\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nZwRenameKey(\n    _In_ HANDLE KeyHandle,\n    _In_ PUNICODE_STRING NewName\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nZwRenameTransactionManager(\n    _In_ PUNICODE_STRING LogFileName,\n    _In_ LPGUID ExistingTransactionManagerGuid\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nZwReplaceKey(\n    _In_ POBJECT_ATTRIBUTES NewFile,\n    _In_ HANDLE TargetHandle,\n    _In_ POBJECT_ATTRIBUTES OldFile\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nZwReplacePartitionUnit(\n    _In_ PUNICODE_STRING TargetInstancePath,\n    _In_ PUNICODE_STRING SpareInstancePath,\n    _In_ ULONG Flags\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nZwReplyPort(\n    _In_ HANDLE PortHandle,\n    _In_reads_bytes_(ReplyMessage->u1.s1.TotalLength) PPORT_MESSAGE ReplyMessage\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nZwReplyWaitReceivePort(\n    _In_ HANDLE PortHandle,\n    _Out_opt_ PVOID *PortContext,\n    _In_reads_bytes_opt_(ReplyMessage->u1.s1.TotalLength) PPORT_MESSAGE ReplyMessage,\n    _Out_ PPORT_MESSAGE ReceiveMessage\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nZwReplyWaitReceivePortEx(\n    _In_ HANDLE PortHandle,\n    _Out_opt_ PVOID *PortContext,\n    _In_reads_bytes_opt_(ReplyMessage->u1.s1.TotalLength) PPORT_MESSAGE ReplyMessage,\n    _Out_ PPORT_MESSAGE ReceiveMessage,\n    _In_opt_ PLARGE_INTEGER Timeout\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nZwReplyWaitReplyPort(\n    _In_ HANDLE PortHandle,\n    _Inout_ PPORT_MESSAGE ReplyMessage\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nZwRequestPort(\n    _In_ HANDLE PortHandle,\n    _In_reads_bytes_(RequestMessage->u1.s1.TotalLength) PPORT_MESSAGE RequestMessage\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nZwRequestWaitReplyPort(\n    _In_ HANDLE PortHandle,\n    _In_reads_bytes_(RequestMessage->u1.s1.TotalLength) PPORT_MESSAGE RequestMessage,\n    _Out_ PPORT_MESSAGE ReplyMessage\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nZwRequestWakeupLatency(\n    _In_ LATENCY_TIME latency\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nZwResetEvent(\n    _In_ HANDLE EventHandle,\n    _Out_opt_ PLONG PreviousState\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nZwResetWriteWatch(\n    _In_ HANDLE ProcessHandle,\n    _In_ PVOID BaseAddress,\n    _In_ SIZE_T RegionSize\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nZwRestoreKey(\n    _In_ HANDLE KeyHandle,\n    _In_ HANDLE FileHandle,\n    _In_ ULONG Flags\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nZwResumeProcess(\n    _In_ HANDLE ProcessHandle\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nZwResumeThread(\n    _In_ HANDLE ThreadHandle,\n    _Out_opt_ PULONG PreviousSuspendCount\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nZwRevertContainerImpersonation(\n    VOID\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nZwRollbackComplete(\n    _In_ HANDLE EnlistmentHandle,\n    _In_opt_ PLARGE_INTEGER TmVirtualClock\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nZwRollbackEnlistment(\n    _In_ HANDLE EnlistmentHandle,\n    _In_opt_ PLARGE_INTEGER TmVirtualClock\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nZwRollbackTransaction(\n    _In_ HANDLE TransactionHandle,\n    _In_ BOOLEAN Wait\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nZwRollforwardTransactionManager(\n    _In_ HANDLE TransactionManagerHandle,\n    _In_opt_ PLARGE_INTEGER TmVirtualClock\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nZwSaveKey(\n    _In_ HANDLE KeyHandle,\n    _In_ HANDLE FileHandle\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nZwSaveKeyEx(\n    _In_ HANDLE KeyHandle,\n    _In_ HANDLE FileHandle,\n    _In_ ULONG Format\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nZwSaveMergedKeys(\n    _In_ HANDLE HighPrecedenceKeyHandle,\n    _In_ HANDLE LowPrecedenceKeyHandle,\n    _In_ HANDLE FileHandle\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nZwSecureConnectPort(\n    _Out_ PHANDLE PortHandle,\n    _In_ PUNICODE_STRING PortName,\n    _In_ PSECURITY_QUALITY_OF_SERVICE SecurityQos,\n    _Inout_opt_ PPORT_VIEW ClientView,\n    _In_opt_ PSID RequiredServerSid,\n    _Inout_opt_ PREMOTE_PORT_VIEW ServerView,\n    _Out_opt_ PULONG MaxMessageLength,\n    _Inout_updates_bytes_to_opt_(*ConnectionInformationLength, *ConnectionInformationLength) PVOID ConnectionInformation,\n    _Inout_opt_ PULONG ConnectionInformationLength\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nZwSerializeBoot(\n    VOID\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nZwSetBootEntryOrder(\n    _In_reads_(Count) PULONG Ids,\n    _In_ ULONG Count\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nZwSetBootOptions(\n    _In_ PBOOT_OPTIONS BootOptions,\n    _In_ ULONG FieldsToChange\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nZwSetCachedSigningLevel(\n    _In_ ULONG Flags,\n    _In_ SE_SIGNING_LEVEL InputSigningLevel,\n    _In_reads_(SourceFileCount) PHANDLE SourceFiles,\n    _In_ ULONG SourceFileCount,\n    _In_opt_ HANDLE TargetFile\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nZwSetContextThread(\n    _In_ HANDLE ThreadHandle,\n    _In_ PCONTEXT ThreadContext\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nZwSetDebugFilterState(\n    _In_ ULONG ComponentId,\n    _In_ ULONG Level,\n    _In_ BOOLEAN State\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nZwSetDefaultHardErrorPort(\n    _In_ HANDLE DefaultHardErrorPort\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nZwSetDefaultLocale(\n    _In_ BOOLEAN UserProfile,\n    _In_ LCID DefaultLocaleId\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nZwSetDefaultUILanguage(\n    _In_ LANGID DefaultUILanguageId\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nZwSetDriverEntryOrder(\n    _In_reads_(Count) PULONG Ids,\n    _In_ ULONG Count\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nZwSetEaFile(\n    _In_ HANDLE FileHandle,\n    _Out_ PIO_STATUS_BLOCK IoStatusBlock,\n    _In_reads_bytes_(Length) PVOID Buffer,\n    _In_ ULONG Length\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nZwSetEvent(\n    _In_ HANDLE EventHandle,\n    _Out_opt_ PLONG PreviousState\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nZwSetEventBoostPriority(\n    _In_ HANDLE EventHandle\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nZwSetHighEventPair(\n    _In_ HANDLE EventPairHandle\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nZwSetHighWaitLowEventPair(\n    _In_ HANDLE EventPairHandle\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nZwSetIRTimer(\n    _In_ HANDLE TimerHandle,\n    _In_opt_ PLARGE_INTEGER DueTime\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nZwSetInformationDebugObject(\n    _In_ HANDLE DebugObjectHandle,\n    _In_ DEBUGOBJECTINFOCLASS DebugObjectInformationClass,\n    _In_ PVOID DebugInformation,\n    _In_ ULONG DebugInformationLength,\n    _Out_opt_ PULONG ReturnLength\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nZwSetInformationEnlistment(\n    _In_opt_ HANDLE EnlistmentHandle,\n    _In_ ENLISTMENT_INFORMATION_CLASS EnlistmentInformationClass,\n    _In_reads_bytes_(EnlistmentInformationLength) PVOID EnlistmentInformation,\n    _In_ ULONG EnlistmentInformationLength\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nZwSetInformationFile(\n    _In_ HANDLE FileHandle,\n    _Out_ PIO_STATUS_BLOCK IoStatusBlock,\n    _In_reads_bytes_(Length) PVOID FileInformation,\n    _In_ ULONG Length,\n    _In_ FILE_INFORMATION_CLASS FileInformationClass\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nZwSetInformationJobObject(\n    _In_ HANDLE JobHandle,\n    _In_ JOBOBJECTINFOCLASS JobObjectInformationClass,\n    _In_reads_bytes_(JobObjectInformationLength) PVOID JobObjectInformation,\n    _In_ ULONG JobObjectInformationLength\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nZwSetInformationKey(\n    _In_ HANDLE KeyHandle,\n    _In_ KEY_SET_INFORMATION_CLASS KeySetInformationClass,\n    _In_reads_bytes_(KeySetInformationLength) PVOID KeySetInformation,\n    _In_ ULONG KeySetInformationLength\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nZwSetInformationObject(\n    _In_ HANDLE Handle,\n    _In_ OBJECT_INFORMATION_CLASS ObjectInformationClass,\n    _In_reads_bytes_(ObjectInformationLength) PVOID ObjectInformation,\n    _In_ ULONG ObjectInformationLength\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nZwSetInformationProcess(\n    _In_ HANDLE ProcessHandle,\n    _In_ PROCESSINFOCLASS ProcessInformationClass,\n    _In_reads_bytes_(ProcessInformationLength) PVOID ProcessInformation,\n    _In_ ULONG ProcessInformationLength\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nZwSetInformationResourceManager(\n    _In_ HANDLE ResourceManagerHandle,\n    _In_ RESOURCEMANAGER_INFORMATION_CLASS ResourceManagerInformationClass,\n    _In_reads_bytes_(ResourceManagerInformationLength) PVOID ResourceManagerInformation,\n    _In_ ULONG ResourceManagerInformationLength\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nZwSetInformationThread(\n    _In_ HANDLE ThreadHandle,\n    _In_ THREADINFOCLASS ThreadInformationClass,\n    _In_reads_bytes_(ThreadInformationLength) PVOID ThreadInformation,\n    _In_ ULONG ThreadInformationLength\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nZwSetInformationToken(\n    _In_ HANDLE TokenHandle,\n    _In_ TOKEN_INFORMATION_CLASS TokenInformationClass,\n    _In_reads_bytes_(TokenInformationLength) PVOID TokenInformation,\n    _In_ ULONG TokenInformationLength\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nZwSetInformationTransaction(\n    _In_ HANDLE TransactionHandle,\n    _In_ TRANSACTION_INFORMATION_CLASS TransactionInformationClass,\n    _In_reads_bytes_(TransactionInformationLength) PVOID TransactionInformation,\n    _In_ ULONG TransactionInformationLength\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nZwSetInformationTransactionManager(\n    _In_opt_ HANDLE TmHandle,\n    _In_ TRANSACTIONMANAGER_INFORMATION_CLASS TransactionManagerInformationClass,\n    _In_reads_bytes_(TransactionManagerInformationLength) PVOID TransactionManagerInformation,\n    _In_ ULONG TransactionManagerInformationLength\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nZwSetInformationVirtualMemory(\n    _In_ HANDLE ProcessHandle,\n    _In_ VIRTUAL_MEMORY_INFORMATION_CLASS VmInformationClass,\n    _In_ ULONG_PTR NumberOfEntries,\n    _In_reads_ (NumberOfEntries) PMEMORY_RANGE_ENTRY VirtualAddresses,\n    _In_reads_bytes_ (VmInformationLength) PVOID VmInformation,\n    _In_ ULONG VmInformationLength\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nZwSetInformationWorkerFactory(\n    _In_ HANDLE WorkerFactoryHandle,\n    _In_ WORKERFACTORYINFOCLASS WorkerFactoryInformationClass,\n    _In_reads_bytes_(WorkerFactoryInformationLength) PVOID WorkerFactoryInformation,\n    _In_ ULONG WorkerFactoryInformationLength\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nZwSetIntervalProfile(\n    _In_ ULONG Interval,\n    _In_ KPROFILE_SOURCE Source\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nZwSetIoCompletion(\n    _In_ HANDLE IoCompletionHandle,\n    _In_opt_ PVOID KeyContext,\n    _In_opt_ PVOID ApcContext,\n    _In_ NTSTATUS IoStatus,\n    _In_ ULONG_PTR IoStatusInformation\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nZwSetIoCompletionEx(\n    _In_ HANDLE IoCompletionHandle,\n    _In_ HANDLE IoCompletionPacketHandle,\n    _In_opt_ PVOID KeyContext,\n    _In_opt_ PVOID ApcContext,\n    _In_ NTSTATUS IoStatus,\n    _In_ ULONG_PTR IoStatusInformation\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nZwSetLdtEntries(\n    _In_ ULONG Selector0,\n    _In_ ULONG Entry0Low,\n    _In_ ULONG Entry0Hi,\n    _In_ ULONG Selector1,\n    _In_ ULONG Entry1Low,\n    _In_ ULONG Entry1Hi\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nZwSetLowEventPair(\n    _In_ HANDLE EventPairHandle\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nZwSetLowWaitHighEventPair(\n    _In_ HANDLE EventPairHandle\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nZwSetQuotaInformationFile(\n    _In_ HANDLE FileHandle,\n    _Out_ PIO_STATUS_BLOCK IoStatusBlock,\n    _In_reads_bytes_(Length) PVOID Buffer,\n    _In_ ULONG Length\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nZwSetSecurityObject(\n    _In_ HANDLE Handle,\n    _In_ SECURITY_INFORMATION SecurityInformation,\n    _In_ PSECURITY_DESCRIPTOR SecurityDescriptor\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nZwSetSystemEnvironmentValue(\n    _In_ PUNICODE_STRING VariableName,\n    _In_ PUNICODE_STRING VariableValue\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nZwSetSystemEnvironmentValueEx(\n    _In_ PUNICODE_STRING VariableName,\n    _In_ LPGUID VendorGuid,\n    _In_reads_bytes_opt_(ValueLength) PVOID Value,\n    _In_ ULONG ValueLength,\n    _In_ ULONG Attributes\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nZwSetSystemInformation(\n    _In_ SYSTEM_INFORMATION_CLASS SystemInformationClass,\n    _In_reads_bytes_opt_(SystemInformationLength) PVOID SystemInformation,\n    _In_ ULONG SystemInformationLength\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nZwSetSystemPowerState(\n    _In_ POWER_ACTION SystemAction,\n    _In_ SYSTEM_POWER_STATE LightestSystemState,\n    _In_ ULONG Flags // POWER_ACTION_* flags\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nZwSetSystemTime(\n    _In_opt_ PLARGE_INTEGER SystemTime,\n    _Out_opt_ PLARGE_INTEGER PreviousTime\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nZwSetThreadExecutionState(\n    _In_ EXECUTION_STATE NewFlags, // ES_* flags\n    _Out_ EXECUTION_STATE *PreviousFlags\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nZwSetTimer(\n    _In_ HANDLE TimerHandle,\n    _In_ PLARGE_INTEGER DueTime,\n    _In_opt_ PTIMER_APC_ROUTINE TimerApcRoutine,\n    _In_opt_ PVOID TimerContext,\n    _In_ BOOLEAN ResumeTimer,\n    _In_opt_ LONG Period,\n    _Out_opt_ PBOOLEAN PreviousState\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nZwSetTimer2(\n    _In_ HANDLE TimerHandle,\n    _In_ PLARGE_INTEGER DueTime,\n    _In_opt_ PLARGE_INTEGER Period,\n    _In_ PT2_SET_PARAMETERS Parameters\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nZwSetTimerEx(\n    _In_ HANDLE TimerHandle,\n    _In_ TIMER_SET_INFORMATION_CLASS TimerSetInformationClass,\n    _Inout_updates_bytes_opt_(TimerSetInformationLength) PVOID TimerSetInformation,\n    _In_ ULONG TimerSetInformationLength\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nZwSetTimerResolution(\n    _In_ ULONG DesiredTime,\n    _In_ BOOLEAN SetResolution,\n    _Out_ PULONG ActualTime\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nZwSetUuidSeed(\n    _In_ PCHAR Seed\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nZwSetValueKey(\n    _In_ HANDLE KeyHandle,\n    _In_ PUNICODE_STRING ValueName,\n    _In_opt_ ULONG TitleIndex,\n    _In_ ULONG Type,\n    _In_reads_bytes_opt_(DataSize) PVOID Data,\n    _In_ ULONG DataSize\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nZwSetVolumeInformationFile(\n    _In_ HANDLE FileHandle,\n    _Out_ PIO_STATUS_BLOCK IoStatusBlock,\n    _In_reads_bytes_(Length) PVOID FsInformation,\n    _In_ ULONG Length,\n    _In_ FSINFOCLASS FsInformationClass\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nZwSetWnfProcessNotificationEvent(\n    _In_ HANDLE NotificationEvent\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nZwShutdownSystem(\n    _In_ SHUTDOWN_ACTION Action\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nZwShutdownWorkerFactory(\n    _In_ HANDLE WorkerFactoryHandle,\n    _Inout_ volatile LONG *PendingWorkerCount\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nZwSignalAndWaitForSingleObject(\n    _In_ HANDLE SignalHandle,\n    _In_ HANDLE WaitHandle,\n    _In_ BOOLEAN Alertable,\n    _In_opt_ PLARGE_INTEGER Timeout\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nZwSinglePhaseReject(\n    _In_ HANDLE EnlistmentHandle,\n    _In_opt_ PLARGE_INTEGER TmVirtualClock\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nZwStartProfile(\n    _In_ HANDLE ProfileHandle\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nZwStopProfile(\n    _In_ HANDLE ProfileHandle\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nZwSubscribeWnfStateChange(\n    _In_ PCWNF_STATE_NAME StateName,\n    _In_opt_ WNF_CHANGE_STAMP ChangeStamp,\n    _In_ ULONG EventMask,\n    _Out_opt_ PULONG64 SubscriptionId\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nZwSuspendProcess(\n    _In_ HANDLE ProcessHandle\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nZwSuspendThread(\n    _In_ HANDLE ThreadHandle,\n    _Out_opt_ PULONG PreviousSuspendCount\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nZwSystemDebugControl(\n    _In_ SYSDBG_COMMAND Command,\n    _Inout_updates_bytes_opt_(InputBufferLength) PVOID InputBuffer,\n    _In_ ULONG InputBufferLength,\n    _Out_writes_bytes_opt_(OutputBufferLength) PVOID OutputBuffer,\n    _In_ ULONG OutputBufferLength,\n    _Out_opt_ PULONG ReturnLength\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nZwTerminateJobObject(\n    _In_ HANDLE JobHandle,\n    _In_ NTSTATUS ExitStatus\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nZwTerminateProcess(\n    _In_opt_ HANDLE ProcessHandle,\n    _In_ NTSTATUS ExitStatus\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nZwTerminateThread(\n    _In_opt_ HANDLE ThreadHandle,\n    _In_ NTSTATUS ExitStatus\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nZwTestAlert(\n    VOID\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nZwThawRegistry(\n    VOID\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nZwThawTransactions(\n    VOID\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nZwTraceControl(\n    _In_ ULONG FunctionCode,\n    _In_reads_bytes_opt_(InBufferLen) PVOID InBuffer,\n    _In_ ULONG InBufferLen,\n    _Out_writes_bytes_opt_(OutBufferLen) PVOID OutBuffer,\n    _In_ ULONG OutBufferLen,\n    _Out_ PULONG ReturnLength\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nZwTraceEvent(\n    _In_ HANDLE TraceHandle,\n    _In_ ULONG Flags,\n    _In_ ULONG FieldSize,\n    _In_ PVOID Fields\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nZwTranslateFilePath(\n    _In_ PFILE_PATH InputFilePath,\n    _In_ ULONG OutputType,\n    _Out_writes_bytes_opt_(*OutputFilePathLength) PFILE_PATH OutputFilePath,\n    _Inout_opt_ PULONG OutputFilePathLength\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nZwUmsThreadYield(\n    _In_ PVOID SchedulerParam\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nZwUnloadDriver(\n    _In_ PUNICODE_STRING DriverServiceName\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nZwUnloadKey(\n    _In_ POBJECT_ATTRIBUTES TargetKey\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nZwUnloadKey2(\n    _In_ POBJECT_ATTRIBUTES TargetKey,\n    _In_ ULONG Flags\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nZwUnloadKeyEx(\n    _In_ POBJECT_ATTRIBUTES TargetKey,\n    _In_opt_ HANDLE Event\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nZwUnlockFile(\n    _In_ HANDLE FileHandle,\n    _Out_ PIO_STATUS_BLOCK IoStatusBlock,\n    _In_ PLARGE_INTEGER ByteOffset,\n    _In_ PLARGE_INTEGER Length,\n    _In_ ULONG Key\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nZwUnlockVirtualMemory(\n    _In_ HANDLE ProcessHandle,\n    _Inout_ PVOID *BaseAddress,\n    _Inout_ PSIZE_T RegionSize,\n    _In_ ULONG MapType\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nZwUnmapViewOfSection(\n    _In_ HANDLE ProcessHandle,\n    _In_opt_ PVOID BaseAddress\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nZwUnmapViewOfSectionEx(\n    _In_ HANDLE ProcessHandle,\n    _In_opt_ PVOID BaseAddress,\n    _In_ ULONG Flags\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nZwUnsubscribeWnfStateChange(\n    _In_ PCWNF_STATE_NAME StateName\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nZwUpdateWnfStateData(\n    _In_ PCWNF_STATE_NAME StateName,\n    _In_reads_bytes_opt_(Length) const VOID *Buffer,\n    _In_opt_ ULONG Length,\n    _In_opt_ PCWNF_TYPE_ID TypeId,\n    _In_opt_ const VOID *ExplicitScope,\n    _In_ WNF_CHANGE_STAMP MatchingChangeStamp,\n    _In_ LOGICAL CheckStamp\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nZwVdmControl(\n    _In_ VDMSERVICECLASS Service,\n    _Inout_ PVOID ServiceData\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nZwWaitForAlertByThreadId(\n    _In_ PVOID Address,\n    _In_opt_ PLARGE_INTEGER Timeout\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nZwWaitForDebugEvent(\n    _In_ HANDLE DebugObjectHandle,\n    _In_ BOOLEAN Alertable,\n    _In_opt_ PLARGE_INTEGER Timeout,\n    _Out_ PVOID WaitStateChange\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nZwWaitForKeyedEvent(\n    _In_ HANDLE KeyedEventHandle,\n    _In_ PVOID KeyValue,\n    _In_ BOOLEAN Alertable,\n    _In_opt_ PLARGE_INTEGER Timeout\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nZwWaitForMultipleObjects(\n    _In_ ULONG Count,\n    _In_reads_(Count) HANDLE Handles[],\n    _In_ WAIT_TYPE WaitType,\n    _In_ BOOLEAN Alertable,\n    _In_opt_ PLARGE_INTEGER Timeout\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nZwWaitForMultipleObjects32(\n    _In_ ULONG Count,\n    _In_reads_(Count) LONG Handles[],\n    _In_ WAIT_TYPE WaitType,\n    _In_ BOOLEAN Alertable,\n    _In_opt_ PLARGE_INTEGER Timeout\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nZwWaitForSingleObject(\n    _In_ HANDLE Handle,\n    _In_ BOOLEAN Alertable,\n    _In_opt_ PLARGE_INTEGER Timeout\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nZwWaitForWorkViaWorkerFactory(\n    _In_ HANDLE WorkerFactoryHandle,\n    _Out_ struct _FILE_IO_COMPLETION_INFORMATION *MiniPacket\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nZwWaitHighEventPair(\n    _In_ HANDLE EventPairHandle\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nZwWaitLowEventPair(\n    _In_ HANDLE EventPairHandle\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nZwWorkerFactoryWorkerReady(\n    _In_ HANDLE WorkerFactoryHandle\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nZwWriteFile(\n    _In_ HANDLE FileHandle,\n    _In_opt_ HANDLE Event,\n    _In_opt_ PIO_APC_ROUTINE ApcRoutine,\n    _In_opt_ PVOID ApcContext,\n    _Out_ PIO_STATUS_BLOCK IoStatusBlock,\n    _In_reads_bytes_(Length) PVOID Buffer,\n    _In_ ULONG Length,\n    _In_opt_ PLARGE_INTEGER ByteOffset,\n    _In_opt_ PULONG Key\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nZwWriteFileGather(\n    _In_ HANDLE FileHandle,\n    _In_opt_ HANDLE Event,\n    _In_opt_ PIO_APC_ROUTINE ApcRoutine,\n    _In_opt_ PVOID ApcContext,\n    _Out_ PIO_STATUS_BLOCK IoStatusBlock,\n    _In_ PFILE_SEGMENT_ELEMENT SegmentArray,\n    _In_ ULONG Length,\n    _In_opt_ PLARGE_INTEGER ByteOffset,\n    _In_opt_ PULONG Key\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nZwWriteRequestData(\n    _In_ HANDLE PortHandle,\n    _In_ PPORT_MESSAGE Message,\n    _In_ ULONG DataEntryIndex,\n    _In_reads_bytes_(BufferSize) PVOID Buffer,\n    _In_ SIZE_T BufferSize,\n    _Out_opt_ PSIZE_T NumberOfBytesWritten\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nZwWriteVirtualMemory(\n    _In_ HANDLE ProcessHandle,\n    _In_opt_ PVOID BaseAddress,\n    _In_reads_bytes_(BufferSize) PVOID Buffer,\n    _In_ SIZE_T BufferSize,\n    _Out_opt_ PSIZE_T NumberOfBytesWritten\n    );\n\nNTSYSCALLAPI\nNTSTATUS\nNTAPI\nZwYieldExecution(\n    VOID\n    );\n\n#endif\n"
  },
  {
    "path": "third_party/phnt/include/phnt.h",
    "content": "#ifndef _PHNT_H\n#define _PHNT_H\n\n// This header file provides access to NT APIs.\n\n// Definitions are annotated to indicate their source. If a definition is not annotated, it has been\n// retrieved from an official Microsoft source (NT headers, DDK headers, winnt.h).\n\n// * \"winbase\" indicates that a definition has been reconstructed from a Win32-ized NT definition in\n//   winbase.h.\n// * \"rev\" indicates that a definition has been reverse-engineered.\n// * \"dbg\" indicates that a definition has been obtained from a debug message or assertion in a\n//   checked build of the kernel or file.\n\n// Reliability:\n// 1. No annotation.\n// 2. dbg.\n// 3. symbols, private. Types may be incorrect.\n// 4. winbase. Names and types may be incorrect.\n// 5. rev.\n\n// Mode\n#define PHNT_MODE_KERNEL 0\n#define PHNT_MODE_USER 1\n\n// Version\n#define PHNT_WIN2K 50\n#define PHNT_WINXP 51\n#define PHNT_WS03 52\n#define PHNT_VISTA 60\n#define PHNT_WIN7 61\n#define PHNT_WIN8 62\n#define PHNT_WINBLUE 63\n#define PHNT_THRESHOLD 100\n#define PHNT_THRESHOLD2 101\n#define PHNT_REDSTONE 102\n#define PHNT_REDSTONE2 103\n#define PHNT_REDSTONE3 104\n\n#ifndef PHNT_MODE\n#define PHNT_MODE PHNT_MODE_USER\n#endif\n\n#ifndef PHNT_VERSION\n#define PHNT_VERSION PHNT_WIN7\n#endif\n\n// Options\n\n//#define PHNT_NO_INLINE_INIT_STRING\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\n#if (PHNT_MODE != PHNT_MODE_KERNEL)\n#include <phnt_ntdef.h>\n#include <ntnls.h>\n#include <ntkeapi.h>\n#endif\n\n#include <ntldr.h>\n#include <ntexapi.h>\n\n#include <ntmmapi.h>\n#include <ntobapi.h>\n#include <ntpsapi.h>\n\n#if (PHNT_MODE != PHNT_MODE_KERNEL)\n#include <cfg.h>\n#include <ntdbg.h>\n#include <ntioapi.h>\n#include <ntlpcapi.h>\n#include <ntpfapi.h>\n#include <ntpnpapi.h>\n#include <ntpoapi.h>\n#include <ntregapi.h>\n#include <ntrtl.h>\n#endif\n\n#if (PHNT_MODE != PHNT_MODE_KERNEL)\n\n#include <ntseapi.h>\n#include <nttmapi.h>\n#include <nttp.h>\n#include <ntxcapi.h>\n\n#include <ntwow64.h>\n\n#include <ntlsa.h>\n#include <ntsam.h>\n\n#include <ntmisc.h>\n\n#include <ntzwapi.h>\n\n#endif\n\n#ifdef __cplusplus\n}\n#endif\n\n#endif\n"
  },
  {
    "path": "third_party/phnt/include/phnt_ntdef.h",
    "content": "#ifndef _PHNT_NTDEF_H\n#define _PHNT_NTDEF_H\n\n#ifndef _NTDEF_\n#define _NTDEF_\n\n// This header file provides basic NT types not included in Win32. If you have included winnt.h\n// (perhaps indirectly), you must use this file instead of ntdef.h.\n\n#ifndef NOTHING\n#define NOTHING\n#endif\n\n// Basic types\n\ntypedef struct _QUAD\n{\n    union\n    {\n        __int64 UseThisFieldToCopy;\n        double DoNotUseThisField;\n    };\n} QUAD, *PQUAD;\n\n// This isn't in NT, but it's useful.\ntypedef struct DECLSPEC_ALIGN(MEMORY_ALLOCATION_ALIGNMENT) _QUAD_PTR\n{\n    ULONG_PTR DoNotUseThisField1;\n    ULONG_PTR DoNotUseThisField2;\n} QUAD_PTR, *PQUAD_PTR;\n\ntypedef ULONG LOGICAL;\ntypedef ULONG *PLOGICAL;\n\ntypedef _Success_(return >= 0) LONG NTSTATUS;\ntypedef NTSTATUS *PNTSTATUS;\n\n// Cardinal types\n\ntypedef char CCHAR;\ntypedef short CSHORT;\ntypedef ULONG CLONG;\n\ntypedef CCHAR *PCCHAR;\ntypedef CSHORT *PCSHORT;\ntypedef CLONG *PCLONG;\n\ntypedef PCSTR PCSZ;\n\n// Specific\n\ntypedef UCHAR KIRQL, *PKIRQL;\ntypedef LONG KPRIORITY;\ntypedef USHORT RTL_ATOM, *PRTL_ATOM;\n\ntypedef LARGE_INTEGER PHYSICAL_ADDRESS, *PPHYSICAL_ADDRESS;\n\n// NT status macros\n\n#define NT_SUCCESS(Status) (((NTSTATUS)(Status)) >= 0)\n#define NT_INFORMATION(Status) ((((ULONG)(Status)) >> 30) == 1)\n#define NT_WARNING(Status) ((((ULONG)(Status)) >> 30) == 2)\n#define NT_ERROR(Status) ((((ULONG)(Status)) >> 30) == 3)\n\n#define NT_FACILITY_MASK 0xfff\n#define NT_FACILITY_SHIFT 16\n#define NT_FACILITY(Status) ((((ULONG)(Status)) >> NT_FACILITY_SHIFT) & NT_FACILITY_MASK)\n\n#define NT_NTWIN32(Status) (NT_FACILITY(Status) == FACILITY_NTWIN32)\n#define WIN32_FROM_NTSTATUS(Status) (((ULONG)(Status)) & 0xffff)\n\n// Functions\n\n#ifdef _MANAGED\n#define FASTCALL __stdcall\n#elif !defined(_WIN64)\n#define FASTCALL __fastcall\n#else\n#define FASTCALL\n#endif\n\n// Synchronization enumerations\n\ntypedef enum _EVENT_TYPE\n{\n    NotificationEvent,\n    SynchronizationEvent\n} EVENT_TYPE;\n\ntypedef enum _TIMER_TYPE\n{\n    NotificationTimer,\n    SynchronizationTimer\n} TIMER_TYPE;\n\ntypedef enum _WAIT_TYPE\n{\n    WaitAll,\n    WaitAny,\n    WaitNotification\n} WAIT_TYPE;\n\n// Strings\n\ntypedef struct _STRING\n{\n    USHORT Length;\n    USHORT MaximumLength;\n    _Field_size_bytes_part_opt_(MaximumLength, Length) PCHAR Buffer;\n} STRING, *PSTRING, ANSI_STRING, *PANSI_STRING, OEM_STRING, *POEM_STRING;\n\ntypedef const STRING *PCSTRING;\ntypedef const ANSI_STRING *PCANSI_STRING;\ntypedef const OEM_STRING *PCOEM_STRING;\n\ntypedef struct _UNICODE_STRING\n{\n    USHORT Length;\n    USHORT MaximumLength;\n    _Field_size_bytes_part_(MaximumLength, Length) PWCH Buffer;\n} UNICODE_STRING, *PUNICODE_STRING;\n\ntypedef const UNICODE_STRING *PCUNICODE_STRING;\n\n#define RTL_CONSTANT_STRING(s) { sizeof(s) - sizeof((s)[0]), sizeof(s), s }\n\n// Balanced tree node\n\n#define RTL_BALANCED_NODE_RESERVED_PARENT_MASK 3\n\ntypedef struct _RTL_BALANCED_NODE\n{\n    union\n    {\n        struct _RTL_BALANCED_NODE *Children[2];\n        struct\n        {\n            struct _RTL_BALANCED_NODE *Left;\n            struct _RTL_BALANCED_NODE *Right;\n        };\n    };\n    union\n    {\n        UCHAR Red : 1;\n        UCHAR Balance : 2;\n        ULONG_PTR ParentValue;\n    };\n} RTL_BALANCED_NODE, *PRTL_BALANCED_NODE;\n\n#define RTL_BALANCED_NODE_GET_PARENT_POINTER(Node) \\\n    ((PRTL_BALANCED_NODE)((Node)->ParentValue & ~RTL_BALANCED_NODE_RESERVED_PARENT_MASK))\n\n// Portability\n\ntypedef struct _SINGLE_LIST_ENTRY32\n{\n    ULONG Next;\n} SINGLE_LIST_ENTRY32, *PSINGLE_LIST_ENTRY32;\n\ntypedef struct _STRING32\n{\n    USHORT Length;\n    USHORT MaximumLength;\n    ULONG Buffer;\n} STRING32, *PSTRING32;\n\ntypedef STRING32 UNICODE_STRING32, *PUNICODE_STRING32;\ntypedef STRING32 ANSI_STRING32, *PANSI_STRING32;\n\ntypedef struct _STRING64\n{\n    USHORT Length;\n    USHORT MaximumLength;\n    ULONGLONG Buffer;\n} STRING64, *PSTRING64;\n\ntypedef STRING64 UNICODE_STRING64, *PUNICODE_STRING64;\ntypedef STRING64 ANSI_STRING64, *PANSI_STRING64;\n\n// Object attributes\n\n#define OBJ_INHERIT 0x00000002\n#define OBJ_PERMANENT 0x00000010\n#define OBJ_EXCLUSIVE 0x00000020\n#define OBJ_CASE_INSENSITIVE 0x00000040\n#define OBJ_OPENIF 0x00000080\n#define OBJ_OPENLINK 0x00000100\n#define OBJ_KERNEL_HANDLE 0x00000200\n#define OBJ_FORCE_ACCESS_CHECK 0x00000400\n#define OBJ_IGNORE_IMPERSONATED_DEVICEMAP 0x00000800\n#define OBJ_DONT_REPARSE 0x00001000\n#define OBJ_VALID_ATTRIBUTES 0x00001ff2\n\ntypedef struct _OBJECT_ATTRIBUTES\n{\n    ULONG Length;\n    HANDLE RootDirectory;\n    PUNICODE_STRING ObjectName;\n    ULONG Attributes;\n    PVOID SecurityDescriptor; // PSECURITY_DESCRIPTOR;\n    PVOID SecurityQualityOfService; // PSECURITY_QUALITY_OF_SERVICE\n} OBJECT_ATTRIBUTES, *POBJECT_ATTRIBUTES;\n\ntypedef const OBJECT_ATTRIBUTES *PCOBJECT_ATTRIBUTES;\n\n#define InitializeObjectAttributes(p, n, a, r, s) { \\\n    (p)->Length = sizeof(OBJECT_ATTRIBUTES); \\\n    (p)->RootDirectory = r; \\\n    (p)->Attributes = a; \\\n    (p)->ObjectName = n; \\\n    (p)->SecurityDescriptor = s; \\\n    (p)->SecurityQualityOfService = NULL; \\\n    }\n\n#define RTL_CONSTANT_OBJECT_ATTRIBUTES(n, a) { sizeof(OBJECT_ATTRIBUTES), NULL, n, a, NULL, NULL }\n#define RTL_INIT_OBJECT_ATTRIBUTES(n, a) RTL_CONSTANT_OBJECT_ATTRIBUTES(n, a)\n\n// Portability\n\ntypedef struct _OBJECT_ATTRIBUTES64\n{\n    ULONG Length;\n    ULONG64 RootDirectory;\n    ULONG64 ObjectName;\n    ULONG Attributes;\n    ULONG64 SecurityDescriptor;\n    ULONG64 SecurityQualityOfService;\n} OBJECT_ATTRIBUTES64, *POBJECT_ATTRIBUTES64;\n\ntypedef const OBJECT_ATTRIBUTES64 *PCOBJECT_ATTRIBUTES64;\n\ntypedef struct _OBJECT_ATTRIBUTES32\n{\n    ULONG Length;\n    ULONG RootDirectory;\n    ULONG ObjectName;\n    ULONG Attributes;\n    ULONG SecurityDescriptor;\n    ULONG SecurityQualityOfService;\n} OBJECT_ATTRIBUTES32, *POBJECT_ATTRIBUTES32;\n\ntypedef const OBJECT_ATTRIBUTES32 *PCOBJECT_ATTRIBUTES32;\n\n// Product types\n\ntypedef enum _NT_PRODUCT_TYPE\n{\n    NtProductWinNt = 1,\n    NtProductLanManNt,\n    NtProductServer\n} NT_PRODUCT_TYPE, *PNT_PRODUCT_TYPE;\n\ntypedef enum _SUITE_TYPE\n{\n    SmallBusiness,\n    Enterprise,\n    BackOffice,\n    CommunicationServer,\n    TerminalServer,\n    SmallBusinessRestricted,\n    EmbeddedNT,\n    DataCenter,\n    SingleUserTS,\n    Personal,\n    Blade,\n    EmbeddedRestricted,\n    SecurityAppliance,\n    StorageServer,\n    ComputeServer,\n    WHServer,\n    PhoneNT,\n    MaxSuiteType\n} SUITE_TYPE;\n\n// Specific\n\ntypedef struct _CLIENT_ID\n{\n    HANDLE UniqueProcess;\n    HANDLE UniqueThread;\n} CLIENT_ID, *PCLIENT_ID;\n\ntypedef struct _CLIENT_ID32\n{\n    ULONG UniqueProcess;\n    ULONG UniqueThread;\n} CLIENT_ID32, *PCLIENT_ID32;\n\ntypedef struct _CLIENT_ID64\n{\n    ULONGLONG UniqueProcess;\n    ULONGLONG UniqueThread;\n} CLIENT_ID64, *PCLIENT_ID64;\n\n#include <pshpack4.h>\n\ntypedef struct _KSYSTEM_TIME\n{\n    ULONG LowPart;\n    LONG High1Time;\n    LONG High2Time;\n} KSYSTEM_TIME, *PKSYSTEM_TIME;\n\n#include <poppack.h>\n\n#endif\n\n#endif\n"
  },
  {
    "path": "third_party/phnt/include/phnt_windows.h",
    "content": "#ifndef _PHNT_WINDOWS_H\n#define _PHNT_WINDOWS_H\n\n// This header file provides access to Win32, plus NTSTATUS values and some access mask values.\n\n#define WIN32_LEAN_AND_MEAN\n#define WIN32_NO_STATUS\n#include <windows.h>\n#undef WIN32_NO_STATUS\n#include <ntstatus.h>\n#include <winioctl.h>\n\ntypedef double DOUBLE;\ntypedef GUID *PGUID;\n\n// Desktop access rights\n#define DESKTOP_ALL_ACCESS \\\n    (DESKTOP_CREATEMENU | DESKTOP_CREATEWINDOW | DESKTOP_ENUMERATE | \\\n    DESKTOP_HOOKCONTROL | DESKTOP_JOURNALPLAYBACK | DESKTOP_JOURNALRECORD | \\\n    DESKTOP_READOBJECTS | DESKTOP_SWITCHDESKTOP | DESKTOP_WRITEOBJECTS | \\\n    STANDARD_RIGHTS_REQUIRED)\n#define DESKTOP_GENERIC_READ \\\n    (DESKTOP_ENUMERATE | DESKTOP_READOBJECTS | STANDARD_RIGHTS_READ)\n#define DESKTOP_GENERIC_WRITE \\\n    (DESKTOP_CREATEMENU | DESKTOP_CREATEWINDOW | DESKTOP_HOOKCONTROL | \\\n    DESKTOP_JOURNALPLAYBACK | DESKTOP_JOURNALRECORD | DESKTOP_WRITEOBJECTS | \\\n    STANDARD_RIGHTS_WRITE)\n#define DESKTOP_GENERIC_EXECUTE \\\n    (DESKTOP_SWITCHDESKTOP | STANDARD_RIGHTS_EXECUTE)\n\n// Window station access rights\n#define WINSTA_GENERIC_READ \\\n    (WINSTA_ENUMDESKTOPS | WINSTA_ENUMERATE | WINSTA_READATTRIBUTES | \\\n    WINSTA_READSCREEN | STANDARD_RIGHTS_READ)\n#define WINSTA_GENERIC_WRITE \\\n    (WINSTA_ACCESSCLIPBOARD | WINSTA_CREATEDESKTOP | WINSTA_WRITEATTRIBUTES | \\\n    STANDARD_RIGHTS_WRITE)\n#define WINSTA_GENERIC_EXECUTE \\\n    (WINSTA_ACCESSGLOBALATOMS | WINSTA_EXITWINDOWS | STANDARD_RIGHTS_EXECUTE)\n\n// WMI access rights\n#define WMIGUID_GENERIC_READ \\\n    (WMIGUID_QUERY | WMIGUID_NOTIFICATION | WMIGUID_READ_DESCRIPTION | \\\n    STANDARD_RIGHTS_READ)\n#define WMIGUID_GENERIC_WRITE \\\n    (WMIGUID_SET | TRACELOG_CREATE_REALTIME | TRACELOG_CREATE_ONDISK | \\\n    STANDARD_RIGHTS_WRITE)\n#define WMIGUID_GENERIC_EXECUTE \\\n    (WMIGUID_EXECUTE | TRACELOG_GUID_ENABLE | TRACELOG_LOG_EVENT | \\\n    TRACELOG_ACCESS_REALTIME | TRACELOG_REGISTER_GUIDS | \\\n    STANDARD_RIGHTS_EXECUTE)\n\n#endif\n"
  },
  {
    "path": "third_party/phnt/include/subprocesstag.h",
    "content": "#ifndef _SUBPROCESSTAG_H\n#define _SUBPROCESSTAG_H\n\n// Subprocess tag information\n\ntypedef enum _TAG_INFO_LEVEL\n{\n    eTagInfoLevelNameFromTag = 1, // TAG_INFO_NAME_FROM_TAG\n    eTagInfoLevelNamesReferencingModule, // TAG_INFO_NAMES_REFERENCING_MODULE\n    eTagInfoLevelNameTagMapping, // TAG_INFO_NAME_TAG_MAPPING\n    eTagInfoLevelMax\n} TAG_INFO_LEVEL;\n\ntypedef enum _TAG_TYPE\n{\n    eTagTypeService = 1,\n    eTagTypeMax\n} TAG_TYPE;\n\ntypedef struct _TAG_INFO_NAME_FROM_TAG_IN_PARAMS\n{\n    DWORD dwPid;\n    DWORD dwTag;\n} TAG_INFO_NAME_FROM_TAG_IN_PARAMS, *PTAG_INFO_NAME_FROM_TAG_IN_PARAMS;\n\ntypedef struct _TAG_INFO_NAME_FROM_TAG_OUT_PARAMS\n{\n    DWORD eTagType;\n    LPWSTR pszName;\n} TAG_INFO_NAME_FROM_TAG_OUT_PARAMS, *PTAG_INFO_NAME_FROM_TAG_OUT_PARAMS;\n\ntypedef struct _TAG_INFO_NAME_FROM_TAG\n{\n    TAG_INFO_NAME_FROM_TAG_IN_PARAMS InParams;\n    TAG_INFO_NAME_FROM_TAG_OUT_PARAMS OutParams;\n} TAG_INFO_NAME_FROM_TAG, *PTAG_INFO_NAME_FROM_TAG;\n\ntypedef struct _TAG_INFO_NAMES_REFERENCING_MODULE_IN_PARAMS\n{\n    DWORD dwPid;\n    LPWSTR pszModule;\n} TAG_INFO_NAMES_REFERENCING_MODULE_IN_PARAMS, *PTAG_INFO_NAMES_REFERENCING_MODULE_IN_PARAMS;\n\ntypedef struct _TAG_INFO_NAMES_REFERENCING_MODULE_OUT_PARAMS\n{\n    DWORD eTagType;\n    LPWSTR pmszNames;\n} TAG_INFO_NAMES_REFERENCING_MODULE_OUT_PARAMS, *PTAG_INFO_NAMES_REFERENCING_MODULE_OUT_PARAMS;\n\ntypedef struct _TAG_INFO_NAMES_REFERENCING_MODULE\n{\n    TAG_INFO_NAMES_REFERENCING_MODULE_IN_PARAMS InParams;\n    TAG_INFO_NAMES_REFERENCING_MODULE_OUT_PARAMS OutParams;\n} TAG_INFO_NAMES_REFERENCING_MODULE, *PTAG_INFO_NAMES_REFERENCING_MODULE;\n\ntypedef struct _TAG_INFO_NAME_TAG_MAPPING_IN_PARAMS\n{\n    DWORD dwPid;\n} TAG_INFO_NAME_TAG_MAPPING_IN_PARAMS, *PTAG_INFO_NAME_TAG_MAPPING_IN_PARAMS;\n\ntypedef struct _TAG_INFO_NAME_TAG_MAPPING_ELEMENT\n{\n    DWORD eTagType;\n    DWORD dwTag;\n    LPWSTR pszName;\n    LPWSTR pszGroupName;\n} TAG_INFO_NAME_TAG_MAPPING_ELEMENT, *PTAG_INFO_NAME_TAG_MAPPING_ELEMENT;\n\ntypedef struct _TAG_INFO_NAME_TAG_MAPPING_OUT_PARAMS\n{\n    DWORD cElements;\n    PTAG_INFO_NAME_TAG_MAPPING_ELEMENT pNameTagMappingElements;\n} TAG_INFO_NAME_TAG_MAPPING_OUT_PARAMS, *PTAG_INFO_NAME_TAG_MAPPING_OUT_PARAMS;\n\ntypedef struct _TAG_INFO_NAME_TAG_MAPPING\n{\n    TAG_INFO_NAME_TAG_MAPPING_IN_PARAMS InParams;\n    PTAG_INFO_NAME_TAG_MAPPING_OUT_PARAMS pOutParams;\n} TAG_INFO_NAME_TAG_MAPPING, *PTAG_INFO_NAME_TAG_MAPPING;\n\n_Must_inspect_result_\nDWORD\nWINAPI\nI_QueryTagInformation(\n    _In_opt_ LPCWSTR pszMachineName,\n    _In_ TAG_INFO_LEVEL eInfoLevel,\n    _Inout_ PVOID pTagInfo\n    );\n\ntypedef DWORD (WINAPI *PQUERY_TAG_INFORMATION)(\n    _In_opt_ LPCWSTR pszMachineName,\n    _In_ TAG_INFO_LEVEL eInfoLevel,\n    _Inout_ PVOID pTagInfo\n    );\n\n#endif\n"
  },
  {
    "path": "third_party/phnt/include/winsta.h",
    "content": "#ifndef _WINSTA_H\n#define _WINSTA_H\n\n// begin_msdn:http://msdn.microsoft.com/en-us/library/cc248779%28PROT.10%29.aspx\n\n// Access rights\n\n#define WINSTATION_QUERY 0x00000001 // WinStationQueryInformation\n#define WINSTATION_SET 0x00000002 // WinStationSetInformation\n#define WINSTATION_RESET 0x00000004 // WinStationReset\n#define WINSTATION_VIRTUAL 0x00000008 //read/write direct data\n#define WINSTATION_SHADOW 0x00000010 // WinStationShadow\n#define WINSTATION_LOGON 0x00000020 // logon to WinStation\n#define WINSTATION_LOGOFF 0x00000040 // WinStationLogoff\n#define WINSTATION_MSG 0x00000080 // WinStationMsg\n#define WINSTATION_CONNECT 0x00000100 // WinStationConnect\n#define WINSTATION_DISCONNECT 0x00000200 // WinStationDisconnect\n#define WINSTATION_GUEST_ACCESS WINSTATION_LOGON\n\n#define WINSTATION_CURRENT_GUEST_ACCESS (WINSTATION_VIRTUAL | WINSTATION_LOGOFF)\n#define WINSTATION_USER_ACCESS (WINSTATION_GUEST_ACCESS | WINSTATION_QUERY | WINSTATION_CONNECT)\n#define WINSTATION_CURRENT_USER_ACCESS \\\n    (WINSTATION_SET | WINSTATION_RESET | WINSTATION_VIRTUAL | \\\n    WINSTATION_LOGOFF | WINSTATION_DISCONNECT)\n#define WINSTATION_ALL_ACCESS (STANDARD_RIGHTS_REQUIRED | WINSTATION_QUERY | \\\n    WINSTATION_SET | WINSTATION_RESET | WINSTATION_VIRTUAL | \\\n    WINSTATION_SHADOW | WINSTATION_LOGON | WINSTATION_MSG | \\\n    WINSTATION_CONNECT | WINSTATION_DISCONNECT)\n\n#define WDPREFIX_LENGTH 12\n#define STACK_ADDRESS_LENGTH 128\n#define MAX_BR_NAME 65\n#define DIRECTORY_LENGTH 256\n#define INITIALPROGRAM_LENGTH 256\n#define USERNAME_LENGTH 20\n#define DOMAIN_LENGTH 17\n#define PASSWORD_LENGTH 14\n#define NASISPECIFICNAME_LENGTH 14\n#define NASIUSERNAME_LENGTH 47\n#define NASIPASSWORD_LENGTH 24\n#define NASISESSIONNAME_LENGTH 16\n#define NASIFILESERVER_LENGTH 47\n\n#define CLIENTDATANAME_LENGTH 7\n#define CLIENTNAME_LENGTH 20\n#define CLIENTADDRESS_LENGTH 30\n#define IMEFILENAME_LENGTH 32\n#define DIRECTORY_LENGTH 256\n#define CLIENTLICENSE_LENGTH 32\n#define CLIENTMODEM_LENGTH 40\n#define CLIENT_PRODUCT_ID_LENGTH 32\n#define MAX_COUNTER_EXTENSIONS 2\n#define WINSTATIONNAME_LENGTH 32\n\n#define TERMSRV_TOTAL_SESSIONS 1\n#define TERMSRV_DISC_SESSIONS 2\n#define TERMSRV_RECON_SESSIONS 3\n#define TERMSRV_CURRENT_ACTIVE_SESSIONS 4\n#define TERMSRV_CURRENT_DISC_SESSIONS 5\n#define TERMSRV_PENDING_SESSIONS 6\n#define TERMSRV_SUCC_TOTAL_LOGONS 7\n#define TERMSRV_SUCC_LOCAL_LOGONS 8\n#define TERMSRV_SUCC_REMOTE_LOGONS 9\n#define TERMSRV_SUCC_SESSION0_LOGONS 10\n#define TERMSRV_CURRENT_TERMINATING_SESSIONS 11\n#define TERMSRV_CURRENT_LOGGEDON_SESSIONS 12\n\ntypedef RTL_TIME_ZONE_INFORMATION TS_TIME_ZONE_INFORMATION, *PTS_TIME_ZONE_INFORMATION;\n\ntypedef WCHAR WINSTATIONNAME[WINSTATIONNAME_LENGTH + 1];\n\n// Variable length data descriptor (not needed)\ntypedef struct _VARDATA_WIRE\n{\n    USHORT Size;\n    USHORT Offset;\n} VARDATA_WIRE, *PVARDATA_WIRE;\n\ntypedef enum _WINSTATIONSTATECLASS\n{\n    State_Active = 0,\n    State_Connected = 1,\n    State_ConnectQuery = 2,\n    State_Shadow = 3,\n    State_Disconnected = 4,\n    State_Idle = 5,\n    State_Listen = 6,\n    State_Reset = 7,\n    State_Down = 8,\n    State_Init = 9\n} WINSTATIONSTATECLASS;\n\ntypedef struct _SESSIONIDW\n{\n    union\n    {\n        ULONG SessionId;\n        ULONG LogonId;\n    };\n    WINSTATIONNAME WinStationName;\n    WINSTATIONSTATECLASS State;\n} SESSIONIDW, *PSESSIONIDW;\n\n// private\ntypedef enum _WINSTATIONINFOCLASS\n{\n    WinStationCreateData,\n    WinStationConfiguration,\n    WinStationPdParams,\n    WinStationWd,\n    WinStationPd,\n    WinStationPrinter,\n    WinStationClient,\n    WinStationModules,\n    WinStationInformation,\n    WinStationTrace,\n    WinStationBeep,\n    WinStationEncryptionOff,\n    WinStationEncryptionPerm,\n    WinStationNtSecurity,\n    WinStationUserToken,\n    WinStationUnused1,\n    WinStationVideoData,\n    WinStationInitialProgram,\n    WinStationCd,\n    WinStationSystemTrace,\n    WinStationVirtualData,\n    WinStationClientData,\n    WinStationSecureDesktopEnter,\n    WinStationSecureDesktopExit,\n    WinStationLoadBalanceSessionTarget,\n    WinStationLoadIndicator,\n    WinStationShadowInfo,\n    WinStationDigProductId,\n    WinStationLockedState,\n    WinStationRemoteAddress,\n    WinStationIdleTime,\n    WinStationLastReconnectType,\n    WinStationDisallowAutoReconnect,\n    WinStationMprNotifyInfo,\n    WinStationExecSrvSystemPipe,\n    WinStationSmartCardAutoLogon,\n    WinStationIsAdminLoggedOn,\n    WinStationReconnectedFromId,\n    WinStationEffectsPolicy,\n    WinStationType,\n    WinStationInformationEx,\n    WinStationValidationInfo\n} WINSTATIONINFOCLASS;\n\n// WinStationCreateData\ntypedef struct _WINSTATIONCREATE\n{\n    ULONG fEnableWinStation : 1;\n    ULONG MaxInstanceCount;\n} WINSTATIONCREATE, *PWINSTATIONCREATE;\n\n// WinStationClient\ntypedef struct _WINSTATIONCLIENT\n{\n    ULONG fTextOnly : 1;\n    ULONG fDisableCtrlAltDel : 1;\n    ULONG fMouse : 1;\n    ULONG fDoubleClickDetect : 1;\n    ULONG fINetClient : 1;\n    ULONG fPromptForPassword : 1;\n    ULONG fMaximizeShell : 1;\n    ULONG fEnableWindowsKey : 1;\n    ULONG fRemoteConsoleAudio : 1;\n    ULONG fPasswordIsScPin : 1;\n    ULONG fNoAudioPlayback : 1;\n    ULONG fUsingSavedCreds : 1;\n    WCHAR ClientName[CLIENTNAME_LENGTH + 1];\n    WCHAR Domain[DOMAIN_LENGTH + 1];\n    WCHAR UserName[USERNAME_LENGTH + 1];\n    WCHAR Password[PASSWORD_LENGTH + 1];\n    WCHAR WorkDirectory[DIRECTORY_LENGTH + 1];\n    WCHAR InitialProgram[INITIALPROGRAM_LENGTH + 1];\n    ULONG SerialNumber;\n    BYTE EncryptionLevel;\n    ULONG ClientAddressFamily;\n    WCHAR ClientAddress[CLIENTADDRESS_LENGTH + 1];\n    USHORT HRes;\n    USHORT VRes;\n    USHORT ColorDepth;\n    USHORT ProtocolType;\n    ULONG KeyboardLayout;\n    ULONG KeyboardType;\n    ULONG KeyboardSubType;\n    ULONG KeyboardFunctionKey;\n    WCHAR ImeFileName[IMEFILENAME_LENGTH + 1];\n    WCHAR ClientDirectory[DIRECTORY_LENGTH + 1];\n    WCHAR ClientLicense[CLIENTLICENSE_LENGTH + 1];\n    WCHAR ClientModem[CLIENTMODEM_LENGTH + 1];\n    ULONG ClientBuildNumber;\n    ULONG ClientHardwareId;\n    USHORT ClientProductId;\n    USHORT OutBufCountHost;\n    USHORT OutBufCountClient;\n    USHORT OutBufLength;\n    WCHAR AudioDriverName[9];\n    TS_TIME_ZONE_INFORMATION ClientTimeZone;\n    ULONG ClientSessionId;\n    WCHAR ClientDigProductId[CLIENT_PRODUCT_ID_LENGTH];\n    ULONG PerformanceFlags;\n    ULONG ActiveInputLocale;\n} WINSTATIONCLIENT, *PWINSTATIONCLIENT;\n\ntypedef struct _TSHARE_COUNTERS\n{\n    ULONG Reserved;\n} TSHARE_COUNTERS, *PTSHARE_COUNTERS;\n\ntypedef struct _PROTOCOLCOUNTERS\n{\n    ULONG WdBytes;\n    ULONG WdFrames;\n    ULONG WaitForOutBuf;\n    ULONG Frames;\n    ULONG Bytes;\n    ULONG CompressedBytes;\n    ULONG CompressFlushes;\n    ULONG Errors;\n    ULONG Timeouts;\n    ULONG AsyncFramingError;\n    ULONG AsyncOverrunError;\n    ULONG AsyncOverflowError;\n    ULONG AsyncParityError;\n    ULONG TdErrors;\n    USHORT ProtocolType;\n    USHORT Length;\n    union\n    {\n        TSHARE_COUNTERS TShareCounters;\n        ULONG Reserved[100];\n    } Specific;\n} PROTOCOLCOUNTERS, *PPROTOCOLCOUNTERS;\n\ntypedef struct _THINWIRECACHE\n{\n    ULONG CacheReads;\n    ULONG CacheHits;\n} THINWIRECACHE, *PTHINWIRECACHE;\n\n#define MAX_THINWIRECACHE 4\n\ntypedef struct _RESERVED_CACHE\n{\n    THINWIRECACHE ThinWireCache[MAX_THINWIRECACHE];\n} RESERVED_CACHE, *PRESERVED_CACHE;\n\ntypedef struct _TSHARE_CACHE\n{\n    ULONG Reserved;\n} TSHARE_CACHE, *PTSHARE_CACHE;\n\ntypedef struct CACHE_STATISTICS\n{\n    USHORT ProtocolType;\n    USHORT Length;\n    union\n    {\n        RESERVED_CACHE ReservedCacheStats;\n        TSHARE_CACHE TShareCacheStats;\n        ULONG Reserved[20];\n    } Specific;\n} CACHE_STATISTICS, *PCACHE_STATISTICS;\n\ntypedef struct _PROTOCOLSTATUS\n{\n    PROTOCOLCOUNTERS Output;\n    PROTOCOLCOUNTERS Input;\n    CACHE_STATISTICS Cache;\n    ULONG AsyncSignal;\n    ULONG AsyncSignalMask;\n} PROTOCOLSTATUS, *PPROTOCOLSTATUS;\n\n// WinStationInformation\ntypedef struct _WINSTATIONINFORMATION\n{\n    WINSTATIONSTATECLASS ConnectState;\n    WINSTATIONNAME WinStationName;\n    ULONG LogonId;\n    LARGE_INTEGER ConnectTime;\n    LARGE_INTEGER DisconnectTime;\n    LARGE_INTEGER LastInputTime;\n    LARGE_INTEGER LogonTime;\n    PROTOCOLSTATUS Status;\n    WCHAR Domain[DOMAIN_LENGTH + 1];\n    WCHAR UserName[USERNAME_LENGTH + 1];\n    LARGE_INTEGER CurrentTime;\n} WINSTATIONINFORMATION, *PWINSTATIONINFORMATION;\n\n// WinStationUserToken\ntypedef struct _WINSTATIONUSERTOKEN\n{\n    HANDLE ProcessId;\n    HANDLE ThreadId;\n    HANDLE UserToken;\n} WINSTATIONUSERTOKEN, *PWINSTATIONUSERTOKEN;\n\n// WinStationVideoData\ntypedef struct _WINSTATIONVIDEODATA\n{\n    USHORT HResolution;\n    USHORT VResolution;\n    USHORT fColorDepth;\n} WINSTATIONVIDEODATA, *PWINSTATIONVIDEODATA;\n\n// WinStationDigProductId\ntypedef struct _WINSTATIONPRODID\n{\n    WCHAR DigProductId[CLIENT_PRODUCT_ID_LENGTH];\n    WCHAR ClientDigProductId[CLIENT_PRODUCT_ID_LENGTH];\n    WCHAR OuterMostDigProductId[CLIENT_PRODUCT_ID_LENGTH];\n    ULONG CurrentSessionId;\n    ULONG ClientSessionId;\n    ULONG OuterMostSessionId;\n} WINSTATIONPRODID, *PWINSTATIONPRODID;\n\n// WinStationRemoteAddress\ntypedef struct _WINSTATIONREMOTEADDRESS\n{\n    USHORT sin_family;\n    union\n    {\n        struct\n        {\n            USHORT sin_port;\n            ULONG sin_addr;\n            UCHAR sin_zero[8];\n        } ipv4;\n        struct\n        {\n            USHORT sin6_port;\n            ULONG sin6_flowinfo;\n            USHORT sin6_addr[8];\n            ULONG sin6_scope_id;\n        } ipv6;\n    };\n} WINSTATIONREMOTEADDRESS, *PWINSTATIONREMOTEADDRESS;\n\n// WinStationInformationEx\n\n// private\ntypedef struct _WINSTATIONINFORMATIONEX_LEVEL1\n{\n    ULONG SessionId;\n    WINSTATIONSTATECLASS SessionState;\n    LONG SessionFlags;\n    WINSTATIONNAME WinStationName;\n    WCHAR UserName[USERNAME_LENGTH + 1];\n    WCHAR DomainName[DOMAIN_LENGTH + 1];\n    LARGE_INTEGER LogonTime;\n    LARGE_INTEGER ConnectTime;\n    LARGE_INTEGER DisconnectTime;\n    LARGE_INTEGER LastInputTime;\n    LARGE_INTEGER CurrentTime;\n    PROTOCOLSTATUS ProtocolStatus;\n} WINSTATIONINFORMATIONEX_LEVEL1, *PWINSTATIONINFORMATIONEX_LEVEL1;\n\n// private\ntypedef struct _WINSTATIONINFORMATIONEX_LEVEL2\n{\n    ULONG SessionId;\n    WINSTATIONSTATECLASS SessionState;\n    LONG SessionFlags;\n    WINSTATIONNAME WinStationName;\n    WCHAR SamCompatibleUserName[USERNAME_LENGTH + 1];\n    WCHAR SamCompatibleDomainName[DOMAIN_LENGTH + 1];\n    LARGE_INTEGER LogonTime;\n    LARGE_INTEGER ConnectTime;\n    LARGE_INTEGER DisconnectTime;\n    LARGE_INTEGER LastInputTime;\n    LARGE_INTEGER CurrentTime;\n    PROTOCOLSTATUS ProtocolStatus;\n    WCHAR UserName[257];\n    WCHAR DomainName[256];\n} WINSTATIONINFORMATIONEX_LEVEL2, *PWINSTATIONINFORMATIONEX_LEVEL2;\n\n// private\ntypedef union _WINSTATIONINFORMATIONEX_LEVEL\n{\n    WINSTATIONINFORMATIONEX_LEVEL1 WinStationInfoExLevel1;\n    WINSTATIONINFORMATIONEX_LEVEL2 WinStationInfoExLevel2;\n} WINSTATIONINFORMATIONEX_LEVEL, *PWINSTATIONINFORMATIONEX_LEVEL;\n\n// private\ntypedef struct _WINSTATIONINFORMATIONEX\n{\n    ULONG Level;\n    WINSTATIONINFORMATIONEX_LEVEL Data;\n} WINSTATIONINFORMATIONEX, *PWINSTATIONINFORMATIONEX;\n\n#define TS_PROCESS_INFO_MAGIC_NT4 0x23495452\n\ntypedef struct _TS_PROCESS_INFORMATION_NT4\n{\n    ULONG MagicNumber;\n    ULONG LogonId;\n    PVOID ProcessSid;\n    ULONG Pad;\n} TS_PROCESS_INFORMATION_NT4, *PTS_PROCESS_INFORMATION_NT4;\n\n#define SIZEOF_TS4_SYSTEM_THREAD_INFORMATION 64\n#define SIZEOF_TS4_SYSTEM_PROCESS_INFORMATION 136\n\ntypedef struct _TS_SYS_PROCESS_INFORMATION\n{\n    ULONG NextEntryOffset;\n    ULONG NumberOfThreads;\n    LARGE_INTEGER SpareLi1;\n    LARGE_INTEGER SpareLi2;\n    LARGE_INTEGER SpareLi3;\n    LARGE_INTEGER CreateTime;\n    LARGE_INTEGER UserTime;\n    LARGE_INTEGER KernelTime;\n    UNICODE_STRING ImageName;\n    LONG BasePriority;\n    ULONG UniqueProcessId;\n    ULONG InheritedFromUniqueProcessId;\n    ULONG HandleCount;\n    ULONG SessionId;\n    ULONG SpareUl3;\n    SIZE_T PeakVirtualSize;\n    SIZE_T VirtualSize;\n    ULONG PageFaultCount;\n    ULONG PeakWorkingSetSize;\n    ULONG WorkingSetSize;\n    SIZE_T QuotaPeakPagedPoolUsage;\n    SIZE_T QuotaPagedPoolUsage;\n    SIZE_T QuotaPeakNonPagedPoolUsage;\n    SIZE_T QuotaNonPagedPoolUsage;\n    SIZE_T PagefileUsage;\n    SIZE_T PeakPagefileUsage;\n    SIZE_T PrivatePageCount;\n} TS_SYS_PROCESS_INFORMATION, *PTS_SYS_PROCESS_INFORMATION;\n\ntypedef struct _TS_ALL_PROCESSES_INFO\n{\n    PTS_SYS_PROCESS_INFORMATION pTsProcessInfo;\n    ULONG SizeOfSid;\n    PSID pSid;\n} TS_ALL_PROCESSES_INFO, *PTS_ALL_PROCESSES_INFO;\n\ntypedef struct _TS_COUNTER_HEADER\n{\n    DWORD dwCounterID;\n    BOOLEAN bResult;\n} TS_COUNTER_HEADER, *PTS_COUNTER_HEADER;\n\ntypedef struct _TS_COUNTER\n{\n    TS_COUNTER_HEADER CounterHead;\n    DWORD dwValue;\n    LARGE_INTEGER StartTime;\n} TS_COUNTER, *PTS_COUNTER;\n\n// Flags for WinStationShutdownSystem\n#define WSD_LOGOFF 0x1\n#define WSD_SHUTDOWN 0x2\n#define WSD_REBOOT 0x4\n#define WSD_POWEROFF 0x8\n\n// Flags for WinStationWaitSystemEvent\n#define WEVENT_NONE 0x0\n#define WEVENT_CREATE 0x1\n#define WEVENT_DELETE 0x2\n#define WEVENT_RENAME 0x4\n#define WEVENT_CONNECT 0x8\n#define WEVENT_DISCONNECT 0x10\n#define WEVENT_LOGON 0x20\n#define WEVENT_LOGOFF 0x40\n#define WEVENT_STATECHANGE 0x80\n#define WEVENT_LICENSE 0x100\n#define WEVENT_ALL 0x7fffffff\n#define WEVENT_FLUSH 0x80000000\n\n// Hotkey modifiers for WinStationShadow\n#define KBDSHIFT 0x1\n#define KBDCTRL 0x2\n#define KBDALT 0x4\n\n// begin_rev\n// Flags for WinStationRegisterConsoleNotification\n#define WNOTIFY_ALL_SESSIONS 0x1\n// end_rev\n\n// In the functions below, memory returned can be freed using LocalFree. NULL can be specified for\n// server handles to indicate the local server. -1 can be specified for session IDs to indicate the\n// current session ID.\n\n#define LOGONID_CURRENT (-1)\n#define SERVERNAME_CURRENT (NULL)\n\n// rev\nBOOLEAN\nWINAPI\nWinStationFreeMemory(\n    _In_ PVOID Buffer\n    );\n\n// rev\nHANDLE\nWINAPI\nWinStationOpenServerW(\n    _In_ PWSTR ServerName\n    );\n\n// rev\nBOOLEAN\nWINAPI\nWinStationCloseServer(\n    _In_ HANDLE hServer\n    );\n\n// rev\nBOOLEAN\nWINAPI\nWinStationServerPing(\n    _In_opt_ HANDLE hServer\n    );\n\n// rev\nBOOLEAN\nWINAPI\nWinStationGetTermSrvCountersValue(\n    _In_opt_ HANDLE hServer,\n    _In_ ULONG Count,\n    _Inout_ PTS_COUNTER Counters // set counter IDs before calling\n    );\n\nBOOLEAN\nWINAPI\nWinStationShutdownSystem(\n    _In_opt_ HANDLE hServer,\n    _In_ ULONG ShutdownFlags // WSD_*\n    );\n\n// rev\nBOOLEAN\nWINAPI\nWinStationWaitSystemEvent(\n    _In_opt_ HANDLE hServer,\n    _In_ ULONG EventMask, // WEVENT_*\n    _Out_ PULONG EventFlags\n    );\n\n// rev\nBOOLEAN\nWINAPI\nWinStationRegisterConsoleNotification(\n    _In_opt_ HANDLE hServer,\n    _In_ HWND WindowHandle,\n    _In_ ULONG Flags\n    );\n\n// rev\nBOOLEAN\nWINAPI\nWinStationUnRegisterConsoleNotification(\n    _In_opt_ HANDLE hServer,\n    _In_ HWND WindowHandle\n    );\n\n// Sessions\n\n// rev\nBOOLEAN\nWINAPI\nWinStationEnumerateW(\n    _In_opt_ HANDLE hServer,\n    _Out_ PSESSIONIDW *SessionIds,\n    _Out_ PULONG Count\n    );\n\nBOOLEAN\nWINAPI\nWinStationQueryInformationW(\n    _In_opt_ HANDLE hServer,\n    _In_ ULONG SessionId,\n    _In_ WINSTATIONINFOCLASS WinStationInformationClass,\n    _Out_writes_bytes_(WinStationInformationLength) PVOID pWinStationInformation,\n    _In_ ULONG WinStationInformationLength,\n    _Out_ PULONG pReturnLength\n    );\n\n// rev\nBOOLEAN\nWINAPI\nWinStationSetInformationW(\n    _In_opt_ HANDLE hServer,\n    _In_ ULONG SessionId,\n    _In_ WINSTATIONINFOCLASS WinStationInformationClass,\n    _In_reads_bytes_(WinStationInformationLength) PVOID pWinStationInformation,\n    _In_ ULONG WinStationInformationLength\n    );\n\nBOOLEAN\nWINAPI\nWinStationNameFromLogonIdW(\n    _In_opt_ HANDLE hServer,\n    _In_ ULONG SessionId,\n    _Out_writes_(WINSTATIONNAME_LENGTH + 1) PWSTR pWinStationName\n    );\n\n// rev\nBOOLEAN\nWINAPI\nWinStationSendMessageW(\n    _In_opt_ HANDLE hServer,\n    _In_ ULONG SessionId,\n    _In_ PWSTR Title,\n    _In_ ULONG TitleLength,\n    _In_ PWSTR Message,\n    _In_ ULONG MessageLength,\n    _In_ ULONG Style,\n    _In_ ULONG Timeout,\n    _Out_ PULONG Response,\n    _In_ BOOLEAN DoNotWait\n    );\n\nBOOLEAN\nWINAPI\nWinStationConnectW(\n    _In_opt_ HANDLE hServer,\n    _In_ ULONG SessionId,\n    _In_ ULONG TargetSessionId,\n    _In_opt_ PWSTR pPassword,\n    _In_ BOOLEAN bWait\n    );\n\nBOOLEAN\nWINAPI\nWinStationDisconnect(\n    _In_opt_ HANDLE hServer,\n    _In_ ULONG SessionId,\n    _In_ BOOLEAN bWait\n    );\n\n// rev\nBOOLEAN\nWINAPI\nWinStationReset(\n    _In_opt_ HANDLE hServer,\n    _In_ ULONG SessionId,\n    _In_ BOOLEAN bWait\n    );\n\n// rev\nBOOLEAN\nWINAPI\nWinStationShadow(\n    _In_opt_ HANDLE hServer,\n    _In_ PWSTR TargetServerName,\n    _In_ ULONG TargetSessionId,\n    _In_ UCHAR HotKeyVk,\n    _In_ USHORT HotkeyModifiers // KBD*\n    );\n\n// rev\nBOOLEAN\nWINAPI\nWinStationShadowStop(\n    _In_opt_ HANDLE hServer,\n    _In_ ULONG SessionId,\n    _In_ BOOLEAN bWait // ignored\n    );\n\n// Processes\n\n// rev\nBOOLEAN\nWINAPI\nWinStationEnumerateProcesses(\n    _In_opt_ HANDLE hServer,\n    _Out_ PVOID *Processes\n    );\n\n// rev\nBOOLEAN\nWINAPI\nWinStationGetAllProcesses(\n    _In_opt_ HANDLE hServer,\n    _In_ ULONG Level,\n    _Out_ PULONG NumberOfProcesses,\n    _Out_ PTS_ALL_PROCESSES_INFO *Processes\n    );\n\n// rev\nBOOLEAN\nWINAPI\nWinStationFreeGAPMemory(\n    _In_ ULONG Level,\n    _In_ PTS_ALL_PROCESSES_INFO Processes,\n    _In_ ULONG NumberOfProcesses\n    );\n\n// rev\nBOOLEAN\nWINAPI\nWinStationTerminateProcess(\n    _In_opt_ HANDLE hServer,\n    _In_ ULONG ProcessId,\n    _In_ ULONG ExitCode\n    );\n\nBOOLEAN\nWINAPI\nWinStationGetProcessSid(\n    _In_opt_ HANDLE hServer,\n    _In_ ULONG ProcessId,\n    _In_ FILETIME ProcessStartTime,\n    _Out_ PVOID pProcessUserSid,\n    _Inout_ PULONG dwSidSize\n    );\n\n// Services isolation\n\n#if (PHNT_VERSION >= PHNT_VISTA)\n\n// rev\nBOOLEAN\nWINAPI\nWinStationSwitchToServicesSession(\n    VOID\n    );\n\n// rev\nBOOLEAN\nWINAPI\nWinStationRevertFromServicesSession(\n    VOID\n    );\n\n#endif\n\n// Misc.\n\nBOOLEAN\nWINAPI\n_WinStationWaitForConnect(\n    VOID\n    );\n\n// end_msdn\n\n#endif\n"
  },
  {
    "path": "third_party/phnt/zw_options.txt",
    "content": "base=include\nin=ntdbg.h;ntexapi.h;ntgdi.h;ntioapi.h;ntkeapi.h;ntldr.h;ntlpcapi.h;ntmisc.h;ntmmapi.h;ntnls.h;ntobapi.h;ntpebteb.h;ntpfapi.h;ntpnpapi.h;ntpoapi.h;ntpsapi.h;ntregapi.h;ntrtl.h;ntsam.h;ntseapi.h;nttmapi.h;nttp.h;ntwow64.h;ntxcapi.h\nout=ntzwapi.h\nheader=#ifndef _NTZWAPI_H\\r\\n#define _NTZWAPI_H\\r\\n\\r\\n// This file was automatically generated. Do not edit.\\r\\n\\r\\n\nfooter=#endif\\r\\n"
  }
]