[rst-commit] r152 - in /redwax-signtext-windows/trunk/Redwax SignText: ./ Redwax SignText (MFC)/ Redwax SignText (MFC)/res/ Redwax SignText Installer/ Redwax SignText/

rst-commit at redwax.eu rst-commit at redwax.eu
Sun Jun 23 16:39:07 CEST 2024


Author: minfrin at redwax.eu
Date: Sun Jun 23 16:39:06 2024
New Revision: 152

Log:
Initial add of the Redwax SignText native app for Windows MFC.

Added:
    redwax-signtext-windows/trunk/Redwax SignText/
    redwax-signtext-windows/trunk/Redwax SignText/Redwax SignText/   (with props)
    redwax-signtext-windows/trunk/Redwax SignText/Redwax SignText (MFC)/   (with props)
    redwax-signtext-windows/trunk/Redwax SignText/Redwax SignText (MFC)/Redwax SignText (MFC).cpp
    redwax-signtext-windows/trunk/Redwax SignText/Redwax SignText (MFC)/Redwax SignText (MFC).h
    redwax-signtext-windows/trunk/Redwax SignText/Redwax SignText (MFC)/Redwax SignText (MFC).vcxproj
    redwax-signtext-windows/trunk/Redwax SignText/Redwax SignText (MFC)/Redwax SignText (MFC).vcxproj.filters
    redwax-signtext-windows/trunk/Redwax SignText/Redwax SignText (MFC)/Redwax SignText (MFC)Dlg.cpp
    redwax-signtext-windows/trunk/Redwax SignText/Redwax SignText (MFC)/Redwax SignText (MFC)Dlg.h
    redwax-signtext-windows/trunk/Redwax SignText/Redwax SignText (MFC)/RedwaxSignTextMFC.rc   (with props)
    redwax-signtext-windows/trunk/Redwax SignText/Redwax SignText (MFC)/Resource.h
    redwax-signtext-windows/trunk/Redwax SignText/Redwax SignText (MFC)/SignPage.cpp
    redwax-signtext-windows/trunk/Redwax SignText/Redwax SignText (MFC)/SignPage.h
    redwax-signtext-windows/trunk/Redwax SignText/Redwax SignText (MFC)/cJSON.c
    redwax-signtext-windows/trunk/Redwax SignText/Redwax SignText (MFC)/cJSON.h
    redwax-signtext-windows/trunk/Redwax SignText/Redwax SignText (MFC)/crypto.c
    redwax-signtext-windows/trunk/Redwax SignText/Redwax SignText (MFC)/crypto.h
    redwax-signtext-windows/trunk/Redwax SignText/Redwax SignText (MFC)/framework.h
    redwax-signtext-windows/trunk/Redwax SignText/Redwax SignText (MFC)/message.c
    redwax-signtext-windows/trunk/Redwax SignText/Redwax SignText (MFC)/message.h
    redwax-signtext-windows/trunk/Redwax SignText/Redwax SignText (MFC)/pch.cpp
    redwax-signtext-windows/trunk/Redwax SignText/Redwax SignText (MFC)/pch.h
    redwax-signtext-windows/trunk/Redwax SignText/Redwax SignText (MFC)/res/
    redwax-signtext-windows/trunk/Redwax SignText/Redwax SignText (MFC)/res/Redwax SignText (MFC).ico   (with props)
    redwax-signtext-windows/trunk/Redwax SignText/Redwax SignText (MFC)/res/RedwaxSignTextMFC.rc2   (with props)
    redwax-signtext-windows/trunk/Redwax SignText/Redwax SignText (MFC)/signtext.c
    redwax-signtext-windows/trunk/Redwax SignText/Redwax SignText (MFC)/signtext.h
    redwax-signtext-windows/trunk/Redwax SignText/Redwax SignText (MFC)/targetver.h
    redwax-signtext-windows/trunk/Redwax SignText/Redwax SignText Installer/   (with props)
    redwax-signtext-windows/trunk/Redwax SignText/Redwax SignText Installer/Folders.wxs
    redwax-signtext-windows/trunk/Redwax SignText/Redwax SignText Installer/Package.en-us.wxl
    redwax-signtext-windows/trunk/Redwax SignText/Redwax SignText Installer/Package.wxs
    redwax-signtext-windows/trunk/Redwax SignText/Redwax SignText Installer/Redwax SignText Installer.wixproj
    redwax-signtext-windows/trunk/Redwax SignText/Redwax SignText/eu.redwax.Redwax.SignText.arm64.json
    redwax-signtext-windows/trunk/Redwax SignText/Redwax SignText/eu.redwax.Redwax.SignText.x64.json
    redwax-signtext-windows/trunk/Redwax SignText/Redwax SignText/eu.redwax.Redwax.SignText.x86.json

Propchange: redwax-signtext-windows/trunk/Redwax SignText/Redwax SignText/
------------------------------------------------------------------------------
--- svn:ignore	(added)
+++ svn:ignore	Sun Jun 23 16:39:06 2024
@@ -0,0 +1,13 @@
+[Bb]in
+obj
+[Dd]ebug
+[Rr]elease
+*.user
+*.aps
+*.eto
+ClientBin
+GeneratedArtifacts
+_Pvt_Extensions
+project.lock.json
+*.nuget.props
+*.nuget.targets

Propchange: redwax-signtext-windows/trunk/Redwax SignText/Redwax SignText (MFC)/
------------------------------------------------------------------------------
--- svn:ignore	(added)
+++ svn:ignore	Sun Jun 23 16:39:06 2024
@@ -0,0 +1,13 @@
+[Bb]in
+obj
+[Dd]ebug
+[Rr]elease
+*.user
+*.aps
+*.eto
+ClientBin
+GeneratedArtifacts
+_Pvt_Extensions
+project.lock.json
+*.nuget.props
+*.nuget.targets

Added: redwax-signtext-windows/trunk/Redwax SignText/Redwax SignText (MFC)/Redwax SignText (MFC).cpp
==============================================================================
--- redwax-signtext-windows/trunk/Redwax SignText/Redwax SignText (MFC)/Redwax SignText (MFC).cpp	(added)
+++ redwax-signtext-windows/trunk/Redwax SignText/Redwax SignText (MFC)/Redwax SignText (MFC).cpp	Sun Jun 23 16:39:06 2024
@@ -0,0 +1,147 @@
+/* Licensed to Stichting The Commons Conservancy (TCC) under one or more
+ * contributor license agreements.  See the AUTHORS file distributed with
+ * this work for additional information regarding copyright ownership.
+ * TCC licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "pch.h"
+#include "framework.h"
+#include "Redwax SignText (MFC).h"
+#include "Redwax SignText (MFC)Dlg.h"
+
+#ifdef _DEBUG
+#define new DEBUG_NEW
+#endif
+
+
+// CRedwaxSignTextMFCApp
+
+BEGIN_MESSAGE_MAP(CRedwaxSignTextMFCApp, CWinApp)
+	ON_COMMAND(ID_HELP, &CWinApp::OnHelp)
+END_MESSAGE_MAP()
+
+
+// CRedwaxSignTextMFCApp construction
+
+CRedwaxSignTextMFCApp::CRedwaxSignTextMFCApp()
+{
+	// support Restart Manager
+	m_dwRestartManagerSupportFlags = AFX_RESTART_MANAGER_SUPPORT_RESTART;
+
+	// TODO: add construction code here,
+	// Place all significant initialization in InitInstance
+}
+
+
+// The one and only CRedwaxSignTextMFCApp object
+
+CRedwaxSignTextMFCApp theApp;
+
+
+// CRedwaxSignTextMFCApp initialization
+
+BOOL CRedwaxSignTextMFCApp::InitInstance()
+{
+	// InitCommonControlsEx() is required on Windows XP if an application
+	// manifest specifies use of ComCtl32.dll version 6 or later to enable
+	// visual styles.  Otherwise, any window creation will fail.
+	INITCOMMONCONTROLSEX InitCtrls;
+	InitCtrls.dwSize = sizeof(InitCtrls);
+	// Set this to include all the common control classes you want to use
+	// in your application.
+	InitCtrls.dwICC = ICC_WIN95_CLASSES;
+	InitCommonControlsEx(&InitCtrls);
+
+	CWinApp::InitInstance();
+
+
+	// Create the shell manager, in case the dialog contains
+	// any shell tree view or shell list view controls.
+//	CShellManager *pShellManager = new CShellManager;
+
+	// Activate "Windows Native" visual manager for enabling themes in MFC controls
+	CMFCVisualManager::SetDefaultManager(RUNTIME_CLASS(CMFCVisualManagerWindows));
+
+	// Standard initialization
+	// If you are not using these features and wish to reduce the size
+	// of your final executable, you should remove from the following
+	// the specific initialization routines you do not need
+	// Change the registry key under which our settings are stored
+	// TODO: You should modify this string to be something appropriate
+	// such as the name of your company or organization
+//	SetRegistryKey(_T("Local AppWizard-Generated Applications"));
+
+
+
+#if 0
+	while (!::IsDebuggerPresent())
+		::Sleep(100); // to avoid 100% CPU load
+#endif
+
+//	CRedwaxSignTextMFCDlg dlg;
+//	m_pMainWnd = &dlg;
+
+#if 1
+
+	CRedwaxSignTextMFCDlg *dlg = new CRedwaxSignTextMFCDlg();
+	m_pMainWnd = dlg;
+
+	dlg->Create(IDD_REDWAX_SIGNTEXT_MFC_DIALOG);
+//	dlg->ShowWindow(SW_HIDE);
+
+	return TRUE;
+#endif
+
+#if 0
+
+	CRedwaxSignTextMFCDlg dlg;
+	m_pMainWnd = &dlg;
+
+	INT_PTR nResponse = dlg.DoModal();
+	if (nResponse == IDOK)
+	{
+		// TODO: Place code here to handle when the dialog is
+		//  dismissed with OK
+	}
+	else if (nResponse == IDCANCEL)
+	{
+		// TODO: Place code here to handle when the dialog is
+		//  dismissed with Cancel
+	}
+	else if (nResponse == -1)
+	{
+		TRACE(traceAppMsg, 0, "Warning: dialog creation failed, so application is terminating unexpectedly.\n");
+		TRACE(traceAppMsg, 0, "Warning: if you are using MFC controls on the dialog, you cannot #define _AFX_NO_MFC_CONTROLS_IN_DIALOGS.\n");
+	}
+
+	// Delete the shell manager created above.
+	if (pShellManager != nullptr)
+	{
+		delete pShellManager;
+	}
+
+#if !defined(_AFXDLL) && !defined(_AFX_NO_MFC_CONTROLS_IN_DIALOGS)
+	ControlBarCleanUp();
+#endif
+
+	// Since the dialog has been closed, return FALSE so that we exit the
+	//  application, rather than start the application's message pump.
+	return FALSE;
+#endif
+
+}
+
+BOOL CRedwaxSignTextMFCApp::ExitInstance()
+{
+	return CWinApp::ExitInstance();
+}

Added: redwax-signtext-windows/trunk/Redwax SignText/Redwax SignText (MFC)/Redwax SignText (MFC).h
==============================================================================
--- redwax-signtext-windows/trunk/Redwax SignText/Redwax SignText (MFC)/Redwax SignText (MFC).h	(added)
+++ redwax-signtext-windows/trunk/Redwax SignText/Redwax SignText (MFC)/Redwax SignText (MFC).h	Sun Jun 23 16:39:06 2024
@@ -0,0 +1,51 @@
+/* Licensed to Stichting The Commons Conservancy (TCC) under one or more
+ * contributor license agreements.  See the AUTHORS file distributed with
+ * this work for additional information regarding copyright ownership.
+ * TCC licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#ifndef __AFXWIN_H__
+	#error "include 'pch.h' before including this file for PCH"
+#endif
+
+#include "resource.h"		// main symbols
+
+#include "signtext.h"
+#include "message.h"
+#include "crypto.h"
+
+
+// CRedwaxSignTextMFCApp:
+// See Redwax SignText (MFC).cpp for the implementation of this class
+//
+
+class CRedwaxSignTextMFCApp : public CWinApp
+{
+public:
+	CRedwaxSignTextMFCApp();
+
+// Overrides
+public:
+	virtual BOOL InitInstance();
+	virtual BOOL ExitInstance();
+
+// Implementation
+
+	DECLARE_MESSAGE_MAP()
+
+protected:
+};
+
+extern CRedwaxSignTextMFCApp theApp;

Added: redwax-signtext-windows/trunk/Redwax SignText/Redwax SignText (MFC)/Redwax SignText (MFC).vcxproj
==============================================================================
--- redwax-signtext-windows/trunk/Redwax SignText/Redwax SignText (MFC)/Redwax SignText (MFC).vcxproj	(added)
+++ redwax-signtext-windows/trunk/Redwax SignText/Redwax SignText (MFC)/Redwax SignText (MFC).vcxproj	Sun Jun 23 16:39:06 2024
@@ -0,0 +1,227 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+  <ItemGroup Label="ProjectConfigurations">
+    <ProjectConfiguration Include="Debug|Win32">
+      <Configuration>Debug</Configuration>
+      <Platform>Win32</Platform>
+    </ProjectConfiguration>
+    <ProjectConfiguration Include="Release|Win32">
+      <Configuration>Release</Configuration>
+      <Platform>Win32</Platform>
+    </ProjectConfiguration>
+    <ProjectConfiguration Include="Debug|x64">
+      <Configuration>Debug</Configuration>
+      <Platform>x64</Platform>
+    </ProjectConfiguration>
+    <ProjectConfiguration Include="Release|x64">
+      <Configuration>Release</Configuration>
+      <Platform>x64</Platform>
+    </ProjectConfiguration>
+  </ItemGroup>
+  <PropertyGroup Label="Globals">
+    <VCProjectVersion>17.0</VCProjectVersion>
+    <ProjectGuid>{AFFA14F3-34DD-4FA1-8E53-3D2799DB757E}</ProjectGuid>
+    <Keyword>MFCProj</Keyword>
+    <RootNamespace>RedwaxSignTextMFC</RootNamespace>
+    <WindowsTargetPlatformVersion>10.0</WindowsTargetPlatformVersion>
+  </PropertyGroup>
+  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
+    <ConfigurationType>Application</ConfigurationType>
+    <UseDebugLibraries>true</UseDebugLibraries>
+    <PlatformToolset>v143</PlatformToolset>
+    <CharacterSet>Unicode</CharacterSet>
+    <UseOfMfc>Static</UseOfMfc>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
+    <ConfigurationType>Application</ConfigurationType>
+    <UseDebugLibraries>false</UseDebugLibraries>
+    <PlatformToolset>v143</PlatformToolset>
+    <WholeProgramOptimization>true</WholeProgramOptimization>
+    <CharacterSet>Unicode</CharacterSet>
+    <UseOfMfc>Static</UseOfMfc>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
+    <ConfigurationType>Application</ConfigurationType>
+    <UseDebugLibraries>true</UseDebugLibraries>
+    <PlatformToolset>v143</PlatformToolset>
+    <CharacterSet>Unicode</CharacterSet>
+    <UseOfMfc>Static</UseOfMfc>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
+    <ConfigurationType>Application</ConfigurationType>
+    <UseDebugLibraries>false</UseDebugLibraries>
+    <PlatformToolset>v143</PlatformToolset>
+    <WholeProgramOptimization>true</WholeProgramOptimization>
+    <CharacterSet>Unicode</CharacterSet>
+    <UseOfMfc>Static</UseOfMfc>
+  </PropertyGroup>
+  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
+  <ImportGroup Label="ExtensionSettings">
+  </ImportGroup>
+  <ImportGroup Label="Shared">
+  </ImportGroup>
+  <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+  </ImportGroup>
+  <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+  </ImportGroup>
+  <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
+    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+  </ImportGroup>
+  <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
+    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+  </ImportGroup>
+  <PropertyGroup Label="UserMacros" />
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
+    <LinkIncremental>true</LinkIncremental>
+    <TargetName>$(SolutionName)</TargetName>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+    <LinkIncremental>true</LinkIncremental>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+    <LinkIncremental>false</LinkIncremental>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
+    <LinkIncremental>false</LinkIncremental>
+    <TargetName>$(SolutionName)</TargetName>
+  </PropertyGroup>
+  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
+    <ClCompile>
+      <PrecompiledHeader>NotUsing</PrecompiledHeader>
+      <WarningLevel>Level3</WarningLevel>
+      <SDLCheck>true</SDLCheck>
+      <PreprocessorDefinitions>_WINDOWS;_DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+      <PrecompiledHeaderFile>pch.h</PrecompiledHeaderFile>
+    </ClCompile>
+    <Link>
+      <SubSystem>Windows</SubSystem>
+    </Link>
+    <Midl>
+      <MkTypLibCompatible>false</MkTypLibCompatible>
+      <ValidateAllParameters>true</ValidateAllParameters>
+      <PreprocessorDefinitions>_DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+    </Midl>
+    <ResourceCompile>
+      <Culture>0x0409</Culture>
+      <PreprocessorDefinitions>_DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+      <AdditionalIncludeDirectories>$(IntDir);%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+    </ResourceCompile>
+  </ItemDefinitionGroup>
+  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+    <ClCompile>
+      <PrecompiledHeader>Use</PrecompiledHeader>
+      <WarningLevel>Level3</WarningLevel>
+      <SDLCheck>true</SDLCheck>
+      <PreprocessorDefinitions>WIN32;_WINDOWS;_DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+      <PrecompiledHeaderFile>pch.h</PrecompiledHeaderFile>
+    </ClCompile>
+    <Link>
+      <SubSystem>Windows</SubSystem>
+    </Link>
+    <Midl>
+      <MkTypLibCompatible>false</MkTypLibCompatible>
+      <ValidateAllParameters>true</ValidateAllParameters>
+      <PreprocessorDefinitions>_DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+    </Midl>
+    <ResourceCompile>
+      <Culture>0x0409</Culture>
+      <PreprocessorDefinitions>_DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+      <AdditionalIncludeDirectories>$(IntDir);%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+    </ResourceCompile>
+  </ItemDefinitionGroup>
+  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+    <ClCompile>
+      <PrecompiledHeader>Use</PrecompiledHeader>
+      <WarningLevel>Level3</WarningLevel>
+      <FunctionLevelLinking>true</FunctionLevelLinking>
+      <IntrinsicFunctions>true</IntrinsicFunctions>
+      <SDLCheck>true</SDLCheck>
+      <PreprocessorDefinitions>WIN32;_WINDOWS;NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+      <PrecompiledHeaderFile>pch.h</PrecompiledHeaderFile>
+    </ClCompile>
+    <Link>
+      <SubSystem>Windows</SubSystem>
+      <EnableCOMDATFolding>true</EnableCOMDATFolding>
+      <OptimizeReferences>true</OptimizeReferences>
+    </Link>
+    <Midl>
+      <MkTypLibCompatible>false</MkTypLibCompatible>
+      <ValidateAllParameters>true</ValidateAllParameters>
+      <PreprocessorDefinitions>NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+    </Midl>
+    <ResourceCompile>
+      <Culture>0x0409</Culture>
+      <PreprocessorDefinitions>NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+      <AdditionalIncludeDirectories>$(IntDir);%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+    </ResourceCompile>
+  </ItemDefinitionGroup>
+  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
+    <ClCompile>
+      <PrecompiledHeader>NotUsing</PrecompiledHeader>
+      <WarningLevel>Level3</WarningLevel>
+      <FunctionLevelLinking>true</FunctionLevelLinking>
+      <IntrinsicFunctions>true</IntrinsicFunctions>
+      <SDLCheck>true</SDLCheck>
+      <PreprocessorDefinitions>_WINDOWS;NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+      <PrecompiledHeaderFile>pch.h</PrecompiledHeaderFile>
+    </ClCompile>
+    <Link>
+      <SubSystem>Windows</SubSystem>
+      <EnableCOMDATFolding>true</EnableCOMDATFolding>
+      <OptimizeReferences>true</OptimizeReferences>
+    </Link>
+    <Midl>
+      <MkTypLibCompatible>false</MkTypLibCompatible>
+      <ValidateAllParameters>true</ValidateAllParameters>
+      <PreprocessorDefinitions>NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+    </Midl>
+    <ResourceCompile>
+      <Culture>0x0409</Culture>
+      <PreprocessorDefinitions>NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+      <AdditionalIncludeDirectories>$(IntDir);%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+    </ResourceCompile>
+  </ItemDefinitionGroup>
+  <ItemGroup>
+    <ClInclude Include="cJSON.h" />
+    <ClInclude Include="crypto.h" />
+    <ClInclude Include="framework.h" />
+    <ClInclude Include="message.h" />
+    <ClInclude Include="pch.h" />
+    <ClInclude Include="Redwax SignText (MFC).h" />
+    <ClInclude Include="Redwax SignText (MFC)Dlg.h" />
+    <ClInclude Include="Resource.h" />
+    <ClInclude Include="SignPage.h" />
+    <ClInclude Include="signtext.h" />
+    <ClInclude Include="targetver.h" />
+  </ItemGroup>
+  <ItemGroup>
+    <ClCompile Include="cJSON.c" />
+    <ClCompile Include="crypto.c" />
+    <ClCompile Include="message.c" />
+    <ClCompile Include="pch.cpp">
+      <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">Create</PrecompiledHeader>
+      <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">Create</PrecompiledHeader>
+      <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">Create</PrecompiledHeader>
+      <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release|x64'">Create</PrecompiledHeader>
+    </ClCompile>
+    <ClCompile Include="Redwax SignText (MFC).cpp" />
+    <ClCompile Include="Redwax SignText (MFC)Dlg.cpp" />
+    <ClCompile Include="SignPage.cpp" />
+    <ClCompile Include="signtext.c" />
+  </ItemGroup>
+  <ItemGroup>
+    <ResourceCompile Include="RedwaxSignTextMFC.rc" />
+  </ItemGroup>
+  <ItemGroup>
+    <None Include="res\RedwaxSignTextMFC.rc2" />
+  </ItemGroup>
+  <ItemGroup>
+    <Image Include="res\Redwax SignText (MFC).ico" />
+  </ItemGroup>
+  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
+  <ImportGroup Label="ExtensionTargets">
+  </ImportGroup>
+</Project>

Added: redwax-signtext-windows/trunk/Redwax SignText/Redwax SignText (MFC)/Redwax SignText (MFC).vcxproj.filters
==============================================================================
--- redwax-signtext-windows/trunk/Redwax SignText/Redwax SignText (MFC)/Redwax SignText (MFC).vcxproj.filters	(added)
+++ redwax-signtext-windows/trunk/Redwax SignText/Redwax SignText (MFC)/Redwax SignText (MFC).vcxproj.filters	Sun Jun 23 16:39:06 2024
@@ -0,0 +1,93 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+  <ItemGroup>
+    <Filter Include="Source Files">
+      <UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier>
+      <Extensions>cpp;c;cc;cxx;c++;cppm;ixx;def;odl;idl;hpj;bat;asm;asmx</Extensions>
+    </Filter>
+    <Filter Include="Header Files">
+      <UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier>
+      <Extensions>h;hh;hpp;hxx;h++;hm;inl;inc;ipp;xsd</Extensions>
+    </Filter>
+    <Filter Include="Resource Files">
+      <UniqueIdentifier>{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}</UniqueIdentifier>
+      <Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms</Extensions>
+    </Filter>
+  </ItemGroup>
+  <ItemGroup>
+    <ClInclude Include="Redwax SignText (MFC).h">
+      <Filter>Header Files</Filter>
+    </ClInclude>
+    <ClInclude Include="Redwax SignText (MFC)Dlg.h">
+      <Filter>Header Files</Filter>
+    </ClInclude>
+    <ClInclude Include="framework.h">
+      <Filter>Header Files</Filter>
+    </ClInclude>
+    <ClInclude Include="targetver.h">
+      <Filter>Header Files</Filter>
+    </ClInclude>
+    <ClInclude Include="Resource.h">
+      <Filter>Header Files</Filter>
+    </ClInclude>
+    <ClInclude Include="pch.h">
+      <Filter>Header Files</Filter>
+    </ClInclude>
+    <ClInclude Include="crypto.h">
+      <Filter>Header Files</Filter>
+    </ClInclude>
+    <ClInclude Include="cJSON.h">
+      <Filter>Header Files</Filter>
+    </ClInclude>
+    <ClInclude Include="message.h">
+      <Filter>Header Files</Filter>
+    </ClInclude>
+    <ClInclude Include="signtext.h">
+      <Filter>Header Files</Filter>
+    </ClInclude>
+    <ClInclude Include="SignPage.h">
+      <Filter>Header Files</Filter>
+    </ClInclude>
+  </ItemGroup>
+  <ItemGroup>
+    <ClCompile Include="Redwax SignText (MFC).cpp">
+      <Filter>Source Files</Filter>
+    </ClCompile>
+    <ClCompile Include="Redwax SignText (MFC)Dlg.cpp">
+      <Filter>Source Files</Filter>
+    </ClCompile>
+    <ClCompile Include="pch.cpp">
+      <Filter>Source Files</Filter>
+    </ClCompile>
+    <ClCompile Include="message.c">
+      <Filter>Source Files</Filter>
+    </ClCompile>
+    <ClCompile Include="cJSON.c">
+      <Filter>Source Files</Filter>
+    </ClCompile>
+    <ClCompile Include="signtext.c">
+      <Filter>Source Files</Filter>
+    </ClCompile>
+    <ClCompile Include="SignPage.cpp">
+      <Filter>Source Files</Filter>
+    </ClCompile>
+    <ClCompile Include="crypto.c">
+      <Filter>Source Files</Filter>
+    </ClCompile>
+  </ItemGroup>
+  <ItemGroup>
+    <ResourceCompile Include="RedwaxSignTextMFC.rc">
+      <Filter>Resource Files</Filter>
+    </ResourceCompile>
+  </ItemGroup>
+  <ItemGroup>
+    <None Include="res\RedwaxSignTextMFC.rc2">
+      <Filter>Resource Files</Filter>
+    </None>
+  </ItemGroup>
+  <ItemGroup>
+    <Image Include="res\Redwax SignText (MFC).ico">
+      <Filter>Resource Files</Filter>
+    </Image>
+  </ItemGroup>
+</Project>

Added: redwax-signtext-windows/trunk/Redwax SignText/Redwax SignText (MFC)/Redwax SignText (MFC)Dlg.cpp
==============================================================================
--- redwax-signtext-windows/trunk/Redwax SignText/Redwax SignText (MFC)/Redwax SignText (MFC)Dlg.cpp	(added)
+++ redwax-signtext-windows/trunk/Redwax SignText/Redwax SignText (MFC)/Redwax SignText (MFC)Dlg.cpp	Sun Jun 23 16:39:06 2024
@@ -0,0 +1,727 @@
+/* Licensed to Stichting The Commons Conservancy (TCC) under one or more
+ * contributor license agreements.  See the AUTHORS file distributed with
+ * this work for additional information regarding copyright ownership.
+ * TCC licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "pch.h"
+#include "framework.h"
+#include "Redwax SignText (MFC).h"
+#include "Redwax SignText (MFC)Dlg.h"
+#include "afxdialogex.h"
+
+#include <wininet.h>
+
+#pragma comment(lib, "wininet.lib")
+
+#ifdef _DEBUG
+#define new DEBUG_NEW
+#endif
+
+
+// CAboutDlg dialog used for App About
+
+class CAboutDlg : public CDialogEx
+{
+public:
+	CAboutDlg();
+
+// Dialog Data
+#ifdef AFX_DESIGN_TIME
+	enum { IDD = IDD_ABOUTBOX };
+#endif
+
+	protected:
+	virtual void DoDataExchange(CDataExchange* pDX);    // DDX/DDV support
+
+// Implementation
+protected:
+	DECLARE_MESSAGE_MAP()
+};
+
+UINT ReadStdinFunction(LPVOID pParam)
+{
+	SignTextData* signtext;
+
+	signtext = (SignTextData*)pParam;
+
+	message_receive(signtext);
+
+	return 0;
+}
+
+UINT HandleCryptoFunction(LPVOID pParam)
+{
+	SignTextData* signtext;
+
+	signtext = (SignTextData*)pParam;
+
+	crypto_start(signtext);
+
+	return 0;
+}
+
+UINT HandleSignFunction(LPVOID pParam)
+{
+	SignTextInstance* instance;
+
+	instance = (SignTextInstance*)pParam;
+
+	crypto_sign(instance);
+
+	return 0;
+}
+
+CAboutDlg::CAboutDlg() : CDialogEx(IDD_ABOUTBOX)
+{
+}
+
+void CAboutDlg::DoDataExchange(CDataExchange* pDX)
+{
+	CDialogEx::DoDataExchange(pDX);
+}
+
+BEGIN_MESSAGE_MAP(CAboutDlg, CDialogEx)
+END_MESSAGE_MAP()
+
+
+// CRedwaxSignTextMFCDlg dialog
+
+
+
+CRedwaxSignTextMFCDlg::CRedwaxSignTextMFCDlg(CWnd* pParent /*=nullptr*/)
+	: CDialogEx(IDD_REDWAX_SIGNTEXT_MFC_DIALOG, pParent)
+{
+	m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME);
+
+}
+
+void CRedwaxSignTextMFCDlg::DoDataExchange(CDataExchange* pDX)
+{
+	CDialogEx::DoDataExchange(pDX);
+	//	m_dlg1.DoDataExchange(pDX);
+	//	m_dlg2.DoDataExchange(pDX);
+	DDX_Control(pDX, IDC_TAB1, m_ctlTab);
+	DDX_Control(pDX, IDSIGN, m_sign);
+	DDX_Control(pDX, IDCANCEL, m_cancel);
+}
+
+BEGIN_MESSAGE_MAP(CRedwaxSignTextMFCDlg, CDialogEx)
+	ON_NOTIFY(TCN_SELCHANGE, IDC_TAB1, OnSelchangeTab1)
+	ON_WM_SYSCOMMAND()
+	ON_WM_PAINT()
+	ON_WM_QUERYDRAGICON()
+	ON_MESSAGE(WM_MESSAGE_RECEIVE, OnMessageReceive)
+	ON_MESSAGE(WM_MESSAGE_RECEIVED, OnMessageReceived)
+	ON_MESSAGE(WM_MESSAGE_SEND, OnMessageSend)
+	ON_MESSAGE(WM_MESSAGE_SENT, OnMessageSent)
+	ON_MESSAGE(WM_MESSAGE_SHOW, OnMessageShow)
+	ON_MESSAGE(WM_CRYPTO_UPDATED, OnCryptoUpdated)
+	ON_MESSAGE(WM_CRYPTO_SELECTED, OnCryptoSelected)
+	ON_MESSAGE(WM_CRYPTO_SIGNED, OnCryptoSigned)
+	ON_MESSAGE(WM_CRYPTO_NOTSIGNED, OnCryptoNotSigned)
+	ON_WM_SIZE()
+	ON_WM_SIZING()
+	ON_WM_GETMINMAXINFO()
+	ON_BN_CLICKED(IDSIGN, &CRedwaxSignTextMFCDlg::OnBnClickedSign)
+	ON_BN_CLICKED(IDCANCEL, &CRedwaxSignTextMFCDlg::OnBnClickedCancel)
+	ON_WM_CLOSE()
+	ON_WM_ENTERIDLE()
+END_MESSAGE_MAP()
+
+
+// CRedwaxSignTextMFCDlg message handlers
+
+BOOL CRedwaxSignTextMFCDlg::OnInitDialog()
+{
+	CDialogEx::OnInitDialog();
+
+	// Add "About..." menu item to system menu.
+
+	// IDM_ABOUTBOX must be in the system command range.
+	ASSERT((IDM_ABOUTBOX & 0xFFF0) == IDM_ABOUTBOX);
+	ASSERT(IDM_ABOUTBOX < 0xF000);
+
+	CMenu* pSysMenu = GetSystemMenu(FALSE);
+	if (pSysMenu != nullptr)
+	{
+		BOOL bNameValid;
+		CString strAboutMenu;
+		bNameValid = strAboutMenu.LoadString(IDS_ABOUTBOX);
+		ASSERT(bNameValid);
+		if (!strAboutMenu.IsEmpty())
+		{
+			pSysMenu->AppendMenu(MF_SEPARATOR);
+			pSysMenu->AppendMenu(MF_STRING, IDM_ABOUTBOX, strAboutMenu);
+		}
+	}
+
+	// Set the icon for this dialog.  The framework does this automatically
+	//  when the application's main window is not a dialog
+	SetIcon(m_hIcon, TRUE);			// Set big icon
+	SetIcon(m_hIcon, FALSE);		// Set small icon
+
+	// TODO: Add extra initialization here
+
+//    std::shared_ptr<SignPage> upm_dlg1 = std::make_shared<SignPage>();
+//	std::shared_ptr<SignPage> upm_dlg2 = std::make_shared<SignPage>();
+
+//	VERIFY(upm_dlg1->Create(IDD_SIGN_PAGE, this));
+//	VERIFY(upm_dlg2->Create(IDD_SIGN_PAGE, this));
+
+//	m_dlg1.EnableDynamicLayout(TRUE);
+//	m_dlg2.EnableDynamicLayout(TRUE);
+
+//	CString text;
+//	upm_dlg1->GetWindowText(text);
+//	VERIFY(m_ctlTab.InsertItem(TCIF_TEXT, 0, text, 0, 0, 0, 0) == 0);
+//	std::vector<std::shared_ptr<SignPage>>::iterator it;//	it = m_dlgs.begin();
+//	m_dlgs.insert(m_dlgs.begin(), upm_dlg1);
+
+//	upm_dlg2->GetWindowText(text);
+//	VERIFY(m_ctlTab.InsertItem(TCIF_TEXT, 0, text, 0, 0, 0, 0) == 0);
+//	m_dlgs.insert(m_dlgs.begin(), upm_dlg2);
+
+	ResizeTab();
+	UpdateVisibleTab();
+
+	signtext = signtext_data_new();
+
+	/* stash away the window handle */
+	signtext->hwnd = GetSafeHwnd();
+
+	PostMessage(WM_MESSAGE_RECEIVE, 0, 0);
+
+	AfxBeginThread(HandleCryptoFunction, signtext);
+
+	/* store this dialog away so the timer can find it */
+//	SetProp(signtext->hwnd, L"signtext", signtext);
+
+//	SetTimer((UINT_PTR)signtext, 2000, CryptoTimer);
+
+	return TRUE;  // return TRUE  unless you set the focus to a control
+}
+
+void CRedwaxSignTextMFCDlg::OnSelchangeTab1(NMHDR* pNMHDR, LRESULT* pResult)
+{
+	UpdateVisibleTab();
+
+	*pResult = 0;
+}
+
+void CRedwaxSignTextMFCDlg::UpdateVisibleTab()
+{
+	int index = 0;
+	int current = m_ctlTab.GetCurSel();
+
+	/* until further notice */
+	int can_sign = FALSE;
+	int can_cancel = TRUE;
+
+	for (std::shared_ptr<SignPage>& m_dlg : m_dlgs) {
+
+		if (current == index) {
+
+			/* should it be possible to click the sign button */
+			if ((m_dlg->m_certificateBox.GetCurSel() > -1) &&
+				(!m_dlg->instance->is_signing)) {
+				can_sign = TRUE;
+			}
+
+			/* should it be possible to click the cancel button */
+			if ((m_dlg->instance->is_cancelled)) {
+				can_cancel = FALSE;
+			}
+
+			/* disable PIN and certificate selector while signing */
+			if (!m_dlg->instance->is_signing) {
+				m_dlg->m_certificateBox.EnableWindow(TRUE);
+				m_dlg->m_pinText.EnableWindow(TRUE);
+			}
+			else {
+				m_dlg->m_certificateBox.EnableWindow(FALSE);
+				m_dlg->m_pinText.EnableWindow(FALSE);
+			}
+
+			m_dlg->m_pinText.SetCueBanner(L"Enter PIN", TRUE);
+
+			m_dlg->ShowWindow(SW_SHOW);
+		}
+		else {
+			m_dlg->ShowWindow(SW_HIDE);
+		}
+
+		index++;
+	}
+
+	/* sign button disabled or no */
+	m_sign.EnableWindow(can_sign);
+	m_cancel.EnableWindow(can_cancel);
+
+	ShowWindow(m_dlgs.size() ? SW_SHOW : SW_HIDE);
+}
+
+void CRedwaxSignTextMFCDlg::ResizeTab()
+{
+#if 1
+
+	RECT rect;
+
+	// Get size of dialog window.
+	m_ctlTab.GetClientRect(&rect);
+
+	// Adjust the rectangle to fit the tab control into the
+	// dialog's client rectangle.
+	m_ctlTab.AdjustRect(FALSE, &rect);
+
+	// Move the tab control to the new position and size.
+	for (std::shared_ptr<SignPage>& m_dlg : m_dlgs) {
+		m_dlg->MoveWindow(&rect, FALSE);
+//		m_dlg->SetWindowPos(NULL, rc.left, rc.top, 500, 500,
+//			SWP_NOZORDER);
+	}
+#endif
+
+#if 0
+
+	CRect tabRect, itemRect;
+
+	m_ctlTab.GetClientRect(&tabRect);
+	m_ctlTab.GetItemRect(m_ctlTab.GetCurSel(), &itemRect);
+
+	int x, y, xc, yc;
+
+	x = itemRect.left;
+	y = itemRect.bottom + 1;
+	xc = tabRect.right - itemRect.left - 1;
+	yc = tabRect.bottom - y - 1;
+
+	//	m_ctlTab.AdjustRect(FALSE, &rect);
+
+
+	for (std::shared_ptr<SignPage>& m_dlg : m_dlgs) {
+		m_dlg->ModifyStyle(WS_BORDER | WS_DLGFRAME | WS_CAPTION | WS_DISABLED
+			| WS_THICKFRAME, WS_CLIPCHILDREN | WS_CHILD | WS_CLIPSIBLINGS);
+		m_dlg->SetWindowPos(&wndTop, x, y, xc, yc, 0);
+	}
+
+#endif
+
+}
+
+void CRedwaxSignTextMFCDlg::OnSysCommand(UINT nID, LPARAM lParam)
+{
+	if ((nID & 0xFFF0) == IDM_ABOUTBOX)
+	{
+		CAboutDlg dlgAbout;
+		dlgAbout.DoModal();
+	}
+	else
+	{
+		CDialogEx::OnSysCommand(nID, lParam);
+	}
+}
+
+// If you add a minimize button to your dialog, you will need the code below
+//  to draw the icon.  For MFC applications using the document/view model,
+//  this is automatically done for you by the framework.
+
+void CRedwaxSignTextMFCDlg::OnPaint()
+{
+	if (IsIconic())
+	{
+		CPaintDC dc(this); // device context for painting
+
+		SendMessage(WM_ICONERASEBKGND, reinterpret_cast<WPARAM>(dc.GetSafeHdc()), 0);
+
+		// Center icon in client rectangle
+		int cxIcon = GetSystemMetrics(SM_CXICON);
+		int cyIcon = GetSystemMetrics(SM_CYICON);
+		CRect rect;
+		GetClientRect(&rect);
+		int x = (rect.Width() - cxIcon + 1) / 2;
+		int y = (rect.Height() - cyIcon + 1) / 2;
+
+		// Draw the icon
+		dc.DrawIcon(x, y, m_hIcon);
+	}
+	else
+	{
+		CDialogEx::OnPaint();
+	}
+}
+
+// The system calls this function to obtain the cursor to display while the user drags
+//  the minimized window.
+HCURSOR CRedwaxSignTextMFCDlg::OnQueryDragIcon()
+{
+	return static_cast<HCURSOR>(m_hIcon);
+}
+
+LRESULT CRedwaxSignTextMFCDlg::OnMessageReceive(WPARAM wParam, LPARAM lParam)
+{
+	/* start the stdin thread */
+
+	AfxBeginThread(ReadStdinFunction, signtext);
+
+	return NULL;
+}
+
+LRESULT CRedwaxSignTextMFCDlg::OnMessageReceived(WPARAM wParam, LPARAM lParam)
+{
+	char* buffer = (char *)lParam;
+	uint32_t length = (uint32_t)wParam;
+
+	message_receive_do(signtext, buffer, length);
+
+	return NULL;
+}
+
+LRESULT CRedwaxSignTextMFCDlg::OnMessageSend(WPARAM wParam, LPARAM lParam)
+{
+	char* buffer = (char*)lParam;
+	uint32_t length = (uint32_t)wParam;
+
+	message_send(signtext, buffer, length);
+
+	return NULL;
+}
+
+LRESULT CRedwaxSignTextMFCDlg::OnMessageSent(WPARAM wParam, LPARAM lParam)
+{
+
+	int index = 0;
+
+	for (std::vector<std::shared_ptr<SignPage>>::iterator it = m_dlgs.begin(); it != m_dlgs.end(); ++it) {
+
+		std::shared_ptr<SignPage> dlg = *it;
+
+		/*
+		 * Any tabs marked done must be gracefully cleaned up.
+		 */
+		if (dlg->instance->response_done || dlg->instance->is_cancelled) {
+
+			m_ctlTab.DeleteItem(index);
+
+			m_dlgs.erase(it);
+
+			if (m_ctlTab.GetItemCount() == 0) {
+
+				/*
+				 * No more tabs left, we are done - close down gracefully
+				 */
+				ShowWindow(SW_HIDE);
+
+				PostQuitMessage(0);
+			}
+
+			else {
+
+				/*
+				 * Rather than messing around with iterators, re-trigger
+				 * the message to walk the rest of the loop
+				 */
+				PostMessage(WM_MESSAGE_SENT, 0, 0);
+
+			}
+
+			if (m_ctlTab.GetCurSel() == -1 && m_ctlTab.GetItemCount() > 0) {
+				m_ctlTab.SetCurSel(0);
+			}
+
+			ResizeTab();
+			UpdateVisibleTab();
+
+			break;
+		}
+
+		index++;
+	}
+
+	return NULL;
+}
+
+LRESULT CRedwaxSignTextMFCDlg::OnMessageShow(WPARAM wParam, LPARAM lParam)
+{
+	SignTextInstance* instance = (SignTextInstance *)lParam;
+
+	LPWSTR wUri = signtext_utf8ToUtf16(instance->uri, strlen(instance->uri));
+
+	URL_COMPONENTS URLparts = { 0 };
+
+	TCHAR hostName[256];
+
+	URLparts.dwStructSize = sizeof(URLparts);
+	URLparts.lpszHostName = hostName;
+	URLparts.dwHostNameLength = sizeof(hostName);
+
+	if (!InternetCrackUrl(wUri, (DWORD)_tcslen(wUri), 0,
+		&URLparts))
+	{
+		assert(0);
+	}
+
+	free(wUri);
+
+	std::shared_ptr<SignPage> upm_dlg1 = std::make_shared<SignPage>(instance, this);
+
+	VERIFY(upm_dlg1->Create(IDD_SIGN_PAGE, this));
+	VERIFY(m_ctlTab.InsertItem(TCIF_TEXT, 0, hostName, 0, 0, 0, 0) == 0);
+	m_dlgs.insert(m_dlgs.begin(), upm_dlg1);
+
+	upm_dlg1->m_signText.SetReadOnly(TRUE);
+	upm_dlg1->m_signText.HideCaret();
+
+	/*
+	 * Insert line by line to convert line endings.
+	 */
+	const char* buffer = instance->in_buffer;
+	const char* next;
+	size_t length;
+
+	do {
+		next = strchr(buffer, '\n');
+
+		if (next) {
+			length = next - buffer;
+		}
+		else {
+			length = strlen(buffer);
+		}
+
+		LPWSTR wBuffer = signtext_utf8ToUtf16(buffer, length);
+
+		int nLength = upm_dlg1->m_signText.GetWindowTextLength();
+		upm_dlg1->m_signText.SetSel(nLength, nLength, TRUE);
+		upm_dlg1->m_signText.ReplaceSel(wBuffer);
+
+		free(wBuffer);
+
+		if (next) {
+
+			int nLength = upm_dlg1->m_signText.GetWindowTextLength();
+			upm_dlg1->m_signText.SetSel(nLength, nLength, TRUE);
+			upm_dlg1->m_signText.ReplaceSel(L"\r\n");
+
+			/* skip LF we found */
+			buffer = next + 1;
+		}
+
+	} while (next);
+
+
+	//	RECT rect;
+//	m_ctlTab.GetClientRect(&rect);
+//	m_ctlTab.AdjustRect(FALSE, &rect);
+//	dialogItem.dialog.SetWindowPos(&CWnd::wndBottom, 0, 0, rect.right, rect.bottom,
+//		SWP_NOMOVE);
+
+	m_ctlTab.SetCurSel(0);
+
+	ResizeTab();
+	UpdateVisibleTab();
+
+	return NULL;
+}
+
+void CRedwaxSignTextMFCDlg::OnSize(UINT nType, int cx, int cy)
+{
+	CDialogEx::OnSize(nType, cx, cy);
+}
+
+
+void CRedwaxSignTextMFCDlg::OnSizing(UINT fwSide, LPRECT pRect)
+{
+	CDialogEx::OnSizing(fwSide, pRect);
+
+	ResizeTab();
+}
+
+
+void CRedwaxSignTextMFCDlg::OnGetMinMaxInfo(MINMAXINFO* lpMMI)
+{
+	CDialogEx::OnGetMinMaxInfo(lpMMI);
+}
+
+LRESULT CRedwaxSignTextMFCDlg::OnCryptoUpdated(WPARAM wParam, LPARAM lParam)
+{
+	SignTextCertificate* certificates = (SignTextCertificate*)lParam;
+
+	for (std::shared_ptr<SignPage>& m_dlg : m_dlgs) {
+
+		/* remove vanished certificates */
+
+		int count = m_dlg->m_certificateBox.GetCount();
+		for (int i = 0; i < count;) {
+			SignTextCertificate* cert = (SignTextCertificate*)m_dlg->m_certificateBox.GetItemDataPtr(i);
+
+			if (!crypto_certificate_find(certificates, cert)) {
+
+				if (i == m_dlg->m_certificateBox.GetCurSel()) {
+					m_dlg->m_certificateBox.SetCurSel(-1);
+				}
+
+				m_dlg->m_certificateBox.DeleteString(i);
+				count = m_dlg->m_certificateBox.GetCount();
+
+				signtext_certificate_unref(cert);
+
+			}
+			else {
+				i++;
+			}
+		}
+
+		/* add new certificates */
+
+		SignTextCertificate* certs = certificates;
+		while (certs) {
+
+			int found = 0;
+
+			int count = m_dlg->m_certificateBox.GetCount();
+			for (int i = 0; i < count; i++) {
+
+				SignTextCertificate* cert = (SignTextCertificate*)m_dlg->m_certificateBox.GetItemDataPtr(i);
+
+				if (!crypto_certificate_compare(certs, cert)) {
+					found = 1;
+				}
+
+			}
+
+			if (!found) {
+
+				signtext_certificate_ref(certs);
+
+				int index = m_dlg->m_certificateBox.AddString(certs->name);
+				m_dlg->m_certificateBox.SetItemDataPtr(index, certs);
+
+				assert(count + 1 == m_dlg->m_certificateBox.GetCount());
+
+			}
+
+			certs = certs->next;
+		}
+
+	}
+
+	while (certificates) {
+
+		SignTextCertificate* next = certificates->next;
+
+		signtext_certificate_unref(certificates);
+
+		certificates = next;
+	}
+
+	return NULL;
+}
+
+LRESULT CRedwaxSignTextMFCDlg::OnCryptoSelected(WPARAM wParam, LPARAM lParam)
+{
+	UpdateVisibleTab();
+
+	return NULL;
+}
+
+LRESULT CRedwaxSignTextMFCDlg::OnCryptoSigned(WPARAM wParam, LPARAM lParam)
+{
+	UpdateVisibleTab();
+
+	return NULL;
+}
+
+LRESULT CRedwaxSignTextMFCDlg::OnCryptoNotSigned(WPARAM wParam, LPARAM lParam)
+{
+	UpdateVisibleTab();
+
+	return NULL;
+}
+
+void CRedwaxSignTextMFCDlg::OnClose()
+{
+	for (std::vector<std::shared_ptr<SignPage>>::iterator it = m_dlgs.begin(); it != m_dlgs.end(); ++it) {
+
+		std::shared_ptr<SignPage> dlg = *it;
+
+		/*
+		 * Send cancel for anything not done or already cancelled.
+		 */
+		if (!dlg->instance->response_done && !dlg->instance->is_cancelled) {
+
+			message_send_cancel_response(dlg->instance);
+
+		}
+
+	}
+
+	UpdateVisibleTab();
+
+}
+
+void CRedwaxSignTextMFCDlg::OnBnClickedSign()
+{
+	int current = m_ctlTab.GetCurSel();
+
+	assert(current >= 0);
+
+	std::shared_ptr<SignPage>& m_dlg = m_dlgs.at(current);
+
+	current = m_dlg->m_certificateBox.GetCurSel();
+
+	assert(current >= 0);
+
+	SignTextCertificate* cert = (SignTextCertificate*)m_dlg->m_certificateBox.GetItemDataPtr(current);
+
+	assert(cert);
+
+	m_dlg->instance->certificate = signtext_certificate_ref(cert);
+
+	m_dlg->instance->pinLen = m_dlg->m_pinText.GetWindowTextLength();
+	m_dlg->instance->pinBuffer = (LPWSTR)malloc((m_dlg->instance->pinLen + 1) * sizeof(wchar_t));
+	m_dlg->m_pinText.GetWindowText(m_dlg->instance->pinBuffer, m_dlg->instance->pinLen + 1);
+
+	m_dlg->instance->is_signing = TRUE;
+
+	UpdateVisibleTab();
+
+	AfxBeginThread(HandleSignFunction, m_dlg->instance);
+
+}
+
+void CRedwaxSignTextMFCDlg::OnBnClickedCancel()
+{
+
+	int current = m_ctlTab.GetCurSel();
+
+	if (current >= 0) {
+
+		std::shared_ptr<SignPage>& m_dlg = m_dlgs.at(current);
+
+		message_send_cancel_response(m_dlg->instance);
+
+		UpdateVisibleTab();
+	}
+
+}
+
+CRedwaxSignTextMFCDlg::~CRedwaxSignTextMFCDlg()
+{
+	WaitForSingleObject(hThread, INFINITE);
+	WaitForSingleObject(cThread, INFINITE);
+
+	signtext_data_free(signtext);
+
+}
+

Added: redwax-signtext-windows/trunk/Redwax SignText/Redwax SignText (MFC)/Redwax SignText (MFC)Dlg.h
==============================================================================
--- redwax-signtext-windows/trunk/Redwax SignText/Redwax SignText (MFC)/Redwax SignText (MFC)Dlg.h	(added)
+++ redwax-signtext-windows/trunk/Redwax SignText/Redwax SignText (MFC)/Redwax SignText (MFC)Dlg.h	Sun Jun 23 16:39:06 2024
@@ -0,0 +1,97 @@
+/* Licensed to Stichting The Commons Conservancy (TCC) under one or more
+ * contributor license agreements.  See the AUTHORS file distributed with
+ * this work for additional information regarding copyright ownership.
+ * TCC licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#define WM_MESSAGE_RECEIVE WM_APP+1
+#define WM_MESSAGE_RECEIVED WM_APP+2
+#define WM_MESSAGE_SEND WM_APP+3
+#define WM_MESSAGE_SENT WM_APP+4
+#define WM_MESSAGE_SHOW WM_APP+5
+
+#define WM_CRYPTO_UPDATED WM_APP+101
+#define WM_CRYPTO_SELECTED WM_APP+102
+#define WM_CRYPTO_SIGNED WM_APP+103
+#define WM_CRYPTO_NOTSIGNED WM_APP+104
+
+#define IDT_TIMER_CERTS WM_APP+201
+
+#include <vector>
+#include <memory>
+
+#include "SignPage.h"
+
+// CRedwaxSignTextMFCDlg dialog
+class CRedwaxSignTextMFCDlg : public CDialogEx
+{
+// Construction
+public:
+	CRedwaxSignTextMFCDlg(CWnd* pParent = nullptr);	// standard constructor
+	~CRedwaxSignTextMFCDlg();	// standard destructor
+
+// Dialog Data
+#ifdef AFX_DESIGN_TIME
+	enum { IDD = IDD_REDWAX_SIGNTEXT_MFC_DIALOG };
+#endif
+
+	protected:
+	virtual void DoDataExchange(CDataExchange* pDX);	// DDX/DDV support
+
+
+// Implementation
+protected:
+
+	HANDLE  hThread;
+	HANDLE  cThread;
+	SignTextData* signtext;
+
+	HICON m_hIcon;
+	
+	CTabCtrl	m_ctlTab;
+
+	std::vector<std::shared_ptr<SignPage>> m_dlgs;
+
+	CButton m_sign;
+	CButton m_cancel;
+
+	// Generated message map functions
+	virtual BOOL OnInitDialog();
+	afx_msg void OnSelchangeTab1(NMHDR* pNMHDR, LRESULT* pResult);
+	afx_msg void OnSysCommand(UINT nID, LPARAM lParam);
+	afx_msg void OnPaint();
+	afx_msg HCURSOR OnQueryDragIcon();
+	afx_msg LRESULT OnMessageReceive(WPARAM wParam, LPARAM lParam);
+	afx_msg LRESULT OnMessageReceived(WPARAM wParam, LPARAM lParam);
+	afx_msg LRESULT OnMessageSend(WPARAM wParam, LPARAM lParam);
+	afx_msg LRESULT OnMessageSent(WPARAM wParam, LPARAM lParam);
+	afx_msg LRESULT OnMessageShow(WPARAM wParam, LPARAM lParam);
+	afx_msg LRESULT OnCryptoUpdated(WPARAM wParam, LPARAM lParam);
+	afx_msg LRESULT OnCryptoSelected(WPARAM wParam, LPARAM lParam);
+	afx_msg LRESULT CRedwaxSignTextMFCDlg::OnCryptoSigned(WPARAM wParam, LPARAM lParam);
+	afx_msg LRESULT CRedwaxSignTextMFCDlg::OnCryptoNotSigned(WPARAM wParam, LPARAM lParam);
+	afx_msg void OnSize(UINT nType, int cx, int cy);
+	afx_msg void OnSizing(UINT fwSide, LPRECT pRect);
+	afx_msg void OnGetMinMaxInfo(MINMAXINFO* lpMMI);
+	DECLARE_MESSAGE_MAP()
+
+private:
+	void ResizeTab();
+	void UpdateVisibleTab();
+public:
+	afx_msg void OnClose();
+	afx_msg void OnBnClickedSign();
+	afx_msg void OnBnClickedCancel();
+};

Added: redwax-signtext-windows/trunk/Redwax SignText/Redwax SignText (MFC)/RedwaxSignTextMFC.rc
==============================================================================
Binary file - no diff available.

Propchange: redwax-signtext-windows/trunk/Redwax SignText/Redwax SignText (MFC)/RedwaxSignTextMFC.rc
------------------------------------------------------------------------------
    svn:mime-type = application/octet-stream

Added: redwax-signtext-windows/trunk/Redwax SignText/Redwax SignText (MFC)/Resource.h
==============================================================================
--- redwax-signtext-windows/trunk/Redwax SignText/Redwax SignText (MFC)/Resource.h	(added)
+++ redwax-signtext-windows/trunk/Redwax SignText/Redwax SignText (MFC)/Resource.h	Sun Jun 23 16:39:06 2024
@@ -0,0 +1,26 @@
+//{{NO_DEPENDENCIES}}
+// Microsoft Visual C++ generated include file.
+// Used by RedwaxSignTextMFC.rc
+//
+#define IDM_ABOUTBOX                    0x0010
+#define IDD_ABOUTBOX                    100
+#define IDS_ABOUTBOX                    101
+#define IDD_REDWAX_SIGNTEXT_MFC_DIALOG  102
+#define IDD_SIGN_PAGE                   105
+#define IDR_MAINFRAME                   128
+#define IDC_TAB1                        1012
+#define IDC_SIGNTEXT                    1014
+#define IDC_CERTIFICATEBOX              1017
+#define IDC_PINTEXT                     1019
+#define IDSIGN                          1020
+
+// Next default values for new objects
+// 
+#ifdef APSTUDIO_INVOKED
+#ifndef APSTUDIO_READONLY_SYMBOLS
+#define _APS_NEXT_RESOURCE_VALUE        133
+#define _APS_NEXT_COMMAND_VALUE         32771
+#define _APS_NEXT_CONTROL_VALUE         1021
+#define _APS_NEXT_SYMED_VALUE           101
+#endif
+#endif

Added: redwax-signtext-windows/trunk/Redwax SignText/Redwax SignText (MFC)/SignPage.cpp
==============================================================================
--- redwax-signtext-windows/trunk/Redwax SignText/Redwax SignText (MFC)/SignPage.cpp	(added)
+++ redwax-signtext-windows/trunk/Redwax SignText/Redwax SignText (MFC)/SignPage.cpp	Sun Jun 23 16:39:06 2024
@@ -0,0 +1,65 @@
+/* Licensed to Stichting The Commons Conservancy (TCC) under one or more
+ * contributor license agreements.  See the AUTHORS file distributed with
+ * this work for additional information regarding copyright ownership.
+ * TCC licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "pch.h"
+#include "Redwax SignText (MFC).h"
+#include "afxdialogex.h"
+#include "SignPage.h"
+#include "Redwax SignText (MFC)Dlg.h"
+
+
+// SignPage dialog
+
+IMPLEMENT_DYNAMIC(SignPage, CDialogEx)
+
+SignPage::SignPage(CWnd* pParent /*=nullptr*/)
+	: CDialogEx(IDD_SIGN_PAGE, pParent)
+{
+
+}
+
+SignPage::SignPage(SignTextInstance* instance, CWnd* pParent /*=nullptr*/)
+	: CDialogEx(IDD_SIGN_PAGE, pParent)
+{
+	this->instance = instance;
+}
+
+SignPage::~SignPage()
+{
+}
+
+void SignPage::DoDataExchange(CDataExchange* pDX)
+{
+	CDialogEx::DoDataExchange(pDX);
+	DDX_Control(pDX, IDC_SIGNTEXT, m_signText);
+	DDX_Control(pDX, IDC_CERTIFICATEBOX, m_certificateBox);
+	DDX_Control(pDX, IDC_PINTEXT, m_pinText);
+}
+
+
+BEGIN_MESSAGE_MAP(SignPage, CDialogEx)
+	ON_WM_SYSCOMMAND()
+	ON_WM_PAINT()
+	ON_CBN_SELCHANGE(IDC_CERTIFICATEBOX, &SignPage::OnCbnSelchangeCertificatebox)
+END_MESSAGE_MAP()
+
+
+// SignPage message handlers
+
+void SignPage::OnCbnSelchangeCertificatebox()
+{
+	::PostMessage(instance->signtext->hwnd, WM_CRYPTO_SELECTED, 0, 0);
+}

Added: redwax-signtext-windows/trunk/Redwax SignText/Redwax SignText (MFC)/SignPage.h
==============================================================================
--- redwax-signtext-windows/trunk/Redwax SignText/Redwax SignText (MFC)/SignPage.h	(added)
+++ redwax-signtext-windows/trunk/Redwax SignText/Redwax SignText (MFC)/SignPage.h	Sun Jun 23 16:39:06 2024
@@ -0,0 +1,52 @@
+/* Licensed to Stichting The Commons Conservancy (TCC) under one or more
+ * contributor license agreements.  See the AUTHORS file distributed with
+ * this work for additional information regarding copyright ownership.
+ * TCC licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+#include "afxdialogex.h"
+
+// SignPage dialog
+
+class SignPage : public CDialogEx
+{
+	DECLARE_DYNAMIC(SignPage)
+
+public:
+	SignPage(CWnd* pParent = nullptr);   // standard constructor
+	SignPage(SignTextInstance* instance, CWnd* pParent = nullptr);
+	virtual ~SignPage();
+
+	CEdit	m_signText;
+	CComboBox	m_certificateBox;
+	CEdit	m_pinText;
+
+	SignTextInstance* instance;
+
+	HANDLE  sThread;
+
+	// Dialog Data
+#ifdef AFX_DESIGN_TIME
+	enum { IDD = IDD_SIGN_PAGE };
+#endif
+
+protected:
+
+	virtual void DoDataExchange(CDataExchange* pDX);    // DDX/DDV support
+
+	DECLARE_MESSAGE_MAP()
+public:
+	afx_msg void OnCbenInsertitemCertificatebox(NMHDR* pNMHDR, LRESULT* pResult);
+	afx_msg void OnCbnSelchangeCertificatebox();
+};

Added: redwax-signtext-windows/trunk/Redwax SignText/Redwax SignText (MFC)/cJSON.c
==============================================================================
--- redwax-signtext-windows/trunk/Redwax SignText/Redwax SignText (MFC)/cJSON.c	(added)
+++ redwax-signtext-windows/trunk/Redwax SignText/Redwax SignText (MFC)/cJSON.c	Sun Jun 23 16:39:06 2024
@@ -0,0 +1,3143 @@
+/*
+  Copyright (c) 2009-2017 Dave Gamble and cJSON contributors
+
+  Permission is hereby granted, free of charge, to any person obtaining a copy
+  of this software and associated documentation files (the "Software"), to deal
+  in 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:
+
+  The above copyright notice and this permission notice shall be included in
+  all copies or substantial portions of the Software.
+
+  THE 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
+  AUTHORS 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 IN
+  THE SOFTWARE.
+*/
+
+/* cJSON */
+/* JSON parser in C. */
+
+/* disable warnings about old C89 functions in MSVC */
+#if !defined(_CRT_SECURE_NO_DEPRECATE) && defined(_MSC_VER)
+#define _CRT_SECURE_NO_DEPRECATE
+#endif
+
+#ifdef __GNUC__
+#pragma GCC visibility push(default)
+#endif
+#if defined(_MSC_VER)
+#pragma warning (push)
+/* disable warning about single line comments in system headers */
+#pragma warning (disable : 4001)
+#endif
+
+#include <string.h>
+#include <stdio.h>
+#include <math.h>
+#include <stdlib.h>
+#include <limits.h>
+#include <ctype.h>
+#include <float.h>
+
+#ifdef ENABLE_LOCALES
+#include <locale.h>
+#endif
+
+#if defined(_MSC_VER)
+#pragma warning (pop)
+#endif
+#ifdef __GNUC__
+#pragma GCC visibility pop
+#endif
+
+#include "cJSON.h"
+
+/* define our own boolean type */
+#ifdef true
+#undef true
+#endif
+#define true ((cJSON_bool)1)
+
+#ifdef false
+#undef false
+#endif
+#define false ((cJSON_bool)0)
+
+/* define isnan and isinf for ANSI C, if in C99 or above, isnan and isinf has been defined in math.h */
+#ifndef isinf
+#define isinf(d) (isnan((d - d)) && !isnan(d))
+#endif
+#ifndef isnan
+#define isnan(d) (d != d)
+#endif
+
+#ifndef NAN
+#ifdef _WIN32
+#define NAN sqrt(-1.0)
+#else
+#define NAN 0.0/0.0
+#endif
+#endif
+
+typedef struct {
+    const unsigned char* json;
+    size_t position;
+} error;
+static error global_error = { NULL, 0 };
+
+CJSON_PUBLIC(const char*) cJSON_GetErrorPtr(void)
+{
+    return (const char*)(global_error.json + global_error.position);
+}
+
+CJSON_PUBLIC(char*) cJSON_GetStringValue(const cJSON* const item)
+{
+    if (!cJSON_IsString(item))
+    {
+        return NULL;
+    }
+
+    return item->valuestring;
+}
+
+CJSON_PUBLIC(double) cJSON_GetNumberValue(const cJSON* const item)
+{
+    if (!cJSON_IsNumber(item))
+    {
+        return (double)NAN;
+    }
+
+    return item->valuedouble;
+}
+
+/* This is a safeguard to prevent copy-pasters from using incompatible C and header files */
+#if (CJSON_VERSION_MAJOR != 1) || (CJSON_VERSION_MINOR != 7) || (CJSON_VERSION_PATCH != 18)
+#error cJSON.h and cJSON.c have different versions. Make sure that both have the same.
+#endif
+
+CJSON_PUBLIC(const char*) cJSON_Version(void)
+{
+    static char version[15];
+    sprintf(version, "%i.%i.%i", CJSON_VERSION_MAJOR, CJSON_VERSION_MINOR, CJSON_VERSION_PATCH);
+
+    return version;
+}
+
+/* Case insensitive string comparison, doesn't consider two NULL pointers equal though */
+static int case_insensitive_strcmp(const unsigned char* string1, const unsigned char* string2)
+{
+    if ((string1 == NULL) || (string2 == NULL))
+    {
+        return 1;
+    }
+
+    if (string1 == string2)
+    {
+        return 0;
+    }
+
+    for (; tolower(*string1) == tolower(*string2); (void)string1++, string2++)
+    {
+        if (*string1 == '\0')
+        {
+            return 0;
+        }
+    }
+
+    return tolower(*string1) - tolower(*string2);
+}
+
+typedef struct internal_hooks
+{
+    void* (CJSON_CDECL* allocate)(size_t size);
+    void (CJSON_CDECL* deallocate)(void* pointer);
+    void* (CJSON_CDECL* reallocate)(void* pointer, size_t size);
+} internal_hooks;
+
+#if defined(_MSC_VER)
+/* work around MSVC error C2322: '...' address of dllimport '...' is not static */
+static void* CJSON_CDECL internal_malloc(size_t size)
+{
+    return malloc(size);
+}
+static void CJSON_CDECL internal_free(void* pointer)
+{
+    free(pointer);
+}
+static void* CJSON_CDECL internal_realloc(void* pointer, size_t size)
+{
+    return realloc(pointer, size);
+}
+#else
+#define internal_malloc malloc
+#define internal_free free
+#define internal_realloc realloc
+#endif
+
+/* strlen of character literals resolved at compile time */
+#define static_strlen(string_literal) (sizeof(string_literal) - sizeof(""))
+
+static internal_hooks global_hooks = { internal_malloc, internal_free, internal_realloc };
+
+static unsigned char* cJSON_strdup(const unsigned char* string, const internal_hooks* const hooks)
+{
+    size_t length = 0;
+    unsigned char* copy = NULL;
+
+    if (string == NULL)
+    {
+        return NULL;
+    }
+
+    length = strlen((const char*)string) + sizeof("");
+    copy = (unsigned char*)hooks->allocate(length);
+    if (copy == NULL)
+    {
+        return NULL;
+    }
+    memcpy(copy, string, length);
+
+    return copy;
+}
+
+CJSON_PUBLIC(void) cJSON_InitHooks(cJSON_Hooks* hooks)
+{
+    if (hooks == NULL)
+    {
+        /* Reset hooks */
+        global_hooks.allocate = malloc;
+        global_hooks.deallocate = free;
+        global_hooks.reallocate = realloc;
+        return;
+    }
+
+    global_hooks.allocate = malloc;
+    if (hooks->malloc_fn != NULL)
+    {
+        global_hooks.allocate = hooks->malloc_fn;
+    }
+
+    global_hooks.deallocate = free;
+    if (hooks->free_fn != NULL)
+    {
+        global_hooks.deallocate = hooks->free_fn;
+    }
+
+    /* use realloc only if both free and malloc are used */
+    global_hooks.reallocate = NULL;
+    if ((global_hooks.allocate == malloc) && (global_hooks.deallocate == free))
+    {
+        global_hooks.reallocate = realloc;
+    }
+}
+
+/* Internal constructor. */
+static cJSON* cJSON_New_Item(const internal_hooks* const hooks)
+{
+    cJSON* node = (cJSON*)hooks->allocate(sizeof(cJSON));
+    if (node)
+    {
+        memset(node, '\0', sizeof(cJSON));
+    }
+
+    return node;
+}
+
+/* Delete a cJSON structure. */
+CJSON_PUBLIC(void) cJSON_Delete(cJSON* item)
+{
+    cJSON* next = NULL;
+    while (item != NULL)
+    {
+        next = item->next;
+        if (!(item->type & cJSON_IsReference) && (item->child != NULL))
+        {
+            cJSON_Delete(item->child);
+        }
+        if (!(item->type & cJSON_IsReference) && (item->valuestring != NULL))
+        {
+            global_hooks.deallocate(item->valuestring);
+            item->valuestring = NULL;
+        }
+        if (!(item->type & cJSON_StringIsConst) && (item->string != NULL))
+        {
+            global_hooks.deallocate(item->string);
+            item->string = NULL;
+        }
+        global_hooks.deallocate(item);
+        item = next;
+    }
+}
+
+/* get the decimal point character of the current locale */
+static unsigned char get_decimal_point(void)
+{
+#ifdef ENABLE_LOCALES
+    struct lconv* lconv = localeconv();
+    return (unsigned char)lconv->decimal_point[0];
+#else
+    return '.';
+#endif
+}
+
+typedef struct
+{
+    const unsigned char* content;
+    size_t length;
+    size_t offset;
+    size_t depth; /* How deeply nested (in arrays/objects) is the input at the current offset. */
+    internal_hooks hooks;
+} parse_buffer;
+
+/* check if the given size is left to read in a given parse buffer (starting with 1) */
+#define can_read(buffer, size) ((buffer != NULL) && (((buffer)->offset + size) <= (buffer)->length))
+/* check if the buffer can be accessed at the given index (starting with 0) */
+#define can_access_at_index(buffer, index) ((buffer != NULL) && (((buffer)->offset + index) < (buffer)->length))
+#define cannot_access_at_index(buffer, index) (!can_access_at_index(buffer, index))
+/* get a pointer to the buffer at the position */
+#define buffer_at_offset(buffer) ((buffer)->content + (buffer)->offset)
+
+/* Parse the input text to generate a number, and populate the result into item. */
+static cJSON_bool parse_number(cJSON* const item, parse_buffer* const input_buffer)
+{
+    double number = 0;
+    unsigned char* after_end = NULL;
+    unsigned char number_c_string[64];
+    unsigned char decimal_point = get_decimal_point();
+    size_t i = 0;
+
+    if ((input_buffer == NULL) || (input_buffer->content == NULL))
+    {
+        return false;
+    }
+
+    /* copy the number into a temporary buffer and replace '.' with the decimal point
+     * of the current locale (for strtod)
+     * This also takes care of '\0' not necessarily being available for marking the end of the input */
+    for (i = 0; (i < (sizeof(number_c_string) - 1)) && can_access_at_index(input_buffer, i); i++)
+    {
+        switch (buffer_at_offset(input_buffer)[i])
+        {
+        case '0':
+        case '1':
+        case '2':
+        case '3':
+        case '4':
+        case '5':
+        case '6':
+        case '7':
+        case '8':
+        case '9':
+        case '+':
+        case '-':
+        case 'e':
+        case 'E':
+            number_c_string[i] = buffer_at_offset(input_buffer)[i];
+            break;
+
+        case '.':
+            number_c_string[i] = decimal_point;
+            break;
+
+        default:
+            goto loop_end;
+        }
+    }
+loop_end:
+    number_c_string[i] = '\0';
+
+    number = strtod((const char*)number_c_string, (char**)&after_end);
+    if (number_c_string == after_end)
+    {
+        return false; /* parse_error */
+    }
+
+    item->valuedouble = number;
+
+    /* use saturation in case of overflow */
+    if (number >= INT_MAX)
+    {
+        item->valueint = INT_MAX;
+    }
+    else if (number <= (double)INT_MIN)
+    {
+        item->valueint = INT_MIN;
+    }
+    else
+    {
+        item->valueint = (int)number;
+    }
+
+    item->type = cJSON_Number;
+
+    input_buffer->offset += (size_t)(after_end - number_c_string);
+    return true;
+}
+
+/* don't ask me, but the original cJSON_SetNumberValue returns an integer or double */
+CJSON_PUBLIC(double) cJSON_SetNumberHelper(cJSON* object, double number)
+{
+    if (number >= INT_MAX)
+    {
+        object->valueint = INT_MAX;
+    }
+    else if (number <= (double)INT_MIN)
+    {
+        object->valueint = INT_MIN;
+    }
+    else
+    {
+        object->valueint = (int)number;
+    }
+
+    return object->valuedouble = number;
+}
+
+/* Note: when passing a NULL valuestring, cJSON_SetValuestring treats this as an error and return NULL */
+CJSON_PUBLIC(char*) cJSON_SetValuestring(cJSON* object, const char* valuestring)
+{
+    char* copy = NULL;
+    /* if object's type is not cJSON_String or is cJSON_IsReference, it should not set valuestring */
+    if ((object == NULL) || !(object->type & cJSON_String) || (object->type & cJSON_IsReference))
+    {
+        return NULL;
+    }
+    /* return NULL if the object is corrupted or valuestring is NULL */
+    if (object->valuestring == NULL || valuestring == NULL)
+    {
+        return NULL;
+    }
+    if (strlen(valuestring) <= strlen(object->valuestring))
+    {
+        strcpy(object->valuestring, valuestring);
+        return object->valuestring;
+    }
+    copy = (char*)cJSON_strdup((const unsigned char*)valuestring, &global_hooks);
+    if (copy == NULL)
+    {
+        return NULL;
+    }
+    if (object->valuestring != NULL)
+    {
+        cJSON_free(object->valuestring);
+    }
+    object->valuestring = copy;
+
+    return copy;
+}
+
+typedef struct
+{
+    unsigned char* buffer;
+    size_t length;
+    size_t offset;
+    size_t depth; /* current nesting depth (for formatted printing) */
+    cJSON_bool noalloc;
+    cJSON_bool format; /* is this print a formatted print */
+    internal_hooks hooks;
+} printbuffer;
+
+/* realloc printbuffer if necessary to have at least "needed" bytes more */
+static unsigned char* ensure(printbuffer* const p, size_t needed)
+{
+    unsigned char* newbuffer = NULL;
+    size_t newsize = 0;
+
+    if ((p == NULL) || (p->buffer == NULL))
+    {
+        return NULL;
+    }
+
+    if ((p->length > 0) && (p->offset >= p->length))
+    {
+        /* make sure that offset is valid */
+        return NULL;
+    }
+
+    if (needed > INT_MAX)
+    {
+        /* sizes bigger than INT_MAX are currently not supported */
+        return NULL;
+    }
+
+    needed += p->offset + 1;
+    if (needed <= p->length)
+    {
+        return p->buffer + p->offset;
+    }
+
+    if (p->noalloc) {
+        return NULL;
+    }
+
+    /* calculate new buffer size */
+    if (needed > (INT_MAX / 2))
+    {
+        /* overflow of int, use INT_MAX if possible */
+        if (needed <= INT_MAX)
+        {
+            newsize = INT_MAX;
+        }
+        else
+        {
+            return NULL;
+        }
+    }
+    else
+    {
+        newsize = needed * 2;
+    }
+
+    if (p->hooks.reallocate != NULL)
+    {
+        /* reallocate with realloc if available */
+        newbuffer = (unsigned char*)p->hooks.reallocate(p->buffer, newsize);
+        if (newbuffer == NULL)
+        {
+            p->hooks.deallocate(p->buffer);
+            p->length = 0;
+            p->buffer = NULL;
+
+            return NULL;
+        }
+    }
+    else
+    {
+        /* otherwise reallocate manually */
+        newbuffer = (unsigned char*)p->hooks.allocate(newsize);
+        if (!newbuffer)
+        {
+            p->hooks.deallocate(p->buffer);
+            p->length = 0;
+            p->buffer = NULL;
+
+            return NULL;
+        }
+
+        memcpy(newbuffer, p->buffer, p->offset + 1);
+        p->hooks.deallocate(p->buffer);
+    }
+    p->length = newsize;
+    p->buffer = newbuffer;
+
+    return newbuffer + p->offset;
+}
+
+/* calculate the new length of the string in a printbuffer and update the offset */
+static void update_offset(printbuffer* const buffer)
+{
+    const unsigned char* buffer_pointer = NULL;
+    if ((buffer == NULL) || (buffer->buffer == NULL))
+    {
+        return;
+    }
+    buffer_pointer = buffer->buffer + buffer->offset;
+
+    buffer->offset += strlen((const char*)buffer_pointer);
+}
+
+/* securely comparison of floating-point variables */
+static cJSON_bool compare_double(double a, double b)
+{
+    double maxVal = fabs(a) > fabs(b) ? fabs(a) : fabs(b);
+    return (fabs(a - b) <= maxVal * DBL_EPSILON);
+}
+
+/* Render the number nicely from the given item into a string. */
+static cJSON_bool print_number(const cJSON* const item, printbuffer* const output_buffer)
+{
+    unsigned char* output_pointer = NULL;
+    double d = item->valuedouble;
+    int length = 0;
+    size_t i = 0;
+    unsigned char number_buffer[26] = { 0 }; /* temporary buffer to print the number into */
+    unsigned char decimal_point = get_decimal_point();
+    double test = 0.0;
+
+    if (output_buffer == NULL)
+    {
+        return false;
+    }
+
+    /* This checks for NaN and Infinity */
+    if (isnan(d) || isinf(d))
+    {
+        length = sprintf((char*)number_buffer, "null");
+    }
+    else if (d == (double)item->valueint)
+    {
+        length = sprintf((char*)number_buffer, "%d", item->valueint);
+    }
+    else
+    {
+        /* Try 15 decimal places of precision to avoid nonsignificant nonzero digits */
+        length = sprintf((char*)number_buffer, "%1.15g", d);
+
+        /* Check whether the original double can be recovered */
+        if ((sscanf((char*)number_buffer, "%lg", &test) != 1) || !compare_double((double)test, d))
+        {
+            /* If not, print with 17 decimal places of precision */
+            length = sprintf((char*)number_buffer, "%1.17g", d);
+        }
+    }
+
+    /* sprintf failed or buffer overrun occurred */
+    if ((length < 0) || (length > (int)(sizeof(number_buffer) - 1)))
+    {
+        return false;
+    }
+
+    /* reserve appropriate space in the output */
+    output_pointer = ensure(output_buffer, (size_t)length + sizeof(""));
+    if (output_pointer == NULL)
+    {
+        return false;
+    }
+
+    /* copy the printed number to the output and replace locale
+     * dependent decimal point with '.' */
+    for (i = 0; i < ((size_t)length); i++)
+    {
+        if (number_buffer[i] == decimal_point)
+        {
+            output_pointer[i] = '.';
+            continue;
+        }
+
+        output_pointer[i] = number_buffer[i];
+    }
+    output_pointer[i] = '\0';
+
+    output_buffer->offset += (size_t)length;
+
+    return true;
+}
+
+/* parse 4 digit hexadecimal number */
+static unsigned parse_hex4(const unsigned char* const input)
+{
+    unsigned int h = 0;
+    size_t i = 0;
+
+    for (i = 0; i < 4; i++)
+    {
+        /* parse digit */
+        if ((input[i] >= '0') && (input[i] <= '9'))
+        {
+            h += (unsigned int)input[i] - '0';
+        }
+        else if ((input[i] >= 'A') && (input[i] <= 'F'))
+        {
+            h += (unsigned int)10 + input[i] - 'A';
+        }
+        else if ((input[i] >= 'a') && (input[i] <= 'f'))
+        {
+            h += (unsigned int)10 + input[i] - 'a';
+        }
+        else /* invalid */
+        {
+            return 0;
+        }
+
+        if (i < 3)
+        {
+            /* shift left to make place for the next nibble */
+            h = h << 4;
+        }
+    }
+
+    return h;
+}
+
+/* converts a UTF-16 literal to UTF-8
+ * A literal can be one or two sequences of the form \uXXXX */
+static unsigned char utf16_literal_to_utf8(const unsigned char* const input_pointer, const unsigned char* const input_end, unsigned char** output_pointer)
+{
+    long unsigned int codepoint = 0;
+    unsigned int first_code = 0;
+    const unsigned char* first_sequence = input_pointer;
+    unsigned char utf8_length = 0;
+    unsigned char utf8_position = 0;
+    unsigned char sequence_length = 0;
+    unsigned char first_byte_mark = 0;
+
+    if ((input_end - first_sequence) < 6)
+    {
+        /* input ends unexpectedly */
+        goto fail;
+    }
+
+    /* get the first utf16 sequence */
+    first_code = parse_hex4(first_sequence + 2);
+
+    /* check that the code is valid */
+    if (((first_code >= 0xDC00) && (first_code <= 0xDFFF)))
+    {
+        goto fail;
+    }
+
+    /* UTF16 surrogate pair */
+    if ((first_code >= 0xD800) && (first_code <= 0xDBFF))
+    {
+        const unsigned char* second_sequence = first_sequence + 6;
+        unsigned int second_code = 0;
+        sequence_length = 12; /* \uXXXX\uXXXX */
+
+        if ((input_end - second_sequence) < 6)
+        {
+            /* input ends unexpectedly */
+            goto fail;
+        }
+
+        if ((second_sequence[0] != '\\') || (second_sequence[1] != 'u'))
+        {
+            /* missing second half of the surrogate pair */
+            goto fail;
+        }
+
+        /* get the second utf16 sequence */
+        second_code = parse_hex4(second_sequence + 2);
+        /* check that the code is valid */
+        if ((second_code < 0xDC00) || (second_code > 0xDFFF))
+        {
+            /* invalid second half of the surrogate pair */
+            goto fail;
+        }
+
+
+        /* calculate the unicode codepoint from the surrogate pair */
+        codepoint = 0x10000 + (((first_code & 0x3FF) << 10) | (second_code & 0x3FF));
+    }
+    else
+    {
+        sequence_length = 6; /* \uXXXX */
+        codepoint = first_code;
+    }
+
+    /* encode as UTF-8
+     * takes at maximum 4 bytes to encode:
+     * 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx */
+    if (codepoint < 0x80)
+    {
+        /* normal ascii, encoding 0xxxxxxx */
+        utf8_length = 1;
+    }
+    else if (codepoint < 0x800)
+    {
+        /* two bytes, encoding 110xxxxx 10xxxxxx */
+        utf8_length = 2;
+        first_byte_mark = 0xC0; /* 11000000 */
+    }
+    else if (codepoint < 0x10000)
+    {
+        /* three bytes, encoding 1110xxxx 10xxxxxx 10xxxxxx */
+        utf8_length = 3;
+        first_byte_mark = 0xE0; /* 11100000 */
+    }
+    else if (codepoint <= 0x10FFFF)
+    {
+        /* four bytes, encoding 1110xxxx 10xxxxxx 10xxxxxx 10xxxxxx */
+        utf8_length = 4;
+        first_byte_mark = 0xF0; /* 11110000 */
+    }
+    else
+    {
+        /* invalid unicode codepoint */
+        goto fail;
+    }
+
+    /* encode as utf8 */
+    for (utf8_position = (unsigned char)(utf8_length - 1); utf8_position > 0; utf8_position--)
+    {
+        /* 10xxxxxx */
+        (*output_pointer)[utf8_position] = (unsigned char)((codepoint | 0x80) & 0xBF);
+        codepoint >>= 6;
+    }
+    /* encode first byte */
+    if (utf8_length > 1)
+    {
+        (*output_pointer)[0] = (unsigned char)((codepoint | first_byte_mark) & 0xFF);
+    }
+    else
+    {
+        (*output_pointer)[0] = (unsigned char)(codepoint & 0x7F);
+    }
+
+    *output_pointer += utf8_length;
+
+    return sequence_length;
+
+fail:
+    return 0;
+}
+
+/* Parse the input text into an unescaped cinput, and populate item. */
+static cJSON_bool parse_string(cJSON* const item, parse_buffer* const input_buffer)
+{
+    const unsigned char* input_pointer = buffer_at_offset(input_buffer) + 1;
+    const unsigned char* input_end = buffer_at_offset(input_buffer) + 1;
+    unsigned char* output_pointer = NULL;
+    unsigned char* output = NULL;
+
+    /* not a string */
+    if (buffer_at_offset(input_buffer)[0] != '\"')
+    {
+        goto fail;
+    }
+
+    {
+        /* calculate approximate size of the output (overestimate) */
+        size_t allocation_length = 0;
+        size_t skipped_bytes = 0;
+        while (((size_t)(input_end - input_buffer->content) < input_buffer->length) && (*input_end != '\"'))
+        {
+            /* is escape sequence */
+            if (input_end[0] == '\\')
+            {
+                if ((size_t)(input_end + 1 - input_buffer->content) >= input_buffer->length)
+                {
+                    /* prevent buffer overflow when last input character is a backslash */
+                    goto fail;
+                }
+                skipped_bytes++;
+                input_end++;
+            }
+            input_end++;
+        }
+        if (((size_t)(input_end - input_buffer->content) >= input_buffer->length) || (*input_end != '\"'))
+        {
+            goto fail; /* string ended unexpectedly */
+        }
+
+        /* This is at most how much we need for the output */
+        allocation_length = (size_t)(input_end - buffer_at_offset(input_buffer)) - skipped_bytes;
+        output = (unsigned char*)input_buffer->hooks.allocate(allocation_length + sizeof(""));
+        if (output == NULL)
+        {
+            goto fail; /* allocation failure */
+        }
+    }
+
+    output_pointer = output;
+    /* loop through the string literal */
+    while (input_pointer < input_end)
+    {
+        if (*input_pointer != '\\')
+        {
+            *output_pointer++ = *input_pointer++;
+        }
+        /* escape sequence */
+        else
+        {
+            unsigned char sequence_length = 2;
+            if ((input_end - input_pointer) < 1)
+            {
+                goto fail;
+            }
+
+            switch (input_pointer[1])
+            {
+            case 'b':
+                *output_pointer++ = '\b';
+                break;
+            case 'f':
+                *output_pointer++ = '\f';
+                break;
+            case 'n':
+                *output_pointer++ = '\n';
+                break;
+            case 'r':
+                *output_pointer++ = '\r';
+                break;
+            case 't':
+                *output_pointer++ = '\t';
+                break;
+            case '\"':
+            case '\\':
+            case '/':
+                *output_pointer++ = input_pointer[1];
+                break;
+
+                /* UTF-16 literal */
+            case 'u':
+                sequence_length = utf16_literal_to_utf8(input_pointer, input_end, &output_pointer);
+                if (sequence_length == 0)
+                {
+                    /* failed to convert UTF16-literal to UTF-8 */
+                    goto fail;
+                }
+                break;
+
+            default:
+                goto fail;
+            }
+            input_pointer += sequence_length;
+        }
+    }
+
+    /* zero terminate the output */
+    *output_pointer = '\0';
+
+    item->type = cJSON_String;
+    item->valuestring = (char*)output;
+
+    input_buffer->offset = (size_t)(input_end - input_buffer->content);
+    input_buffer->offset++;
+
+    return true;
+
+fail:
+    if (output != NULL)
+    {
+        input_buffer->hooks.deallocate(output);
+        output = NULL;
+    }
+
+    if (input_pointer != NULL)
+    {
+        input_buffer->offset = (size_t)(input_pointer - input_buffer->content);
+    }
+
+    return false;
+}
+
+/* Render the cstring provided to an escaped version that can be printed. */
+static cJSON_bool print_string_ptr(const unsigned char* const input, printbuffer* const output_buffer)
+{
+    const unsigned char* input_pointer = NULL;
+    unsigned char* output = NULL;
+    unsigned char* output_pointer = NULL;
+    size_t output_length = 0;
+    /* numbers of additional characters needed for escaping */
+    size_t escape_characters = 0;
+
+    if (output_buffer == NULL)
+    {
+        return false;
+    }
+
+    /* empty string */
+    if (input == NULL)
+    {
+        output = ensure(output_buffer, sizeof("\"\""));
+        if (output == NULL)
+        {
+            return false;
+        }
+        strcpy((char*)output, "\"\"");
+
+        return true;
+    }
+
+    /* set "flag" to 1 if something needs to be escaped */
+    for (input_pointer = input; *input_pointer; input_pointer++)
+    {
+        switch (*input_pointer)
+        {
+        case '\"':
+        case '\\':
+        case '\b':
+        case '\f':
+        case '\n':
+        case '\r':
+        case '\t':
+            /* one character escape sequence */
+            escape_characters++;
+            break;
+        default:
+            if (*input_pointer < 32)
+            {
+                /* UTF-16 escape sequence uXXXX */
+                escape_characters += 5;
+            }
+            break;
+        }
+    }
+    output_length = (size_t)(input_pointer - input) + escape_characters;
+
+    output = ensure(output_buffer, output_length + sizeof("\"\""));
+    if (output == NULL)
+    {
+        return false;
+    }
+
+    /* no characters have to be escaped */
+    if (escape_characters == 0)
+    {
+        output[0] = '\"';
+        memcpy(output + 1, input, output_length);
+        output[output_length + 1] = '\"';
+        output[output_length + 2] = '\0';
+
+        return true;
+    }
+
+    output[0] = '\"';
+    output_pointer = output + 1;
+    /* copy the string */
+    for (input_pointer = input; *input_pointer != '\0'; (void)input_pointer++, output_pointer++)
+    {
+        if ((*input_pointer > 31) && (*input_pointer != '\"') && (*input_pointer != '\\'))
+        {
+            /* normal character, copy */
+            *output_pointer = *input_pointer;
+        }
+        else
+        {
+            /* character needs to be escaped */
+            *output_pointer++ = '\\';
+            switch (*input_pointer)
+            {
+            case '\\':
+                *output_pointer = '\\';
+                break;
+            case '\"':
+                *output_pointer = '\"';
+                break;
+            case '\b':
+                *output_pointer = 'b';
+                break;
+            case '\f':
+                *output_pointer = 'f';
+                break;
+            case '\n':
+                *output_pointer = 'n';
+                break;
+            case '\r':
+                *output_pointer = 'r';
+                break;
+            case '\t':
+                *output_pointer = 't';
+                break;
+            default:
+                /* escape and print as unicode codepoint */
+                sprintf((char*)output_pointer, "u%04x", *input_pointer);
+                output_pointer += 4;
+                break;
+            }
+        }
+    }
+    output[output_length + 1] = '\"';
+    output[output_length + 2] = '\0';
+
+    return true;
+}
+
+/* Invoke print_string_ptr (which is useful) on an item. */
+static cJSON_bool print_string(const cJSON* const item, printbuffer* const p)
+{
+    return print_string_ptr((unsigned char*)item->valuestring, p);
+}
+
+/* Predeclare these prototypes. */
+static cJSON_bool parse_value(cJSON* const item, parse_buffer* const input_buffer);
+static cJSON_bool print_value(const cJSON* const item, printbuffer* const output_buffer);
+static cJSON_bool parse_array(cJSON* const item, parse_buffer* const input_buffer);
+static cJSON_bool print_array(const cJSON* const item, printbuffer* const output_buffer);
+static cJSON_bool parse_object(cJSON* const item, parse_buffer* const input_buffer);
+static cJSON_bool print_object(const cJSON* const item, printbuffer* const output_buffer);
+
+/* Utility to jump whitespace and cr/lf */
+static parse_buffer* buffer_skip_whitespace(parse_buffer* const buffer)
+{
+    if ((buffer == NULL) || (buffer->content == NULL))
+    {
+        return NULL;
+    }
+
+    if (cannot_access_at_index(buffer, 0))
+    {
+        return buffer;
+    }
+
+    while (can_access_at_index(buffer, 0) && (buffer_at_offset(buffer)[0] <= 32))
+    {
+        buffer->offset++;
+    }
+
+    if (buffer->offset == buffer->length)
+    {
+        buffer->offset--;
+    }
+
+    return buffer;
+}
+
+/* skip the UTF-8 BOM (byte order mark) if it is at the beginning of a buffer */
+static parse_buffer* skip_utf8_bom(parse_buffer* const buffer)
+{
+    if ((buffer == NULL) || (buffer->content == NULL) || (buffer->offset != 0))
+    {
+        return NULL;
+    }
+
+    if (can_access_at_index(buffer, 4) && (strncmp((const char*)buffer_at_offset(buffer), "\xEF\xBB\xBF", 3) == 0))
+    {
+        buffer->offset += 3;
+    }
+
+    return buffer;
+}
+
+CJSON_PUBLIC(cJSON*) cJSON_ParseWithOpts(const char* value, const char** return_parse_end, cJSON_bool require_null_terminated)
+{
+    size_t buffer_length;
+
+    if (NULL == value)
+    {
+        return NULL;
+    }
+
+    /* Adding null character size due to require_null_terminated. */
+    buffer_length = strlen(value) + sizeof("");
+
+    return cJSON_ParseWithLengthOpts(value, buffer_length, return_parse_end, require_null_terminated);
+}
+
+/* Parse an object - create a new root, and populate. */
+CJSON_PUBLIC(cJSON*) cJSON_ParseWithLengthOpts(const char* value, size_t buffer_length, const char** return_parse_end, cJSON_bool require_null_terminated)
+{
+    parse_buffer buffer = { 0, 0, 0, 0, { 0, 0, 0 } };
+    cJSON* item = NULL;
+
+    /* reset error position */
+    global_error.json = NULL;
+    global_error.position = 0;
+
+    if (value == NULL || 0 == buffer_length)
+    {
+        goto fail;
+    }
+
+    buffer.content = (const unsigned char*)value;
+    buffer.length = buffer_length;
+    buffer.offset = 0;
+    buffer.hooks = global_hooks;
+
+    item = cJSON_New_Item(&global_hooks);
+    if (item == NULL) /* memory fail */
+    {
+        goto fail;
+    }
+
+    if (!parse_value(item, buffer_skip_whitespace(skip_utf8_bom(&buffer))))
+    {
+        /* parse failure. ep is set. */
+        goto fail;
+    }
+
+    /* if we require null-terminated JSON without appended garbage, skip and then check for a null terminator */
+    if (require_null_terminated)
+    {
+        buffer_skip_whitespace(&buffer);
+        if ((buffer.offset >= buffer.length) || buffer_at_offset(&buffer)[0] != '\0')
+        {
+            goto fail;
+        }
+    }
+    if (return_parse_end)
+    {
+        *return_parse_end = (const char*)buffer_at_offset(&buffer);
+    }
+
+    return item;
+
+fail:
+    if (item != NULL)
+    {
+        cJSON_Delete(item);
+    }
+
+    if (value != NULL)
+    {
+        error local_error;
+        local_error.json = (const unsigned char*)value;
+        local_error.position = 0;
+
+        if (buffer.offset < buffer.length)
+        {
+            local_error.position = buffer.offset;
+        }
+        else if (buffer.length > 0)
+        {
+            local_error.position = buffer.length - 1;
+        }
+
+        if (return_parse_end != NULL)
+        {
+            *return_parse_end = (const char*)local_error.json + local_error.position;
+        }
+
+        global_error = local_error;
+    }
+
+    return NULL;
+}
+
+/* Default options for cJSON_Parse */
+CJSON_PUBLIC(cJSON*) cJSON_Parse(const char* value)
+{
+    return cJSON_ParseWithOpts(value, 0, 0);
+}
+
+CJSON_PUBLIC(cJSON*) cJSON_ParseWithLength(const char* value, size_t buffer_length)
+{
+    return cJSON_ParseWithLengthOpts(value, buffer_length, 0, 0);
+}
+
+#define cjson_min(a, b) (((a) < (b)) ? (a) : (b))
+
+static unsigned char* print(const cJSON* const item, cJSON_bool format, const internal_hooks* const hooks)
+{
+    static const size_t default_buffer_size = 256;
+    printbuffer buffer[1];
+    unsigned char* printed = NULL;
+
+    memset(buffer, 0, sizeof(buffer));
+
+    /* create buffer */
+    buffer->buffer = (unsigned char*)hooks->allocate(default_buffer_size);
+    buffer->length = default_buffer_size;
+    buffer->format = format;
+    buffer->hooks = *hooks;
+    if (buffer->buffer == NULL)
+    {
+        goto fail;
+    }
+
+    /* print the value */
+    if (!print_value(item, buffer))
+    {
+        goto fail;
+    }
+    update_offset(buffer);
+
+    /* check if reallocate is available */
+    if (hooks->reallocate != NULL)
+    {
+        printed = (unsigned char*)hooks->reallocate(buffer->buffer, buffer->offset + 1);
+        if (printed == NULL) {
+            goto fail;
+        }
+        buffer->buffer = NULL;
+    }
+    else /* otherwise copy the JSON over to a new buffer */
+    {
+        printed = (unsigned char*)hooks->allocate(buffer->offset + 1);
+        if (printed == NULL)
+        {
+            goto fail;
+        }
+        memcpy(printed, buffer->buffer, cjson_min(buffer->length, buffer->offset + 1));
+        printed[buffer->offset] = '\0'; /* just to be sure */
+
+        /* free the buffer */
+        hooks->deallocate(buffer->buffer);
+        buffer->buffer = NULL;
+    }
+
+    return printed;
+
+fail:
+    if (buffer->buffer != NULL)
+    {
+        hooks->deallocate(buffer->buffer);
+        buffer->buffer = NULL;
+    }
+
+    if (printed != NULL)
+    {
+        hooks->deallocate(printed);
+        printed = NULL;
+    }
+
+    return NULL;
+}
+
+/* Render a cJSON item/entity/structure to text. */
+CJSON_PUBLIC(char*) cJSON_Print(const cJSON* item)
+{
+    return (char*)print(item, true, &global_hooks);
+}
+
+CJSON_PUBLIC(char*) cJSON_PrintUnformatted(const cJSON* item)
+{
+    return (char*)print(item, false, &global_hooks);
+}
+
+CJSON_PUBLIC(char*) cJSON_PrintBuffered(const cJSON* item, int prebuffer, cJSON_bool fmt)
+{
+    printbuffer p = { 0, 0, 0, 0, 0, 0, { 0, 0, 0 } };
+
+    if (prebuffer < 0)
+    {
+        return NULL;
+    }
+
+    p.buffer = (unsigned char*)global_hooks.allocate((size_t)prebuffer);
+    if (!p.buffer)
+    {
+        return NULL;
+    }
+
+    p.length = (size_t)prebuffer;
+    p.offset = 0;
+    p.noalloc = false;
+    p.format = fmt;
+    p.hooks = global_hooks;
+
+    if (!print_value(item, &p))
+    {
+        global_hooks.deallocate(p.buffer);
+        p.buffer = NULL;
+        return NULL;
+    }
+
+    return (char*)p.buffer;
+}
+
+CJSON_PUBLIC(cJSON_bool) cJSON_PrintPreallocated(cJSON* item, char* buffer, const int length, const cJSON_bool format)
+{
+    printbuffer p = { 0, 0, 0, 0, 0, 0, { 0, 0, 0 } };
+
+    if ((length < 0) || (buffer == NULL))
+    {
+        return false;
+    }
+
+    p.buffer = (unsigned char*)buffer;
+    p.length = (size_t)length;
+    p.offset = 0;
+    p.noalloc = true;
+    p.format = format;
+    p.hooks = global_hooks;
+
+    return print_value(item, &p);
+}
+
+/* Parser core - when encountering text, process appropriately. */
+static cJSON_bool parse_value(cJSON* const item, parse_buffer* const input_buffer)
+{
+    if ((input_buffer == NULL) || (input_buffer->content == NULL))
+    {
+        return false; /* no input */
+    }
+
+    /* parse the different types of values */
+    /* null */
+    if (can_read(input_buffer, 4) && (strncmp((const char*)buffer_at_offset(input_buffer), "null", 4) == 0))
+    {
+        item->type = cJSON_NULL;
+        input_buffer->offset += 4;
+        return true;
+    }
+    /* false */
+    if (can_read(input_buffer, 5) && (strncmp((const char*)buffer_at_offset(input_buffer), "false", 5) == 0))
+    {
+        item->type = cJSON_False;
+        input_buffer->offset += 5;
+        return true;
+    }
+    /* true */
+    if (can_read(input_buffer, 4) && (strncmp((const char*)buffer_at_offset(input_buffer), "true", 4) == 0))
+    {
+        item->type = cJSON_True;
+        item->valueint = 1;
+        input_buffer->offset += 4;
+        return true;
+    }
+    /* string */
+    if (can_access_at_index(input_buffer, 0) && (buffer_at_offset(input_buffer)[0] == '\"'))
+    {
+        return parse_string(item, input_buffer);
+    }
+    /* number */
+    if (can_access_at_index(input_buffer, 0) && ((buffer_at_offset(input_buffer)[0] == '-') || ((buffer_at_offset(input_buffer)[0] >= '0') && (buffer_at_offset(input_buffer)[0] <= '9'))))
+    {
+        return parse_number(item, input_buffer);
+    }
+    /* array */
+    if (can_access_at_index(input_buffer, 0) && (buffer_at_offset(input_buffer)[0] == '['))
+    {
+        return parse_array(item, input_buffer);
+    }
+    /* object */
+    if (can_access_at_index(input_buffer, 0) && (buffer_at_offset(input_buffer)[0] == '{'))
+    {
+        return parse_object(item, input_buffer);
+    }
+
+    return false;
+}
+
+/* Render a value to text. */
+static cJSON_bool print_value(const cJSON* const item, printbuffer* const output_buffer)
+{
+    unsigned char* output = NULL;
+
+    if ((item == NULL) || (output_buffer == NULL))
+    {
+        return false;
+    }
+
+    switch ((item->type) & 0xFF)
+    {
+    case cJSON_NULL:
+        output = ensure(output_buffer, 5);
+        if (output == NULL)
+        {
+            return false;
+        }
+        strcpy((char*)output, "null");
+        return true;
+
+    case cJSON_False:
+        output = ensure(output_buffer, 6);
+        if (output == NULL)
+        {
+            return false;
+        }
+        strcpy((char*)output, "false");
+        return true;
+
+    case cJSON_True:
+        output = ensure(output_buffer, 5);
+        if (output == NULL)
+        {
+            return false;
+        }
+        strcpy((char*)output, "true");
+        return true;
+
+    case cJSON_Number:
+        return print_number(item, output_buffer);
+
+    case cJSON_Raw:
+    {
+        size_t raw_length = 0;
+        if (item->valuestring == NULL)
+        {
+            return false;
+        }
+
+        raw_length = strlen(item->valuestring) + sizeof("");
+        output = ensure(output_buffer, raw_length);
+        if (output == NULL)
+        {
+            return false;
+        }
+        memcpy(output, item->valuestring, raw_length);
+        return true;
+    }
+
+    case cJSON_String:
+        return print_string(item, output_buffer);
+
+    case cJSON_Array:
+        return print_array(item, output_buffer);
+
+    case cJSON_Object:
+        return print_object(item, output_buffer);
+
+    default:
+        return false;
+    }
+}
+
+/* Build an array from input text. */
+static cJSON_bool parse_array(cJSON* const item, parse_buffer* const input_buffer)
+{
+    cJSON* head = NULL; /* head of the linked list */
+    cJSON* current_item = NULL;
+
+    if (input_buffer->depth >= CJSON_NESTING_LIMIT)
+    {
+        return false; /* to deeply nested */
+    }
+    input_buffer->depth++;
+
+    if (buffer_at_offset(input_buffer)[0] != '[')
+    {
+        /* not an array */
+        goto fail;
+    }
+
+    input_buffer->offset++;
+    buffer_skip_whitespace(input_buffer);
+    if (can_access_at_index(input_buffer, 0) && (buffer_at_offset(input_buffer)[0] == ']'))
+    {
+        /* empty array */
+        goto success;
+    }
+
+    /* check if we skipped to the end of the buffer */
+    if (cannot_access_at_index(input_buffer, 0))
+    {
+        input_buffer->offset--;
+        goto fail;
+    }
+
+    /* step back to character in front of the first element */
+    input_buffer->offset--;
+    /* loop through the comma separated array elements */
+    do
+    {
+        /* allocate next item */
+        cJSON* new_item = cJSON_New_Item(&(input_buffer->hooks));
+        if (new_item == NULL)
+        {
+            goto fail; /* allocation failure */
+        }
+
+        /* attach next item to list */
+        if (head == NULL)
+        {
+            /* start the linked list */
+            current_item = head = new_item;
+        }
+        else
+        {
+            /* add to the end and advance */
+            current_item->next = new_item;
+            new_item->prev = current_item;
+            current_item = new_item;
+        }
+
+        /* parse next value */
+        input_buffer->offset++;
+        buffer_skip_whitespace(input_buffer);
+        if (!parse_value(current_item, input_buffer))
+        {
+            goto fail; /* failed to parse value */
+        }
+        buffer_skip_whitespace(input_buffer);
+    } while (can_access_at_index(input_buffer, 0) && (buffer_at_offset(input_buffer)[0] == ','));
+
+    if (cannot_access_at_index(input_buffer, 0) || buffer_at_offset(input_buffer)[0] != ']')
+    {
+        goto fail; /* expected end of array */
+    }
+
+success:
+    input_buffer->depth--;
+
+    if (head != NULL) {
+        head->prev = current_item;
+    }
+
+    item->type = cJSON_Array;
+    item->child = head;
+
+    input_buffer->offset++;
+
+    return true;
+
+fail:
+    if (head != NULL)
+    {
+        cJSON_Delete(head);
+    }
+
+    return false;
+}
+
+/* Render an array to text */
+static cJSON_bool print_array(const cJSON* const item, printbuffer* const output_buffer)
+{
+    unsigned char* output_pointer = NULL;
+    size_t length = 0;
+    cJSON* current_element = item->child;
+
+    if (output_buffer == NULL)
+    {
+        return false;
+    }
+
+    /* Compose the output array. */
+    /* opening square bracket */
+    output_pointer = ensure(output_buffer, 1);
+    if (output_pointer == NULL)
+    {
+        return false;
+    }
+
+    *output_pointer = '[';
+    output_buffer->offset++;
+    output_buffer->depth++;
+
+    while (current_element != NULL)
+    {
+        if (!print_value(current_element, output_buffer))
+        {
+            return false;
+        }
+        update_offset(output_buffer);
+        if (current_element->next)
+        {
+            length = (size_t)(output_buffer->format ? 2 : 1);
+            output_pointer = ensure(output_buffer, length + 1);
+            if (output_pointer == NULL)
+            {
+                return false;
+            }
+            *output_pointer++ = ',';
+            if (output_buffer->format)
+            {
+                *output_pointer++ = ' ';
+            }
+            *output_pointer = '\0';
+            output_buffer->offset += length;
+        }
+        current_element = current_element->next;
+    }
+
+    output_pointer = ensure(output_buffer, 2);
+    if (output_pointer == NULL)
+    {
+        return false;
+    }
+    *output_pointer++ = ']';
+    *output_pointer = '\0';
+    output_buffer->depth--;
+
+    return true;
+}
+
+/* Build an object from the text. */
+static cJSON_bool parse_object(cJSON* const item, parse_buffer* const input_buffer)
+{
+    cJSON* head = NULL; /* linked list head */
+    cJSON* current_item = NULL;
+
+    if (input_buffer->depth >= CJSON_NESTING_LIMIT)
+    {
+        return false; /* to deeply nested */
+    }
+    input_buffer->depth++;
+
+    if (cannot_access_at_index(input_buffer, 0) || (buffer_at_offset(input_buffer)[0] != '{'))
+    {
+        goto fail; /* not an object */
+    }
+
+    input_buffer->offset++;
+    buffer_skip_whitespace(input_buffer);
+    if (can_access_at_index(input_buffer, 0) && (buffer_at_offset(input_buffer)[0] == '}'))
+    {
+        goto success; /* empty object */
+    }
+
+    /* check if we skipped to the end of the buffer */
+    if (cannot_access_at_index(input_buffer, 0))
+    {
+        input_buffer->offset--;
+        goto fail;
+    }
+
+    /* step back to character in front of the first element */
+    input_buffer->offset--;
+    /* loop through the comma separated array elements */
+    do
+    {
+        /* allocate next item */
+        cJSON* new_item = cJSON_New_Item(&(input_buffer->hooks));
+        if (new_item == NULL)
+        {
+            goto fail; /* allocation failure */
+        }
+
+        /* attach next item to list */
+        if (head == NULL)
+        {
+            /* start the linked list */
+            current_item = head = new_item;
+        }
+        else
+        {
+            /* add to the end and advance */
+            current_item->next = new_item;
+            new_item->prev = current_item;
+            current_item = new_item;
+        }
+
+        if (cannot_access_at_index(input_buffer, 1))
+        {
+            goto fail; /* nothing comes after the comma */
+        }
+
+        /* parse the name of the child */
+        input_buffer->offset++;
+        buffer_skip_whitespace(input_buffer);
+        if (!parse_string(current_item, input_buffer))
+        {
+            goto fail; /* failed to parse name */
+        }
+        buffer_skip_whitespace(input_buffer);
+
+        /* swap valuestring and string, because we parsed the name */
+        current_item->string = current_item->valuestring;
+        current_item->valuestring = NULL;
+
+        if (cannot_access_at_index(input_buffer, 0) || (buffer_at_offset(input_buffer)[0] != ':'))
+        {
+            goto fail; /* invalid object */
+        }
+
+        /* parse the value */
+        input_buffer->offset++;
+        buffer_skip_whitespace(input_buffer);
+        if (!parse_value(current_item, input_buffer))
+        {
+            goto fail; /* failed to parse value */
+        }
+        buffer_skip_whitespace(input_buffer);
+    } while (can_access_at_index(input_buffer, 0) && (buffer_at_offset(input_buffer)[0] == ','));
+
+    if (cannot_access_at_index(input_buffer, 0) || (buffer_at_offset(input_buffer)[0] != '}'))
+    {
+        goto fail; /* expected end of object */
+    }
+
+success:
+    input_buffer->depth--;
+
+    if (head != NULL) {
+        head->prev = current_item;
+    }
+
+    item->type = cJSON_Object;
+    item->child = head;
+
+    input_buffer->offset++;
+    return true;
+
+fail:
+    if (head != NULL)
+    {
+        cJSON_Delete(head);
+    }
+
+    return false;
+}
+
+/* Render an object to text. */
+static cJSON_bool print_object(const cJSON* const item, printbuffer* const output_buffer)
+{
+    unsigned char* output_pointer = NULL;
+    size_t length = 0;
+    cJSON* current_item = item->child;
+
+    if (output_buffer == NULL)
+    {
+        return false;
+    }
+
+    /* Compose the output: */
+    length = (size_t)(output_buffer->format ? 2 : 1); /* fmt: {\n */
+    output_pointer = ensure(output_buffer, length + 1);
+    if (output_pointer == NULL)
+    {
+        return false;
+    }
+
+    *output_pointer++ = '{';
+    output_buffer->depth++;
+    if (output_buffer->format)
+    {
+        *output_pointer++ = '\n';
+    }
+    output_buffer->offset += length;
+
+    while (current_item)
+    {
+        if (output_buffer->format)
+        {
+            size_t i;
+            output_pointer = ensure(output_buffer, output_buffer->depth);
+            if (output_pointer == NULL)
+            {
+                return false;
+            }
+            for (i = 0; i < output_buffer->depth; i++)
+            {
+                *output_pointer++ = '\t';
+            }
+            output_buffer->offset += output_buffer->depth;
+        }
+
+        /* print key */
+        if (!print_string_ptr((unsigned char*)current_item->string, output_buffer))
+        {
+            return false;
+        }
+        update_offset(output_buffer);
+
+        length = (size_t)(output_buffer->format ? 2 : 1);
+        output_pointer = ensure(output_buffer, length);
+        if (output_pointer == NULL)
+        {
+            return false;
+        }
+        *output_pointer++ = ':';
+        if (output_buffer->format)
+        {
+            *output_pointer++ = '\t';
+        }
+        output_buffer->offset += length;
+
+        /* print value */
+        if (!print_value(current_item, output_buffer))
+        {
+            return false;
+        }
+        update_offset(output_buffer);
+
+        /* print comma if not last */
+        length = ((size_t)(output_buffer->format ? 1 : 0) + (size_t)(current_item->next ? 1 : 0));
+        output_pointer = ensure(output_buffer, length + 1);
+        if (output_pointer == NULL)
+        {
+            return false;
+        }
+        if (current_item->next)
+        {
+            *output_pointer++ = ',';
+        }
+
+        if (output_buffer->format)
+        {
+            *output_pointer++ = '\n';
+        }
+        *output_pointer = '\0';
+        output_buffer->offset += length;
+
+        current_item = current_item->next;
+    }
+
+    output_pointer = ensure(output_buffer, output_buffer->format ? (output_buffer->depth + 1) : 2);
+    if (output_pointer == NULL)
+    {
+        return false;
+    }
+    if (output_buffer->format)
+    {
+        size_t i;
+        for (i = 0; i < (output_buffer->depth - 1); i++)
+        {
+            *output_pointer++ = '\t';
+        }
+    }
+    *output_pointer++ = '}';
+    *output_pointer = '\0';
+    output_buffer->depth--;
+
+    return true;
+}
+
+/* Get Array size/item / object item. */
+CJSON_PUBLIC(int) cJSON_GetArraySize(const cJSON* array)
+{
+    cJSON* child = NULL;
+    size_t size = 0;
+
+    if (array == NULL)
+    {
+        return 0;
+    }
+
+    child = array->child;
+
+    while (child != NULL)
+    {
+        size++;
+        child = child->next;
+    }
+
+    /* FIXME: Can overflow here. Cannot be fixed without breaking the API */
+
+    return (int)size;
+}
+
+static cJSON* get_array_item(const cJSON* array, size_t index)
+{
+    cJSON* current_child = NULL;
+
+    if (array == NULL)
+    {
+        return NULL;
+    }
+
+    current_child = array->child;
+    while ((current_child != NULL) && (index > 0))
+    {
+        index--;
+        current_child = current_child->next;
+    }
+
+    return current_child;
+}
+
+CJSON_PUBLIC(cJSON*) cJSON_GetArrayItem(const cJSON* array, int index)
+{
+    if (index < 0)
+    {
+        return NULL;
+    }
+
+    return get_array_item(array, (size_t)index);
+}
+
+static cJSON* get_object_item(const cJSON* const object, const char* const name, const cJSON_bool case_sensitive)
+{
+    cJSON* current_element = NULL;
+
+    if ((object == NULL) || (name == NULL))
+    {
+        return NULL;
+    }
+
+    current_element = object->child;
+    if (case_sensitive)
+    {
+        while ((current_element != NULL) && (current_element->string != NULL) && (strcmp(name, current_element->string) != 0))
+        {
+            current_element = current_element->next;
+        }
+    }
+    else
+    {
+        while ((current_element != NULL) && (case_insensitive_strcmp((const unsigned char*)name, (const unsigned char*)(current_element->string)) != 0))
+        {
+            current_element = current_element->next;
+        }
+    }
+
+    if ((current_element == NULL) || (current_element->string == NULL)) {
+        return NULL;
+    }
+
+    return current_element;
+}
+
+CJSON_PUBLIC(cJSON*) cJSON_GetObjectItem(const cJSON* const object, const char* const string)
+{
+    return get_object_item(object, string, false);
+}
+
+CJSON_PUBLIC(cJSON*) cJSON_GetObjectItemCaseSensitive(const cJSON* const object, const char* const string)
+{
+    return get_object_item(object, string, true);
+}
+
+CJSON_PUBLIC(cJSON_bool) cJSON_HasObjectItem(const cJSON* object, const char* string)
+{
+    return cJSON_GetObjectItem(object, string) ? 1 : 0;
+}
+
+/* Utility for array list handling. */
+static void suffix_object(cJSON* prev, cJSON* item)
+{
+    prev->next = item;
+    item->prev = prev;
+}
+
+/* Utility for handling references. */
+static cJSON* create_reference(const cJSON* item, const internal_hooks* const hooks)
+{
+    cJSON* reference = NULL;
+    if (item == NULL)
+    {
+        return NULL;
+    }
+
+    reference = cJSON_New_Item(hooks);
+    if (reference == NULL)
+    {
+        return NULL;
+    }
+
+    memcpy(reference, item, sizeof(cJSON));
+    reference->string = NULL;
+    reference->type |= cJSON_IsReference;
+    reference->next = reference->prev = NULL;
+    return reference;
+}
+
+static cJSON_bool add_item_to_array(cJSON* array, cJSON* item)
+{
+    cJSON* child = NULL;
+
+    if ((item == NULL) || (array == NULL) || (array == item))
+    {
+        return false;
+    }
+
+    child = array->child;
+    /*
+     * To find the last item in array quickly, we use prev in array
+     */
+    if (child == NULL)
+    {
+        /* list is empty, start new one */
+        array->child = item;
+        item->prev = item;
+        item->next = NULL;
+    }
+    else
+    {
+        /* append to the end */
+        if (child->prev)
+        {
+            suffix_object(child->prev, item);
+            array->child->prev = item;
+        }
+    }
+
+    return true;
+}
+
+/* Add item to array/object. */
+CJSON_PUBLIC(cJSON_bool) cJSON_AddItemToArray(cJSON* array, cJSON* item)
+{
+    return add_item_to_array(array, item);
+}
+
+#if defined(__clang__) || (defined(__GNUC__)  && ((__GNUC__ > 4) || ((__GNUC__ == 4) && (__GNUC_MINOR__ > 5))))
+#pragma GCC diagnostic push
+#endif
+#ifdef __GNUC__
+#pragma GCC diagnostic ignored "-Wcast-qual"
+#endif
+/* helper function to cast away const */
+static void* cast_away_const(const void* string)
+{
+    return (void*)string;
+}
+#if defined(__clang__) || (defined(__GNUC__)  && ((__GNUC__ > 4) || ((__GNUC__ == 4) && (__GNUC_MINOR__ > 5))))
+#pragma GCC diagnostic pop
+#endif
+
+
+static cJSON_bool add_item_to_object(cJSON* const object, const char* const string, cJSON* const item, const internal_hooks* const hooks, const cJSON_bool constant_key)
+{
+    char* new_key = NULL;
+    int new_type = cJSON_Invalid;
+
+    if ((object == NULL) || (string == NULL) || (item == NULL) || (object == item))
+    {
+        return false;
+    }
+
+    if (constant_key)
+    {
+        new_key = (char*)cast_away_const(string);
+        new_type = item->type | cJSON_StringIsConst;
+    }
+    else
+    {
+        new_key = (char*)cJSON_strdup((const unsigned char*)string, hooks);
+        if (new_key == NULL)
+        {
+            return false;
+        }
+
+        new_type = item->type & ~cJSON_StringIsConst;
+    }
+
+    if (!(item->type & cJSON_StringIsConst) && (item->string != NULL))
+    {
+        hooks->deallocate(item->string);
+    }
+
+    item->string = new_key;
+    item->type = new_type;
+
+    return add_item_to_array(object, item);
+}
+
+CJSON_PUBLIC(cJSON_bool) cJSON_AddItemToObject(cJSON* object, const char* string, cJSON* item)
+{
+    return add_item_to_object(object, string, item, &global_hooks, false);
+}
+
+/* Add an item to an object with constant string as key */
+CJSON_PUBLIC(cJSON_bool) cJSON_AddItemToObjectCS(cJSON* object, const char* string, cJSON* item)
+{
+    return add_item_to_object(object, string, item, &global_hooks, true);
+}
+
+CJSON_PUBLIC(cJSON_bool) cJSON_AddItemReferenceToArray(cJSON* array, cJSON* item)
+{
+    if (array == NULL)
+    {
+        return false;
+    }
+
+    return add_item_to_array(array, create_reference(item, &global_hooks));
+}
+
+CJSON_PUBLIC(cJSON_bool) cJSON_AddItemReferenceToObject(cJSON* object, const char* string, cJSON* item)
+{
+    if ((object == NULL) || (string == NULL))
+    {
+        return false;
+    }
+
+    return add_item_to_object(object, string, create_reference(item, &global_hooks), &global_hooks, false);
+}
+
+CJSON_PUBLIC(cJSON*) cJSON_AddNullToObject(cJSON* const object, const char* const name)
+{
+    cJSON* null = cJSON_CreateNull();
+    if (add_item_to_object(object, name, null, &global_hooks, false))
+    {
+        return null;
+    }
+
+    cJSON_Delete(null);
+    return NULL;
+}
+
+CJSON_PUBLIC(cJSON*) cJSON_AddTrueToObject(cJSON* const object, const char* const name)
+{
+    cJSON* true_item = cJSON_CreateTrue();
+    if (add_item_to_object(object, name, true_item, &global_hooks, false))
+    {
+        return true_item;
+    }
+
+    cJSON_Delete(true_item);
+    return NULL;
+}
+
+CJSON_PUBLIC(cJSON*) cJSON_AddFalseToObject(cJSON* const object, const char* const name)
+{
+    cJSON* false_item = cJSON_CreateFalse();
+    if (add_item_to_object(object, name, false_item, &global_hooks, false))
+    {
+        return false_item;
+    }
+
+    cJSON_Delete(false_item);
+    return NULL;
+}
+
+CJSON_PUBLIC(cJSON*) cJSON_AddBoolToObject(cJSON* const object, const char* const name, const cJSON_bool boolean)
+{
+    cJSON* bool_item = cJSON_CreateBool(boolean);
+    if (add_item_to_object(object, name, bool_item, &global_hooks, false))
+    {
+        return bool_item;
+    }
+
+    cJSON_Delete(bool_item);
+    return NULL;
+}
+
+CJSON_PUBLIC(cJSON*) cJSON_AddNumberToObject(cJSON* const object, const char* const name, const double number)
+{
+    cJSON* number_item = cJSON_CreateNumber(number);
+    if (add_item_to_object(object, name, number_item, &global_hooks, false))
+    {
+        return number_item;
+    }
+
+    cJSON_Delete(number_item);
+    return NULL;
+}
+
+CJSON_PUBLIC(cJSON*) cJSON_AddStringToObject(cJSON* const object, const char* const name, const char* const string)
+{
+    cJSON* string_item = cJSON_CreateString(string);
+    if (add_item_to_object(object, name, string_item, &global_hooks, false))
+    {
+        return string_item;
+    }
+
+    cJSON_Delete(string_item);
+    return NULL;
+}
+
+CJSON_PUBLIC(cJSON*) cJSON_AddRawToObject(cJSON* const object, const char* const name, const char* const raw)
+{
+    cJSON* raw_item = cJSON_CreateRaw(raw);
+    if (add_item_to_object(object, name, raw_item, &global_hooks, false))
+    {
+        return raw_item;
+    }
+
+    cJSON_Delete(raw_item);
+    return NULL;
+}
+
+CJSON_PUBLIC(cJSON*) cJSON_AddObjectToObject(cJSON* const object, const char* const name)
+{
+    cJSON* object_item = cJSON_CreateObject();
+    if (add_item_to_object(object, name, object_item, &global_hooks, false))
+    {
+        return object_item;
+    }
+
+    cJSON_Delete(object_item);
+    return NULL;
+}
+
+CJSON_PUBLIC(cJSON*) cJSON_AddArrayToObject(cJSON* const object, const char* const name)
+{
+    cJSON* array = cJSON_CreateArray();
+    if (add_item_to_object(object, name, array, &global_hooks, false))
+    {
+        return array;
+    }
+
+    cJSON_Delete(array);
+    return NULL;
+}
+
+CJSON_PUBLIC(cJSON*) cJSON_DetachItemViaPointer(cJSON* parent, cJSON* const item)
+{
+    if ((parent == NULL) || (item == NULL))
+    {
+        return NULL;
+    }
+
+    if (item != parent->child)
+    {
+        /* not the first element */
+        item->prev->next = item->next;
+    }
+    if (item->next != NULL)
+    {
+        /* not the last element */
+        item->next->prev = item->prev;
+    }
+
+    if (item == parent->child)
+    {
+        /* first element */
+        parent->child = item->next;
+    }
+    else if (item->next == NULL)
+    {
+        /* last element */
+        parent->child->prev = item->prev;
+    }
+
+    /* make sure the detached item doesn't point anywhere anymore */
+    item->prev = NULL;
+    item->next = NULL;
+
+    return item;
+}
+
+CJSON_PUBLIC(cJSON*) cJSON_DetachItemFromArray(cJSON* array, int which)
+{
+    if (which < 0)
+    {
+        return NULL;
+    }
+
+    return cJSON_DetachItemViaPointer(array, get_array_item(array, (size_t)which));
+}
+
+CJSON_PUBLIC(void) cJSON_DeleteItemFromArray(cJSON* array, int which)
+{
+    cJSON_Delete(cJSON_DetachItemFromArray(array, which));
+}
+
+CJSON_PUBLIC(cJSON*) cJSON_DetachItemFromObject(cJSON* object, const char* string)
+{
+    cJSON* to_detach = cJSON_GetObjectItem(object, string);
+
+    return cJSON_DetachItemViaPointer(object, to_detach);
+}
+
+CJSON_PUBLIC(cJSON*) cJSON_DetachItemFromObjectCaseSensitive(cJSON* object, const char* string)
+{
+    cJSON* to_detach = cJSON_GetObjectItemCaseSensitive(object, string);
+
+    return cJSON_DetachItemViaPointer(object, to_detach);
+}
+
+CJSON_PUBLIC(void) cJSON_DeleteItemFromObject(cJSON* object, const char* string)
+{
+    cJSON_Delete(cJSON_DetachItemFromObject(object, string));
+}
+
+CJSON_PUBLIC(void) cJSON_DeleteItemFromObjectCaseSensitive(cJSON* object, const char* string)
+{
+    cJSON_Delete(cJSON_DetachItemFromObjectCaseSensitive(object, string));
+}
+
+/* Replace array/object items with new ones. */
+CJSON_PUBLIC(cJSON_bool) cJSON_InsertItemInArray(cJSON* array, int which, cJSON* newitem)
+{
+    cJSON* after_inserted = NULL;
+
+    if (which < 0 || newitem == NULL)
+    {
+        return false;
+    }
+
+    after_inserted = get_array_item(array, (size_t)which);
+    if (after_inserted == NULL)
+    {
+        return add_item_to_array(array, newitem);
+    }
+
+    if (after_inserted != array->child && after_inserted->prev == NULL) {
+        /* return false if after_inserted is a corrupted array item */
+        return false;
+    }
+
+    newitem->next = after_inserted;
+    newitem->prev = after_inserted->prev;
+    after_inserted->prev = newitem;
+    if (after_inserted == array->child)
+    {
+        array->child = newitem;
+    }
+    else
+    {
+        newitem->prev->next = newitem;
+    }
+    return true;
+}
+
+CJSON_PUBLIC(cJSON_bool) cJSON_ReplaceItemViaPointer(cJSON* const parent, cJSON* const item, cJSON* replacement)
+{
+    if ((parent == NULL) || (parent->child == NULL) || (replacement == NULL) || (item == NULL))
+    {
+        return false;
+    }
+
+    if (replacement == item)
+    {
+        return true;
+    }
+
+    replacement->next = item->next;
+    replacement->prev = item->prev;
+
+    if (replacement->next != NULL)
+    {
+        replacement->next->prev = replacement;
+    }
+    if (parent->child == item)
+    {
+        if (parent->child->prev == parent->child)
+        {
+            replacement->prev = replacement;
+        }
+        parent->child = replacement;
+    }
+    else
+    {   /*
+         * To find the last item in array quickly, we use prev in array.
+         * We can't modify the last item's next pointer where this item was the parent's child
+         */
+        if (replacement->prev != NULL)
+        {
+            replacement->prev->next = replacement;
+        }
+        if (replacement->next == NULL)
+        {
+            parent->child->prev = replacement;
+        }
+    }
+
+    item->next = NULL;
+    item->prev = NULL;
+    cJSON_Delete(item);
+
+    return true;
+}
+
+CJSON_PUBLIC(cJSON_bool) cJSON_ReplaceItemInArray(cJSON* array, int which, cJSON* newitem)
+{
+    if (which < 0)
+    {
+        return false;
+    }
+
+    return cJSON_ReplaceItemViaPointer(array, get_array_item(array, (size_t)which), newitem);
+}
+
+static cJSON_bool replace_item_in_object(cJSON* object, const char* string, cJSON* replacement, cJSON_bool case_sensitive)
+{
+    if ((replacement == NULL) || (string == NULL))
+    {
+        return false;
+    }
+
+    /* replace the name in the replacement */
+    if (!(replacement->type & cJSON_StringIsConst) && (replacement->string != NULL))
+    {
+        cJSON_free(replacement->string);
+    }
+    replacement->string = (char*)cJSON_strdup((const unsigned char*)string, &global_hooks);
+    if (replacement->string == NULL)
+    {
+        return false;
+    }
+
+    replacement->type &= ~cJSON_StringIsConst;
+
+    return cJSON_ReplaceItemViaPointer(object, get_object_item(object, string, case_sensitive), replacement);
+}
+
+CJSON_PUBLIC(cJSON_bool) cJSON_ReplaceItemInObject(cJSON* object, const char* string, cJSON* newitem)
+{
+    return replace_item_in_object(object, string, newitem, false);
+}
+
+CJSON_PUBLIC(cJSON_bool) cJSON_ReplaceItemInObjectCaseSensitive(cJSON* object, const char* string, cJSON* newitem)
+{
+    return replace_item_in_object(object, string, newitem, true);
+}
+
+/* Create basic types: */
+CJSON_PUBLIC(cJSON*) cJSON_CreateNull(void)
+{
+    cJSON* item = cJSON_New_Item(&global_hooks);
+    if (item)
+    {
+        item->type = cJSON_NULL;
+    }
+
+    return item;
+}
+
+CJSON_PUBLIC(cJSON*) cJSON_CreateTrue(void)
+{
+    cJSON* item = cJSON_New_Item(&global_hooks);
+    if (item)
+    {
+        item->type = cJSON_True;
+    }
+
+    return item;
+}
+
+CJSON_PUBLIC(cJSON*) cJSON_CreateFalse(void)
+{
+    cJSON* item = cJSON_New_Item(&global_hooks);
+    if (item)
+    {
+        item->type = cJSON_False;
+    }
+
+    return item;
+}
+
+CJSON_PUBLIC(cJSON*) cJSON_CreateBool(cJSON_bool boolean)
+{
+    cJSON* item = cJSON_New_Item(&global_hooks);
+    if (item)
+    {
+        item->type = boolean ? cJSON_True : cJSON_False;
+    }
+
+    return item;
+}
+
+CJSON_PUBLIC(cJSON*) cJSON_CreateNumber(double num)
+{
+    cJSON* item = cJSON_New_Item(&global_hooks);
+    if (item)
+    {
+        item->type = cJSON_Number;
+        item->valuedouble = num;
+
+        /* use saturation in case of overflow */
+        if (num >= INT_MAX)
+        {
+            item->valueint = INT_MAX;
+        }
+        else if (num <= (double)INT_MIN)
+        {
+            item->valueint = INT_MIN;
+        }
+        else
+        {
+            item->valueint = (int)num;
+        }
+    }
+
+    return item;
+}
+
+CJSON_PUBLIC(cJSON*) cJSON_CreateString(const char* string)
+{
+    cJSON* item = cJSON_New_Item(&global_hooks);
+    if (item)
+    {
+        item->type = cJSON_String;
+        item->valuestring = (char*)cJSON_strdup((const unsigned char*)string, &global_hooks);
+        if (!item->valuestring)
+        {
+            cJSON_Delete(item);
+            return NULL;
+        }
+    }
+
+    return item;
+}
+
+CJSON_PUBLIC(cJSON*) cJSON_CreateStringReference(const char* string)
+{
+    cJSON* item = cJSON_New_Item(&global_hooks);
+    if (item != NULL)
+    {
+        item->type = cJSON_String | cJSON_IsReference;
+        item->valuestring = (char*)cast_away_const(string);
+    }
+
+    return item;
+}
+
+CJSON_PUBLIC(cJSON*) cJSON_CreateObjectReference(const cJSON* child)
+{
+    cJSON* item = cJSON_New_Item(&global_hooks);
+    if (item != NULL) {
+        item->type = cJSON_Object | cJSON_IsReference;
+        item->child = (cJSON*)cast_away_const(child);
+    }
+
+    return item;
+}
+
+CJSON_PUBLIC(cJSON*) cJSON_CreateArrayReference(const cJSON* child) {
+    cJSON* item = cJSON_New_Item(&global_hooks);
+    if (item != NULL) {
+        item->type = cJSON_Array | cJSON_IsReference;
+        item->child = (cJSON*)cast_away_const(child);
+    }
+
+    return item;
+}
+
+CJSON_PUBLIC(cJSON*) cJSON_CreateRaw(const char* raw)
+{
+    cJSON* item = cJSON_New_Item(&global_hooks);
+    if (item)
+    {
+        item->type = cJSON_Raw;
+        item->valuestring = (char*)cJSON_strdup((const unsigned char*)raw, &global_hooks);
+        if (!item->valuestring)
+        {
+            cJSON_Delete(item);
+            return NULL;
+        }
+    }
+
+    return item;
+}
+
+CJSON_PUBLIC(cJSON*) cJSON_CreateArray(void)
+{
+    cJSON* item = cJSON_New_Item(&global_hooks);
+    if (item)
+    {
+        item->type = cJSON_Array;
+    }
+
+    return item;
+}
+
+CJSON_PUBLIC(cJSON*) cJSON_CreateObject(void)
+{
+    cJSON* item = cJSON_New_Item(&global_hooks);
+    if (item)
+    {
+        item->type = cJSON_Object;
+    }
+
+    return item;
+}
+
+/* Create Arrays: */
+CJSON_PUBLIC(cJSON*) cJSON_CreateIntArray(const int* numbers, int count)
+{
+    size_t i = 0;
+    cJSON* n = NULL;
+    cJSON* p = NULL;
+    cJSON* a = NULL;
+
+    if ((count < 0) || (numbers == NULL))
+    {
+        return NULL;
+    }
+
+    a = cJSON_CreateArray();
+
+    for (i = 0; a && (i < (size_t)count); i++)
+    {
+        n = cJSON_CreateNumber(numbers[i]);
+        if (!n)
+        {
+            cJSON_Delete(a);
+            return NULL;
+        }
+        if (!i)
+        {
+            a->child = n;
+        }
+        else
+        {
+            suffix_object(p, n);
+        }
+        p = n;
+    }
+
+    if (a && a->child) {
+        a->child->prev = n;
+    }
+
+    return a;
+}
+
+CJSON_PUBLIC(cJSON*) cJSON_CreateFloatArray(const float* numbers, int count)
+{
+    size_t i = 0;
+    cJSON* n = NULL;
+    cJSON* p = NULL;
+    cJSON* a = NULL;
+
+    if ((count < 0) || (numbers == NULL))
+    {
+        return NULL;
+    }
+
+    a = cJSON_CreateArray();
+
+    for (i = 0; a && (i < (size_t)count); i++)
+    {
+        n = cJSON_CreateNumber((double)numbers[i]);
+        if (!n)
+        {
+            cJSON_Delete(a);
+            return NULL;
+        }
+        if (!i)
+        {
+            a->child = n;
+        }
+        else
+        {
+            suffix_object(p, n);
+        }
+        p = n;
+    }
+
+    if (a && a->child) {
+        a->child->prev = n;
+    }
+
+    return a;
+}
+
+CJSON_PUBLIC(cJSON*) cJSON_CreateDoubleArray(const double* numbers, int count)
+{
+    size_t i = 0;
+    cJSON* n = NULL;
+    cJSON* p = NULL;
+    cJSON* a = NULL;
+
+    if ((count < 0) || (numbers == NULL))
+    {
+        return NULL;
+    }
+
+    a = cJSON_CreateArray();
+
+    for (i = 0; a && (i < (size_t)count); i++)
+    {
+        n = cJSON_CreateNumber(numbers[i]);
+        if (!n)
+        {
+            cJSON_Delete(a);
+            return NULL;
+        }
+        if (!i)
+        {
+            a->child = n;
+        }
+        else
+        {
+            suffix_object(p, n);
+        }
+        p = n;
+    }
+
+    if (a && a->child) {
+        a->child->prev = n;
+    }
+
+    return a;
+}
+
+CJSON_PUBLIC(cJSON*) cJSON_CreateStringArray(const char* const* strings, int count)
+{
+    size_t i = 0;
+    cJSON* n = NULL;
+    cJSON* p = NULL;
+    cJSON* a = NULL;
+
+    if ((count < 0) || (strings == NULL))
+    {
+        return NULL;
+    }
+
+    a = cJSON_CreateArray();
+
+    for (i = 0; a && (i < (size_t)count); i++)
+    {
+        n = cJSON_CreateString(strings[i]);
+        if (!n)
+        {
+            cJSON_Delete(a);
+            return NULL;
+        }
+        if (!i)
+        {
+            a->child = n;
+        }
+        else
+        {
+            suffix_object(p, n);
+        }
+        p = n;
+    }
+
+    if (a && a->child) {
+        a->child->prev = n;
+    }
+
+    return a;
+}
+
+/* Duplication */
+CJSON_PUBLIC(cJSON*) cJSON_Duplicate(const cJSON* item, cJSON_bool recurse)
+{
+    cJSON* newitem = NULL;
+    cJSON* child = NULL;
+    cJSON* next = NULL;
+    cJSON* newchild = NULL;
+
+    /* Bail on bad ptr */
+    if (!item)
+    {
+        goto fail;
+    }
+    /* Create new item */
+    newitem = cJSON_New_Item(&global_hooks);
+    if (!newitem)
+    {
+        goto fail;
+    }
+    /* Copy over all vars */
+    newitem->type = item->type & (~cJSON_IsReference);
+    newitem->valueint = item->valueint;
+    newitem->valuedouble = item->valuedouble;
+    if (item->valuestring)
+    {
+        newitem->valuestring = (char*)cJSON_strdup((unsigned char*)item->valuestring, &global_hooks);
+        if (!newitem->valuestring)
+        {
+            goto fail;
+        }
+    }
+    if (item->string)
+    {
+        newitem->string = (item->type & cJSON_StringIsConst) ? item->string : (char*)cJSON_strdup((unsigned char*)item->string, &global_hooks);
+        if (!newitem->string)
+        {
+            goto fail;
+        }
+    }
+    /* If non-recursive, then we're done! */
+    if (!recurse)
+    {
+        return newitem;
+    }
+    /* Walk the ->next chain for the child. */
+    child = item->child;
+    while (child != NULL)
+    {
+        newchild = cJSON_Duplicate(child, true); /* Duplicate (with recurse) each item in the ->next chain */
+        if (!newchild)
+        {
+            goto fail;
+        }
+        if (next != NULL)
+        {
+            /* If newitem->child already set, then crosswire ->prev and ->next and move on */
+            next->next = newchild;
+            newchild->prev = next;
+            next = newchild;
+        }
+        else
+        {
+            /* Set newitem->child and move to it */
+            newitem->child = newchild;
+            next = newchild;
+        }
+        child = child->next;
+    }
+    if (newitem && newitem->child)
+    {
+        newitem->child->prev = newchild;
+    }
+
+    return newitem;
+
+fail:
+    if (newitem != NULL)
+    {
+        cJSON_Delete(newitem);
+    }
+
+    return NULL;
+}
+
+static void skip_oneline_comment(char** input)
+{
+    *input += static_strlen("//");
+
+    for (; (*input)[0] != '\0'; ++(*input))
+    {
+        if ((*input)[0] == '\n') {
+            *input += static_strlen("\n");
+            return;
+        }
+    }
+}
+
+static void skip_multiline_comment(char** input)
+{
+    *input += static_strlen("/*");
+
+    for (; (*input)[0] != '\0'; ++(*input))
+    {
+        if (((*input)[0] == '*') && ((*input)[1] == '/'))
+        {
+            *input += static_strlen("*/");
+            return;
+        }
+    }
+}
+
+static void minify_string(char** input, char** output) {
+    (*output)[0] = (*input)[0];
+    *input += static_strlen("\"");
+    *output += static_strlen("\"");
+
+
+    for (; (*input)[0] != '\0'; (void)++(*input), ++(*output)) {
+        (*output)[0] = (*input)[0];
+
+        if ((*input)[0] == '\"') {
+            (*output)[0] = '\"';
+            *input += static_strlen("\"");
+            *output += static_strlen("\"");
+            return;
+        }
+        else if (((*input)[0] == '\\') && ((*input)[1] == '\"')) {
+            (*output)[1] = (*input)[1];
+            *input += static_strlen("\"");
+            *output += static_strlen("\"");
+        }
+    }
+}
+
+CJSON_PUBLIC(void) cJSON_Minify(char* json)
+{
+    char* into = json;
+
+    if (json == NULL)
+    {
+        return;
+    }
+
+    while (json[0] != '\0')
+    {
+        switch (json[0])
+        {
+        case ' ':
+        case '\t':
+        case '\r':
+        case '\n':
+            json++;
+            break;
+
+        case '/':
+            if (json[1] == '/')
+            {
+                skip_oneline_comment(&json);
+            }
+            else if (json[1] == '*')
+            {
+                skip_multiline_comment(&json);
+            }
+            else {
+                json++;
+            }
+            break;
+
+        case '\"':
+            minify_string(&json, (char**)&into);
+            break;
+
+        default:
+            into[0] = json[0];
+            json++;
+            into++;
+        }
+    }
+
+    /* and null-terminate. */
+    *into = '\0';
+}
+
+CJSON_PUBLIC(cJSON_bool) cJSON_IsInvalid(const cJSON* const item)
+{
+    if (item == NULL)
+    {
+        return false;
+    }
+
+    return (item->type & 0xFF) == cJSON_Invalid;
+}
+
+CJSON_PUBLIC(cJSON_bool) cJSON_IsFalse(const cJSON* const item)
+{
+    if (item == NULL)
+    {
+        return false;
+    }
+
+    return (item->type & 0xFF) == cJSON_False;
+}
+
+CJSON_PUBLIC(cJSON_bool) cJSON_IsTrue(const cJSON* const item)
+{
+    if (item == NULL)
+    {
+        return false;
+    }
+
+    return (item->type & 0xff) == cJSON_True;
+}
+
+
+CJSON_PUBLIC(cJSON_bool) cJSON_IsBool(const cJSON* const item)
+{
+    if (item == NULL)
+    {
+        return false;
+    }
+
+    return (item->type & (cJSON_True | cJSON_False)) != 0;
+}
+CJSON_PUBLIC(cJSON_bool) cJSON_IsNull(const cJSON* const item)
+{
+    if (item == NULL)
+    {
+        return false;
+    }
+
+    return (item->type & 0xFF) == cJSON_NULL;
+}
+
+CJSON_PUBLIC(cJSON_bool) cJSON_IsNumber(const cJSON* const item)
+{
+    if (item == NULL)
+    {
+        return false;
+    }
+
+    return (item->type & 0xFF) == cJSON_Number;
+}
+
+CJSON_PUBLIC(cJSON_bool) cJSON_IsString(const cJSON* const item)
+{
+    if (item == NULL)
+    {
+        return false;
+    }
+
+    return (item->type & 0xFF) == cJSON_String;
+}
+
+CJSON_PUBLIC(cJSON_bool) cJSON_IsArray(const cJSON* const item)
+{
+    if (item == NULL)
+    {
+        return false;
+    }
+
+    return (item->type & 0xFF) == cJSON_Array;
+}
+
+CJSON_PUBLIC(cJSON_bool) cJSON_IsObject(const cJSON* const item)
+{
+    if (item == NULL)
+    {
+        return false;
+    }
+
+    return (item->type & 0xFF) == cJSON_Object;
+}
+
+CJSON_PUBLIC(cJSON_bool) cJSON_IsRaw(const cJSON* const item)
+{
+    if (item == NULL)
+    {
+        return false;
+    }
+
+    return (item->type & 0xFF) == cJSON_Raw;
+}
+
+CJSON_PUBLIC(cJSON_bool) cJSON_Compare(const cJSON* const a, const cJSON* const b, const cJSON_bool case_sensitive)
+{
+    if ((a == NULL) || (b == NULL) || ((a->type & 0xFF) != (b->type & 0xFF)))
+    {
+        return false;
+    }
+
+    /* check if type is valid */
+    switch (a->type & 0xFF)
+    {
+    case cJSON_False:
+    case cJSON_True:
+    case cJSON_NULL:
+    case cJSON_Number:
+    case cJSON_String:
+    case cJSON_Raw:
+    case cJSON_Array:
+    case cJSON_Object:
+        break;
+
+    default:
+        return false;
+    }
+
+    /* identical objects are equal */
+    if (a == b)
+    {
+        return true;
+    }
+
+    switch (a->type & 0xFF)
+    {
+        /* in these cases and equal type is enough */
+    case cJSON_False:
+    case cJSON_True:
+    case cJSON_NULL:
+        return true;
+
+    case cJSON_Number:
+        if (compare_double(a->valuedouble, b->valuedouble))
+        {
+            return true;
+        }
+        return false;
+
+    case cJSON_String:
+    case cJSON_Raw:
+        if ((a->valuestring == NULL) || (b->valuestring == NULL))
+        {
+            return false;
+        }
+        if (strcmp(a->valuestring, b->valuestring) == 0)
+        {
+            return true;
+        }
+
+        return false;
+
+    case cJSON_Array:
+    {
+        cJSON* a_element = a->child;
+        cJSON* b_element = b->child;
+
+        for (; (a_element != NULL) && (b_element != NULL);)
+        {
+            if (!cJSON_Compare(a_element, b_element, case_sensitive))
+            {
+                return false;
+            }
+
+            a_element = a_element->next;
+            b_element = b_element->next;
+        }
+
+        /* one of the arrays is longer than the other */
+        if (a_element != b_element) {
+            return false;
+        }
+
+        return true;
+    }
+
+    case cJSON_Object:
+    {
+        cJSON* a_element = NULL;
+        cJSON* b_element = NULL;
+        cJSON_ArrayForEach(a_element, a)
+        {
+            /* TODO This has O(n^2) runtime, which is horrible! */
+            b_element = get_object_item(b, a_element->string, case_sensitive);
+            if (b_element == NULL)
+            {
+                return false;
+            }
+
+            if (!cJSON_Compare(a_element, b_element, case_sensitive))
+            {
+                return false;
+            }
+        }
+
+        /* doing this twice, once on a and b to prevent true comparison if a subset of b
+         * TODO: Do this the proper way, this is just a fix for now */
+        cJSON_ArrayForEach(b_element, b)
+        {
+            a_element = get_object_item(a, b_element->string, case_sensitive);
+            if (a_element == NULL)
+            {
+                return false;
+            }
+
+            if (!cJSON_Compare(b_element, a_element, case_sensitive))
+            {
+                return false;
+            }
+        }
+
+        return true;
+    }
+
+    default:
+        return false;
+    }
+}
+
+CJSON_PUBLIC(void*) cJSON_malloc(size_t size)
+{
+    return global_hooks.allocate(size);
+}
+
+CJSON_PUBLIC(void) cJSON_free(void* object)
+{
+    global_hooks.deallocate(object);
+    object = NULL;
+}

Added: redwax-signtext-windows/trunk/Redwax SignText/Redwax SignText (MFC)/cJSON.h
==============================================================================
--- redwax-signtext-windows/trunk/Redwax SignText/Redwax SignText (MFC)/cJSON.h	(added)
+++ redwax-signtext-windows/trunk/Redwax SignText/Redwax SignText (MFC)/cJSON.h	Sun Jun 23 16:39:06 2024
@@ -0,0 +1,300 @@
+/*
+  Copyright (c) 2009-2017 Dave Gamble and cJSON contributors
+
+  Permission is hereby granted, free of charge, to any person obtaining a copy
+  of this software and associated documentation files (the "Software"), to deal
+  in 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:
+
+  The above copyright notice and this permission notice shall be included in
+  all copies or substantial portions of the Software.
+
+  THE 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
+  AUTHORS 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 IN
+  THE SOFTWARE.
+*/
+
+#ifndef cJSON__h
+#define cJSON__h
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+#if !defined(__WINDOWS__) && (defined(WIN32) || defined(WIN64) || defined(_MSC_VER) || defined(_WIN32))
+#define __WINDOWS__
+#endif
+
+#ifdef __WINDOWS__
+
+    /* When compiling for windows, we specify a specific calling convention to avoid issues where we are being called from a project with a different default calling convention.  For windows you have 3 define options:
+
+    CJSON_HIDE_SYMBOLS - Define this in the case where you don't want to ever dllexport symbols
+    CJSON_EXPORT_SYMBOLS - Define this on library build when you want to dllexport symbols (default)
+    CJSON_IMPORT_SYMBOLS - Define this if you want to dllimport symbol
+
+    For *nix builds that support visibility attribute, you can define similar behavior by
+
+    setting default visibility to hidden by adding
+    -fvisibility=hidden (for gcc)
+    or
+    -xldscope=hidden (for sun cc)
+    to CFLAGS
+
+    then using the CJSON_API_VISIBILITY flag to "export" the same symbols the way CJSON_EXPORT_SYMBOLS does
+
+    */
+
+#define CJSON_CDECL __cdecl
+#define CJSON_STDCALL __stdcall
+
+    /* export symbols by default, this is necessary for copy pasting the C and header file */
+#if !defined(CJSON_HIDE_SYMBOLS) && !defined(CJSON_IMPORT_SYMBOLS) && !defined(CJSON_EXPORT_SYMBOLS)
+#define CJSON_EXPORT_SYMBOLS
+#endif
+
+#if defined(CJSON_HIDE_SYMBOLS)
+#define CJSON_PUBLIC(type)   type CJSON_STDCALL
+#elif defined(CJSON_EXPORT_SYMBOLS)
+#define CJSON_PUBLIC(type)   __declspec(dllexport) type CJSON_STDCALL
+#elif defined(CJSON_IMPORT_SYMBOLS)
+#define CJSON_PUBLIC(type)   __declspec(dllimport) type CJSON_STDCALL
+#endif
+#else /* !__WINDOWS__ */
+#define CJSON_CDECL
+#define CJSON_STDCALL
+
+#if (defined(__GNUC__) || defined(__SUNPRO_CC) || defined (__SUNPRO_C)) && defined(CJSON_API_VISIBILITY)
+#define CJSON_PUBLIC(type)   __attribute__((visibility("default"))) type
+#else
+#define CJSON_PUBLIC(type) type
+#endif
+#endif
+
+    /* project version */
+#define CJSON_VERSION_MAJOR 1
+#define CJSON_VERSION_MINOR 7
+#define CJSON_VERSION_PATCH 18
+
+#include <stddef.h>
+
+/* cJSON Types: */
+#define cJSON_Invalid (0)
+#define cJSON_False  (1 << 0)
+#define cJSON_True   (1 << 1)
+#define cJSON_NULL   (1 << 2)
+#define cJSON_Number (1 << 3)
+#define cJSON_String (1 << 4)
+#define cJSON_Array  (1 << 5)
+#define cJSON_Object (1 << 6)
+#define cJSON_Raw    (1 << 7) /* raw json */
+
+#define cJSON_IsReference 256
+#define cJSON_StringIsConst 512
+
+/* The cJSON structure: */
+    typedef struct cJSON
+    {
+        /* next/prev allow you to walk array/object chains. Alternatively, use GetArraySize/GetArrayItem/GetObjectItem */
+        struct cJSON* next;
+        struct cJSON* prev;
+        /* An array or object item will have a child pointer pointing to a chain of the items in the array/object. */
+        struct cJSON* child;
+
+        /* The type of the item, as above. */
+        int type;
+
+        /* The item's string, if type==cJSON_String  and type == cJSON_Raw */
+        char* valuestring;
+        /* writing to valueint is DEPRECATED, use cJSON_SetNumberValue instead */
+        int valueint;
+        /* The item's number, if type==cJSON_Number */
+        double valuedouble;
+
+        /* The item's name string, if this item is the child of, or is in the list of subitems of an object. */
+        char* string;
+    } cJSON;
+
+    typedef struct cJSON_Hooks
+    {
+        /* malloc/free are CDECL on Windows regardless of the default calling convention of the compiler, so ensure the hooks allow passing those functions directly. */
+        void* (CJSON_CDECL* malloc_fn)(size_t sz);
+        void (CJSON_CDECL* free_fn)(void* ptr);
+    } cJSON_Hooks;
+
+    typedef int cJSON_bool;
+
+    /* Limits how deeply nested arrays/objects can be before cJSON rejects to parse them.
+     * This is to prevent stack overflows. */
+#ifndef CJSON_NESTING_LIMIT
+#define CJSON_NESTING_LIMIT 1000
+#endif
+
+     /* returns the version of cJSON as a string */
+    CJSON_PUBLIC(const char*) cJSON_Version(void);
+
+    /* Supply malloc, realloc and free functions to cJSON */
+    CJSON_PUBLIC(void) cJSON_InitHooks(cJSON_Hooks* hooks);
+
+    /* Memory Management: the caller is always responsible to free the results from all variants of cJSON_Parse (with cJSON_Delete) and cJSON_Print (with stdlib free, cJSON_Hooks.free_fn, or cJSON_free as appropriate). The exception is cJSON_PrintPreallocated, where the caller has full responsibility of the buffer. */
+    /* Supply a block of JSON, and this returns a cJSON object you can interrogate. */
+    CJSON_PUBLIC(cJSON*) cJSON_Parse(const char* value);
+    CJSON_PUBLIC(cJSON*) cJSON_ParseWithLength(const char* value, size_t buffer_length);
+    /* ParseWithOpts allows you to require (and check) that the JSON is null terminated, and to retrieve the pointer to the final byte parsed. */
+    /* If you supply a ptr in return_parse_end and parsing fails, then return_parse_end will contain a pointer to the error so will match cJSON_GetErrorPtr(). */
+    CJSON_PUBLIC(cJSON*) cJSON_ParseWithOpts(const char* value, const char** return_parse_end, cJSON_bool require_null_terminated);
+    CJSON_PUBLIC(cJSON*) cJSON_ParseWithLengthOpts(const char* value, size_t buffer_length, const char** return_parse_end, cJSON_bool require_null_terminated);
+
+    /* Render a cJSON entity to text for transfer/storage. */
+    CJSON_PUBLIC(char*) cJSON_Print(const cJSON* item);
+    /* Render a cJSON entity to text for transfer/storage without any formatting. */
+    CJSON_PUBLIC(char*) cJSON_PrintUnformatted(const cJSON* item);
+    /* Render a cJSON entity to text using a buffered strategy. prebuffer is a guess at the final size. guessing well reduces reallocation. fmt=0 gives unformatted, =1 gives formatted */
+    CJSON_PUBLIC(char*) cJSON_PrintBuffered(const cJSON* item, int prebuffer, cJSON_bool fmt);
+    /* Render a cJSON entity to text using a buffer already allocated in memory with given length. Returns 1 on success and 0 on failure. */
+    /* NOTE: cJSON is not always 100% accurate in estimating how much memory it will use, so to be safe allocate 5 bytes more than you actually need */
+    CJSON_PUBLIC(cJSON_bool) cJSON_PrintPreallocated(cJSON* item, char* buffer, const int length, const cJSON_bool format);
+    /* Delete a cJSON entity and all subentities. */
+    CJSON_PUBLIC(void) cJSON_Delete(cJSON* item);
+
+    /* Returns the number of items in an array (or object). */
+    CJSON_PUBLIC(int) cJSON_GetArraySize(const cJSON* array);
+    /* Retrieve item number "index" from array "array". Returns NULL if unsuccessful. */
+    CJSON_PUBLIC(cJSON*) cJSON_GetArrayItem(const cJSON* array, int index);
+    /* Get item "string" from object. Case insensitive. */
+    CJSON_PUBLIC(cJSON*) cJSON_GetObjectItem(const cJSON* const object, const char* const string);
+    CJSON_PUBLIC(cJSON*) cJSON_GetObjectItemCaseSensitive(const cJSON* const object, const char* const string);
+    CJSON_PUBLIC(cJSON_bool) cJSON_HasObjectItem(const cJSON* object, const char* string);
+    /* For analysing failed parses. This returns a pointer to the parse error. You'll probably need to look a few chars back to make sense of it. Defined when cJSON_Parse() returns 0. 0 when cJSON_Parse() succeeds. */
+    CJSON_PUBLIC(const char*) cJSON_GetErrorPtr(void);
+
+    /* Check item type and return its value */
+    CJSON_PUBLIC(char*) cJSON_GetStringValue(const cJSON* const item);
+    CJSON_PUBLIC(double) cJSON_GetNumberValue(const cJSON* const item);
+
+    /* These functions check the type of an item */
+    CJSON_PUBLIC(cJSON_bool) cJSON_IsInvalid(const cJSON* const item);
+    CJSON_PUBLIC(cJSON_bool) cJSON_IsFalse(const cJSON* const item);
+    CJSON_PUBLIC(cJSON_bool) cJSON_IsTrue(const cJSON* const item);
+    CJSON_PUBLIC(cJSON_bool) cJSON_IsBool(const cJSON* const item);
+    CJSON_PUBLIC(cJSON_bool) cJSON_IsNull(const cJSON* const item);
+    CJSON_PUBLIC(cJSON_bool) cJSON_IsNumber(const cJSON* const item);
+    CJSON_PUBLIC(cJSON_bool) cJSON_IsString(const cJSON* const item);
+    CJSON_PUBLIC(cJSON_bool) cJSON_IsArray(const cJSON* const item);
+    CJSON_PUBLIC(cJSON_bool) cJSON_IsObject(const cJSON* const item);
+    CJSON_PUBLIC(cJSON_bool) cJSON_IsRaw(const cJSON* const item);
+
+    /* These calls create a cJSON item of the appropriate type. */
+    CJSON_PUBLIC(cJSON*) cJSON_CreateNull(void);
+    CJSON_PUBLIC(cJSON*) cJSON_CreateTrue(void);
+    CJSON_PUBLIC(cJSON*) cJSON_CreateFalse(void);
+    CJSON_PUBLIC(cJSON*) cJSON_CreateBool(cJSON_bool boolean);
+    CJSON_PUBLIC(cJSON*) cJSON_CreateNumber(double num);
+    CJSON_PUBLIC(cJSON*) cJSON_CreateString(const char* string);
+    /* raw json */
+    CJSON_PUBLIC(cJSON*) cJSON_CreateRaw(const char* raw);
+    CJSON_PUBLIC(cJSON*) cJSON_CreateArray(void);
+    CJSON_PUBLIC(cJSON*) cJSON_CreateObject(void);
+
+    /* Create a string where valuestring references a string so
+     * it will not be freed by cJSON_Delete */
+    CJSON_PUBLIC(cJSON*) cJSON_CreateStringReference(const char* string);
+    /* Create an object/array that only references it's elements so
+     * they will not be freed by cJSON_Delete */
+    CJSON_PUBLIC(cJSON*) cJSON_CreateObjectReference(const cJSON* child);
+    CJSON_PUBLIC(cJSON*) cJSON_CreateArrayReference(const cJSON* child);
+
+    /* These utilities create an Array of count items.
+     * The parameter count cannot be greater than the number of elements in the number array, otherwise array access will be out of bounds.*/
+    CJSON_PUBLIC(cJSON*) cJSON_CreateIntArray(const int* numbers, int count);
+    CJSON_PUBLIC(cJSON*) cJSON_CreateFloatArray(const float* numbers, int count);
+    CJSON_PUBLIC(cJSON*) cJSON_CreateDoubleArray(const double* numbers, int count);
+    CJSON_PUBLIC(cJSON*) cJSON_CreateStringArray(const char* const* strings, int count);
+
+    /* Append item to the specified array/object. */
+    CJSON_PUBLIC(cJSON_bool) cJSON_AddItemToArray(cJSON* array, cJSON* item);
+    CJSON_PUBLIC(cJSON_bool) cJSON_AddItemToObject(cJSON* object, const char* string, cJSON* item);
+    /* Use this when string is definitely const (i.e. a literal, or as good as), and will definitely survive the cJSON object.
+     * WARNING: When this function was used, make sure to always check that (item->type & cJSON_StringIsConst) is zero before
+     * writing to `item->string` */
+    CJSON_PUBLIC(cJSON_bool) cJSON_AddItemToObjectCS(cJSON* object, const char* string, cJSON* item);
+    /* Append reference to item to the specified array/object. Use this when you want to add an existing cJSON to a new cJSON, but don't want to corrupt your existing cJSON. */
+    CJSON_PUBLIC(cJSON_bool) cJSON_AddItemReferenceToArray(cJSON* array, cJSON* item);
+    CJSON_PUBLIC(cJSON_bool) cJSON_AddItemReferenceToObject(cJSON* object, const char* string, cJSON* item);
+
+    /* Remove/Detach items from Arrays/Objects. */
+    CJSON_PUBLIC(cJSON*) cJSON_DetachItemViaPointer(cJSON* parent, cJSON* const item);
+    CJSON_PUBLIC(cJSON*) cJSON_DetachItemFromArray(cJSON* array, int which);
+    CJSON_PUBLIC(void) cJSON_DeleteItemFromArray(cJSON* array, int which);
+    CJSON_PUBLIC(cJSON*) cJSON_DetachItemFromObject(cJSON* object, const char* string);
+    CJSON_PUBLIC(cJSON*) cJSON_DetachItemFromObjectCaseSensitive(cJSON* object, const char* string);
+    CJSON_PUBLIC(void) cJSON_DeleteItemFromObject(cJSON* object, const char* string);
+    CJSON_PUBLIC(void) cJSON_DeleteItemFromObjectCaseSensitive(cJSON* object, const char* string);
+
+    /* Update array items. */
+    CJSON_PUBLIC(cJSON_bool) cJSON_InsertItemInArray(cJSON* array, int which, cJSON* newitem); /* Shifts pre-existing items to the right. */
+    CJSON_PUBLIC(cJSON_bool) cJSON_ReplaceItemViaPointer(cJSON* const parent, cJSON* const item, cJSON* replacement);
+    CJSON_PUBLIC(cJSON_bool) cJSON_ReplaceItemInArray(cJSON* array, int which, cJSON* newitem);
+    CJSON_PUBLIC(cJSON_bool) cJSON_ReplaceItemInObject(cJSON* object, const char* string, cJSON* newitem);
+    CJSON_PUBLIC(cJSON_bool) cJSON_ReplaceItemInObjectCaseSensitive(cJSON* object, const char* string, cJSON* newitem);
+
+    /* Duplicate a cJSON item */
+    CJSON_PUBLIC(cJSON*) cJSON_Duplicate(const cJSON* item, cJSON_bool recurse);
+    /* Duplicate will create a new, identical cJSON item to the one you pass, in new memory that will
+     * need to be released. With recurse!=0, it will duplicate any children connected to the item.
+     * The item->next and ->prev pointers are always zero on return from Duplicate. */
+     /* Recursively compare two cJSON items for equality. If either a or b is NULL or invalid, they will be considered unequal.
+      * case_sensitive determines if object keys are treated case sensitive (1) or case insensitive (0) */
+    CJSON_PUBLIC(cJSON_bool) cJSON_Compare(const cJSON* const a, const cJSON* const b, const cJSON_bool case_sensitive);
+
+    /* Minify a strings, remove blank characters(such as ' ', '\t', '\r', '\n') from strings.
+     * The input pointer json cannot point to a read-only address area, such as a string constant,
+     * but should point to a readable and writable address area. */
+    CJSON_PUBLIC(void) cJSON_Minify(char* json);
+
+    /* Helper functions for creating and adding items to an object at the same time.
+     * They return the added item or NULL on failure. */
+    CJSON_PUBLIC(cJSON*) cJSON_AddNullToObject(cJSON* const object, const char* const name);
+    CJSON_PUBLIC(cJSON*) cJSON_AddTrueToObject(cJSON* const object, const char* const name);
+    CJSON_PUBLIC(cJSON*) cJSON_AddFalseToObject(cJSON* const object, const char* const name);
+    CJSON_PUBLIC(cJSON*) cJSON_AddBoolToObject(cJSON* const object, const char* const name, const cJSON_bool boolean);
+    CJSON_PUBLIC(cJSON*) cJSON_AddNumberToObject(cJSON* const object, const char* const name, const double number);
+    CJSON_PUBLIC(cJSON*) cJSON_AddStringToObject(cJSON* const object, const char* const name, const char* const string);
+    CJSON_PUBLIC(cJSON*) cJSON_AddRawToObject(cJSON* const object, const char* const name, const char* const raw);
+    CJSON_PUBLIC(cJSON*) cJSON_AddObjectToObject(cJSON* const object, const char* const name);
+    CJSON_PUBLIC(cJSON*) cJSON_AddArrayToObject(cJSON* const object, const char* const name);
+
+    /* When assigning an integer value, it needs to be propagated to valuedouble too. */
+#define cJSON_SetIntValue(object, number) ((object) ? (object)->valueint = (object)->valuedouble = (number) : (number))
+/* helper for the cJSON_SetNumberValue macro */
+    CJSON_PUBLIC(double) cJSON_SetNumberHelper(cJSON* object, double number);
+#define cJSON_SetNumberValue(object, number) ((object != NULL) ? cJSON_SetNumberHelper(object, (double)number) : (number))
+    /* Change the valuestring of a cJSON_String object, only takes effect when type of object is cJSON_String */
+    CJSON_PUBLIC(char*) cJSON_SetValuestring(cJSON* object, const char* valuestring);
+
+    /* If the object is not a boolean type this does nothing and returns cJSON_Invalid else it returns the new type*/
+#define cJSON_SetBoolValue(object, boolValue) ( \
+    (object != NULL && ((object)->type & (cJSON_False|cJSON_True))) ? \
+    (object)->type=((object)->type &(~(cJSON_False|cJSON_True)))|((boolValue)?cJSON_True:cJSON_False) : \
+    cJSON_Invalid\
+)
+
+/* Macro for iterating over an array or object */
+#define cJSON_ArrayForEach(element, array) for(element = (array != NULL) ? (array)->child : NULL; element != NULL; element = element->next)
+
+/* malloc/free objects using the malloc/free functions that have been set with cJSON_InitHooks */
+    CJSON_PUBLIC(void*) cJSON_malloc(size_t size);
+    CJSON_PUBLIC(void) cJSON_free(void* object);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif

Added: redwax-signtext-windows/trunk/Redwax SignText/Redwax SignText (MFC)/crypto.c
==============================================================================
--- redwax-signtext-windows/trunk/Redwax SignText/Redwax SignText (MFC)/crypto.c	(added)
+++ redwax-signtext-windows/trunk/Redwax SignText/Redwax SignText (MFC)/crypto.c	Sun Jun 23 16:39:06 2024
@@ -0,0 +1,376 @@
+/* Licensed to Stichting The Commons Conservancy (TCC) under one or more
+ * contributor license agreements.  See the AUTHORS file distributed with
+ * this work for additional information regarding copyright ownership.
+ * TCC licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+
+
+#include "crypto.h"
+#include "message.h"
+
+#include <stdio.h>
+#include <assert.h>
+#include <wincrypt.h>
+#include <ncrypt.h>
+
+void
+crypto_start(SignTextData* signtext)
+{
+#if 1
+	fprintf(stderr, "crypto_start\n");
+#endif
+
+#if 0
+	volatile int done = 0;
+	while (!done) sleep(1);
+	/* inside gdb: set var done = 1 */
+#endif
+
+    HANDLE hTimer = NULL;
+    LARGE_INTEGER liDueTime;
+
+    liDueTime.QuadPart = -20000000LL;
+
+    // Create an unnamed waitable timer.
+    hTimer = CreateWaitableTimer(NULL, TRUE, NULL);
+    if (NULL == hTimer)
+    {
+        assert(0);
+    }
+
+    // printf("Waiting for 2 seconds...\n");
+
+    while (1) {
+
+		SignTextCertificate* certificate = NULL;
+
+        HCERTSTORE sys = CertOpenStore(CERT_STORE_PROV_SYSTEM,
+            X509_ASN_ENCODING, 0, CERT_SYSTEM_STORE_CURRENT_USER | CERT_STORE_READONLY_FLAG, L"MY");
+        if (!sys) {
+            assert(0);
+        }
+
+		PCCERT_CONTEXT cert = NULL;
+		while ((cert = CertEnumCertificatesInStore(sys, cert)) != NULL) {
+
+			DWORD flags = CRYPT_ACQUIRE_CACHE_FLAG | CRYPT_ACQUIRE_COMPARE_KEY_FLAG | CRYPT_ACQUIRE_SILENT_FLAG | CRYPT_ACQUIRE_PREFER_NCRYPT_KEY_FLAG;
+			HCRYPTPROV_OR_NCRYPT_KEY_HANDLE key = 0;
+			DWORD spec = 0;
+			BOOL freeKey = FALSE;
+
+			CryptAcquireCertificatePrivateKey(cert, flags, NULL, &key, &spec, &freeKey);
+
+			/* ignore anything that doesn't have a key */
+			if (!key) {
+				continue;
+			}
+
+			DWORD size;
+
+			LPWSTR subject;
+
+			size = CertGetNameString(cert, CERT_NAME_FRIENDLY_DISPLAY_TYPE, CERT_NAME_STR_ENABLE_PUNYCODE_FLAG, NULL, NULL, 0);
+
+			subject = malloc(size * sizeof(wchar_t));
+			if (!subject) {
+				assert(0);
+			}
+
+			CertGetNameString(cert, CERT_NAME_FRIENDLY_DISPLAY_TYPE, CERT_NAME_STR_ENABLE_PUNYCODE_FLAG, NULL, subject, size);
+
+			LPWSTR issuer;
+
+			size = CertGetNameString(cert, CERT_NAME_FRIENDLY_DISPLAY_TYPE, CERT_NAME_ISSUER_FLAG | CERT_NAME_STR_ENABLE_PUNYCODE_FLAG, NULL, NULL, 0);
+
+			issuer = malloc(size * sizeof(wchar_t));
+			if (!issuer) {
+				assert(0);
+			}
+
+			CertGetNameString(cert, CERT_NAME_FRIENDLY_DISPLAY_TYPE, CERT_NAME_ISSUER_FLAG | CERT_NAME_STR_ENABLE_PUNYCODE_FLAG, NULL, issuer, size);
+
+			size = swprintf(NULL, 0, L"%s (%s)", subject, issuer);
+
+			LPWSTR name = malloc((size + 1) * sizeof(wchar_t));
+			if (!name) {
+				assert(0);
+			}
+
+			swprintf(name, size + 1, L"%s (%s)", subject, issuer);
+
+			free(subject);
+			free(issuer);
+
+			switch (spec)
+			{
+			case CERT_NCRYPT_KEY_SPEC:
+			{
+				NCRYPT_PROV_HANDLE prov = 0;
+				DWORD type = 0, size = sizeof(prov);
+				NCryptGetProperty(key, NCRYPT_PROVIDER_HANDLE_PROPERTY, (PBYTE) & prov, size, &size, 0);
+				if (prov)
+				{
+					size = sizeof(type);
+					NCryptGetProperty(prov, NCRYPT_IMPL_TYPE_PROPERTY, (PBYTE) & type, size, &size, 0);
+					NCryptFreeObject(prov);
+				}
+
+				// NCRYPT_EXPORT_POLICY_PROPERTY
+				// NCRYPT_KEY_USAGE_PROPERTY
+				// NCRYPT_SCARD_PIN_INFO
+
+				if (freeKey) {
+					NCryptFreeObject(key);
+				}
+
+				certificate = signtext_certificate_new(signtext, name, cert, spec, type, certificate);
+
+				break;
+			}
+			case AT_KEYEXCHANGE:
+			case AT_SIGNATURE:
+			{
+				DWORD type = 0;
+				DWORD size = sizeof(type);
+				CryptGetProvParam(key, PP_IMPTYPE, (PBYTE) & type, &size, 0);
+
+				if (freeKey) {
+					CryptReleaseContext(key, 0);
+				}
+
+				certificate = signtext_certificate_new(signtext, name, cert, spec, type, certificate);
+
+				break;
+			}
+			}
+
+		}
+		CertCloseStore(sys, 0);
+
+		PostMessage(signtext->hwnd, WM_CRYPTO_UPDATED, sizeof(certificate), (LPARAM)certificate);
+
+		/* Set a timer to wait for 2 seconds. */
+		if (!SetWaitableTimer(hTimer, &liDueTime, 0, NULL, NULL, 0))
+		{
+			//        printf("SetWaitableTimer failed (%d)\n", GetLastError());
+			assert(0);
+		}
+
+		/* Wait for the timer. */
+
+		if (WaitForSingleObject(hTimer, INFINITE) != WAIT_OBJECT_0) {
+			assert(0);
+		}
+
+	}
+
+}
+
+int
+crypto_certificate_is_hardware(SignTextCertificate* certificate)
+{
+	switch (certificate->spec)
+	{
+	case CERT_NCRYPT_KEY_SPEC:
+	{
+		return ((certificate->type & (NCRYPT_IMPL_HARDWARE_FLAG)));
+	}
+	case AT_KEYEXCHANGE:
+	case AT_SIGNATURE:
+	{
+		return ((certificate->type & (CRYPT_IMPL_HARDWARE)));
+	}
+	default:
+		assert(0);
+		return 0;
+	}
+}
+
+int
+crypto_certificate_is_removable(SignTextCertificate* certificate)
+{
+	switch (certificate->spec)
+	{
+	case CERT_NCRYPT_KEY_SPEC:
+	{
+		return ((certificate->type & (NCRYPT_IMPL_REMOVABLE_FLAG)));
+	}
+	case AT_KEYEXCHANGE:
+	case AT_SIGNATURE:
+	{
+		return ((certificate->type & (CRYPT_IMPL_REMOVABLE)));
+	}
+	default:
+		assert(0);
+		return 0;
+	}
+}
+
+int
+crypto_certificate_find(SignTextCertificate* certs, SignTextCertificate* cert)
+{
+	int found = 0;
+
+	while (certs) {
+
+		if (!crypto_certificate_compare(certs, cert)) {
+			found = 1;
+			break;
+		}
+
+		certs = certs->next;
+	}
+
+	return found;
+}
+
+int
+crypto_certificate_compare(SignTextCertificate* c1, SignTextCertificate* c2)
+{
+	assert(c1);
+	assert(c1->pbCertEncoded);
+	assert(c2);
+	assert(c2->pbCertEncoded);
+
+	if (c1->cbCertEncoded != c2->cbCertEncoded) {
+		return c1->cbCertEncoded - c2->cbCertEncoded;
+	}
+
+	return memcmp(c1->pbCertEncoded, c2->pbCertEncoded, c1->cbCertEncoded);
+}
+
+void
+crypto_sign(SignTextInstance* instance)
+{
+
+	HCERTSTORE sys = CertOpenStore(CERT_STORE_PROV_SYSTEM,
+		X509_ASN_ENCODING, 0, CERT_SYSTEM_STORE_CURRENT_USER | CERT_STORE_READONLY_FLAG, L"MY");
+	if (!sys) {
+		assert(0);
+	}
+
+	PCCERT_CONTEXT search;
+
+	if (!(search = CertCreateCertificateContext(
+		X509_ASN_ENCODING,
+		instance->certificate->pbCertEncoded,
+		instance->certificate->cbCertEncoded)))
+	{
+		assert(0);
+	}
+
+	PCCERT_CONTEXT cert = NULL;
+	if (!(cert = CertFindCertificateInStore(sys, X509_ASN_ENCODING, 0, CERT_FIND_EXISTING, search, NULL))) {
+		assert(0);
+	}
+
+	CertFreeCertificateContext(search);
+
+	/* no need for the cert any more, forget it */
+	signtext_certificate_unref(instance->certificate);
+
+	instance->certificate = NULL;
+
+	NCRYPT_HANDLE key;
+	DWORD dwKeySpec = 0;
+	if (!CryptAcquireCertificatePrivateKey(cert, CRYPT_ACQUIRE_CACHE_FLAG | CRYPT_ACQUIRE_COMPARE_KEY_FLAG | CRYPT_ACQUIRE_SILENT_FLAG | CRYPT_ACQUIRE_ONLY_NCRYPT_KEY_FLAG, NULL, &key, &dwKeySpec, NULL))
+	{
+		signtext_lasterror();
+
+		CertCloseStore(sys, 0);
+
+		PostMessage(instance->signtext->hwnd, WM_CRYPTO_NOTSIGNED, 0, 0);
+
+		return;
+	}
+
+	if (NCryptSetProperty(key, NCRYPT_PIN_PROPERTY, (BYTE*)instance->pinBuffer, instance->pinLen, 0) != ERROR_SUCCESS)
+	{
+		instance->is_signing = FALSE;
+
+		CertCloseStore(sys, 0);
+
+		/* wrong pin fails here */
+		MessageBox(instance->signtext->hwnd, TEXT("The PIN was not accepted. Please enter it again carefully.\r\nEntering the PIN incorrectly multiple times will lock you out."), TEXT("Signing Error"), MB_OK);
+
+		PostMessage(instance->signtext->hwnd, WM_CRYPTO_NOTSIGNED, 0, 0);
+
+		return;
+	}
+
+
+	CRYPT_ALGORITHM_IDENTIFIER hashAlgorithm;
+	memset(&hashAlgorithm, 0, sizeof(hashAlgorithm));
+	hashAlgorithm.pszObjId = szOID_RSA_SHA256RSA;
+
+	CRYPT_SIGN_MESSAGE_PARA signParam;
+	memset(&signParam, 0, sizeof(signParam));
+	signParam.cbSize = sizeof(signParam);
+	signParam.dwMsgEncodingType = PKCS_7_ASN_ENCODING;
+	signParam.pSigningCert = cert;
+	signParam.cMsgCert = 1;
+	signParam.rgpMsgCert = &cert;
+	signParam.HashAlgorithm = hashAlgorithm;
+	signParam.dwFlags = CRYPT_MESSAGE_SILENT_KEYSET_FLAG;
+
+
+	DWORD cbEncodedBlob = 0;
+	const BYTE* rgpbToBeSigned = (BYTE*)instance->in_buffer;
+	DWORD rgcbToBeSigned = (DWORD)instance->in_length;
+
+	if (!CryptSignMessage(&signParam, FALSE, 1, &rgpbToBeSigned, &rgcbToBeSigned, NULL, &cbEncodedBlob))
+	{
+		signtext_lasterror();
+
+		CertCloseStore(sys, 0);
+
+		PostMessage(instance->signtext->hwnd, WM_CRYPTO_NOTSIGNED, 0, 0);
+
+		return;
+	}
+
+	BYTE* pbEncodedBlob = (BYTE*)malloc(cbEncodedBlob);
+	if (!CryptSignMessage(&signParam, FALSE , 1, &rgpbToBeSigned, &rgcbToBeSigned, pbEncodedBlob, &cbEncodedBlob))
+	{
+		signtext_lasterror();
+
+		PostMessage(instance->signtext->hwnd, WM_CRYPTO_NOTSIGNED, 0, 0);
+
+		free(pbEncodedBlob);
+
+		instance->is_signing = FALSE;
+
+		CertCloseStore(sys, 0);
+
+		return;
+	}
+	else
+	{
+
+		DWORD cchString;
+		CryptBinaryToStringA(pbEncodedBlob, cbEncodedBlob, CRYPT_STRING_BASE64 | CRYPT_STRING_NOCRLF, NULL, &cchString);
+		LPSTR pszString = malloc((cchString + 1) * sizeof(char));
+		CryptBinaryToStringA(pbEncodedBlob, cbEncodedBlob, CRYPT_STRING_BASE64 | CRYPT_STRING_NOCRLF, pszString, &cchString);
+
+		free(pbEncodedBlob);
+
+		instance->out_buffer = pszString;
+		instance->out_length = cchString;
+
+		message_send_response(instance);
+
+		CertCloseStore(sys, 0);
+	}
+
+}

Added: redwax-signtext-windows/trunk/Redwax SignText/Redwax SignText (MFC)/crypto.h
==============================================================================
--- redwax-signtext-windows/trunk/Redwax SignText/Redwax SignText (MFC)/crypto.h	(added)
+++ redwax-signtext-windows/trunk/Redwax SignText/Redwax SignText (MFC)/crypto.h	Sun Jun 23 16:39:06 2024
@@ -0,0 +1,52 @@
+/* Licensed to Stichting The Commons Conservancy (TCC) under one or more
+ * contributor license agreements.  See the AUTHORS file distributed with
+ * this work for additional information regarding copyright ownership.
+ * TCC licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+
+#include "signtext.h"
+
+#ifndef CRYPTO_H
+#define CRYPTO_H
+
+#pragma comment(lib, "crypt32.lib")
+#pragma comment(lib, "ncrypt.lib")
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+void
+crypto_start(SignTextData* signtext);
+
+int
+crypto_certificate_is_hardware(SignTextCertificate* certificate);
+
+int
+crypto_certificate_is_removable(SignTextCertificate* certificate);
+
+int
+crypto_certificate_find(SignTextCertificate* c1, SignTextCertificate* c2);
+
+int
+crypto_certificate_compare(SignTextCertificate* c1, SignTextCertificate* c2);
+
+void
+crypto_sign(SignTextInstance* instance);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif

Added: redwax-signtext-windows/trunk/Redwax SignText/Redwax SignText (MFC)/framework.h
==============================================================================
--- redwax-signtext-windows/trunk/Redwax SignText/Redwax SignText (MFC)/framework.h	(added)
+++ redwax-signtext-windows/trunk/Redwax SignText/Redwax SignText (MFC)/framework.h	Sun Jun 23 16:39:06 2024
@@ -0,0 +1,48 @@
+#pragma once
+
+#ifndef VC_EXTRALEAN
+#define VC_EXTRALEAN            // Exclude rarely-used stuff from Windows headers
+#endif
+
+#include "targetver.h"
+
+#define _ATL_CSTRING_EXPLICIT_CONSTRUCTORS      // some CString constructors will be explicit
+
+// turns off MFC's hiding of some common and often safely ignored warning messages
+#define _AFX_ALL_WARNINGS
+
+#include <afxwin.h>         // MFC core and standard components
+#include <afxext.h>         // MFC extensions
+
+
+
+
+
+#ifndef _AFX_NO_OLE_SUPPORT
+#include <afxdtctl.h>           // MFC support for Internet Explorer 4 Common Controls
+#endif
+#ifndef _AFX_NO_AFXCMN_SUPPORT
+#include <afxcmn.h>             // MFC support for Windows Common Controls
+#endif // _AFX_NO_AFXCMN_SUPPORT
+
+#include <afxcontrolbars.h>     // MFC support for ribbons and control bars
+
+
+
+
+
+
+
+
+
+#ifdef _UNICODE
+#if defined _M_IX86
+#pragma comment(linker,"/manifestdependency:\"type='win32' name='Microsoft.Windows.Common-Controls' version='6.0.0.0' processorArchitecture='x86' publicKeyToken='6595b64144ccf1df' language='*'\"")
+#elif defined _M_X64
+#pragma comment(linker,"/manifestdependency:\"type='win32' name='Microsoft.Windows.Common-Controls' version='6.0.0.0' processorArchitecture='amd64' publicKeyToken='6595b64144ccf1df' language='*'\"")
+#else
+#pragma comment(linker,"/manifestdependency:\"type='win32' name='Microsoft.Windows.Common-Controls' version='6.0.0.0' processorArchitecture='*' publicKeyToken='6595b64144ccf1df' language='*'\"")
+#endif
+#endif
+
+

Added: redwax-signtext-windows/trunk/Redwax SignText/Redwax SignText (MFC)/message.c
==============================================================================
--- redwax-signtext-windows/trunk/Redwax SignText/Redwax SignText (MFC)/message.c	(added)
+++ redwax-signtext-windows/trunk/Redwax SignText/Redwax SignText (MFC)/message.c	Sun Jun 23 16:39:06 2024
@@ -0,0 +1,434 @@
+/* Licensed to Stichting The Commons Conservancy (TCC) under one or more
+ * contributor license agreements.  See the AUTHORS file distributed with
+ * this work for additional information regarding copyright ownership.
+ * TCC licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "signtext.h"
+#include "crypto.h"
+#include "message.h"
+
+#include <stdio.h>
+#include <stdint.h>
+#include <fcntl.h>
+#include <io.h>
+#include <strsafe.h>
+#include "cJSON.h"
+#include <assert.h>
+
+void
+message_cancel(SignTextData *signtext)
+{
+//  const char *uuid = adw_view_stack_get_visible_child_name(signtext->stack);
+
+//  SignTextInstance *instance = g_object_get_data(G_OBJECT (signtext->stack), uuid);
+
+//  if (instance) {
+
+    /*
+     * Send an error to show we cancelled.
+     */
+//    message_send_error(instance, "error:userCancel");
+
+//    signtext_instance_free(instance);
+
+//  }
+
+}
+
+
+void
+message_receive(SignTextData* signtext)
+{
+    int rv;
+
+    /* read single message */
+    uint32_t length = 0;
+    int actual = 0;
+
+    // Set "stdin" to have binary mode:
+    rv = _setmode(_fileno(stdin), _O_BINARY);
+    if (rv == -1) {
+        perror("_setmode failed: ");
+        return;
+    }
+
+    while (1) {
+
+        if (fread(&length, sizeof(length), 1, stdin) == 1) {
+
+            char* buffer = malloc(length);
+
+            if (fread(buffer, length, 1, stdin) != 1) {
+                // error
+                assert(0);
+            }
+
+            fputs("Request: ", stderr);
+            fwrite(buffer, length, 1, stderr);
+            fputs("\r\n", stderr);
+
+            PostMessage(signtext->hwnd, WM_MESSAGE_RECEIVED, length, (LPARAM)buffer);
+
+        }
+        else if (feof(stdin)) {
+
+            /*
+             * Browser went away, our work here is done.
+             */
+            PostMessage(signtext->hwnd, WM_DESTROY, 0, 0);
+
+            break;
+        }
+        else {
+            // error
+            assert(0);
+        }
+
+    }
+
+}
+
+void
+message_receive_do(SignTextData* signtext, char* buffer, uint32_t length)
+{
+
+    cJSON* json = cJSON_ParseWithLength(buffer, length);
+
+    if (!json) {
+        // error
+        assert(0);
+    }
+
+    const cJSON* url = cJSON_GetObjectItemCaseSensitive(json, "url");
+    if (!cJSON_IsString(url) || (url->valuestring == NULL))
+    {
+        // error
+        assert(0);
+    }
+
+    const cJSON* uuid = cJSON_GetObjectItemCaseSensitive(json, "uuid");
+    if (!cJSON_IsString(uuid) || (uuid->valuestring == NULL))
+    {
+        // error
+        assert(0);
+    }
+
+    const cJSON* id = cJSON_GetObjectItemCaseSensitive(json, "id");
+    if (!cJSON_IsNumber(id))
+    {
+        // error
+        assert(0);
+    }
+
+    const cJSON* request = cJSON_GetObjectItemCaseSensitive(json, "request");
+    if (!request)
+    {
+        // error
+        assert(0);
+    }
+
+    LPWSTR wUuid = signtext_utf8ToUtf16(uuid->valuestring, strlen(uuid->valuestring));
+
+    SignTextInstance* instance;
+
+    instance = (SignTextInstance*)GetProp(signtext->hwnd, wUuid);
+
+    if (!instance) {
+
+        fprintf(stderr, "Creating instance - should happen just once");
+
+        instance = signtext_instance_new(signtext, id->valueint, uuid->valuestring, url->valuestring);
+
+        instance->wUuid = wUuid;
+
+        SetProp(signtext->hwnd, wUuid, instance);
+
+    }
+    else {
+        fprintf(stderr, "Using existing instance - second and subsequent message");
+        free(wUuid);
+    }
+
+    /*
+     * Did we get a message on a cancelled connection?
+     */
+    if (instance->is_cancelled) {
+        /* do nothing, someone will be around to clean this up */
+    }
+
+    /*
+     * Process request.
+     *
+     * A string request is a data payload, append it to existing text buffer and
+     * send back an ACK.
+     */
+    else if (cJSON_IsString(request))
+    {
+        size_t length = strlen(request->valuestring);
+
+        instance->in_buffer = realloc(instance->in_buffer, instance->in_length + length + 1);
+
+        memcpy(instance->in_buffer + instance->in_length, request->valuestring, length);
+
+        instance->in_length += length;
+
+        instance->in_buffer[instance->in_length] = 0;
+
+        /*
+         * A response with a value of TRUE means ACK, send us the next bit of data.
+         */
+        message_send_boolean_response(instance, TRUE);
+
+    }
+
+    /*
+     * An object request means the data is done and we're ready to let the end user
+     * see the UI.
+     *
+     * Make the UI visible.
+     */
+    else if (cJSON_IsObject(request))
+    {
+
+        PostMessage(signtext->hwnd, WM_MESSAGE_SHOW, 0, (LPARAM)instance);
+
+    }
+
+    /*
+     * Process ACK response.
+     *
+     * A boolean request is an ACK/NAK recognising a chunk of data that has been
+     * sent back. Send the next bit of the response.
+     */
+    else if (cJSON_IsTrue(request))
+    {
+        message_send_response(instance);
+    }
+
+
+    else {
+        // error
+        assert(0);
+    }
+
+    free(buffer);
+
+}
+
+void
+message_send_response(SignTextInstance* instance)
+{
+    size_t length = instance->out_length - instance->out_offset;
+
+    if (length > 8) {
+        length = 8;
+    }
+
+    /*
+     * Any data to send, send it, otherwise it's EOF, which is FALSE.
+     */
+    if (length) {
+
+        char* buffer = malloc(length + 1);
+
+        StringCbCopyNA(buffer, length + 1, instance->out_buffer + instance->out_offset, length);
+
+        instance->out_offset += length;
+
+        message_send_string_response(instance, buffer);
+
+        free(buffer);
+
+    }
+    else {
+
+        instance->response_done = TRUE;
+
+        message_send_boolean_response(instance, FALSE);
+
+    }
+
+}
+
+void
+message_send(SignTextData* signtext, char *buffer, uint32_t length)
+{
+    int rv;
+
+    // todo: mutex needed here, or iovec?
+
+    rv = _setmode(_fileno(stdout), _O_BINARY);
+    if (rv == -1) {
+        perror("_setmode failed: ");
+        return;
+    }
+
+    if (fwrite(&length, sizeof(length), 1, stdout) != 1) {
+        // error
+        assert(0);
+    }
+
+    if (fwrite(buffer, length, 1, stdout) != 1) {
+        // error
+        assert(0);
+    }
+
+    fflush(stdout);
+
+    fputs("Response: ", stderr);
+    fwrite(buffer, length, 1, stderr);
+    fputs("\r\n", stderr);
+
+    free(buffer);
+
+    PostMessage(signtext->hwnd, WM_MESSAGE_SENT, 0, 0);
+
+}
+
+void
+message_send_boolean_response(SignTextInstance* instance, int response)
+{
+
+    cJSON* root = cJSON_CreateObject();
+    if (root == NULL)
+    {
+        // error
+        assert(0);
+    }
+
+    if (!cJSON_AddStringToObject(root, "uuid", instance->uuid))
+    {
+        // error
+        assert(0);
+    }
+
+    if (!cJSON_AddNumberToObject(root, "id", instance->id))
+    {
+        // error
+        assert(0);
+    }
+
+    if (!cJSON_AddBoolToObject(root, "response", response))
+    {
+        // error
+        assert(0);
+    }
+
+    const char *buffer = cJSON_PrintUnformatted(root);
+    if (!buffer)
+    {
+        // error
+        assert(0);
+    }
+
+    PostMessage(instance->signtext->hwnd, WM_MESSAGE_SEND, strlen(buffer), (LPARAM)buffer);
+
+    cJSON_Delete(root);
+}
+
+void
+message_send_string_response(SignTextInstance* instance, const char *response)
+{
+
+    cJSON* root = cJSON_CreateObject();
+    if (root == NULL)
+    {
+        // error
+        assert(0);
+    }
+
+    if (!cJSON_AddStringToObject(root, "uuid", instance->uuid))
+    {
+        // error
+        assert(0);
+    }
+
+    if (!cJSON_AddNumberToObject(root, "id", instance->id))
+    {
+        // error
+        assert(0);
+    }
+
+    if (!cJSON_AddStringToObject(root, "response", response))
+    {
+        // error
+        assert(0);
+    }
+
+    char* buffer = cJSON_PrintUnformatted(root);
+    if (!buffer)
+    {
+        // error
+        assert(0);
+    }
+
+    PostMessage(instance->signtext->hwnd, WM_MESSAGE_SEND, strlen(buffer), (LPARAM)buffer);
+
+    cJSON_Delete(root);
+}
+
+void
+message_send_cancel_response(SignTextInstance* instance)
+{
+
+    instance->is_cancelled = TRUE;
+
+    cJSON* root = cJSON_CreateObject();
+    if (root == NULL)
+    {
+        // error
+        assert(0);
+    }
+
+    if (!cJSON_AddStringToObject(root, "uuid", instance->uuid))
+    {
+        // error
+        assert(0);
+    }
+
+    if (!cJSON_AddNumberToObject(root, "id", instance->id))
+    {
+        // error
+        assert(0);
+    }
+
+    if (!cJSON_AddStringToObject(root, "error", "error:userCancel"))
+    {
+        // error
+        assert(0);
+    }
+
+    char* buffer = cJSON_PrintUnformatted(root);
+    if (!buffer)
+    {
+        // error
+        assert(0);
+    }
+// todo check me
+    PostMessage(instance->signtext->hwnd, WM_MESSAGE_SEND, strlen(buffer), (LPARAM)buffer);
+
+    cJSON_Delete(root);
+}
+
+void
+message_close(SignTextData* signtext)
+{
+
+    /* to shut down, close stdin and stdout */
+    fclose(stdin);
+    fclose(stdout);
+
+    PostMessage(signtext->hwnd, WM_DESTROY, 0, 0);
+
+}

Added: redwax-signtext-windows/trunk/Redwax SignText/Redwax SignText (MFC)/message.h
==============================================================================
--- redwax-signtext-windows/trunk/Redwax SignText/Redwax SignText (MFC)/message.h	(added)
+++ redwax-signtext-windows/trunk/Redwax SignText/Redwax SignText (MFC)/message.h	Sun Jun 23 16:39:06 2024
@@ -0,0 +1,61 @@
+/* Licensed to Stichting The Commons Conservancy (TCC) under one or more
+ * contributor license agreements.  See the AUTHORS file distributed with
+ * this work for additional information regarding copyright ownership.
+ * TCC licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+
+#include "signtext.h"
+
+#ifndef MESSAGE_H
+#define MESSAGE_H
+
+#include <stdint.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+void
+message_cancel(SignTextData* signtext);
+
+void
+message_receive(SignTextData* signtext);
+
+void
+message_receive_do(SignTextData* signtext, char* buffer, uint32_t length);
+
+void
+message_send(SignTextData *signtext, char *buffer, uint32_t length);
+
+void
+message_send_response(SignTextInstance* instance);
+
+void
+message_send_boolean_response(SignTextInstance* instance, int response);
+
+void
+message_send_string_response(SignTextInstance* instance, const char *response);
+
+void
+message_send_cancel_response(SignTextInstance* instance);
+
+void
+message_close(SignTextData* signtext);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
+

Added: redwax-signtext-windows/trunk/Redwax SignText/Redwax SignText (MFC)/pch.cpp
==============================================================================
--- redwax-signtext-windows/trunk/Redwax SignText/Redwax SignText (MFC)/pch.cpp	(added)
+++ redwax-signtext-windows/trunk/Redwax SignText/Redwax SignText (MFC)/pch.cpp	Sun Jun 23 16:39:06 2024
@@ -0,0 +1,5 @@
+// pch.cpp: source file corresponding to the pre-compiled header
+
+#include "pch.h"
+
+// When you are using pre-compiled headers, this source file is necessary for compilation to succeed.

Added: redwax-signtext-windows/trunk/Redwax SignText/Redwax SignText (MFC)/pch.h
==============================================================================
--- redwax-signtext-windows/trunk/Redwax SignText/Redwax SignText (MFC)/pch.h	(added)
+++ redwax-signtext-windows/trunk/Redwax SignText/Redwax SignText (MFC)/pch.h	Sun Jun 23 16:39:06 2024
@@ -0,0 +1,13 @@
+// pch.h: This is a precompiled header file.
+// Files listed below are compiled only once, improving build performance for future builds.
+// This also affects IntelliSense performance, including code completion and many code browsing features.
+// However, files listed here are ALL re-compiled if any one of them is updated between builds.
+// Do not add files here that you will be updating frequently as this negates the performance advantage.
+
+#ifndef PCH_H
+#define PCH_H
+
+// add headers that you want to pre-compile here
+#include "framework.h"
+
+#endif //PCH_H

Added: redwax-signtext-windows/trunk/Redwax SignText/Redwax SignText (MFC)/res/Redwax SignText (MFC).ico
==============================================================================
Binary file - no diff available.

Propchange: redwax-signtext-windows/trunk/Redwax SignText/Redwax SignText (MFC)/res/Redwax SignText (MFC).ico
------------------------------------------------------------------------------
    svn:mime-type = application/octet-stream

Added: redwax-signtext-windows/trunk/Redwax SignText/Redwax SignText (MFC)/res/RedwaxSignTextMFC.rc2
==============================================================================
Binary file - no diff available.

Propchange: redwax-signtext-windows/trunk/Redwax SignText/Redwax SignText (MFC)/res/RedwaxSignTextMFC.rc2
------------------------------------------------------------------------------
    svn:mime-type = application/octet-stream

Added: redwax-signtext-windows/trunk/Redwax SignText/Redwax SignText (MFC)/signtext.c
==============================================================================
--- redwax-signtext-windows/trunk/Redwax SignText/Redwax SignText (MFC)/signtext.c	(added)
+++ redwax-signtext-windows/trunk/Redwax SignText/Redwax SignText (MFC)/signtext.c	Sun Jun 23 16:39:06 2024
@@ -0,0 +1,170 @@
+/* Licensed to Stichting The Commons Conservancy (TCC) under one or more
+ * contributor license agreements.  See the AUTHORS file distributed with
+ * this work for additional information regarding copyright ownership.
+ * TCC licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+
+#include "signtext.h"
+
+#include <assert.h>
+#include <strsafe.h>
+
+SignTextData* signtext_data_new()
+{
+    SignTextData* signtext = calloc(sizeof(SignTextData), 1);
+
+//    signtext->incoming = g_list_store_new(GCR_TYPE_CERTIFICATE);
+//    signtext->certificates = g_list_store_new(GCR_TYPE_CERTIFICATE);
+
+//    signtext->hStdin = GetStdHandle(STD_INPUT_HANDLE);
+//    signtext->hStdout = GetStdHandle(STD_OUTPUT_HANDLE);
+
+    return signtext;
+}
+
+void signtext_data_free(SignTextData* data)
+{
+    if (data) {
+//        if (data->incoming) g_object_unref(data->incoming);
+//        if (data->certificates) g_object_unref(data->certificates);
+//        if (data->modules) g_list_free_full(g_steal_pointer(&data->modules), g_object_unref);
+//        if (data->slots) g_list_free_full(g_steal_pointer(&data->slots), g_object_unref);
+    }
+    free(data);
+}
+
+SignTextInstance* signtext_instance_new(SignTextData* signtext, int id, const char* uuid, const char* uri)
+{
+    SignTextInstance* instance = calloc(sizeof(SignTextInstance), 1);
+
+    instance->signtext = signtext;
+
+    instance->id = id;
+    instance->uuid = _strdup(uuid);
+    instance->uri = _strdup(uri);
+
+    return instance;
+}
+
+void signtext_instance_free(SignTextInstance* data)
+{
+    if (data) {
+        if (data->uuid) free(data->uuid);
+        if (data->uri) free(data->uri);
+        if (data->wUuid) free(data->wUuid);
+
+        if (data->pinBuffer) {
+            memset(data->pinBuffer, 0, data->pinLen);
+            free(data->pinBuffer);
+        }
+    }
+    free(data);
+}
+
+SignTextCertificate* signtext_certificate_new(SignTextData* signtext, LPWSTR name, PCCERT_CONTEXT cert, DWORD spec, DWORD type, SignTextCertificate *prev)
+{
+    SignTextCertificate* certificate = calloc(sizeof(SignTextCertificate), 1);
+
+    certificate->signtext = signtext;
+
+    certificate->name = name;
+    certificate->pbCertEncoded = malloc(cert->cbCertEncoded);
+    certificate->cbCertEncoded = cert->cbCertEncoded;
+    certificate->spec = spec;
+    certificate->type = type;
+
+    certificate->ref = 1;
+
+    memcpy(certificate->pbCertEncoded, cert->pbCertEncoded, cert->cbCertEncoded);
+
+    if (prev) {
+        prev->next = certificate;
+    }
+
+    return certificate;
+}
+
+SignTextCertificate* signtext_certificate_ref(SignTextCertificate* certificate)
+{
+    assert(certificate->ref > 0);
+
+    certificate->ref++;
+
+    return certificate;
+}
+
+SignTextCertificate* signtext_certificate_unref(SignTextCertificate* certificate)
+{
+    assert(certificate->ref > 0);
+
+    certificate->ref--;
+
+    if (!certificate->ref) {
+
+        if (certificate->name) {
+            free(certificate->name);
+        }
+
+        if (certificate->pbCertEncoded) {
+            free(certificate->pbCertEncoded);
+        }
+
+        free(certificate);
+
+        return NULL;
+    }
+
+    return certificate;
+}
+
+LPWSTR signtext_utf8ToUtf16(const char* buffer, size_t length)
+{
+    int num = MultiByteToWideChar(CP_UTF8, 0, buffer, (int)length, NULL, 0);
+
+    LPWSTR wbuffer = (LPWSTR)calloc((num + 1), sizeof(wchar_t));
+
+    MultiByteToWideChar(CP_UTF8, 0, buffer, (int)length + 1, wbuffer, num);
+
+    return wbuffer;
+}
+
+void signtext_lasterror()
+{
+    LPVOID lpMsgBuf;
+    LPVOID lpDisplayBuf;
+    DWORD dw = GetLastError();
+
+    FormatMessage(
+        FORMAT_MESSAGE_ALLOCATE_BUFFER |
+        FORMAT_MESSAGE_FROM_SYSTEM |
+        FORMAT_MESSAGE_IGNORE_INSERTS,
+        NULL,
+        dw,
+        MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
+        (LPTSTR)&lpMsgBuf,
+        0, NULL);
+
+    // Display the error message and exit the process
+
+    lpDisplayBuf = (LPVOID)LocalAlloc(LMEM_ZEROINIT,
+        (lstrlen((LPCTSTR)lpMsgBuf) + 40) * sizeof(TCHAR));
+    StringCchPrintf((LPTSTR)lpDisplayBuf,
+        LocalSize(lpDisplayBuf) / sizeof(TCHAR),
+        TEXT("Failed with error %d: %s"),
+        dw, lpMsgBuf);
+    MessageBox(NULL, (LPCTSTR)lpDisplayBuf, TEXT("Error"), MB_OK);
+
+    LocalFree(lpMsgBuf);
+    LocalFree(lpDisplayBuf);
+}

Added: redwax-signtext-windows/trunk/Redwax SignText/Redwax SignText (MFC)/signtext.h
==============================================================================
--- redwax-signtext-windows/trunk/Redwax SignText/Redwax SignText (MFC)/signtext.h	(added)
+++ redwax-signtext-windows/trunk/Redwax SignText/Redwax SignText (MFC)/signtext.h	Sun Jun 23 16:39:06 2024
@@ -0,0 +1,123 @@
+/* Licensed to Stichting The Commons Conservancy (TCC) under one or more
+ * contributor license agreements.  See the AUTHORS file distributed with
+ * this work for additional information regarding copyright ownership.
+ * TCC licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef SIGNTEXT_H
+#define SIGNTEXT_H
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+#ifndef UNICODE
+#define UNICODE
+#endif 
+
+#include <windows.h>
+
+#include <wincrypt.h>
+#include <ncrypt.h>
+
+#define WM_MESSAGE_RECEIVE WM_APP+1
+#define WM_MESSAGE_RECEIVED WM_APP+2
+#define WM_MESSAGE_SEND WM_APP+3
+#define WM_MESSAGE_SENT WM_APP+4
+#define WM_MESSAGE_SHOW WM_APP+5
+
+#define WM_CRYPTO_UPDATED WM_APP+101
+#define WM_CRYPTO_SELECTED WM_APP+102
+#define WM_CRYPTO_SIGNED WM_APP+103
+#define WM_CRYPTO_NOTSIGNED WM_APP+104
+
+
+typedef struct SignTextData {
+	HWND hwnd;
+} SignTextData;
+
+typedef struct SignTextToken SignTextToken;
+
+struct SignTextToken {
+	SignTextData* signtext;
+	SignTextToken* next;
+};
+
+typedef struct SignTextCertificate SignTextCertificate;
+
+struct SignTextCertificate {
+	SignTextData* signtext;
+	LPWSTR name;
+	BYTE* pbCertEncoded;
+	DWORD cbCertEncoded;
+	DWORD spec;
+	DWORD type;
+	SignTextCertificate* next;
+	int ref;
+};
+
+typedef struct SignTextInstance {
+	SignTextData* signtext;
+
+	char *uri;
+	char *uuid;
+	int id;
+
+//	GList* cas;
+
+	LPWSTR wUuid;
+
+	size_t in_length;
+	char* in_buffer;
+
+	HWND dialogHwnd;
+
+	SignTextCertificate* certificate;
+
+	int pinLen;
+	LPWSTR pinBuffer;
+
+	size_t out_offset;
+	size_t out_length;
+	char* out_buffer;
+
+	int is_cancelled;
+	int is_signing;
+	int response_done;
+
+} SignTextInstance;
+
+SignTextData* signtext_data_new();
+void signtext_data_free(SignTextData* data);
+
+SignTextToken* signtext_token_new();
+void signtext_token_free(SignTextToken* data);
+
+SignTextInstance* signtext_instance_new(SignTextData* signtext, int id, const char* uuid, const char* uri);
+void signtext_instance_free(SignTextInstance* instance);
+
+SignTextCertificate* signtext_certificate_new(SignTextData* signtext, LPWSTR name, PCCERT_CONTEXT cert, DWORD spec, DWORD type, SignTextCertificate* prev);
+SignTextCertificate* signtext_certificate_ref(SignTextCertificate* cert);
+SignTextCertificate* signtext_certificate_unref(SignTextCertificate* cert);
+
+void signtext_lasterror();
+
+LPWSTR signtext_utf8ToUtf16(const char* buffer, size_t length);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
+

Added: redwax-signtext-windows/trunk/Redwax SignText/Redwax SignText (MFC)/targetver.h
==============================================================================
--- redwax-signtext-windows/trunk/Redwax SignText/Redwax SignText (MFC)/targetver.h	(added)
+++ redwax-signtext-windows/trunk/Redwax SignText/Redwax SignText (MFC)/targetver.h	Sun Jun 23 16:39:06 2024
@@ -0,0 +1,8 @@
+#pragma once
+
+// Including SDKDDKVer.h defines the highest available Windows platform.
+
+// If you wish to build your application for a previous Windows platform, include WinSDKVer.h and
+// set the _WIN32_WINNT macro to the platform you wish to support before including SDKDDKVer.h.
+
+#include <SDKDDKVer.h>

Propchange: redwax-signtext-windows/trunk/Redwax SignText/Redwax SignText Installer/
------------------------------------------------------------------------------
--- svn:ignore	(added)
+++ svn:ignore	Sun Jun 23 16:39:06 2024
@@ -0,0 +1,13 @@
+[Bb]in
+obj
+[Dd]ebug
+[Rr]elease
+*.user
+*.aps
+*.eto
+ClientBin
+GeneratedArtifacts
+_Pvt_Extensions
+project.lock.json
+*.nuget.props
+*.nuget.targets

Added: redwax-signtext-windows/trunk/Redwax SignText/Redwax SignText Installer/Folders.wxs
==============================================================================
--- redwax-signtext-windows/trunk/Redwax SignText/Redwax SignText Installer/Folders.wxs	(added)
+++ redwax-signtext-windows/trunk/Redwax SignText/Redwax SignText Installer/Folders.wxs	Sun Jun 23 16:39:06 2024
@@ -0,0 +1,7 @@
+<Wix xmlns="http://wixtoolset.org/schemas/v4/wxs">
+  <Fragment>
+    <StandardDirectory Id="ProgramFiles6432Folder">
+      <Directory Id="INSTALLFOLDER" Name="!(bind.Property.Manufacturer)\!(bind.Property.ProductName)" />
+    </StandardDirectory>
+  </Fragment>
+</Wix>

Added: redwax-signtext-windows/trunk/Redwax SignText/Redwax SignText Installer/Package.en-us.wxl
==============================================================================
--- redwax-signtext-windows/trunk/Redwax SignText/Redwax SignText Installer/Package.en-us.wxl	(added)
+++ redwax-signtext-windows/trunk/Redwax SignText/Redwax SignText Installer/Package.en-us.wxl	Sun Jun 23 16:39:06 2024
@@ -0,0 +1,8 @@
+<!--
+This file contains the declaration of all the localizable strings.
+-->
+<WixLocalization xmlns="http://wixtoolset.org/schemas/v4/wxl" Culture="en-US">
+
+  <String Id="DowngradeError" Value="A newer version of [ProductName] is already installed." />
+
+</WixLocalization>

Added: redwax-signtext-windows/trunk/Redwax SignText/Redwax SignText Installer/Package.wxs
==============================================================================
--- redwax-signtext-windows/trunk/Redwax SignText/Redwax SignText Installer/Package.wxs	(added)
+++ redwax-signtext-windows/trunk/Redwax SignText/Redwax SignText Installer/Package.wxs	Sun Jun 23 16:39:06 2024
@@ -0,0 +1,9 @@
+<Wix xmlns="http://wixtoolset.org/schemas/v4/wxs">
+  <Package Name="Redwax SignText" Manufacturer="Redwax Project" Version="1.0.0.0" UpgradeCode="ef73d279-fc6d-4beb-a5bf-27cd95d0bca2">
+    <MajorUpgrade DowngradeErrorMessage="!(loc.DowngradeError)" />
+    <MediaTemplate EmbedCab="yes" />
+    <Feature Id="Main">
+      <ComponentGroupRef Id="NativeComponents" />
+    </Feature>
+  </Package>
+</Wix>

Added: redwax-signtext-windows/trunk/Redwax SignText/Redwax SignText Installer/Redwax SignText Installer.wixproj
==============================================================================
--- redwax-signtext-windows/trunk/Redwax SignText/Redwax SignText Installer/Redwax SignText Installer.wixproj	(added)
+++ redwax-signtext-windows/trunk/Redwax SignText/Redwax SignText Installer/Redwax SignText Installer.wixproj	Sun Jun 23 16:39:06 2024
@@ -0,0 +1,5 @@
+<Project Sdk="WixToolset.Sdk/5.0.0">
+  <ItemGroup>
+    <ProjectReference Include="..\Redwax SignText (MFC)\Redwax SignText (MFC).vcxproj" />
+  </ItemGroup>
+</Project>

Added: redwax-signtext-windows/trunk/Redwax SignText/Redwax SignText/eu.redwax.Redwax.SignText.arm64.json
==============================================================================
--- redwax-signtext-windows/trunk/Redwax SignText/Redwax SignText/eu.redwax.Redwax.SignText.arm64.json	(added)
+++ redwax-signtext-windows/trunk/Redwax SignText/Redwax SignText/eu.redwax.Redwax.SignText.arm64.json	Sun Jun 23 16:39:06 2024
@@ -0,0 +1,7 @@
+{
+  "allowed_extensions": [ "rst at redwax.eu" ],
+  "description": "Redwax SignText Native Extension",
+  "name": "eu.redwax.Redwax.SignText",
+  "path": "C:\\Program Files (arm64)\\Redwax Project\\Redwax SignText\\Redwax SignText.exe",
+  "type": "stdio"
+}

Added: redwax-signtext-windows/trunk/Redwax SignText/Redwax SignText/eu.redwax.Redwax.SignText.x64.json
==============================================================================
--- redwax-signtext-windows/trunk/Redwax SignText/Redwax SignText/eu.redwax.Redwax.SignText.x64.json	(added)
+++ redwax-signtext-windows/trunk/Redwax SignText/Redwax SignText/eu.redwax.Redwax.SignText.x64.json	Sun Jun 23 16:39:06 2024
@@ -0,0 +1,7 @@
+{
+  "allowed_extensions": [ "rst at redwax.eu" ],
+  "description": "Redwax SignText Native Extension",
+  "name": "eu.redwax.Redwax.SignText",
+  "path": "C:\\Program Files\\Redwax Project\\Redwax SignText\\Redwax SignText.exe",
+  "type": "stdio"
+}

Added: redwax-signtext-windows/trunk/Redwax SignText/Redwax SignText/eu.redwax.Redwax.SignText.x86.json
==============================================================================
--- redwax-signtext-windows/trunk/Redwax SignText/Redwax SignText/eu.redwax.Redwax.SignText.x86.json	(added)
+++ redwax-signtext-windows/trunk/Redwax SignText/Redwax SignText/eu.redwax.Redwax.SignText.x86.json	Sun Jun 23 16:39:06 2024
@@ -0,0 +1,7 @@
+{
+  "allowed_extensions": [ "rst at redwax.eu" ],
+  "description": "Redwax SignText Native Extension",
+  "name": "eu.redwax.Redwax.SignText",
+  "path": "C:\\Program Files (x86)\\Redwax Project\\Redwax SignText\\Redwax SignText.exe",
+  "type": "stdio"
+}



More information about the rst-commit mailing list