From 0adf122d1d258d5b5be38ff10a4208fb09876681 Mon Sep 17 00:00:00 2001 From: Kilian Hofmann Date: Sat, 1 Jan 2022 23:50:23 +0100 Subject: [PATCH] Real Name --- CMakeLists.txt | 15 + GermanAirlinesVA-GAConnector/.clang-format | 54 + GermanAirlinesVA-GAConnector/.gitattributes | 63 + GermanAirlinesVA-GAConnector/.gitignore | 366 + GermanAirlinesVA-GAConnector/.idea/.gitignore | 8 + GermanAirlinesVA-GAConnector/.idea/.name | 1 + .../.idea/GermanAirlinesVA-GAConnector.iml | 2 + GermanAirlinesVA-GAConnector/.idea/misc.xml | 4 + .../.idea/modules.xml | 8 + GermanAirlinesVA-GAConnector/.idea/vcs.xml | 6 + GermanAirlinesVA-GAConnector/CMakeLists.txt | 15 + GermanAirlinesVA-GAConnector/Jenkinsfile | 127 + GermanAirlinesVA-GAConnector/README.md | 11 + .../CHeaders/Widgets/XPStandardWidgets.h | 628 + .../XPSDK/CHeaders/Widgets/XPUIGraphics.h | 395 + .../XPSDK/CHeaders/Widgets/XPWidgetDefs.h | 525 + .../XPSDK/CHeaders/Widgets/XPWidgetUtils.h | 224 + .../XPSDK/CHeaders/Widgets/XPWidgets.h | 541 + .../CHeaders/Wrappers/XPCBroadcaster.cpp | 45 + .../XPSDK/CHeaders/Wrappers/XPCBroadcaster.h | 31 + .../XPSDK/CHeaders/Wrappers/XPCDisplay.cpp | 107 + .../XPSDK/CHeaders/Wrappers/XPCDisplay.h | 70 + .../XPSDK/CHeaders/Wrappers/XPCListener.cpp | 23 + .../XPSDK/CHeaders/Wrappers/XPCListener.h | 30 + .../XPSDK/CHeaders/Wrappers/XPCProcessing.cpp | 60 + .../XPSDK/CHeaders/Wrappers/XPCProcessing.h | 33 + .../XPSDK/CHeaders/Wrappers/XPCWidget.cpp | 111 + .../XPSDK/CHeaders/Wrappers/XPCWidget.h | 71 + .../Wrappers/XPCWidgetAttachments.cpp | 235 + .../CHeaders/Wrappers/XPCWidgetAttachments.h | 132 + .../XPSDK/CHeaders/XPLM/XPLMCamera.h | 167 + .../XPSDK/CHeaders/XPLM/XPLMDataAccess.h | 670 + .../XPSDK/CHeaders/XPLM/XPLMDefs.h | 518 + .../XPSDK/CHeaders/XPLM/XPLMDisplay.h | 743 + .../XPSDK/CHeaders/XPLM/XPLMGraphics.h | 413 + .../XPSDK/CHeaders/XPLM/XPLMMenus.h | 210 + .../XPSDK/CHeaders/XPLM/XPLMNavigation.h | 373 + .../XPSDK/CHeaders/XPLM/XPLMPlanes.h | 245 + .../XPSDK/CHeaders/XPLM/XPLMPlugin.h | 311 + .../XPSDK/CHeaders/XPLM/XPLMProcessing.h | 248 + .../XPSDK/CHeaders/XPLM/XPLMScenery.h | 386 + .../XPSDK/CHeaders/XPLM/XPLMUtilities.h | 829 + .../Delphi/Widgets/XPStandardWidgets.pas | 497 + .../XPSDK/Delphi/Widgets/XPUIGraphics.pas | 380 + .../XPSDK/Delphi/Widgets/XPWidgetDefs.pas | 441 + .../XPSDK/Delphi/Widgets/XPWidgetUtils.pas | 225 + .../XPSDK/Delphi/Widgets/XPWidgets.pas | 665 + .../XPSDK/Delphi/XPLM/XPLMCamera.pas | 174 + .../XPSDK/Delphi/XPLM/XPLMDataAccess.pas | 764 + .../XPSDK/Delphi/XPLM/XPLMDefs.pas | 446 + .../XPSDK/Delphi/XPLM/XPLMDisplay.pas | 835 + .../XPSDK/Delphi/XPLM/XPLMGraphics.pas | 441 + .../XPSDK/Delphi/XPLM/XPLMMenus.pas | 259 + .../XPSDK/Delphi/XPLM/XPLMNavigation.pas | 434 + .../XPSDK/Delphi/XPLM/XPLMPlanes.pas | 294 + .../XPSDK/Delphi/XPLM/XPLMPlugin.pas | 381 + .../XPSDK/Delphi/XPLM/XPLMProcessing.pas | 276 + .../XPSDK/Delphi/XPLM/XPLMScenery.pas | 419 + .../XPSDK/Delphi/XPLM/XPLMUtilities.pas | 927 + .../XPSDK/Libraries/Mac/XPLM.framework/XPLM | Bin 0 -> 650652 bytes .../Mac/XPWidgets.framework/XPWidgets | Bin 0 -> 210904 bytes .../XPSDK/Libraries/Win/XPLM.lib | Bin 0 -> 39362 bytes .../XPSDK/Libraries/Win/XPLM_64.lib | Bin 0 -> 39060 bytes .../XPSDK/Libraries/Win/XPWidgets.lib | Bin 0 -> 10524 bytes .../XPSDK/Libraries/Win/XPWidgets_64.lib | Bin 0 -> 10564 bytes GermanAirlinesVA-GAConnector/XPSDK/README.txt | 197 + .../XPSDK/license.txt | 27 + GermanAirlinesVA-GAConnector/build.sh | 37 + .../ixwebsocket/IXBench.cpp | 56 + .../ixwebsocket/IXCancellationRequest.cpp | 39 + .../ixwebsocket/IXConnectionState.cpp | 54 + .../ixwebsocket/IXDNSLookup.cpp | 190 + .../ixwebsocket/IXExponentialBackoff.cpp | 30 + .../ixwebsocket/IXGetFreePort.cpp | 95 + .../ixwebsocket/IXGzipCodec.cpp | 186 + .../ixwebsocket/IXHttp.cpp | 208 + .../ixwebsocket/IXHttpClient.cpp | 724 + .../ixwebsocket/IXHttpServer.cpp | 239 + .../ixwebsocket/IXNetSystem.cpp | 296 + .../ixwebsocket/IXSelectInterrupt.cpp | 27 + .../ixwebsocket/IXSelectInterruptFactory.cpp | 26 + .../ixwebsocket/IXSelectInterruptPipe.cpp | 156 + .../ixwebsocket/IXSetThreadName.cpp | 81 + .../ixwebsocket/IXSocket.cpp | 373 + .../ixwebsocket/IXSocketAppleSSL.cpp | 307 + .../ixwebsocket/IXSocketConnect.cpp | 150 + .../ixwebsocket/IXSocketFactory.cpp | 60 + .../ixwebsocket/IXSocketMbedTLS.cpp | 350 + .../ixwebsocket/IXSocketOpenSSL.cpp | 761 + .../ixwebsocket/IXSocketServer.cpp | 467 + .../ixwebsocket/IXSocketTLSOptions.cpp | 86 + .../ixwebsocket/IXStrCaseCompare.cpp | 39 + .../ixwebsocket/IXUdpSocket.cpp | 125 + .../ixwebsocket/IXUrlParser.cpp | 363 + .../ixwebsocket/IXUserAgent.cpp | 92 + .../ixwebsocket/IXUuid.cpp | 75 + .../ixwebsocket/IXWebSocket.cpp | 588 + .../ixwebsocket/IXWebSocketCloseConstants.cpp | 46 + .../ixwebsocket/IXWebSocketHandshake.cpp | 365 + .../ixwebsocket/IXWebSocketHttpHeaders.cpp | 71 + .../IXWebSocketPerMessageDeflate.cpp | 93 + .../IXWebSocketPerMessageDeflateCodec.cpp | 253 + .../IXWebSocketPerMessageDeflateOptions.cpp | 193 + .../ixwebsocket/IXWebSocketProxyServer.cpp | 117 + .../ixwebsocket/IXWebSocketServer.cpp | 206 + .../ixwebsocket/IXWebSocketTransport.cpp | 1130 + .../ixwebsocket/License.txt | 29 + .../ixwebsocket/include/IXBench.h | 32 + .../include/IXCancellationRequest.h | 19 + .../ixwebsocket/include/IXConnectionState.h | 54 + .../ixwebsocket/include/IXDNSLookup.h | 73 + .../include/IXExponentialBackoff.h | 17 + .../ixwebsocket/include/IXGetFreePort.h | 12 + .../ixwebsocket/include/IXGzipCodec.h | 15 + .../ixwebsocket/include/IXHttp.h | 117 + .../ixwebsocket/include/IXHttpClient.h | 126 + .../ixwebsocket/include/IXHttpServer.h | 62 + .../ixwebsocket/include/IXNetSystem.h | 87 + .../ixwebsocket/include/IXProgressCallback.h | 14 + .../ixwebsocket/include/IXSelectInterrupt.h | 34 + .../include/IXSelectInterruptFactory.h | 16 + .../include/IXSelectInterruptPipe.h | 40 + .../ixwebsocket/include/IXSetThreadName.h | 12 + .../ixwebsocket/include/IXSocket.h | 97 + .../ixwebsocket/include/IXSocketAppleSSL.h | 56 + .../ixwebsocket/include/IXSocketConnect.h | 32 + .../ixwebsocket/include/IXSocketFactory.h | 21 + .../ixwebsocket/include/IXSocketMbedTLS.h | 61 + .../ixwebsocket/include/IXSocketOpenSSL.h | 75 + .../ixwebsocket/include/IXSocketServer.h | 134 + .../ixwebsocket/include/IXSocketTLSOptions.h | 53 + .../ixwebsocket/include/IXStrCaseCompare.h | 23 + .../ixwebsocket/include/IXUdpSocket.h | 45 + .../ixwebsocket/include/IXUniquePtr.h | 18 + .../ixwebsocket/include/IXUrlParser.h | 23 + .../ixwebsocket/include/IXUserAgent.h | 14 + .../ixwebsocket/include/IXUtf8Validator.h | 184 + .../ixwebsocket/include/IXUuid.h | 17 + .../ixwebsocket/include/IXWebSocket.h | 174 + .../include/IXWebSocketCloseConstants.h | 36 + .../include/IXWebSocketCloseInfo.h | 27 + .../include/IXWebSocketErrorInfo.h | 21 + .../include/IXWebSocketHandshake.h | 57 + .../include/IXWebSocketHandshakeKeyGen.h | 174 + .../include/IXWebSocketHttpHeaders.h | 25 + .../include/IXWebSocketInitResult.h | 35 + .../ixwebsocket/include/IXWebSocketMessage.h | 55 + .../include/IXWebSocketMessageType.h | 20 + .../ixwebsocket/include/IXWebSocketOpenInfo.h | 28 + .../include/IXWebSocketPerMessageDeflate.h | 64 + .../IXWebSocketPerMessageDeflateCodec.h | 60 + .../IXWebSocketPerMessageDeflateOptions.h | 47 + .../include/IXWebSocketProxyServer.h | 24 + .../ixwebsocket/include/IXWebSocketSendInfo.h | 26 + .../ixwebsocket/include/IXWebSocketServer.h | 84 + .../include/IXWebSocketTransport.h | 261 + .../ixwebsocket/include/IXWebSocketVersion.h | 9 + .../nlohmann/License.txt | 21 + .../nlohmann/json.hpp | 31780 ++++++++++++++++ .../toolchain-lin.cmake | 11 + .../toolchain-mac.cmake | 18 + .../toolchain-win-32.cmake | 18 + .../toolchain-win-64.cmake | 18 + .../websocket/include/types.h | 55 + .../websocket/include/websocket.h | 62 + .../websocket/websocket.cpp | 293 + .../xplugin/CMakeLists.txt | 140 + .../xplugin/include/main.h | 33 + GermanAirlinesVA-GAConnector/xplugin/main.cpp | 202 + .../xplugin/xPluginWin.cpp | 19 + Jenkinsfile | 127 + XPSDK/CHeaders/Widgets/XPStandardWidgets.h | 628 + XPSDK/CHeaders/Widgets/XPUIGraphics.h | 395 + XPSDK/CHeaders/Widgets/XPWidgetDefs.h | 525 + XPSDK/CHeaders/Widgets/XPWidgetUtils.h | 224 + XPSDK/CHeaders/Widgets/XPWidgets.h | 541 + XPSDK/CHeaders/Wrappers/XPCBroadcaster.cpp | 45 + XPSDK/CHeaders/Wrappers/XPCBroadcaster.h | 31 + XPSDK/CHeaders/Wrappers/XPCDisplay.cpp | 107 + XPSDK/CHeaders/Wrappers/XPCDisplay.h | 70 + XPSDK/CHeaders/Wrappers/XPCListener.cpp | 23 + XPSDK/CHeaders/Wrappers/XPCListener.h | 30 + XPSDK/CHeaders/Wrappers/XPCProcessing.cpp | 60 + XPSDK/CHeaders/Wrappers/XPCProcessing.h | 33 + XPSDK/CHeaders/Wrappers/XPCWidget.cpp | 111 + XPSDK/CHeaders/Wrappers/XPCWidget.h | 71 + .../Wrappers/XPCWidgetAttachments.cpp | 235 + .../CHeaders/Wrappers/XPCWidgetAttachments.h | 132 + XPSDK/CHeaders/XPLM/XPLMCamera.h | 167 + XPSDK/CHeaders/XPLM/XPLMDataAccess.h | 670 + XPSDK/CHeaders/XPLM/XPLMDefs.h | 518 + XPSDK/CHeaders/XPLM/XPLMDisplay.h | 743 + XPSDK/CHeaders/XPLM/XPLMGraphics.h | 413 + XPSDK/CHeaders/XPLM/XPLMMenus.h | 210 + XPSDK/CHeaders/XPLM/XPLMNavigation.h | 373 + XPSDK/CHeaders/XPLM/XPLMPlanes.h | 245 + XPSDK/CHeaders/XPLM/XPLMPlugin.h | 311 + XPSDK/CHeaders/XPLM/XPLMProcessing.h | 248 + XPSDK/CHeaders/XPLM/XPLMScenery.h | 386 + XPSDK/CHeaders/XPLM/XPLMUtilities.h | 829 + XPSDK/Delphi/Widgets/XPStandardWidgets.pas | 497 + XPSDK/Delphi/Widgets/XPUIGraphics.pas | 380 + XPSDK/Delphi/Widgets/XPWidgetDefs.pas | 441 + XPSDK/Delphi/Widgets/XPWidgetUtils.pas | 225 + XPSDK/Delphi/Widgets/XPWidgets.pas | 665 + XPSDK/Delphi/XPLM/XPLMCamera.pas | 174 + XPSDK/Delphi/XPLM/XPLMDataAccess.pas | 764 + XPSDK/Delphi/XPLM/XPLMDefs.pas | 446 + XPSDK/Delphi/XPLM/XPLMDisplay.pas | 835 + XPSDK/Delphi/XPLM/XPLMGraphics.pas | 441 + XPSDK/Delphi/XPLM/XPLMMenus.pas | 259 + XPSDK/Delphi/XPLM/XPLMNavigation.pas | 434 + XPSDK/Delphi/XPLM/XPLMPlanes.pas | 294 + XPSDK/Delphi/XPLM/XPLMPlugin.pas | 381 + XPSDK/Delphi/XPLM/XPLMProcessing.pas | 276 + XPSDK/Delphi/XPLM/XPLMScenery.pas | 419 + XPSDK/Delphi/XPLM/XPLMUtilities.pas | 927 + XPSDK/Libraries/Mac/XPLM.framework/XPLM | Bin 0 -> 650652 bytes .../Mac/XPWidgets.framework/XPWidgets | Bin 0 -> 210904 bytes XPSDK/Libraries/Win/XPLM.lib | Bin 0 -> 39362 bytes XPSDK/Libraries/Win/XPLM_64.lib | Bin 0 -> 39060 bytes XPSDK/Libraries/Win/XPWidgets.lib | Bin 0 -> 10524 bytes XPSDK/Libraries/Win/XPWidgets_64.lib | Bin 0 -> 10564 bytes XPSDK/README.txt | 197 + XPSDK/license.txt | 27 + build-lin/.cmake/api/v1/query/cache-v2 | 0 build-lin/.cmake/api/v1/query/cmakeFiles-v1 | 0 build-lin/.cmake/api/v1/query/codemodel-v2 | 0 build-lin/.cmake/api/v1/query/toolchains-v1 | 0 .../reply/cache-v2-81e32d47656441db6f4b.json | 1227 + .../cmakeFiles-v1-f30b6725c229d3c47955.json | 763 + .../codemodel-v2-ca5882791008547413fa.json | 76 + ...irectory-.-Debug-f5ebdc15457944623624.json | 14 + ...ry-xplugin-Debug-5600733809e8ef9a4488.json | 14 + .../reply/index-2022-01-01T22-36-30-0832.json | 108 + ...va_xplugin-Debug-ae0b9bb84c1b770cea7c.json | 523 + .../toolchains-v1-77b1fedc25d3af5713c5.json | 113 + build-lin/CMakeCache.txt | 379 + .../CMakeFiles/3.21.1/CMakeCCompiler.cmake | 80 + .../CMakeFiles/3.21.1/CMakeCXXCompiler.cmake | 91 + .../3.21.1/CMakeDetermineCompilerABI_C.bin | Bin 0 -> 16408 bytes .../3.21.1/CMakeDetermineCompilerABI_CXX.bin | Bin 0 -> 16432 bytes build-lin/CMakeFiles/3.21.1/CMakeSystem.cmake | 15 + .../3.21.1/CompilerIdC/CMakeCCompilerId.c | 807 + build-lin/CMakeFiles/3.21.1/CompilerIdC/a.out | Bin 0 -> 16464 bytes .../CompilerIdCXX/CMakeCXXCompilerId.cpp | 795 + .../CMakeFiles/3.21.1/CompilerIdCXX/a.out | Bin 0 -> 16472 bytes .../CMakeDirectoryInformation.cmake | 16 + build-lin/CMakeFiles/CMakeOutput.log | 393 + build-lin/CMakeFiles/Makefile.cmake | 131 + build-lin/CMakeFiles/Makefile2 | 128 + build-lin/CMakeFiles/TargetDirectories.txt | 5 + build-lin/CMakeFiles/VerifyGlobs.cmake | 60 + build-lin/CMakeFiles/clion-environment.txt | Bin 0 -> 205 bytes build-lin/CMakeFiles/clion-log.txt | 17 + build-lin/CMakeFiles/cmake.check_cache | 1 + build-lin/CMakeFiles/cmake.verify_globs | 1 + build-lin/CMakeFiles/progress.marks | 1 + build-lin/Makefile | 156 + build-lin/cmake_install.cmake | 60 + .../CMakeDirectoryInformation.cmake | 16 + .../DependInfo.cmake | 58 + .../germanairlinesva_xplugin.dir/build.make | 734 + .../cmake_clean.cmake | 89 + .../compiler_depend.make | 2 + .../compiler_depend.ts | 2 + .../germanairlinesva_xplugin.dir/depend.make | 2 + .../germanairlinesva_xplugin.dir/flags.make | 10 + .../germanairlinesva_xplugin.dir/link.txt | 1 + .../progress.make | 42 + build-lin/xplugin/CMakeFiles/progress.marks | 1 + build-lin/xplugin/Makefile | 1237 + build-lin/xplugin/cmake_install.cmake | 44 + build-mac/.cmake/api/v1/query/cache-v2 | 0 build-mac/.cmake/api/v1/query/cmakeFiles-v1 | 0 build-mac/.cmake/api/v1/query/codemodel-v2 | 0 build-mac/.cmake/api/v1/query/toolchains-v1 | 0 .../reply/cache-v2-675f95f050489ccb94db.json | 1255 + .../cmakeFiles-v1-1c218b19e22045540904.json | 758 + .../codemodel-v2-65037702c357d77e645d.json | 76 + ...irectory-.-Debug-f5ebdc15457944623624.json | 14 + ...ry-xplugin-Debug-5600733809e8ef9a4488.json | 14 + .../reply/index-2022-01-01T22-36-30-0842.json | 108 + ...va_xplugin-Debug-36503d0c3fe46bb75f36.json | 565 + .../toolchains-v1-127409b8a758e6dfad8d.json | 86 + build-mac/CMakeCache.txt | 389 + .../CMakeFiles/3.21.1/CMakeCCompiler.cmake | 80 + .../CMakeFiles/3.21.1/CMakeCXXCompiler.cmake | 91 + .../3.21.1/CMakeDetermineCompilerABI_C.bin | Bin 0 -> 8496 bytes .../3.21.1/CMakeDetermineCompilerABI_CXX.bin | Bin 0 -> 12584 bytes build-mac/CMakeFiles/3.21.1/CMakeSystem.cmake | 15 + .../3.21.1/CompilerIdC/CMakeCCompilerId.c | 807 + build-mac/CMakeFiles/3.21.1/CompilerIdC/a.out | Bin 0 -> 8616 bytes .../CompilerIdCXX/CMakeCXXCompilerId.cpp | 795 + .../CMakeFiles/3.21.1/CompilerIdCXX/a.out | Bin 0 -> 8600 bytes .../CMakeDirectoryInformation.cmake | 16 + build-mac/CMakeFiles/CMakeOutput.log | 267 + build-mac/CMakeFiles/Makefile.cmake | 130 + build-mac/CMakeFiles/Makefile2 | 128 + build-mac/CMakeFiles/TargetDirectories.txt | 5 + build-mac/CMakeFiles/VerifyGlobs.cmake | 60 + build-mac/CMakeFiles/clion-environment.txt | Bin 0 -> 205 bytes build-mac/CMakeFiles/clion-log.txt | 39 + build-mac/CMakeFiles/cmake.check_cache | 1 + build-mac/CMakeFiles/cmake.verify_globs | 1 + build-mac/CMakeFiles/progress.marks | 1 + build-mac/Makefile | 156 + build-mac/cmake_install.cmake | 55 + .../CMakeDirectoryInformation.cmake | 16 + .../DependInfo.cmake | 58 + .../germanairlinesva_xplugin.dir/build.make | 735 + .../cmake_clean.cmake | 89 + .../compiler_depend.make | 2 + .../compiler_depend.ts | 2 + .../germanairlinesva_xplugin.dir/depend.make | 2 + .../germanairlinesva_xplugin.dir/flags.make | 10 + .../germanairlinesva_xplugin.dir/link.txt | 1 + .../progress.make | 42 + build-mac/xplugin/CMakeFiles/progress.marks | 1 + build-mac/xplugin/Makefile | 1237 + build-mac/xplugin/cmake_install.cmake | 39 + build-win/.cmake/api/v1/query/cache-v2 | 0 build-win/.cmake/api/v1/query/cmakeFiles-v1 | 0 build-win/.cmake/api/v1/query/codemodel-v2 | 0 build-win/.cmake/api/v1/query/toolchains-v1 | 0 .../reply/cache-v2-aaf1f5c58890f178affe.json | 1367 + .../cmakeFiles-v1-1917a1c891fc4e27947d.json | 797 + .../codemodel-v2-2013d1073c0ff9eab183.json | 76 + ...irectory-.-Debug-f5ebdc15457944623624.json | 14 + ...ry-xplugin-Debug-5600733809e8ef9a4488.json | 14 + .../reply/index-2022-01-01T22-36-30-0781.json | 108 + ...va_xplugin-Debug-1b204b6bb48bb7bc17b8.json | 566 + .../toolchains-v1-a31bd5b59156d0a53439.json | 129 + build-win/CMakeCache.txt | 421 + .../CMakeFiles/3.21.1/CMakeCCompiler.cmake | 80 + .../CMakeFiles/3.21.1/CMakeCXXCompiler.cmake | 91 + .../3.21.1/CMakeDetermineCompilerABI_C.bin | Bin 0 -> 83456 bytes .../3.21.1/CMakeDetermineCompilerABI_CXX.bin | Bin 0 -> 83456 bytes .../CMakeFiles/3.21.1/CMakeRCCompiler.cmake | 6 + build-win/CMakeFiles/3.21.1/CMakeSystem.cmake | 15 + .../3.21.1/CompilerIdC/CMakeCCompilerId.c | 807 + build-win/CMakeFiles/3.21.1/CompilerIdC/a.exe | Bin 0 -> 83456 bytes .../CompilerIdCXX/CMakeCXXCompilerId.cpp | 795 + .../CMakeFiles/3.21.1/CompilerIdCXX/a.exe | Bin 0 -> 83456 bytes .../CMakeDirectoryInformation.cmake | 16 + build-win/CMakeFiles/CMakeOutput.log | 297 + build-win/CMakeFiles/Makefile.cmake | 139 + build-win/CMakeFiles/Makefile2 | 128 + build-win/CMakeFiles/TargetDirectories.txt | 5 + build-win/CMakeFiles/VerifyGlobs.cmake | 60 + build-win/CMakeFiles/clion-environment.txt | Bin 0 -> 208 bytes build-win/CMakeFiles/clion-log.txt | 17 + build-win/CMakeFiles/cmake.check_cache | 1 + build-win/CMakeFiles/cmake.verify_globs | 1 + build-win/CMakeFiles/progress.marks | 1 + build-win/Makefile | 156 + build-win/Testing/Temporary/LastTest.log | 3 + build-win/cmake_install.cmake | 55 + .../CMakeDirectoryInformation.cmake | 16 + .../DependInfo.cmake | 59 + .../germanairlinesva_xplugin.dir/build.make | 794 + .../cmake_clean.cmake | 92 + .../compiler_depend.make | 2 + .../compiler_depend.ts | 2 + .../germanairlinesva_xplugin.dir/depend.make | 2 + .../germanairlinesva_xplugin.dir/flags.make | 10 + .../includes_CXX.rsp | 1 + .../germanairlinesva_xplugin.dir/link.txt | 3 + .../germanairlinesva_xplugin.dir/linklibs.rsp | 1 + .../germanairlinesva_xplugin.dir/objects1.rsp | 1 + .../progress.make | 43 + build-win/xplugin/CMakeFiles/progress.marks | 1 + build-win/xplugin/Makefile | 1264 + build-win/xplugin/cmake_install.cmake | 39 + build.sh | 37 + build/CMakeCache.txt | 364 + build/CMakeFiles/3.16.3/CMakeCCompiler.cmake | 76 + .../CMakeFiles/3.16.3/CMakeCXXCompiler.cmake | 88 + .../3.16.3/CMakeDetermineCompilerABI_C.bin | Bin 0 -> 16304 bytes .../3.16.3/CMakeDetermineCompilerABI_CXX.bin | Bin 0 -> 16320 bytes build/CMakeFiles/3.16.3/CMakeSystem.cmake | 15 + .../3.16.3/CompilerIdC/CMakeCCompilerId.c | 671 + build/CMakeFiles/3.16.3/CompilerIdC/a.out | Bin 0 -> 16464 bytes .../CompilerIdCXX/CMakeCXXCompilerId.cpp | 660 + build/CMakeFiles/3.16.3/CompilerIdCXX/a.out | Bin 0 -> 16472 bytes .../CMakeDirectoryInformation.cmake | 16 + build/CMakeFiles/CMakeOutput.log | 818 + build/CMakeFiles/Makefile.cmake | 128 + build/CMakeFiles/Makefile2 | 125 + build/CMakeFiles/TargetDirectories.txt | 5 + build/CMakeFiles/VerifyGlobs.cmake | 59 + build/CMakeFiles/cmake.check_cache | 1 + build/CMakeFiles/cmake.verify_globs | 1 + build/CMakeFiles/progress.marks | 1 + build/Makefile | 150 + build/Plugin/GAConnector/64/lin.xpl | Bin 0 -> 481384 bytes build/cmake_install.cmake | 55 + .../CMakeDirectoryInformation.cmake | 16 + .../CXX.includecache | 1614 + .../DependInfo.cmake | 71 + .../__/ixwebsocket/IXBench.cpp.o | Bin 0 -> 5856 bytes .../ixwebsocket/IXCancellationRequest.cpp.o | Bin 0 -> 3488 bytes .../__/ixwebsocket/IXConnectionState.cpp.o | Bin 0 -> 14448 bytes .../__/ixwebsocket/IXDNSLookup.cpp.o | Bin 0 -> 25056 bytes .../__/ixwebsocket/IXExponentialBackoff.cpp.o | Bin 0 -> 1336 bytes .../__/ixwebsocket/IXGetFreePort.cpp.o | Bin 0 -> 3904 bytes .../__/ixwebsocket/IXGzipCodec.cpp.o | Bin 0 -> 1248 bytes .../__/ixwebsocket/IXHttp.cpp.o | Bin 0 -> 47568 bytes .../__/ixwebsocket/IXHttpClient.cpp.o | Bin 0 -> 111216 bytes .../__/ixwebsocket/IXHttpServer.cpp.o | Bin 0 -> 60392 bytes .../__/ixwebsocket/IXNetSystem.cpp.o | Bin 0 -> 1904 bytes .../__/ixwebsocket/IXSelectInterrupt.cpp.o | Bin 0 -> 3040 bytes .../IXSelectInterruptFactory.cpp.o | Bin 0 -> 1944 bytes .../ixwebsocket/IXSelectInterruptPipe.cpp.o | Bin 0 -> 11536 bytes .../__/ixwebsocket/IXSetThreadName.cpp.o | Bin 0 -> 1520 bytes .../__/ixwebsocket/IXSocket.cpp.o | Bin 0 -> 14928 bytes .../__/ixwebsocket/IXSocketAppleSSL.cpp.o | Bin 0 -> 680 bytes .../__/ixwebsocket/IXSocketConnect.cpp.o | Bin 0 -> 13328 bytes .../__/ixwebsocket/IXSocketFactory.cpp.o | Bin 0 -> 2648 bytes .../__/ixwebsocket/IXSocketMbedTLS.cpp.o | Bin 0 -> 680 bytes .../__/ixwebsocket/IXSocketOpenSSL.cpp.o | Bin 0 -> 680 bytes .../__/ixwebsocket/IXSocketServer.cpp.o | Bin 0 -> 54488 bytes .../__/ixwebsocket/IXSocketTLSOptions.cpp.o | Bin 0 -> 10848 bytes .../__/ixwebsocket/IXStrCaseCompare.cpp.o | Bin 0 -> 2080 bytes .../__/ixwebsocket/IXUdpSocket.cpp.o | Bin 0 -> 4680 bytes .../__/ixwebsocket/IXUrlParser.cpp.o | Bin 0 -> 13440 bytes .../__/ixwebsocket/IXUserAgent.cpp.o | Bin 0 -> 3624 bytes .../__/ixwebsocket/IXUuid.cpp.o | Bin 0 -> 7808 bytes .../__/ixwebsocket/IXWebSocket.cpp.o | Bin 0 -> 78736 bytes .../IXWebSocketCloseConstants.cpp.o | Bin 0 -> 8640 bytes .../__/ixwebsocket/IXWebSocketHandshake.cpp.o | Bin 0 -> 79152 bytes .../ixwebsocket/IXWebSocketHttpHeaders.cpp.o | Bin 0 -> 13544 bytes .../IXWebSocketPerMessageDeflate.cpp.o | Bin 0 -> 4496 bytes .../IXWebSocketPerMessageDeflateCodec.cpp.o | Bin 0 -> 4072 bytes .../IXWebSocketPerMessageDeflateOptions.cpp.o | Bin 0 -> 4896 bytes .../ixwebsocket/IXWebSocketProxyServer.cpp.o | Bin 0 -> 44192 bytes .../__/ixwebsocket/IXWebSocketServer.cpp.o | Bin 0 -> 39192 bytes .../__/ixwebsocket/IXWebSocketTransport.cpp.o | Bin 0 -> 76512 bytes .../__/websocket/websocket.cpp.o | Bin 0 -> 135856 bytes .../germanairlinesva_xplugin.dir/build.make | 683 + .../cmake_clean.cmake | 49 + .../depend.internal | 408 + .../germanairlinesva_xplugin.dir/depend.make | 408 + .../germanairlinesva_xplugin.dir/flags.make | 10 + .../germanairlinesva_xplugin.dir/link.txt | 1 + .../germanairlinesva_xplugin.dir/main.cpp.o | Bin 0 -> 31952 bytes .../progress.make | 42 + build/xplugin/CMakeFiles/progress.marks | 1 + build/xplugin/Makefile | 1352 + build/xplugin/cmake_install.cmake | 39 + format.sh | 9 + ixwebsocket/IXBench.cpp | 56 + ixwebsocket/IXCancellationRequest.cpp | 39 + ixwebsocket/IXConnectionState.cpp | 54 + ixwebsocket/IXDNSLookup.cpp | 190 + ixwebsocket/IXExponentialBackoff.cpp | 30 + ixwebsocket/IXGetFreePort.cpp | 95 + ixwebsocket/IXGzipCodec.cpp | 186 + ixwebsocket/IXHttp.cpp | 208 + ixwebsocket/IXHttpClient.cpp | 724 + ixwebsocket/IXHttpServer.cpp | 239 + ixwebsocket/IXNetSystem.cpp | 296 + ixwebsocket/IXSelectInterrupt.cpp | 27 + ixwebsocket/IXSelectInterruptFactory.cpp | 26 + ixwebsocket/IXSelectInterruptPipe.cpp | 156 + ixwebsocket/IXSetThreadName.cpp | 81 + ixwebsocket/IXSocket.cpp | 373 + ixwebsocket/IXSocketAppleSSL.cpp | 307 + ixwebsocket/IXSocketConnect.cpp | 150 + ixwebsocket/IXSocketFactory.cpp | 60 + ixwebsocket/IXSocketMbedTLS.cpp | 350 + ixwebsocket/IXSocketOpenSSL.cpp | 761 + ixwebsocket/IXSocketServer.cpp | 467 + ixwebsocket/IXSocketTLSOptions.cpp | 86 + ixwebsocket/IXStrCaseCompare.cpp | 39 + ixwebsocket/IXUdpSocket.cpp | 125 + ixwebsocket/IXUrlParser.cpp | 363 + ixwebsocket/IXUserAgent.cpp | 92 + ixwebsocket/IXUuid.cpp | 75 + ixwebsocket/IXWebSocket.cpp | 588 + ixwebsocket/IXWebSocketCloseConstants.cpp | 46 + ixwebsocket/IXWebSocketHandshake.cpp | 365 + ixwebsocket/IXWebSocketHttpHeaders.cpp | 71 + ixwebsocket/IXWebSocketPerMessageDeflate.cpp | 93 + .../IXWebSocketPerMessageDeflateCodec.cpp | 253 + .../IXWebSocketPerMessageDeflateOptions.cpp | 193 + ixwebsocket/IXWebSocketProxyServer.cpp | 117 + ixwebsocket/IXWebSocketServer.cpp | 206 + ixwebsocket/IXWebSocketTransport.cpp | 1130 + ixwebsocket/License.txt | 29 + ixwebsocket/include/IXBench.h | 32 + ixwebsocket/include/IXCancellationRequest.h | 19 + ixwebsocket/include/IXConnectionState.h | 54 + ixwebsocket/include/IXDNSLookup.h | 73 + ixwebsocket/include/IXExponentialBackoff.h | 17 + ixwebsocket/include/IXGetFreePort.h | 12 + ixwebsocket/include/IXGzipCodec.h | 15 + ixwebsocket/include/IXHttp.h | 117 + ixwebsocket/include/IXHttpClient.h | 126 + ixwebsocket/include/IXHttpServer.h | 62 + ixwebsocket/include/IXNetSystem.h | 87 + ixwebsocket/include/IXProgressCallback.h | 14 + ixwebsocket/include/IXSelectInterrupt.h | 34 + .../include/IXSelectInterruptFactory.h | 16 + ixwebsocket/include/IXSelectInterruptPipe.h | 40 + ixwebsocket/include/IXSetThreadName.h | 12 + ixwebsocket/include/IXSocket.h | 97 + ixwebsocket/include/IXSocketAppleSSL.h | 56 + ixwebsocket/include/IXSocketConnect.h | 32 + ixwebsocket/include/IXSocketFactory.h | 21 + ixwebsocket/include/IXSocketMbedTLS.h | 61 + ixwebsocket/include/IXSocketOpenSSL.h | 75 + ixwebsocket/include/IXSocketServer.h | 134 + ixwebsocket/include/IXSocketTLSOptions.h | 53 + ixwebsocket/include/IXStrCaseCompare.h | 23 + ixwebsocket/include/IXUdpSocket.h | 45 + ixwebsocket/include/IXUniquePtr.h | 18 + ixwebsocket/include/IXUrlParser.h | 23 + ixwebsocket/include/IXUserAgent.h | 14 + ixwebsocket/include/IXUtf8Validator.h | 184 + ixwebsocket/include/IXUuid.h | 17 + ixwebsocket/include/IXWebSocket.h | 174 + .../include/IXWebSocketCloseConstants.h | 36 + ixwebsocket/include/IXWebSocketCloseInfo.h | 27 + ixwebsocket/include/IXWebSocketErrorInfo.h | 21 + ixwebsocket/include/IXWebSocketHandshake.h | 57 + .../include/IXWebSocketHandshakeKeyGen.h | 174 + ixwebsocket/include/IXWebSocketHttpHeaders.h | 25 + ixwebsocket/include/IXWebSocketInitResult.h | 35 + ixwebsocket/include/IXWebSocketMessage.h | 55 + ixwebsocket/include/IXWebSocketMessageType.h | 20 + ixwebsocket/include/IXWebSocketOpenInfo.h | 28 + .../include/IXWebSocketPerMessageDeflate.h | 64 + .../IXWebSocketPerMessageDeflateCodec.h | 60 + .../IXWebSocketPerMessageDeflateOptions.h | 47 + ixwebsocket/include/IXWebSocketProxyServer.h | 24 + ixwebsocket/include/IXWebSocketSendInfo.h | 26 + ixwebsocket/include/IXWebSocketServer.h | 84 + ixwebsocket/include/IXWebSocketTransport.h | 261 + ixwebsocket/include/IXWebSocketVersion.h | 9 + nlohmann/License.txt | 21 + nlohmann/json.hpp | 31780 ++++++++++++++++ toolchain-lin.cmake | 11 + toolchain-mac.cmake | 18 + toolchain-win-32.cmake | 18 + toolchain-win-64.cmake | 18 + websocket/include/types.h | 55 + websocket/include/websocket.h | 62 + websocket/websocket.cpp | 293 + xplugin/CMakeLists.txt | 140 + xplugin/include/main.h | 33 + xplugin/main.cpp | 202 + xplugin/xPluginWin.cpp | 19 + 553 files changed, 155034 insertions(+) create mode 100644 CMakeLists.txt create mode 100644 GermanAirlinesVA-GAConnector/.clang-format create mode 100644 GermanAirlinesVA-GAConnector/.gitattributes create mode 100644 GermanAirlinesVA-GAConnector/.gitignore create mode 100644 GermanAirlinesVA-GAConnector/.idea/.gitignore create mode 100644 GermanAirlinesVA-GAConnector/.idea/.name create mode 100644 GermanAirlinesVA-GAConnector/.idea/GermanAirlinesVA-GAConnector.iml create mode 100644 GermanAirlinesVA-GAConnector/.idea/misc.xml create mode 100644 GermanAirlinesVA-GAConnector/.idea/modules.xml create mode 100644 GermanAirlinesVA-GAConnector/.idea/vcs.xml create mode 100644 GermanAirlinesVA-GAConnector/CMakeLists.txt create mode 100644 GermanAirlinesVA-GAConnector/Jenkinsfile create mode 100644 GermanAirlinesVA-GAConnector/README.md create mode 100644 GermanAirlinesVA-GAConnector/XPSDK/CHeaders/Widgets/XPStandardWidgets.h create mode 100644 GermanAirlinesVA-GAConnector/XPSDK/CHeaders/Widgets/XPUIGraphics.h create mode 100644 GermanAirlinesVA-GAConnector/XPSDK/CHeaders/Widgets/XPWidgetDefs.h create mode 100644 GermanAirlinesVA-GAConnector/XPSDK/CHeaders/Widgets/XPWidgetUtils.h create mode 100644 GermanAirlinesVA-GAConnector/XPSDK/CHeaders/Widgets/XPWidgets.h create mode 100644 GermanAirlinesVA-GAConnector/XPSDK/CHeaders/Wrappers/XPCBroadcaster.cpp create mode 100644 GermanAirlinesVA-GAConnector/XPSDK/CHeaders/Wrappers/XPCBroadcaster.h create mode 100644 GermanAirlinesVA-GAConnector/XPSDK/CHeaders/Wrappers/XPCDisplay.cpp create mode 100644 GermanAirlinesVA-GAConnector/XPSDK/CHeaders/Wrappers/XPCDisplay.h create mode 100644 GermanAirlinesVA-GAConnector/XPSDK/CHeaders/Wrappers/XPCListener.cpp create mode 100644 GermanAirlinesVA-GAConnector/XPSDK/CHeaders/Wrappers/XPCListener.h create mode 100644 GermanAirlinesVA-GAConnector/XPSDK/CHeaders/Wrappers/XPCProcessing.cpp create mode 100644 GermanAirlinesVA-GAConnector/XPSDK/CHeaders/Wrappers/XPCProcessing.h create mode 100644 GermanAirlinesVA-GAConnector/XPSDK/CHeaders/Wrappers/XPCWidget.cpp create mode 100644 GermanAirlinesVA-GAConnector/XPSDK/CHeaders/Wrappers/XPCWidget.h create mode 100644 GermanAirlinesVA-GAConnector/XPSDK/CHeaders/Wrappers/XPCWidgetAttachments.cpp create mode 100644 GermanAirlinesVA-GAConnector/XPSDK/CHeaders/Wrappers/XPCWidgetAttachments.h create mode 100644 GermanAirlinesVA-GAConnector/XPSDK/CHeaders/XPLM/XPLMCamera.h create mode 100644 GermanAirlinesVA-GAConnector/XPSDK/CHeaders/XPLM/XPLMDataAccess.h create mode 100644 GermanAirlinesVA-GAConnector/XPSDK/CHeaders/XPLM/XPLMDefs.h create mode 100644 GermanAirlinesVA-GAConnector/XPSDK/CHeaders/XPLM/XPLMDisplay.h create mode 100644 GermanAirlinesVA-GAConnector/XPSDK/CHeaders/XPLM/XPLMGraphics.h create mode 100644 GermanAirlinesVA-GAConnector/XPSDK/CHeaders/XPLM/XPLMMenus.h create mode 100644 GermanAirlinesVA-GAConnector/XPSDK/CHeaders/XPLM/XPLMNavigation.h create mode 100644 GermanAirlinesVA-GAConnector/XPSDK/CHeaders/XPLM/XPLMPlanes.h create mode 100644 GermanAirlinesVA-GAConnector/XPSDK/CHeaders/XPLM/XPLMPlugin.h create mode 100644 GermanAirlinesVA-GAConnector/XPSDK/CHeaders/XPLM/XPLMProcessing.h create mode 100644 GermanAirlinesVA-GAConnector/XPSDK/CHeaders/XPLM/XPLMScenery.h create mode 100644 GermanAirlinesVA-GAConnector/XPSDK/CHeaders/XPLM/XPLMUtilities.h create mode 100644 GermanAirlinesVA-GAConnector/XPSDK/Delphi/Widgets/XPStandardWidgets.pas create mode 100644 GermanAirlinesVA-GAConnector/XPSDK/Delphi/Widgets/XPUIGraphics.pas create mode 100644 GermanAirlinesVA-GAConnector/XPSDK/Delphi/Widgets/XPWidgetDefs.pas create mode 100644 GermanAirlinesVA-GAConnector/XPSDK/Delphi/Widgets/XPWidgetUtils.pas create mode 100644 GermanAirlinesVA-GAConnector/XPSDK/Delphi/Widgets/XPWidgets.pas create mode 100644 GermanAirlinesVA-GAConnector/XPSDK/Delphi/XPLM/XPLMCamera.pas create mode 100644 GermanAirlinesVA-GAConnector/XPSDK/Delphi/XPLM/XPLMDataAccess.pas create mode 100644 GermanAirlinesVA-GAConnector/XPSDK/Delphi/XPLM/XPLMDefs.pas create mode 100644 GermanAirlinesVA-GAConnector/XPSDK/Delphi/XPLM/XPLMDisplay.pas create mode 100644 GermanAirlinesVA-GAConnector/XPSDK/Delphi/XPLM/XPLMGraphics.pas create mode 100644 GermanAirlinesVA-GAConnector/XPSDK/Delphi/XPLM/XPLMMenus.pas create mode 100644 GermanAirlinesVA-GAConnector/XPSDK/Delphi/XPLM/XPLMNavigation.pas create mode 100644 GermanAirlinesVA-GAConnector/XPSDK/Delphi/XPLM/XPLMPlanes.pas create mode 100644 GermanAirlinesVA-GAConnector/XPSDK/Delphi/XPLM/XPLMPlugin.pas create mode 100644 GermanAirlinesVA-GAConnector/XPSDK/Delphi/XPLM/XPLMProcessing.pas create mode 100644 GermanAirlinesVA-GAConnector/XPSDK/Delphi/XPLM/XPLMScenery.pas create mode 100644 GermanAirlinesVA-GAConnector/XPSDK/Delphi/XPLM/XPLMUtilities.pas create mode 100644 GermanAirlinesVA-GAConnector/XPSDK/Libraries/Mac/XPLM.framework/XPLM create mode 100644 GermanAirlinesVA-GAConnector/XPSDK/Libraries/Mac/XPWidgets.framework/XPWidgets create mode 100644 GermanAirlinesVA-GAConnector/XPSDK/Libraries/Win/XPLM.lib create mode 100644 GermanAirlinesVA-GAConnector/XPSDK/Libraries/Win/XPLM_64.lib create mode 100644 GermanAirlinesVA-GAConnector/XPSDK/Libraries/Win/XPWidgets.lib create mode 100644 GermanAirlinesVA-GAConnector/XPSDK/Libraries/Win/XPWidgets_64.lib create mode 100644 GermanAirlinesVA-GAConnector/XPSDK/README.txt create mode 100644 GermanAirlinesVA-GAConnector/XPSDK/license.txt create mode 100755 GermanAirlinesVA-GAConnector/build.sh create mode 100644 GermanAirlinesVA-GAConnector/ixwebsocket/IXBench.cpp create mode 100644 GermanAirlinesVA-GAConnector/ixwebsocket/IXCancellationRequest.cpp create mode 100644 GermanAirlinesVA-GAConnector/ixwebsocket/IXConnectionState.cpp create mode 100644 GermanAirlinesVA-GAConnector/ixwebsocket/IXDNSLookup.cpp create mode 100644 GermanAirlinesVA-GAConnector/ixwebsocket/IXExponentialBackoff.cpp create mode 100644 GermanAirlinesVA-GAConnector/ixwebsocket/IXGetFreePort.cpp create mode 100644 GermanAirlinesVA-GAConnector/ixwebsocket/IXGzipCodec.cpp create mode 100644 GermanAirlinesVA-GAConnector/ixwebsocket/IXHttp.cpp create mode 100644 GermanAirlinesVA-GAConnector/ixwebsocket/IXHttpClient.cpp create mode 100644 GermanAirlinesVA-GAConnector/ixwebsocket/IXHttpServer.cpp create mode 100644 GermanAirlinesVA-GAConnector/ixwebsocket/IXNetSystem.cpp create mode 100644 GermanAirlinesVA-GAConnector/ixwebsocket/IXSelectInterrupt.cpp create mode 100644 GermanAirlinesVA-GAConnector/ixwebsocket/IXSelectInterruptFactory.cpp create mode 100644 GermanAirlinesVA-GAConnector/ixwebsocket/IXSelectInterruptPipe.cpp create mode 100644 GermanAirlinesVA-GAConnector/ixwebsocket/IXSetThreadName.cpp create mode 100644 GermanAirlinesVA-GAConnector/ixwebsocket/IXSocket.cpp create mode 100644 GermanAirlinesVA-GAConnector/ixwebsocket/IXSocketAppleSSL.cpp create mode 100644 GermanAirlinesVA-GAConnector/ixwebsocket/IXSocketConnect.cpp create mode 100644 GermanAirlinesVA-GAConnector/ixwebsocket/IXSocketFactory.cpp create mode 100644 GermanAirlinesVA-GAConnector/ixwebsocket/IXSocketMbedTLS.cpp create mode 100644 GermanAirlinesVA-GAConnector/ixwebsocket/IXSocketOpenSSL.cpp create mode 100644 GermanAirlinesVA-GAConnector/ixwebsocket/IXSocketServer.cpp create mode 100644 GermanAirlinesVA-GAConnector/ixwebsocket/IXSocketTLSOptions.cpp create mode 100644 GermanAirlinesVA-GAConnector/ixwebsocket/IXStrCaseCompare.cpp create mode 100644 GermanAirlinesVA-GAConnector/ixwebsocket/IXUdpSocket.cpp create mode 100644 GermanAirlinesVA-GAConnector/ixwebsocket/IXUrlParser.cpp create mode 100644 GermanAirlinesVA-GAConnector/ixwebsocket/IXUserAgent.cpp create mode 100644 GermanAirlinesVA-GAConnector/ixwebsocket/IXUuid.cpp create mode 100644 GermanAirlinesVA-GAConnector/ixwebsocket/IXWebSocket.cpp create mode 100644 GermanAirlinesVA-GAConnector/ixwebsocket/IXWebSocketCloseConstants.cpp create mode 100644 GermanAirlinesVA-GAConnector/ixwebsocket/IXWebSocketHandshake.cpp create mode 100644 GermanAirlinesVA-GAConnector/ixwebsocket/IXWebSocketHttpHeaders.cpp create mode 100644 GermanAirlinesVA-GAConnector/ixwebsocket/IXWebSocketPerMessageDeflate.cpp create mode 100644 GermanAirlinesVA-GAConnector/ixwebsocket/IXWebSocketPerMessageDeflateCodec.cpp create mode 100644 GermanAirlinesVA-GAConnector/ixwebsocket/IXWebSocketPerMessageDeflateOptions.cpp create mode 100644 GermanAirlinesVA-GAConnector/ixwebsocket/IXWebSocketProxyServer.cpp create mode 100644 GermanAirlinesVA-GAConnector/ixwebsocket/IXWebSocketServer.cpp create mode 100644 GermanAirlinesVA-GAConnector/ixwebsocket/IXWebSocketTransport.cpp create mode 100644 GermanAirlinesVA-GAConnector/ixwebsocket/License.txt create mode 100644 GermanAirlinesVA-GAConnector/ixwebsocket/include/IXBench.h create mode 100644 GermanAirlinesVA-GAConnector/ixwebsocket/include/IXCancellationRequest.h create mode 100644 GermanAirlinesVA-GAConnector/ixwebsocket/include/IXConnectionState.h create mode 100644 GermanAirlinesVA-GAConnector/ixwebsocket/include/IXDNSLookup.h create mode 100644 GermanAirlinesVA-GAConnector/ixwebsocket/include/IXExponentialBackoff.h create mode 100644 GermanAirlinesVA-GAConnector/ixwebsocket/include/IXGetFreePort.h create mode 100644 GermanAirlinesVA-GAConnector/ixwebsocket/include/IXGzipCodec.h create mode 100644 GermanAirlinesVA-GAConnector/ixwebsocket/include/IXHttp.h create mode 100644 GermanAirlinesVA-GAConnector/ixwebsocket/include/IXHttpClient.h create mode 100644 GermanAirlinesVA-GAConnector/ixwebsocket/include/IXHttpServer.h create mode 100644 GermanAirlinesVA-GAConnector/ixwebsocket/include/IXNetSystem.h create mode 100644 GermanAirlinesVA-GAConnector/ixwebsocket/include/IXProgressCallback.h create mode 100644 GermanAirlinesVA-GAConnector/ixwebsocket/include/IXSelectInterrupt.h create mode 100644 GermanAirlinesVA-GAConnector/ixwebsocket/include/IXSelectInterruptFactory.h create mode 100644 GermanAirlinesVA-GAConnector/ixwebsocket/include/IXSelectInterruptPipe.h create mode 100644 GermanAirlinesVA-GAConnector/ixwebsocket/include/IXSetThreadName.h create mode 100644 GermanAirlinesVA-GAConnector/ixwebsocket/include/IXSocket.h create mode 100644 GermanAirlinesVA-GAConnector/ixwebsocket/include/IXSocketAppleSSL.h create mode 100644 GermanAirlinesVA-GAConnector/ixwebsocket/include/IXSocketConnect.h create mode 100644 GermanAirlinesVA-GAConnector/ixwebsocket/include/IXSocketFactory.h create mode 100644 GermanAirlinesVA-GAConnector/ixwebsocket/include/IXSocketMbedTLS.h create mode 100644 GermanAirlinesVA-GAConnector/ixwebsocket/include/IXSocketOpenSSL.h create mode 100644 GermanAirlinesVA-GAConnector/ixwebsocket/include/IXSocketServer.h create mode 100644 GermanAirlinesVA-GAConnector/ixwebsocket/include/IXSocketTLSOptions.h create mode 100644 GermanAirlinesVA-GAConnector/ixwebsocket/include/IXStrCaseCompare.h create mode 100644 GermanAirlinesVA-GAConnector/ixwebsocket/include/IXUdpSocket.h create mode 100644 GermanAirlinesVA-GAConnector/ixwebsocket/include/IXUniquePtr.h create mode 100644 GermanAirlinesVA-GAConnector/ixwebsocket/include/IXUrlParser.h create mode 100644 GermanAirlinesVA-GAConnector/ixwebsocket/include/IXUserAgent.h create mode 100644 GermanAirlinesVA-GAConnector/ixwebsocket/include/IXUtf8Validator.h create mode 100644 GermanAirlinesVA-GAConnector/ixwebsocket/include/IXUuid.h create mode 100644 GermanAirlinesVA-GAConnector/ixwebsocket/include/IXWebSocket.h create mode 100644 GermanAirlinesVA-GAConnector/ixwebsocket/include/IXWebSocketCloseConstants.h create mode 100644 GermanAirlinesVA-GAConnector/ixwebsocket/include/IXWebSocketCloseInfo.h create mode 100644 GermanAirlinesVA-GAConnector/ixwebsocket/include/IXWebSocketErrorInfo.h create mode 100644 GermanAirlinesVA-GAConnector/ixwebsocket/include/IXWebSocketHandshake.h create mode 100644 GermanAirlinesVA-GAConnector/ixwebsocket/include/IXWebSocketHandshakeKeyGen.h create mode 100644 GermanAirlinesVA-GAConnector/ixwebsocket/include/IXWebSocketHttpHeaders.h create mode 100644 GermanAirlinesVA-GAConnector/ixwebsocket/include/IXWebSocketInitResult.h create mode 100644 GermanAirlinesVA-GAConnector/ixwebsocket/include/IXWebSocketMessage.h create mode 100644 GermanAirlinesVA-GAConnector/ixwebsocket/include/IXWebSocketMessageType.h create mode 100644 GermanAirlinesVA-GAConnector/ixwebsocket/include/IXWebSocketOpenInfo.h create mode 100644 GermanAirlinesVA-GAConnector/ixwebsocket/include/IXWebSocketPerMessageDeflate.h create mode 100644 GermanAirlinesVA-GAConnector/ixwebsocket/include/IXWebSocketPerMessageDeflateCodec.h create mode 100644 GermanAirlinesVA-GAConnector/ixwebsocket/include/IXWebSocketPerMessageDeflateOptions.h create mode 100644 GermanAirlinesVA-GAConnector/ixwebsocket/include/IXWebSocketProxyServer.h create mode 100644 GermanAirlinesVA-GAConnector/ixwebsocket/include/IXWebSocketSendInfo.h create mode 100644 GermanAirlinesVA-GAConnector/ixwebsocket/include/IXWebSocketServer.h create mode 100644 GermanAirlinesVA-GAConnector/ixwebsocket/include/IXWebSocketTransport.h create mode 100644 GermanAirlinesVA-GAConnector/ixwebsocket/include/IXWebSocketVersion.h create mode 100644 GermanAirlinesVA-GAConnector/nlohmann/License.txt create mode 100644 GermanAirlinesVA-GAConnector/nlohmann/json.hpp create mode 100644 GermanAirlinesVA-GAConnector/toolchain-lin.cmake create mode 100644 GermanAirlinesVA-GAConnector/toolchain-mac.cmake create mode 100644 GermanAirlinesVA-GAConnector/toolchain-win-32.cmake create mode 100644 GermanAirlinesVA-GAConnector/toolchain-win-64.cmake create mode 100644 GermanAirlinesVA-GAConnector/websocket/include/types.h create mode 100644 GermanAirlinesVA-GAConnector/websocket/include/websocket.h create mode 100644 GermanAirlinesVA-GAConnector/websocket/websocket.cpp create mode 100644 GermanAirlinesVA-GAConnector/xplugin/CMakeLists.txt create mode 100644 GermanAirlinesVA-GAConnector/xplugin/include/main.h create mode 100644 GermanAirlinesVA-GAConnector/xplugin/main.cpp create mode 100644 GermanAirlinesVA-GAConnector/xplugin/xPluginWin.cpp create mode 100644 Jenkinsfile create mode 100644 XPSDK/CHeaders/Widgets/XPStandardWidgets.h create mode 100644 XPSDK/CHeaders/Widgets/XPUIGraphics.h create mode 100644 XPSDK/CHeaders/Widgets/XPWidgetDefs.h create mode 100644 XPSDK/CHeaders/Widgets/XPWidgetUtils.h create mode 100644 XPSDK/CHeaders/Widgets/XPWidgets.h create mode 100644 XPSDK/CHeaders/Wrappers/XPCBroadcaster.cpp create mode 100644 XPSDK/CHeaders/Wrappers/XPCBroadcaster.h create mode 100644 XPSDK/CHeaders/Wrappers/XPCDisplay.cpp create mode 100644 XPSDK/CHeaders/Wrappers/XPCDisplay.h create mode 100644 XPSDK/CHeaders/Wrappers/XPCListener.cpp create mode 100644 XPSDK/CHeaders/Wrappers/XPCListener.h create mode 100644 XPSDK/CHeaders/Wrappers/XPCProcessing.cpp create mode 100644 XPSDK/CHeaders/Wrappers/XPCProcessing.h create mode 100644 XPSDK/CHeaders/Wrappers/XPCWidget.cpp create mode 100644 XPSDK/CHeaders/Wrappers/XPCWidget.h create mode 100644 XPSDK/CHeaders/Wrappers/XPCWidgetAttachments.cpp create mode 100644 XPSDK/CHeaders/Wrappers/XPCWidgetAttachments.h create mode 100644 XPSDK/CHeaders/XPLM/XPLMCamera.h create mode 100644 XPSDK/CHeaders/XPLM/XPLMDataAccess.h create mode 100644 XPSDK/CHeaders/XPLM/XPLMDefs.h create mode 100644 XPSDK/CHeaders/XPLM/XPLMDisplay.h create mode 100644 XPSDK/CHeaders/XPLM/XPLMGraphics.h create mode 100644 XPSDK/CHeaders/XPLM/XPLMMenus.h create mode 100644 XPSDK/CHeaders/XPLM/XPLMNavigation.h create mode 100644 XPSDK/CHeaders/XPLM/XPLMPlanes.h create mode 100644 XPSDK/CHeaders/XPLM/XPLMPlugin.h create mode 100644 XPSDK/CHeaders/XPLM/XPLMProcessing.h create mode 100644 XPSDK/CHeaders/XPLM/XPLMScenery.h create mode 100644 XPSDK/CHeaders/XPLM/XPLMUtilities.h create mode 100644 XPSDK/Delphi/Widgets/XPStandardWidgets.pas create mode 100644 XPSDK/Delphi/Widgets/XPUIGraphics.pas create mode 100644 XPSDK/Delphi/Widgets/XPWidgetDefs.pas create mode 100644 XPSDK/Delphi/Widgets/XPWidgetUtils.pas create mode 100644 XPSDK/Delphi/Widgets/XPWidgets.pas create mode 100644 XPSDK/Delphi/XPLM/XPLMCamera.pas create mode 100644 XPSDK/Delphi/XPLM/XPLMDataAccess.pas create mode 100644 XPSDK/Delphi/XPLM/XPLMDefs.pas create mode 100644 XPSDK/Delphi/XPLM/XPLMDisplay.pas create mode 100644 XPSDK/Delphi/XPLM/XPLMGraphics.pas create mode 100644 XPSDK/Delphi/XPLM/XPLMMenus.pas create mode 100644 XPSDK/Delphi/XPLM/XPLMNavigation.pas create mode 100644 XPSDK/Delphi/XPLM/XPLMPlanes.pas create mode 100644 XPSDK/Delphi/XPLM/XPLMPlugin.pas create mode 100644 XPSDK/Delphi/XPLM/XPLMProcessing.pas create mode 100644 XPSDK/Delphi/XPLM/XPLMScenery.pas create mode 100644 XPSDK/Delphi/XPLM/XPLMUtilities.pas create mode 100644 XPSDK/Libraries/Mac/XPLM.framework/XPLM create mode 100644 XPSDK/Libraries/Mac/XPWidgets.framework/XPWidgets create mode 100644 XPSDK/Libraries/Win/XPLM.lib create mode 100644 XPSDK/Libraries/Win/XPLM_64.lib create mode 100644 XPSDK/Libraries/Win/XPWidgets.lib create mode 100644 XPSDK/Libraries/Win/XPWidgets_64.lib create mode 100644 XPSDK/README.txt create mode 100644 XPSDK/license.txt create mode 100644 build-lin/.cmake/api/v1/query/cache-v2 create mode 100644 build-lin/.cmake/api/v1/query/cmakeFiles-v1 create mode 100644 build-lin/.cmake/api/v1/query/codemodel-v2 create mode 100644 build-lin/.cmake/api/v1/query/toolchains-v1 create mode 100644 build-lin/.cmake/api/v1/reply/cache-v2-81e32d47656441db6f4b.json create mode 100644 build-lin/.cmake/api/v1/reply/cmakeFiles-v1-f30b6725c229d3c47955.json create mode 100644 build-lin/.cmake/api/v1/reply/codemodel-v2-ca5882791008547413fa.json create mode 100644 build-lin/.cmake/api/v1/reply/directory-.-Debug-f5ebdc15457944623624.json create mode 100644 build-lin/.cmake/api/v1/reply/directory-xplugin-Debug-5600733809e8ef9a4488.json create mode 100644 build-lin/.cmake/api/v1/reply/index-2022-01-01T22-36-30-0832.json create mode 100644 build-lin/.cmake/api/v1/reply/target-germanairlinesva_xplugin-Debug-ae0b9bb84c1b770cea7c.json create mode 100644 build-lin/.cmake/api/v1/reply/toolchains-v1-77b1fedc25d3af5713c5.json create mode 100644 build-lin/CMakeCache.txt create mode 100644 build-lin/CMakeFiles/3.21.1/CMakeCCompiler.cmake create mode 100644 build-lin/CMakeFiles/3.21.1/CMakeCXXCompiler.cmake create mode 100755 build-lin/CMakeFiles/3.21.1/CMakeDetermineCompilerABI_C.bin create mode 100755 build-lin/CMakeFiles/3.21.1/CMakeDetermineCompilerABI_CXX.bin create mode 100644 build-lin/CMakeFiles/3.21.1/CMakeSystem.cmake create mode 100644 build-lin/CMakeFiles/3.21.1/CompilerIdC/CMakeCCompilerId.c create mode 100755 build-lin/CMakeFiles/3.21.1/CompilerIdC/a.out create mode 100644 build-lin/CMakeFiles/3.21.1/CompilerIdCXX/CMakeCXXCompilerId.cpp create mode 100755 build-lin/CMakeFiles/3.21.1/CompilerIdCXX/a.out create mode 100644 build-lin/CMakeFiles/CMakeDirectoryInformation.cmake create mode 100644 build-lin/CMakeFiles/CMakeOutput.log create mode 100644 build-lin/CMakeFiles/Makefile.cmake create mode 100644 build-lin/CMakeFiles/Makefile2 create mode 100644 build-lin/CMakeFiles/TargetDirectories.txt create mode 100644 build-lin/CMakeFiles/VerifyGlobs.cmake create mode 100644 build-lin/CMakeFiles/clion-environment.txt create mode 100644 build-lin/CMakeFiles/clion-log.txt create mode 100644 build-lin/CMakeFiles/cmake.check_cache create mode 100644 build-lin/CMakeFiles/cmake.verify_globs create mode 100644 build-lin/CMakeFiles/progress.marks create mode 100644 build-lin/Makefile create mode 100644 build-lin/cmake_install.cmake create mode 100644 build-lin/xplugin/CMakeFiles/CMakeDirectoryInformation.cmake create mode 100644 build-lin/xplugin/CMakeFiles/germanairlinesva_xplugin.dir/DependInfo.cmake create mode 100644 build-lin/xplugin/CMakeFiles/germanairlinesva_xplugin.dir/build.make create mode 100644 build-lin/xplugin/CMakeFiles/germanairlinesva_xplugin.dir/cmake_clean.cmake create mode 100644 build-lin/xplugin/CMakeFiles/germanairlinesva_xplugin.dir/compiler_depend.make create mode 100644 build-lin/xplugin/CMakeFiles/germanairlinesva_xplugin.dir/compiler_depend.ts create mode 100644 build-lin/xplugin/CMakeFiles/germanairlinesva_xplugin.dir/depend.make create mode 100644 build-lin/xplugin/CMakeFiles/germanairlinesva_xplugin.dir/flags.make create mode 100644 build-lin/xplugin/CMakeFiles/germanairlinesva_xplugin.dir/link.txt create mode 100644 build-lin/xplugin/CMakeFiles/germanairlinesva_xplugin.dir/progress.make create mode 100644 build-lin/xplugin/CMakeFiles/progress.marks create mode 100644 build-lin/xplugin/Makefile create mode 100644 build-lin/xplugin/cmake_install.cmake create mode 100644 build-mac/.cmake/api/v1/query/cache-v2 create mode 100644 build-mac/.cmake/api/v1/query/cmakeFiles-v1 create mode 100644 build-mac/.cmake/api/v1/query/codemodel-v2 create mode 100644 build-mac/.cmake/api/v1/query/toolchains-v1 create mode 100644 build-mac/.cmake/api/v1/reply/cache-v2-675f95f050489ccb94db.json create mode 100644 build-mac/.cmake/api/v1/reply/cmakeFiles-v1-1c218b19e22045540904.json create mode 100644 build-mac/.cmake/api/v1/reply/codemodel-v2-65037702c357d77e645d.json create mode 100644 build-mac/.cmake/api/v1/reply/directory-.-Debug-f5ebdc15457944623624.json create mode 100644 build-mac/.cmake/api/v1/reply/directory-xplugin-Debug-5600733809e8ef9a4488.json create mode 100644 build-mac/.cmake/api/v1/reply/index-2022-01-01T22-36-30-0842.json create mode 100644 build-mac/.cmake/api/v1/reply/target-germanairlinesva_xplugin-Debug-36503d0c3fe46bb75f36.json create mode 100644 build-mac/.cmake/api/v1/reply/toolchains-v1-127409b8a758e6dfad8d.json create mode 100644 build-mac/CMakeCache.txt create mode 100644 build-mac/CMakeFiles/3.21.1/CMakeCCompiler.cmake create mode 100644 build-mac/CMakeFiles/3.21.1/CMakeCXXCompiler.cmake create mode 100755 build-mac/CMakeFiles/3.21.1/CMakeDetermineCompilerABI_C.bin create mode 100755 build-mac/CMakeFiles/3.21.1/CMakeDetermineCompilerABI_CXX.bin create mode 100644 build-mac/CMakeFiles/3.21.1/CMakeSystem.cmake create mode 100644 build-mac/CMakeFiles/3.21.1/CompilerIdC/CMakeCCompilerId.c create mode 100755 build-mac/CMakeFiles/3.21.1/CompilerIdC/a.out create mode 100644 build-mac/CMakeFiles/3.21.1/CompilerIdCXX/CMakeCXXCompilerId.cpp create mode 100755 build-mac/CMakeFiles/3.21.1/CompilerIdCXX/a.out create mode 100644 build-mac/CMakeFiles/CMakeDirectoryInformation.cmake create mode 100644 build-mac/CMakeFiles/CMakeOutput.log create mode 100644 build-mac/CMakeFiles/Makefile.cmake create mode 100644 build-mac/CMakeFiles/Makefile2 create mode 100644 build-mac/CMakeFiles/TargetDirectories.txt create mode 100644 build-mac/CMakeFiles/VerifyGlobs.cmake create mode 100644 build-mac/CMakeFiles/clion-environment.txt create mode 100644 build-mac/CMakeFiles/clion-log.txt create mode 100644 build-mac/CMakeFiles/cmake.check_cache create mode 100644 build-mac/CMakeFiles/cmake.verify_globs create mode 100644 build-mac/CMakeFiles/progress.marks create mode 100644 build-mac/Makefile create mode 100644 build-mac/cmake_install.cmake create mode 100644 build-mac/xplugin/CMakeFiles/CMakeDirectoryInformation.cmake create mode 100644 build-mac/xplugin/CMakeFiles/germanairlinesva_xplugin.dir/DependInfo.cmake create mode 100644 build-mac/xplugin/CMakeFiles/germanairlinesva_xplugin.dir/build.make create mode 100644 build-mac/xplugin/CMakeFiles/germanairlinesva_xplugin.dir/cmake_clean.cmake create mode 100644 build-mac/xplugin/CMakeFiles/germanairlinesva_xplugin.dir/compiler_depend.make create mode 100644 build-mac/xplugin/CMakeFiles/germanairlinesva_xplugin.dir/compiler_depend.ts create mode 100644 build-mac/xplugin/CMakeFiles/germanairlinesva_xplugin.dir/depend.make create mode 100644 build-mac/xplugin/CMakeFiles/germanairlinesva_xplugin.dir/flags.make create mode 100644 build-mac/xplugin/CMakeFiles/germanairlinesva_xplugin.dir/link.txt create mode 100644 build-mac/xplugin/CMakeFiles/germanairlinesva_xplugin.dir/progress.make create mode 100644 build-mac/xplugin/CMakeFiles/progress.marks create mode 100644 build-mac/xplugin/Makefile create mode 100644 build-mac/xplugin/cmake_install.cmake create mode 100644 build-win/.cmake/api/v1/query/cache-v2 create mode 100644 build-win/.cmake/api/v1/query/cmakeFiles-v1 create mode 100644 build-win/.cmake/api/v1/query/codemodel-v2 create mode 100644 build-win/.cmake/api/v1/query/toolchains-v1 create mode 100644 build-win/.cmake/api/v1/reply/cache-v2-aaf1f5c58890f178affe.json create mode 100644 build-win/.cmake/api/v1/reply/cmakeFiles-v1-1917a1c891fc4e27947d.json create mode 100644 build-win/.cmake/api/v1/reply/codemodel-v2-2013d1073c0ff9eab183.json create mode 100644 build-win/.cmake/api/v1/reply/directory-.-Debug-f5ebdc15457944623624.json create mode 100644 build-win/.cmake/api/v1/reply/directory-xplugin-Debug-5600733809e8ef9a4488.json create mode 100644 build-win/.cmake/api/v1/reply/index-2022-01-01T22-36-30-0781.json create mode 100644 build-win/.cmake/api/v1/reply/target-germanairlinesva_xplugin-Debug-1b204b6bb48bb7bc17b8.json create mode 100644 build-win/.cmake/api/v1/reply/toolchains-v1-a31bd5b59156d0a53439.json create mode 100644 build-win/CMakeCache.txt create mode 100644 build-win/CMakeFiles/3.21.1/CMakeCCompiler.cmake create mode 100644 build-win/CMakeFiles/3.21.1/CMakeCXXCompiler.cmake create mode 100755 build-win/CMakeFiles/3.21.1/CMakeDetermineCompilerABI_C.bin create mode 100755 build-win/CMakeFiles/3.21.1/CMakeDetermineCompilerABI_CXX.bin create mode 100644 build-win/CMakeFiles/3.21.1/CMakeRCCompiler.cmake create mode 100644 build-win/CMakeFiles/3.21.1/CMakeSystem.cmake create mode 100644 build-win/CMakeFiles/3.21.1/CompilerIdC/CMakeCCompilerId.c create mode 100755 build-win/CMakeFiles/3.21.1/CompilerIdC/a.exe create mode 100644 build-win/CMakeFiles/3.21.1/CompilerIdCXX/CMakeCXXCompilerId.cpp create mode 100755 build-win/CMakeFiles/3.21.1/CompilerIdCXX/a.exe create mode 100644 build-win/CMakeFiles/CMakeDirectoryInformation.cmake create mode 100644 build-win/CMakeFiles/CMakeOutput.log create mode 100644 build-win/CMakeFiles/Makefile.cmake create mode 100644 build-win/CMakeFiles/Makefile2 create mode 100644 build-win/CMakeFiles/TargetDirectories.txt create mode 100644 build-win/CMakeFiles/VerifyGlobs.cmake create mode 100644 build-win/CMakeFiles/clion-environment.txt create mode 100644 build-win/CMakeFiles/clion-log.txt create mode 100644 build-win/CMakeFiles/cmake.check_cache create mode 100644 build-win/CMakeFiles/cmake.verify_globs create mode 100644 build-win/CMakeFiles/progress.marks create mode 100644 build-win/Makefile create mode 100644 build-win/Testing/Temporary/LastTest.log create mode 100644 build-win/cmake_install.cmake create mode 100644 build-win/xplugin/CMakeFiles/CMakeDirectoryInformation.cmake create mode 100644 build-win/xplugin/CMakeFiles/germanairlinesva_xplugin.dir/DependInfo.cmake create mode 100644 build-win/xplugin/CMakeFiles/germanairlinesva_xplugin.dir/build.make create mode 100644 build-win/xplugin/CMakeFiles/germanairlinesva_xplugin.dir/cmake_clean.cmake create mode 100644 build-win/xplugin/CMakeFiles/germanairlinesva_xplugin.dir/compiler_depend.make create mode 100644 build-win/xplugin/CMakeFiles/germanairlinesva_xplugin.dir/compiler_depend.ts create mode 100644 build-win/xplugin/CMakeFiles/germanairlinesva_xplugin.dir/depend.make create mode 100644 build-win/xplugin/CMakeFiles/germanairlinesva_xplugin.dir/flags.make create mode 100644 build-win/xplugin/CMakeFiles/germanairlinesva_xplugin.dir/includes_CXX.rsp create mode 100644 build-win/xplugin/CMakeFiles/germanairlinesva_xplugin.dir/link.txt create mode 100644 build-win/xplugin/CMakeFiles/germanairlinesva_xplugin.dir/linklibs.rsp create mode 100644 build-win/xplugin/CMakeFiles/germanairlinesva_xplugin.dir/objects1.rsp create mode 100644 build-win/xplugin/CMakeFiles/germanairlinesva_xplugin.dir/progress.make create mode 100644 build-win/xplugin/CMakeFiles/progress.marks create mode 100644 build-win/xplugin/Makefile create mode 100644 build-win/xplugin/cmake_install.cmake create mode 100755 build.sh create mode 100644 build/CMakeCache.txt create mode 100644 build/CMakeFiles/3.16.3/CMakeCCompiler.cmake create mode 100644 build/CMakeFiles/3.16.3/CMakeCXXCompiler.cmake create mode 100755 build/CMakeFiles/3.16.3/CMakeDetermineCompilerABI_C.bin create mode 100755 build/CMakeFiles/3.16.3/CMakeDetermineCompilerABI_CXX.bin create mode 100644 build/CMakeFiles/3.16.3/CMakeSystem.cmake create mode 100644 build/CMakeFiles/3.16.3/CompilerIdC/CMakeCCompilerId.c create mode 100755 build/CMakeFiles/3.16.3/CompilerIdC/a.out create mode 100644 build/CMakeFiles/3.16.3/CompilerIdCXX/CMakeCXXCompilerId.cpp create mode 100755 build/CMakeFiles/3.16.3/CompilerIdCXX/a.out create mode 100644 build/CMakeFiles/CMakeDirectoryInformation.cmake create mode 100644 build/CMakeFiles/CMakeOutput.log create mode 100644 build/CMakeFiles/Makefile.cmake create mode 100644 build/CMakeFiles/Makefile2 create mode 100644 build/CMakeFiles/TargetDirectories.txt create mode 100644 build/CMakeFiles/VerifyGlobs.cmake create mode 100644 build/CMakeFiles/cmake.check_cache create mode 100644 build/CMakeFiles/cmake.verify_globs create mode 100644 build/CMakeFiles/progress.marks create mode 100644 build/Makefile create mode 100755 build/Plugin/GAConnector/64/lin.xpl create mode 100644 build/cmake_install.cmake create mode 100644 build/xplugin/CMakeFiles/CMakeDirectoryInformation.cmake create mode 100644 build/xplugin/CMakeFiles/germanairlinesva_xplugin.dir/CXX.includecache create mode 100644 build/xplugin/CMakeFiles/germanairlinesva_xplugin.dir/DependInfo.cmake create mode 100644 build/xplugin/CMakeFiles/germanairlinesva_xplugin.dir/__/ixwebsocket/IXBench.cpp.o create mode 100644 build/xplugin/CMakeFiles/germanairlinesva_xplugin.dir/__/ixwebsocket/IXCancellationRequest.cpp.o create mode 100644 build/xplugin/CMakeFiles/germanairlinesva_xplugin.dir/__/ixwebsocket/IXConnectionState.cpp.o create mode 100644 build/xplugin/CMakeFiles/germanairlinesva_xplugin.dir/__/ixwebsocket/IXDNSLookup.cpp.o create mode 100644 build/xplugin/CMakeFiles/germanairlinesva_xplugin.dir/__/ixwebsocket/IXExponentialBackoff.cpp.o create mode 100644 build/xplugin/CMakeFiles/germanairlinesva_xplugin.dir/__/ixwebsocket/IXGetFreePort.cpp.o create mode 100644 build/xplugin/CMakeFiles/germanairlinesva_xplugin.dir/__/ixwebsocket/IXGzipCodec.cpp.o create mode 100644 build/xplugin/CMakeFiles/germanairlinesva_xplugin.dir/__/ixwebsocket/IXHttp.cpp.o create mode 100644 build/xplugin/CMakeFiles/germanairlinesva_xplugin.dir/__/ixwebsocket/IXHttpClient.cpp.o create mode 100644 build/xplugin/CMakeFiles/germanairlinesva_xplugin.dir/__/ixwebsocket/IXHttpServer.cpp.o create mode 100644 build/xplugin/CMakeFiles/germanairlinesva_xplugin.dir/__/ixwebsocket/IXNetSystem.cpp.o create mode 100644 build/xplugin/CMakeFiles/germanairlinesva_xplugin.dir/__/ixwebsocket/IXSelectInterrupt.cpp.o create mode 100644 build/xplugin/CMakeFiles/germanairlinesva_xplugin.dir/__/ixwebsocket/IXSelectInterruptFactory.cpp.o create mode 100644 build/xplugin/CMakeFiles/germanairlinesva_xplugin.dir/__/ixwebsocket/IXSelectInterruptPipe.cpp.o create mode 100644 build/xplugin/CMakeFiles/germanairlinesva_xplugin.dir/__/ixwebsocket/IXSetThreadName.cpp.o create mode 100644 build/xplugin/CMakeFiles/germanairlinesva_xplugin.dir/__/ixwebsocket/IXSocket.cpp.o create mode 100644 build/xplugin/CMakeFiles/germanairlinesva_xplugin.dir/__/ixwebsocket/IXSocketAppleSSL.cpp.o create mode 100644 build/xplugin/CMakeFiles/germanairlinesva_xplugin.dir/__/ixwebsocket/IXSocketConnect.cpp.o create mode 100644 build/xplugin/CMakeFiles/germanairlinesva_xplugin.dir/__/ixwebsocket/IXSocketFactory.cpp.o create mode 100644 build/xplugin/CMakeFiles/germanairlinesva_xplugin.dir/__/ixwebsocket/IXSocketMbedTLS.cpp.o create mode 100644 build/xplugin/CMakeFiles/germanairlinesva_xplugin.dir/__/ixwebsocket/IXSocketOpenSSL.cpp.o create mode 100644 build/xplugin/CMakeFiles/germanairlinesva_xplugin.dir/__/ixwebsocket/IXSocketServer.cpp.o create mode 100644 build/xplugin/CMakeFiles/germanairlinesva_xplugin.dir/__/ixwebsocket/IXSocketTLSOptions.cpp.o create mode 100644 build/xplugin/CMakeFiles/germanairlinesva_xplugin.dir/__/ixwebsocket/IXStrCaseCompare.cpp.o create mode 100644 build/xplugin/CMakeFiles/germanairlinesva_xplugin.dir/__/ixwebsocket/IXUdpSocket.cpp.o create mode 100644 build/xplugin/CMakeFiles/germanairlinesva_xplugin.dir/__/ixwebsocket/IXUrlParser.cpp.o create mode 100644 build/xplugin/CMakeFiles/germanairlinesva_xplugin.dir/__/ixwebsocket/IXUserAgent.cpp.o create mode 100644 build/xplugin/CMakeFiles/germanairlinesva_xplugin.dir/__/ixwebsocket/IXUuid.cpp.o create mode 100644 build/xplugin/CMakeFiles/germanairlinesva_xplugin.dir/__/ixwebsocket/IXWebSocket.cpp.o create mode 100644 build/xplugin/CMakeFiles/germanairlinesva_xplugin.dir/__/ixwebsocket/IXWebSocketCloseConstants.cpp.o create mode 100644 build/xplugin/CMakeFiles/germanairlinesva_xplugin.dir/__/ixwebsocket/IXWebSocketHandshake.cpp.o create mode 100644 build/xplugin/CMakeFiles/germanairlinesva_xplugin.dir/__/ixwebsocket/IXWebSocketHttpHeaders.cpp.o create mode 100644 build/xplugin/CMakeFiles/germanairlinesva_xplugin.dir/__/ixwebsocket/IXWebSocketPerMessageDeflate.cpp.o create mode 100644 build/xplugin/CMakeFiles/germanairlinesva_xplugin.dir/__/ixwebsocket/IXWebSocketPerMessageDeflateCodec.cpp.o create mode 100644 build/xplugin/CMakeFiles/germanairlinesva_xplugin.dir/__/ixwebsocket/IXWebSocketPerMessageDeflateOptions.cpp.o create mode 100644 build/xplugin/CMakeFiles/germanairlinesva_xplugin.dir/__/ixwebsocket/IXWebSocketProxyServer.cpp.o create mode 100644 build/xplugin/CMakeFiles/germanairlinesva_xplugin.dir/__/ixwebsocket/IXWebSocketServer.cpp.o create mode 100644 build/xplugin/CMakeFiles/germanairlinesva_xplugin.dir/__/ixwebsocket/IXWebSocketTransport.cpp.o create mode 100644 build/xplugin/CMakeFiles/germanairlinesva_xplugin.dir/__/websocket/websocket.cpp.o create mode 100644 build/xplugin/CMakeFiles/germanairlinesva_xplugin.dir/build.make create mode 100644 build/xplugin/CMakeFiles/germanairlinesva_xplugin.dir/cmake_clean.cmake create mode 100644 build/xplugin/CMakeFiles/germanairlinesva_xplugin.dir/depend.internal create mode 100644 build/xplugin/CMakeFiles/germanairlinesva_xplugin.dir/depend.make create mode 100644 build/xplugin/CMakeFiles/germanairlinesva_xplugin.dir/flags.make create mode 100644 build/xplugin/CMakeFiles/germanairlinesva_xplugin.dir/link.txt create mode 100644 build/xplugin/CMakeFiles/germanairlinesva_xplugin.dir/main.cpp.o create mode 100644 build/xplugin/CMakeFiles/germanairlinesva_xplugin.dir/progress.make create mode 100644 build/xplugin/CMakeFiles/progress.marks create mode 100644 build/xplugin/Makefile create mode 100644 build/xplugin/cmake_install.cmake create mode 100755 format.sh create mode 100644 ixwebsocket/IXBench.cpp create mode 100644 ixwebsocket/IXCancellationRequest.cpp create mode 100644 ixwebsocket/IXConnectionState.cpp create mode 100644 ixwebsocket/IXDNSLookup.cpp create mode 100644 ixwebsocket/IXExponentialBackoff.cpp create mode 100644 ixwebsocket/IXGetFreePort.cpp create mode 100644 ixwebsocket/IXGzipCodec.cpp create mode 100644 ixwebsocket/IXHttp.cpp create mode 100644 ixwebsocket/IXHttpClient.cpp create mode 100644 ixwebsocket/IXHttpServer.cpp create mode 100644 ixwebsocket/IXNetSystem.cpp create mode 100644 ixwebsocket/IXSelectInterrupt.cpp create mode 100644 ixwebsocket/IXSelectInterruptFactory.cpp create mode 100644 ixwebsocket/IXSelectInterruptPipe.cpp create mode 100644 ixwebsocket/IXSetThreadName.cpp create mode 100644 ixwebsocket/IXSocket.cpp create mode 100644 ixwebsocket/IXSocketAppleSSL.cpp create mode 100644 ixwebsocket/IXSocketConnect.cpp create mode 100644 ixwebsocket/IXSocketFactory.cpp create mode 100644 ixwebsocket/IXSocketMbedTLS.cpp create mode 100644 ixwebsocket/IXSocketOpenSSL.cpp create mode 100644 ixwebsocket/IXSocketServer.cpp create mode 100644 ixwebsocket/IXSocketTLSOptions.cpp create mode 100644 ixwebsocket/IXStrCaseCompare.cpp create mode 100644 ixwebsocket/IXUdpSocket.cpp create mode 100644 ixwebsocket/IXUrlParser.cpp create mode 100644 ixwebsocket/IXUserAgent.cpp create mode 100644 ixwebsocket/IXUuid.cpp create mode 100644 ixwebsocket/IXWebSocket.cpp create mode 100644 ixwebsocket/IXWebSocketCloseConstants.cpp create mode 100644 ixwebsocket/IXWebSocketHandshake.cpp create mode 100644 ixwebsocket/IXWebSocketHttpHeaders.cpp create mode 100644 ixwebsocket/IXWebSocketPerMessageDeflate.cpp create mode 100644 ixwebsocket/IXWebSocketPerMessageDeflateCodec.cpp create mode 100644 ixwebsocket/IXWebSocketPerMessageDeflateOptions.cpp create mode 100644 ixwebsocket/IXWebSocketProxyServer.cpp create mode 100644 ixwebsocket/IXWebSocketServer.cpp create mode 100644 ixwebsocket/IXWebSocketTransport.cpp create mode 100644 ixwebsocket/License.txt create mode 100644 ixwebsocket/include/IXBench.h create mode 100644 ixwebsocket/include/IXCancellationRequest.h create mode 100644 ixwebsocket/include/IXConnectionState.h create mode 100644 ixwebsocket/include/IXDNSLookup.h create mode 100644 ixwebsocket/include/IXExponentialBackoff.h create mode 100644 ixwebsocket/include/IXGetFreePort.h create mode 100644 ixwebsocket/include/IXGzipCodec.h create mode 100644 ixwebsocket/include/IXHttp.h create mode 100644 ixwebsocket/include/IXHttpClient.h create mode 100644 ixwebsocket/include/IXHttpServer.h create mode 100644 ixwebsocket/include/IXNetSystem.h create mode 100644 ixwebsocket/include/IXProgressCallback.h create mode 100644 ixwebsocket/include/IXSelectInterrupt.h create mode 100644 ixwebsocket/include/IXSelectInterruptFactory.h create mode 100644 ixwebsocket/include/IXSelectInterruptPipe.h create mode 100644 ixwebsocket/include/IXSetThreadName.h create mode 100644 ixwebsocket/include/IXSocket.h create mode 100644 ixwebsocket/include/IXSocketAppleSSL.h create mode 100644 ixwebsocket/include/IXSocketConnect.h create mode 100644 ixwebsocket/include/IXSocketFactory.h create mode 100644 ixwebsocket/include/IXSocketMbedTLS.h create mode 100644 ixwebsocket/include/IXSocketOpenSSL.h create mode 100644 ixwebsocket/include/IXSocketServer.h create mode 100644 ixwebsocket/include/IXSocketTLSOptions.h create mode 100644 ixwebsocket/include/IXStrCaseCompare.h create mode 100644 ixwebsocket/include/IXUdpSocket.h create mode 100644 ixwebsocket/include/IXUniquePtr.h create mode 100644 ixwebsocket/include/IXUrlParser.h create mode 100644 ixwebsocket/include/IXUserAgent.h create mode 100644 ixwebsocket/include/IXUtf8Validator.h create mode 100644 ixwebsocket/include/IXUuid.h create mode 100644 ixwebsocket/include/IXWebSocket.h create mode 100644 ixwebsocket/include/IXWebSocketCloseConstants.h create mode 100644 ixwebsocket/include/IXWebSocketCloseInfo.h create mode 100644 ixwebsocket/include/IXWebSocketErrorInfo.h create mode 100644 ixwebsocket/include/IXWebSocketHandshake.h create mode 100644 ixwebsocket/include/IXWebSocketHandshakeKeyGen.h create mode 100644 ixwebsocket/include/IXWebSocketHttpHeaders.h create mode 100644 ixwebsocket/include/IXWebSocketInitResult.h create mode 100644 ixwebsocket/include/IXWebSocketMessage.h create mode 100644 ixwebsocket/include/IXWebSocketMessageType.h create mode 100644 ixwebsocket/include/IXWebSocketOpenInfo.h create mode 100644 ixwebsocket/include/IXWebSocketPerMessageDeflate.h create mode 100644 ixwebsocket/include/IXWebSocketPerMessageDeflateCodec.h create mode 100644 ixwebsocket/include/IXWebSocketPerMessageDeflateOptions.h create mode 100644 ixwebsocket/include/IXWebSocketProxyServer.h create mode 100644 ixwebsocket/include/IXWebSocketSendInfo.h create mode 100644 ixwebsocket/include/IXWebSocketServer.h create mode 100644 ixwebsocket/include/IXWebSocketTransport.h create mode 100644 ixwebsocket/include/IXWebSocketVersion.h create mode 100644 nlohmann/License.txt create mode 100644 nlohmann/json.hpp create mode 100644 toolchain-lin.cmake create mode 100644 toolchain-mac.cmake create mode 100644 toolchain-win-32.cmake create mode 100644 toolchain-win-64.cmake create mode 100644 websocket/include/types.h create mode 100644 websocket/include/websocket.h create mode 100644 websocket/websocket.cpp create mode 100644 xplugin/CMakeLists.txt create mode 100644 xplugin/include/main.h create mode 100644 xplugin/main.cpp create mode 100644 xplugin/xPluginWin.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 0000000..ba9aab7 --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,15 @@ +cmake_minimum_required(VERSION 3.8) + +project(GermanAirlinesVA_GAConnector) + +set(CMAKE_CXX_STANDARD 14) +set(CMAKE_CXX_STANDARD_REQUIRED ON) +set(CMAKE_CXX_EXTENSIONS OFF) +set(CMAKE_BUILD_WITH_INSTALL_RPATH TRUE) +set(PLUGIN_NAME GAConnector) + +option(DEBUG "Debug symbols" OFF) + +add_subdirectory( + xplugin +) diff --git a/GermanAirlinesVA-GAConnector/.clang-format b/GermanAirlinesVA-GAConnector/.clang-format new file mode 100644 index 0000000..edb326d --- /dev/null +++ b/GermanAirlinesVA-GAConnector/.clang-format @@ -0,0 +1,54 @@ +Language: Cpp +AccessModifierOffset: -4 +AlignEscapedNewlinesLeft: false +AlignOperands: true +AlignTrailingComments: true +AllowAllArgumentsOnNextLine: false +AllowAllParametersOfDeclarationOnNextLine: false +AlignAfterOpenBracket: Align +AllowShortFunctionsOnASingleLine: true +AllowShortIfStatementsOnASingleLine: false +AllowShortLoopsOnASingleLine: false +AlwaysBreakBeforeMultilineStrings: false +AlwaysBreakTemplateDeclarations: false +BinPackArguments: false +BinPackParameters: false +BreakBeforeBinaryOperators: false +BreakBeforeBraces: Linux +BreakBeforeTernaryOperators: true +BreakConstructorInitializersBeforeComma: false +ColumnLimit: 80 +CommentPragmas: '^ IWYU pragma:' +ConstructorInitializerAllOnOneLineOrOnePerLine: false +ConstructorInitializerIndentWidth: 4 +ContinuationIndentWidth: 4 +Cpp11BracedListStyle: true +DerivePointerBinding: false +ExperimentalAutoDetectBinPacking: false +IndentCaseLabels: true +IndentFunctionDeclarationAfterType: true +IndentWidth: 4 +MaxEmptyLinesToKeep: 2 +NamespaceIndentation: None +ObjCSpaceAfterProperty: true +ObjCSpaceBeforeProtocolList: true +ObjCBlockIndentWidth: 4 +PenaltyBreakBeforeFirstCallParameter: 19 +PenaltyBreakComment: 300 +PenaltyBreakFirstLessLess: 120 +PenaltyBreakString: 1000 +PenaltyExcessCharacter: 100000 +PenaltyReturnTypeOnItsOwnLine: 60 +PointerBindsToType: false +SpaceBeforeAssignmentOperators: true +SpaceBeforeParens: ControlStatements +SpaceInEmptyParentheses: false +SpacesBeforeTrailingComments: 1 +SpacesInAngles: false +SpacesInContainerLiterals: true +SpacesInCStyleCastParentheses: false +SpacesInParentheses: false +Standard: c++14 +SortIncludes: true +TabWidth: 4 +UseTab: Never diff --git a/GermanAirlinesVA-GAConnector/.gitattributes b/GermanAirlinesVA-GAConnector/.gitattributes new file mode 100644 index 0000000..1ff0c42 --- /dev/null +++ b/GermanAirlinesVA-GAConnector/.gitattributes @@ -0,0 +1,63 @@ +############################################################################### +# Set default behavior to automatically normalize line endings. +############################################################################### +* text=auto + +############################################################################### +# Set default behavior for command prompt diff. +# +# This is need for earlier builds of msysgit that does not have it on by +# default for csharp files. +# Note: This is only used by command line +############################################################################### +#*.cs diff=csharp + +############################################################################### +# Set the merge driver for project and solution files +# +# Merging from the command prompt will add diff markers to the files if there +# are conflicts (Merging from VS is not affected by the settings below, in VS +# the diff markers are never inserted). Diff markers may cause the following +# file extensions to fail to load in VS. An alternative would be to treat +# these files as binary and thus will always conflict and require user +# intervention with every merge. To do so, just uncomment the entries below +############################################################################### +#*.sln merge=binary +#*.csproj merge=binary +#*.vbproj merge=binary +#*.vcxproj merge=binary +#*.vcproj merge=binary +#*.dbproj merge=binary +#*.fsproj merge=binary +#*.lsproj merge=binary +#*.wixproj merge=binary +#*.modelproj merge=binary +#*.sqlproj merge=binary +#*.wwaproj merge=binary + +############################################################################### +# behavior for image files +# +# image files are treated as binary by default. +############################################################################### +#*.jpg binary +#*.png binary +#*.gif binary + +############################################################################### +# diff behavior for common document formats +# +# Convert binary document formats to text before diffing them. This feature +# is only available from the command line. Turn it on by uncommenting the +# entries below. +############################################################################### +#*.doc diff=astextplain +#*.DOC diff=astextplain +#*.docx diff=astextplain +#*.DOCX diff=astextplain +#*.dot diff=astextplain +#*.DOT diff=astextplain +#*.pdf diff=astextplain +#*.PDF diff=astextplain +#*.rtf diff=astextplain +#*.RTF diff=astextplain diff --git a/GermanAirlinesVA-GAConnector/.gitignore b/GermanAirlinesVA-GAConnector/.gitignore new file mode 100644 index 0000000..eed511b --- /dev/null +++ b/GermanAirlinesVA-GAConnector/.gitignore @@ -0,0 +1,366 @@ +## Ignore Visual Studio temporary files, build results, and +## files generated by popular Visual Studio add-ons. +## +## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore + +# User-specific files +*.rsuser +*.suo +*.user +*.userosscache +*.sln.docstates + +# User-specific files (MonoDevelop/Xamarin Studio) +*.userprefs + +# Mono auto generated files +mono_crash.* + +# Build results +[Dd]ebug/ +[Dd]ebugPublic/ +[Rr]elease/ +[Rr]eleases/ +x64/ +x86/ +[Ww][Ii][Nn]32/ +[Aa][Rr][Mm]/ +[Aa][Rr][Mm]64/ +bld/ +[Bb]in/ +[Oo]bj/ +[Oo]ut/ +[Ll]og/ +[Ll]ogs/ + +# Visual Studio 2015/2017 cache/options directory +.vs/ +# Uncomment if you have tasks that create the project's static files in wwwroot +#wwwroot/ + +# Visual Studio 2017 auto generated files +Generated\ Files/ + +# MSTest test Results +[Tt]est[Rr]esult*/ +[Bb]uild[Ll]og.* + +# NUnit +*.VisualState.xml +TestResult.xml +nunit-*.xml + +# Build Results of an ATL Project +[Dd]ebugPS/ +[Rr]eleasePS/ +dlldata.c + +# Benchmark Results +BenchmarkDotNet.Artifacts/ + +# .NET Core +project.lock.json +project.fragment.lock.json +artifacts/ + +# ASP.NET Scaffolding +ScaffoldingReadMe.txt + +# StyleCop +StyleCopReport.xml + +# Files built by Visual Studio +*_i.c +*_p.c +*_h.h +*.ilk +*.meta +*.obj +*.iobj +*.pch +*.pdb +*.ipdb +*.pgc +*.pgd +*.rsp +*.sbr +*.tlb +*.tli +*.tlh +*.tmp +*.tmp_proj +*_wpftmp.csproj +*.log +*.vspscc +*.vssscc +.builds +*.pidb +*.svclog +*.scc + +# Chutzpah Test files +_Chutzpah* + +# Visual C++ cache files +ipch/ +*.aps +*.ncb +*.opendb +*.opensdf +*.sdf +*.cachefile +*.VC.db +*.VC.VC.opendb + +# Visual Studio profiler +*.psess +*.vsp +*.vspx +*.sap + +# Visual Studio Trace Files +*.e2e + +# TFS 2012 Local Workspace +$tf/ + +# Guidance Automation Toolkit +*.gpState + +# ReSharper is a .NET coding add-in +_ReSharper*/ +*.[Rr]e[Ss]harper +*.DotSettings.user + +# TeamCity is a build add-in +_TeamCity* + +# DotCover is a Code Coverage Tool +*.dotCover + +# AxoCover is a Code Coverage Tool +.axoCover/* +!.axoCover/settings.json + +# Coverlet is a free, cross platform Code Coverage Tool +coverage*.json +coverage*.xml +coverage*.info + +# Visual Studio code coverage results +*.coverage +*.coveragexml + +# NCrunch +_NCrunch_* +.*crunch*.local.xml +nCrunchTemp_* + +# MightyMoose +*.mm.* +AutoTest.Net/ + +# Web workbench (sass) +.sass-cache/ + +# Installshield output folder +[Ee]xpress/ + +# DocProject is a documentation generator add-in +DocProject/buildhelp/ +DocProject/Help/*.HxT +DocProject/Help/*.HxC +DocProject/Help/*.hhc +DocProject/Help/*.hhk +DocProject/Help/*.hhp +DocProject/Help/Html2 +DocProject/Help/html + +# Click-Once directory +publish/ + +# Publish Web Output +*.[Pp]ublish.xml +*.azurePubxml +# Note: Comment the next line if you want to checkin your web deploy settings, +# but database connection strings (with potential passwords) will be unencrypted +*.pubxml +*.publishproj + +# Microsoft Azure Web App publish settings. Comment the next line if you want to +# checkin your Azure Web App publish settings, but sensitive information contained +# in these scripts will be unencrypted +PublishScripts/ + +# NuGet Packages +*.nupkg +# NuGet Symbol Packages +*.snupkg +# The packages folder can be ignored because of Package Restore +**/[Pp]ackages/* +# except build/, which is used as an MSBuild target. +!**/[Pp]ackages/build/ +# Uncomment if necessary however generally it will be regenerated when needed +#!**/[Pp]ackages/repositories.config +# NuGet v3's project.json files produces more ignorable files +*.nuget.props +*.nuget.targets + +# Microsoft Azure Build Output +csx/ +*.build.csdef + +# Microsoft Azure Emulator +ecf/ +rcf/ + +# Windows Store app package directories and files +AppPackages/ +BundleArtifacts/ +Package.StoreAssociation.xml +_pkginfo.txt +*.appx +*.appxbundle +*.appxupload + +# Visual Studio cache files +# files ending in .cache can be ignored +*.[Cc]ache +# but keep track of directories ending in .cache +!?*.[Cc]ache/ + +# Others +ClientBin/ +~$* +*~ +*.dbmdl +*.dbproj.schemaview +*.jfm +*.pfx +*.publishsettings +orleans.codegen.cs + +# Including strong name files can present a security risk +# (https://github.com/github/gitignore/pull/2483#issue-259490424) +#*.snk + +# Since there are multiple workflows, uncomment next line to ignore bower_components +# (https://github.com/github/gitignore/pull/1529#issuecomment-104372622) +#bower_components/ + +# RIA/Silverlight projects +Generated_Code/ + +# Backup & report files from converting an old project file +# to a newer Visual Studio version. Backup files are not needed, +# because we have git ;-) +_UpgradeReport_Files/ +Backup*/ +UpgradeLog*.XML +UpgradeLog*.htm +ServiceFabricBackup/ +*.rptproj.bak + +# SQL Server files +*.mdf +*.ldf +*.ndf + +# Business Intelligence projects +*.rdl.data +*.bim.layout +*.bim_*.settings +*.rptproj.rsuser +*- [Bb]ackup.rdl +*- [Bb]ackup ([0-9]).rdl +*- [Bb]ackup ([0-9][0-9]).rdl + +# Microsoft Fakes +FakesAssemblies/ + +# GhostDoc plugin setting file +*.GhostDoc.xml + +# Node.js Tools for Visual Studio +.ntvs_analysis.dat +node_modules/ + +# Visual Studio 6 build log +*.plg + +# Visual Studio 6 workspace options file +*.opt + +# Visual Studio 6 auto-generated workspace file (contains which files were open etc.) +*.vbw + +# Visual Studio LightSwitch build output +**/*.HTMLClient/GeneratedArtifacts +**/*.DesktopClient/GeneratedArtifacts +**/*.DesktopClient/ModelManifest.xml +**/*.Server/GeneratedArtifacts +**/*.Server/ModelManifest.xml +_Pvt_Extensions + +# Paket dependency manager +.paket/paket.exe +paket-files/ + +# FAKE - F# Make +.fake/ + +# CodeRush personal settings +.cr/personal + +# Python Tools for Visual Studio (PTVS) +__pycache__/ +*.pyc + +# Cake - Uncomment if you are using it +# tools/** +# !tools/packages.config + +# Tabs Studio +*.tss + +# Telerik's JustMock configuration file +*.jmconfig + +# BizTalk build output +*.btp.cs +*.btm.cs +*.odx.cs +*.xsd.cs + +# OpenCover UI analysis results +OpenCover/ + +# Azure Stream Analytics local run output +ASALocalRun/ + +# MSBuild Binary and Structured Log +*.binlog + +# NVidia Nsight GPU debugger configuration file +*.nvuser + +# MFractors (Xamarin productivity tool) working folder +.mfractor/ + +# Local History for Visual Studio +.localhistory/ + +# BeatPulse healthcheck temp database +healthchecksdb + +# Backup folder for Package Reference Convert tool in Visual Studio 2017 +MigrationBackup/ + +# Ionide (cross platform F# VS Code tools) working folder +.ionide/ + +# Fody - auto-generated XML schema +FodyWeavers.xsd + +# Cmake +build*/ \ No newline at end of file diff --git a/GermanAirlinesVA-GAConnector/.idea/.gitignore b/GermanAirlinesVA-GAConnector/.idea/.gitignore new file mode 100644 index 0000000..13566b8 --- /dev/null +++ b/GermanAirlinesVA-GAConnector/.idea/.gitignore @@ -0,0 +1,8 @@ +# Default ignored files +/shelf/ +/workspace.xml +# Editor-based HTTP Client requests +/httpRequests/ +# Datasource local storage ignored files +/dataSources/ +/dataSources.local.xml diff --git a/GermanAirlinesVA-GAConnector/.idea/.name b/GermanAirlinesVA-GAConnector/.idea/.name new file mode 100644 index 0000000..6abfb67 --- /dev/null +++ b/GermanAirlinesVA-GAConnector/.idea/.name @@ -0,0 +1 @@ +GermanAirlinesVA_GAConnector \ No newline at end of file diff --git a/GermanAirlinesVA-GAConnector/.idea/GermanAirlinesVA-GAConnector.iml b/GermanAirlinesVA-GAConnector/.idea/GermanAirlinesVA-GAConnector.iml new file mode 100644 index 0000000..f08604b --- /dev/null +++ b/GermanAirlinesVA-GAConnector/.idea/GermanAirlinesVA-GAConnector.iml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/GermanAirlinesVA-GAConnector/.idea/misc.xml b/GermanAirlinesVA-GAConnector/.idea/misc.xml new file mode 100644 index 0000000..79b3c94 --- /dev/null +++ b/GermanAirlinesVA-GAConnector/.idea/misc.xml @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/GermanAirlinesVA-GAConnector/.idea/modules.xml b/GermanAirlinesVA-GAConnector/.idea/modules.xml new file mode 100644 index 0000000..ff0f9b0 --- /dev/null +++ b/GermanAirlinesVA-GAConnector/.idea/modules.xml @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file diff --git a/GermanAirlinesVA-GAConnector/.idea/vcs.xml b/GermanAirlinesVA-GAConnector/.idea/vcs.xml new file mode 100644 index 0000000..94a25f7 --- /dev/null +++ b/GermanAirlinesVA-GAConnector/.idea/vcs.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/GermanAirlinesVA-GAConnector/CMakeLists.txt b/GermanAirlinesVA-GAConnector/CMakeLists.txt new file mode 100644 index 0000000..ba9aab7 --- /dev/null +++ b/GermanAirlinesVA-GAConnector/CMakeLists.txt @@ -0,0 +1,15 @@ +cmake_minimum_required(VERSION 3.8) + +project(GermanAirlinesVA_GAConnector) + +set(CMAKE_CXX_STANDARD 14) +set(CMAKE_CXX_STANDARD_REQUIRED ON) +set(CMAKE_CXX_EXTENSIONS OFF) +set(CMAKE_BUILD_WITH_INSTALL_RPATH TRUE) +set(PLUGIN_NAME GAConnector) + +option(DEBUG "Debug symbols" OFF) + +add_subdirectory( + xplugin +) diff --git a/GermanAirlinesVA-GAConnector/Jenkinsfile b/GermanAirlinesVA-GAConnector/Jenkinsfile new file mode 100644 index 0000000..4a0105d --- /dev/null +++ b/GermanAirlinesVA-GAConnector/Jenkinsfile @@ -0,0 +1,127 @@ +pipeline { + agent any + stages { + stage('Build Windows Debug') { + when { + branch 'develop' + beforeAgent true + } + agent { + docker { + image 'llvm-mingw:latest' + reuseNode true + } + } + environment { + DEBUG = 1 + } + steps { + sh 'bash ./build.sh win32' + sh 'bash ./build.sh win64' + } + } + stage('Build Linux Debug') { + when { + branch 'develop' + beforeAgent true + } + agent { + docker { + image 'llvm:latest' + reuseNode true + } + } + environment { + DEBUG = 1 + } + steps { + sh 'bash ./build.sh lin32' + sh 'bash ./build.sh lin64' + } + } + stage('Build MacOSX Debug') { + when { + branch 'develop' + beforeAgent true + } + agent { + docker { + image 'osxcross:latest' + reuseNode true + } + } + environment { + DEBUG = 1 + } + steps { + sh 'bash ./build.sh mac' + } + } + stage('Archive Debug') { + when { + branch 'develop' + } + steps { + zip zipFile: 'Debug.zip', archive: true, dir: 'build/Plugin' + sh 'rm -rf build' + } + } + stage('Build Windows Release') { + when { + branch 'prod' + beforeAgent true + } + agent { + docker { + image 'llvm-mingw:latest' + reuseNode true + } + } + steps { + sh 'bash ./build.sh win32' + sh 'bash ./build.sh win64' + } + } + stage('Build Linux Release') { + when { + branch 'prod' + beforeAgent true + } + agent { + docker { + image 'llvm:latest' + reuseNode true + } + } + steps { + sh 'bash ./build.sh lin32' + sh 'bash ./build.sh lin64' + } + } + stage('Build MacOSX Release') { + when { + branch 'prod' + beforeAgent true + } + agent { + docker { + image 'osxcross:latest' + reuseNode true + } + } + steps { + sh 'bash ./build.sh mac' + } + } + stage('Archive Release') { + when { + branch 'prod' + beforeAgent true + } + steps { + zip zipFile: 'Release.zip', archive: true, dir: 'build/Plugin' + sh 'rm -rf build' + } + } + } +} diff --git a/GermanAirlinesVA-GAConnector/README.md b/GermanAirlinesVA-GAConnector/README.md new file mode 100644 index 0000000..5bc92d2 --- /dev/null +++ b/GermanAirlinesVA-GAConnector/README.md @@ -0,0 +1,11 @@ +### Develop Status +[![Build Status](https://jenkins.hofmannnet.myhome-server.de/job/WebSocketTest/job/develop/badge/icon)](https://jenkins.hofmannnet.myhome-server.de/job/WebSocketTest/job/develop) + +### Prod Status +[![Build Status](https://jenkins.hofmannnet.myhome-server.de/job/WebSocketTest/job/prod/badge/icon)](https://jenkins.hofmannnet.myhome-server.de/job/WebSocketTest/job/prod) + +### Master Status +[![Build Status](https://jenkins.hofmannnet.myhome-server.de/job/WebSocketTest/job/master/badge/icon)](https://jenkins.hofmannnet.myhome-server.de/job/WebSocketTest/job/master) + +X-Plane Plugin for all supported platforms. +Demo of WebSocket capabilities diff --git a/GermanAirlinesVA-GAConnector/XPSDK/CHeaders/Widgets/XPStandardWidgets.h b/GermanAirlinesVA-GAConnector/XPSDK/CHeaders/Widgets/XPStandardWidgets.h new file mode 100644 index 0000000..ee3654c --- /dev/null +++ b/GermanAirlinesVA-GAConnector/XPSDK/CHeaders/Widgets/XPStandardWidgets.h @@ -0,0 +1,628 @@ +#ifndef _XPStandardWidgets_h_ +#define _XPStandardWidgets_h_ + +/* + * Copyright 2005-2012 Sandy Barbour and Ben Supnik + * + * All rights reserved. See license.txt for usage. + * + * X-Plane SDK Version: 2.1.1 + * + */ + +/* + * XPStandardWidgets - THEORY OF OPERATION + * + * The standard widgets are widgets built into the widgets library. While you + * can gain access to the widget function that drives them, you generally use + * them by calling XPCreateWidget and then listening for special messages, + * etc. + * + * The standard widgets often send mesages to themselves when the user + * performs an event; these messages are sent up the widget hierarchy until + * they are handled. So you can add a widget proc directly to a push button + * (for example) to intercept the message when it is clicked, or you can put + * one widget proc on a window for all of the push buttons in the window. + * Most of these messages contain the original widget ID as a parameter so you + * can know which widget is messaging no matter who it is sent to. + * + */ + +#include "XPWidgetDefs.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/*************************************************************************** + * MAIN WINDOW + ***************************************************************************/ +/* + * The main window widget class provides a "window" as the user knows it. + * These windows are dragable and can be selected. Use them to create + * floating windows and non-modal dialogs. + * + */ + + +#define xpWidgetClass_MainWindow 1 + +/* + * Main Window Type Values + * + * These type values are used to control the appearance of a main window. + * + */ +enum { + /* The standard main window; pin stripes on XP7, metal frame on XP 6. */ + xpMainWindowStyle_MainWindow = 0 + + /* A translucent dark gray window, like the one ATC messages appear in. */ + , + xpMainWindowStyle_Translucent = 1 + + +}; + +/* + * Main Window Properties + * + * + */ +enum { + /* This property specifies the type of window. Set to one of the main + * window * types above. */ + xpProperty_MainWindowType = 1100 + + /* This property specifies whether the main window has close boxes in its * + * corners. */ + , + xpProperty_MainWindowHasCloseBoxes = 1200 + + +}; + +/* + * MainWindow Messages + * + * + */ +enum { + /* This message is sent when the close buttons are pressed for your window. + */ + xpMessage_CloseButtonPushed = 1200 + + +}; + +/*************************************************************************** + * SUB WINDOW + ***************************************************************************/ +/* + * X-plane dialogs are divided into separate areas; the sub window widgets + * allow you to make these areas. Create one main window and place several + * subwindows inside it. Then place your controls inside the subwindows. + * + */ + + +#define xpWidgetClass_SubWindow 2 + +/* + * SubWindow Type Values + * + * These values control the appearance of the subwindow. + * + */ +enum { + /* A panel that sits inside a main window. */ + xpSubWindowStyle_SubWindow = 0 + + /* A screen that sits inside a panel for showing text information. */ + , + xpSubWindowStyle_Screen = 2 + + /* A list view for scrolling lists. */ + , + xpSubWindowStyle_ListView = 3 + + +}; + +/* + * SubWindow Properties + * + * + */ +enum { + /* This property specifies the type of window. Set to one of the subwindow + * * types above. */ + xpProperty_SubWindowType = 1200 + + +}; + +/*************************************************************************** + * BUTTON + ***************************************************************************/ +/* + * The button class provides a number of different button styles and + * behaviors, including push buttons, radio buttons, check boxes, etc. The + * button label appears on or next to the button depending on the button's + * appearance, or type. + * + * The button's behavior is a separate property that dictates who it hilights + * and what kinds of messages it sends. Since behavior and type are + * different, you can do strange things like make check boxes that act as push + * buttons or push buttons with radio button behavior. + * + * In X-Plane 6 there were no check box graphics. The result is the following + * behavior: in x-plane 6 all check box and radio buttons are round + * (radio-button style) buttons; in X-Plane 7 they are all square (check-box + * style) buttons. In a future version of x-plane, the xpButtonBehavior enums + * will provide the correct graphic (check box or radio button) giving the + * expected result. + * + */ + + +#define xpWidgetClass_Button 3 + +/* + * Button Types + * + * These define the visual appearance of buttons but not how they respond to + * the mouse. + * + */ +enum { + /* This is a standard push button, like an "OK" or "Cancel" button in a + * dialog * box. */ + xpPushButton = 0 + + /* A check box or radio button. Use this and the button behaviors below to + * * get the desired behavior. */ + , + xpRadioButton = 1 + + /* A window close box. */ + , + xpWindowCloseBox = 3 + + /* A small down arrow. */ + , + xpLittleDownArrow = 5 + + /* A small up arrow. */ + , + xpLittleUpArrow = 6 + + +}; + +/* + * Button Behavior Values + * + * These define how the button responds to mouse clicks. + * + */ +enum { + /* Standard push button behavior. The button hilites while the mouse is * + * clicked over it and unhilites when the mouse is moved outside of it or * + * released. If the mouse is released over the button, the * + * xpMsg_PushButtonPressed message is sent. */ + xpButtonBehaviorPushButton = 0 + + /* Check box behavior. The button immediately toggles its value when the * + * mouse is clicked and sends out a xpMsg_ButtonStateChanged message. */ + , + xpButtonBehaviorCheckBox = 1 + + /* Radio button behavior. The button immediately sets its state to one and + * * sends out a xpMsg_ButtonStateChanged message if it was not already set + * to * one. You must turn off other radio buttons in a group in your + * code. */ + , + xpButtonBehaviorRadioButton = 2 + + +}; + +/* + * Button Properties + * + * + */ +enum { + /* This property sets the visual type of button. Use one of the button + * types * above. */ + xpProperty_ButtonType = 1300 + + /* This property sets the button's behavior. Use one of the button + * behaviors * above. */ + , + xpProperty_ButtonBehavior = 1301 + + /* This property tells whether a check box or radio button is "checked" or * + * not. Not used for push buttons. */ + , + xpProperty_ButtonState = 1302 + + +}; + +/* + * Button Messages + * + * These messages are sent by the button to itself and then up the widget + * chain when the button is clicked. (You may intercept them by providing a + * widget handler for the button itself or by providing a handler in a parent + * widget.) + * + */ +enum { + /* This message is sent when the user completes a click and release in a * + * button with push button behavior. Parameter one of the message is the * + * widget ID of the button. This message is dispatched up the widget * + * hierarchy. */ + xpMsg_PushButtonPressed = 1300 + + /* This message is sent when a button is clicked that has radio button or * + * check box behavior and its value changes. (Note that if the value + * changes * by setting a property you do not receive this message!) + * Parameter one is * the widget ID of the button, parameter 2 is the new + * state value, either * + * zero or one. This message is dispatched up the widget hierarchy. */ + , + xpMsg_ButtonStateChanged = 1301 + + +}; + +/*************************************************************************** + * TEXT FIELD + ***************************************************************************/ +/* + * The text field widget provides an editable text field including mouse + * selection and keyboard navigation. The contents of the text field are its + * descriptor. (The descriptor changes as the user types.) + * + * The text field can have a number of types, that effect the visual layout of + * the text field. The text field sends messages to itself so you may control + * its behavior. + * + * If you need to filter keystrokes, add a new handler and intercept the key + * press message. Since key presses are passed by pointer, you can modify the + * keystroke and pass it through to the text field widget. + * + * WARNING: in x-plane before 7.10 (including 6.70) null characters could + * crash x-plane. To prevent this, wrap this object with a filter function + * (more instructions can be found on the SDK website). + * + */ + + +#define xpWidgetClass_TextField 4 + +/* + * Text Field Type Values + * + * These control the look of the text field. + * + */ +enum { + /* A field for text entry. */ + xpTextEntryField = 0 + + /* A transparent text field. The user can type and the text is drawn, but + * no * background is drawn. You can draw your own background by adding a + * widget * handler and prehandling the draw message. */ + , + xpTextTransparent = 3 + + /* A translucent edit field, dark gray. */ + , + xpTextTranslucent = 4 + + +}; + +/* + * Text Field Properties + * + * + */ +enum { + /* This is the character position the selection starts at, zero based. If it + * * is the same as the end insertion point, the insertion point is not a * + * selection. */ + xpProperty_EditFieldSelStart = 1400 + + /* This is the character position of the end of the selection. */ + , + xpProperty_EditFieldSelEnd = 1401 + + /* This is the character position a drag was started at if the user is * + * dragging to select text, or -1 if a drag is not in progress. */ + , + xpProperty_EditFieldSelDragStart = 1402 + + /* This is the type of text field to display, from the above list. */ + , + xpProperty_TextFieldType = 1403 + + /* Set this property to 1 to password protect the field. Characters will be + * * drawn as *s even though the descriptor will contain plain-text. */ + , + xpProperty_PasswordMode = 1404 + + /* The max number of characters you can enter, if limited. Zero means * + * unlimited. */ + , + xpProperty_MaxCharacters = 1405 + + /* The first visible character on the left. This effectively scrolls the + * text * field. */ + , + xpProperty_ScrollPosition = 1406 + + /* The font to draw the field's text with. (An XPLMFontID.) */ + , + xpProperty_Font = 1407 + + /* This is the active side of the insert selection. (Internal) */ + , + xpProperty_ActiveEditSide = 1408 + + +}; + +/* + * Text Field Messages + * + * + */ +enum { + /* Text Field Messages * + * * + * The text field sends this message to itself when its text changes. It * + * sends the message up the call chain; param1 is the text field's widget + * ID. */ + xpMsg_TextFieldChanged = 1400 + + +}; + +/*************************************************************************** + * SCROLL BAR + ***************************************************************************/ +/* + * A standard scroll bar or slider control. The scroll bar has a minimum, + * maximum and current value that is updated when the user drags it. The + * scroll bar sends continuous messages as it is dragged. + * + */ + + +#define xpWidgetClass_ScrollBar 5 + +/* + * Scroll Bar Type Values + * + * This defines how the scroll bar looks. + * + */ +enum { + /* Scroll bar types. * + * * + * A standard x-plane scroll bar (with arrows on the ends). */ + xpScrollBarTypeScrollBar = 0 + + /* A slider, no arrows. */ + , + xpScrollBarTypeSlider = 1 + + +}; + +/* + * Scroll Bar Properties + * + * + */ +enum { + /* The current position of the thumb (in between the min and max, inclusive) + */ + xpProperty_ScrollBarSliderPosition = 1500 + + /* The value the scroll bar has when the thumb is in the lowest position. */ + , + xpProperty_ScrollBarMin = 1501 + + /* The value the scroll bar has when the thumb is in the highest position. + */ + , + xpProperty_ScrollBarMax = 1502 + + /* How many units to moev the scroll bar when clicking next to the thumb. + * The * scroll bar always moves one unit when the arrows are clicked. */ + , + xpProperty_ScrollBarPageAmount = 1503 + + /* The type of scrollbar from the enums above. */ + , + xpProperty_ScrollBarType = 1504 + + /* Used internally. */ + , + xpProperty_ScrollBarSlop = 1505 + + +}; + +/* + * Scroll Bar Messages + * + * + */ +enum { + /* The Scroll Bar sends this message when the slider position changes. It * + * sends the message up the call chain; param1 is the Scroll Bar widget ID. + */ + xpMsg_ScrollBarSliderPositionChanged = 1500 + + +}; + +/*************************************************************************** + * CAPTION + ***************************************************************************/ +/* + * A caption is a simple widget that shows its descriptor as a string, useful + * for labeling parts of a window. It always shows its descriptor as its + * string and is otherwise transparent. + * + */ + + +#define xpWidgetClass_Caption 6 + +/* + * Caption Properties + * + * + */ +enum { + /* This property specifies whether the caption is lit; use lit captions * + * against screens. */ + xpProperty_CaptionLit = 1600 + + +}; + +/*************************************************************************** + * GENERAL GRAPHICS + ***************************************************************************/ +/* + * The general graphics widget can show one of many icons available from + * x-plane. + * + */ + + +#define xpWidgetClass_GeneralGraphics 7 + +/* + * General Graphics Types Values + * + * These define the icon for the general graphics. + * + */ +enum { + xpShip = 4 + + , + xpILSGlideScope = 5 + + , + xpMarkerLeft = 6 + + , + xp_Airport = 7 + + , + xpNDB = 8 + + , + xpVOR = 9 + + , + xpRadioTower = 10 + + , + xpAircraftCarrier = 11 + + , + xpFire = 12 + + , + xpMarkerRight = 13 + + , + xpCustomObject = 14 + + , + xpCoolingTower = 15 + + , + xpSmokeStack = 16 + + , + xpBuilding = 17 + + , + xpPowerLine = 18 + + , + xpVORWithCompassRose = 19 + + , + xpOilPlatform = 21 + + , + xpOilPlatformSmall = 22 + + , + xpWayPoint = 23 + + +}; + +/* + * General Graphics Properties + * + * + */ +enum { + /* This property controls the type of icon that is drawn. */ + xpProperty_GeneralGraphicsType = 1700 + + +}; + +/*************************************************************************** + * PROGRESS INDICATOR + ***************************************************************************/ +/* + * This widget implements a progress indicator as seen when x-plane starts up. + * + */ + + +#define xpWidgetClass_Progress 8 + +/* + * Progress Indicator Properties + * + * + */ +enum { + /* This is the current value of the progress indicator. */ + xpProperty_ProgressPosition = 1800 + + /* This is the minimum value, equivalent to 0% filled. */ + , + xpProperty_ProgressMin = 1801 + + /* This is the maximum value, equivalent to 100% filled. */ + , + xpProperty_ProgressMax = 1802 + + +}; + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/GermanAirlinesVA-GAConnector/XPSDK/CHeaders/Widgets/XPUIGraphics.h b/GermanAirlinesVA-GAConnector/XPSDK/CHeaders/Widgets/XPUIGraphics.h new file mode 100644 index 0000000..be67bb4 --- /dev/null +++ b/GermanAirlinesVA-GAConnector/XPSDK/CHeaders/Widgets/XPUIGraphics.h @@ -0,0 +1,395 @@ +#ifndef _XPUIGraphics_h_ +#define _XPUIGraphics_h_ + +/* + * Copyright 2005-2012 Sandy Barbour and Ben Supnik + * + * All rights reserved. See license.txt for usage. + * + * X-Plane SDK Version: 2.1.1 + * + */ + +/* + * + * + */ + +#include "XPWidgetDefs.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/*************************************************************************** + * UI GRAPHICS + ***************************************************************************/ +/* + * + * + */ + + +/* + * XPWindowStyle + * + * There are a few built-in window styles in X-Plane that you can use. + * + * Note that X-Plane 6 does not offer real shadow-compositing; you must make + * sure to put a window on top of another window of the right style to the + * shadows work, etc. This applies to elements with insets and shadows. The + * rules are: + * + * Sub windows must go on top of main windows, and screens and list views on + * top of subwindows. Only help and main windows can be over the main screen. + * + * + * With X-Plane 7 any window or element may be placed over any other element. + * + * Some windows are scaled by stretching, some by repeating. The drawing + * routines know which scaling method to use. The list view cannot be + * rescaled in x-plane 6 because it has both a repeating pattern and a + * gradient in one element. All other elements can be rescaled. + * + */ +enum { + /* An LCD screen that shows help. */ + xpWindow_Help = 0 + + /* A dialog box window. */ + , + xpWindow_MainWindow = 1 + + /* A panel or frame within a dialog box window. */ + , + xpWindow_SubWindow = 2 + + /* An LCD screen within a panel to hold text displays. */ + , + xpWindow_Screen = 4 + + /* A list view within a panel for scrolling file names, etc. */ + , + xpWindow_ListView = 5 + + +}; +typedef int XPWindowStyle; + +/* + * XPDrawWindow + * + * This routine draws a window of the given dimensions at the given offset on + * the virtual screen in a given style. The window is automatically scaled as + * appropriate using a bitmap scaling technique (scaling or repeating) as + * appropriate to the style. + * + */ +WIDGET_API void + XPDrawWindow(int inX1, int inY1, int inX2, int inY2, XPWindowStyle inStyle); + +/* + * XPGetWindowDefaultDimensions + * + * This routine returns the default dimensions for a window. Output is either + * a minimum or fixed value depending on whether the window is scalable. + * + */ +WIDGET_API void XPGetWindowDefaultDimensions(XPWindowStyle inStyle, + int *outWidth, /* Can be NULL */ + int *outHeight); /* Can be NULL */ + +/* + * XPElementStyle + * + * Elements are individually drawable UI things like push buttons, etc. The + * style defines what kind of element you are drawing. Elements can be + * stretched in one or two dimensions (depending on the element). Some + * elements can be lit. + * + * In x-plane 6 some elements must be drawn over metal. Some are scalable and + * some are not. Any element can be drawn anywhere in x-plane 7. + * + * Scalable Axis Required Background + * + */ +enum { + /* x metal */ + xpElement_TextField = 6 + + /* none metal */ + , + xpElement_CheckBox = 9 + + /* none metal */ + , + xpElement_CheckBoxLit = 10 + + /* none window header */ + , + xpElement_WindowCloseBox = 14 + + /* none window header */ + , + xpElement_WindowCloseBoxPressed = 15 + + /* x metal */ + , + xpElement_PushButton = 16 + + /* x metal */ + , + xpElement_PushButtonLit = 17 + + /* none any */ + , + xpElement_OilPlatform = 24 + + /* none any */ + , + xpElement_OilPlatformSmall = 25 + + /* none any */ + , + xpElement_Ship = 26 + + /* none any */ + , + xpElement_ILSGlideScope = 27 + + /* none any */ + , + xpElement_MarkerLeft = 28 + + /* none any */ + , + xpElement_Airport = 29 + + /* none any */ + , + xpElement_Waypoint = 30 + + /* none any */ + , + xpElement_NDB = 31 + + /* none any */ + , + xpElement_VOR = 32 + + /* none any */ + , + xpElement_RadioTower = 33 + + /* none any */ + , + xpElement_AircraftCarrier = 34 + + /* none any */ + , + xpElement_Fire = 35 + + /* none any */ + , + xpElement_MarkerRight = 36 + + /* none any */ + , + xpElement_CustomObject = 37 + + /* none any */ + , + xpElement_CoolingTower = 38 + + /* none any */ + , + xpElement_SmokeStack = 39 + + /* none any */ + , + xpElement_Building = 40 + + /* none any */ + , + xpElement_PowerLine = 41 + + /* none metal */ + , + xpElement_CopyButtons = 45 + + /* none metal */ + , + xpElement_CopyButtonsWithEditingGrid = 46 + + /* x, y metal */ + , + xpElement_EditingGrid = 47 + + /* THIS CAN PROBABLY BE REMOVED */ + , + xpElement_ScrollBar = 48 + + /* none any */ + , + xpElement_VORWithCompassRose = 49 + + /* none metal */ + , + xpElement_Zoomer = 51 + + /* x, y metal */ + , + xpElement_TextFieldMiddle = 52 + + /* none metal */ + , + xpElement_LittleDownArrow = 53 + + /* none metal */ + , + xpElement_LittleUpArrow = 54 + + /* none metal */ + , + xpElement_WindowDragBar = 61 + + /* none metal */ + , + xpElement_WindowDragBarSmooth = 62 + + +}; +typedef int XPElementStyle; + +/* + * XPDrawElement + * + * XPDrawElement draws a given element at an offset on the virtual screen in + * set dimensions. EVEN if the element is not scalable, it will be scaled if + * the width and height do not match the preferred dimensions; it'll just look + * ugly. Pass inLit to see the lit version of the element; if the element + * cannot be lit this is ignored. + * + */ +WIDGET_API void XPDrawElement(int inX1, + int inY1, + int inX2, + int inY2, + XPElementStyle inStyle, + int inLit); + +/* + * XPGetElementDefaultDimensions + * + * This routine returns the recommended or minimum dimensions of a given UI + * element. outCanBeLit tells whether the element has both a lit and unlit + * state. Pass NULL to not receive any of these parameters. + * + */ +WIDGET_API void + XPGetElementDefaultDimensions(XPElementStyle inStyle, + int *outWidth, /* Can be NULL */ + int *outHeight, /* Can be NULL */ + int *outCanBeLit); /* Can be NULL */ + +/* + * XPTrackStyle + * + * A track is a UI element that displays a value vertically or horizontally. + * X-Plane has three kinds of tracks: scroll bars, sliders, and progress bars. + * Tracks can be displayed either horizontally or vertically; tracks will + * choose their own layout based on the larger dimension of their dimensions + * (e.g. they know if they are tall or wide). Sliders may be lit or unlit + * (showing the user manipulating them). + * + * ScrollBar - this is a standard scroll bar with arrows and a thumb to drag. + * Slider - this is a simple track with a ball in the middle that can be + * slid. Progress - this is a progress indicator showing how a long task is + * going. + * + */ +enum { + /* not over metal can be lit can be rotated */ + xpTrack_ScrollBar = 0 + + /* over metal can be lit can be rotated */ + , + xpTrack_Slider = 1 + + /* over metal cannot be lit cannot be rotated */ + , + xpTrack_Progress = 2 + + +}; +typedef int XPTrackStyle; + +/* + * XPDrawTrack + * + * This routine draws a track. You pass in the track dimensions and size; the + * track picks the optimal orientation for these dimensions. Pass in the + * track's minimum current and maximum values; the indicator will be + * positioned appropriately. You can also specify whether the track is lit or + * not. + * + */ +WIDGET_API void XPDrawTrack(int inX1, + int inY1, + int inX2, + int inY2, + int inMin, + int inMax, + int inValue, + XPTrackStyle inTrackStyle, + int inLit); + +/* + * XPGetTrackDefaultDimensions + * + * This routine returns a track's default smaller dimension; all tracks are + * scalable in the larger dimension. It also returns whether a track can be + * lit. + * + */ +WIDGET_API void XPGetTrackDefaultDimensions(XPTrackStyle inStyle, + int *outWidth, + int *outCanBeLit); + +/* + * XPGetTrackMetrics + * + * This routine returns the metrics of a track. If you want to write UI code + * to manipulate a track, this routine helps you know where the mouse + * locations are. For most other elements, the rectangle the element is drawn + * in is enough information. However, the scrollbar drawing routine does some + * automatic placement; this routine lets you know where things ended up. You + * pass almost everything you would pass to the draw routine. You get out the + * orientation, and other useful stuff. + * + * Besides orientation, you get five dimensions for the five parts of a + * scrollbar, which are the down button, down area (area before the thumb), + * the thumb, and the up area and button. For horizontal scrollers, the left + * button decreases; for vertical scrollers, the top button decreases. + * + */ +WIDGET_API void XPGetTrackMetrics(int inX1, + int inY1, + int inX2, + int inY2, + int inMin, + int inMax, + int inValue, + XPTrackStyle inTrackStyle, + int *outIsVertical, + int *outDownBtnSize, + int *outDownPageSize, + int *outThumbSize, + int *outUpPageSize, + int *outUpBtnSize); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/GermanAirlinesVA-GAConnector/XPSDK/CHeaders/Widgets/XPWidgetDefs.h b/GermanAirlinesVA-GAConnector/XPSDK/CHeaders/Widgets/XPWidgetDefs.h new file mode 100644 index 0000000..15ae492 --- /dev/null +++ b/GermanAirlinesVA-GAConnector/XPSDK/CHeaders/Widgets/XPWidgetDefs.h @@ -0,0 +1,525 @@ +#ifndef _XPWidgetDefs_h_ +#define _XPWidgetDefs_h_ + +/* + * Copyright 2005-2012 Sandy Barbour and Ben Supnik + * + * All rights reserved. See license.txt for usage. + * + * X-Plane SDK Version: 2.1.1 + * + */ + +/* + * + * + */ + +#include "XPLMDefs.h" + +#ifdef __cplusplus +extern "C" { +#endif + + +#if APL +#if XPWIDGETS +#if __GNUC__ >= 4 +#define WIDGET_API __attribute__((visibility("default"))) +#elif __MACH__ +#define WIDGET_API +#else +#define WIDGET_API __declspec(dllexport) +#endif +#else +#define WIDGET_API +#endif +#elif IBM +#if XPWIDGETS +#define WIDGET_API __declspec(dllexport) +#else +#define WIDGET_API __declspec(dllimport) +#endif +#elif LIN +#if XPWIDGETS +#if __GNUC__ >= 4 +#define WIDGET_API __attribute__((visibility("default"))) +#else +#define WIDGET_API +#endif +#else +#define WIDGET_API +#endif +#else +#pragma error "Platform not defined!" +#endif +/*************************************************************************** + * WIDGET DEFINITIONS + ***************************************************************************/ +/* + * A widget is a call-back driven screen entity like a push-button, window, + * text entry field, etc. + * + * Use the widget API to create widgets of various classes. You can nest them + * into trees of widgets to create complex user interfaces. + * + */ + + +/* + * XPWidgetID + * + * A Widget ID is an opaque unique non-zero handle identifying your widget. + * Use 0 to specify "no widget". This type is defined as wide enough to hold + * a pointer. You receive a widget ID when you create a new widget and then + * use that widget ID to further refer to the widget. + * + */ +typedef void *XPWidgetID; + +/* + * XPWidgetPropertyID + * + * Properties are values attached to instances of your widgets. A property is + * identified by a 32-bit ID and its value is the width of a pointer. + * + * Each widget instance may have a property or not have it. When you set a + * property on a widget for the first time, the property is added to the + * widget; it then stays there for the life of the widget. + * + * Some property IDs are predefined by the widget package; you can make up + * your own property IDs as well. + * + */ +enum { + /* A window's refcon is an opaque value used by client code to find other + * data * based on it. */ + xpProperty_Refcon = 0 + + /* These properties are used by the utlities to implement dragging. */ + , + xpProperty_Dragging = 1 + + , + xpProperty_DragXOff = 2 + + , + xpProperty_DragYOff = 3 + + /* Is the widget hilited? (For widgets that support this kind of thing.) */ + , + xpProperty_Hilited = 4 + + /* Is there a C++ object attached to this widget? */ + , + xpProperty_Object = 5 + + /* If this property is 1, the widget package will use OpenGL to restrict * + * drawing to the Wiget's exposed rectangle. */ + , + xpProperty_Clip = 6 + + /* Is this widget enabled (for those that have a disabled state too)? */ + , + xpProperty_Enabled = 7 + + /* NOTE: Property IDs 1 - 999 are reserved for the widget's library. * + * * + * NOTE: Property IDs 1000 - 9999 are allocated to the standard widget + * classes * provided with the library Properties 1000 - 1099 are for widget + * class 0, * 1100 - 1199 for widget class 1, etc. */ + , + xpProperty_UserStart = 10000 + + +}; +typedef int XPWidgetPropertyID; + +/* + * XPMouseState_t + * + * When the mouse is clicked or dragged, a pointer to this structure is passed + * to your widget function. + * + */ +typedef struct { + int x; + int y; + /* Mouse Button number, left = 0 (right button not yet supported. */ + int button; +#if defined(XPLM200) + /* Scroll wheel delta (button in this case would be the wheel axis number). + */ + int delta; +#endif /* XPLM200 */ +} XPMouseState_t; + +/* + * XPKeyState_t + * + * When a key is pressed, a pointer to this struct is passed to your widget + * function. + * + */ +typedef struct { + /* The ASCII key that was pressed. WARNING: this may be 0 for some + * non-ASCII * key sequences. */ + char key; + /* The flags. Make sure to check this if you only want key-downs! */ + XPLMKeyFlags flags; + /* The virtual key code for the key */ + char vkey; +} XPKeyState_t; + +/* + * XPWidgetGeometryChange_t + * + * This structure contains the deltas for your widget's geometry when it + * changes. + * + */ +typedef struct { + int dx; + /* +Y = the widget moved up */ + int dy; + int dwidth; + int dheight; +} XPWidgetGeometryChange_t; + +/* + * XPDispatchMode + * + * The dispatching modes describe how the widgets library sends out messages. + * Currently there are three modes: + * + */ +enum { + /* The message will only be sent to the target widget. */ + xpMode_Direct = 0 + + /* The message is sent to the target widget, then up the chain of parents * + * until the message is handled or a parentless widget is reached. */ + , + xpMode_UpChain = 1 + + /* The message is sent to the target widget and then all of its children * + * recursively depth-first. */ + , + xpMode_Recursive = 2 + + /* The message is snet just to the target, but goes to every callback, even + * if * it is handled. */ + , + xpMode_DirectAllCallbacks = 3 + + /* The message is only sent to the very first handler even if it is not * + * accepted. (This is really only useful for some internal Widget Lib * + * functions. */ + , + xpMode_Once = 4 + + +}; +typedef int XPDispatchMode; + +/* + * XPWidgetClass + * + * Widget classes define predefined widget types. A widget class basically + * specifies from a library the widget function to be used for the widget. + * Most widgets can be made right from classes. + * + */ +typedef int XPWidgetClass; + +/* An unspecified widget class. Other widget classes are in * + * XPStandardWidgets.h */ +#define xpWidgetClass_None 0 + +/*************************************************************************** + * WIDGET MESSAGES + ***************************************************************************/ +/* + * + * + */ + + +/* + * XPWidgetMessage + * + * Widgets receive 32-bit messages indicating what action is to be taken or + * notifications of events. The list of messages may be expanded. + * + */ +enum { + /* No message, should not be sent. */ + xpMsg_None = 0 + + /* The create message is sent once per widget that is created with your + * widget * function and once for any widget that has your widget function + * attached. * + * * + * Dispatching: Direct * + * * + * Param 1: 1 if you are being added as a subclass, 0 if the widget is first + * * being created. */ + , + xpMsg_Create = 1 + + /* The destroy message is sent once for each message that is destroyed that + * * has your widget function. * + * * + * Dispatching: Direct for all * + * * + * Param 1: 1 if being deleted by a recursive delete to the parent, 0 for * + * explicit deletion. */ + , + xpMsg_Destroy = 2 + + /* The paint message is sent to your widget to draw itself. The paint + * message * is the bare-bones message; in response you must draw yourself, + * draw your * children, set up clipping and culling, check for + * visibility, etc. If you * don't want to do all of this, ignore the + * paint message and a draw message * (see below) will be sent to you. * + * * + * Dispatching: Direct */ + , + xpMsg_Paint = 3 + + /* The draw message is sent to your widget when it is time to draw yourself. + * * OpenGL will be set up to draw in 2-d global screen coordinates, but you + * * should use the XPLM to set up OpenGL state. * + * * + * Dispatching: Direct */ + , + xpMsg_Draw = 4 + + /* The key press message is sent once per key that is pressed. The first * + * parameter is the type of key code (integer or char) and the second is the + * * code itself. By handling this event, you consume the key stroke. * + * * + * Handling this message 'consumes' the keystroke; not handling it passes it + * * to your parent widget. * + * * + * Dispatching: Up Chain * + * * + * : Param 1: A pointer to an XPKeyState_t structure with the keystroke. */ + , + xpMsg_KeyPress = 5 + + /* Keyboard focus is being given to you. By handling this message you + * accept * keyboard focus. The first parameter will be one if a child of + * yours gave * up focus to you, 0 if someone set focus on you explicitly. + * * + * * + * : Handling this message accepts focus; not handling refuses focus. * + * * + * Dispatching: direct * + * * + * Param 1: 1 if you are gaining focus because your child is giving it up, 0 + * * if someone is explicitly giving you focus. */ + , + xpMsg_KeyTakeFocus = 6 + + /* Keyboard focus is being taken away from you. The first parameter will be + * * one if you are losing focus because another widget is taking it, or 0 + * if * someone called the API to make you lose focus explicitly. * + * * + * Dispatching: Direct * + * * + * Param 1: 1 if focus is being taken by another widget, 0 if code requested + * * to remove focus. */ + , + xpMsg_KeyLoseFocus = 7 + + /* You receive one mousedown event per click with a mouse-state structure * + * pointed to by parameter 1, by accepting this you eat the click, otherwise + * * your parent gets it. You will not receive drag and mouse up messages + * if * you do not accept the down message. * + * * + * Handling this message consumes the mouse click, not handling it passes it + * * to the next widget. You can act 'transparent' as a window by never + * handling * moues clicks to certain areas. * + * * + * Dispatching: Up chain NOTE: Technically this is direct dispatched, but + * the * widgets library will shop it to each widget until one consumes the + * click, * making it effectively "up chain". * + * * + * Param 1: A pointer to an XPMouseState_t containing the mouse status. */ + , + xpMsg_MouseDown = 8 + + /* You receive a series of mouse drag messages (typically one per frame in + * the * sim) as the mouse is moved once you have accepted a mouse down + * message. * Parameter one points to a mouse-state structure describing + * the mouse * location. You will continue to receive these until + * the mouse button is * released. You may receive multiple mouse state + * messages with the same mouse * position. You will receive mouse drag + * events even if the mouse is dragged * out of your current or original + * bounds at the time of the mouse down. * + * * + * Dispatching: Direct * + * * + * Param 1: A pointer to an XPMouseState_t containing the mouse status. */ + , + xpMsg_MouseDrag = 9 + + /* The mouseup event is sent once when the mouse button is released after a + * * drag or click. You only receive this message if you accept the + * mouseDown * message. Parameter one points to a mouse state structure. + * * + * * + * Dispatching: Direct * + * * + * Param 1: A pointer to an XPMouseState_t containing the mouse status. */ + , + xpMsg_MouseUp = 10 + + /* Your geometry or a child's geometry is being changed. * + * * + * Dispatching: Up chain * + * * + * Param 1: The widget ID of the original reshaped target. * + * * + * Param 2: A pointer to a XPWidgetGeometryChange_t struct describing the * + * change. */ + , + xpMsg_Reshape = 11 + + /* Your exposed area has changed. * + * * + * Dispatching: Direct */ + , + xpMsg_ExposedChanged = 12 + + /* A child has been added to you. The child's ID is passed in parameter + * one. * + * * + * * + * Dispatching: Direct * + * * + * Param 1: The Widget ID of the child being added. */ + , + xpMsg_AcceptChild = 13 + + /* A child has been removed from to you. The child's ID is passed in * + * parameter one. * + * * + * Dispatching: Direct * + * * + * Param 1: The Widget ID of the child being removed. */ + , + xpMsg_LoseChild = 14 + + /* You now have a new parent, or have no parent. The parent's ID is passed + * * in, or 0 for no parent. * + * * + * Dispatching: Direct * + * * + * Param 1: The Widget ID of your parent */ + , + xpMsg_AcceptParent = 15 + + /* You or a child has been shown. Note that this does not include you being + * * shown because your parent was shown, you were put in a new parent, + * your * root was shown, etc. * + * * + * Dispatching: Up chain * + * * + * Param 1: The widget ID of the shown widget. */ + , + xpMsg_Shown = 16 + + /* You have been hidden. See limitations above. * + * * + * Dispatching: Up chain * + * * + * Param 1: The widget ID of the hidden widget. */ + , + xpMsg_Hidden = 17 + + /* Your descriptor has changed. * + * * + * Dispatching: Direct */ + , + xpMsg_DescriptorChanged = 18 + + /* A property has changed. Param 1 contains the property ID. * + * * + * Dispatching: Direct * + * * + * Param 1: The Property ID being changed. * + * * + * Param 2: The new property value */ + , + xpMsg_PropertyChanged = 19 + +#if defined(XPLM200) + /* The mouse wheel has moved. * + * * + * Return 1 to consume the mouse wheel move, or 0 to pass the message to a * + * parent. Dispatching: Up chain * + * * + * Param 1: A pointer to an XPMouseState_t containing the mouse status. */ + , + xpMsg_MouseWheel = 20 + +#endif /* XPLM200 */ +#if defined(XPLM200) + /* The cursor is over your widget. If you consume this message, change the + * * XPLMCursorStatus value to indicate the desired result, with the same + * rules * as in XPLMDisplay.h. * + * * + * Return 1 to consume this message, 0 to pass it on. * + * * + * Dispatching: Up chain Param 1: A pointer to an XPMouseState_t struct * + * containing the mouse status. * + * * + * Param 2: A pointer to a XPLMCursorStatus - set this to the cursor result + * * you desire. */ + , + xpMsg_CursorAdjust = 21 + +#endif /* XPLM200 */ + /* NOTE: Message IDs 1000 - 9999 are allocated to the standard widget + * classes * provided with the library with 1000 - 1099 for widget class + * 0, 1100 - 1199 * for widget class 1, etc. Message IDs 10,000 and + * beyond are for plugin use. */ + , + xpMsg_UserStart = 10000 + + +}; +typedef int XPWidgetMessage; + +/*************************************************************************** + * WIDGET CALLBACK FUNCTION + ***************************************************************************/ +/* + * + * + */ + + +/* + * XPWidgetFunc_t + * + * This function defines your custom widget's behavior. It will be called by + * the widgets library to send messages to your widget. The message and + * widget ID are passed in, as well as two ptr-width signed parameters whose + * meaning varies with the message. Return 1 to indicate that you have + * processed the message, 0 to indicate that you have not. For any message + * that is not understood, return 0. + * + */ +typedef int (*XPWidgetFunc_t)(XPWidgetMessage inMessage, + XPWidgetID inWidget, + intptr_t inParam1, + intptr_t inParam2); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/GermanAirlinesVA-GAConnector/XPSDK/CHeaders/Widgets/XPWidgetUtils.h b/GermanAirlinesVA-GAConnector/XPSDK/CHeaders/Widgets/XPWidgetUtils.h new file mode 100644 index 0000000..3379491 --- /dev/null +++ b/GermanAirlinesVA-GAConnector/XPSDK/CHeaders/Widgets/XPWidgetUtils.h @@ -0,0 +1,224 @@ +#ifndef _XPWidgetUtils_h_ +#define _XPWidgetUtils_h_ + +/* + * Copyright 2005-2012 Sandy Barbour and Ben Supnik + * + * All rights reserved. See license.txt for usage. + * + * X-Plane SDK Version: 2.1.1 + * + */ + +/* + * XPWidgetUtils - USAGE NOTES + * + * The XPWidgetUtils library contains useful functions that make writing and + * using widgets less of a pain. + * + * One set of functions are the widget behavior functions. These functions + * each add specific useful behaviors to widgets. They can be used in two + * manners: + * + * 1. You can add a widget behavior function to a widget as a callback proc + * using the XPAddWidgetCallback function. The widget will gain that + * behavior. Remember that the last function you add has highest priority. + * You can use this to change or augment the behavior of an existing finished + * widget. + * + * 2. You can call a widget function from inside your own widget function. + * This allows you to include useful behaviors in custom-built widgets. A + * number of the standard widgets get their behavior from this library. To do + * this, call the behavior function from your function first. If it returns + * 1, that means it handled the event and you don't need to; simply return 1. + * + */ + +#include "XPWidgetDefs.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/*************************************************************************** + * GENERAL UTILITIES + ***************************************************************************/ +/* + * + * + */ + + +/* + * Convenience accessors + * + * It can be clumsy accessing the variables passed in by pointer to a struct + * for mouse and reshape messages; these accessors let you simply pass in the + * param right from the arguments of your widget proc and get back the value you + * want. + * + */ +#define MOUSE_X(param) (((XPMouseState_t *)(param))->x) +#define MOUSE_Y(param) (((XPMouseState_t *)(param))->y) + +#define DELTA_X(param) (((XPWidgetGeometryChange_t *)(param))->dx) +#define DELTA_Y(param) (((XPWidgetGeometryChange_t *)(param))->dy) +#define DELTA_W(param) (((XPWidgetGeometryChange_t *)(param))->dwidth) +#define DELTA_H(param) (((XPWidgetGeometryChange_t *)(param))->dheight) + +#define KEY_CHAR(param) (((XPKeyState_t *)(param))->key) +#define KEY_FLAGS(param) (((XPKeyState_t *)(param))->flags) +#define KEY_VKEY(param) (((XPKeyState_t *)(param))->vkey) + +#define IN_RECT(x, y, l, t, r, b) \ + (((x) >= (l)) && ((x) <= (r)) && ((y) >= (b)) && ((y) <= (t))) + +/* + * XPWidgetCreate_t + * + * This structure contains all of the parameters needed to create a wiget. It + * is used with XPUCreateWidgets to create widgets in bulk from an array. All + * parameters correspond to those of XPCreateWidget except for the container + * index. If the container index is equal to the index of a widget in the + * array, the widget in the array passed to XPUCreateWidgets is used as the + * parent of this widget. Note that if you pass an index greater than your + * own position in the array, the parent you are requesting will not exist + * yet. If the container index is NO_PARENT, the parent widget is specified as + * NULL. If the container index is PARAM_PARENT, the widget passed into + * XPUCreateWidgets is used. + * + */ +typedef struct { + int left; + int top; + int right; + int bottom; + int visible; + const char *descriptor; + int isRoot; + int containerIndex; + XPWidgetClass widgetClass; +} XPWidgetCreate_t; + +#define NO_PARENT -1 + +#define PARAM_PARENT -2 + +#define WIDGET_COUNT(x) ((sizeof(x) / sizeof(XPWidgetCreate_t))) + +/* + * XPUCreateWidgets + * + * This function creates a series of widgets from a table...see + * XPCreateWidget_t above. Pass in an array of widget creation structures and + * an array of widget IDs that will receive each widget. + * + * Widget parents are specified by index into the created widget table, + * allowing you to create nested widget structures. You can create multiple + * widget trees in one table. Generally you should create widget trees from + * the top down. + * + * You can also pass in a widget ID that will be used when the widget's parent + * is listed as PARAM_PARENT; this allows you to embed widgets created with + * XPUCreateWidgets in a widget created previously. + * + */ +WIDGET_API void XPUCreateWidgets(const XPWidgetCreate_t *inWidgetDefs, + int inCount, + XPWidgetID inParamParent, + XPWidgetID *ioWidgets); + +/* + * XPUMoveWidgetBy + * + * Simply moves a widget by an amount, +x = right, +y=up, without resizing the + * widget. + * + */ +WIDGET_API void + XPUMoveWidgetBy(XPWidgetID inWidget, int inDeltaX, int inDeltaY); + +/*************************************************************************** + * LAYOUT MANAGERS + ***************************************************************************/ +/* + * The layout managers are widget behavior functions for handling where + * widgets move. Layout managers can be called from a widget function or + * attached to a widget later. + * + */ + + +/* + * XPUFixedLayout + * + * This function causes the widget to maintain its children in fixed position + * relative to itself as it is resized. Use this on the top level 'window' + * widget for your window. + * + */ +WIDGET_API int XPUFixedLayout(XPWidgetMessage inMessage, + XPWidgetID inWidget, + intptr_t inParam1, + intptr_t inParam2); + +/*************************************************************************** + * WIDGET PROC BEHAVIORS + ***************************************************************************/ +/* + * These widget behavior functions add other useful behaviors to widgets. + * These functions cannot be attached to a widget; they must be called from + * your widget function. + * + */ + + +/* + * XPUSelectIfNeeded + * + * This causes the widget to bring its window to the foreground if it is not + * already. inEatClick specifies whether clicks in the background should be + * consumed by bringin the window to the foreground. + * + */ +WIDGET_API int XPUSelectIfNeeded(XPWidgetMessage inMessage, + XPWidgetID inWidget, + intptr_t inParam1, + intptr_t inParam2, + int inEatClick); + +/* + * XPUDefocusKeyboard + * + * This causes a click in the widget to send keyboard focus back to X-Plane. + * This stops editing of any text fields, etc. + * + */ +WIDGET_API int XPUDefocusKeyboard(XPWidgetMessage inMessage, + XPWidgetID inWidget, + intptr_t inParam1, + intptr_t inParam2, + int inEatClick); + +/* + * XPUDragWidget + * + * XPUDragWidget drags the widget in response to mouse clicks. Pass in not + * only the event, but the global coordinates of the drag region, which might + * be a sub-region of your widget (for example, a title bar). + * + */ +WIDGET_API int XPUDragWidget(XPWidgetMessage inMessage, + XPWidgetID inWidget, + intptr_t inParam1, + intptr_t inParam2, + int inLeft, + int inTop, + int inRight, + int inBottom); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/GermanAirlinesVA-GAConnector/XPSDK/CHeaders/Widgets/XPWidgets.h b/GermanAirlinesVA-GAConnector/XPSDK/CHeaders/Widgets/XPWidgets.h new file mode 100644 index 0000000..6cfd277 --- /dev/null +++ b/GermanAirlinesVA-GAConnector/XPSDK/CHeaders/Widgets/XPWidgets.h @@ -0,0 +1,541 @@ +#ifndef _XPWidgets_h_ +#define _XPWidgets_h_ + +/* + * Copyright 2005-2012 Sandy Barbour and Ben Supnik + * + * All rights reserved. See license.txt for usage. + * + * X-Plane SDK Version: 2.1.1 + * + */ + +/* + * WIDGETS - THEORY OF OPERATION AND NOTES + * + * Widgets are persistent view 'objects' for X-Plane. A widget is an object + * referenced by its opaque handle (widget ID) and the APIs in this file. You + * cannot access the widget's guts directly. Every Widget has the following + * intrinsic data: + * + * - A bounding box defined in global screen coordinates with 0,0 in the + * bottom left and +y = up, +x = right. + * + * - A visible box, which is the intersection of the bounding box with the + * widget's parents visible box. + * + * - Zero or one parent widgets. (Always zero if the widget is a root widget. + * + * + * - Zero or more child widgets. + * + * - Whether the widget is a root. Root widgets are the top level plugin + * windows. + * + * - Whether the widget is visible. + * + * - A text string descriptor, whose meaning varies from widget to widget. + * + * - An arbitrary set of 32 bit integral properties defined by 32-bit integral + * keys. This is how specific widgets + * + * store specific data. + * + * - A list of widget callbacks proc that implements the widgets behaviors. + * + * The Widgets library sends messages to widgets to request specific behaviors + * or notify the widget of things. + * + * Widgets may have more than one callback function, in which case messages + * are sent to the most recently added callback function until the message is + * handled. Messages may also be sent to parents or children; see the + * XPWidgetDefs.h header file for the different widget message dispatching + * functions. By adding a callback function to a window you can 'subclass' + * its behavior. + * + * A set of standard widgets are provided that serve common UI purposes. You + * can also customize or implement entirely custom widgets. + * + * Widgets are different than other view hierarchies (most notably Win32, + * which they bear a striking resemblance to) in the following ways: + * + * - Not all behavior can be patched. State that is managed by the XPWidgets + * DLL and not by individual widgets cannot be customized. + * + * - All coordinates are in global screen coordinates. Coordinates are not + * relative to an enclosing widget, nor are they relative to a display window. + * + * + * - Widget messages are always dispatched synchronously, and there is no + * concept of scheduling an update or a dirty region. Messages originate from + * X-Plane as the sim cycle goes by. Since x-plane is constantly redrawing, + * so are widgets; there is no need to mark a part of a widget as 'needing + * redrawing' because redrawing happens frequently whether the widget needs it + * or not. + * + * - Any widget may be a 'root' widget, causing it to be drawn; there is no + * relationship between widget class and rootness. Root widgets are + * imlemented as XPLMDisply windows. + * + */ + +#include "XPWidgetDefs.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/*************************************************************************** + * WIDGET CREATION AND MANAGEMENT + ***************************************************************************/ +/* + * + * + */ + + +/* + * XPCreateWidget + * + * This function creates a new widget and returns the new widget's ID to you. + * If the widget creation fails for some reason, it returns NULL. Widget + * creation will fail either if you pass a bad class ID or if there is not + * adequate memory. + * + * Input Parameters: + * + * - Top, left, bottom, and right in global screen coordinates defining the + * widget's location on the screen. + * + * - inVisible is 1 if the widget should be drawn, 0 to start the widget as + * hidden. + * + * - inDescriptor is a null terminated string that will become the widget's + * descriptor. + * + * - inIsRoot is 1 if this is going to be a root widget, 0 if it will not be. + * + * - inContainer is the ID of this widget's container. It must be 0 for a + * root widget. for a non-root widget, pass the widget ID of the widget to + * place this widget within. If this widget is not going to start inside + * another widget, pass 0; this new widget will then just be floating off in + * space (and will not be drawn until it is placed in a widget. + * + * - inClass is the class of the widget to draw. Use one of the predefined + * class-IDs to create a standard widget. + * + * A note on widget embedding: a widget is only called (and will be drawn, + * etc.) if it is placed within a widget that will be called. Root widgets + * are always called. So it is possible to have whole chains of widgets that + * are simply not called. You can preconstruct widget trees and then place + * them into root widgets later to activate them if you wish. + * + */ +WIDGET_API XPWidgetID XPCreateWidget(int inLeft, + int inTop, + int inRight, + int inBottom, + int inVisible, + const char *inDescriptor, + int inIsRoot, + XPWidgetID inContainer, + XPWidgetClass inClass); + +/* + * XPCreateCustomWidget + * + * This function is the same as XPCreateWidget except that instead of passing + * a class ID, you pass your widget callback function pointer defining the + * widget. Use this function to define a custom widget. All parameters are + * the same as XPCreateWidget, except that the widget class has been replaced + * with the widget function. + * + */ +WIDGET_API XPWidgetID XPCreateCustomWidget(int inLeft, + int inTop, + int inRight, + int inBottom, + int inVisible, + const char *inDescriptor, + int inIsRoot, + XPWidgetID inContainer, + XPWidgetFunc_t inCallback); + +/* + * XPDestroyWidget + * + * This class destroys a widget. Pass in the ID of the widget to kill. If + * you pass 1 for inDestroyChilren, the widget's children will be destroyed + * first, then this widget will be destroyed. (Furthermore, the widget's + * children will be destroyed with the inDestroyChildren flag set to 1, so the + * destruction will recurse down the widget tree.) If you pass 0 for this + * flag, the child widgets will simply end up with their parent set to 0. + * + */ +WIDGET_API void XPDestroyWidget(XPWidgetID inWidget, int inDestroyChildren); + +/* + * XPSendMessageToWidget + * + * This sends any message to a widget. You should probably not go around + * simulating the predefined messages that the widgets library defines for + * you. You may however define custom messages for your widgets and send them + * with this method. + * + * This method supports several dispatching patterns; see XPDispatchMode for + * more info. The function returns 1 if the message was handled, 0 if it was + * not. + * + * For each widget that receives the message (see the dispatching modes), each + * widget function from the most recently installed to the oldest one + * receives the message in order until it is handled. + * + */ +WIDGET_API int XPSendMessageToWidget(XPWidgetID inWidget, + XPWidgetMessage inMessage, + XPDispatchMode inMode, + intptr_t inParam1, + intptr_t inParam2); + +/*************************************************************************** + * WIDGET POSITIONING AND VISIBILITY + ***************************************************************************/ +/* + * + * + */ + + +/* + * XPPlaceWidgetWithin + * + * This function changes which container a widget resides in. You may NOT use + * this function on a root widget! inSubWidget is the widget that will be + * moved. Pass a widget ID in inContainer to make inSubWidget be a child of + * inContainer. It will become the last/closest widget in the container. + * Pass 0 to remove the widget from any container. Any call to this other + * than passing the widget ID of the old parent of the affected widget will + * cause the widget to be removed from its old parent. Placing a widget within + * its own parent simply makes it the last widget. + * + * NOTE: this routine does not reposition the sub widget in global + * coordinates. If the container has layout management code, it will + * reposition the subwidget for you, otherwise you must do it with + * SetWidgetGeometry. + * + */ +WIDGET_API void XPPlaceWidgetWithin(XPWidgetID inSubWidget, + XPWidgetID inContainer); + +/* + * XPCountChildWidgets + * + * This routine returns the number of widgets another widget contains. + * + */ +WIDGET_API int XPCountChildWidgets(XPWidgetID inWidget); + +/* + * XPGetNthChildWidget + * + * This routine returns the widget ID of a child widget by index. Indexes are + * 0 based, from 0 to one minus the number of widgets in the parent, + * inclusive. If the index is invalid, 0 is returned. + * + */ +WIDGET_API XPWidgetID XPGetNthChildWidget(XPWidgetID inWidget, int inIndex); + +/* + * XPGetParentWidget + * + * This routine returns the parent of a widget, or 0 if the widget has no + * parent. Root widgets never have parents and therefore always return 0. + * + */ +WIDGET_API XPWidgetID XPGetParentWidget(XPWidgetID inWidget); + +/* + * XPShowWidget + * + * This routine makes a widget visible if it is not already. Note that if a + * widget is not in a rooted widget hierarchy or one of its parents is not + * visible, it will still not be visible to the user. + * + */ +WIDGET_API void XPShowWidget(XPWidgetID inWidget); + +/* + * XPHideWidget + * + * Makes a widget invisible. See XPShowWidget for considerations of when a + * widget might not be visible despite its own visibility state. + * + */ +WIDGET_API void XPHideWidget(XPWidgetID inWidget); + +/* + * XPIsWidgetVisible + * + * This returns 1 if a widget is visible, 0 if it is not. Note that this + * routine takes into consideration whether a parent is invisible. Use this + * routine to tell if the user can see the widget. + * + */ +WIDGET_API int XPIsWidgetVisible(XPWidgetID inWidget); + +/* + * XPFindRootWidget + * + * XPFindRootWidget returns the Widget ID of the root widget that contains the + * passed in widget or NULL if the passed in widget is not in a rooted + * hierarchy. + * + */ +WIDGET_API XPWidgetID XPFindRootWidget(XPWidgetID inWidget); + +/* + * XPBringRootWidgetToFront + * + * This routine makes the specified widget be in the front most widget + * hierarchy. If this widget is a root widget, its widget hierarchy comes to + * front, otherwise the widget's root is brought to the front. If this widget + * is not in an active widget hiearchy (e.g. there is no root widget at the + * top of the tree), this routine does nothing. + * + */ +WIDGET_API void XPBringRootWidgetToFront(XPWidgetID inWidget); + +/* + * XPIsWidgetInFront + * + * This routine returns true if this widget's hierarchy is the front most + * hierarchy. It returns false if the widget's hierarchy is not in front, or + * if the widget is not in a rooted hierarchy. + * + */ +WIDGET_API int XPIsWidgetInFront(XPWidgetID inWidget); + +/* + * XPGetWidgetGeometry + * + * This routine returns the bounding box of a widget in global coordinates. + * Pass NULL for any parameter you are not interested in. + * + */ +WIDGET_API void XPGetWidgetGeometry(XPWidgetID inWidget, + int *outLeft, /* Can be NULL */ + int *outTop, /* Can be NULL */ + int *outRight, /* Can be NULL */ + int *outBottom); /* Can be NULL */ + +/* + * XPSetWidgetGeometry + * + * This function changes the bounding box of a widget. + * + */ +WIDGET_API void XPSetWidgetGeometry(XPWidgetID inWidget, + int inLeft, + int inTop, + int inRight, + int inBottom); + +/* + * XPGetWidgetForLocation + * + * Given a widget and a location, this routine returns the widget ID of the + * child of that widget that owns that location. If inRecursive is true then + * this will return a child of a child of a widget as it tries to find the + * deepest widget at that location. If inVisibleOnly is true, then only + * visible widgets are considered, otherwise all widgets are considered. The + * widget ID passed for inContainer will be returned if the location is in + * that widget but not in a child widget. 0 is returned if the location is + * not in the container. + * + * NOTE: if a widget's geometry extends outside its parents geometry, it will + * not be returned by this call for mouse locations outside the parent + * geometry. The parent geometry limits the child's eligibility for mouse + * location. + * + */ +WIDGET_API XPWidgetID XPGetWidgetForLocation(XPWidgetID inContainer, + int inXOffset, + int inYOffset, + int inRecursive, + int inVisibleOnly); + +/* + * XPGetWidgetExposedGeometry + * + * This routine returns the bounds of the area of a widget that is completely + * within its parent widgets. Since a widget's bounding box can be outside + * its parent, part of its area will not be elligible for mouse clicks and + * should not draw. Use XPGetWidgetGeometry to find out what area defines + * your widget's shape, but use this routine to find out what area to actually + * draw into. Note that the widget library does not use OpenGL clipping to + * keep frame rates up, although you could use it internally. + * + */ +WIDGET_API void XPGetWidgetExposedGeometry(XPWidgetID inWidgetID, + int *outLeft, /* Can be NULL */ + int *outTop, /* Can be NULL */ + int *outRight, /* Can be NULL */ + int *outBottom); /* Can be NULL */ + +/*************************************************************************** + * ACCESSING WIDGET DATA + ***************************************************************************/ +/* + * + * + */ + + +/* + * XPSetWidgetDescriptor + * + * Every widget has a descriptor, which is a text string. What the text + * string is used for varies from widget to widget; for example, a push + * button's text is its descriptor, a caption shows its descriptor, and a text + * field's descriptor is the text being edited. In other words, the usage for + * the text varies from widget to widget, but this API provides a universal + * and convenient way to get at it. While not all UI widgets need their + * descriptor, many do. + * + */ +WIDGET_API void XPSetWidgetDescriptor(XPWidgetID inWidget, + const char *inDescriptor); + +/* + * XPGetWidgetDescriptor + * + * This routine returns the widget's descriptor. Pass in the length of the + * buffer you are going to receive the descriptor in. The descriptor will be + * null terminated for you. This routine returns the length of the actual + * descriptor; if you pass NULL for outDescriptor, you can get the + * descriptor's length without getting its text. If the length of the + * descriptor exceeds your buffer length, the buffer will not be null + * terminated (this routine has 'strncpy' semantics). + * + */ +WIDGET_API int XPGetWidgetDescriptor(XPWidgetID inWidget, + char *outDescriptor, + int inMaxDescLength); + +/* + * XPSetWidgetProperty + * + * This function sets a widget's property. Properties are arbitrary values + * associated by a widget by ID. + * + */ +WIDGET_API void XPSetWidgetProperty(XPWidgetID inWidget, + XPWidgetPropertyID inProperty, + intptr_t inValue); + +/* + * XPGetWidgetProperty + * + * This routine returns the value of a widget's property, or 0 if the property + * is not defined. If you need to know whether the property is defined, pass + * a pointer to an int for inExists; the existence of that property will be + * returned in the int. Pass NULL for inExists if you do not need this + * information. + * + */ +WIDGET_API intptr_t XPGetWidgetProperty(XPWidgetID inWidget, + XPWidgetPropertyID inProperty, + int *inExists); /* Can be NULL */ + +/*************************************************************************** + * KEYBOARD MANAGEMENT + ***************************************************************************/ +/* + * + * + */ + + +/* + * XPSetKeyboardFocus + * + * XPSetKeyboardFocus controls which widget will receive keystrokes. Pass the + * Widget ID of the widget to get the keys. Note that if the widget does not + * care about keystrokes, they will go to the parent widget, and if no widget + * cares about them, they go to X-Plane. + * + * If you set the keyboard focus to Widget ID 0, X-Plane gets keyboard focus. + * + * This routine returns the widget ID that ended up with keyboard focus, or 0 + * for x-plane. + * + * Keyboard focus is not changed if the new widget will not accept it. For + * setting to x-plane, keyboard focus is always accepted. + * + * * + */ +WIDGET_API XPWidgetID XPSetKeyboardFocus(XPWidgetID inWidget); + +/* + * XPLoseKeyboardFocus + * + * This causes the specified widget to lose focus; focus is passed to its + * parent, or the next parent that will accept it. This routine does nothing + * if this widget does not have focus. + * + */ +WIDGET_API void XPLoseKeyboardFocus(XPWidgetID inWidget); + +/* + * XPGetWidgetWithFocus + * + * This routine returns the widget that has keyboard focus, or 0 if X-Plane + * has keyboard focus or some other plugin window that does not have widgets + * has focus. + * + */ +WIDGET_API XPWidgetID XPGetWidgetWithFocus(void); + +/*************************************************************************** + * CREATING CUSTOM WIDGETS + ***************************************************************************/ +/* + * + * + */ + + +/* + * XPAddWidgetCallback + * + * This function adds a new widget callback to a widget. This widget callback + * supercedes any existing ones and will receive messages first; if it does + * not handle messages they will go on to be handled by pre-existing widgets. + * + * The widget function will remain on the widget for the life of the widget. + * The creation message will be sent to the new callback immediately with the + * widget ID, and the destruction message will be sent before the other widget + * function receives a destruction message. + * + * This provides a way to 'subclass' an existing widget. By providing a + * second hook that only handles certain widget messages, you can customize or + * extend widget behavior. + * + */ +WIDGET_API void XPAddWidgetCallback(XPWidgetID inWidget, + XPWidgetFunc_t inNewCallback); + +/* + * XPGetWidgetClassFunc + * + * Given a widget class, this function returns the callbacks that power that + * widget class. + * + */ +WIDGET_API XPWidgetFunc_t XPGetWidgetClassFunc(XPWidgetClass inWidgetClass); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/GermanAirlinesVA-GAConnector/XPSDK/CHeaders/Wrappers/XPCBroadcaster.cpp b/GermanAirlinesVA-GAConnector/XPSDK/CHeaders/Wrappers/XPCBroadcaster.cpp new file mode 100644 index 0000000..97c14b9 --- /dev/null +++ b/GermanAirlinesVA-GAConnector/XPSDK/CHeaders/Wrappers/XPCBroadcaster.cpp @@ -0,0 +1,45 @@ +#include "XPCBroadcaster.h" +#include "XPCListener.h" + +XPCBroadcaster::XPCBroadcaster() : mIterator(NULL) {} + +XPCBroadcaster::~XPCBroadcaster() +{ + ListenerVector::iterator iter; + mIterator = &iter; + for (iter = mListeners.begin(); iter != mListeners.end(); ++iter) { + (*iter)->BroadcasterRemoved(this); + } +} + +void XPCBroadcaster::AddListener(XPCListener *inListener) +{ + mListeners.push_back(inListener); + inListener->BroadcasterAdded(this); +} + +void XPCBroadcaster::RemoveListener(XPCListener *inListener) +{ + ListenerVector::iterator iter = + std::find(mListeners.begin(), mListeners.end(), inListener); + if (iter == mListeners.end()) + return; + + if (mIterator != NULL) { + if (*mIterator >= iter) + (*mIterator)--; + } + + mListeners.erase(iter); + inListener->BroadcasterRemoved(this); +} + +void XPCBroadcaster::BroadcastMessage(int inMessage, void *inParam) +{ + ListenerVector::iterator iter; + mIterator = &iter; + for (iter = mListeners.begin(); iter != mListeners.end(); ++iter) { + (*iter)->ListenToMessage(inMessage, inParam); + } + mIterator = NULL; +} diff --git a/GermanAirlinesVA-GAConnector/XPSDK/CHeaders/Wrappers/XPCBroadcaster.h b/GermanAirlinesVA-GAConnector/XPSDK/CHeaders/Wrappers/XPCBroadcaster.h new file mode 100644 index 0000000..ae4f76f --- /dev/null +++ b/GermanAirlinesVA-GAConnector/XPSDK/CHeaders/Wrappers/XPCBroadcaster.h @@ -0,0 +1,31 @@ +#ifndef _XPCBroadcaster_h_ +#define _XPCBroadcaster_h_ + +#include +#include + +class XPCListener; + +class XPCBroadcaster +{ +public: + XPCBroadcaster(); + virtual ~XPCBroadcaster(); + + void AddListener(XPCListener *inListener); + void RemoveListener(XPCListener *inListener); + +protected: + void BroadcastMessage(int inMessage, void *inParam = 0); + +private: + typedef std::vector ListenerVector; + + ListenerVector mListeners; + + // Reentrancy support + + ListenerVector::iterator *mIterator; +}; + +#endif \ No newline at end of file diff --git a/GermanAirlinesVA-GAConnector/XPSDK/CHeaders/Wrappers/XPCDisplay.cpp b/GermanAirlinesVA-GAConnector/XPSDK/CHeaders/Wrappers/XPCDisplay.cpp new file mode 100644 index 0000000..ce39eb5 --- /dev/null +++ b/GermanAirlinesVA-GAConnector/XPSDK/CHeaders/Wrappers/XPCDisplay.cpp @@ -0,0 +1,107 @@ +#include "XPCDisplay.h" + +XPCKeySniffer::XPCKeySniffer(int inBeforeWindows) + : mBeforeWindows(inBeforeWindows) +{ + XPLMRegisterKeySniffer(KeySnifferCB, + mBeforeWindows, + reinterpret_cast(this)); +} + +XPCKeySniffer::~XPCKeySniffer() +{ + XPLMUnregisterKeySniffer(KeySnifferCB, + mBeforeWindows, + reinterpret_cast(this)); +} + + +int XPCKeySniffer::KeySnifferCB(char inCharKey, + XPLMKeyFlags inFlags, + char inVirtualKey, + void *inRefCon) +{ + XPCKeySniffer *me = reinterpret_cast(inRefCon); + return me->HandleKeyStroke(inCharKey, inFlags, inVirtualKey); +} + +XPCWindow::XPCWindow(int inLeft, + int inTop, + int inRight, + int inBottom, + int inIsVisible) +{ + mWindow = XPLMCreateWindow(inLeft, + inTop, + inRight, + inBottom, + inIsVisible, + DrawCB, + HandleKeyCB, + MouseClickCB, + reinterpret_cast(this)); +} + +XPCWindow::~XPCWindow() { XPLMDestroyWindow(mWindow); } + +void XPCWindow::GetWindowGeometry(int *outLeft, + int *outTop, + int *outRight, + int *outBottom) +{ + XPLMGetWindowGeometry(mWindow, outLeft, outTop, outRight, outBottom); +} + +void XPCWindow::SetWindowGeometry(int inLeft, + int inTop, + int inRight, + int inBottom) +{ + XPLMSetWindowGeometry(mWindow, inLeft, inTop, inRight, inBottom); +} + +int XPCWindow::GetWindowIsVisible(void) +{ + return XPLMGetWindowIsVisible(mWindow); +} + +void XPCWindow::SetWindowIsVisible(int inIsVisible) +{ + XPLMSetWindowIsVisible(mWindow, inIsVisible); +} + +void XPCWindow::TakeKeyboardFocus(void) { XPLMTakeKeyboardFocus(mWindow); } + +void XPCWindow::BringWindowToFront(void) { XPLMBringWindowToFront(mWindow); } + +int XPCWindow::IsWindowInFront(void) { return XPLMIsWindowInFront(mWindow); } + +void XPCWindow::DrawCB(XPLMWindowID inWindowID, void *inRefcon) +{ + XPCWindow *me = reinterpret_cast(inRefcon); + me->DoDraw(); +} + +void XPCWindow::HandleKeyCB(XPLMWindowID inWindowID, + char inKey, + XPLMKeyFlags inFlags, + char inVirtualKey, + void *inRefcon, + int losingFocus) +{ + XPCWindow *me = reinterpret_cast(inRefcon); + if (losingFocus) + me->LoseFocus(); + else + me->HandleKey(inKey, inFlags, inVirtualKey); +} + +int XPCWindow::MouseClickCB(XPLMWindowID inWindowID, + int x, + int y, + XPLMMouseStatus inMouse, + void *inRefcon) +{ + XPCWindow *me = reinterpret_cast(inRefcon); + return me->HandleClick(x, y, inMouse); +} diff --git a/GermanAirlinesVA-GAConnector/XPSDK/CHeaders/Wrappers/XPCDisplay.h b/GermanAirlinesVA-GAConnector/XPSDK/CHeaders/Wrappers/XPCDisplay.h new file mode 100644 index 0000000..13d1dc1 --- /dev/null +++ b/GermanAirlinesVA-GAConnector/XPSDK/CHeaders/Wrappers/XPCDisplay.h @@ -0,0 +1,70 @@ +#ifndef _XPCDisplay_h_ +#define _XPCDisplay_h_ + +#include "XPLMDisplay.h" + +class XPCKeySniffer +{ +public: + XPCKeySniffer(int inBeforeWindows); + virtual ~XPCKeySniffer(); + + virtual int HandleKeyStroke(char inCharKey, + XPLMKeyFlags inFlags, + char inVirtualKey) = 0; + +private: + int mBeforeWindows; + + static int KeySnifferCB(char inCharKey, + XPLMKeyFlags inFlags, + char inVirtualKey, + void *inRefCon); +}; + + +class XPCWindow +{ +public: + XPCWindow(int inLeft, + int inTop, + int inRight, + int inBottom, + int inIsVisible); + virtual ~XPCWindow(); + + virtual void DoDraw(void) = 0; + virtual void + HandleKey(char inKey, XPLMKeyFlags inFlags, char inVirtualKey) = 0; + virtual void LoseFocus(void) = 0; + virtual int HandleClick(int x, int y, XPLMMouseStatus inMouse) = 0; + + void GetWindowGeometry(int *outLeft, + int *outTop, + int *outRight, + int *outBottom); + void SetWindowGeometry(int inLeft, int inTop, int inRight, int inBottom); + int GetWindowIsVisible(void); + void SetWindowIsVisible(int inIsVisible); + void TakeKeyboardFocus(void); + void BringWindowToFront(void); + int IsWindowInFront(void); + +private: + XPLMWindowID mWindow; + + static void DrawCB(XPLMWindowID inWindowID, void *inRefcon); + static void HandleKeyCB(XPLMWindowID inWindowID, + char inKey, + XPLMKeyFlags inFlags, + char inVirtualKey, + void *inRefcon, + int losingFocus); + static int MouseClickCB(XPLMWindowID inWindowID, + int x, + int y, + XPLMMouseStatus inMouse, + void *inRefcon); +}; + +#endif \ No newline at end of file diff --git a/GermanAirlinesVA-GAConnector/XPSDK/CHeaders/Wrappers/XPCListener.cpp b/GermanAirlinesVA-GAConnector/XPSDK/CHeaders/Wrappers/XPCListener.cpp new file mode 100644 index 0000000..467b391 --- /dev/null +++ b/GermanAirlinesVA-GAConnector/XPSDK/CHeaders/Wrappers/XPCListener.cpp @@ -0,0 +1,23 @@ +#include "XPCListener.h" +#include "XPCBroadcaster.h" + +XPCListener::XPCListener() {} + +XPCListener::~XPCListener() +{ + while (!mBroadcasters.empty()) + mBroadcasters.front()->RemoveListener(this); +} + +void XPCListener::BroadcasterAdded(XPCBroadcaster *inBroadcaster) +{ + mBroadcasters.push_back(inBroadcaster); +} + +void XPCListener::BroadcasterRemoved(XPCBroadcaster *inBroadcaster) +{ + BroadcastVector::iterator iter = + std::find(mBroadcasters.begin(), mBroadcasters.end(), inBroadcaster); + if (iter != mBroadcasters.end()) + mBroadcasters.erase(iter); +} diff --git a/GermanAirlinesVA-GAConnector/XPSDK/CHeaders/Wrappers/XPCListener.h b/GermanAirlinesVA-GAConnector/XPSDK/CHeaders/Wrappers/XPCListener.h new file mode 100644 index 0000000..bc20826 --- /dev/null +++ b/GermanAirlinesVA-GAConnector/XPSDK/CHeaders/Wrappers/XPCListener.h @@ -0,0 +1,30 @@ +#ifndef _XPCListener_h_ +#define _XPCListener_h_ + +#include +#include + +class XPCBroadcaster; + + +class XPCListener +{ +public: + XPCListener(); + virtual ~XPCListener(); + + virtual void ListenToMessage(int inMessage, void *inParam) = 0; + +private: + typedef std::vector BroadcastVector; + + BroadcastVector mBroadcasters; + + friend class XPCBroadcaster; + + void BroadcasterAdded(XPCBroadcaster *inBroadcaster); + + void BroadcasterRemoved(XPCBroadcaster *inBroadcaster); +}; + +#endif \ No newline at end of file diff --git a/GermanAirlinesVA-GAConnector/XPSDK/CHeaders/Wrappers/XPCProcessing.cpp b/GermanAirlinesVA-GAConnector/XPSDK/CHeaders/Wrappers/XPCProcessing.cpp new file mode 100644 index 0000000..5e9552e --- /dev/null +++ b/GermanAirlinesVA-GAConnector/XPSDK/CHeaders/Wrappers/XPCProcessing.cpp @@ -0,0 +1,60 @@ +#include "XPCProcessing.h" +#include "XPLMUtilities.h" + +XPCProcess::XPCProcess() : mInCallback(false), mCallbackTime(0) +{ + XPLMRegisterFlightLoopCallback(FlightLoopCB, + 0, + reinterpret_cast(this)); +} + +XPCProcess::~XPCProcess() +{ + XPLMUnregisterFlightLoopCallback(FlightLoopCB, + reinterpret_cast(this)); +} + +void XPCProcess::StartProcessTime(float inSeconds) +{ + mCallbackTime = inSeconds; + if (!mInCallback) + XPLMSetFlightLoopCallbackInterval(FlightLoopCB, + mCallbackTime, + 1 /*relative to now*/, + reinterpret_cast(this)); +} + +void XPCProcess::StartProcessCycles(int inCycles) +{ + mCallbackTime = -inCycles; + if (!mInCallback) + XPLMSetFlightLoopCallbackInterval(FlightLoopCB, + mCallbackTime, + 1 /*relative to now*/, + reinterpret_cast(this)); +} + +void XPCProcess::StopProcess(void) +{ + mCallbackTime = 0; + if (!mInCallback) + XPLMSetFlightLoopCallbackInterval(FlightLoopCB, + mCallbackTime, + 1 /*relative to now*/, + reinterpret_cast(this)); +} + + +float XPCProcess::FlightLoopCB(float inElapsedSinceLastCall, + float inElapsedTimeSinceLastFlightLoop, + int inCounter, + void *inRefcon) +{ + XPCProcess *me = reinterpret_cast(inRefcon); + me->mInCallback = true; + me->DoProcessing(inElapsedSinceLastCall, + inElapsedTimeSinceLastFlightLoop, + inCounter); + me->mInCallback = false; + return me->mCallbackTime; +} \ No newline at end of file diff --git a/GermanAirlinesVA-GAConnector/XPSDK/CHeaders/Wrappers/XPCProcessing.h b/GermanAirlinesVA-GAConnector/XPSDK/CHeaders/Wrappers/XPCProcessing.h new file mode 100644 index 0000000..e963d49 --- /dev/null +++ b/GermanAirlinesVA-GAConnector/XPSDK/CHeaders/Wrappers/XPCProcessing.h @@ -0,0 +1,33 @@ +#ifndef _XPCProcessing_h_ +#define _XPCProcessing_h_ + +#include "XPLMProcessing.h" + +class XPCProcess +{ +public: + XPCProcess(); + virtual ~XPCProcess(); + + void StartProcessTime(float inSeconds); + void StartProcessCycles(int inCycles); + void StopProcess(void); + + virtual void DoProcessing(float inElapsedSinceLastCall, + float inElapsedTimeSinceLastFlightLoop, + int inCounter) = 0; + +private: + static float FlightLoopCB(float inElapsedSinceLastCall, + float inElapsedTimeSinceLastFlightLoop, + int inCounter, + void *inRefcon); + + bool mInCallback; + float mCallbackTime; + + XPCProcess(const XPCProcess &); + XPCProcess &operator=(const XPCProcess &); +}; + +#endif diff --git a/GermanAirlinesVA-GAConnector/XPSDK/CHeaders/Wrappers/XPCWidget.cpp b/GermanAirlinesVA-GAConnector/XPSDK/CHeaders/Wrappers/XPCWidget.cpp new file mode 100644 index 0000000..be1e6a8 --- /dev/null +++ b/GermanAirlinesVA-GAConnector/XPSDK/CHeaders/Wrappers/XPCWidget.cpp @@ -0,0 +1,111 @@ +#include "XPCWidget.h" + +XPCWidget::XPCWidget(int inLeft, + int inTop, + int inRight, + int inBottom, + bool inVisible, + const char *inDescriptor, + bool inIsRoot, + XPWidgetID inParent, + XPWidgetClass inClass) + : mWidget(NULL), mOwnsChildren(false), mOwnsWidget(true) +{ + mWidget = XPCreateWidget(inLeft, + inTop, + inRight, + inBottom, + inVisible ? 1 : 0, + inDescriptor, + inIsRoot ? 1 : 0, + inIsRoot ? NULL : inParent, + inClass); + + XPSetWidgetProperty(mWidget, + xpProperty_Object, + reinterpret_cast(this)); + XPAddWidgetCallback(mWidget, WidgetCallback); +} + +XPCWidget::XPCWidget(XPWidgetID inWidget, bool inOwnsWidget) + : mWidget(inWidget), mOwnsChildren(false), mOwnsWidget(inOwnsWidget) +{ + XPSetWidgetProperty(mWidget, + xpProperty_Object, + reinterpret_cast(this)); + XPAddWidgetCallback(mWidget, WidgetCallback); +} + +XPCWidget::~XPCWidget() +{ + if (mOwnsWidget) + XPDestroyWidget(mWidget, mOwnsChildren ? 1 : 0); +} + +void XPCWidget::SetOwnsWidget(bool inOwnsWidget) { mOwnsWidget = inOwnsWidget; } + +void XPCWidget::SetOwnsChildren(bool inOwnsChildren) +{ + mOwnsChildren = inOwnsChildren; +} + +XPCWidget::operator XPWidgetID() const { return mWidget; } + +XPWidgetID XPCWidget::Get(void) const { return mWidget; } + +void XPCWidget::AddAttachment(XPCWidgetAttachment *inAttachment, + bool inOwnsAttachment, + bool inPrefilter) +{ + if (inPrefilter) { + mAttachments.insert(mAttachments.begin(), + AttachmentInfo(inAttachment, inOwnsAttachment)); + } else { + mAttachments.push_back(AttachmentInfo(inAttachment, inOwnsAttachment)); + } +} + +void XPCWidget::RemoveAttachment(XPCWidgetAttachment *inAttachment) +{ + for (AttachmentVector::iterator iter = mAttachments.begin(); + iter != mAttachments.end(); + ++iter) { + if (iter->first == inAttachment) { + mAttachments.erase(iter); + return; + } + } +} + +int XPCWidget::HandleWidgetMessage(XPWidgetMessage inMessage, + XPWidgetID inWidget, + intptr_t inParam1, + intptr_t inParam2) +{ + return 0; +} + +int XPCWidget::WidgetCallback(XPWidgetMessage inMessage, + XPWidgetID inWidget, + intptr_t inParam1, + intptr_t inParam2) +{ + XPCWidget *me = reinterpret_cast( + XPGetWidgetProperty(inWidget, xpProperty_Object, NULL)); + if (me == NULL) + return 0; + + for (AttachmentVector::iterator iter = me->mAttachments.begin(); + iter != me->mAttachments.end(); + ++iter) { + int result = iter->first->HandleWidgetMessage(me, + inMessage, + inWidget, + inParam1, + inParam2); + if (result != 0) + return result; + } + + return me->HandleWidgetMessage(inMessage, inWidget, inParam1, inParam2); +} diff --git a/GermanAirlinesVA-GAConnector/XPSDK/CHeaders/Wrappers/XPCWidget.h b/GermanAirlinesVA-GAConnector/XPSDK/CHeaders/Wrappers/XPCWidget.h new file mode 100644 index 0000000..584a5ee --- /dev/null +++ b/GermanAirlinesVA-GAConnector/XPSDK/CHeaders/Wrappers/XPCWidget.h @@ -0,0 +1,71 @@ +#ifndef _XPCWidget_h_ +#define _XPCWidget_h_ + +#include "XPWidgets.h" +#include +#include + +class XPCWidget; + +class XPCWidgetAttachment +{ +public: + virtual int HandleWidgetMessage(XPCWidget *inObject, + XPWidgetMessage inMessage, + XPWidgetID inWidget, + intptr_t inParam1, + intptr_t inParam2) = 0; +}; + +class XPCWidget +{ +public: + XPCWidget(int inLeft, + int inTop, + int inRight, + int inBottom, + bool inVisible, + const char *inDescriptor, + bool inIsRoot, + XPWidgetID inParent, + XPWidgetClass inClass); + XPCWidget(XPWidgetID inWidget, bool inOwnsWidget); + virtual ~XPCWidget(); + + void SetOwnsWidget(bool inOwnsWidget); + void SetOwnsChildren(bool inOwnsChildren); + + operator XPWidgetID() const; + + XPWidgetID Get(void) const; + + void AddAttachment(XPCWidgetAttachment *inAttachment, + bool inOwnsAttachment, + bool inPrefilter); + void RemoveAttachment(XPCWidgetAttachment *inAttachment); + + virtual int HandleWidgetMessage(XPWidgetMessage inMessage, + XPWidgetID inWidget, + intptr_t inParam1, + intptr_t inParam2); + +private: + static int WidgetCallback(XPWidgetMessage inMessage, + XPWidgetID inWidget, + intptr_t inParam1, + intptr_t inParam2); + + typedef std::pair AttachmentInfo; + typedef std::vector AttachmentVector; + + AttachmentVector mAttachments; + XPWidgetID mWidget; + bool mOwnsChildren; + bool mOwnsWidget; + + XPCWidget(); + XPCWidget(const XPCWidget &); + XPCWidget &operator=(const XPCWidget &); +}; + +#endif \ No newline at end of file diff --git a/GermanAirlinesVA-GAConnector/XPSDK/CHeaders/Wrappers/XPCWidgetAttachments.cpp b/GermanAirlinesVA-GAConnector/XPSDK/CHeaders/Wrappers/XPCWidgetAttachments.cpp new file mode 100644 index 0000000..9d3a03d --- /dev/null +++ b/GermanAirlinesVA-GAConnector/XPSDK/CHeaders/Wrappers/XPCWidgetAttachments.cpp @@ -0,0 +1,235 @@ +#include "XPCWidgetAttachments.h" +#include "XPStandardWidgets.h" +#include "XPWidgetUtils.h" + +static void XPCGetOrderedSubWidgets(XPWidgetID inWidget, + std::vector &outChildren); + +XPCKeyFilterAttachment::XPCKeyFilterAttachment(const char *inValidKeys, + const char *outValidKeys) + : mInput(inValidKeys), mOutput(outValidKeys) +{ +} + +XPCKeyFilterAttachment::~XPCKeyFilterAttachment() {} + +int XPCKeyFilterAttachment::HandleWidgetMessage(XPCWidget *inObject, + XPWidgetMessage inMessage, + XPWidgetID inWidget, + intptr_t inParam1, + intptr_t inParam2) +{ + if (inMessage == xpMsg_KeyPress) { + char &theKey = KEY_CHAR(inParam1); + std::string::size_type pos = mInput.find(theKey); + if (pos == std::string::npos) + return 1; // Not found; eat the key! + else { + theKey = mOutput[pos]; + return 0; + } // Let it live. + } + return 0; +} + + +XPCKeyMessageAttachment::XPCKeyMessageAttachment(char inKey, + int inMessage, + void *inParam, + bool inConsume, + bool inVkey, + XPCListener *inListener) + : mKey(inKey), mMsg(inMessage), mParam(inParam), mConsume(inConsume), + mVkey(inVkey) +{ + if (inListener != NULL) + this->AddListener(inListener); +} + +XPCKeyMessageAttachment::~XPCKeyMessageAttachment() {} + +int XPCKeyMessageAttachment::HandleWidgetMessage(XPCWidget *inObject, + XPWidgetMessage inMessage, + XPWidgetID inWidget, + intptr_t inParam1, + intptr_t inParam2) +{ + if (inMessage == xpMsg_KeyPress) { + char theKey = mVkey ? KEY_VKEY(inParam1) : KEY_CHAR(inParam1); + if (theKey != mKey) + return 0; + if (!(KEY_FLAGS(inParam1) & xplm_DownFlag)) + return 0; + + BroadcastMessage(mMsg, mParam); + return mConsume ? 1 : 0; + } + return 0; +} + +XPCPushButtonMessageAttachment::XPCPushButtonMessageAttachment( + XPWidgetID inWidget, + int inMessage, + void *inParam, + XPCListener *inListener) + : mMsg(inMessage), mParam(inParam), mWidget(inWidget) +{ + if (inListener != NULL) + this->AddListener(inListener); +} + +XPCPushButtonMessageAttachment::~XPCPushButtonMessageAttachment() {} + +int XPCPushButtonMessageAttachment::HandleWidgetMessage( + XPCWidget *inObject, + XPWidgetMessage inMessage, + XPWidgetID inWidget, + intptr_t inParam1, + intptr_t inParam2) +{ + if ((inMessage == xpMsg_PushButtonPressed) && + ((XPWidgetID)inParam1 == mWidget)) { + BroadcastMessage(mMsg, mParam); + return 1; + } + + if ((inMessage == xpMsg_ButtonStateChanged) && + ((XPWidgetID)inParam1 == mWidget)) { + BroadcastMessage(mMsg, mParam); + return 1; + } + return 0; +} + +XPCSliderMessageAttachment::XPCSliderMessageAttachment(XPWidgetID inWidget, + int inMessage, + void *inParam, + XPCListener *inListener) + : mMsg(inMessage), mParam(inParam), mWidget(inWidget) +{ + if (inListener != NULL) + this->AddListener(inListener); +} + +XPCSliderMessageAttachment::~XPCSliderMessageAttachment() {} + +int XPCSliderMessageAttachment::HandleWidgetMessage(XPCWidget *inObject, + XPWidgetMessage inMessage, + XPWidgetID inWidget, + intptr_t inParam1, + intptr_t inParam2) +{ + if ((inMessage == xpMsg_ScrollBarSliderPositionChanged) && + ((XPWidgetID)inParam1 == mWidget)) { + BroadcastMessage(mMsg, mParam); + return 1; + } + + return 0; +} + + +XPCCloseButtonMessageAttachment::XPCCloseButtonMessageAttachment( + XPWidgetID inWidget, + int inMessage, + void *inParam, + XPCListener *inListener) + : mMsg(inMessage), mParam(inParam), mWidget(inWidget) +{ + if (inListener != NULL) + this->AddListener(inListener); +} + +XPCCloseButtonMessageAttachment::~XPCCloseButtonMessageAttachment() {} + +int XPCCloseButtonMessageAttachment::HandleWidgetMessage( + XPCWidget *inObject, + XPWidgetMessage inMessage, + XPWidgetID inWidget, + intptr_t inParam1, + intptr_t inParam2) +{ + if ((inMessage == xpMessage_CloseButtonPushed) && + ((XPWidgetID)inParam1 == mWidget)) { + BroadcastMessage(mMsg, mParam); + return 1; + } + + return 0; +} + +XPCTabGroupAttachment::XPCTabGroupAttachment() {} + +XPCTabGroupAttachment::~XPCTabGroupAttachment() {} + +int XPCTabGroupAttachment::HandleWidgetMessage(XPCWidget *inObject, + XPWidgetMessage inMessage, + XPWidgetID inWidget, + intptr_t inParam1, + intptr_t inParam2) +{ + if ((inMessage == xpMsg_KeyPress) && (KEY_CHAR(inParam1) == XPLM_KEY_TAB) && + ((KEY_FLAGS(inParam1) & xplm_UpFlag) == 0)) { + bool backwards = (KEY_FLAGS(inParam1) & xplm_ShiftFlag) != 0; + std::vector widgets; + XPCGetOrderedSubWidgets(inWidget, widgets); + int n, index = 0; + XPWidgetID focusWidget = XPGetWidgetWithFocus(); + std::vector::iterator iter = + std::find(widgets.begin(), widgets.end(), focusWidget); + if (iter != widgets.end()) { + index = std::distance(widgets.begin(), iter); + if (backwards) + index--; + else + index++; + if (index < 0) + index = widgets.size() - 1; + if (index >= widgets.size()) + index = 0; + } + + if (backwards) { + for (n = index; n >= 0; --n) { + if (XPGetWidgetProperty(widgets[n], xpProperty_Enabled, NULL)) + if (XPSetKeyboardFocus(widgets[n]) != NULL) + return 1; + } + for (n = widgets.size() - 1; n > index; --n) { + if (XPGetWidgetProperty(widgets[n], xpProperty_Enabled, NULL)) + if (XPSetKeyboardFocus(widgets[n]) != NULL) + return 1; + } + } else { + for (n = index; n < widgets.size(); ++n) { + if (XPGetWidgetProperty(widgets[n], xpProperty_Enabled, NULL)) + if (XPSetKeyboardFocus(widgets[n]) != NULL) + return 1; + } + for (n = 0; n < index; ++n) { + if (XPGetWidgetProperty(widgets[n], xpProperty_Enabled, NULL)) + if (XPSetKeyboardFocus(widgets[n]) != NULL) + return 1; + } + } + } + return 0; +} + + +static void XPCGetOrderedSubWidgets(XPWidgetID inWidget, + std::vector &outChildren) +{ + outChildren.clear(); + int count = XPCountChildWidgets(inWidget); + for (int n = 0; n < count; ++n) { + XPWidgetID child = XPGetNthChildWidget(inWidget, n); + outChildren.push_back(child); + std::vector grandChildren; + XPCGetOrderedSubWidgets(child, grandChildren); + + outChildren.insert(outChildren.end(), + grandChildren.begin(), + grandChildren.end()); + } +} diff --git a/GermanAirlinesVA-GAConnector/XPSDK/CHeaders/Wrappers/XPCWidgetAttachments.h b/GermanAirlinesVA-GAConnector/XPSDK/CHeaders/Wrappers/XPCWidgetAttachments.h new file mode 100644 index 0000000..086d6ea --- /dev/null +++ b/GermanAirlinesVA-GAConnector/XPSDK/CHeaders/Wrappers/XPCWidgetAttachments.h @@ -0,0 +1,132 @@ +#ifndef _XPCWidgetAttachments_h_ +#define _XPCWidgetAttachments_h_ + +#include + +#include "XPCBroadcaster.h" +#include "XPCWidget.h" + +class XPCKeyFilterAttachment : public XPCWidgetAttachment +{ +public: + XPCKeyFilterAttachment(const char *inValidKeys, const char *outValidKeys); + virtual ~XPCKeyFilterAttachment(); + + virtual int HandleWidgetMessage(XPCWidget *inObject, + XPWidgetMessage inMessage, + XPWidgetID inWidget, + intptr_t inParam1, + intptr_t inParam2); + +private: + std::string mInput; + std::string mOutput; +}; + + +class XPCKeyMessageAttachment : public XPCWidgetAttachment, + public XPCBroadcaster +{ +public: + XPCKeyMessageAttachment(char inKey, + int inMessage, + void *inParam, + bool inConsume, + bool inVkey, + XPCListener *inListener); + virtual ~XPCKeyMessageAttachment(); + + virtual int HandleWidgetMessage(XPCWidget *inObject, + XPWidgetMessage inMessage, + XPWidgetID inWidget, + intptr_t inParam1, + intptr_t inParam2); + +private: + char mKey; + bool mVkey; + int mMsg; + void *mParam; + bool mConsume; +}; + +class XPCPushButtonMessageAttachment : public XPCWidgetAttachment, + XPCBroadcaster +{ +public: + XPCPushButtonMessageAttachment(XPWidgetID inWidget, + int inMessage, + void *inParam, + XPCListener *inListener); + virtual ~XPCPushButtonMessageAttachment(); + + virtual int HandleWidgetMessage(XPCWidget *inObject, + XPWidgetMessage inMessage, + XPWidgetID inWidget, + intptr_t inParam1, + intptr_t inParam2); + +private: + XPWidgetID mWidget; + int mMsg; + void *mParam; +}; + +class XPCSliderMessageAttachment : public XPCWidgetAttachment, XPCBroadcaster +{ +public: + XPCSliderMessageAttachment(XPWidgetID inWidget, + int inMessage, + void *inParam, + XPCListener *inListener); + virtual ~XPCSliderMessageAttachment(); + + virtual int HandleWidgetMessage(XPCWidget *inObject, + XPWidgetMessage inMessage, + XPWidgetID inWidget, + intptr_t inParam1, + intptr_t inParam2); + +private: + XPWidgetID mWidget; + int mMsg; + void *mParam; +}; + + +class XPCCloseButtonMessageAttachment : public XPCWidgetAttachment, + XPCBroadcaster +{ +public: + XPCCloseButtonMessageAttachment(XPWidgetID inWidget, + int inMessage, + void *inParam, + XPCListener *inListener); + virtual ~XPCCloseButtonMessageAttachment(); + + virtual int HandleWidgetMessage(XPCWidget *inObject, + XPWidgetMessage inMessage, + XPWidgetID inWidget, + intptr_t inParam1, + intptr_t inParam2); + +private: + XPWidgetID mWidget; + int mMsg; + void *mParam; +}; + +class XPCTabGroupAttachment : public XPCWidgetAttachment +{ +public: + XPCTabGroupAttachment(); + virtual ~XPCTabGroupAttachment(); + + virtual int HandleWidgetMessage(XPCWidget *inObject, + XPWidgetMessage inMessage, + XPWidgetID inWidget, + intptr_t inParam1, + intptr_t inParam2); +}; + +#endif \ No newline at end of file diff --git a/GermanAirlinesVA-GAConnector/XPSDK/CHeaders/XPLM/XPLMCamera.h b/GermanAirlinesVA-GAConnector/XPSDK/CHeaders/XPLM/XPLMCamera.h new file mode 100644 index 0000000..f493525 --- /dev/null +++ b/GermanAirlinesVA-GAConnector/XPSDK/CHeaders/XPLM/XPLMCamera.h @@ -0,0 +1,167 @@ +#ifndef _XPLMCamera_h_ +#define _XPLMCamera_h_ + +/* + * Copyright 2005-2012 Sandy Barbour and Ben Supnik + * + * All rights reserved. See license.txt for usage. + * + * X-Plane SDK Version: 2.1.1 + * + */ + +/* + * XPLMCamera - THEORY OF OPERATION The XPLMCamera APIs allow plug-ins to + * control the camera angle in X-Plane. This has a number of applications, + * including but not limited to: + * + * - Creating new views (including dynamic/user-controllable views) for the + * user. + * + * - Creating applications that use X-Plane as a renderer of scenery, + * aircrafts, or both. + * + * The camera is controlled via six parameters: a location in OpenGL + * coordinates and pitch, roll and yaw, similar to an airplane's position. + * OpenGL coordinate info is described in detail in the XPLMGraphics + * documentation; generally you should use the XPLMGraphics routines to + * convert from world to local coordinates. The camera's orientation starts + * facing level with the ground directly up the negative-Z axis + * (approximately north) with the horizon horizontal. It is then rotated + * clockwise for yaw, pitched up for positive pitch, and rolled clockwise + * around the vector it is looking along for roll. + * + * You control the camera either either until the user selects a new view or + * permanently (the later being similar to how UDP camera control works). You + * control the camera by registering a callback per frame from which you + * calculate the new camera positions. This guarantees smooth camera motion. + * + * Use the XPLMDataAccess APIs to get information like the position of the + * aircraft, etc. for complex camera positioning. + * + */ + +#include "XPLMDefs.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/*************************************************************************** + * CAMERA CONTROL + ***************************************************************************/ +/* + * + * + */ + + +/* + * XPLMCameraControlDuration + * + * This enumeration states how long you want to retain control of the camera. + * You can retain it indefinitely or until the user selects a new view. + * + */ +enum { + /* Control the camera until the user picks a new view. */ + xplm_ControlCameraUntilViewChanges = 1 + + /* Control the camera until your plugin is disabled or another plugin + * forcably * takes control. */ + , + xplm_ControlCameraForever = 2 + + +}; +typedef int XPLMCameraControlDuration; + +/* + * XPLMCameraPosition_t + * + * This structure contains a full specification of the camera. X, Y, and Z + * are the camera's position in OpenGL coordiantes; pitch, roll, and yaw are + * rotations from a camera facing flat north in degrees. Positive pitch means + * nose up, positive roll means roll right, and positive yaw means yaw right, + * all in degrees. Zoom is a zoom factor, with 1.0 meaning normal zoom and 2.0 + * magnifying by 2x (objects appear larger). + * + */ +typedef struct { + float x; + float y; + float z; + float pitch; + float heading; + float roll; + float zoom; +} XPLMCameraPosition_t; + +/* + * XPLMCameraControl_f + * + * You use an XPLMCameraControl function to provide continuous control over + * the camera. You are passed in a structure in which to put the new camera + * position; modify it and return 1 to reposition the camera. Return 0 to + * surrender control of the camera; camera control will be handled by X-Plane + * on this draw loop. The contents of the structure as you are called are + * undefined. + * + * If X-Plane is taking camera control away from you, this function will be + * called with inIsLosingControl set to 1 and ioCameraPosition NULL. + * + */ +typedef int (*XPLMCameraControl_f)( + XPLMCameraPosition_t *outCameraPosition, /* Can be NULL */ + int inIsLosingControl, + void *inRefcon); + +/* + * XPLMControlCamera + * + * This function repositions the camera on the next drawing cycle. You must + * pass a non-null control function. Specify in inHowLong how long you'd like + * control (indefinitely or until a key is pressed). + * + */ +XPLM_API void XPLMControlCamera(XPLMCameraControlDuration inHowLong, + XPLMCameraControl_f inControlFunc, + void *inRefcon); + +/* + * XPLMDontControlCamera + * + * This function stops you from controlling the camera. If you have a camera + * control function, it will not be called with an inIsLosingControl flag. + * X-Plane will control the camera on the next cycle. + * + * For maximum compatibility you should not use this routine unless you are in + * posession of the camera. + * + */ +XPLM_API void XPLMDontControlCamera(void); + +/* + * XPLMIsCameraBeingControlled + * + * This routine returns 1 if the camera is being controlled, zero if it is + * not. If it is and you pass in a pointer to a camera control duration, the + * current control duration will be returned. + * + */ +XPLM_API int XPLMIsCameraBeingControlled( + XPLMCameraControlDuration *outCameraControlDuration); /* Can be NULL */ + +/* + * XPLMReadCameraPosition + * + * This function reads the current camera position. + * + */ +XPLM_API void XPLMReadCameraPosition(XPLMCameraPosition_t *outCameraPosition); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/GermanAirlinesVA-GAConnector/XPSDK/CHeaders/XPLM/XPLMDataAccess.h b/GermanAirlinesVA-GAConnector/XPSDK/CHeaders/XPLM/XPLMDataAccess.h new file mode 100644 index 0000000..ba37559 --- /dev/null +++ b/GermanAirlinesVA-GAConnector/XPSDK/CHeaders/XPLM/XPLMDataAccess.h @@ -0,0 +1,670 @@ +#ifndef _XPLMDataAccess_h_ +#define _XPLMDataAccess_h_ + +/* + * Copyright 2005-2012 Sandy Barbour and Ben Supnik + * + * All rights reserved. See license.txt for usage. + * + * X-Plane SDK Version: 2.1.1 + * + */ + +/* + * XPLM Data Access API - Theory of Operation + * + * The data access API gives you a generic, flexible, high performance way to + * read and write data to and from X-Plane and other plug-ins. For example, + * this API allows you to read and set the nav radios, get the plane location, + * determine the current effective graphics frame rate, etc. + * + * The data access APIs are the way that you read and write data from the sim + * as well as other plugins. + * + * The API works using opaque data references. A data reference is a source + * of data; you do not know where it comes from, but once you have it you can + * read the data quickly and possibly write it. To get a data reference, you + * look it up. + * + * Data references are identified by verbose string names + * (sim/cockpit/radios/nav1_freq_hz). The actual numeric value of the data + * reference is implementation defined and is likely to change each time the + * simulator is run (or the plugin that provides the datareference is + * reloaded). + * + * The task of looking up a data reference is relatively expensive; look up + * your data references once based on verbose strings, and save the opaque + * data reference value for the duration of your plugin's operation. Reading + * and writing data references is relatively fast (the cost is equivalent to + * two function calls through function pointers). + * + * This allows data access to be high performance, while leaving in + * abstraction; since data references are opaque and are searched for, the + * underlying data access system can be rebuilt. + * + * A note on typing: you must know the correct data type to read and write. + * APIs are provided for reading and writing data in a number of ways. You + * can also double check the data type for a data ref. Note that automatic + * conversion is not done for you. + * + * A note for plugins sharing data with other plugins: the load order of + * plugins is not guaranteed. To make sure that every plugin publishing data + * has published their data references before other plugins try to subscribe, + * publish your data references in your start routine but resolve them the + * first time your 'enable' routine is called, or the first time they are + * needed in code. + * + * X-Plane publishes well over 1000 datarefs; a complete list may be found in + * the reference section of the SDK online documentation (from the SDK home + * page, choose Documentation). + * + */ + +#include "XPLMDefs.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/*************************************************************************** + * READING AND WRITING DATA + ***************************************************************************/ +/* + * These routines allow you to access a wide variety of data from within + * x-plane and modify some of it. + * + */ + + +/* + * XPLMDataRef + * + * A data ref is an opaque handle to data provided by the simulator or another + * plugin. It uniquely identifies one variable (or array of variables) over + * the lifetime of your plugin. You never hard code these values; you always + * get them from XPLMFindDataRef. + * + */ +typedef void *XPLMDataRef; + +/* + * XPLMDataTypeID + * + * This is an enumeration that defines the type of the data behind a data + * reference. This allows you to sanity check that the data type matches what + * you expect. But for the most part, you will know the type of data you are + * expecting from the online documentation. + * + * Data types each take a bit field, so sets of data types may be formed. + * + */ +enum { + /* Data of a type the current XPLM doesn't do. */ + xplmType_Unknown = 0 + + /* A single 4-byte integer, native endian. */ + , + xplmType_Int = 1 + + /* A single 4-byte float, native endian. */ + , + xplmType_Float = 2 + + /* A single 8-byte double, native endian. */ + , + xplmType_Double = 4 + + /* An array of 4-byte floats, native endian. */ + , + xplmType_FloatArray = 8 + + /* An array of 4-byte integers, native endian. */ + , + xplmType_IntArray = 16 + + /* A variable block of data. */ + , + xplmType_Data = 32 + + +}; +typedef int XPLMDataTypeID; + +/* + * XPLMFindDataRef + * + * Given a c-style string that names the data ref, this routine looks up the + * actual opaque XPLMDataRef that you use to read and write the data. The + * string names for datarefs are published on the x-plane SDK web site. + * + * This function returns NULL if the data ref cannot be found. + * + * NOTE: this function is relatively expensive; save the XPLMDataRef this + * function returns for future use. Do not look up your data ref by string + * every time you need to read or write it. + * + */ +XPLM_API XPLMDataRef XPLMFindDataRef(const char *inDataRefName); + +/* + * XPLMCanWriteDataRef + * + * Given a data ref, this routine returns true if you can successfully set + * the data, false otherwise. Some datarefs are read-only. + * + */ +XPLM_API int XPLMCanWriteDataRef(XPLMDataRef inDataRef); + +/* + * XPLMIsDataRefGood + * + * WARNING: This function is deprecated and should not be used. Datarefs are + * valid until plugins are reloaded or the sim quits. Plugins sharing + * datarefs should support these semantics by not unregistering datarefs + * during operation. (You should however unregister datarefs when your plugin + * is unloaded, as part of general resource cleanup.) + * + * This function returns whether a data ref is still valid. If it returns + * false, you should refind the data ref from its original string. Calling an + * accessor function on a bad data ref will return a default value, typically + * 0 or 0-length data. + * + */ +XPLM_API int XPLMIsDataRefGood(XPLMDataRef inDataRef); + +/* + * XPLMGetDataRefTypes + * + * This routine returns the types of the data ref for accessor use. If a data + * ref is available in multiple data types, they will all be returned. + * + */ +XPLM_API XPLMDataTypeID XPLMGetDataRefTypes(XPLMDataRef inDataRef); + +/*************************************************************************** + * DATA ACCESSORS + ***************************************************************************/ +/* + * These routines read and write the data references. For each supported data + * type there is a reader and a writer. + * + * If the data ref is invalid or the plugin that provides it is disabled or + * there is a type mismatch, the functions that read data will return 0 as a + * default value or not modify the passed in memory. The plugins that write + * data will not write under these circumstances or if the data ref is + * read-only. NOTE: to keep the overhead of reading datarefs low, these + * routines do not do full validation of a dataref; passing a junk value for + * a dataref can result in crashing the sim. + * + * For array-style datarefs, you specify the number of items to read/write and + * the offset into the array; the actual number of items read or written is + * returned. This may be less to prevent an array-out-of-bounds error. + * + */ + + +/* + * XPLMGetDatai + * + * Read an integer data ref and return its value. The return value is the + * dataref value or 0 if the dataref is invalid/NULL or the plugin is + * disabled. + * + */ +XPLM_API int XPLMGetDatai(XPLMDataRef inDataRef); + +/* + * XPLMSetDatai + * + * Write a new value to an integer data ref. This routine is a no-op if the + * plugin publishing the dataref is disabled, the dataref is invalid, or the + * dataref is not writable. + * + */ +XPLM_API void XPLMSetDatai(XPLMDataRef inDataRef, int inValue); + +/* + * XPLMGetDataf + * + * Read a single precision floating point dataref and return its value. The + * return value is the dataref value or 0.0 if the dataref is invalid/NULL or + * the plugin is disabled. + * + */ +XPLM_API float XPLMGetDataf(XPLMDataRef inDataRef); + +/* + * XPLMSetDataf + * + * Write a new value to a single precision floating point data ref. This + * routine is a no-op if the plugin publishing the dataref is disabled, the + * dataref is invalid, or the dataref is not writable. + * + */ +XPLM_API void XPLMSetDataf(XPLMDataRef inDataRef, float inValue); + +/* + * XPLMGetDatad + * + * Read a double precision floating point dataref and return its value. The + * return value is the dataref value or 0.0 if the dataref is invalid/NULL or + * the plugin is disabled. + * + */ +XPLM_API double XPLMGetDatad(XPLMDataRef inDataRef); + +/* + * XPLMSetDatad + * + * Write a new value to a double precision floating point data ref. This + * routine is a no-op if the plugin publishing the dataref is disabled, the + * dataref is invalid, or the dataref is not writable. + * + */ +XPLM_API void XPLMSetDatad(XPLMDataRef inDataRef, double inValue); + +/* + * XPLMGetDatavi + * + * Read a part of an integer array dataref. If you pass NULL for outVaules, + * the routine will return the size of the array, ignoring inOffset and inMax. + * + * + * If outValues is not NULL, then up to inMax values are copied from the + * dataref into outValues, starting at inOffset in the dataref. If inMax + + * inOffset is larger than the size of the dataref, less than inMax values + * will be copied. The number of values copied is returned. + * + * Note: the semantics of array datarefs are entirely implemented by the + * plugin (or X-Plane) that provides the dataref, not the SDK itself; the + * above description is how these datarefs are intended to work, but a rogue + * plugin may have different behavior. + * + */ +XPLM_API int XPLMGetDatavi(XPLMDataRef inDataRef, + int *outValues, /* Can be NULL */ + int inOffset, + int inMax); + +/* + * XPLMSetDatavi + * + * Write part or all of an integer array dataref. The values passed by + * inValues are written into the dataref starting at inOffset. Up to inCount + * values are written; however if the values would write "off the end" of the + * dataref array, then fewer values are written. + * + * Note: the semantics of array datarefs are entirely implemented by the + * plugin (or X-Plane) that provides the dataref, not the SDK itself; the + * above description is how these datarefs are intended to work, but a rogue + * plugin may have different behavior. + * + */ +XPLM_API void XPLMSetDatavi(XPLMDataRef inDataRef, + int *inValues, + int inoffset, + int inCount); + +/* + * XPLMGetDatavf + * + * Read a part of a single precision floating point array dataref. If you + * pass NULL for outVaules, the routine will return the size of the array, + * ignoring inOffset and inMax. + * + * If outValues is not NULL, then up to inMax values are copied from the + * dataref into outValues, starting at inOffset in the dataref. If inMax + + * inOffset is larger than the size of the dataref, less than inMax values + * will be copied. The number of values copied is returned. + * + * Note: the semantics of array datarefs are entirely implemented by the + * plugin (or X-Plane) that provides the dataref, not the SDK itself; the + * above description is how these datarefs are intended to work, but a rogue + * plugin may have different behavior. + * + */ +XPLM_API int XPLMGetDatavf(XPLMDataRef inDataRef, + float *outValues, /* Can be NULL */ + int inOffset, + int inMax); + +/* + * XPLMSetDatavf + * + * Write part or all of a single precision floating point array dataref. The + * values passed by inValues are written into the dataref starting at + * inOffset. Up to inCount values are written; however if the values would + * write "off the end" of the dataref array, then fewer values are written. + * + * Note: the semantics of array datarefs are entirely implemented by the + * plugin (or X-Plane) that provides the dataref, not the SDK itself; the + * above description is how these datarefs are intended to work, but a rogue + * plugin may have different behavior. + * + */ +XPLM_API void XPLMSetDatavf(XPLMDataRef inDataRef, + float *inValues, + int inoffset, + int inCount); + +/* + * XPLMGetDatab + * + * Read a part of a byte array dataref. If you pass NULL for outVaules, the + * routine will return the size of the array, ignoring inOffset and inMax. + * + * If outValues is not NULL, then up to inMax values are copied from the + * dataref into outValues, starting at inOffset in the dataref. If inMax + + * inOffset is larger than the size of the dataref, less than inMax values + * will be copied. The number of values copied is returned. + * + * Note: the semantics of array datarefs are entirely implemented by the + * plugin (or X-Plane) that provides the dataref, not the SDK itself; the + * above description is how these datarefs are intended to work, but a rogue + * plugin may have different behavior. + * + */ +XPLM_API int XPLMGetDatab(XPLMDataRef inDataRef, + void *outValue, /* Can be NULL */ + int inOffset, + int inMaxBytes); + +/* + * XPLMSetDatab + * + * Write part or all of a byte array dataref. The values passed by inValues + * are written into the dataref starting at inOffset. Up to inCount values + * are written; however if the values would write "off the end" of the dataref + * array, then fewer values are written. + * + * Note: the semantics of array datarefs are entirely implemented by the + * plugin (or X-Plane) that provides the dataref, not the SDK itself; the + * above description is how these datarefs are intended to work, but a rogue + * plugin may have different behavior. + * + */ +XPLM_API void XPLMSetDatab(XPLMDataRef inDataRef, + void *inValue, + int inOffset, + int inLength); + +/*************************************************************************** + * PUBLISHING YOUR PLUGINS DATA + ***************************************************************************/ +/* + * These functions allow you to create data references that other plug-ins can + * access via the above data access APIs. Data references published by other + * plugins operate the same as ones published by x-plane in all manners except + * that your data reference will not be available to other plugins if/when + * your plugin is disabled. + * + * You share data by registering data provider callback functions. When a + * plug-in requests your data, these callbacks are then called. You provide + * one callback to return the value when a plugin 'reads' it and another to + * change the value when a plugin 'writes' it. + * + * Important: you must pick a prefix for your datarefs other than "sim/" - + * this prefix is reserved for X-Plane. The X-Plane SDK website contains a + * registry where authors can select a unique first word for dataref names, to + * prevent dataref collisions between plugins. + * + */ + + +/* + * XPLMGetDatai_f + * + * Data provider function pointers. + * + * These define the function pointers you provide to get or set data. Note + * that you are passed a generic pointer for each one. This is the same + * pointer you pass in your register routine; you can use it to find global + * variables, etc. + * + * The semantics of your callbacks are the same as the dataref accessor above + * - basically routines like XPLMGetDatai are just pass-throughs from a caller + * to your plugin. Be particularly mindful in implementing array dataref + * read-write accessors; you are responsible for avoiding overruns, supporting + * offset read/writes, and handling a read with a NULL buffer. + * + */ +typedef int (*XPLMGetDatai_f)(void *inRefcon); + +/* + * XPLMSetDatai_f + * + * + */ +typedef void (*XPLMSetDatai_f)(void *inRefcon, int inValue); + +/* + * XPLMGetDataf_f + * + * + */ +typedef float (*XPLMGetDataf_f)(void *inRefcon); + +/* + * XPLMSetDataf_f + * + * + */ +typedef void (*XPLMSetDataf_f)(void *inRefcon, float inValue); + +/* + * XPLMGetDatad_f + * + * + */ +typedef double (*XPLMGetDatad_f)(void *inRefcon); + +/* + * XPLMSetDatad_f + * + * + */ +typedef void (*XPLMSetDatad_f)(void *inRefcon, double inValue); + +/* + * XPLMGetDatavi_f + * + * + */ +typedef int (*XPLMGetDatavi_f)(void *inRefcon, + int *outValues, /* Can be NULL */ + int inOffset, + int inMax); + +/* + * XPLMSetDatavi_f + * + * + */ +typedef void (*XPLMSetDatavi_f)(void *inRefcon, + int *inValues, + int inOffset, + int inCount); + +/* + * XPLMGetDatavf_f + * + * + */ +typedef int (*XPLMGetDatavf_f)(void *inRefcon, + float *outValues, /* Can be NULL */ + int inOffset, + int inMax); + +/* + * XPLMSetDatavf_f + * + * + */ +typedef void (*XPLMSetDatavf_f)(void *inRefcon, + float *inValues, + int inOffset, + int inCount); + +/* + * XPLMGetDatab_f + * + * + */ +typedef int (*XPLMGetDatab_f)(void *inRefcon, + void *outValue, /* Can be NULL */ + int inOffset, + int inMaxLength); + +/* + * XPLMSetDatab_f + * + * + */ +typedef void (*XPLMSetDatab_f)(void *inRefcon, + void *inValue, + int inOffset, + int inLength); + +/* + * XPLMRegisterDataAccessor + * + * This routine creates a new item of data that can be read and written. Pass + * in the data's full name for searching, the type(s) of the data for + * accessing, and whether the data can be written to. For each data type you + * support, pass in a read accessor function and a write accessor function if + * necessary. Pass NULL for data types you do not support or write accessors + * if you are read-only. + * + * You are returned a data ref for the new item of data created. You can use + * this data ref to unregister your data later or read or write from it. + * + */ +XPLM_API XPLMDataRef XPLMRegisterDataAccessor(const char *inDataName, + XPLMDataTypeID inDataType, + int inIsWritable, + XPLMGetDatai_f inReadInt, + XPLMSetDatai_f inWriteInt, + XPLMGetDataf_f inReadFloat, + XPLMSetDataf_f inWriteFloat, + XPLMGetDatad_f inReadDouble, + XPLMSetDatad_f inWriteDouble, + XPLMGetDatavi_f inReadIntArray, + XPLMSetDatavi_f inWriteIntArray, + XPLMGetDatavf_f inReadFloatArray, + XPLMSetDatavf_f inWriteFloatArray, + XPLMGetDatab_f inReadData, + XPLMSetDatab_f inWriteData, + void *inReadRefcon, + void *inWriteRefcon); + +/* + * XPLMUnregisterDataAccessor + * + * Use this routine to unregister any data accessors you may have registered. + * You unregister a data ref by the XPLMDataRef you get back from + * registration. Once you unregister a data ref, your function pointer will + * not be called anymore. + * + * For maximum compatibility, do not unregister your data accessors until + * final shutdown (when your XPluginStop routine is called). This allows + * other plugins to find your data reference once and use it for their entire + * time of operation. + * + */ +XPLM_API void XPLMUnregisterDataAccessor(XPLMDataRef inDataRef); + +/*************************************************************************** + * SHARING DATA BETWEEN MULTIPLE PLUGINS + ***************************************************************************/ +/* + * The data reference registration APIs from the previous section allow a + * plugin to publish data in a one-owner manner; the plugin that publishes the + * data reference owns the real memory that the data ref uses. This is + * satisfactory for most cases, but there are also cases where plugnis need to + * share actual data. + * + * With a shared data reference, no one plugin owns the actual memory for the + * data reference; the plugin SDK allocates that for you. When the first + * plugin asks to 'share' the data, the memory is allocated. When the data is + * changed, every plugin that is sharing the data is notified. + * + * Shared data references differ from the 'owned' data references from the + * previous section in a few ways: + * + * - With shared data references, any plugin can create the data reference; + * with owned plugins one plugin must create the data reference and others + * subscribe. (This can be a problem if you don't know which set of plugins + * will be present). + * + * - With shared data references, every plugin that is sharing the data is + * notified when the data is changed. With owned data references, only the + * one owner is notified when the data is changed. + * + * - With shared data references, you cannot access the physical memory of the + * data reference; you must use the XPLMGet... and XPLMSet... APIs. With an + * owned data reference, the one owning data reference can manipulate the + * data reference's memory in any way it sees fit. + * + * Shared data references solve two problems: if you need to have a data + * reference used by several plugins but do not know which plugins will be + * installed, or if all plugins sharing data need to be notified when that + * data is changed, use shared data references. + * + */ + + +/* + * XPLMDataChanged_f + * + * An XPLMDataChanged_f is a callback that the XPLM calls whenever any other + * plug-in modifies shared data. A refcon you provide is passed back to help + * identify which data is being changed. In response, you may want to call one + * of the XPLMGetDataxxx routines to find the new value of the data. + * + */ +typedef void (*XPLMDataChanged_f)(void *inRefcon); + +/* + * XPLMShareData + * + * This routine connects a plug-in to shared data, creating the shared data if + * necessary. inDataName is a standard path for the data ref, and inDataType + * specifies the type. This function will create the data if it does not + * exist. If the data already exists but the type does not match, an error is + * returned, so it is important that plug-in authors collaborate to establish + * public standards for shared data. + * + * If a notificationFunc is passed in and is not NULL, that notification + * function will be called whenever the data is modified. The notification + * refcon will be passed to it. This allows your plug-in to know which shared + * data was changed if multiple shared data are handled by one callback, or if + * the plug-in does not use global variables. + * + * A one is returned for successfully creating or finding the shared data; a + * zero if the data already exists but is of the wrong type. + * + */ +XPLM_API int XPLMShareData(const char *inDataName, + XPLMDataTypeID inDataType, + XPLMDataChanged_f inNotificationFunc, + void *inNotificationRefcon); + +/* + * XPLMUnshareData + * + * This routine removes your notification function for shared data. Call it + * when done with the data to stop receiving change notifications. Arguments + * must match XPLMShareData. The actual memory will not necessarily be freed, + * since other plug-ins could be using it. + * + */ +XPLM_API int XPLMUnshareData(const char *inDataName, + XPLMDataTypeID inDataType, + XPLMDataChanged_f inNotificationFunc, + void *inNotificationRefcon); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/GermanAirlinesVA-GAConnector/XPSDK/CHeaders/XPLM/XPLMDefs.h b/GermanAirlinesVA-GAConnector/XPSDK/CHeaders/XPLM/XPLMDefs.h new file mode 100644 index 0000000..c720e70 --- /dev/null +++ b/GermanAirlinesVA-GAConnector/XPSDK/CHeaders/XPLM/XPLMDefs.h @@ -0,0 +1,518 @@ +#ifndef _XPLMDefs_h_ +#define _XPLMDefs_h_ + +/* + * Copyright 2005-2012 Sandy Barbour and Ben Supnik + * + * All rights reserved. See license.txt for usage. + * + * X-Plane SDK Version: 2.1.1 + * + */ + +/* + * This file is contains the cross-platform and basic definitions for the + * X-Plane SDK. + * + * The preprocessor macros APL and IBM must be defined to specify the + * compilation target; define APL to 1 and IBM 0 to compile on Macintosh and + * APL to 0 and IBM to 1 for Windows. You must specify these macro definitions + * before including XPLMDefs.h or any other XPLM headers. You can do this + * using the -D command line option or a preprocessor header. + * + */ + + +#ifdef __cplusplus +extern "C" { +#endif + +#if IBM +#include +#else +#include +#endif +/*************************************************************************** + * DLL Definitions + ***************************************************************************/ +/* + * These definitions control the importing and exporting of functions within + * the DLL. + * + * You can prefix your five required callbacks with the PLUGIN_API macro to + * declare them as exported C functions. The XPLM_API macro identifies + * functions that are provided to you via the plugin SDK. (Link against + * XPLM.lib to use these functions.) + * + */ + + +#ifdef __cplusplus +#if APL +#if __GNUC__ >= 4 +#define PLUGIN_API extern "C" __attribute__((visibility("default"))) +#elif __MACH__ +#define PLUGIN_API extern "C" +#else +#define PLUGIN_API extern "C" __declspec(dllexport) +#endif +#elif IBM +#define PLUGIN_API extern "C" __declspec(dllexport) +#elif LIN +#if __GNUC__ >= 4 +#define PLUGIN_API extern "C" __attribute__((visibility("default"))) +#else +#define PLUGIN_API extern "C" +#endif +#else +#error "Platform not defined!" +#endif +#else +#if APL +#if __GNUC__ >= 4 +#define PLUGIN_API __attribute__((visibility("default"))) +#elif __MACH__ +#define PLUGIN_API +#else +#define PLUGIN_API __declspec(dllexport) +#endif +#elif IBM +#define PLUGIN_API __declspec(dllexport) +#elif LIN +#if __GNUC__ >= 4 +#define PLUGIN_API __attribute__((visibility("default"))) +#else +#define PLUGIN_API +#endif +#else +#error "Platform not defined!" +#endif +#endif + +#if APL +#if XPLM +#if __GNUC__ >= 4 +#define XPLM_API __attribute__((visibility("default"))) +#elif __MACH__ +#define XPLM_API +#else +#define XPLM_API __declspec(dllexport) +#endif +#else +#define XPLM_API +#endif +#elif IBM +#if XPLM +#define XPLM_API __declspec(dllexport) +#else +#define XPLM_API __declspec(dllimport) +#endif +#elif LIN +#if XPLM +#if __GNUC__ >= 4 +#define XPLM_API __attribute__((visibility("default"))) +#else +#define XPLM_API +#endif +#else +#define XPLM_API +#endif +#else +#error "Platform not defined!" +#endif + +/*************************************************************************** + * GLOBAL DEFINITIONS + ***************************************************************************/ +/* + * These definitions are used in all parts of the SDK. + * + */ + + +/* + * XPLMPluginID + * + * Each plug-in is identified by a unique integer ID. This ID can be used to + * disable or enable a plug-in, or discover what plug-in is 'running' at the + * time. A plug-in ID is unique within the currently running instance of + * X-Plane unless plug-ins are reloaded. Plug-ins may receive a different + * unique ID each time they are loaded. + * + * For persistent identification of plug-ins, use XPLMFindPluginBySignature in + * XPLMUtiltiies.h + * + * -1 indicates no plug-in. + * + */ +typedef int XPLMPluginID; + +/* No plugin. */ +#define XPLM_NO_PLUGIN_ID (-1) + +/* X-Plane itself */ +#define XPLM_PLUGIN_XPLANE (0) + +/* The current XPLM revision is 2.10 (210). */ +#define kXPLM_Version (210) + +/* + * XPLMKeyFlags + * + * These bitfields define modifier keys in a platform independent way. When a + * key is pressed, a series of messages are sent to your plugin. The down + * flag is set in the first of these messages, and the up flag in the last. + * While the key is held down, messages are sent with neither to indicate that + * the key is being held down as a repeated character. + * + * The control flag is mapped to the control flag on Macintosh and PC. + * Generally X-Plane uses the control key and not the command key on + * Macintosh, providing a consistent interface across platforms that does not + * necessarily match the Macintosh user interface guidelines. There is not + * yet a way for plugins to access the Macintosh control keys without using + * #ifdefed code. + * + */ +enum { + /* The shift key is down */ + xplm_ShiftFlag = 1 + + /* The option or alt key is down */ + , + xplm_OptionAltFlag = 2 + + /* The control key is down* */ + , + xplm_ControlFlag = 4 + + /* The key is being pressed down */ + , + xplm_DownFlag = 8 + + /* The key is being released */ + , + xplm_UpFlag = 16 + + +}; +typedef int XPLMKeyFlags; + +/*************************************************************************** + * ASCII CONTROL KEY CODES + ***************************************************************************/ +/* + * These definitions define how various control keys are mapped to ASCII key + * codes. Not all key presses generate an ASCII value, so plugin code should + * be prepared to see null characters come from the keyboard...this usually + * represents a key stroke that has no equivalent ASCII, like a page-down + * press. Use virtual key codes to find these key strokes. ASCII key codes + * take into account modifier keys; shift keys will affect capitals and + * punctuation; control key combinations may have no vaild ASCII and produce + * NULL. To detect control-key combinations, use virtual key codes, not ASCII + * keys. + * + */ + + +#define XPLM_KEY_RETURN 13 + +#define XPLM_KEY_ESCAPE 27 + +#define XPLM_KEY_TAB 9 + +#define XPLM_KEY_DELETE 8 + +#define XPLM_KEY_LEFT 28 + +#define XPLM_KEY_RIGHT 29 + +#define XPLM_KEY_UP 30 + +#define XPLM_KEY_DOWN 31 + +#define XPLM_KEY_0 48 + +#define XPLM_KEY_1 49 + +#define XPLM_KEY_2 50 + +#define XPLM_KEY_3 51 + +#define XPLM_KEY_4 52 + +#define XPLM_KEY_5 53 + +#define XPLM_KEY_6 54 + +#define XPLM_KEY_7 55 + +#define XPLM_KEY_8 56 + +#define XPLM_KEY_9 57 + +#define XPLM_KEY_DECIMAL 46 + +/*************************************************************************** + * VIRTUAL KEY CODES + ***************************************************************************/ +/* + * These are cross-platform defines for every distinct keyboard press on the + * computer. Every physical key on the keyboard has a virtual key code. So + * the "two" key on the top row of the main keyboard has a different code + * from the "two" key on the numeric key pad. But the 'w' and 'W' character + * are indistinguishable by virtual key code because they are the same + * physical key (one with and one without the shift key). + * + * Use virtual key codes to detect keystrokes that do not have ASCII + * equivalents, allow the user to map the numeric keypad separately from the + * main keyboard, and detect control key and other modifier-key combinations + * that generate ASCII control key sequences (many of which are not available + * directly via character keys in the SDK). + * + * To assign virtual key codes we started with the Microsoft set but made some + * additions and changes. A few differences: + * + * 1. Modifier keys are not available as virtual key codes. You cannot get + * distinct modifier press and release messages. Please do not try to use + * modifier keys as regular keys; doing so will almost certainly interfere + * with users' abilities to use the native x-plane key bindings. + * + * 2. Some keys that do not exist on both Mac and PC keyboards are removed. + * + * 3. Do not assume that the values of these keystrokes are interchangeable + * with MS v-keys. + * + */ + + +#define XPLM_VK_BACK 0x08 + +#define XPLM_VK_TAB 0x09 + +#define XPLM_VK_CLEAR 0x0C + +#define XPLM_VK_RETURN 0x0D + +#define XPLM_VK_ESCAPE 0x1B + +#define XPLM_VK_SPACE 0x20 + +#define XPLM_VK_PRIOR 0x21 + +#define XPLM_VK_NEXT 0x22 + +#define XPLM_VK_END 0x23 + +#define XPLM_VK_HOME 0x24 + +#define XPLM_VK_LEFT 0x25 + +#define XPLM_VK_UP 0x26 + +#define XPLM_VK_RIGHT 0x27 + +#define XPLM_VK_DOWN 0x28 + +#define XPLM_VK_SELECT 0x29 + +#define XPLM_VK_PRINT 0x2A + +#define XPLM_VK_EXECUTE 0x2B + +#define XPLM_VK_SNAPSHOT 0x2C + +#define XPLM_VK_INSERT 0x2D + +#define XPLM_VK_DELETE 0x2E + +#define XPLM_VK_HELP 0x2F + +/* XPLM_VK_0 thru XPLM_VK_9 are the same as ASCII '0' thru '9' (0x30 - 0x39) */ +#define XPLM_VK_0 0x30 + +#define XPLM_VK_1 0x31 + +#define XPLM_VK_2 0x32 + +#define XPLM_VK_3 0x33 + +#define XPLM_VK_4 0x34 + +#define XPLM_VK_5 0x35 + +#define XPLM_VK_6 0x36 + +#define XPLM_VK_7 0x37 + +#define XPLM_VK_8 0x38 + +#define XPLM_VK_9 0x39 + +/* XPLM_VK_A thru XPLM_VK_Z are the same as ASCII 'A' thru 'Z' (0x41 - 0x5A) */ +#define XPLM_VK_A 0x41 + +#define XPLM_VK_B 0x42 + +#define XPLM_VK_C 0x43 + +#define XPLM_VK_D 0x44 + +#define XPLM_VK_E 0x45 + +#define XPLM_VK_F 0x46 + +#define XPLM_VK_G 0x47 + +#define XPLM_VK_H 0x48 + +#define XPLM_VK_I 0x49 + +#define XPLM_VK_J 0x4A + +#define XPLM_VK_K 0x4B + +#define XPLM_VK_L 0x4C + +#define XPLM_VK_M 0x4D + +#define XPLM_VK_N 0x4E + +#define XPLM_VK_O 0x4F + +#define XPLM_VK_P 0x50 + +#define XPLM_VK_Q 0x51 + +#define XPLM_VK_R 0x52 + +#define XPLM_VK_S 0x53 + +#define XPLM_VK_T 0x54 + +#define XPLM_VK_U 0x55 + +#define XPLM_VK_V 0x56 + +#define XPLM_VK_W 0x57 + +#define XPLM_VK_X 0x58 + +#define XPLM_VK_Y 0x59 + +#define XPLM_VK_Z 0x5A + +#define XPLM_VK_NUMPAD0 0x60 + +#define XPLM_VK_NUMPAD1 0x61 + +#define XPLM_VK_NUMPAD2 0x62 + +#define XPLM_VK_NUMPAD3 0x63 + +#define XPLM_VK_NUMPAD4 0x64 + +#define XPLM_VK_NUMPAD5 0x65 + +#define XPLM_VK_NUMPAD6 0x66 + +#define XPLM_VK_NUMPAD7 0x67 + +#define XPLM_VK_NUMPAD8 0x68 + +#define XPLM_VK_NUMPAD9 0x69 + +#define XPLM_VK_MULTIPLY 0x6A + +#define XPLM_VK_ADD 0x6B + +#define XPLM_VK_SEPARATOR 0x6C + +#define XPLM_VK_SUBTRACT 0x6D + +#define XPLM_VK_DECIMAL 0x6E + +#define XPLM_VK_DIVIDE 0x6F + +#define XPLM_VK_F1 0x70 + +#define XPLM_VK_F2 0x71 + +#define XPLM_VK_F3 0x72 + +#define XPLM_VK_F4 0x73 + +#define XPLM_VK_F5 0x74 + +#define XPLM_VK_F6 0x75 + +#define XPLM_VK_F7 0x76 + +#define XPLM_VK_F8 0x77 + +#define XPLM_VK_F9 0x78 + +#define XPLM_VK_F10 0x79 + +#define XPLM_VK_F11 0x7A + +#define XPLM_VK_F12 0x7B + +#define XPLM_VK_F13 0x7C + +#define XPLM_VK_F14 0x7D + +#define XPLM_VK_F15 0x7E + +#define XPLM_VK_F16 0x7F + +#define XPLM_VK_F17 0x80 + +#define XPLM_VK_F18 0x81 + +#define XPLM_VK_F19 0x82 + +#define XPLM_VK_F20 0x83 + +#define XPLM_VK_F21 0x84 + +#define XPLM_VK_F22 0x85 + +#define XPLM_VK_F23 0x86 + +#define XPLM_VK_F24 0x87 + +/* The following definitions are extended and are not based on the Microsoft * + * key set. */ +#define XPLM_VK_EQUAL 0xB0 + +#define XPLM_VK_MINUS 0xB1 + +#define XPLM_VK_RBRACE 0xB2 + +#define XPLM_VK_LBRACE 0xB3 + +#define XPLM_VK_QUOTE 0xB4 + +#define XPLM_VK_SEMICOLON 0xB5 + +#define XPLM_VK_BACKSLASH 0xB6 + +#define XPLM_VK_COMMA 0xB7 + +#define XPLM_VK_SLASH 0xB8 + +#define XPLM_VK_PERIOD 0xB9 + +#define XPLM_VK_BACKQUOTE 0xBA + +#define XPLM_VK_ENTER 0xBB + +#define XPLM_VK_NUMPAD_ENT 0xBC + +#define XPLM_VK_NUMPAD_EQ 0xBD + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/GermanAirlinesVA-GAConnector/XPSDK/CHeaders/XPLM/XPLMDisplay.h b/GermanAirlinesVA-GAConnector/XPSDK/CHeaders/XPLM/XPLMDisplay.h new file mode 100644 index 0000000..c2f16bc --- /dev/null +++ b/GermanAirlinesVA-GAConnector/XPSDK/CHeaders/XPLM/XPLMDisplay.h @@ -0,0 +1,743 @@ +#ifndef _XPLMDisplay_h_ +#define _XPLMDisplay_h_ + +/* + * Copyright 2005-2012 Sandy Barbour and Ben Supnik + * + * All rights reserved. See license.txt for usage. + * + * X-Plane SDK Version: 2.1.1 + * + */ + +/* + * XPLM Display APIs - THEORY OF OPERATION + * + * This API provides the basic hooks to draw in X-Plane and create user + * interface. All X-Plane drawing is done in OpenGL. The X-Plane plug-in + * manager takes care of properly setting up the OpenGL context and matrices. + * You do not decide when in your code's execution to draw; X-Plane tells you + * when it is ready to have your plugin draw. + * + * X-Plane's drawing strategy is straightforward: every "frame" the screen is + * rendered by drawing the 3-d scene (dome, ground, objects, airplanes, etc.) + * and then drawing the cockpit on top of it. Alpha blending is used to + * overlay the cockpit over the world (and the gauges over the panel, etc.). + * + * There are two ways you can draw: directly and in a window. + * + * Direct drawing involves drawing to the screen before or after X-Plane + * finishes a phase of drawing. When you draw directly, you can specify + * whether x-plane is to complete this phase or not. This allows you to do + * three things: draw before x-plane does (under it), draw after x-plane does + * (over it), or draw instead of x-plane. + * + * To draw directly, you register a callback and specify what phase you want + * to intercept. The plug-in manager will call you over and over to draw that + * phase. + * + * Direct drawing allows you to override scenery, panels, or anything. Note + * that you cannot assume that you are the only plug-in drawing at this + * phase. + * + * Window drawing provides slightly higher level functionality. With window + * drawing you create a window that takes up a portion of the screen. Window + * drawing is always two dimensional. Window drawing is front-to-back + * controlled; you can specify that you want your window to be brought on + * top, and other plug-ins may put their window on top of you. Window drawing + * also allows you to sign up for key presses and receive mouse clicks. + * + * There are three ways to get keystrokes: + * + * If you create a window, the window can take keyboard focus. It will then + * receive all keystrokes. If no window has focus, X-Plane receives + * keystrokes. Use this to implement typing in dialog boxes, etc. Only one + * window may have focus at a time; your window will be notified if it loses + * focus. + * + * If you need to associate key strokes with commands/functions in your + * plug-in, use a hot key. A hoy is a key-specific callback. Hotkeys are + * sent based on virtual key strokes, so any key may be distinctly mapped with + * any modifiers. Hot keys can be remapped by other plug-ins. As a plug-in, + * you don't have to worry about what your hot key ends up mapped to; other + * plug-ins may provide a UI for remapping keystrokes. So hotkeys allow a + * user to resolve conflicts and customize keystrokes. + * + * If you need low level access to the keystroke stream, install a key + * sniffer. Key sniffers can be installed above everything or right in front + * of the sim. + * + */ + +#include "XPLMDefs.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/*************************************************************************** + * DRAWING CALLBACKS + ***************************************************************************/ +/* + * Basic drawing callbacks, for low level intercepting of render loop. The + * purpose of drawing callbacks is to provide targeted additions or + * replacements to x-plane's graphics environment (for example, to add extra + * custom objects, or replace drawing of the AI aircraft). Do not assume that + * the drawing callbacks will be called in the order implied by the + * enumerations. Also do not assume that each drawing phase ends before + * another begins; they may be nested. + * + */ + + +/* + * XPLMDrawingPhase + * + * This constant indicates which part of drawing we are in. Drawing is done + * from the back to the front. We get a callback before or after each item. + * Metaphases provide access to the beginning and end of the 3d (scene) and 2d + * (cockpit) drawing in a manner that is independent of new phases added via + * x-plane implementation. + * + * WARNING: As X-Plane's scenery evolves, some drawing phases may cease to + * exist and new ones may be invented. If you need a particularly specific + * use of these codes, consult Austin and/or be prepared to revise your code + * as X-Plane evolves. + * + */ +enum { + /* This is the earliest point at which you can draw in 3-d. */ + xplm_Phase_FirstScene = 0 + + /* Drawing of land and water. */ + , + xplm_Phase_Terrain = 5 + + /* Drawing runways and other airport detail. */ + , + xplm_Phase_Airports = 10 + + /* Drawing roads, trails, trains, etc. */ + , + xplm_Phase_Vectors = 15 + + /* 3-d objects (houses, smokestacks, etc. */ + , + xplm_Phase_Objects = 20 + + /* External views of airplanes, both yours and the AI aircraft. */ + , + xplm_Phase_Airplanes = 25 + + /* This is the last point at which you can draw in 3-d. */ + , + xplm_Phase_LastScene = 30 + + /* This is the first phase where you can draw in 2-d. */ + , + xplm_Phase_FirstCockpit = 35 + + /* The non-moving parts of the aircraft panel. */ + , + xplm_Phase_Panel = 40 + + /* The moving parts of the aircraft panel. */ + , + xplm_Phase_Gauges = 45 + + /* Floating windows from plugins. */ + , + xplm_Phase_Window = 50 + + /* The last change to draw in 2d. */ + , + xplm_Phase_LastCockpit = 55 + +#if defined(XPLM200) + /* 3-d Drawing for the local map. Use regular OpenGL coordinates to draw in + * * this phase. */ + , + xplm_Phase_LocalMap3D = 100 + +#endif /* XPLM200 */ +#if defined(XPLM200) + /* 2-d Drawing of text over the local map. */ + , + xplm_Phase_LocalMap2D = 101 + +#endif /* XPLM200 */ +#if defined(XPLM200) + /* Drawing of the side-profile view in the local map screen. */ + , + xplm_Phase_LocalMapProfile = 102 + +#endif /* XPLM200 */ + +}; +typedef int XPLMDrawingPhase; + +/* + * XPLMDrawCallback_f + * + * This is the prototype for a low level drawing callback. You are passed in + * the phase and whether it is before or after. If you are before the phase, + * return 1 to let x-plane draw or 0 to suppress x-plane drawing. If you are + * after the phase the return value is ignored. + * + * Refcon is a unique value that you specify when registering the callback, + * allowing you to slip a pointer to your own data to the callback. + * + * Upon entry the OpenGL context will be correctly set up for you and OpenGL + * will be in 'local' coordinates for 3d drawing and panel coordinates for 2d + * drawing. The OpenGL state (texturing, etc.) will be unknown. + * + */ +typedef int (*XPLMDrawCallback_f)(XPLMDrawingPhase inPhase, + int inIsBefore, + void *inRefcon); + +/* + * XPLMKeySniffer_f + * + * This is the prototype for a low level key-sniffing function. Window-based + * UI _should not use this_! The windowing system provides high-level + * mediated keyboard access. By comparison, the key sniffer provides low + * level keyboard access. + * + * Key sniffers are provided to allow libraries to provide non-windowed user + * interaction. For example, the MUI library uses a key sniffer to do pop-up + * text entry. + * + * inKey is the character pressed, inRefCon is a value you supply during + * registration. Return 1 to pass the key on to the next sniffer, the window + * mgr, x-plane, or whomever is down stream. Return 0 to consume the key. + * + * Warning: this API declares virtual keys as a signed character; however the + * VKEY #define macros in XPLMDefs.h define the vkeys using unsigned values + * (that is 0x80 instead of -0x80). So you may need to cast the incoming vkey + * to an unsigned char to get correct comparisons in C. + * + */ +typedef int (*XPLMKeySniffer_f)(char inChar, + XPLMKeyFlags inFlags, + char inVirtualKey, + void *inRefcon); + +/* + * XPLMRegisterDrawCallback + * + * This routine registers a low level drawing callback. Pass in the phase you + * want to be called for and whether you want to be called before or after. + * This routine returns 1 if the registration was successful, or 0 if the + * phase does not exist in this version of x-plane. You may register a + * callback multiple times for the same or different phases as long as the + * refcon is unique each time. + * + */ +XPLM_API int XPLMRegisterDrawCallback(XPLMDrawCallback_f inCallback, + XPLMDrawingPhase inPhase, + int inWantsBefore, + void *inRefcon); + +/* + * XPLMUnregisterDrawCallback + * + * This routine unregisters a draw callback. You must unregister a callback + * for each time you register a callback if you have registered it multiple + * times with different refcons. The routine returns 1 if it can find the + * callback to unregister, 0 otherwise. + * + */ +XPLM_API int XPLMUnregisterDrawCallback(XPLMDrawCallback_f inCallback, + XPLMDrawingPhase inPhase, + int inWantsBefore, + void *inRefcon); + +/* + * XPLMRegisterKeySniffer + * + * This routine registers a key sniffing callback. You specify whether you + * want to sniff before the window system, or only sniff keys the window + * system does not consume. You should ALMOST ALWAYS sniff non-control keys + * after the window system. When the window system consumes a key, it is + * because the user has "focused" a window. Consuming the key or taking + * action based on the key will produce very weird results. Returns 1 if + * successful. + * + */ +XPLM_API int XPLMRegisterKeySniffer(XPLMKeySniffer_f inCallback, + int inBeforeWindows, + void *inRefcon); + +/* + * XPLMUnregisterKeySniffer + * + * This routine unregisters a key sniffer. You must unregister a key sniffer + * for every time you register one with the exact same signature. Returns 1 + * if successful. + * + */ +XPLM_API int XPLMUnregisterKeySniffer(XPLMKeySniffer_f inCallback, + int inBeforeWindows, + void *inRefcon); + +/*************************************************************************** + * WINDOW API + ***************************************************************************/ +/* + * Window API, for higher level drawing with UI interaction. + * + * Note: all 2-d (and thus all window drawing) is done in 'cockpit pixels'. + * Even when the OpenGL window contains more than 1024x768 pixels, the cockpit + * drawing is magnified so that only 1024x768 pixels are available. + * + */ + + +/* + * XPLMMouseStatus + * + * When the mouse is clicked, your mouse click routine is called repeatedly. + * It is first called with the mouse down message. It is then called zero or + * more times with the mouse-drag message, and finally it is called once with + * the mouse up message. All of these messages will be directed to the same + * window. + * + */ +enum { + xplm_MouseDown = 1 + + , + xplm_MouseDrag = 2 + + , + xplm_MouseUp = 3 + + +}; +typedef int XPLMMouseStatus; + +#if defined(XPLM200) +/* + * XPLMCursorStatus + * + * XPLMCursorStatus describes how you would like X-Plane to manage the cursor. + * See XPLMHandleCursor_f for more info. + * + */ +enum { + /* X-Plane manages the cursor normally, plugin does not affect the cusrsor. + */ + xplm_CursorDefault = 0 + + /* X-Plane hides the cursor. */ + , + xplm_CursorHidden = 1 + + /* X-Plane shows the cursor as the default arrow. */ + , + xplm_CursorArrow = 2 + + /* X-Plane shows the cursor but lets you select an OS cursor. */ + , + xplm_CursorCustom = 3 + + +}; +typedef int XPLMCursorStatus; +#endif /* XPLM200 */ + +/* + * XPLMWindowID + * + * This is an opaque identifier for a window. You use it to control your + * window. When you create a window, you will specify callbacks to handle + * drawing and mouse interaction, etc. + * + */ +typedef void *XPLMWindowID; + +/* + * XPLMDrawWindow_f + * + * This function handles drawing. You are passed in your window and its + * refcon. Draw the window. You can use XPLM functions to find the current + * dimensions of your window, etc. When this callback is called, the OpenGL + * context will be set properly for cockpit drawing. NOTE: Because you are + * drawing your window over a background, you can make a translucent window + * easily by simply not filling in your entire window's bounds. + * + */ +typedef void (*XPLMDrawWindow_f)(XPLMWindowID inWindowID, void *inRefcon); + +/* + * XPLMHandleKey_f + * + * This function is called when a key is pressed or keyboard focus is taken + * away from your window. If losingFocus is 1, you are losign the keyboard + * focus, otherwise a key was pressed and inKey contains its character. You + * are also passewd your window and a refcon. Warning: this API declares + * virtual keys as a signed character; however the VKEY #define macros in + * XPLMDefs.h define the vkeys using unsigned values (that is 0x80 instead of + * -0x80). So you may need to cast the incoming vkey to an unsigned char to + * get correct comparisons in C. + * + */ +typedef void (*XPLMHandleKey_f)(XPLMWindowID inWindowID, + char inKey, + XPLMKeyFlags inFlags, + char inVirtualKey, + void *inRefcon, + int losingFocus); + +/* + * XPLMHandleMouseClick_f + * + * You receive this call when the mouse button is pressed down or released. + * Between then these two calls is a drag. You receive the x and y of the + * click, your window, and a refcon. Return 1 to consume the click, or 0 to + * pass it through. + * + * WARNING: passing clicks through windows (as of this writing) causes mouse + * tracking problems in X-Plane; do not use this feature! + * + */ +typedef int (*XPLMHandleMouseClick_f)(XPLMWindowID inWindowID, + int x, + int y, + XPLMMouseStatus inMouse, + void *inRefcon); + +#if defined(XPLM200) +/* + * XPLMHandleCursor_f + * + * The SDK calls your cursor status callback when the mouse is over your + * plugin window. Return a cursor status code to indicate how you would like + * X-Plane to manage the cursor. If you return xplm_CursorDefault, the SDK + * will try lower-Z-order plugin windows, then let the sim manage the cursor. + * + * Note: you should never show or hide the cursor yourself - these APIs are + * typically reference-counted and thus cannot safely and predictably be used + * by the SDK. Instead return one of xplm_CursorHidden to hide the cursor or + * xplm_CursorArrow/xplm_CursorCustom to show the cursor. + * + * If you want to implement a custom cursor by drawing a cursor in OpenGL, use + * xplm_CursorHidden to hide the OS cursor and draw the cursor using a 2-d + * drawing callback (after xplm_Phase_Window is probably a good choice). If + * you want to use a custom OS-based cursor, use xplm_CursorCustom to ask + * X-Plane to show the cursor but not affect its image. You can then use an + * OS specific call like SetThemeCursor (Mac) or SetCursor/LoadCursor + * (Windows). + * + */ +typedef XPLMCursorStatus (*XPLMHandleCursor_f)(XPLMWindowID inWindowID, + int x, + int y, + void *inRefcon); +#endif /* XPLM200 */ + +#if defined(XPLM200) +/* + * XPLMHandleMouseWheel_f + * + * The SDK calls your mouse wheel callback when one of the mouse wheels is + * turned within your window. Return 1 to consume the mouse wheel clicks or + * 0 to pass them on to a lower window. (You should consume mouse wheel + * clicks even if they do nothing if your window appears opaque to the user.) + * The number of clicks indicates how far the wheel was turned since the last + * callback. The wheel is 0 for the vertical axis or 1 for the horizontal axis + * (for OS/mouse combinations that support this). + * + */ +typedef int (*XPLMHandleMouseWheel_f)(XPLMWindowID inWindowID, + int x, + int y, + int wheel, + int clicks, + void *inRefcon); +#endif /* XPLM200 */ + +#if defined(XPLM200) +/* + * XPLMCreateWindow_t + * + * The XPMCreateWindow_t structure defines all of the parameters used to + * create a window using XPLMCreateWindowEx. The structure will be expanded + * in future SDK APIs to include more features. Always set the structSize + * member to the size of your struct in bytes! + * + */ +typedef struct { + int structSize; + int left; + int top; + int right; + int bottom; + int visible; + XPLMDrawWindow_f drawWindowFunc; + XPLMHandleMouseClick_f handleMouseClickFunc; + XPLMHandleKey_f handleKeyFunc; + XPLMHandleCursor_f handleCursorFunc; + XPLMHandleMouseWheel_f handleMouseWheelFunc; + void *refcon; +} XPLMCreateWindow_t; +#endif /* XPLM200 */ + +/* + * XPLMGetScreenSize + * + * This routine returns the size of the size of the X-Plane OpenGL window in + * pixels. Please note that this is not the size of the screen when doing + * 2-d drawing (the 2-d screen is currently always 1024x768, and graphics are + * scaled up by OpenGL when doing 2-d drawing for higher-res monitors). This + * number can be used to get a rough idea of the amount of detail the user + * will be able to see when drawing in 3-d. + * + */ +XPLM_API void XPLMGetScreenSize(int *outWidth, /* Can be NULL */ + int *outHeight); /* Can be NULL */ + +/* + * XPLMGetMouseLocation + * + * This routine returns the current mouse location in cockpit pixels. The + * bottom left corner of the display is 0,0. Pass NULL to not receive info + * about either parameter. + * + */ +XPLM_API void XPLMGetMouseLocation(int *outX, /* Can be NULL */ + int *outY); /* Can be NULL */ + +/* + * XPLMCreateWindow + * + * This routine creates a new window. Pass in the dimensions and offsets to + * the window's bottom left corner from the bottom left of the screen. You + * can specify whether the window is initially visible or not. Also, you pass + * in three callbacks to run the window and a refcon. This function returns a + * window ID you can use to refer to the new window. + * + * NOTE: windows do not have "frames"; you are responsible for drawing the + * background and frame of the window. Higher level libraries have routines + * which make this easy. + * + */ +XPLM_API XPLMWindowID XPLMCreateWindow(int inLeft, + int inTop, + int inRight, + int inBottom, + int inIsVisible, + XPLMDrawWindow_f inDrawCallback, + XPLMHandleKey_f inKeyCallback, + XPLMHandleMouseClick_f inMouseCallback, + void *inRefcon); + +#if defined(XPLM200) +/* + * XPLMCreateWindowEx + * + * This routine creates a new window - you pass in an XPLMCreateWindow_t + * structure with all of the fields set in. You must set the structSize of + * the structure to the size of the actual structure you used. Also, you + * must provide funtions for every callback - you may not leave them null! + * (If you do not support the cursor or mouse wheel, use functions that return + * the default values.) The numeric values of the XPMCreateWindow_t structure + * correspond to the parameters of XPLMCreateWindow. + * + */ +XPLM_API XPLMWindowID XPLMCreateWindowEx(XPLMCreateWindow_t *inParams); +#endif /* XPLM200 */ + +/* + * XPLMDestroyWindow + * + * This routine destroys a window. The callbacks are not called after this + * call. Keyboard focus is removed from the window before destroying it. + * + */ +XPLM_API void XPLMDestroyWindow(XPLMWindowID inWindowID); + +/* + * XPLMGetWindowGeometry + * + * This routine returns the position and size of a window in cockpit pixels. + * Pass NULL to not receive any paramter. + * + */ +XPLM_API void XPLMGetWindowGeometry(XPLMWindowID inWindowID, + int *outLeft, /* Can be NULL */ + int *outTop, /* Can be NULL */ + int *outRight, /* Can be NULL */ + int *outBottom); /* Can be NULL */ + +/* + * XPLMSetWindowGeometry + * + * This routine allows you to set the position or height aspects of a window. + * + */ +XPLM_API void XPLMSetWindowGeometry(XPLMWindowID inWindowID, + int inLeft, + int inTop, + int inRight, + int inBottom); + +/* + * XPLMGetWindowIsVisible + * + * This routine returns whether a window is visible. + * + */ +XPLM_API int XPLMGetWindowIsVisible(XPLMWindowID inWindowID); + +/* + * XPLMSetWindowIsVisible + * + * This routine shows or hides a window. + * + */ +XPLM_API void XPLMSetWindowIsVisible(XPLMWindowID inWindowID, int inIsVisible); + +/* + * XPLMGetWindowRefCon + * + * This routine returns a windows refcon, the unique value you can use for + * your own purposes. + * + */ +XPLM_API void *XPLMGetWindowRefCon(XPLMWindowID inWindowID); + +/* + * XPLMSetWindowRefCon + * + * This routine sets a window's reference constant. Use this to pass data to + * yourself in the callbacks. + * + */ +XPLM_API void XPLMSetWindowRefCon(XPLMWindowID inWindowID, void *inRefcon); + +/* + * XPLMTakeKeyboardFocus + * + * This routine gives a specific window keyboard focus. Keystrokes will be + * sent to that window. Pass a window ID of 0 to pass keyboard strokes + * directly to X-Plane. + * + */ +XPLM_API void XPLMTakeKeyboardFocus(XPLMWindowID inWindow); + +/* + * XPLMBringWindowToFront + * + * This routine brings the window to the front of the Z-order. Windows are + * brought to the front when they are created...beyond that you should make + * sure you are front before handling mouse clicks. + * + */ +XPLM_API void XPLMBringWindowToFront(XPLMWindowID inWindow); + +/* + * XPLMIsWindowInFront + * + * This routine returns true if you pass inthe ID of the frontmost visible + * window. + * + */ +XPLM_API int XPLMIsWindowInFront(XPLMWindowID inWindow); + +/*************************************************************************** + * HOT KEYS + ***************************************************************************/ +/* + * Hot Keys - keystrokes that can be managed by others. + * + */ + + +/* + * XPLMHotKey_f + * + * Your hot key callback simply takes a pointer of your choosing. + * + */ +typedef void (*XPLMHotKey_f)(void *inRefcon); + +/* + * XPLMHotKeyID + * + * Hot keys are identified by opaque IDs. + * + */ +typedef void *XPLMHotKeyID; + +/* + * XPLMRegisterHotKey + * + * This routine registers a hot key. You specify your preferred key stroke + * virtual key/flag combination, a description of what your callback does (so + * other plug-ins can describe the plug-in to the user for remapping) and a + * callback function and opaque pointer to pass in). A new hot key ID is + * returned. During execution, the actual key associated with your hot key + * may change, but you are insulated from this. + * + */ +XPLM_API XPLMHotKeyID XPLMRegisterHotKey(char inVirtualKey, + XPLMKeyFlags inFlags, + const char *inDescription, + XPLMHotKey_f inCallback, + void *inRefcon); + +/* + * XPLMUnregisterHotKey + * + * This API unregisters a hot key. You can only register your own hot keys. + * + */ +XPLM_API void XPLMUnregisterHotKey(XPLMHotKeyID inHotKey); + +/* + * XPLMCountHotKeys + * + * Returns the number of current hot keys. + * + */ +XPLM_API int XPLMCountHotKeys(void); + +/* + * XPLMGetNthHotKey + * + * Returns a hot key by index, for iteration on all hot keys. + * + */ +XPLM_API XPLMHotKeyID XPLMGetNthHotKey(int inIndex); + +/* + * XPLMGetHotKeyInfo + * + * Returns information about the hot key. Return NULL for any parameter you + * don't want info about. The description should be at least 512 chars long. + * + */ +XPLM_API void XPLMGetHotKeyInfo(XPLMHotKeyID inHotKey, + char *outVirtualKey, /* Can be NULL */ + XPLMKeyFlags *outFlags, /* Can be NULL */ + char *outDescription, /* Can be NULL */ + XPLMPluginID *outPlugin); /* Can be NULL */ + +/* + * XPLMSetHotKeyCombination + * + * XPLMSetHotKeyCombination remaps a hot keys keystrokes. You may remap + * another plugin's keystrokes. + * + */ +XPLM_API void XPLMSetHotKeyCombination(XPLMHotKeyID inHotKey, + char inVirtualKey, + XPLMKeyFlags inFlags); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/GermanAirlinesVA-GAConnector/XPSDK/CHeaders/XPLM/XPLMGraphics.h b/GermanAirlinesVA-GAConnector/XPSDK/CHeaders/XPLM/XPLMGraphics.h new file mode 100644 index 0000000..0eb3630 --- /dev/null +++ b/GermanAirlinesVA-GAConnector/XPSDK/CHeaders/XPLM/XPLMGraphics.h @@ -0,0 +1,413 @@ +#ifndef _XPLMGraphics_h_ +#define _XPLMGraphics_h_ + +/* + * Copyright 2005-2012 Sandy Barbour and Ben Supnik + * + * All rights reserved. See license.txt for usage. + * + * X-Plane SDK Version: 2.1.1 + * + */ + +/* + * Graphics routines for X-Plane and OpenGL. + * + * A few notes on coordinate systems: + * + * X-Plane uses three kinds of coordinates. Global coordinates are specified + * as latitude, longitude and elevation. This coordinate system never changes + * but is not very precise. + * + * OpenGL (or 'local') coordinates are cartesian and shift with the plane. + * They offer more precision and are used for 3-d OpenGL drawing. The X axis + * is aligned east-west with positive X meaning east. The Y axis is aligned + * straight up and down at the point 0,0,0 (but since the earth is round it is + * not truly straight up and down at other points). The Z axis is aligned + * north-south at 0, 0, 0 with positive Z pointing south (but since the earth + * is round it isn't exactly north-south as you move east or west of 0, 0, 0). + * One unit is one meter and the point 0,0,0 is on the surface of the earth + * at sea level for some latitude and longitude picked by the sim such that + * the user's aircraft is reasonably nearby. + * + * Cockpit coordinates are 2d, with the X axis horizontal and the Y axis + * vertical. The point 0,0 is the bottom left and 1024,768 is the upper right + * of the screen. This is true no matter what resolution the user's monitor is + * in; when running in higher resolution, graphics will be scaled. + * + * Use X-Plane's routines to convert between global and local coordinates. Do + * not attempt to do this conversion yourself; the precise 'roundness' of + * X-Plane's physics model may not match your own, and (to make things + * weirder) the user can potentially customize the physics of the current + * planet. + * + */ + +#include "XPLMDefs.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/*************************************************************************** + * X-PLANE GRAPHICS + ***************************************************************************/ +/* + * These routines allow you to use OpenGL with X-Plane. + * + */ + + +/* + * XPLMTextureID + * + * XPLM Texture IDs name well-known textures in the sim for you to use. This + * allows you to recycle textures from X-Plane, saving VRAM. + * + */ +enum { + /* The bitmap that contains window outlines, button outlines, fonts, etc. */ + xplm_Tex_GeneralInterface = 0 + + /* The exterior paint for the user's aircraft (daytime). */ + , + xplm_Tex_AircraftPaint = 1 + + /* The exterior light map for the user's aircraft. */ + , + xplm_Tex_AircraftLiteMap = 2 + + +}; +typedef int XPLMTextureID; + +/* + * XPLMSetGraphicsState + * + * XPLMSetGraphicsState changes OpenGL's graphics state in a number of ways: + * + * inEnableFog - enables or disables fog, equivalent to: glEnable(GL_FOG); + * + * inNumberTexUnits - enables or disables a number of multitexturing units. If + * the number is 0, 2d texturing is disabled entirely, as in + * glDisable(GL_TEXTURE_2D); Otherwise, 2d texturing is enabled, and a + * number of multitexturing units are enabled sequentially, starting with + * unit 0, e.g. glActiveTextureARB(GL_TEXTURE0_ARB); glEnable + * (GL_TEXTURE_2D); + * + * inEnableLighting - enables or disables OpenGL lighting, e.g. + * glEnable(GL_LIGHTING); glEnable(GL_LIGHT0); + * + * inEnableAlphaTesting - enables or disables the alpha test per pixel, e.g. + * glEnable(GL_ALPHA_TEST); + * + * inEnableAlphaBlending - enables or disables alpha blending per pixel, e.g. + * glEnable(GL_BLEND); + * + * inEnableDepthTesting - enables per pixel depth testing, as in + * glEnable(GL_DEPTH_TEST); + * + * inEnableDepthWriting - enables writing back of depth information to the + * depth bufffer, as in glDepthMask(GL_TRUE); + * + * The purpose of this function is to change OpenGL state while keeping + * X-Plane aware of the state changes; this keeps X-Plane from getting + * surprised by OGL state changes, and prevents X-Plane and plug-ins from + * having to set all state before all draws; XPLMSetGraphicsState internally + * skips calls to change state that is already properly enabled. + * + * X-Plane does not have a 'default' OGL state to plug-ins; plug-ins should + * totally set OGL state before drawing. Use XPLMSetGraphicsState instead of + * any of the above OpenGL calls. + * + * WARNING: Any routine that performs drawing (e.g. XPLMDrawString or widget + * code) may change X-Plane's state. Always set state before drawing after + * unknown code has executed. + * + */ +XPLM_API void XPLMSetGraphicsState(int inEnableFog, + int inNumberTexUnits, + int inEnableLighting, + int inEnableAlphaTesting, + int inEnableAlphaBlending, + int inEnableDepthTesting, + int inEnableDepthWriting); + +/* + * XPLMBindTexture2d + * + * XPLMBindTexture2d changes what texture is bound to the 2d texturing target. + * This routine caches the current 2d texture across all texturing units in + * the sim and plug-ins, preventing extraneous binding. For example, consider + * several plug-ins running in series; if they all use the 'general interface' + * bitmap to do UI, calling this function will skip the rebinding of the + * general interface texture on all but the first plug-in, which can provide + * better frame rate son some graphics cards. + * + * inTextureID is the ID of the texture object to bind; inTextureUnit is a + * zero-based texture unit (e.g. 0 for the first one), up to a maximum of 4 + * units. (This number may increase in future versions of x-plane.) + * + * Use this routine instead of glBindTexture(GL_TEXTURE_2D, ....); + * + */ +XPLM_API void XPLMBindTexture2d(int inTextureNum, int inTextureUnit); + +/* + * XPLMGenerateTextureNumbers + * + * This routine generates unused texture numbers that a plug-in can use to + * safely bind textures. Use this routine instead of glGenTextures; + * glGenTextures will allocate texture numbers in ranges that X-Plane reserves + * for its own use but does not always use; for example, it might provide an + * ID within the range of textures reserved for terrain...loading a new .env + * file as the plane flies might then cause X-Plane to use this texture ID. + * X-Plane will then overwrite the plug-ins texture. This routine returns + * texture IDs that are out of X-Plane's usage range. + * + */ +XPLM_API void XPLMGenerateTextureNumbers(int *outTextureIDs, int inCount); + +/* + * XPLMGetTexture + * + * XPLMGetTexture returns the OpenGL texture enumeration of an X-Plane texture + * based on a generic identifying code. For example, you can get the texture + * for X-Plane's UI bitmaps. This allows you to build new gauges that take + * advantage of x-plane's textures, for smooth artwork integration and also + * saving texture memory. Note that the texture might not be loaded yet, + * depending on what the plane's panel contains. + * + * OPEN ISSUE: We really need a way to make sure X-Plane loads this texture if + * it isn't around, or at least a way to find out whether it is loaded or not. + * + */ +XPLM_API int XPLMGetTexture(XPLMTextureID inTexture); + +/* + * XPLMWorldToLocal + * + * This routine translates coordinates from latitude, longitude, and altitude + * to local scene coordinates. Latitude and longitude are in decimal degrees, + * and altitude is in meters MSL (mean sea level). The XYZ coordinates are in + * meters in the local OpenGL coordinate system. + * + */ +XPLM_API void XPLMWorldToLocal(double inLatitude, + double inLongitude, + double inAltitude, + double *outX, + double *outY, + double *outZ); + +/* + * XPLMLocalToWorld + * + * This routine translates a local coordinate triplet back into latitude, + * longitude, and altitude. Latitude and longitude are in decimal degrees, + * and altitude is in meters MSL (mean sea level). The XYZ coordinates are in + * meters in the local OpenGL coordinate system. + * + * NOTE: world coordinates are less precise than local coordinates; you should + * try to avoid round tripping from local to world and back. + * + */ +XPLM_API void XPLMLocalToWorld(double inX, + double inY, + double inZ, + double *outLatitude, + double *outLongitude, + double *outAltitude); + +/* + * XPLMDrawTranslucentDarkBox + * + * This routine draws a translucent dark box, partially obscuring parts of the + * screen but making text easy to read. This is the same graphics primitive + * used by X-Plane to show text files and ATC info. + * + */ +XPLM_API void XPLMDrawTranslucentDarkBox(int inLeft, + int inTop, + int inRight, + int inBottom); + +/*************************************************************************** + * X-PLANE TEXT + ***************************************************************************/ +/* + * + * + */ + + +/* + * XPLMFontID + * + * X-Plane features some fixed-character fonts. Each font may have its own + * metrics. + * + * WARNING: Some of these fonts are no longer supported or may have changed + * geometries. For maximum copmatibility, see the comments below. + * + * Note: X-Plane 7 supports proportional-spaced fonts. Since no measuring + * routine is available yet, the SDK will normally draw using a fixed-width + * font. You can use a dataref to enable proportional font drawing on XP7 if + * you want to. + * + */ +enum { + /* Mono-spaced font for user interface. Available in all versions of the + SDK. */ + xplmFont_Basic = 0 + + /* Deprecated, do not use. */ + , + xplmFont_Menus = 1 + + /* Deprecated, do not use. */ + , + xplmFont_Metal = 2 + + /* Deprecated, do not use. */ + , + xplmFont_Led = 3 + + /* Deprecated, do not use. */ + , + xplmFont_LedWide = 4 + + /* Deprecated, do not use. */ + , + xplmFont_PanelHUD = 5 + + /* Deprecated, do not use. */ + , + xplmFont_PanelEFIS = 6 + + /* Deprecated, do not use. */ + , + xplmFont_PanelGPS = 7 + + /* Deprecated, do not use. */ + , + xplmFont_RadiosGA = 8 + + /* Deprecated, do not use. */ + , + xplmFont_RadiosBC = 9 + + /* Deprecated, do not use. */ + , + xplmFont_RadiosHM = 10 + + /* Deprecated, do not use. */ + , + xplmFont_RadiosGANarrow = 11 + + /* Deprecated, do not use. */ + , + xplmFont_RadiosBCNarrow = 12 + + /* Deprecated, do not use. */ + , + xplmFont_RadiosHMNarrow = 13 + + /* Deprecated, do not use. */ + , + xplmFont_Timer = 14 + + /* Deprecated, do not use. */ + , + xplmFont_FullRound = 15 + + /* Deprecated, do not use. */ + , + xplmFont_SmallRound = 16 + + /* Deprecated, do not use. */ + , + xplmFont_Menus_Localized = 17 + +#if defined(XPLM200) + /* Proportional UI font. */ + , + xplmFont_Proportional = 18 + +#endif /* XPLM200 */ + +}; +typedef int XPLMFontID; + +/* + * XPLMDrawString + * + * This routine draws a NULL termianted string in a given font. Pass in the + * lower left pixel that the character is to be drawn onto. Also pass the + * character and font ID. This function returns the x offset plus the width of + * all drawn characters. The color to draw in is specified as a pointer to an + * array of three floating point colors, representing RGB intensities from 0.0 + * to 1.0. + * + */ +XPLM_API void XPLMDrawString(float *inColorRGB, + int inXOffset, + int inYOffset, + char *inChar, + int *inWordWrapWidth, /* Can be NULL */ + XPLMFontID inFontID); + +/* + * XPLMDrawNumber + * + * This routine draws a number similar to the digit editing fields in + * PlaneMaker and data output display in X-Plane. Pass in a color, a + * position, a floating point value, and formatting info. Specify how many + * integer and how many decimal digits to show and whether to show a sign, as + * well as a character set. This routine returns the xOffset plus width of the + * string drawn. + * + */ +XPLM_API void XPLMDrawNumber(float *inColorRGB, + int inXOffset, + int inYOffset, + double inValue, + int inDigits, + int inDecimals, + int inShowSign, + XPLMFontID inFontID); + +/* + * XPLMGetFontDimensions + * + * This routine returns the width and height of a character in a given font. + * It also tells you if the font only supports numeric digits. Pass NULL if + * you don't need a given field. Note that for a proportional font the width + * will be an arbitrary, hopefully average width. + * + */ +XPLM_API void XPLMGetFontDimensions(XPLMFontID inFontID, + int *outCharWidth, /* Can be NULL */ + int *outCharHeight, /* Can be NULL */ + int *outDigitsOnly); /* Can be NULL */ + +#if defined(XPLM200) +/* + * XPLMMeasureString + * + * This routine returns the width in pixels of a string using a given font. + * The string is passed as a pointer plus length (and does not need to be null + * terminated); this is used to allow for measuring substrings. The return + * value is floating point; it is possible that future font drawing may allow + * for fractional pixels. + * + */ +XPLM_API float + XPLMMeasureString(XPLMFontID inFontID, const char *inChar, int inNumChars); +#endif /* XPLM200 */ + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/GermanAirlinesVA-GAConnector/XPSDK/CHeaders/XPLM/XPLMMenus.h b/GermanAirlinesVA-GAConnector/XPSDK/CHeaders/XPLM/XPLMMenus.h new file mode 100644 index 0000000..a94d7dd --- /dev/null +++ b/GermanAirlinesVA-GAConnector/XPSDK/CHeaders/XPLM/XPLMMenus.h @@ -0,0 +1,210 @@ +#ifndef _XPLMMenus_h_ +#define _XPLMMenus_h_ + +/* + * Copyright 2005-2012 Sandy Barbour and Ben Supnik + * + * All rights reserved. See license.txt for usage. + * + * X-Plane SDK Version: 2.1.1 + * + */ + +/* + * XPLMMenus - Theory of Operation + * + * Plug-ins can create menus in the menu bar of X-Plane. This is done by + * creating a menu and then creating items. Menus are referred to by an + * opaque ID. Items are referred to by index number. For each menu and item + * you specify a void *. Per menu you specify a handler function that is + * called with each void * when the menu item is picked. Menu item indices + * are zero based. + * + */ + +#include "XPLMDefs.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/*************************************************************************** + * XPLM MENUS + ***************************************************************************/ +/* + * + * + */ + + +/* + * XPLMMenuCheck + * + * These enumerations define the various 'check' states for an X-Plane menu. + * 'checking' in x-plane actually appears as a light which may or may not be + * lit. So there are three possible states. + * + */ +enum { + /* there is no symbol to the left of the menu item. */ + xplm_Menu_NoCheck = 0 + + /* the menu has a mark next to it that is unmarked (not lit). */ + , + xplm_Menu_Unchecked = 1 + + /* the menu has a mark next to it that is checked (lit). */ + , + xplm_Menu_Checked = 2 + + +}; +typedef int XPLMMenuCheck; + +/* + * XPLMMenuID + * + * This is a unique ID for each menu you create. + * + */ +typedef void *XPLMMenuID; + +/* + * XPLMMenuHandler_f + * + * A menu handler function takes two reference pointers, one for the menu + * (specified when the menu was created) and one for the item (specified when + * the item was created). + * + */ +typedef void (*XPLMMenuHandler_f)(void *inMenuRef, void *inItemRef); + +/* + * XPLMFindPluginsMenu + * + * This function returns the ID of the plug-ins menu, which is created for you + * at startup. + * + */ +XPLM_API XPLMMenuID XPLMFindPluginsMenu(void); + +/* + * XPLMCreateMenu + * + * This function creates a new menu and returns its ID. It returns NULL if + * the menu cannot be created. Pass in a parent menu ID and an item index to + * create a submenu, or NULL for the parent menu to put the menu in the menu + * bar. The menu's name is only used if the menu is in the menubar. You also + * pass a handler function and a menu reference value. Pass NULL for the + * handler if you do not need callbacks from the menu (for example, if it only + * contains submenus). + * + * Important: you must pass a valid, non-empty menu title even if the menu is + * a submenu where the title is not visible. + * + */ +XPLM_API XPLMMenuID XPLMCreateMenu(const char *inName, + XPLMMenuID inParentMenu, + int inParentItem, + XPLMMenuHandler_f inHandler, + void *inMenuRef); + +/* + * XPLMDestroyMenu + * + * This function destroys a menu that you have created. Use this to remove a + * submenu if necessary. (Normally this function will not be necessary.) + * + */ +XPLM_API void XPLMDestroyMenu(XPLMMenuID inMenuID); + +/* + * XPLMClearAllMenuItems + * + * This function removes all menu items from a menu, allowing you to rebuild + * it. Use this function if you need to change the number of items on a menu. + * + */ +XPLM_API void XPLMClearAllMenuItems(XPLMMenuID inMenuID); + +/* + * XPLMAppendMenuItem + * + * This routine appends a new menu item to the bottom of a menu and returns + * its index. Pass in the menu to add the item to, the items name, and a void + * * ref for this item. If you pass in inForceEnglish, this menu item will be + * drawn using the english character set no matter what language x-plane is + * running in. Otherwise the menu item will be drawn localized. (An example + * of why you'd want to do this is for a proper name.) See XPLMUtilities for + * determining the current langauge. + * + */ +XPLM_API int XPLMAppendMenuItem(XPLMMenuID inMenu, + const char *inItemName, + void *inItemRef, + int inForceEnglish); + +/* + * XPLMAppendMenuSeparator + * + * This routine adds a seperator to the end of a menu. + * + */ +XPLM_API void XPLMAppendMenuSeparator(XPLMMenuID inMenu); + +/* + * XPLMSetMenuItemName + * + * This routine changes the name of an existing menu item. Pass in the menu + * ID and the index of the menu item. + * + */ +XPLM_API void XPLMSetMenuItemName(XPLMMenuID inMenu, + int inIndex, + const char *inItemName, + int inForceEnglish); + +/* + * XPLMCheckMenuItem + * + * Set whether a menu item is checked. Pass in the menu ID and item index. + * + */ +XPLM_API void + XPLMCheckMenuItem(XPLMMenuID inMenu, int index, XPLMMenuCheck inCheck); + +/* + * XPLMCheckMenuItemState + * + * This routine returns whether a menu item is checked or not. A menu item's + * check mark may be on or off, or a menu may not have an icon at all. + * + */ +XPLM_API void XPLMCheckMenuItemState(XPLMMenuID inMenu, + int index, + XPLMMenuCheck *outCheck); + +/* + * XPLMEnableMenuItem + * + * Sets whether this menu item is enabled. Items start out enabled. + * + */ +XPLM_API void XPLMEnableMenuItem(XPLMMenuID inMenu, int index, int enabled); + +#if defined(XPLM210) +/* + * XPLMRemoveMenuItem + * + * Removes one item from a menu. Note that all menu items below are moved up + * one; your plugin must track the change in index numbers. + * + */ +XPLM_API void XPLMRemoveMenuItem(XPLMMenuID inMenu, int inIndex); +#endif /* XPLM210 */ + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/GermanAirlinesVA-GAConnector/XPSDK/CHeaders/XPLM/XPLMNavigation.h b/GermanAirlinesVA-GAConnector/XPSDK/CHeaders/XPLM/XPLMNavigation.h new file mode 100644 index 0000000..8bdbde2 --- /dev/null +++ b/GermanAirlinesVA-GAConnector/XPSDK/CHeaders/XPLM/XPLMNavigation.h @@ -0,0 +1,373 @@ +#ifndef _XPLMNavigation_h_ +#define _XPLMNavigation_h_ + +/* + * Copyright 2005-2012 Sandy Barbour and Ben Supnik + * + * All rights reserved. See license.txt for usage. + * + * X-Plane SDK Version: 2.1.1 + * + */ + +/* + * XPLMNavigation - THEORY OF OPERATION + * + * The XPLM Navigation APIs give you some access to the navigation databases + * inside X-Plane. X-Plane stores all navigation information in RAM, so by + * using these APIs you can gain access to most information without having to + * go to disk or parse the files yourself. + * + * You can also use this API to program the FMS. You must use the navigation + * APIs to find the nav-aids you want to program into the FMS, since the FMS + * is powered internally by x-plane's navigation database. + * + */ + +#include "XPLMDefs.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/*************************************************************************** + * NAVIGATION DATABASE ACCESS + ***************************************************************************/ +/* + * + * + */ + + +/* + * XPLMNavType + * + * These enumerations define the different types of navaids. They are each + * defined with a separate bit so that they may be bit-wise added together to + * form sets of nav-aid types. + * + * NOTE: xplm_Nav_LatLon is a specific lat-lon coordinate entered into the + * FMS. It will not exist in the database, and cannot be programmed into the + * FMS. Querying the FMS for navaids will return it. Use + * XPLMSetFMSEntryLatLon to set a lat/lon waypoint. + * + */ +enum { + xplm_Nav_Unknown = 0 + + , + xplm_Nav_Airport = 1 + + , + xplm_Nav_NDB = 2 + + , + xplm_Nav_VOR = 4 + + , + xplm_Nav_ILS = 8 + + , + xplm_Nav_Localizer = 16 + + , + xplm_Nav_GlideSlope = 32 + + , + xplm_Nav_OuterMarker = 64 + + , + xplm_Nav_MiddleMarker = 128 + + , + xplm_Nav_InnerMarker = 256 + + , + xplm_Nav_Fix = 512 + + , + xplm_Nav_DME = 1024 + + , + xplm_Nav_LatLon = 2048 + + +}; +typedef int XPLMNavType; + +/* + * XPLMNavRef + * + * XPLMNavRef is an iterator into the navigation database. The navigation + * database is essentially an array, but it is not necessarily densely + * populated. The only assumption you can safely make is that like-typed + * nav-aids are grouped together. + * + * Use XPLMNavRef to refer to a nav-aid. + * + * XPLM_NAV_NOT_FOUND is returned by functions that return an XPLMNavRef when + * the iterator must be invalid. + * + */ +typedef int XPLMNavRef; + +#define XPLM_NAV_NOT_FOUND -1 + +/* + * XPLMGetFirstNavAid + * + * This returns the very first navaid in the database. Use this to traverse + * the entire database. Returns XPLM_NAV_NOT_FOUND if the nav database is + * empty. + * + */ +XPLM_API XPLMNavRef XPLMGetFirstNavAid(void); + +/* + * XPLMGetNextNavAid + * + * Given a nav aid ref, this routine returns the next navaid. It returns + * XPLM_NAV_NOT_FOUND if the nav aid passed in was invalid or if the navaid + * passed in was the last one in the database. Use this routine to iterate + * across all like-typed navaids or the entire database. + * + * WARNING: due to a bug in the SDK, when fix loading is disabled in the + * rendering settings screen, calling this routine with the last airport + * returns a bogus nav aid. Using this nav aid can crash x-plane. + * + */ +XPLM_API XPLMNavRef XPLMGetNextNavAid(XPLMNavRef inNavAidRef); + +/* + * XPLMFindFirstNavAidOfType + * + * This routine returns the ref of the first navaid of the given type in the + * database or XPLM_NAV_NOT_FOUND if there are no navaids of that type in the + * database. You must pass exactly one nav aid type to this routine. + * + * WARNING: due to a bug in the SDK, when fix loading is disabled in the + * rendering settings screen, calling this routine with fixes returns a bogus + * nav aid. Using this nav aid can crash x-plane. + * + */ +XPLM_API XPLMNavRef XPLMFindFirstNavAidOfType(XPLMNavType inType); + +/* + * XPLMFindLastNavAidOfType + * + * This routine returns the ref of the last navaid of the given type in the + * database or XPLM_NAV_NOT_FOUND if there are no navaids of that type in the + * database. You must pass exactly one nav aid type to this routine. + * + * WARNING: due to a bug in the SDK, when fix loading is disabled in the + * rendering settings screen, calling this routine with fixes returns a bogus + * nav aid. Using this nav aid can crash x-plane. + * + */ +XPLM_API XPLMNavRef XPLMFindLastNavAidOfType(XPLMNavType inType); + +/* + * XPLMFindNavAid + * + * This routine provides a number of searching capabilities for the nav + * database. XPLMFindNavAid will search through every nav aid whose type is + * within inType (multiple types may be added together) and return any + * nav-aids found based on the following rules: + * + * If inLat and inLon are not NULL, the navaid nearest to that lat/lon will be + * returned, otherwise the last navaid found will be returned. + * + * If inFrequency is not NULL, then any navaids considered must match this + * frequency. Note that this will screen out radio beacons that do not have + * frequency data published (like inner markers) but not fixes and airports. + * + * If inNameFragment is not NULL, only navaids that contain the fragment in + * their name will be returned. + * + * If inIDFragment is not NULL, only navaids that contain the fragment in + * their IDs will be returned. + * + * This routine provides a simple way to do a number of useful searches: + * + * Find the nearest navaid on this frequency. Find the nearest airport. Find + * the VOR whose ID is "KBOS". Find the nearest airport whose name contains + * "Chicago". + * + */ +XPLM_API XPLMNavRef XPLMFindNavAid(const char *inNameFragment, /* Can be NULL */ + const char *inIDFragment, /* Can be NULL */ + float *inLat, /* Can be NULL */ + float *inLon, /* Can be NULL */ + int *inFrequency, /* Can be NULL */ + XPLMNavType inType); + +/* + * XPLMGetNavAidInfo + * + * This routine returns information about a navaid. Any non-null field is + * filled out with information if it is available. + * + * Frequencies are in the nav.dat convention as described in the X-Plane nav + * database FAQ: NDB frequencies are exact, all others are multiplied by 100. + * + * The buffer for IDs should be at least 6 chars and the buffer for names + * should be at least 41 chars, but since these values are likely to go up, I + * recommend passing at least 32 chars for IDs and 256 chars for names when + * possible. + * + * The outReg parameter tells if the navaid is within the local "region" of + * loaded DSFs. (This information may not be particularly useful to plugins.) + * The parameter is a single byte value 1 for true or 0 for false, not a C + * string. + * + */ +XPLM_API void XPLMGetNavAidInfo(XPLMNavRef inRef, + XPLMNavType *outType, /* Can be NULL */ + float *outLatitude, /* Can be NULL */ + float *outLongitude, /* Can be NULL */ + float *outHeight, /* Can be NULL */ + int *outFrequency, /* Can be NULL */ + float *outHeading, /* Can be NULL */ + char *outID, /* Can be NULL */ + char *outName, /* Can be NULL */ + char *outReg); /* Can be NULL */ + +/*************************************************************************** + * FLIGHT MANAGEMENT COMPUTER + ***************************************************************************/ +/* + * Note: the FMS works based on an array of entries. Indices into the array + * are zero-based. Each entry is a nav-aid plus an altitude. The FMS tracks + * the currently displayed entry and the entry that it is flying to. + * + * The FMS must be programmed with contiguous entries, so clearing an entry at + * the end shortens the effective flight plan. There is a max of 100 + * waypoints in the flight plan. + * + */ + + +/* + * XPLMCountFMSEntries + * + * This routine returns the number of entries in the FMS. + * + */ +XPLM_API int XPLMCountFMSEntries(void); + +/* + * XPLMGetDisplayedFMSEntry + * + * This routine returns the index of the entry the pilot is viewing. + * + */ +XPLM_API int XPLMGetDisplayedFMSEntry(void); + +/* + * XPLMGetDestinationFMSEntry + * + * This routine returns the index of the entry the FMS is flying to. + * + */ +XPLM_API int XPLMGetDestinationFMSEntry(void); + +/* + * XPLMSetDisplayedFMSEntry + * + * This routine changes which entry the FMS is showing to the index specified. + * * + */ +XPLM_API void XPLMSetDisplayedFMSEntry(int inIndex); + +/* + * XPLMSetDestinationFMSEntry + * + * This routine changes which entry the FMS is flying the aircraft toward. + * + */ +XPLM_API void XPLMSetDestinationFMSEntry(int inIndex); + +/* + * XPLMGetFMSEntryInfo + * + * This routine returns information about a given FMS entry. A reference to a + * navaid can be returned allowing you to find additional information (such as + * a frequency, ILS heading, name, etc.). Some information is available + * immediately. For a lat/lon entry, the lat/lon is returned by this routine + * but the navaid cannot be looked up (and the reference will be + * XPLM_NAV_NOT_FOUND. FMS name entry buffers should be at least 256 chars in + * length. + * + */ +XPLM_API void XPLMGetFMSEntryInfo(int inIndex, + XPLMNavType *outType, /* Can be NULL */ + char *outID, /* Can be NULL */ + XPLMNavRef *outRef, /* Can be NULL */ + int *outAltitude, /* Can be NULL */ + float *outLat, /* Can be NULL */ + float *outLon); /* Can be NULL */ + +/* + * XPLMSetFMSEntryInfo + * + * This routine changes an entry in the FMS to have the destination navaid + * passed in and the altitude specified. Use this only for airports, fixes, + * and radio-beacon navaids. Currently of radio beacons, the FMS can only + * support VORs and NDBs. Use the routines below to clear or fly to a lat/lon. + * + */ +XPLM_API void + XPLMSetFMSEntryInfo(int inIndex, XPLMNavRef inRef, int inAltitude); + +/* + * XPLMSetFMSEntryLatLon + * + * This routine changes the entry in the FMS to a lat/lon entry with the given + * coordinates. + * + */ +XPLM_API void XPLMSetFMSEntryLatLon(int inIndex, + float inLat, + float inLon, + int inAltitude); + +/* + * XPLMClearFMSEntry + * + * This routine clears the given entry, potentially shortening the flight + * plan. + * + */ +XPLM_API void XPLMClearFMSEntry(int inIndex); + +/*************************************************************************** + * GPS RECEIVER + ***************************************************************************/ +/* + * These APIs let you read data from the GPS unit. + * + */ + + +/* + * XPLMGetGPSDestinationType + * + * This routine returns the type of the currently selected GPS destination, + * one of fix, airport, VOR or NDB. + * + */ +XPLM_API XPLMNavType XPLMGetGPSDestinationType(void); + +/* + * XPLMGetGPSDestination + * + * This routine returns the current GPS destination. + * + */ +XPLM_API XPLMNavRef XPLMGetGPSDestination(void); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/GermanAirlinesVA-GAConnector/XPSDK/CHeaders/XPLM/XPLMPlanes.h b/GermanAirlinesVA-GAConnector/XPSDK/CHeaders/XPLM/XPLMPlanes.h new file mode 100644 index 0000000..4b4d3a5 --- /dev/null +++ b/GermanAirlinesVA-GAConnector/XPSDK/CHeaders/XPLM/XPLMPlanes.h @@ -0,0 +1,245 @@ +#ifndef _XPLMPlanes_h_ +#define _XPLMPlanes_h_ + +/* + * Copyright 2005-2012 Sandy Barbour and Ben Supnik + * + * All rights reserved. See license.txt for usage. + * + * X-Plane SDK Version: 2.1.1 + * + */ + +/* + * The XPLMPlanes APIs allow you to control the various aircraft in x-plane, + * both the user's and the sim's. + * + */ + +#include "XPLMDefs.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/*************************************************************************** + * USER AIRCRAFT ACCESS + ***************************************************************************/ +/* + * + * + */ + + +/* + * XPLMSetUsersAircraft + * + * This routine changes the user's aircraft. Note that this will reinitialize + * the user to be on the nearest airport's first runway. Pass in a full path + * (hard drive and everything including the .acf extension) to the .acf file. + * + */ +XPLM_API void XPLMSetUsersAircraft(const char *inAircraftPath); +/* + * XPLMPlaceUserAtAirport + * + * This routine places the user at a given airport. Specify the airport by + * its ICAO code (e.g. 'KBOS'). + * + */ +XPLM_API void XPLMPlaceUserAtAirport(const char *inAirportCode); +/*************************************************************************** + * GLOBAL AIRCRAFT ACCESS + ***************************************************************************/ +/* + * + * + */ + + +/* The user's aircraft is always index 0. */ +#define XPLM_USER_AIRCRAFT 0 +/* + * XPLMPlaneDrawState_t + * + * This structure contains additional plane parameter info to be passed to + * draw plane. Make sure to fill in the size of the structure field with + * sizeof(XPLMDrawPlaneState_t) so that the XPLM can tell how many fields you + * knew about when compiling your plugin (since more fields may be added + * later). + * + * Most of these fields are ratios from 0 to 1 for control input. X-Plane + * calculates what the actual controls look like based on the .acf file for + * that airplane. Note for the yoke inputs, this is what the pilot of the + * plane has commanded (post artificial stability system if there were one) + * and affects aelerons, rudder, etc. It is not necessarily related to the + * actual position of the plane! + * + */ +typedef struct { + /* The size of the draw state struct. */ + int structSize; + /* A ratio from [0..1] describing how far the landing gear is extended. */ + float gearPosition; + /* Ratio of flap deployment, 0 = up, 1 = full deploy. */ + float flapRatio; + /* Ratio of spoiler deployment, 0 = none, 1 = full deploy. */ + float spoilerRatio; + /* Ratio of speed brake deployment, 0 = none, 1 = full deploy. */ + float speedBrakeRatio; + /* Ratio of slat deployment, 0 = none, 1 = full deploy. */ + float slatRatio; + /* Wing sweep ratio, 0 = forward, 1 = swept. */ + float wingSweep; + /* Thrust power, 0 = none, 1 = full fwd, -1 = full reverse. */ + float thrust; + /* Total pitch input for this plane. */ + float yokePitch; + /* Total Heading input for this plane. */ + float yokeHeading; + /* Total Roll input for this plane. */ + float yokeRoll; +} XPLMPlaneDrawState_t; +/* + * XPLMCountAircraft + * + * This function returns the number of aircraft X-Plane is capable of having, + * as well as the number of aircraft that are currently active. These numbers + * count the user's aircraft. It can also return the plugin that is currently + * controlling aircraft. In X-Plane 7, this routine reflects the number of + * aircraft the user has enabled in the rendering options window. + * + */ +XPLM_API void XPLMCountAircraft(int *outTotalAircraft, + int *outActiveAircraft, + XPLMPluginID *outController); +/* + * XPLMGetNthAircraftModel + * + * This function returns the aircraft model for the Nth aircraft. Indices are + * zero based, with zero being the user's aircraft. The file name should be + * at least 256 chars in length; the path should be at least 512 chars in + * length. + * + */ +XPLM_API void + XPLMGetNthAircraftModel(int inIndex, char *outFileName, char *outPath); +/*************************************************************************** + * EXCLUSIVE AIRCRAFT ACCESS + ***************************************************************************/ +/* + * The following routines require exclusive access to the airplane APIs. Only + * one plugin may have this access at a time. + * + */ + + +/* + * XPLMPlanesAvailable_f + * + * Your airplanes available callback is called when another plugin gives up + * access to the multiplayer planes. Use this to wait for access to + * multiplayer. + * + */ +typedef void (*XPLMPlanesAvailable_f)(void *inRefcon); + +/* + * XPLMAcquirePlanes + * + * XPLMAcquirePlanes grants your plugin exclusive access to the aircraft. It + * returns 1 if you gain access, 0 if you do not. inAircraft - pass in an + * array of pointers to strings specifying the planes you want loaded. For + * any plane index you do not want loaded, pass a 0-length string. Other + * strings should be full paths with the .acf extension. NULL terminates this + * array, or pass NULL if there are no planes you want loaded. If you pass in + * a callback and do not receive access to the planes your callback will be + * called when the airplanes are available. If you do receive airplane access, + * your callback will not be called. + * + */ +XPLM_API int XPLMAcquirePlanes(char **inAircraft, /* Can be NULL */ + XPLMPlanesAvailable_f inCallback, + void *inRefcon); + +/* + * XPLMReleasePlanes + * + * Call this function to release access to the planes. Note that if you are + * disabled, access to planes is released for you and you must reacquire it. + * + */ +XPLM_API void XPLMReleasePlanes(void); + +/* + * XPLMSetActiveAircraftCount + * + * This routine sets the number of active planes. If you pass in a number + * higher than the total number of planes availables, only the total number of + * planes available is actually used. + * + */ +XPLM_API void XPLMSetActiveAircraftCount(int inCount); + +/* + * XPLMSetAircraftModel + * + * This routine loads an aircraft model. It may only be called if you have + * exclusive access to the airplane APIs. Pass in the path of the model with + * the .acf extension. The index is zero based, but you may not pass in 0 + * (use XPLMSetUsersAircraft to load the user's aircracft). + * + */ +XPLM_API void XPLMSetAircraftModel(int inIndex, const char *inAircraftPath); + +/* + * XPLMDisableAIForPlane + * + * This routine turns off X-Plane's AI for a given plane. The plane will + * continue to draw and be a real plane in X-Plane, but will not move itself. + * + */ +XPLM_API void XPLMDisableAIForPlane(int inPlaneIndex); + +/* + * XPLMDrawAircraft + * + * This routine draws an aircraft. It can only be called from a 3-d drawing + * callback. Pass in the position of the plane in OpenGL local coordinates + * and the orientation of the plane. A 1 for full drawing indicates that the + * whole plane must be drawn; a 0 indicates you only need the nav lights + * drawn. (This saves rendering time when planes are far away.) + * + */ +XPLM_API void XPLMDrawAircraft(int inPlaneIndex, + float inX, + float inY, + float inZ, + float inPitch, + float inRoll, + float inYaw, + int inFullDraw, + XPLMPlaneDrawState_t *inDrawStateInfo); + +/* + * XPLMReinitUsersPlane + * + * This function recomputes the derived flight model data from the aircraft + * structure in memory. If you have used the data access layer to modify the + * aircraft structure, use this routine to resynchronize x-plane; since + * X-plane works at least partly from derived values, the sim will not behave + * properly until this is called. + * + * WARNING: this routine does not necessarily place the airplane at the + * airport; use XPLMSetUsersAircraft to be compatible. This routine is + * provided to do special experimentation with flight models without resetting + * flight. + * + */ +XPLM_API void XPLMReinitUsersPlane(void); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/GermanAirlinesVA-GAConnector/XPSDK/CHeaders/XPLM/XPLMPlugin.h b/GermanAirlinesVA-GAConnector/XPSDK/CHeaders/XPLM/XPLMPlugin.h new file mode 100644 index 0000000..8080a94 --- /dev/null +++ b/GermanAirlinesVA-GAConnector/XPSDK/CHeaders/XPLM/XPLMPlugin.h @@ -0,0 +1,311 @@ +#ifndef _XPLMPlugin_h_ +#define _XPLMPlugin_h_ + +/* + * Copyright 2005-2012 Sandy Barbour and Ben Supnik + * + * All rights reserved. See license.txt for usage. + * + * X-Plane SDK Version: 2.1.1 + * + */ + +/* + * These APIs provide facilities to find and work with other plugins and + * manage other plugins. + * + */ + +#include "XPLMDefs.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/*************************************************************************** + * FINDING PLUGINS + ***************************************************************************/ +/* + * These APIs allow you to find another plugin or yourself, or iterate across + * all plugins. For example, if you wrote an FMS plugin that needed to talk + * to an autopilot plugin, you could use these APIs to locate the autopilot + * plugin. + * + */ + + +/* + * XPLMGetMyID + * + * This routine returns the plugin ID of the calling plug-in. Call this to + * get your own ID. + * + */ +XPLM_API XPLMPluginID XPLMGetMyID(void); + +/* + * XPLMCountPlugins + * + * This routine returns the total number of plug-ins that are loaded, both + * disabled and enabled. + * + */ +XPLM_API int XPLMCountPlugins(void); + +/* + * XPLMGetNthPlugin + * + * This routine returns the ID of a plug-in by index. Index is 0 based from 0 + * to XPLMCountPlugins-1, inclusive. Plugins may be returned in any arbitrary + * order. + * + */ +XPLM_API XPLMPluginID XPLMGetNthPlugin(int inIndex); + +/* + * XPLMFindPluginByPath + * + * This routine returns the plug-in ID of the plug-in whose file exists at the + * passed in absolute file system path. XPLM_NO_PLUGIN_ID is returned if the + * path does not point to a currently loaded plug-in. + * + */ +XPLM_API XPLMPluginID XPLMFindPluginByPath(const char *inPath); + +/* + * XPLMFindPluginBySignature + * + * This routine returns the plug-in ID of the plug-in whose signature matches + * what is passed in or XPLM_NO_PLUGIN_ID if no running plug-in has this + * signature. Signatures are the best way to identify another plug-in as they + * are independent of the file system path of a plug-in or the human-readable + * plug-in name, and should be unique for all plug-ins. Use this routine to + * locate another plugin that your plugin interoperates with + * + */ +XPLM_API XPLMPluginID XPLMFindPluginBySignature(const char *inSignature); + +/* + * XPLMGetPluginInfo + * + * This routine returns information about a plug-in. Each parameter should be + * a pointer to a buffer of at least 256 characters, or NULL to not receive + * the information. + * + * outName - the human-readable name of the plug-in. outFilePath - the + * absolute file path to the file that contains this plug-in. outSignature - a + * unique string that identifies this plug-in. outDescription - a + * human-readable description of this plug-in. + * + */ +XPLM_API void XPLMGetPluginInfo(XPLMPluginID inPlugin, + char *outName, /* Can be NULL */ + char *outFilePath, /* Can be NULL */ + char *outSignature, /* Can be NULL */ + char *outDescription); /* Can be NULL */ + +/*************************************************************************** + * ENABLING/DISABLING PLUG-INS + ***************************************************************************/ +/* + * These routines are used to work with plug-ins and manage them. Most + * plugins will not need to use these APIs. + * + */ + + +/* + * XPLMIsPluginEnabled + * + * Returns whether the specified plug-in is enabled for running. + * + */ +XPLM_API int XPLMIsPluginEnabled(XPLMPluginID inPluginID); + +/* + * XPLMEnablePlugin + * + * This routine enables a plug-in if it is not already enabled. It returns 1 + * if the plugin was enabled or successfully enables itself, 0 if it does not. + * Plugins may fail to enable (for example, if resources cannot be acquired) + * by returning 0 from their XPluginEnable callback. + * + */ +XPLM_API int XPLMEnablePlugin(XPLMPluginID inPluginID); + +/* + * XPLMDisablePlugin + * + * This routine disableds an enabled plug-in. + * + */ +XPLM_API void XPLMDisablePlugin(XPLMPluginID inPluginID); + +/* + * XPLMReloadPlugins + * + * This routine reloads all plug-ins. Once this routine is called and you + * return from the callback you were within (e.g. a menu select callback) you + * will receive your XPluginDisable and XPluginStop callbacks and your DLL + * will be unloaded, then the start process happens as if the sim was starting + * up. + * + */ +XPLM_API void XPLMReloadPlugins(void); + +/*************************************************************************** + * INTERPLUGIN MESSAGING + ***************************************************************************/ +/* + * Plugin messages are defined as 32-bit integers. Messages below 0x00FFFFFF + * are reserved for X-Plane and the plugin SDK. + * + * Messages have two conceptual uses: notifications and commands. Commands + * are sent from one plugin to another to induce behavior; notifications are + * sent from one plugin to all others for informational purposes. It is + * important that commands and notifications not have the same values because + * this could cause a notification sent by one plugin to accidentally induce a + * command in another. + * + * By convention, plugin-defined notifications should have the high bit set + * (e.g. be greater or equal to unsigned 0x8000000) while commands should have + * this bit be cleared. + * + * The following messages are sent to your plugin by x-plane. + * + */ + + +/* This message is sent to your plugin whenever the user's plane crashes. */ +#define XPLM_MSG_PLANE_CRASHED 101 + +/* This message is sent to your plugin whenever a new plane is loaded. The * + * parameter is the number of the plane being loaded; 0 indicates the user's * + * plane. */ +#define XPLM_MSG_PLANE_LOADED 102 + +/* This messages is called whenever the user's plane is positioned at a new * + * airport. */ +#define XPLM_MSG_AIRPORT_LOADED 103 + +/* This message is sent whenever new scenery is loaded. Use datarefs to * + * determine the new scenery files that were loaded. */ +#define XPLM_MSG_SCENERY_LOADED 104 + +/* This message is sent whenever the user adjusts the number of X-Plane * + * aircraft models. You must use XPLMCountPlanes to find out how many planes * + * are now available. This message will only be sent in XP7 and higher * + * because in XP6 the number of aircraft is not user-adjustable. */ +#define XPLM_MSG_AIRPLANE_COUNT_CHANGED 105 + +#if defined(XPLM200) +/* This message is sent to your plugin whenever a plane is unloaded. The * + * parameter is the number of the plane being unloaded; 0 indicates the user's * + * plane. The parameter is of type int, passed as the value of the pointer. * + * (That is: the parameter is an int, not a pointer to an int.) */ +#define XPLM_MSG_PLANE_UNLOADED 106 +#endif /* XPLM200 */ + +#if defined(XPLM210) +/* This message is sent to your plugin right before X-Plane writes its * + * preferences file. You can use this for two purposes: to write your own * + * preferences, and to modify any datarefs to influence preferences output. * + * For example, if your plugin temporarily modifies saved preferences, you can * + * put them back to their default values here to avoid having the tweaks be * + * persisted if your plugin is not loaded on the next invocation of X-Plane. */ +#define XPLM_MSG_WILL_WRITE_PREFS 107 +#endif /* XPLM210 */ + +#if defined(XPLM210) +/* This message is sent to your plugin right after a livery is loaded for an * + * airplane. You can use this to check the new livery (via datarefs) and * + * react accordingly. The parameter is of type int, passed as the value of a * + * pointer and represents the aicraft plane number - 0 is the user's plane. */ +#define XPLM_MSG_LIVERY_LOADED 108 +#endif /* XPLM210 */ + +/* + * XPLMSendMessageToPlugin + * + * This function sends a message to another plug-in or X-Plane. Pass + * XPLM_NO_PLUGIN_ID to broadcast to all plug-ins. Only enabled plug-ins with + * a message receive function receive the message. + * + */ +XPLM_API void XPLMSendMessageToPlugin(XPLMPluginID inPlugin, + int inMessage, + void *inParam); + +#if defined(XPLM200) +/*************************************************************************** + * Plugin Features API + ***************************************************************************/ +/* + * The plugin features API allows your plugin to "sign up" for additional + * capabilities and plugin system features that are normally disabled for + * backward compatibility. This allows advanced plugins to "opt-in" to new + * behavior. + * + * Each feature is defined by a permanent string name. The feature string + * names will vary with the particular installation of X-Plane, so plugins + * should not expect a feature to be guaranteed present. + * + */ + + +/* + * XPLMFeatureEnumerator_f + * + * You pass an XPLMFeatureEnumerator_f to get a list of all features supported + * by a given version running version of X-Plane. This routine is called once + * for each feature. + * + */ +typedef void (*XPLMFeatureEnumerator_f)(const char *inFeature, void *inRef); + +/* + * XPLMHasFeature + * + * This returns 1 if the given installation of X-Plane supports a feature, or + * 0 if it does not. + * + */ +XPLM_API int XPLMHasFeature(const char *inFeature); + +/* + * XPLMIsFeatureEnabled + * + * This returns 1 if a feature is currently enabled for your plugin, or 0 if + * it is not enabled. It is an error to call this routine with an unsupported + * feature. + * + */ +XPLM_API int XPLMIsFeatureEnabled(const char *inFeature); + +/* + * XPLMEnableFeature + * + * This routine enables or disables a feature for your plugin. This will + * change the running behavior of X-Plane and your plugin in some way, + * depending on the feature. + * + */ +XPLM_API void XPLMEnableFeature(const char *inFeature, int inEnable); + +/* + * XPLMEnumerateFeatures + * + * This routine calls your enumerator callback once for each feature that this + * running version of X-Plane supports. Use this routine to determine all of + * the features that X-Plane can support. + * + */ +XPLM_API void XPLMEnumerateFeatures(XPLMFeatureEnumerator_f inEnumerator, + void *inRef); + +#endif /* XPLM200 */ +#ifdef __cplusplus +} +#endif + +#endif diff --git a/GermanAirlinesVA-GAConnector/XPSDK/CHeaders/XPLM/XPLMProcessing.h b/GermanAirlinesVA-GAConnector/XPSDK/CHeaders/XPLM/XPLMProcessing.h new file mode 100644 index 0000000..5119449 --- /dev/null +++ b/GermanAirlinesVA-GAConnector/XPSDK/CHeaders/XPLM/XPLMProcessing.h @@ -0,0 +1,248 @@ +#ifndef _XPLMProcessing_h_ +#define _XPLMProcessing_h_ + +/* + * Copyright 2005-2012 Sandy Barbour and Ben Supnik + * + * All rights reserved. See license.txt for usage. + * + * X-Plane SDK Version: 2.1.1 + * + */ + +/* + * This API allows you to get regular callbacks during the flight loop, the + * part of X-Plane where the plane's position calculates the physics of + * flight, etc. Use these APIs to accomplish periodic tasks like logging data + * and performing I/O. + * + * WARNING: Do NOT use these callbacks to draw! You cannot draw during flight + * loop callbacks. Use the drawing callbacks (see XPLMDisplay for more info) + * for graphics. + * + */ + +#include "XPLMDefs.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/*************************************************************************** + * FLIGHT LOOP CALLBACKS + ***************************************************************************/ +/* + * + * + */ + + +#if defined(XPLM210) +/* + * XPLMFlightLoopPhaseType + * + * You can register a flight loop callback to run either before or after the + * flight model is integrated by X-Plane. + * + */ +enum { + /* Your callback runs before X-Plane integrates the flight model. */ + xplm_FlightLoop_Phase_BeforeFlightModel = 0 + + /* Your callback runs after X-Plane integrates the flight model. */ + , + xplm_FlightLoop_Phase_AfterFlightModel = 1 + + +}; +typedef int XPLMFlightLoopPhaseType; +#endif /* XPLM210 */ + +#if defined(XPLM210) +/* + * XPLMFlightLoopID + * + * This is an opaque identifier for a flight loop callback. You can use this + * identifier to easily track and remove your callbacks, or to use the new + * flight loop APIs. + * + */ +typedef void *XPLMFlightLoopID; +#endif /* XPLM210 */ + +/* + * XPLMFlightLoop_f + * + * This is your flight loop callback. Each time the flight loop is iterated + * through, you receive this call at the end. You receive a time since you + * were last called and a time since the last loop, as well as a loop counter. + * The 'phase' parameter is deprecated and should be ignored. + * + * Your return value controls when you will next be called. Return 0 to stop + * receiving callbacks. Pass a positive number to specify how many seconds + * until the next callback. (You will be called at or after this time, not + * before.) Pass a negative number to specify how many loops must go by until + * you are called. For example, -1.0 means call me the very next loop. Try + * to run your flight loop as infrequently as is practical, and suspend it + * (using return value 0) when you do not need it; lots of flight loop + * callbacks that do nothing lowers x-plane's frame rate. + * + * Your callback will NOT be unregistered if you return 0; it will merely be + * inactive. + * + * The reference constant you passed to your loop is passed back to you. + * + */ +typedef float (*XPLMFlightLoop_f)(float inElapsedSinceLastCall, + float inElapsedTimeSinceLastFlightLoop, + int inCounter, + void *inRefcon); + +#if defined(XPLM210) +/* + * XPLMCreateFlightLoop_t + * + * XPLMCreateFlightLoop_t contains the parameters to create a new flight loop + * callback. The strsucture can be expanded in future SDKs - always set + * structSize to the size of your structure in bytes. + * + */ +typedef struct { + int structSize; + XPLMFlightLoopPhaseType phase; + XPLMFlightLoop_f callbackFunc; + void *refcon; +} XPLMCreateFlightLoop_t; +#endif /* XPLM210 */ + +/* + * XPLMGetElapsedTime + * + * This routine returns the elapsed time since the sim started up in decimal + * seconds. + * + */ +XPLM_API float XPLMGetElapsedTime(void); + +/* + * XPLMGetCycleNumber + * + * This routine returns a counter starting at zero for each sim cycle + * computed/video frame rendered. + * + */ +XPLM_API int XPLMGetCycleNumber(void); + +/* + * XPLMRegisterFlightLoopCallback + * + * This routine registers your flight loop callback. Pass in a pointer to a + * flight loop function and a refcon. inInterval defines when you will be + * called. Pass in a positive number to specify seconds from registration + * time to the next callback. Pass in a negative number to indicate when you + * will be called (e.g. pass -1 to be called at the next cylcle). Pass 0 to + * not be called; your callback will be inactive. + * + */ +XPLM_API void XPLMRegisterFlightLoopCallback(XPLMFlightLoop_f inFlightLoop, + float inInterval, + void *inRefcon); + +/* + * XPLMUnregisterFlightLoopCallback + * + * This routine unregisters your flight loop callback. Do NOT call it from + * your flight loop callback. Once your flight loop callback is + * unregistered, it will not be called again. + * + */ +XPLM_API void XPLMUnregisterFlightLoopCallback(XPLMFlightLoop_f inFlightLoop, + void *inRefcon); + +/* + * XPLMSetFlightLoopCallbackInterval + * + * This routine sets when a callback will be called. Do NOT call it from your + * callback; use the return value of the callback to change your callback + * interval from inside your callback. + * + * inInterval is formatted the same way as in XPLMRegisterFlightLoopCallback; + * positive for seconds, negative for cycles, and 0 for deactivating the + * callback. If inRelativeToNow is 1, times are from the time of this call; + * otherwise they are from the time the callback was last called (or the time + * it was registered if it has never been called. + * + */ +XPLM_API void XPLMSetFlightLoopCallbackInterval(XPLMFlightLoop_f inFlightLoop, + float inInterval, + int inRelativeToNow, + void *inRefcon); + +#if defined(XPLM210) +/* + * XPLMCreateFlightLoop + * + * This routine creates a flight loop callback and returns its ID. The flight + * loop callback is created using the input param struct, and is inited to be + * unscheduled. + * + */ +XPLM_API XPLMFlightLoopID + XPLMCreateFlightLoop(XPLMCreateFlightLoop_t *inParams); +#endif /* XPLM210 */ + +#if defined(XPLM210) +/* + * XPLMDestroyFlightLoop + * + * This routine destroys a flight loop callback by ID. + * + */ +XPLM_API void XPLMDestroyFlightLoop(XPLMFlightLoopID inFlightLoopID); +#endif /* XPLM210 */ + +#if defined(XPLM210) +/* + * XPLMScheduleFlightLoop + * + * This routine schedules a flight loop callback for future execution. If + * inInterval is negative, it is run in a certain number of frames based on + * the absolute value of the input. If the interval is positive, it is a + * duration in seconds. + * + * If inRelativeToNow is true, ties are interpretted relative to the time this + * routine is called; otherwise they are relative to the last call time or the + * time the flight loop was registered (if never called). + * + * THREAD SAFETY: it is legal to call this routine from any thread under the + * following conditions: + * + * 1. The call must be between the beginning of an XPLMEnable and the end of + * an XPLMDisable sequence. (That is, you must not call this routine from + * thread activity when your plugin was supposed to be disabled. Since + * plugins are only enabled while loaded, this also implies you cannot run + * this routine outside an XPLMStart/XPLMStop sequence.) + * + * 2. You may not call this routine re-entrantly for a single flight loop ID. + * (That is, you can't enable from multiple threads at the same time.) + * + * 3. You must call this routine between the time after XPLMCreateFlightLoop + * returns a value and the time you call XPLMDestroyFlightLoop. (That is, you + * must ensure that your threaded activity is within the life of the object. + * The SDK does not check this for you, nor does it synchronize destruction of + * the object.) + * + * 4. The object must be unscheduled if this routine is to be called from a + * thread other than the main thread. + * + */ +XPLM_API void XPLMScheduleFlightLoop(XPLMFlightLoopID inFlightLoopID, + float inInterval, + int inRelativeToNow); +#endif /* XPLM210 */ + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/GermanAirlinesVA-GAConnector/XPSDK/CHeaders/XPLM/XPLMScenery.h b/GermanAirlinesVA-GAConnector/XPSDK/CHeaders/XPLM/XPLMScenery.h new file mode 100644 index 0000000..0233cbb --- /dev/null +++ b/GermanAirlinesVA-GAConnector/XPSDK/CHeaders/XPLM/XPLMScenery.h @@ -0,0 +1,386 @@ +#ifndef _XPLMScenery_h_ +#define _XPLMScenery_h_ + +/* + * Copyright 2005-2012 Sandy Barbour and Ben Supnik + * + * All rights reserved. See license.txt for usage. + * + * X-Plane SDK Version: 2.1.1 + * + */ + +/* + * This package contains APIs to interact with X-Plane's scenery system. + * + */ + +#include "XPLMDefs.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#if defined(XPLM200) +/*************************************************************************** + * Terrain Y-Testing + ***************************************************************************/ +/* + * The Y-testing API allows you to locate the physical scenery mesh. This + * would be used to place dynamic graphics on top of the ground in a + * plausible way or do physics interactions. + * + * The Y-test API works via probe objects, which are allocated by your plugin + * and used to query terrain. Probe objects exist both to capture which + * algorithm you have requested (see probe types) and also to cache query + * information. + * + * Performance guidelines: It is generally faster to use the same probe for + * nearby points and different probes for different points. Try not to + * allocate more than "hundreds" of probes at most. Share probes if you need + * more. Generally, probing operations are expensive, and should be avoided + * via caching when possible. + * + * Y testing returns a location on the terrain, a normal vectory, and a + * velocity vector. The normal vector tells you the slope of the terrain at + * that point. The velocity vector tells you if that terrain is moving (and + * is in meters/second). For example, if your Y test hits the aircraft carrier + * deck, this tells you the velocity of that point on the deck. + * + * Note: the Y-testing API is limited to probing the loaded scenery area, + * which is approximately 300x300 km in X-Plane 9. Probes outside this area + * will return the height of a 0 MSL sphere. + * + */ + + +/* + * XPLMProbeType + * + * XPLMProbeType defines the type of terrain probe - each probe has a + * different algorithm. (Only one type of probe is provided right now, but + * future APIs will expose more flexible or poewrful or useful probes. + * + */ +enum { + /* The Y probe gives you the location of the tallest physical scenery along + * * the Y axis going through the queried point. */ + xplm_ProbeY = 0 + + +}; +typedef int XPLMProbeType; + +/* + * XPLMProbeResult + * + * Probe results - possible results from a probe query. + * + */ +enum { + /* The probe hit terrain and returned valid values. */ + xplm_ProbeHitTerrain = 0 + + /* An error in the API call. Either the probe struct size is bad, or the * + * probe is invalid or the type is mismatched for the specific query call. + */ + , + xplm_ProbeError = 1 + + /* The probe call succeeded but there is no terrain under this point + * (perhaps * it is off the side of the planet?) */ + , + xplm_ProbeMissed = 2 + + +}; +typedef int XPLMProbeResult; + +/* + * XPLMProbeRef + * + * An XPLMProbeRef is an opaque handle to a probe, used for querying the + * terrain. + * + */ +typedef void *XPLMProbeRef; + +/* + * XPLMProbeInfo_t + * + * XPLMProbeInfo_t contains the results of a probe call. Make sure to set + * structSize to the size of the struct before using it. + * + */ +typedef struct { + /* Size of structure in bytes - always set this before calling the XPLM. */ + int structSize; + /* Resulting X location of the terrain point we hit, in local OpenGL * + * coordinates. */ + float locationX; + /* Resulting Y location of the terrain point we hit, in local OpenGL * + * coordinates. */ + float locationY; + /* Resulting Z location of the terrain point we hit, in local OpenGL * + * coordinates. */ + float locationZ; + /* X component of the normal vector to the terrain we found. */ + float normalX; + /* Y component of the normal vector to the terrain we found. */ + float normalY; + /* Z component of the normal vector to the terrain we found. */ + float normalZ; + /* X component of the velocity vector of the terrain we found. */ + float velocityX; + /* Y component of the velocity vector of the terrain we found. */ + float velocityY; + /* Z component of the velocity vector of the terrain we found. */ + float velocityZ; + /* Tells if the surface we hit is water (otherwise it is land). */ + int is_wet; +} XPLMProbeInfo_t; + +/* + * XPLMCreateProbe + * + * Creates a new probe object of a given type and returns. + * + */ +XPLM_API XPLMProbeRef XPLMCreateProbe(XPLMProbeType inProbeType); + +/* + * XPLMDestroyProbe + * + * Deallocates an existing probe object. + * + */ +XPLM_API void XPLMDestroyProbe(XPLMProbeRef inProbe); + +/* + * XPLMProbeTerrainXYZ + * + * Probes the terrain. Pass in the XYZ coordinate of the probe point, a probe + * object, and an XPLMProbeInfo_t struct that has its structSize member set + * properly. Other fields are filled in if we hit terrain, and a probe result + * is returned. + * + */ +XPLM_API XPLMProbeResult XPLMProbeTerrainXYZ(XPLMProbeRef inProbe, + float inX, + float inY, + float inZ, + XPLMProbeInfo_t *outInfo); + +#endif /* XPLM200 */ +/*************************************************************************** + * Object Drawing + ***************************************************************************/ +/* + * The object drawing routines let you load and draw X-Plane OBJ files. + * Objects are loaded by file path and managed via an opaque handle. X-Plane + * naturally reference counts objects, so it is important that you balance + * every successful call to XPLMLoadObject with a call to XPLMUnloadObject! + * + */ + + +#if defined(XPLM200) +/* + * XPLMObjectRef + * + * An XPLMObjectRef is a opaque handle to an .obj file that has been loaded + * into memory. + * + */ +typedef void *XPLMObjectRef; +#endif /* XPLM200 */ + +#if defined(XPLM200) +/* + * XPLMDrawInfo_t + * + * The XPLMDrawInfo_t structure contains positioning info for one object that + * is to be drawn. Be sure to set structSize to the size of the structure for + * future expansion. + * + */ +typedef struct { + /* Set this to the size of this structure! */ + int structSize; + /* X location of the object in local coordinates. */ + float x; + /* Y location of the object in local coordinates. */ + float y; + /* Z location of the object in local coordinates. */ + float z; + /* Pitch in degres to rotate the object, positive is up. */ + float pitch; + /* Heading in local coordinates to rotate the object, clockwise. */ + float heading; + /* Roll to rotate the object. */ + float roll; +} XPLMDrawInfo_t; +#endif /* XPLM200 */ + +#if defined(XPLM210) +/* + * XPLMObjectLoaded_f + * + * You provide this callback when loading an object asynchronously; it will be + * called once the object is loaded. Your refcon is passed back. The object + * ref passed in is the newly loaded object (ready for use) or NULL if an + * error occured. + * + * If your plugin is disabled, this callback will be delivered as soon as the + * plugin is re-enabled. If your plugin is unloaded before this callback is + * ever called, the SDK will release the object handle for you. + * + */ +typedef void (*XPLMObjectLoaded_f)(XPLMObjectRef inObject, void *inRefcon); +#endif /* XPLM210 */ + +#if defined(XPLM200) +/* + * XPLMLoadObject + * + * This routine loads an OBJ file and returns a handle to it. If X-plane has + * already loaded the object, the handle to the existing object is returned. + * Do not assume you will get the same handle back twice, but do make sure to + * call unload once for every load to avoid "leaking" objects. The object + * will be purged from memory when no plugins and no scenery are using it. + * + * The path for the object must be relative to the X-System base folder. If + * the path is in the root of the X-System folder you may need to prepend ./ + * to it; loading objects in the root of the X-System folder is STRONGLY + * discouraged - your plugin should not dump art resources in the root folder! + * + * + * XPLMLoadObject will return NULL if the object cannot be loaded (either + * because it is not found or the file is misformatted). This routine will + * load any object that can be used in the X-Plane scenery system. + * + * It is important that the datarefs an object uses for animation already be + * loaded before you load the object. For this reason it may be necessary to + * defer object loading until the sim has fully started. + * + */ +XPLM_API XPLMObjectRef XPLMLoadObject(const char *inPath); +#endif /* XPLM200 */ + +#if defined(XPLM210) +/* + * XPLMLoadObjectAsync + * + * This routine loads an object asynchronously; control is returned to you + * immediately while X-Plane loads the object. The sim will not stop flying + * while the object loads. For large objects, it may be several seconds + * before the load finishes. + * + * You provide a callback function that is called once the load has completed. + * Note that if the object cannot be loaded, you will not find out until the + * callback function is called with a NULL object handle. + * + * There is no way to cancel an asynchronous object load; you must wait for + * the load to complete and then release the object if it is no longer + * desired. + * + */ +XPLM_API void XPLMLoadObjectAsync(const char *inPath, + XPLMObjectLoaded_f inCallback, + void *inRefcon); +#endif /* XPLM210 */ + +#if defined(XPLM200) +/* + * XPLMDrawObjects + * + * XPLMDrawObjects draws an object from an OBJ file one or more times. You + * pass in the object and an array of XPLMDrawInfo_t structs, one for each + * place you would like the object to be drawn. + * + * X-Plane will attempt to cull the objects based on LOD and visibility, and + * will pick the appropriate LOD. + * + * Lighting is a boolean; pass 1 to show the night version of object with + * night-only lights lit up. Pass 0 to show the daytime version of the + * object. + * + * earth_relative controls the coordinate system. If this is 1, the rotations + * you specify are applied to the object after its coordinate system is + * transformed from local to earth-relative coordinates -- that is, an object + * with no rotations will point toward true north and the Y axis will be up + * against gravity. If this is 0, the object is drawn with your rotations + * from local coordanates -- that is, an object with no rotations is drawn + * pointing down the -Z axis and the Y axis of the object matches the local + * coordinate Y axis. + * + */ +XPLM_API void XPLMDrawObjects(XPLMObjectRef inObject, + int inCount, + XPLMDrawInfo_t *inLocations, + int lighting, + int earth_relative); +#endif /* XPLM200 */ + +#if defined(XPLM200) +/* + * XPLMUnloadObject + * + * This routine marks an object as no longer being used by your plugin. + * Objects are reference counted: once no plugins are using an object, it is + * purged from memory. Make sure to call XPLMUnloadObject once for each + * successful call to XPLMLoadObject. + * + */ +XPLM_API void XPLMUnloadObject(XPLMObjectRef inObject); +#endif /* XPLM200 */ + +#if defined(XPLM200) +/*************************************************************************** + * Library Access + ***************************************************************************/ +/* + * The library access routines allow you to locate scenery objects via the + * X-Plane library system. Right now library access is only provided for + * objects, allowing plugin-drawn objects to be extended using the library + * system. + * + */ + + +/* + * XPLMLibraryEnumerator_f + * + * An XPLMLibraryEnumerator_f is a callback you provide that is called once + * for each library element that is located. The returned paths will be + * relative to the X-System folder. + * + */ +typedef void (*XPLMLibraryEnumerator_f)(const char *inFilePath, void *inRef); + +/* + * XPLMLookupObjects + * + * This routine looks up a virtual path in the library system and returns all + * matching elements. You provide a callback - one virtual path may match + * many objects in the library. XPLMLookupObjects returns the number of + * objects found. + * + * The latitude and longitude parameters specify the location the object will + * be used. The library system allows for scenery packages to only provide + * objects to certain local locations. Only objects that are allowed at the + * latitude/longitude you provide will be returned. + * + */ +XPLM_API int XPLMLookupObjects(const char *inPath, + float inLatitude, + float inLongitude, + XPLMLibraryEnumerator_f enumerator, + void *ref); + +#endif /* XPLM200 */ +#ifdef __cplusplus +} +#endif + +#endif diff --git a/GermanAirlinesVA-GAConnector/XPSDK/CHeaders/XPLM/XPLMUtilities.h b/GermanAirlinesVA-GAConnector/XPSDK/CHeaders/XPLM/XPLMUtilities.h new file mode 100644 index 0000000..ab57f10 --- /dev/null +++ b/GermanAirlinesVA-GAConnector/XPSDK/CHeaders/XPLM/XPLMUtilities.h @@ -0,0 +1,829 @@ +#ifndef _XPLMUtilities_h_ +#define _XPLMUtilities_h_ + +/* + * Copyright 2005-2012 Sandy Barbour and Ben Supnik + * + * All rights reserved. See license.txt for usage. + * + * X-Plane SDK Version: 2.1.1 + * + */ + +/* + * + * + */ + +#include "XPLMDefs.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/*************************************************************************** + * X-PLANE USER INTERACTION + ***************************************************************************/ +/* + * The user interaction APIs let you simulate commands the user can do with a + * joystick, keyboard etc. Note that it is generally safer for future + * compatibility to use one of these commands than to manipulate the + * underlying sim data. + * + */ + + +/* + * XPLMCommandKeyID + * + * These enums represent all the keystrokes available within x-plane. They + * can be sent to x-plane directly. For example, you can reverse thrust using + * these enumerations. + * + */ +enum { + xplm_key_pause = 0, + xplm_key_revthrust, + xplm_key_jettison, + xplm_key_brakesreg, + xplm_key_brakesmax, + xplm_key_gear, + xplm_key_timedn, + xplm_key_timeup, + xplm_key_fadec, + xplm_key_otto_dis, + xplm_key_otto_atr, + xplm_key_otto_asi, + xplm_key_otto_hdg, + xplm_key_otto_gps, + xplm_key_otto_lev, + xplm_key_otto_hnav, + xplm_key_otto_alt, + xplm_key_otto_vvi, + xplm_key_otto_vnav, + xplm_key_otto_nav1, + xplm_key_otto_nav2, + xplm_key_targ_dn, + xplm_key_targ_up, + xplm_key_hdgdn, + xplm_key_hdgup, + xplm_key_barodn, + xplm_key_baroup, + xplm_key_obs1dn, + xplm_key_obs1up, + xplm_key_obs2dn, + xplm_key_obs2up, + xplm_key_com1_1, + xplm_key_com1_2, + xplm_key_com1_3, + xplm_key_com1_4, + xplm_key_nav1_1, + xplm_key_nav1_2, + xplm_key_nav1_3, + xplm_key_nav1_4, + xplm_key_com2_1, + xplm_key_com2_2, + xplm_key_com2_3, + xplm_key_com2_4, + xplm_key_nav2_1, + xplm_key_nav2_2, + xplm_key_nav2_3, + xplm_key_nav2_4, + xplm_key_adf_1, + xplm_key_adf_2, + xplm_key_adf_3, + xplm_key_adf_4, + xplm_key_adf_5, + xplm_key_adf_6, + xplm_key_transpon_1, + xplm_key_transpon_2, + xplm_key_transpon_3, + xplm_key_transpon_4, + xplm_key_transpon_5, + xplm_key_transpon_6, + xplm_key_transpon_7, + xplm_key_transpon_8, + xplm_key_flapsup, + xplm_key_flapsdn, + xplm_key_cheatoff, + xplm_key_cheaton, + xplm_key_sbrkoff, + xplm_key_sbrkon, + xplm_key_ailtrimL, + xplm_key_ailtrimR, + xplm_key_rudtrimL, + xplm_key_rudtrimR, + xplm_key_elvtrimD, + xplm_key_elvtrimU, + xplm_key_forward, + xplm_key_down, + xplm_key_left, + xplm_key_right, + xplm_key_back, + xplm_key_tower, + xplm_key_runway, + xplm_key_chase, + xplm_key_free1, + xplm_key_free2, + xplm_key_spot, + xplm_key_fullscrn1, + xplm_key_fullscrn2, + xplm_key_tanspan, + xplm_key_smoke, + xplm_key_map, + xplm_key_zoomin, + xplm_key_zoomout, + xplm_key_cycledump, + xplm_key_replay, + xplm_key_tranID, + xplm_key_max +}; +typedef int XPLMCommandKeyID; + +/* + * XPLMCommandButtonID + * + * These are enumerations for all of the things you can do with a joystick + * button in X-Plane. They currently match the buttons menu in the equipment + * setup dialog, but these enums will be stable even if they change in + * X-Plane. + * + */ +enum { + xplm_joy_nothing = 0, + xplm_joy_start_all, + xplm_joy_start_0, + xplm_joy_start_1, + xplm_joy_start_2, + xplm_joy_start_3, + xplm_joy_start_4, + xplm_joy_start_5, + xplm_joy_start_6, + xplm_joy_start_7, + xplm_joy_throt_up, + xplm_joy_throt_dn, + xplm_joy_prop_up, + xplm_joy_prop_dn, + xplm_joy_mixt_up, + xplm_joy_mixt_dn, + xplm_joy_carb_tog, + xplm_joy_carb_on, + xplm_joy_carb_off, + xplm_joy_trev, + xplm_joy_trm_up, + xplm_joy_trm_dn, + xplm_joy_rot_trm_up, + xplm_joy_rot_trm_dn, + xplm_joy_rud_lft, + xplm_joy_rud_cntr, + xplm_joy_rud_rgt, + xplm_joy_ail_lft, + xplm_joy_ail_cntr, + xplm_joy_ail_rgt, + xplm_joy_B_rud_lft, + xplm_joy_B_rud_rgt, + xplm_joy_look_up, + xplm_joy_look_dn, + xplm_joy_look_lft, + xplm_joy_look_rgt, + xplm_joy_glance_l, + xplm_joy_glance_r, + xplm_joy_v_fnh, + xplm_joy_v_fwh, + xplm_joy_v_tra, + xplm_joy_v_twr, + xplm_joy_v_run, + xplm_joy_v_cha, + xplm_joy_v_fr1, + xplm_joy_v_fr2, + xplm_joy_v_spo, + xplm_joy_flapsup, + xplm_joy_flapsdn, + xplm_joy_vctswpfwd, + xplm_joy_vctswpaft, + xplm_joy_gear_tog, + xplm_joy_gear_up, + xplm_joy_gear_down, + xplm_joy_lft_brake, + xplm_joy_rgt_brake, + xplm_joy_brakesREG, + xplm_joy_brakesMAX, + xplm_joy_speedbrake, + xplm_joy_ott_dis, + xplm_joy_ott_atr, + xplm_joy_ott_asi, + xplm_joy_ott_hdg, + xplm_joy_ott_alt, + xplm_joy_ott_vvi, + xplm_joy_tim_start, + xplm_joy_tim_reset, + xplm_joy_ecam_up, + xplm_joy_ecam_dn, + xplm_joy_fadec, + xplm_joy_yaw_damp, + xplm_joy_art_stab, + xplm_joy_chute, + xplm_joy_JATO, + xplm_joy_arrest, + xplm_joy_jettison, + xplm_joy_fuel_dump, + xplm_joy_puffsmoke, + xplm_joy_prerotate, + xplm_joy_UL_prerot, + xplm_joy_UL_collec, + xplm_joy_TOGA, + xplm_joy_shutdown, + xplm_joy_con_atc, + xplm_joy_fail_now, + xplm_joy_pause, + xplm_joy_rock_up, + xplm_joy_rock_dn, + xplm_joy_rock_lft, + xplm_joy_rock_rgt, + xplm_joy_rock_for, + xplm_joy_rock_aft, + xplm_joy_idle_hilo, + xplm_joy_lanlights, + xplm_joy_max +}; +typedef int XPLMCommandButtonID; + +/* + * XPLMHostApplicationID + * + * The plug-in system is based on Austin's cross-platform OpenGL framework and + * could theoretically be adapted to run in other apps like WorldMaker. The + * plug-in system also runs against a test harness for internal development + * and could be adapted to another flight sim (in theory at least). So an ID + * is providing allowing plug-ins to indentify what app they are running + * under. + * + */ +enum { + xplm_Host_Unknown = 0 + + , + xplm_Host_XPlane = 1 + + , + xplm_Host_PlaneMaker = 2 + + , + xplm_Host_WorldMaker = 3 + + , + xplm_Host_Briefer = 4 + + , + xplm_Host_PartMaker = 5 + + , + xplm_Host_YoungsMod = 6 + + , + xplm_Host_XAuto = 7 + + +}; +typedef int XPLMHostApplicationID; + +/* + * XPLMLanguageCode + * + * These enums define what language the sim is running in. These enumerations + * do not imply that the sim can or does run in all of these languages; they + * simply provide a known encoding in the event that a given sim version is + * localized to a certain language. + * + */ +enum { + xplm_Language_Unknown = 0 + + , + xplm_Language_English = 1 + + , + xplm_Language_French = 2 + + , + xplm_Language_German = 3 + + , + xplm_Language_Italian = 4 + + , + xplm_Language_Spanish = 5 + + , + xplm_Language_Korean = 6 + +#if defined(XPLM200) + , + xplm_Language_Russian = 7 + +#endif /* XPLM200 */ +#if defined(XPLM200) + , + xplm_Language_Greek = 8 + +#endif /* XPLM200 */ +#if defined(XPLM200) + , + xplm_Language_Japanese = 9 + +#endif /* XPLM200 */ +#if defined(XPLM200) + , + xplm_Language_Chinese = 10 + +#endif /* XPLM200 */ + +}; +typedef int XPLMLanguageCode; + +#if defined(XPLM200) +/* + * XPLMDataFileType + * + * These enums define types of data files you can load or unload using the + * SDK. + * + */ +enum { + /* A situation (.sit) file, which starts off a flight in a given * + * configuration. */ + xplm_DataFile_Situation = 1 + + /* A situation movie (.smo) file, which replays a past flight. */ + , + xplm_DataFile_ReplayMovie = 2 + + +}; +typedef int XPLMDataFileType; +#endif /* XPLM200 */ + +#if defined(XPLM200) +/* + * XPLMError_f + * + * An XPLM error callback is a function that you provide to receive debugging + * information from the plugin SDK. See XPLMSetErrorCallback for more + * information. NOTE: for the sake of debugging, your error callback will be + * called even if your plugin is not enabled, allowing you to receive debug + * info in your XPluginStart and XPluginStop callbacks. To avoid causing + * logic errors in the management code, do not call any other plugin routines + * from your error callback - it is only meant for logging! + * + */ +typedef void (*XPLMError_f)(const char *inMessage); +#endif /* XPLM200 */ + +/* + * XPLMSimulateKeyPress + * + * This function simulates a key being pressed for x-plane. The keystroke + * goes directly to x-plane; it is never sent to any plug-ins. However, since + * this is a raw key stroke it may be mapped by the keys file or enter text + * into a field. + * + * WARNING: This function will be deprecated; do not use it. Instead use + * XPLMCommandKeyStroke. + * + */ +XPLM_API void XPLMSimulateKeyPress(int inKeyType, int inKey); + +/* + * XPLMSpeakString + * + * This function displays the string in a translucent overlay over the current + * display and also speaks the string if text-to-speech is enabled. The + * string is spoken asynchronously, this function returns immediately. + * + */ +XPLM_API void XPLMSpeakString(const char *inString); + +/* + * XPLMCommandKeyStroke + * + * This routine simulates a command-key stroke. However, the keys are done by + * function, not by actual letter, so this function works even if the user has + * remapped their keyboard. Examples of things you might do with this include + * pausing the simulator. + * + */ +XPLM_API void XPLMCommandKeyStroke(XPLMCommandKeyID inKey); + +/* + * XPLMCommandButtonPress + * + * This function simulates any of the actions that might be taken by pressing + * a joystick button. However, this lets you call the command directly rather + * than have to know which button is mapped where. Important: you must + * release each button you press. The APIs are separate so that you can 'hold + * down' a button for a fixed amount of time. + * + */ +XPLM_API void XPLMCommandButtonPress(XPLMCommandButtonID inButton); + +/* + * XPLMCommandButtonRelease + * + * This function simulates any of the actions that might be taken by pressing + * a joystick button. See XPLMCommandButtonPress + * + */ +XPLM_API void XPLMCommandButtonRelease(XPLMCommandButtonID inButton); + +/* + * XPLMGetVirtualKeyDescription + * + * Given a virtual key code (as defined in XPLMDefs.h) this routine returns a + * human-readable string describing the character. This routine is provided + * for showing users what keyboard mappings they have set up. The string may + * read 'unknown' or be a blank or NULL string if the virtual key is unknown. + * + */ +XPLM_API const char *XPLMGetVirtualKeyDescription(char inVirtualKey); + +/*************************************************************************** + * X-PLANE MISC + ***************************************************************************/ +/* + * + * + */ + + +/* + * XPLMReloadScenery + * + * XPLMReloadScenery reloads the current set of scenery. You can use this + * function in two typical ways: simply call it to reload the scenery, picking + * up any new installed scenery, .env files, etc. from disk. Or, change the + * lat/ref and lon/ref data refs and then call this function to shift the + * scenery environment. + * + */ +XPLM_API void XPLMReloadScenery(void); + +/* + * XPLMGetSystemPath + * + * This function returns the full path to the X-System folder. Note that this + * is a directory path, so it ends in a trailing : or /. The buffer you pass + * should be at least 512 characters long. + * + */ +XPLM_API void XPLMGetSystemPath(char *outSystemPath); + +/* + * XPLMGetPrefsPath + * + * This routine returns a full path to the proper directory to store + * preferences in. It ends in a : or /. The buffer you pass should be at + * least 512 characters long. + * + */ +XPLM_API void XPLMGetPrefsPath(char *outPrefsPath); + +/* + * XPLMGetDirectorySeparator + * + * This routine returns a string with one char and a null terminator that is + * the directory separator for the current platform. This allows you to write + * code that concatinates directory paths without having to #ifdef for + * platform. + * + */ +XPLM_API const char *XPLMGetDirectorySeparator(void); + +/* + * XPLMExtractFileAndPath + * + * Given a full path to a file, this routine separates the path from the file. + * If the path is a partial directory (e.g. ends in : or \) the trailing + * directory separator is removed. This routine works in-place; a pointer to + * the file part of the buffer is returned; the original buffer still starts + * with the path. + * + */ +XPLM_API char *XPLMExtractFileAndPath(char *inFullPath); + +/* + * XPLMGetDirectoryContents + * + * This routine returns a list of files in a directory (specified by a full + * path, no trailing : or \). The output is returned as a list of NULL + * terminated strings. An index array (if specified) is filled with pointers + * into the strings. This routine The last file is indicated by a zero-length + * string (and NULL in the indices). This routine will return 1 if you had + * capacity for all files or 0 if you did not. You can also skip a given + * number of files. + * + * inDirectoryPath - a null terminated C string containing the full path to + * the directory with no trailing directory char. + * + * inFirstReturn - the zero-based index of the first file in the directory to + * return. (Usually zero to fetch all in one pass.) + * + * outFileNames - a buffer to receive a series of sequential null terminated + * C-string file names. A zero-length C string will be appended to the very + * end. + * + * inFileNameBufSize - the size of the file name buffer in bytes. + * + * outIndices - a pointer to an array of character pointers that will become + * an index into the directory. The last file will be followed by a NULL + * value. Pass NULL if you do not want indexing information. + * + * inIndexCount - the max size of the index in entries. + * + * outTotalFiles - if not NULL, this is filled in with the number of files in + * the directory. + * + * outReturnedFiles - if not NULL, the number of files returned by this + * iteration. + * + * Return value - 1 if all info could be returned, 0 if there was a buffer + * overrun. + * + * WARNING: Before X-Plane 7 this routine did not properly iterate through + * directories. If X-Plane 6 compatibility is needed, use your own code to + * iterate directories. + * + */ +XPLM_API int XPLMGetDirectoryContents(const char *inDirectoryPath, + int inFirstReturn, + char *outFileNames, + int inFileNameBufSize, + char **outIndices, /* Can be NULL */ + int inIndexCount, + int *outTotalFiles, /* Can be NULL */ + int *outReturnedFiles); /* Can be NULL */ + +/* + * XPLMInitialized + * + * This function returns 1 if X-Plane has properly initialized the plug-in + * system. If this routine returns 0, many XPLM functions will not work. + * + * NOTE: Under normal circumstances a plug-in should never be running while + * the plug-in manager is not initialized. + * + * WARNING: This function is generally not needed and may be deprecated in the + * future. + * + */ +XPLM_API int XPLMInitialized(void); + +/* + * XPLMGetVersions + * + * This routine returns the revision of both X-Plane and the XPLM DLL. All + * versions are three-digit decimal numbers (e.g. 606 for version 6.06 of + * X-Plane); the current revision of the XPLM is 200 (2.00). This routine + * also returns the host ID of the app running us. + * + * The most common use of this routine is to special-case around x-plane + * version-specific behavior. + * + */ +XPLM_API void XPLMGetVersions(int *outXPlaneVersion, + int *outXPLMVersion, + XPLMHostApplicationID *outHostID); + +/* + * XPLMGetLanguage + * + * This routine returns the langauge the sim is running in. + * + */ +XPLM_API XPLMLanguageCode XPLMGetLanguage(void); + +/* + * XPLMDebugString + * + * This routine outputs a C-style string to the Log.txt file. The file is + * immediately flushed so you will not lose data. (This does cause a + * performance penalty.) + * + */ +XPLM_API void XPLMDebugString(const char *inString); + +#if defined(XPLM200) +/* + * XPLMSetErrorCallback + * + * XPLMSetErrorCallback installs an error-reporting callback for your plugin. + * Normally the plugin system performs minimum diagnostics to maximize + * performance. When you install an error callback, you will receive calls + * due to certain plugin errors, such as passing bad parameters or incorrect + * data. + * + * The intention is for you to install the error callback during debug + * sections and put a break-point inside your callback. This will cause you + * to break into the debugger from within the SDK at the point in your plugin + * where you made an illegal call. + * + * Installing an error callback may activate error checking code that would + * not normally run, and this may adversely affect performance, so do not + * leave error callbacks installed in shipping plugins. + * + */ +XPLM_API void XPLMSetErrorCallback(XPLMError_f inCallback); +#endif /* XPLM200 */ + +#if defined(XPLM200) +/* + * XPLMFindSymbol + * + * This routine will attempt to find the symbol passed in the inString + * parameter. If the symbol is found a pointer the function is returned, + * othewise the function will return NULL. + * + */ +XPLM_API void *XPLMFindSymbol(const char *inString); +#endif /* XPLM200 */ + +#if defined(XPLM200) +/* + * XPLMLoadDataFile + * + * Loads a data file of a given type. Paths must be relative to the X-System + * folder. To clear the replay, pass a NULL file name (this is only valid with + * replay movies, not sit files). + * + */ +XPLM_API int XPLMLoadDataFile(XPLMDataFileType inFileType, + const char *inFilePath); /* Can be NULL */ +#endif /* XPLM200 */ + +#if defined(XPLM200) +/* + * XPLMSaveDataFile + * + * Saves the current situation or replay; paths are relative to the X-System + * folder. + * + */ +XPLM_API int XPLMSaveDataFile(XPLMDataFileType inFileType, + const char *inFilePath); +#endif /* XPLM200 */ + +#if defined(XPLM200) +/*************************************************************************** + * X-PLANE COMMAND MANAGEMENT + ***************************************************************************/ +/* + * The command management APIs let plugins interact with the command-system in + * X-Plane, the abstraction behind keyboard presses and joystick buttons. + * This API lets you create new commands and modify the behavior (or get + * notification) of existing ones. + * + * An X-Plane command consists of three phases: a beginning, continuous + * repetition, and an ending. The command may be repeated zero times in the + * event that the user presses a button only momentarily. + * + */ + + +/* + * XPLMCommandPhase + * + * The phases of a command. + * + */ +enum { + /* The command is being started. */ + xplm_CommandBegin = 0 + + /* The command is continuing to execute. */ + , + xplm_CommandContinue = 1 + + /* The command has ended. */ + , + xplm_CommandEnd = 2 + + +}; +typedef int XPLMCommandPhase; + +/* + * XPLMCommandRef + * + * A command ref is an opaque identifier for an X-Plane command. Command + * references stay the same for the life of your plugin but not between + * executions of X-Plane. Command refs are used to execute commands, create + * commands, and create callbacks for particular commands. + * + * Note that a command is not "owned" by a particular plugin. Since many + * plugins may participate in a command's execution, the command does not go + * away if the plugin that created it is unloaded. + * + */ +typedef void *XPLMCommandRef; + +/* + * XPLMCommandCallback_f + * + * A command callback is a function in your plugin that is called when a + * command is pressed. Your callback receives the commadn reference for the + * particular command, the phase of the command that is executing, and a + * reference pointer that you specify when registering the callback. + * + * Your command handler should return 1 to let processing of the command + * continue to other plugins and X-Plane, or 0 to halt processing, + * potentially bypassing X-Plane code. + * + */ +typedef int (*XPLMCommandCallback_f)(XPLMCommandRef inCommand, + XPLMCommandPhase inPhase, + void *inRefcon); + +/* + * XPLMFindCommand + * + * XPLMFindCommand looks up a command by name, and returns its command + * reference or NULL if the command does not exist. + * + */ +XPLM_API XPLMCommandRef XPLMFindCommand(const char *inName); + +/* + * XPLMCommandBegin + * + * XPLMCommandBegin starts the execution of a command, specified by its + * command reference. The command is "held down" until XPLMCommandEnd is + * called. + * + */ +XPLM_API void XPLMCommandBegin(XPLMCommandRef inCommand); + +/* + * XPLMCommandEnd + * + * XPLMCommandEnd ends the execution of a given command that was started with + * XPLMCommandBegin. + * + */ +XPLM_API void XPLMCommandEnd(XPLMCommandRef inCommand); + +/* + * XPLMCommandOnce + * + * This executes a given command momentarily, that is, the command begins and + * ends immediately. + * + */ +XPLM_API void XPLMCommandOnce(XPLMCommandRef inCommand); + +/* + * XPLMCreateCommand + * + * XPLMCreateCommand creates a new command for a given string. If the command + * already exists, the existing command reference is returned. The + * description may appear in user interface contexts, such as the joystick + * configuration screen. + * + */ +XPLM_API XPLMCommandRef XPLMCreateCommand(const char *inName, + const char *inDescription); + +/* + * XPLMRegisterCommandHandler + * + * XPLMRegisterCommandHandler registers a callback to be called when a command + * is executed. You provide a callback with a reference pointer. + * + * If inBefore is true, your command handler callback will be executed before + * X-Plane executes the command, and returning 0 from your callback will + * disable X-Plane's processing of the command. If inBefore is false, your + * callback will run after X-Plane. (You can register a single callback both + * before and after a command.) + * + */ +XPLM_API void XPLMRegisterCommandHandler(XPLMCommandRef inComand, + XPLMCommandCallback_f inHandler, + int inBefore, + void *inRefcon); + +/* + * XPLMUnregisterCommandHandler + * + * XPLMUnregisterCommandHandler removes a command callback registered with + * XPLMRegisterCommandHandler. + * + */ +XPLM_API void XPLMUnregisterCommandHandler(XPLMCommandRef inComand, + XPLMCommandCallback_f inHandler, + int inBefore, + void *inRefcon); + +#endif /* XPLM200 */ +#ifdef __cplusplus +} +#endif + +#endif diff --git a/GermanAirlinesVA-GAConnector/XPSDK/Delphi/Widgets/XPStandardWidgets.pas b/GermanAirlinesVA-GAConnector/XPSDK/Delphi/Widgets/XPStandardWidgets.pas new file mode 100644 index 0000000..bde7c77 --- /dev/null +++ b/GermanAirlinesVA-GAConnector/XPSDK/Delphi/Widgets/XPStandardWidgets.pas @@ -0,0 +1,497 @@ +{ + Copyright 2005-2012 Sandy Barbour and Ben Supnik + + All rights reserved. See license.txt for usage. + + X-Plane SDK Version: 2.1.1 +} + +UNIT XPStandardWidgets; +INTERFACE +{ + XPStandardWidgets - THEORY OF OPERATION + + The standard widgets are widgets built into the widgets library. While you + can gain access to the widget function that drives them, you generally use + them by calling XPCreateWidget and then listening for special messages, + etc. + + The standard widgets often send mesages to themselves when the user + performs an event; these messages are sent up the widget hierarchy until + they are handled. So you can add a widget proc directly to a push button + (for example) to intercept the message when it is clicked, or you can put + one widget proc on a window for all of the push buttons in the window. + Most of these messages contain the original widget ID as a parameter so you + can know which widget is messaging no matter who it is sent to. +} + +USES XPWidgetDefs; + {$A4} +{$IFDEF MSWINDOWS} + {$DEFINE DELPHI} +{$ENDIF} +{___________________________________________________________________________ + * MAIN WINDOW + ___________________________________________________________________________} +{ + The main window widget class provides a "window" as the user knows it. + These windows are dragable and can be selected. Use them to create + floating windows and non-modal dialogs. +} + + + +CONST + xpWidgetClass_MainWindow = 1; + + { + Main Window Type Values + + These type values are used to control the appearance of a main window. + } + { The standard main window; pin stripes on XP7, metal frame on XP 6. } + xpMainWindowStyle_MainWindow = 0 +; + { A translucent dark gray window, like the one ATC messages appear in. } + xpMainWindowStyle_Translucent = 1 +; + + { + Main Window Properties + + } + { This property specifies the type of window. Set to one of the main window } + { types above. } + xpProperty_MainWindowType = 1100 +; + { This property specifies whether the main window has close boxes in its } + { corners. } + xpProperty_MainWindowHasCloseBoxes = 1200 +; + + { + MainWindow Messages + + } + { This message is sent when the close buttons are pressed for your window. } + xpMessage_CloseButtonPushed = 1200 +; + +{___________________________________________________________________________ + * SUB WINDOW + ___________________________________________________________________________} +{ + X-plane dialogs are divided into separate areas; the sub window widgets + allow you to make these areas. Create one main window and place several + subwindows inside it. Then place your controls inside the subwindows. +} + + + +CONST + xpWidgetClass_SubWindow = 2; + + { + SubWindow Type Values + + These values control the appearance of the subwindow. + } + { A panel that sits inside a main window. } + xpSubWindowStyle_SubWindow = 0 +; + { A screen that sits inside a panel for showing text information. } + xpSubWindowStyle_Screen = 2 +; + { A list view for scrolling lists. } + xpSubWindowStyle_ListView = 3 +; + + { + SubWindow Properties + + } + { This property specifies the type of window. Set to one of the subwindow } + { types above. } + xpProperty_SubWindowType = 1200 +; + +{___________________________________________________________________________ + * BUTTON + ___________________________________________________________________________} +{ + The button class provides a number of different button styles and + behaviors, including push buttons, radio buttons, check boxes, etc. The + button label appears on or next to the button depending on the button's + appearance, or type. + + The button's behavior is a separate property that dictates who it hilights + and what kinds of messages it sends. Since behavior and type are + different, you can do strange things like make check boxes that act as push + buttons or push buttons with radio button behavior. + + In X-Plane 6 there were no check box graphics. The result is the following + behavior: in x-plane 6 all check box and radio buttons are round + (radio-button style) buttons; in X-Plane 7 they are all square (check-box + style) buttons. In a future version of x-plane, the xpButtonBehavior enums + will provide the correct graphic (check box or radio button) giving the + expected result. +} + + + +CONST + xpWidgetClass_Button = 3; + + { + Button Types + + These define the visual appearance of buttons but not how they respond to + the mouse. + } + { This is a standard push button, like an "OK" or "Cancel" button in a dialog } + { box. } + xpPushButton = 0 +; + { A check box or radio button. Use this and the button behaviors below to } + { get the desired behavior. } + xpRadioButton = 1 +; + { A window close box. } + xpWindowCloseBox = 3 +; + { A small down arrow. } + xpLittleDownArrow = 5 +; + { A small up arrow. } + xpLittleUpArrow = 6 +; + + { + Button Behavior Values + + These define how the button responds to mouse clicks. + } + { Standard push button behavior. The button hilites while the mouse is } + { clicked over it and unhilites when the mouse is moved outside of it or } + { released. If the mouse is released over the button, the } + { xpMsg_PushButtonPressed message is sent. } + xpButtonBehaviorPushButton = 0 +; + { Check box behavior. The button immediately toggles its value when the } + { mouse is clicked and sends out a xpMsg_ButtonStateChanged message. } + xpButtonBehaviorCheckBox = 1 +; + { Radio button behavior. The button immediately sets its state to one and } + { sends out a xpMsg_ButtonStateChanged message if it was not already set to } + { one. You must turn off other radio buttons in a group in your code. } + xpButtonBehaviorRadioButton = 2 +; + + { + Button Properties + + } + { This property sets the visual type of button. Use one of the button types } + { above. } + xpProperty_ButtonType = 1300 +; + { This property sets the button's behavior. Use one of the button behaviors } + { above. } + xpProperty_ButtonBehavior = 1301 +; + { This property tells whether a check box or radio button is "checked" or } + { not. Not used for push buttons. } + xpProperty_ButtonState = 1302 +; + + { + Button Messages + + These messages are sent by the button to itself and then up the widget + chain when the button is clicked. (You may intercept them by providing a + widget handler for the button itself or by providing a handler in a parent + widget.) + } + { This message is sent when the user completes a click and release in a } + { button with push button behavior. Parameter one of the message is the } + { widget ID of the button. This message is dispatched up the widget } + { hierarchy. } + xpMsg_PushButtonPressed = 1300 +; + { This message is sent when a button is clicked that has radio button or } + { check box behavior and its value changes. (Note that if the value changes } + { by setting a property you do not receive this message!) Parameter one is } + { the widget ID of the button, parameter 2 is the new state value, either } + { zero or one. This message is dispatched up the widget hierarchy. } + xpMsg_ButtonStateChanged = 1301 +; + +{___________________________________________________________________________ + * TEXT FIELD + ___________________________________________________________________________} +{ + The text field widget provides an editable text field including mouse + selection and keyboard navigation. The contents of the text field are its + descriptor. (The descriptor changes as the user types.) + + The text field can have a number of types, that effect the visual layout of + the text field. The text field sends messages to itself so you may control + its behavior. + + If you need to filter keystrokes, add a new handler and intercept the key + press message. Since key presses are passed by pointer, you can modify the + keystroke and pass it through to the text field widget. + + WARNING: in x-plane before 7.10 (including 6.70) null characters could + crash x-plane. To prevent this, wrap this object with a filter function + (more instructions can be found on the SDK website). +} + + + +CONST + xpWidgetClass_TextField = 4; + + { + Text Field Type Values + + These control the look of the text field. + } + { A field for text entry. } + xpTextEntryField = 0 +; + { A transparent text field. The user can type and the text is drawn, but no } + { background is drawn. You can draw your own background by adding a widget } + { handler and prehandling the draw message. } + xpTextTransparent = 3 +; + { A translucent edit field, dark gray. } + xpTextTranslucent = 4 +; + + { + Text Field Properties + + } + { This is the character position the selection starts at, zero based. If it } + { is the same as the end insertion point, the insertion point is not a } + { selection. } + xpProperty_EditFieldSelStart = 1400 +; + { This is the character position of the end of the selection. } + xpProperty_EditFieldSelEnd = 1401 +; + { This is the character position a drag was started at if the user is } + { dragging to select text, or -1 if a drag is not in progress. } + xpProperty_EditFieldSelDragStart = 1402 +; + { This is the type of text field to display, from the above list. } + xpProperty_TextFieldType = 1403 +; + { Set this property to 1 to password protect the field. Characters will be } + { drawn as *s even though the descriptor will contain plain-text. } + xpProperty_PasswordMode = 1404 +; + { The max number of characters you can enter, if limited. Zero means } + { unlimited. } + xpProperty_MaxCharacters = 1405 +; + { The first visible character on the left. This effectively scrolls the text } + { field. } + xpProperty_ScrollPosition = 1406 +; + { The font to draw the field's text with. (An XPLMFontID.) } + xpProperty_Font = 1407 +; + { This is the active side of the insert selection. (Internal) } + xpProperty_ActiveEditSide = 1408 +; + + { + Text Field Messages + + } + { Text Field Messages } + { } + { The text field sends this message to itself when its text changes. It } + { sends the message up the call chain; param1 is the text field's widget ID. } + xpMsg_TextFieldChanged = 1400 +; + +{___________________________________________________________________________ + * SCROLL BAR + ___________________________________________________________________________} +{ + A standard scroll bar or slider control. The scroll bar has a minimum, + maximum and current value that is updated when the user drags it. The + scroll bar sends continuous messages as it is dragged. +} + + + +CONST + xpWidgetClass_ScrollBar = 5; + + { + Scroll Bar Type Values + + This defines how the scroll bar looks. + } + { Scroll bar types. } + { } + { A standard x-plane scroll bar (with arrows on the ends). } + xpScrollBarTypeScrollBar = 0 +; + { A slider, no arrows. } + xpScrollBarTypeSlider = 1 +; + + { + Scroll Bar Properties + + } + { The current position of the thumb (in between the min and max, inclusive) } + xpProperty_ScrollBarSliderPosition = 1500 +; + { The value the scroll bar has when the thumb is in the lowest position. } + xpProperty_ScrollBarMin = 1501 +; + { The value the scroll bar has when the thumb is in the highest position. } + xpProperty_ScrollBarMax = 1502 +; + { How many units to moev the scroll bar when clicking next to the thumb. The } + { scroll bar always moves one unit when the arrows are clicked. } + xpProperty_ScrollBarPageAmount = 1503 +; + { The type of scrollbar from the enums above. } + xpProperty_ScrollBarType = 1504 +; + { Used internally. } + xpProperty_ScrollBarSlop = 1505 +; + + { + Scroll Bar Messages + + } + { The Scroll Bar sends this message when the slider position changes. It } + { sends the message up the call chain; param1 is the Scroll Bar widget ID. } + xpMsg_ScrollBarSliderPositionChanged = 1500 +; + +{___________________________________________________________________________ + * CAPTION + ___________________________________________________________________________} +{ + A caption is a simple widget that shows its descriptor as a string, useful + for labeling parts of a window. It always shows its descriptor as its + string and is otherwise transparent. +} + + + +CONST + xpWidgetClass_Caption = 6; + + { + Caption Properties + + } + { This property specifies whether the caption is lit; use lit captions } + { against screens. } + xpProperty_CaptionLit = 1600 +; + +{___________________________________________________________________________ + * GENERAL GRAPHICS + ___________________________________________________________________________} +{ + The general graphics widget can show one of many icons available from + x-plane. +} + + + +CONST + xpWidgetClass_GeneralGraphics = 7; + + { + General Graphics Types Values + + These define the icon for the general graphics. + } + xpShip = 4 +; + xpILSGlideScope = 5 +; + xpMarkerLeft = 6 +; + xp_Airport = 7 +; + xpNDB = 8 +; + xpVOR = 9 +; + xpRadioTower = 10 +; + xpAircraftCarrier = 11 +; + xpFire = 12 +; + xpMarkerRight = 13 +; + xpCustomObject = 14 +; + xpCoolingTower = 15 +; + xpSmokeStack = 16 +; + xpBuilding = 17 +; + xpPowerLine = 18 +; + xpVORWithCompassRose = 19 +; + xpOilPlatform = 21 +; + xpOilPlatformSmall = 22 +; + xpWayPoint = 23 +; + + { + General Graphics Properties + + } + { This property controls the type of icon that is drawn. } + xpProperty_GeneralGraphicsType = 1700 +; + +{___________________________________________________________________________ + * PROGRESS INDICATOR + ___________________________________________________________________________} +{ + This widget implements a progress indicator as seen when x-plane starts up. +} + + + +CONST + xpWidgetClass_Progress = 8; + + { + Progress Indicator Properties + + } + { This is the current value of the progress indicator. } + xpProperty_ProgressPosition = 1800 +; + { This is the minimum value, equivalent to 0% filled. } + xpProperty_ProgressMin = 1801 +; + { This is the maximum value, equivalent to 100% filled. } + xpProperty_ProgressMax = 1802 +; + +IMPLEMENTATION +END. diff --git a/GermanAirlinesVA-GAConnector/XPSDK/Delphi/Widgets/XPUIGraphics.pas b/GermanAirlinesVA-GAConnector/XPSDK/Delphi/Widgets/XPUIGraphics.pas new file mode 100644 index 0000000..f06806a --- /dev/null +++ b/GermanAirlinesVA-GAConnector/XPSDK/Delphi/Widgets/XPUIGraphics.pas @@ -0,0 +1,380 @@ +{ + Copyright 2005-2012 Sandy Barbour and Ben Supnik + + All rights reserved. See license.txt for usage. + + X-Plane SDK Version: 2.1.1 +} + +UNIT XPUIGraphics; +INTERFACE +{ + +} + +USES XPWidgetDefs; + {$A4} +{$IFDEF MSWINDOWS} + {$DEFINE DELPHI} +{$ENDIF} +{___________________________________________________________________________ + * UI GRAPHICS + ___________________________________________________________________________} +{ + +} + + + { + XPWindowStyle + + There are a few built-in window styles in X-Plane that you can use. + + Note that X-Plane 6 does not offer real shadow-compositing; you must make + sure to put a window on top of another window of the right style to the + shadows work, etc. This applies to elements with insets and shadows. The + rules are: + + Sub windows must go on top of main windows, and screens and list views on + top of subwindows. Only help and main windows can be over the main screen. + + + With X-Plane 7 any window or element may be placed over any other element. + + Some windows are scaled by stretching, some by repeating. The drawing + routines know which scaling method to use. The list view cannot be + rescaled in x-plane 6 because it has both a repeating pattern and a + gradient in one element. All other elements can be rescaled. + } +TYPE + XPWindowStyle = ( + { An LCD screen that shows help. } + xpWindow_Help = 0 + + { A dialog box window. } + ,xpWindow_MainWindow = 1 + + { A panel or frame within a dialog box window. } + ,xpWindow_SubWindow = 2 + + { An LCD screen within a panel to hold text displays. } + ,xpWindow_Screen = 4 + + { A list view within a panel for scrolling file names, etc. } + ,xpWindow_ListView = 5 + + ); + PXPWindowStyle = ^XPWindowStyle; + + { + XPDrawWindow + + This routine draws a window of the given dimensions at the given offset on + the virtual screen in a given style. The window is automatically scaled as + appropriate using a bitmap scaling technique (scaling or repeating) as + appropriate to the style. + } + PROCEDURE XPDrawWindow( + inX1 : integer; + inY1 : integer; + inX2 : integer; + inY2 : integer; + inStyle : XPWindowStyle); +{$IFDEF DELPHI} + cdecl; external 'XPWIDGETS.DLL'; +{$ELSE} + cdecl; external ''; +{$ENDIF} + + { + XPGetWindowDefaultDimensions + + This routine returns the default dimensions for a window. Output is either + a minimum or fixed value depending on whether the window is scalable. + } + PROCEDURE XPGetWindowDefaultDimensions( + inStyle : XPWindowStyle; + outWidth : Pinteger; { Can be nil } + outHeight : Pinteger); { Can be nil } +{$IFDEF DELPHI} + cdecl; external 'XPWIDGETS.DLL'; +{$ELSE} + cdecl; external ''; +{$ENDIF} + + { + XPElementStyle + + Elements are individually drawable UI things like push buttons, etc. The + style defines what kind of element you are drawing. Elements can be + stretched in one or two dimensions (depending on the element). Some + elements can be lit. + + In x-plane 6 some elements must be drawn over metal. Some are scalable and + some are not. Any element can be drawn anywhere in x-plane 7. + + Scalable Axis Required Background + } +TYPE + XPElementStyle = ( + { x metal } + xpElement_TextField = 6 + + { none metal } + ,xpElement_CheckBox = 9 + + { none metal } + ,xpElement_CheckBoxLit = 10 + + { none window header } + ,xpElement_WindowCloseBox = 14 + + { none window header } + ,xpElement_WindowCloseBoxPressed = 15 + + { x metal } + ,xpElement_PushButton = 16 + + { x metal } + ,xpElement_PushButtonLit = 17 + + { none any } + ,xpElement_OilPlatform = 24 + + { none any } + ,xpElement_OilPlatformSmall = 25 + + { none any } + ,xpElement_Ship = 26 + + { none any } + ,xpElement_ILSGlideScope = 27 + + { none any } + ,xpElement_MarkerLeft = 28 + + { none any } + ,xpElement_Airport = 29 + + { none any } + ,xpElement_Waypoint = 30 + + { none any } + ,xpElement_NDB = 31 + + { none any } + ,xpElement_VOR = 32 + + { none any } + ,xpElement_RadioTower = 33 + + { none any } + ,xpElement_AircraftCarrier = 34 + + { none any } + ,xpElement_Fire = 35 + + { none any } + ,xpElement_MarkerRight = 36 + + { none any } + ,xpElement_CustomObject = 37 + + { none any } + ,xpElement_CoolingTower = 38 + + { none any } + ,xpElement_SmokeStack = 39 + + { none any } + ,xpElement_Building = 40 + + { none any } + ,xpElement_PowerLine = 41 + + { none metal } + ,xpElement_CopyButtons = 45 + + { none metal } + ,xpElement_CopyButtonsWithEditingGrid = 46 + + { x, y metal } + ,xpElement_EditingGrid = 47 + + { THIS CAN PROBABLY BE REMOVED } + ,xpElement_ScrollBar = 48 + + { none any } + ,xpElement_VORWithCompassRose = 49 + + { none metal } + ,xpElement_Zoomer = 51 + + { x, y metal } + ,xpElement_TextFieldMiddle = 52 + + { none metal } + ,xpElement_LittleDownArrow = 53 + + { none metal } + ,xpElement_LittleUpArrow = 54 + + { none metal } + ,xpElement_WindowDragBar = 61 + + { none metal } + ,xpElement_WindowDragBarSmooth = 62 + + ); + PXPElementStyle = ^XPElementStyle; + + { + XPDrawElement + + XPDrawElement draws a given element at an offset on the virtual screen in + set dimensions. EVEN if the element is not scalable, it will be scaled if + the width and height do not match the preferred dimensions; it'll just look + ugly. Pass inLit to see the lit version of the element; if the element + cannot be lit this is ignored. + } + PROCEDURE XPDrawElement( + inX1 : integer; + inY1 : integer; + inX2 : integer; + inY2 : integer; + inStyle : XPElementStyle; + inLit : integer); +{$IFDEF DELPHI} + cdecl; external 'XPWIDGETS.DLL'; +{$ELSE} + cdecl; external ''; +{$ENDIF} + + { + XPGetElementDefaultDimensions + + This routine returns the recommended or minimum dimensions of a given UI + element. outCanBeLit tells whether the element has both a lit and unlit + state. Pass NULL to not receive any of these parameters. + } + PROCEDURE XPGetElementDefaultDimensions( + inStyle : XPElementStyle; + outWidth : Pinteger; { Can be nil } + outHeight : Pinteger; { Can be nil } + outCanBeLit : Pinteger); { Can be nil } +{$IFDEF DELPHI} + cdecl; external 'XPWIDGETS.DLL'; +{$ELSE} + cdecl; external ''; +{$ENDIF} + + { + XPTrackStyle + + A track is a UI element that displays a value vertically or horizontally. + X-Plane has three kinds of tracks: scroll bars, sliders, and progress bars. + Tracks can be displayed either horizontally or vertically; tracks will + choose their own layout based on the larger dimension of their dimensions + (e.g. they know if they are tall or wide). Sliders may be lit or unlit + (showing the user manipulating them). + + ScrollBar - this is a standard scroll bar with arrows and a thumb to drag. + Slider - this is a simple track with a ball in the middle that can be + slid. Progress - this is a progress indicator showing how a long task is + going. + } +TYPE + XPTrackStyle = ( + { not over metal can be lit can be rotated } + xpTrack_ScrollBar = 0 + + { over metal can be lit can be rotated } + ,xpTrack_Slider = 1 + + { over metal cannot be lit cannot be rotated } + ,xpTrack_Progress = 2 + + ); + PXPTrackStyle = ^XPTrackStyle; + + { + XPDrawTrack + + This routine draws a track. You pass in the track dimensions and size; the + track picks the optimal orientation for these dimensions. Pass in the + track's minimum current and maximum values; the indicator will be + positioned appropriately. You can also specify whether the track is lit or + not. + } + PROCEDURE XPDrawTrack( + inX1 : integer; + inY1 : integer; + inX2 : integer; + inY2 : integer; + inMin : integer; + inMax : integer; + inValue : integer; + inTrackStyle : XPTrackStyle; + inLit : integer); +{$IFDEF DELPHI} + cdecl; external 'XPWIDGETS.DLL'; +{$ELSE} + cdecl; external ''; +{$ENDIF} + + { + XPGetTrackDefaultDimensions + + This routine returns a track's default smaller dimension; all tracks are + scalable in the larger dimension. It also returns whether a track can be + lit. + } + PROCEDURE XPGetTrackDefaultDimensions( + inStyle : XPTrackStyle; + outWidth : Pinteger; + outCanBeLit : Pinteger); +{$IFDEF DELPHI} + cdecl; external 'XPWIDGETS.DLL'; +{$ELSE} + cdecl; external ''; +{$ENDIF} + + { + XPGetTrackMetrics + + This routine returns the metrics of a track. If you want to write UI code + to manipulate a track, this routine helps you know where the mouse + locations are. For most other elements, the rectangle the element is drawn + in is enough information. However, the scrollbar drawing routine does some + automatic placement; this routine lets you know where things ended up. You + pass almost everything you would pass to the draw routine. You get out the + orientation, and other useful stuff. + + Besides orientation, you get five dimensions for the five parts of a + scrollbar, which are the down button, down area (area before the thumb), + the thumb, and the up area and button. For horizontal scrollers, the left + button decreases; for vertical scrollers, the top button decreases. + } + PROCEDURE XPGetTrackMetrics( + inX1 : integer; + inY1 : integer; + inX2 : integer; + inY2 : integer; + inMin : integer; + inMax : integer; + inValue : integer; + inTrackStyle : XPTrackStyle; + outIsVertical : Pinteger; + outDownBtnSize : Pinteger; + outDownPageSize : Pinteger; + outThumbSize : Pinteger; + outUpPageSize : Pinteger; + outUpBtnSize : Pinteger); +{$IFDEF DELPHI} + cdecl; external 'XPWIDGETS.DLL'; +{$ELSE} + cdecl; external ''; +{$ENDIF} + +IMPLEMENTATION +END. diff --git a/GermanAirlinesVA-GAConnector/XPSDK/Delphi/Widgets/XPWidgetDefs.pas b/GermanAirlinesVA-GAConnector/XPSDK/Delphi/Widgets/XPWidgetDefs.pas new file mode 100644 index 0000000..2e55830 --- /dev/null +++ b/GermanAirlinesVA-GAConnector/XPSDK/Delphi/Widgets/XPWidgetDefs.pas @@ -0,0 +1,441 @@ +{ + Copyright 2005-2012 Sandy Barbour and Ben Supnik + + All rights reserved. See license.txt for usage. + + X-Plane SDK Version: 2.1.1 +} + +UNIT XPWidgetDefs; +INTERFACE +{ + +} + +USES XPLMDefs; + {$A4} +{$IFDEF MSWINDOWS} + {$DEFINE DELPHI} +{$ENDIF} +{___________________________________________________________________________ + * WIDGET DEFINITIONS + ___________________________________________________________________________} +{ + A widget is a call-back driven screen entity like a push-button, window, + text entry field, etc. + + Use the widget API to create widgets of various classes. You can nest them + into trees of widgets to create complex user interfaces. +} + + + +TYPE + { + XPWidgetID + + A Widget ID is an opaque unique non-zero handle identifying your widget. + Use 0 to specify "no widget". This type is defined as wide enough to hold + a pointer. You receive a widget ID when you create a new widget and then + use that widget ID to further refer to the widget. + } + XPWidgetID = pointer; + PXPWidgetID = ^XPWidgetID; + + { + XPWidgetPropertyID + + Properties are values attached to instances of your widgets. A property is + identified by a 32-bit ID and its value is the width of a pointer. + + Each widget instance may have a property or not have it. When you set a + property on a widget for the first time, the property is added to the + widget; it then stays there for the life of the widget. + + Some property IDs are predefined by the widget package; you can make up + your own property IDs as well. + } + XPWidgetPropertyID = ( + { A window's refcon is an opaque value used by client code to find other data } + { based on it. } + xpProperty_Refcon = 0 + + { These properties are used by the utlities to implement dragging. } + ,xpProperty_Dragging = 1 + + ,xpProperty_DragXOff = 2 + + ,xpProperty_DragYOff = 3 + + { Is the widget hilited? (For widgets that support this kind of thing.) } + ,xpProperty_Hilited = 4 + + { Is there a C++ object attached to this widget? } + ,xpProperty_Object = 5 + + { If this property is 1, the widget package will use OpenGL to restrict } + { drawing to the Wiget's exposed rectangle. } + ,xpProperty_Clip = 6 + + { Is this widget enabled (for those that have a disabled state too)? } + ,xpProperty_Enabled = 7 + + { NOTE: Property IDs 1 - 999 are reserved for the widget's library. } + { } + { NOTE: Property IDs 1000 - 9999 are allocated to the standard widget classes } + { provided with the library Properties 1000 - 1099 are for widget class 0, } + { 1100 - 1199 for widget class 1, etc. } + ,xpProperty_UserStart = 10000 + + ); + PXPWidgetPropertyID = ^XPWidgetPropertyID; + + { + XPMouseState_t + + When the mouse is clicked or dragged, a pointer to this structure is passed + to your widget function. + } + XPMouseState_t = RECORD + x : integer; + y : integer; + { Mouse Button number, left = 0 (right button not yet supported. } + button : integer; +{$IFDEF XPLM200} + { Scroll wheel delta (button in this case would be the wheel axis number). } + delta : integer; +{$ENDIF} + END; + PXPMouseState_t = ^XPMouseState_t; + + { + XPKeyState_t + + When a key is pressed, a pointer to this struct is passed to your widget + function. + } + XPKeyState_t = RECORD + { The ASCII key that was pressed. WARNING: this may be 0 for some non-ASCII } + { key sequences. } + key : char; + { The flags. Make sure to check this if you only want key-downs! } + flags : XPLMKeyFlags; + { The virtual key code for the key } + vkey : char; + END; + PXPKeyState_t = ^XPKeyState_t; + + { + XPWidgetGeometryChange_t + + This structure contains the deltas for your widget's geometry when it + changes. + } + XPWidgetGeometryChange_t = RECORD + dx : integer; + { +Y = the widget moved up } + dy : integer; + dwidth : integer; + dheight : integer; + END; + PXPWidgetGeometryChange_t = ^XPWidgetGeometryChange_t; + + { + XPDispatchMode + + The dispatching modes describe how the widgets library sends out messages. + Currently there are three modes: + } + XPDispatchMode = ( + { The message will only be sent to the target widget. } + xpMode_Direct = 0 + + { The message is sent to the target widget, then up the chain of parents } + { until the message is handled or a parentless widget is reached. } + ,xpMode_UpChain = 1 + + { The message is sent to the target widget and then all of its children } + { recursively depth-first. } + ,xpMode_Recursive = 2 + + { The message is snet just to the target, but goes to every callback, even if } + { it is handled. } + ,xpMode_DirectAllCallbacks = 3 + + { The message is only sent to the very first handler even if it is not } + { accepted. (This is really only useful for some internal Widget Lib } + { functions. } + ,xpMode_Once = 4 + + ); + PXPDispatchMode = ^XPDispatchMode; + + { + XPWidgetClass + + Widget classes define predefined widget types. A widget class basically + specifies from a library the widget function to be used for the widget. + Most widgets can be made right from classes. + } + XPWidgetClass = integer; + PXPWidgetClass = ^XPWidgetClass; + +CONST + { An unspecified widget class. Other widget classes are in } + { XPStandardWidgets.h } + xpWidgetClass_None = 0; + +{___________________________________________________________________________ + * WIDGET MESSAGES + ___________________________________________________________________________} +{ + +} + + + { + XPWidgetMessage + + Widgets receive 32-bit messages indicating what action is to be taken or + notifications of events. The list of messages may be expanded. + } +TYPE + XPWidgetMessage = ( + { No message, should not be sent. } + xpMsg_None = 0 + + { The create message is sent once per widget that is created with your widget } + { function and once for any widget that has your widget function attached. } + { } + { Dispatching: Direct } + { } + { Param 1: 1 if you are being added as a subclass, 0 if the widget is first } + { being created. } + ,xpMsg_Create = 1 + + { The destroy message is sent once for each message that is destroyed that } + { has your widget function. } + { } + { Dispatching: Direct for all } + { } + { Param 1: 1 if being deleted by a recursive delete to the parent, 0 for } + { explicit deletion. } + ,xpMsg_Destroy = 2 + + { The paint message is sent to your widget to draw itself. The paint message } + { is the bare-bones message; in response you must draw yourself, draw your } + { children, set up clipping and culling, check for visibility, etc. If you } + { don't want to do all of this, ignore the paint message and a draw message } + { (see below) will be sent to you. } + { } + { Dispatching: Direct } + ,xpMsg_Paint = 3 + + { The draw message is sent to your widget when it is time to draw yourself. } + { OpenGL will be set up to draw in 2-d global screen coordinates, but you } + { should use the XPLM to set up OpenGL state. } + { } + { Dispatching: Direct } + ,xpMsg_Draw = 4 + + { The key press message is sent once per key that is pressed. The first } + { parameter is the type of key code (integer or char) and the second is the } + { code itself. By handling this event, you consume the key stroke. } + { } + { Handling this message 'consumes' the keystroke; not handling it passes it } + { to your parent widget. } + { } + { Dispatching: Up Chain } + { } + { : Param 1: A pointer to an XPKeyState_t structure with the keystroke. } + ,xpMsg_KeyPress = 5 + + { Keyboard focus is being given to you. By handling this message you accept } + { keyboard focus. The first parameter will be one if a child of yours gave } + { up focus to you, 0 if someone set focus on you explicitly. } + { } + { : Handling this message accepts focus; not handling refuses focus. } + { } + { Dispatching: direct } + { } + { Param 1: 1 if you are gaining focus because your child is giving it up, 0 } + { if someone is explicitly giving you focus. } + ,xpMsg_KeyTakeFocus = 6 + + { Keyboard focus is being taken away from you. The first parameter will be } + { one if you are losing focus because another widget is taking it, or 0 if } + { someone called the API to make you lose focus explicitly. } + { } + { Dispatching: Direct } + { } + { Param 1: 1 if focus is being taken by another widget, 0 if code requested } + { to remove focus. } + ,xpMsg_KeyLoseFocus = 7 + + { You receive one mousedown event per click with a mouse-state structure } + { pointed to by parameter 1, by accepting this you eat the click, otherwise } + { your parent gets it. You will not receive drag and mouse up messages if } + { you do not accept the down message. } + { } + { Handling this message consumes the mouse click, not handling it passes it } + { to the next widget. You can act 'transparent' as a window by never handling } + { moues clicks to certain areas. } + { } + { Dispatching: Up chain NOTE: Technically this is direct dispatched, but the } + { widgets library will shop it to each widget until one consumes the click, } + { making it effectively "up chain". } + { } + { Param 1: A pointer to an XPMouseState_t containing the mouse status. } + ,xpMsg_MouseDown = 8 + + { You receive a series of mouse drag messages (typically one per frame in the } + { sim) as the mouse is moved once you have accepted a mouse down message. } + { Parameter one points to a mouse-state structure describing the mouse } + { location. You will continue to receive these until the mouse button is } + { released. You may receive multiple mouse state messages with the same mouse } + { position. You will receive mouse drag events even if the mouse is dragged } + { out of your current or original bounds at the time of the mouse down. } + { } + { Dispatching: Direct } + { } + { Param 1: A pointer to an XPMouseState_t containing the mouse status. } + ,xpMsg_MouseDrag = 9 + + { The mouseup event is sent once when the mouse button is released after a } + { drag or click. You only receive this message if you accept the mouseDown } + { message. Parameter one points to a mouse state structure. } + { } + { Dispatching: Direct } + { } + { Param 1: A pointer to an XPMouseState_t containing the mouse status. } + ,xpMsg_MouseUp = 10 + + { Your geometry or a child's geometry is being changed. } + { } + { Dispatching: Up chain } + { } + { Param 1: The widget ID of the original reshaped target. } + { } + { Param 2: A pointer to a XPWidgetGeometryChange_t struct describing the } + { change. } + ,xpMsg_Reshape = 11 + + { Your exposed area has changed. } + { } + { Dispatching: Direct } + ,xpMsg_ExposedChanged = 12 + + { A child has been added to you. The child's ID is passed in parameter one. } + { } + { } + { Dispatching: Direct } + { } + { Param 1: The Widget ID of the child being added. } + ,xpMsg_AcceptChild = 13 + + { A child has been removed from to you. The child's ID is passed in } + { parameter one. } + { } + { Dispatching: Direct } + { } + { Param 1: The Widget ID of the child being removed. } + ,xpMsg_LoseChild = 14 + + { You now have a new parent, or have no parent. The parent's ID is passed } + { in, or 0 for no parent. } + { } + { Dispatching: Direct } + { } + { Param 1: The Widget ID of your parent } + ,xpMsg_AcceptParent = 15 + + { You or a child has been shown. Note that this does not include you being } + { shown because your parent was shown, you were put in a new parent, your } + { root was shown, etc. } + { } + { Dispatching: Up chain } + { } + { Param 1: The widget ID of the shown widget. } + ,xpMsg_Shown = 16 + + { You have been hidden. See limitations above. } + { } + { Dispatching: Up chain } + { } + { Param 1: The widget ID of the hidden widget. } + ,xpMsg_Hidden = 17 + + { Your descriptor has changed. } + { } + { Dispatching: Direct } + ,xpMsg_DescriptorChanged = 18 + + { A property has changed. Param 1 contains the property ID. } + { } + { Dispatching: Direct } + { } + { Param 1: The Property ID being changed. } + { } + { Param 2: The new property value } + ,xpMsg_PropertyChanged = 19 + +{$IFDEF XPLM200} + { The mouse wheel has moved. } + { } + { Return 1 to consume the mouse wheel move, or 0 to pass the message to a } + { parent. Dispatching: Up chain } + { } + { Param 1: A pointer to an XPMouseState_t containing the mouse status. } + ,xpMsg_MouseWheel = 20 +{$ENDIF} + +{$IFDEF XPLM200} + { The cursor is over your widget. If you consume this message, change the } + { XPLMCursorStatus value to indicate the desired result, with the same rules } + { as in XPLMDisplay.h. } + { } + { Return 1 to consume this message, 0 to pass it on. } + { } + { Dispatching: Up chain Param 1: A pointer to an XPMouseState_t struct } + { containing the mouse status. } + { } + { Param 2: A pointer to a XPLMCursorStatus - set this to the cursor result } + { you desire. } + ,xpMsg_CursorAdjust = 21 +{$ENDIF} + + { NOTE: Message IDs 1000 - 9999 are allocated to the standard widget classes } + { provided with the library with 1000 - 1099 for widget class 0, 1100 - 1199 } + { for widget class 1, etc. Message IDs 10,000 and beyond are for plugin use. } + ,xpMsg_UserStart = 10000 + + ); + PXPWidgetMessage = ^XPWidgetMessage; + +{___________________________________________________________________________ + * WIDGET CALLBACK FUNCTION + ___________________________________________________________________________} +{ + +} + + + { + XPWidgetFunc_t + + This function defines your custom widget's behavior. It will be called by + the widgets library to send messages to your widget. The message and + widget ID are passed in, as well as two ptr-width signed parameters whose + meaning varies with the message. Return 1 to indicate that you have + processed the message, 0 to indicate that you have not. For any message + that is not understood, return 0. + } +TYPE + XPWidgetFunc_t = FUNCTION( + inMessage : XPWidgetMessage; + inWidget : XPWidgetID; + inParam1 : intptr_t; + inParam2 : intptr_t) : integer; cdecl; + +IMPLEMENTATION +END. diff --git a/GermanAirlinesVA-GAConnector/XPSDK/Delphi/Widgets/XPWidgetUtils.pas b/GermanAirlinesVA-GAConnector/XPSDK/Delphi/Widgets/XPWidgetUtils.pas new file mode 100644 index 0000000..9dcb1d2 --- /dev/null +++ b/GermanAirlinesVA-GAConnector/XPSDK/Delphi/Widgets/XPWidgetUtils.pas @@ -0,0 +1,225 @@ +{ + Copyright 2005-2012 Sandy Barbour and Ben Supnik + + All rights reserved. See license.txt for usage. + + X-Plane SDK Version: 2.1.1 +} + +UNIT XPWidgetUtils; +INTERFACE +{ + XPWidgetUtils - USAGE NOTES + + The XPWidgetUtils library contains useful functions that make writing and + using widgets less of a pain. + + One set of functions are the widget behavior functions. These functions + each add specific useful behaviors to widgets. They can be used in two + manners: + + 1. You can add a widget behavior function to a widget as a callback proc + using the XPAddWidgetCallback function. The widget will gain that + behavior. Remember that the last function you add has highest priority. + You can use this to change or augment the behavior of an existing finished + widget. + + 2. You can call a widget function from inside your own widget function. + This allows you to include useful behaviors in custom-built widgets. A + number of the standard widgets get their behavior from this library. To do + this, call the behavior function from your function first. If it returns + 1, that means it handled the event and you don't need to; simply return 1. +} + +USES XPWidgetDefs; + {$A4} +{$IFDEF MSWINDOWS} + {$DEFINE DELPHI} +{$ENDIF} +{___________________________________________________________________________ + * GENERAL UTILITIES + ___________________________________________________________________________} +{ + +} + + + + { + XPWidgetCreate_t + + This structure contains all of the parameters needed to create a wiget. It + is used with XPUCreateWidgets to create widgets in bulk from an array. All + parameters correspond to those of XPCreateWidget except for the container + index. If the container index is equal to the index of a widget in the + array, the widget in the array passed to XPUCreateWidgets is used as the + parent of this widget. Note that if you pass an index greater than your + own position in the array, the parent you are requesting will not exist + yet. If the container index is NO_PARENT, the parent widget is specified as + NULL. If the container index is PARAM_PARENT, the widget passed into + XPUCreateWidgets is used. + } +TYPE + XPWidgetCreate_t = RECORD + left : integer; + top : integer; + right : integer; + bottom : integer; + visible : integer; + descriptor : Pchar; + isRoot : integer; + containerIndex : integer; + widgetClass : XPWidgetClass; + END; + PXPWidgetCreate_t = ^XPWidgetCreate_t; + +CONST + NO_PARENT = -1; + + PARAM_PARENT = -2; + + + { + XPUCreateWidgets + + This function creates a series of widgets from a table...see + XPCreateWidget_t above. Pass in an array of widget creation structures and + an array of widget IDs that will receive each widget. + + Widget parents are specified by index into the created widget table, + allowing you to create nested widget structures. You can create multiple + widget trees in one table. Generally you should create widget trees from + the top down. + + You can also pass in a widget ID that will be used when the widget's parent + is listed as PARAM_PARENT; this allows you to embed widgets created with + XPUCreateWidgets in a widget created previously. + } + PROCEDURE XPUCreateWidgets( + inWidgetDefs : PXPWidgetCreate_t; + inCount : integer; + inParamParent : XPWidgetID; + ioWidgets : PXPWidgetID); +{$IFDEF DELPHI} + cdecl; external 'XPWIDGETS.DLL'; +{$ELSE} + cdecl; external ''; +{$ENDIF} + + { + XPUMoveWidgetBy + + Simply moves a widget by an amount, +x = right, +y=up, without resizing the + widget. + } + PROCEDURE XPUMoveWidgetBy( + inWidget : XPWidgetID; + inDeltaX : integer; + inDeltaY : integer); +{$IFDEF DELPHI} + cdecl; external 'XPWIDGETS.DLL'; +{$ELSE} + cdecl; external ''; +{$ENDIF} + +{___________________________________________________________________________ + * LAYOUT MANAGERS + ___________________________________________________________________________} +{ + The layout managers are widget behavior functions for handling where + widgets move. Layout managers can be called from a widget function or + attached to a widget later. +} + + + + { + XPUFixedLayout + + This function causes the widget to maintain its children in fixed position + relative to itself as it is resized. Use this on the top level 'window' + widget for your window. + } + FUNCTION XPUFixedLayout( + inMessage : XPWidgetMessage; + inWidget : XPWidgetID; + inParam1 : intptr_t; + inParam2 : intptr_t) : integer; +{$IFDEF DELPHI} + cdecl; external 'XPWIDGETS.DLL'; +{$ELSE} + cdecl; external ''; +{$ENDIF} + +{___________________________________________________________________________ + * WIDGET PROC BEHAVIORS + ___________________________________________________________________________} +{ + These widget behavior functions add other useful behaviors to widgets. + These functions cannot be attached to a widget; they must be called from + your widget function. +} + + + + { + XPUSelectIfNeeded + + This causes the widget to bring its window to the foreground if it is not + already. inEatClick specifies whether clicks in the background should be + consumed by bringin the window to the foreground. + } + FUNCTION XPUSelectIfNeeded( + inMessage : XPWidgetMessage; + inWidget : XPWidgetID; + inParam1 : intptr_t; + inParam2 : intptr_t; + inEatClick : integer) : integer; +{$IFDEF DELPHI} + cdecl; external 'XPWIDGETS.DLL'; +{$ELSE} + cdecl; external ''; +{$ENDIF} + + { + XPUDefocusKeyboard + + This causes a click in the widget to send keyboard focus back to X-Plane. + This stops editing of any text fields, etc. + } + FUNCTION XPUDefocusKeyboard( + inMessage : XPWidgetMessage; + inWidget : XPWidgetID; + inParam1 : intptr_t; + inParam2 : intptr_t; + inEatClick : integer) : integer; +{$IFDEF DELPHI} + cdecl; external 'XPWIDGETS.DLL'; +{$ELSE} + cdecl; external ''; +{$ENDIF} + + { + XPUDragWidget + + XPUDragWidget drags the widget in response to mouse clicks. Pass in not + only the event, but the global coordinates of the drag region, which might + be a sub-region of your widget (for example, a title bar). + } + FUNCTION XPUDragWidget( + inMessage : XPWidgetMessage; + inWidget : XPWidgetID; + inParam1 : intptr_t; + inParam2 : intptr_t; + inLeft : integer; + inTop : integer; + inRight : integer; + inBottom : integer) : integer; +{$IFDEF DELPHI} + cdecl; external 'XPWIDGETS.DLL'; +{$ELSE} + cdecl; external ''; +{$ENDIF} + +IMPLEMENTATION +END. diff --git a/GermanAirlinesVA-GAConnector/XPSDK/Delphi/Widgets/XPWidgets.pas b/GermanAirlinesVA-GAConnector/XPSDK/Delphi/Widgets/XPWidgets.pas new file mode 100644 index 0000000..44623dc --- /dev/null +++ b/GermanAirlinesVA-GAConnector/XPSDK/Delphi/Widgets/XPWidgets.pas @@ -0,0 +1,665 @@ +{ + Copyright 2005-2012 Sandy Barbour and Ben Supnik + + All rights reserved. See license.txt for usage. + + X-Plane SDK Version: 2.1.1 +} + +UNIT XPWidgets; +INTERFACE +{ + WIDGETS - THEORY OF OPERATION AND NOTES + + Widgets are persistent view 'objects' for X-Plane. A widget is an object + referenced by its opaque handle (widget ID) and the APIs in this file. You + cannot access the widget's guts directly. Every Widget has the following + intrinsic data: + + - A bounding box defined in global screen coordinates with 0,0 in the + bottom left and +y = up, +x = right. + + - A visible box, which is the intersection of the bounding box with the + widget's parents visible box. + + - Zero or one parent widgets. (Always zero if the widget is a root widget. + + + - Zero or more child widgets. + + - Whether the widget is a root. Root widgets are the top level plugin + windows. + + - Whether the widget is visible. + + - A text string descriptor, whose meaning varies from widget to widget. + + - An arbitrary set of 32 bit integral properties defined by 32-bit integral + keys. This is how specific widgets + + store specific data. + + - A list of widget callbacks proc that implements the widgets behaviors. + + The Widgets library sends messages to widgets to request specific behaviors + or notify the widget of things. + + Widgets may have more than one callback function, in which case messages + are sent to the most recently added callback function until the message is + handled. Messages may also be sent to parents or children; see the + XPWidgetDefs.h header file for the different widget message dispatching + functions. By adding a callback function to a window you can 'subclass' + its behavior. + + A set of standard widgets are provided that serve common UI purposes. You + can also customize or implement entirely custom widgets. + + Widgets are different than other view hierarchies (most notably Win32, + which they bear a striking resemblance to) in the following ways: + + - Not all behavior can be patched. State that is managed by the XPWidgets + DLL and not by individual widgets cannot be customized. + + - All coordinates are in global screen coordinates. Coordinates are not + relative to an enclosing widget, nor are they relative to a display window. + + + - Widget messages are always dispatched synchronously, and there is no + concept of scheduling an update or a dirty region. Messages originate from + X-Plane as the sim cycle goes by. Since x-plane is constantly redrawing, + so are widgets; there is no need to mark a part of a widget as 'needing + redrawing' because redrawing happens frequently whether the widget needs it + or not. + + - Any widget may be a 'root' widget, causing it to be drawn; there is no + relationship between widget class and rootness. Root widgets are + imlemented as XPLMDisply windows. +} + +USES XPWidgetDefs; + {$A4} +{$IFDEF MSWINDOWS} + {$DEFINE DELPHI} +{$ENDIF} +{___________________________________________________________________________ + * WIDGET CREATION AND MANAGEMENT + ___________________________________________________________________________} +{ + +} + + + { + XPCreateWidget + + This function creates a new widget and returns the new widget's ID to you. + If the widget creation fails for some reason, it returns NULL. Widget + creation will fail either if you pass a bad class ID or if there is not + adequate memory. + + Input Parameters: + + - Top, left, bottom, and right in global screen coordinates defining the + widget's location on the screen. + + - inVisible is 1 if the widget should be drawn, 0 to start the widget as + hidden. + + - inDescriptor is a null terminated string that will become the widget's + descriptor. + + - inIsRoot is 1 if this is going to be a root widget, 0 if it will not be. + + - inContainer is the ID of this widget's container. It must be 0 for a + root widget. for a non-root widget, pass the widget ID of the widget to + place this widget within. If this widget is not going to start inside + another widget, pass 0; this new widget will then just be floating off in + space (and will not be drawn until it is placed in a widget. + + - inClass is the class of the widget to draw. Use one of the predefined + class-IDs to create a standard widget. + + A note on widget embedding: a widget is only called (and will be drawn, + etc.) if it is placed within a widget that will be called. Root widgets + are always called. So it is possible to have whole chains of widgets that + are simply not called. You can preconstruct widget trees and then place + them into root widgets later to activate them if you wish. + } + FUNCTION XPCreateWidget( + inLeft : integer; + inTop : integer; + inRight : integer; + inBottom : integer; + inVisible : integer; + inDescriptor : Pchar; + inIsRoot : integer; + inContainer : XPWidgetID; + inClass : XPWidgetClass) : XPWidgetID; +{$IFDEF DELPHI} + cdecl; external 'XPWIDGETS.DLL'; +{$ELSE} + cdecl; external ''; +{$ENDIF} + + { + XPCreateCustomWidget + + This function is the same as XPCreateWidget except that instead of passing + a class ID, you pass your widget callback function pointer defining the + widget. Use this function to define a custom widget. All parameters are + the same as XPCreateWidget, except that the widget class has been replaced + with the widget function. + } + FUNCTION XPCreateCustomWidget( + inLeft : integer; + inTop : integer; + inRight : integer; + inBottom : integer; + inVisible : integer; + inDescriptor : Pchar; + inIsRoot : integer; + inContainer : XPWidgetID; + inCallback : XPWidgetFunc_t) : XPWidgetID; +{$IFDEF DELPHI} + cdecl; external 'XPWIDGETS.DLL'; +{$ELSE} + cdecl; external ''; +{$ENDIF} + + { + XPDestroyWidget + + This class destroys a widget. Pass in the ID of the widget to kill. If + you pass 1 for inDestroyChilren, the widget's children will be destroyed + first, then this widget will be destroyed. (Furthermore, the widget's + children will be destroyed with the inDestroyChildren flag set to 1, so the + destruction will recurse down the widget tree.) If you pass 0 for this + flag, the child widgets will simply end up with their parent set to 0. + } + PROCEDURE XPDestroyWidget( + inWidget : XPWidgetID; + inDestroyChildren : integer); +{$IFDEF DELPHI} + cdecl; external 'XPWIDGETS.DLL'; +{$ELSE} + cdecl; external ''; +{$ENDIF} + + { + XPSendMessageToWidget + + This sends any message to a widget. You should probably not go around + simulating the predefined messages that the widgets library defines for + you. You may however define custom messages for your widgets and send them + with this method. + + This method supports several dispatching patterns; see XPDispatchMode for + more info. The function returns 1 if the message was handled, 0 if it was + not. + + For each widget that receives the message (see the dispatching modes), each + widget function from the most recently installed to the oldest one + receives the message in order until it is handled. + } + FUNCTION XPSendMessageToWidget( + inWidget : XPWidgetID; + inMessage : XPWidgetMessage; + inMode : XPDispatchMode; + inParam1 : intptr_t; + inParam2 : intptr_t) : integer; +{$IFDEF DELPHI} + cdecl; external 'XPWIDGETS.DLL'; +{$ELSE} + cdecl; external ''; +{$ENDIF} + +{___________________________________________________________________________ + * WIDGET POSITIONING AND VISIBILITY + ___________________________________________________________________________} +{ + +} + + + { + XPPlaceWidgetWithin + + This function changes which container a widget resides in. You may NOT use + this function on a root widget! inSubWidget is the widget that will be + moved. Pass a widget ID in inContainer to make inSubWidget be a child of + inContainer. It will become the last/closest widget in the container. + Pass 0 to remove the widget from any container. Any call to this other + than passing the widget ID of the old parent of the affected widget will + cause the widget to be removed from its old parent. Placing a widget within + its own parent simply makes it the last widget. + + NOTE: this routine does not reposition the sub widget in global + coordinates. If the container has layout management code, it will + reposition the subwidget for you, otherwise you must do it with + SetWidgetGeometry. + } + PROCEDURE XPPlaceWidgetWithin( + inSubWidget : XPWidgetID; + inContainer : XPWidgetID); +{$IFDEF DELPHI} + cdecl; external 'XPWIDGETS.DLL'; +{$ELSE} + cdecl; external ''; +{$ENDIF} + + { + XPCountChildWidgets + + This routine returns the number of widgets another widget contains. + } + FUNCTION XPCountChildWidgets( + inWidget : XPWidgetID) : integer; +{$IFDEF DELPHI} + cdecl; external 'XPWIDGETS.DLL'; +{$ELSE} + cdecl; external ''; +{$ENDIF} + + { + XPGetNthChildWidget + + This routine returns the widget ID of a child widget by index. Indexes are + 0 based, from 0 to one minus the number of widgets in the parent, + inclusive. If the index is invalid, 0 is returned. + } + FUNCTION XPGetNthChildWidget( + inWidget : XPWidgetID; + inIndex : integer) : XPWidgetID; +{$IFDEF DELPHI} + cdecl; external 'XPWIDGETS.DLL'; +{$ELSE} + cdecl; external ''; +{$ENDIF} + + { + XPGetParentWidget + + This routine returns the parent of a widget, or 0 if the widget has no + parent. Root widgets never have parents and therefore always return 0. + } + FUNCTION XPGetParentWidget( + inWidget : XPWidgetID) : XPWidgetID; +{$IFDEF DELPHI} + cdecl; external 'XPWIDGETS.DLL'; +{$ELSE} + cdecl; external ''; +{$ENDIF} + + { + XPShowWidget + + This routine makes a widget visible if it is not already. Note that if a + widget is not in a rooted widget hierarchy or one of its parents is not + visible, it will still not be visible to the user. + } + PROCEDURE XPShowWidget( + inWidget : XPWidgetID); +{$IFDEF DELPHI} + cdecl; external 'XPWIDGETS.DLL'; +{$ELSE} + cdecl; external ''; +{$ENDIF} + + { + XPHideWidget + + Makes a widget invisible. See XPShowWidget for considerations of when a + widget might not be visible despite its own visibility state. + } + PROCEDURE XPHideWidget( + inWidget : XPWidgetID); +{$IFDEF DELPHI} + cdecl; external 'XPWIDGETS.DLL'; +{$ELSE} + cdecl; external ''; +{$ENDIF} + + { + XPIsWidgetVisible + + This returns 1 if a widget is visible, 0 if it is not. Note that this + routine takes into consideration whether a parent is invisible. Use this + routine to tell if the user can see the widget. + } + FUNCTION XPIsWidgetVisible( + inWidget : XPWidgetID) : integer; +{$IFDEF DELPHI} + cdecl; external 'XPWIDGETS.DLL'; +{$ELSE} + cdecl; external ''; +{$ENDIF} + + { + XPFindRootWidget + + XPFindRootWidget returns the Widget ID of the root widget that contains the + passed in widget or NULL if the passed in widget is not in a rooted + hierarchy. + } + FUNCTION XPFindRootWidget( + inWidget : XPWidgetID) : XPWidgetID; +{$IFDEF DELPHI} + cdecl; external 'XPWIDGETS.DLL'; +{$ELSE} + cdecl; external ''; +{$ENDIF} + + { + XPBringRootWidgetToFront + + This routine makes the specified widget be in the front most widget + hierarchy. If this widget is a root widget, its widget hierarchy comes to + front, otherwise the widget's root is brought to the front. If this widget + is not in an active widget hiearchy (e.g. there is no root widget at the + top of the tree), this routine does nothing. + } + PROCEDURE XPBringRootWidgetToFront( + inWidget : XPWidgetID); +{$IFDEF DELPHI} + cdecl; external 'XPWIDGETS.DLL'; +{$ELSE} + cdecl; external ''; +{$ENDIF} + + { + XPIsWidgetInFront + + This routine returns true if this widget's hierarchy is the front most + hierarchy. It returns false if the widget's hierarchy is not in front, or + if the widget is not in a rooted hierarchy. + } + FUNCTION XPIsWidgetInFront( + inWidget : XPWidgetID) : integer; +{$IFDEF DELPHI} + cdecl; external 'XPWIDGETS.DLL'; +{$ELSE} + cdecl; external ''; +{$ENDIF} + + { + XPGetWidgetGeometry + + This routine returns the bounding box of a widget in global coordinates. + Pass NULL for any parameter you are not interested in. + } + PROCEDURE XPGetWidgetGeometry( + inWidget : XPWidgetID; + outLeft : Pinteger; { Can be nil } + outTop : Pinteger; { Can be nil } + outRight : Pinteger; { Can be nil } + outBottom : Pinteger); { Can be nil } +{$IFDEF DELPHI} + cdecl; external 'XPWIDGETS.DLL'; +{$ELSE} + cdecl; external ''; +{$ENDIF} + + { + XPSetWidgetGeometry + + This function changes the bounding box of a widget. + } + PROCEDURE XPSetWidgetGeometry( + inWidget : XPWidgetID; + inLeft : integer; + inTop : integer; + inRight : integer; + inBottom : integer); +{$IFDEF DELPHI} + cdecl; external 'XPWIDGETS.DLL'; +{$ELSE} + cdecl; external ''; +{$ENDIF} + + { + XPGetWidgetForLocation + + Given a widget and a location, this routine returns the widget ID of the + child of that widget that owns that location. If inRecursive is true then + this will return a child of a child of a widget as it tries to find the + deepest widget at that location. If inVisibleOnly is true, then only + visible widgets are considered, otherwise all widgets are considered. The + widget ID passed for inContainer will be returned if the location is in + that widget but not in a child widget. 0 is returned if the location is + not in the container. + + NOTE: if a widget's geometry extends outside its parents geometry, it will + not be returned by this call for mouse locations outside the parent + geometry. The parent geometry limits the child's eligibility for mouse + location. + } + FUNCTION XPGetWidgetForLocation( + inContainer : XPWidgetID; + inXOffset : integer; + inYOffset : integer; + inRecursive : integer; + inVisibleOnly : integer) : XPWidgetID; +{$IFDEF DELPHI} + cdecl; external 'XPWIDGETS.DLL'; +{$ELSE} + cdecl; external ''; +{$ENDIF} + + { + XPGetWidgetExposedGeometry + + This routine returns the bounds of the area of a widget that is completely + within its parent widgets. Since a widget's bounding box can be outside + its parent, part of its area will not be elligible for mouse clicks and + should not draw. Use XPGetWidgetGeometry to find out what area defines + your widget's shape, but use this routine to find out what area to actually + draw into. Note that the widget library does not use OpenGL clipping to + keep frame rates up, although you could use it internally. + } + PROCEDURE XPGetWidgetExposedGeometry( + inWidgetID : XPWidgetID; + outLeft : Pinteger; { Can be nil } + outTop : Pinteger; { Can be nil } + outRight : Pinteger; { Can be nil } + outBottom : Pinteger); { Can be nil } +{$IFDEF DELPHI} + cdecl; external 'XPWIDGETS.DLL'; +{$ELSE} + cdecl; external ''; +{$ENDIF} + +{___________________________________________________________________________ + * ACCESSING WIDGET DATA + ___________________________________________________________________________} +{ + +} + + + { + XPSetWidgetDescriptor + + Every widget has a descriptor, which is a text string. What the text + string is used for varies from widget to widget; for example, a push + button's text is its descriptor, a caption shows its descriptor, and a text + field's descriptor is the text being edited. In other words, the usage for + the text varies from widget to widget, but this API provides a universal + and convenient way to get at it. While not all UI widgets need their + descriptor, many do. + } + PROCEDURE XPSetWidgetDescriptor( + inWidget : XPWidgetID; + inDescriptor : Pchar); +{$IFDEF DELPHI} + cdecl; external 'XPWIDGETS.DLL'; +{$ELSE} + cdecl; external ''; +{$ENDIF} + + { + XPGetWidgetDescriptor + + This routine returns the widget's descriptor. Pass in the length of the + buffer you are going to receive the descriptor in. The descriptor will be + null terminated for you. This routine returns the length of the actual + descriptor; if you pass NULL for outDescriptor, you can get the + descriptor's length without getting its text. If the length of the + descriptor exceeds your buffer length, the buffer will not be null + terminated (this routine has 'strncpy' semantics). + } + FUNCTION XPGetWidgetDescriptor( + inWidget : XPWidgetID; + outDescriptor : Pchar; + inMaxDescLength : integer) : integer; +{$IFDEF DELPHI} + cdecl; external 'XPWIDGETS.DLL'; +{$ELSE} + cdecl; external ''; +{$ENDIF} + + { + XPSetWidgetProperty + + This function sets a widget's property. Properties are arbitrary values + associated by a widget by ID. + } + PROCEDURE XPSetWidgetProperty( + inWidget : XPWidgetID; + inProperty : XPWidgetPropertyID; + inValue : intptr_t); +{$IFDEF DELPHI} + cdecl; external 'XPWIDGETS.DLL'; +{$ELSE} + cdecl; external ''; +{$ENDIF} + + { + XPGetWidgetProperty + + This routine returns the value of a widget's property, or 0 if the property + is not defined. If you need to know whether the property is defined, pass + a pointer to an int for inExists; the existence of that property will be + returned in the int. Pass NULL for inExists if you do not need this + information. + } + FUNCTION XPGetWidgetProperty( + inWidget : XPWidgetID; + inProperty : XPWidgetPropertyID; + inExists : Pinteger) : intptr_t; { Can be nil } +{$IFDEF DELPHI} + cdecl; external 'XPWIDGETS.DLL'; +{$ELSE} + cdecl; external ''; +{$ENDIF} + +{___________________________________________________________________________ + * KEYBOARD MANAGEMENT + ___________________________________________________________________________} +{ + +} + + + { + XPSetKeyboardFocus + + XPSetKeyboardFocus controls which widget will receive keystrokes. Pass the + Widget ID of the widget to get the keys. Note that if the widget does not + care about keystrokes, they will go to the parent widget, and if no widget + cares about them, they go to X-Plane. + + If you set the keyboard focus to Widget ID 0, X-Plane gets keyboard focus. + + This routine returns the widget ID that ended up with keyboard focus, or 0 + for x-plane. + + Keyboard focus is not changed if the new widget will not accept it. For + setting to x-plane, keyboard focus is always accepted. + + } + FUNCTION XPSetKeyboardFocus( + inWidget : XPWidgetID) : XPWidgetID; +{$IFDEF DELPHI} + cdecl; external 'XPWIDGETS.DLL'; +{$ELSE} + cdecl; external ''; +{$ENDIF} + + { + XPLoseKeyboardFocus + + This causes the specified widget to lose focus; focus is passed to its + parent, or the next parent that will accept it. This routine does nothing + if this widget does not have focus. + } + PROCEDURE XPLoseKeyboardFocus( + inWidget : XPWidgetID); +{$IFDEF DELPHI} + cdecl; external 'XPWIDGETS.DLL'; +{$ELSE} + cdecl; external ''; +{$ENDIF} + + { + XPGetWidgetWithFocus + + This routine returns the widget that has keyboard focus, or 0 if X-Plane + has keyboard focus or some other plugin window that does not have widgets + has focus. + } + FUNCTION XPGetWidgetWithFocus: XPWidgetID; +{$IFDEF DELPHI} + cdecl; external 'XPWIDGETS.DLL'; +{$ELSE} + cdecl; external ''; +{$ENDIF} + +{___________________________________________________________________________ + * CREATING CUSTOM WIDGETS + ___________________________________________________________________________} +{ + +} + + + { + XPAddWidgetCallback + + This function adds a new widget callback to a widget. This widget callback + supercedes any existing ones and will receive messages first; if it does + not handle messages they will go on to be handled by pre-existing widgets. + + The widget function will remain on the widget for the life of the widget. + The creation message will be sent to the new callback immediately with the + widget ID, and the destruction message will be sent before the other widget + function receives a destruction message. + + This provides a way to 'subclass' an existing widget. By providing a + second hook that only handles certain widget messages, you can customize or + extend widget behavior. + } + PROCEDURE XPAddWidgetCallback( + inWidget : XPWidgetID; + inNewCallback : XPWidgetFunc_t); +{$IFDEF DELPHI} + cdecl; external 'XPWIDGETS.DLL'; +{$ELSE} + cdecl; external ''; +{$ENDIF} + + { + XPGetWidgetClassFunc + + Given a widget class, this function returns the callbacks that power that + widget class. + } + FUNCTION XPGetWidgetClassFunc( + inWidgetClass : XPWidgetClass) : XPWidgetFunc_t; +{$IFDEF DELPHI} + cdecl; external 'XPWIDGETS.DLL'; +{$ELSE} + cdecl; external ''; +{$ENDIF} + +IMPLEMENTATION +END. diff --git a/GermanAirlinesVA-GAConnector/XPSDK/Delphi/XPLM/XPLMCamera.pas b/GermanAirlinesVA-GAConnector/XPSDK/Delphi/XPLM/XPLMCamera.pas new file mode 100644 index 0000000..44b121c --- /dev/null +++ b/GermanAirlinesVA-GAConnector/XPSDK/Delphi/XPLM/XPLMCamera.pas @@ -0,0 +1,174 @@ +{ + Copyright 2005-2012 Sandy Barbour and Ben Supnik + + All rights reserved. See license.txt for usage. + + X-Plane SDK Version: 2.1.1 +} + +UNIT XPLMCamera; +INTERFACE +{ + XPLMCamera - THEORY OF OPERATION The XPLMCamera APIs allow plug-ins to + control the camera angle in X-Plane. This has a number of applications, + including but not limited to: + + - Creating new views (including dynamic/user-controllable views) for the + user. + + - Creating applications that use X-Plane as a renderer of scenery, + aircrafts, or both. + + The camera is controlled via six parameters: a location in OpenGL + coordinates and pitch, roll and yaw, similar to an airplane's position. + OpenGL coordinate info is described in detail in the XPLMGraphics + documentation; generally you should use the XPLMGraphics routines to + convert from world to local coordinates. The camera's orientation starts + facing level with the ground directly up the negative-Z axis + (approximately north) with the horizon horizontal. It is then rotated + clockwise for yaw, pitched up for positive pitch, and rolled clockwise + around the vector it is looking along for roll. + + You control the camera either either until the user selects a new view or + permanently (the later being similar to how UDP camera control works). You + control the camera by registering a callback per frame from which you + calculate the new camera positions. This guarantees smooth camera motion. + + Use the XPLMDataAccess APIs to get information like the position of the + aircraft, etc. for complex camera positioning. +} + +USES XPLMDefs; + {$A4} +{$IFDEF MSWINDOWS} + {$DEFINE DELPHI} +{$ENDIF} +{___________________________________________________________________________ + * CAMERA CONTROL + ___________________________________________________________________________} +{ + +} + + + { + XPLMCameraControlDuration + + This enumeration states how long you want to retain control of the camera. + You can retain it indefinitely or until the user selects a new view. + } +TYPE + XPLMCameraControlDuration = ( + { Control the camera until the user picks a new view. } + xplm_ControlCameraUntilViewChanges = 1 + + { Control the camera until your plugin is disabled or another plugin forcably } + { takes control. } + ,xplm_ControlCameraForever = 2 + + ); + PXPLMCameraControlDuration = ^XPLMCameraControlDuration; + + { + XPLMCameraPosition_t + + This structure contains a full specification of the camera. X, Y, and Z + are the camera's position in OpenGL coordiantes; pitch, roll, and yaw are + rotations from a camera facing flat north in degrees. Positive pitch means + nose up, positive roll means roll right, and positive yaw means yaw right, + all in degrees. Zoom is a zoom factor, with 1.0 meaning normal zoom and 2.0 + magnifying by 2x (objects appear larger). + } + XPLMCameraPosition_t = RECORD + x : single; + y : single; + z : single; + pitch : single; + heading : single; + roll : single; + zoom : single; + END; + PXPLMCameraPosition_t = ^XPLMCameraPosition_t; + + { + XPLMCameraControl_f + + You use an XPLMCameraControl function to provide continuous control over + the camera. You are passed in a structure in which to put the new camera + position; modify it and return 1 to reposition the camera. Return 0 to + surrender control of the camera; camera control will be handled by X-Plane + on this draw loop. The contents of the structure as you are called are + undefined. + + If X-Plane is taking camera control away from you, this function will be + called with inIsLosingControl set to 1 and ioCameraPosition NULL. + } + XPLMCameraControl_f = FUNCTION( + outCameraPosition : PXPLMCameraPosition_t; { Can be nil } + inIsLosingControl : integer; + inRefcon : pointer) : integer; cdecl; + + { + XPLMControlCamera + + This function repositions the camera on the next drawing cycle. You must + pass a non-null control function. Specify in inHowLong how long you'd like + control (indefinitely or until a key is pressed). + } + PROCEDURE XPLMControlCamera( + inHowLong : XPLMCameraControlDuration; + inControlFunc : XPLMCameraControl_f; + inRefcon : pointer); +{$IFDEF DELPHI} + cdecl; external 'XPLM.DLL'; +{$ELSE} + cdecl; external ''; +{$ENDIF} + + { + XPLMDontControlCamera + + This function stops you from controlling the camera. If you have a camera + control function, it will not be called with an inIsLosingControl flag. + X-Plane will control the camera on the next cycle. + + For maximum compatibility you should not use this routine unless you are in + posession of the camera. + } + PROCEDURE XPLMDontControlCamera; +{$IFDEF DELPHI} + cdecl; external 'XPLM.DLL'; +{$ELSE} + cdecl; external ''; +{$ENDIF} + + { + XPLMIsCameraBeingControlled + + This routine returns 1 if the camera is being controlled, zero if it is + not. If it is and you pass in a pointer to a camera control duration, the + current control duration will be returned. + } + FUNCTION XPLMIsCameraBeingControlled( + outCameraControlDuration: PXPLMCameraControlDuration) : integer; { Can be nil } +{$IFDEF DELPHI} + cdecl; external 'XPLM.DLL'; +{$ELSE} + cdecl; external ''; +{$ENDIF} + + { + XPLMReadCameraPosition + + This function reads the current camera position. + } + PROCEDURE XPLMReadCameraPosition( + outCameraPosition : PXPLMCameraPosition_t); +{$IFDEF DELPHI} + cdecl; external 'XPLM.DLL'; +{$ELSE} + cdecl; external ''; +{$ENDIF} + +IMPLEMENTATION +END. diff --git a/GermanAirlinesVA-GAConnector/XPSDK/Delphi/XPLM/XPLMDataAccess.pas b/GermanAirlinesVA-GAConnector/XPSDK/Delphi/XPLM/XPLMDataAccess.pas new file mode 100644 index 0000000..e82ded4 --- /dev/null +++ b/GermanAirlinesVA-GAConnector/XPSDK/Delphi/XPLM/XPLMDataAccess.pas @@ -0,0 +1,764 @@ +{ + Copyright 2005-2012 Sandy Barbour and Ben Supnik + + All rights reserved. See license.txt for usage. + + X-Plane SDK Version: 2.1.1 +} + +UNIT XPLMDataAccess; +INTERFACE +{ + XPLM Data Access API - Theory of Operation + + The data access API gives you a generic, flexible, high performance way to + read and write data to and from X-Plane and other plug-ins. For example, + this API allows you to read and set the nav radios, get the plane location, + determine the current effective graphics frame rate, etc. + + The data access APIs are the way that you read and write data from the sim + as well as other plugins. + + The API works using opaque data references. A data reference is a source + of data; you do not know where it comes from, but once you have it you can + read the data quickly and possibly write it. To get a data reference, you + look it up. + + Data references are identified by verbose string names + (sim/cockpit/radios/nav1_freq_hz). The actual numeric value of the data + reference is implementation defined and is likely to change each time the + simulator is run (or the plugin that provides the datareference is + reloaded). + + The task of looking up a data reference is relatively expensive; look up + your data references once based on verbose strings, and save the opaque + data reference value for the duration of your plugin's operation. Reading + and writing data references is relatively fast (the cost is equivalent to + two function calls through function pointers). + + This allows data access to be high performance, while leaving in + abstraction; since data references are opaque and are searched for, the + underlying data access system can be rebuilt. + + A note on typing: you must know the correct data type to read and write. + APIs are provided for reading and writing data in a number of ways. You + can also double check the data type for a data ref. Note that automatic + conversion is not done for you. + + A note for plugins sharing data with other plugins: the load order of + plugins is not guaranteed. To make sure that every plugin publishing data + has published their data references before other plugins try to subscribe, + publish your data references in your start routine but resolve them the + first time your 'enable' routine is called, or the first time they are + needed in code. + + X-Plane publishes well over 1000 datarefs; a complete list may be found in + the reference section of the SDK online documentation (from the SDK home + page, choose Documentation). +} + +USES XPLMDefs; + {$A4} +{$IFDEF MSWINDOWS} + {$DEFINE DELPHI} +{$ENDIF} +{___________________________________________________________________________ + * READING AND WRITING DATA + ___________________________________________________________________________} +{ + These routines allow you to access a wide variety of data from within + x-plane and modify some of it. +} + + + +TYPE + { + XPLMDataRef + + A data ref is an opaque handle to data provided by the simulator or another + plugin. It uniquely identifies one variable (or array of variables) over + the lifetime of your plugin. You never hard code these values; you always + get them from XPLMFindDataRef. + } + XPLMDataRef = pointer; + PXPLMDataRef = ^XPLMDataRef; + + { + XPLMDataTypeID + + This is an enumeration that defines the type of the data behind a data + reference. This allows you to sanity check that the data type matches what + you expect. But for the most part, you will know the type of data you are + expecting from the online documentation. + + Data types each take a bit field, so sets of data types may be formed. + } + XPLMDataTypeID = ( + { Data of a type the current XPLM doesn't do. } + xplmType_Unknown = 0 + + { A single 4-byte integer, native endian. } + ,xplmType_Int = 1 + + { A single 4-byte float, native endian. } + ,xplmType_Float = 2 + + { A single 8-byte double, native endian. } + ,xplmType_Double = 4 + + { An array of 4-byte floats, native endian. } + ,xplmType_FloatArray = 8 + + { An array of 4-byte integers, native endian. } + ,xplmType_IntArray = 16 + + { A variable block of data. } + ,xplmType_Data = 32 + + ); + PXPLMDataTypeID = ^XPLMDataTypeID; + + { + XPLMFindDataRef + + Given a c-style string that names the data ref, this routine looks up the + actual opaque XPLMDataRef that you use to read and write the data. The + string names for datarefs are published on the x-plane SDK web site. + + This function returns NULL if the data ref cannot be found. + + NOTE: this function is relatively expensive; save the XPLMDataRef this + function returns for future use. Do not look up your data ref by string + every time you need to read or write it. + } + FUNCTION XPLMFindDataRef( + inDataRefName : Pchar) : XPLMDataRef; +{$IFDEF DELPHI} + cdecl; external 'XPLM.DLL'; +{$ELSE} + cdecl; external ''; +{$ENDIF} + + { + XPLMCanWriteDataRef + + Given a data ref, this routine returns true if you can successfully set + the data, false otherwise. Some datarefs are read-only. + } + FUNCTION XPLMCanWriteDataRef( + inDataRef : XPLMDataRef) : integer; +{$IFDEF DELPHI} + cdecl; external 'XPLM.DLL'; +{$ELSE} + cdecl; external ''; +{$ENDIF} + + { + XPLMIsDataRefGood + + WARNING: This function is deprecated and should not be used. Datarefs are + valid until plugins are reloaded or the sim quits. Plugins sharing + datarefs should support these semantics by not unregistering datarefs + during operation. (You should however unregister datarefs when your plugin + is unloaded, as part of general resource cleanup.) + + This function returns whether a data ref is still valid. If it returns + false, you should refind the data ref from its original string. Calling an + accessor function on a bad data ref will return a default value, typically + 0 or 0-length data. + } + FUNCTION XPLMIsDataRefGood( + inDataRef : XPLMDataRef) : integer; +{$IFDEF DELPHI} + cdecl; external 'XPLM.DLL'; +{$ELSE} + cdecl; external ''; +{$ENDIF} + + { + XPLMGetDataRefTypes + + This routine returns the types of the data ref for accessor use. If a data + ref is available in multiple data types, they will all be returned. + } + FUNCTION XPLMGetDataRefTypes( + inDataRef : XPLMDataRef) : XPLMDataTypeID; +{$IFDEF DELPHI} + cdecl; external 'XPLM.DLL'; +{$ELSE} + cdecl; external ''; +{$ENDIF} + +{___________________________________________________________________________ + * DATA ACCESSORS + ___________________________________________________________________________} +{ + These routines read and write the data references. For each supported data + type there is a reader and a writer. + + If the data ref is invalid or the plugin that provides it is disabled or + there is a type mismatch, the functions that read data will return 0 as a + default value or not modify the passed in memory. The plugins that write + data will not write under these circumstances or if the data ref is + read-only. NOTE: to keep the overhead of reading datarefs low, these + routines do not do full validation of a dataref; passing a junk value for + a dataref can result in crashing the sim. + + For array-style datarefs, you specify the number of items to read/write and + the offset into the array; the actual number of items read or written is + returned. This may be less to prevent an array-out-of-bounds error. +} + + + + { + XPLMGetDatai + + Read an integer data ref and return its value. The return value is the + dataref value or 0 if the dataref is invalid/NULL or the plugin is + disabled. + } + FUNCTION XPLMGetDatai( + inDataRef : XPLMDataRef) : integer; +{$IFDEF DELPHI} + cdecl; external 'XPLM.DLL'; +{$ELSE} + cdecl; external ''; +{$ENDIF} + + { + XPLMSetDatai + + Write a new value to an integer data ref. This routine is a no-op if the + plugin publishing the dataref is disabled, the dataref is invalid, or the + dataref is not writable. + } + PROCEDURE XPLMSetDatai( + inDataRef : XPLMDataRef; + inValue : integer); +{$IFDEF DELPHI} + cdecl; external 'XPLM.DLL'; +{$ELSE} + cdecl; external ''; +{$ENDIF} + + { + XPLMGetDataf + + Read a single precision floating point dataref and return its value. The + return value is the dataref value or 0.0 if the dataref is invalid/NULL or + the plugin is disabled. + } + FUNCTION XPLMGetDataf( + inDataRef : XPLMDataRef) : single; +{$IFDEF DELPHI} + cdecl; external 'XPLM.DLL'; +{$ELSE} + cdecl; external ''; +{$ENDIF} + + { + XPLMSetDataf + + Write a new value to a single precision floating point data ref. This + routine is a no-op if the plugin publishing the dataref is disabled, the + dataref is invalid, or the dataref is not writable. + } + PROCEDURE XPLMSetDataf( + inDataRef : XPLMDataRef; + inValue : single); +{$IFDEF DELPHI} + cdecl; external 'XPLM.DLL'; +{$ELSE} + cdecl; external ''; +{$ENDIF} + + { + XPLMGetDatad + + Read a double precision floating point dataref and return its value. The + return value is the dataref value or 0.0 if the dataref is invalid/NULL or + the plugin is disabled. + } + FUNCTION XPLMGetDatad( + inDataRef : XPLMDataRef) : real; +{$IFDEF DELPHI} + cdecl; external 'XPLM.DLL'; +{$ELSE} + cdecl; external ''; +{$ENDIF} + + { + XPLMSetDatad + + Write a new value to a double precision floating point data ref. This + routine is a no-op if the plugin publishing the dataref is disabled, the + dataref is invalid, or the dataref is not writable. + } + PROCEDURE XPLMSetDatad( + inDataRef : XPLMDataRef; + inValue : real); +{$IFDEF DELPHI} + cdecl; external 'XPLM.DLL'; +{$ELSE} + cdecl; external ''; +{$ENDIF} + + { + XPLMGetDatavi + + Read a part of an integer array dataref. If you pass NULL for outVaules, + the routine will return the size of the array, ignoring inOffset and inMax. + + + If outValues is not NULL, then up to inMax values are copied from the + dataref into outValues, starting at inOffset in the dataref. If inMax + + inOffset is larger than the size of the dataref, less than inMax values + will be copied. The number of values copied is returned. + + Note: the semantics of array datarefs are entirely implemented by the + plugin (or X-Plane) that provides the dataref, not the SDK itself; the + above description is how these datarefs are intended to work, but a rogue + plugin may have different behavior. + } + FUNCTION XPLMGetDatavi( + inDataRef : XPLMDataRef; + outValues : Pinteger; { Can be nil } + inOffset : integer; + inMax : integer) : integer; +{$IFDEF DELPHI} + cdecl; external 'XPLM.DLL'; +{$ELSE} + cdecl; external ''; +{$ENDIF} + + { + XPLMSetDatavi + + Write part or all of an integer array dataref. The values passed by + inValues are written into the dataref starting at inOffset. Up to inCount + values are written; however if the values would write "off the end" of the + dataref array, then fewer values are written. + + Note: the semantics of array datarefs are entirely implemented by the + plugin (or X-Plane) that provides the dataref, not the SDK itself; the + above description is how these datarefs are intended to work, but a rogue + plugin may have different behavior. + } + PROCEDURE XPLMSetDatavi( + inDataRef : XPLMDataRef; + inValues : Pinteger; + inoffset : integer; + inCount : integer); +{$IFDEF DELPHI} + cdecl; external 'XPLM.DLL'; +{$ELSE} + cdecl; external ''; +{$ENDIF} + + { + XPLMGetDatavf + + Read a part of a single precision floating point array dataref. If you + pass NULL for outVaules, the routine will return the size of the array, + ignoring inOffset and inMax. + + If outValues is not NULL, then up to inMax values are copied from the + dataref into outValues, starting at inOffset in the dataref. If inMax + + inOffset is larger than the size of the dataref, less than inMax values + will be copied. The number of values copied is returned. + + Note: the semantics of array datarefs are entirely implemented by the + plugin (or X-Plane) that provides the dataref, not the SDK itself; the + above description is how these datarefs are intended to work, but a rogue + plugin may have different behavior. + } + FUNCTION XPLMGetDatavf( + inDataRef : XPLMDataRef; + outValues : Psingle; { Can be nil } + inOffset : integer; + inMax : integer) : integer; +{$IFDEF DELPHI} + cdecl; external 'XPLM.DLL'; +{$ELSE} + cdecl; external ''; +{$ENDIF} + + { + XPLMSetDatavf + + Write part or all of a single precision floating point array dataref. The + values passed by inValues are written into the dataref starting at + inOffset. Up to inCount values are written; however if the values would + write "off the end" of the dataref array, then fewer values are written. + + Note: the semantics of array datarefs are entirely implemented by the + plugin (or X-Plane) that provides the dataref, not the SDK itself; the + above description is how these datarefs are intended to work, but a rogue + plugin may have different behavior. + } + PROCEDURE XPLMSetDatavf( + inDataRef : XPLMDataRef; + inValues : Psingle; + inoffset : integer; + inCount : integer); +{$IFDEF DELPHI} + cdecl; external 'XPLM.DLL'; +{$ELSE} + cdecl; external ''; +{$ENDIF} + + { + XPLMGetDatab + + Read a part of a byte array dataref. If you pass NULL for outVaules, the + routine will return the size of the array, ignoring inOffset and inMax. + + If outValues is not NULL, then up to inMax values are copied from the + dataref into outValues, starting at inOffset in the dataref. If inMax + + inOffset is larger than the size of the dataref, less than inMax values + will be copied. The number of values copied is returned. + + Note: the semantics of array datarefs are entirely implemented by the + plugin (or X-Plane) that provides the dataref, not the SDK itself; the + above description is how these datarefs are intended to work, but a rogue + plugin may have different behavior. + } + FUNCTION XPLMGetDatab( + inDataRef : XPLMDataRef; + outValue : pointer; { Can be nil } + inOffset : integer; + inMaxBytes : integer) : integer; +{$IFDEF DELPHI} + cdecl; external 'XPLM.DLL'; +{$ELSE} + cdecl; external ''; +{$ENDIF} + + { + XPLMSetDatab + + Write part or all of a byte array dataref. The values passed by inValues + are written into the dataref starting at inOffset. Up to inCount values + are written; however if the values would write "off the end" of the dataref + array, then fewer values are written. + + Note: the semantics of array datarefs are entirely implemented by the + plugin (or X-Plane) that provides the dataref, not the SDK itself; the + above description is how these datarefs are intended to work, but a rogue + plugin may have different behavior. + } + PROCEDURE XPLMSetDatab( + inDataRef : XPLMDataRef; + inValue : pointer; + inOffset : integer; + inLength : integer); +{$IFDEF DELPHI} + cdecl; external 'XPLM.DLL'; +{$ELSE} + cdecl; external ''; +{$ENDIF} + +{___________________________________________________________________________ + * PUBLISHING YOUR PLUGINS DATA + ___________________________________________________________________________} +{ + These functions allow you to create data references that other plug-ins can + access via the above data access APIs. Data references published by other + plugins operate the same as ones published by x-plane in all manners except + that your data reference will not be available to other plugins if/when + your plugin is disabled. + + You share data by registering data provider callback functions. When a + plug-in requests your data, these callbacks are then called. You provide + one callback to return the value when a plugin 'reads' it and another to + change the value when a plugin 'writes' it. + + Important: you must pick a prefix for your datarefs other than "sim/" - + this prefix is reserved for X-Plane. The X-Plane SDK website contains a + registry where authors can select a unique first word for dataref names, to + prevent dataref collisions between plugins. +} + + + + { + XPLMGetDatai_f + + Data provider function pointers. + + These define the function pointers you provide to get or set data. Note + that you are passed a generic pointer for each one. This is the same + pointer you pass in your register routine; you can use it to find global + variables, etc. + + The semantics of your callbacks are the same as the dataref accessor above + - basically routines like XPLMGetDatai are just pass-throughs from a caller + to your plugin. Be particularly mindful in implementing array dataref + read-write accessors; you are responsible for avoiding overruns, supporting + offset read/writes, and handling a read with a NULL buffer. + } +TYPE + XPLMGetDatai_f = FUNCTION( + inRefcon : pointer) : integer; cdecl; + + { + XPLMSetDatai_f + + } + XPLMSetDatai_f = PROCEDURE( + inRefcon : pointer; + inValue : integer); cdecl; + + { + XPLMGetDataf_f + + } + XPLMGetDataf_f = FUNCTION( + inRefcon : pointer) : single; cdecl; + + { + XPLMSetDataf_f + + } + XPLMSetDataf_f = PROCEDURE( + inRefcon : pointer; + inValue : single); cdecl; + + { + XPLMGetDatad_f + + } + XPLMGetDatad_f = FUNCTION( + inRefcon : pointer) : real; cdecl; + + { + XPLMSetDatad_f + + } + XPLMSetDatad_f = PROCEDURE( + inRefcon : pointer; + inValue : real); cdecl; + + { + XPLMGetDatavi_f + + } + XPLMGetDatavi_f = FUNCTION( + inRefcon : pointer; + outValues : Pinteger; { Can be nil } + inOffset : integer; + inMax : integer) : integer; cdecl; + + { + XPLMSetDatavi_f + + } + XPLMSetDatavi_f = PROCEDURE( + inRefcon : pointer; + inValues : Pinteger; + inOffset : integer; + inCount : integer); cdecl; + + { + XPLMGetDatavf_f + + } + XPLMGetDatavf_f = FUNCTION( + inRefcon : pointer; + outValues : Psingle; { Can be nil } + inOffset : integer; + inMax : integer) : integer; cdecl; + + { + XPLMSetDatavf_f + + } + XPLMSetDatavf_f = PROCEDURE( + inRefcon : pointer; + inValues : Psingle; + inOffset : integer; + inCount : integer); cdecl; + + { + XPLMGetDatab_f + + } + XPLMGetDatab_f = FUNCTION( + inRefcon : pointer; + outValue : pointer; { Can be nil } + inOffset : integer; + inMaxLength : integer) : integer; cdecl; + + { + XPLMSetDatab_f + + } + XPLMSetDatab_f = PROCEDURE( + inRefcon : pointer; + inValue : pointer; + inOffset : integer; + inLength : integer); cdecl; + + { + XPLMRegisterDataAccessor + + This routine creates a new item of data that can be read and written. Pass + in the data's full name for searching, the type(s) of the data for + accessing, and whether the data can be written to. For each data type you + support, pass in a read accessor function and a write accessor function if + necessary. Pass NULL for data types you do not support or write accessors + if you are read-only. + + You are returned a data ref for the new item of data created. You can use + this data ref to unregister your data later or read or write from it. + } + FUNCTION XPLMRegisterDataAccessor( + inDataName : Pchar; + inDataType : XPLMDataTypeID; + inIsWritable : integer; + inReadInt : XPLMGetDatai_f; + inWriteInt : XPLMSetDatai_f; + inReadFloat : XPLMGetDataf_f; + inWriteFloat : XPLMSetDataf_f; + inReadDouble : XPLMGetDatad_f; + inWriteDouble : XPLMSetDatad_f; + inReadIntArray : XPLMGetDatavi_f; + inWriteIntArray : XPLMSetDatavi_f; + inReadFloatArray : XPLMGetDatavf_f; + inWriteFloatArray : XPLMSetDatavf_f; + inReadData : XPLMGetDatab_f; + inWriteData : XPLMSetDatab_f; + inReadRefcon : pointer; + inWriteRefcon : pointer) : XPLMDataRef; +{$IFDEF DELPHI} + cdecl; external 'XPLM.DLL'; +{$ELSE} + cdecl; external ''; +{$ENDIF} + + { + XPLMUnregisterDataAccessor + + Use this routine to unregister any data accessors you may have registered. + You unregister a data ref by the XPLMDataRef you get back from + registration. Once you unregister a data ref, your function pointer will + not be called anymore. + + For maximum compatibility, do not unregister your data accessors until + final shutdown (when your XPluginStop routine is called). This allows + other plugins to find your data reference once and use it for their entire + time of operation. + } + PROCEDURE XPLMUnregisterDataAccessor( + inDataRef : XPLMDataRef); +{$IFDEF DELPHI} + cdecl; external 'XPLM.DLL'; +{$ELSE} + cdecl; external ''; +{$ENDIF} + +{___________________________________________________________________________ + * SHARING DATA BETWEEN MULTIPLE PLUGINS + ___________________________________________________________________________} +{ + The data reference registration APIs from the previous section allow a + plugin to publish data in a one-owner manner; the plugin that publishes the + data reference owns the real memory that the data ref uses. This is + satisfactory for most cases, but there are also cases where plugnis need to + share actual data. + + With a shared data reference, no one plugin owns the actual memory for the + data reference; the plugin SDK allocates that for you. When the first + plugin asks to 'share' the data, the memory is allocated. When the data is + changed, every plugin that is sharing the data is notified. + + Shared data references differ from the 'owned' data references from the + previous section in a few ways: + + - With shared data references, any plugin can create the data reference; + with owned plugins one plugin must create the data reference and others + subscribe. (This can be a problem if you don't know which set of plugins + will be present). + + - With shared data references, every plugin that is sharing the data is + notified when the data is changed. With owned data references, only the + one owner is notified when the data is changed. + + - With shared data references, you cannot access the physical memory of the + data reference; you must use the XPLMGet... and XPLMSet... APIs. With an + owned data reference, the one owning data reference can manipulate the + data reference's memory in any way it sees fit. + + Shared data references solve two problems: if you need to have a data + reference used by several plugins but do not know which plugins will be + installed, or if all plugins sharing data need to be notified when that + data is changed, use shared data references. +} + + + + { + XPLMDataChanged_f + + An XPLMDataChanged_f is a callback that the XPLM calls whenever any other + plug-in modifies shared data. A refcon you provide is passed back to help + identify which data is being changed. In response, you may want to call one + of the XPLMGetDataxxx routines to find the new value of the data. + } +TYPE + XPLMDataChanged_f = PROCEDURE( + inRefcon : pointer); cdecl; + + { + XPLMShareData + + This routine connects a plug-in to shared data, creating the shared data if + necessary. inDataName is a standard path for the data ref, and inDataType + specifies the type. This function will create the data if it does not + exist. If the data already exists but the type does not match, an error is + returned, so it is important that plug-in authors collaborate to establish + public standards for shared data. + + If a notificationFunc is passed in and is not NULL, that notification + function will be called whenever the data is modified. The notification + refcon will be passed to it. This allows your plug-in to know which shared + data was changed if multiple shared data are handled by one callback, or if + the plug-in does not use global variables. + + A one is returned for successfully creating or finding the shared data; a + zero if the data already exists but is of the wrong type. + } + FUNCTION XPLMShareData( + inDataName : Pchar; + inDataType : XPLMDataTypeID; + inNotificationFunc : XPLMDataChanged_f; + inNotificationRefcon: pointer) : integer; +{$IFDEF DELPHI} + cdecl; external 'XPLM.DLL'; +{$ELSE} + cdecl; external ''; +{$ENDIF} + + { + XPLMUnshareData + + This routine removes your notification function for shared data. Call it + when done with the data to stop receiving change notifications. Arguments + must match XPLMShareData. The actual memory will not necessarily be freed, + since other plug-ins could be using it. + } + FUNCTION XPLMUnshareData( + inDataName : Pchar; + inDataType : XPLMDataTypeID; + inNotificationFunc : XPLMDataChanged_f; + inNotificationRefcon: pointer) : integer; +{$IFDEF DELPHI} + cdecl; external 'XPLM.DLL'; +{$ELSE} + cdecl; external ''; +{$ENDIF} + +IMPLEMENTATION +END. diff --git a/GermanAirlinesVA-GAConnector/XPSDK/Delphi/XPLM/XPLMDefs.pas b/GermanAirlinesVA-GAConnector/XPSDK/Delphi/XPLM/XPLMDefs.pas new file mode 100644 index 0000000..57ffba1 --- /dev/null +++ b/GermanAirlinesVA-GAConnector/XPSDK/Delphi/XPLM/XPLMDefs.pas @@ -0,0 +1,446 @@ +{ + Copyright 2005-2012 Sandy Barbour and Ben Supnik + + All rights reserved. See license.txt for usage. + + X-Plane SDK Version: 2.1.1 +} + +UNIT XPLMDefs; +INTERFACE +{ + This file is contains the cross-platform and basic definitions for the + X-Plane SDK. + + The preprocessor macros APL and IBM must be defined to specify the + compilation target; define APL to 1 and IBM 0 to compile on Macintosh and + APL to 0 and IBM to 1 for Windows. You must specify these macro definitions + before including XPLMDefs.h or any other XPLM headers. You can do this + using the -D command line option or a preprocessor header. +} + + {$A4} +{$IFDEF MSWINDOWS} + {$DEFINE DELPHI} +{$ENDIF} +{$IFDEF LINUX} + {$DEFINE KYLIX} +{$ENDIF} +TYPE +{$IFNDEF DELPHI} +{$IFNDEF KYLIX} + Pchar = ^char; + Ppchar = ^Pchar; + Psingle = ^single; + Pinteger = ^integer; +{$ENDIF} +{$ENDIF} + Preal = ^real; + Plongint = ^longint; +{___________________________________________________________________________ + * DLL Definitions + ___________________________________________________________________________} +{ + These definitions control the importing and exporting of functions within + the DLL. + + You can prefix your five required callbacks with the PLUGIN_API macro to + declare them as exported C functions. The XPLM_API macro identifies + functions that are provided to you via the plugin SDK. (Link against + XPLM.lib to use these functions.) +} + + + + +{___________________________________________________________________________ + * GLOBAL DEFINITIONS + ___________________________________________________________________________} +{ + These definitions are used in all parts of the SDK. +} + + + +TYPE + { + XPLMPluginID + + Each plug-in is identified by a unique integer ID. This ID can be used to + disable or enable a plug-in, or discover what plug-in is 'running' at the + time. A plug-in ID is unique within the currently running instance of + X-Plane unless plug-ins are reloaded. Plug-ins may receive a different + unique ID each time they are loaded. + + For persistent identification of plug-ins, use XPLMFindPluginBySignature in + XPLMUtiltiies.h + + -1 indicates no plug-in. + } + XPLMPluginID = integer; + PXPLMPluginID = ^XPLMPluginID; + +CONST + { No plugin. } + XPLM_NO_PLUGIN_ID = (-1); + + { X-Plane itself } + XPLM_PLUGIN_XPLANE = (0); + + { The current XPLM revision is 2.10 (210). } + kXPLM_Version = (210); + + { + XPLMKeyFlags + + These bitfields define modifier keys in a platform independent way. When a + key is pressed, a series of messages are sent to your plugin. The down + flag is set in the first of these messages, and the up flag in the last. + While the key is held down, messages are sent with neither to indicate that + the key is being held down as a repeated character. + + The control flag is mapped to the control flag on Macintosh and PC. + Generally X-Plane uses the control key and not the command key on + Macintosh, providing a consistent interface across platforms that does not + necessarily match the Macintosh user interface guidelines. There is not + yet a way for plugins to access the Macintosh control keys without using + #ifdefed code. + } +TYPE + XPLMKeyFlags = ( + { The shift key is down } + xplm_ShiftFlag = 1 + + { The option or alt key is down } + ,xplm_OptionAltFlag = 2 + + { The control key is down* } + ,xplm_ControlFlag = 4 + + { The key is being pressed down } + ,xplm_DownFlag = 8 + + { The key is being released } + ,xplm_UpFlag = 16 + + ); + PXPLMKeyFlags = ^XPLMKeyFlags; + +{___________________________________________________________________________ + * ASCII CONTROL KEY CODES + ___________________________________________________________________________} +{ + These definitions define how various control keys are mapped to ASCII key + codes. Not all key presses generate an ASCII value, so plugin code should + be prepared to see null characters come from the keyboard...this usually + represents a key stroke that has no equivalent ASCII, like a page-down + press. Use virtual key codes to find these key strokes. ASCII key codes + take into account modifier keys; shift keys will affect capitals and + punctuation; control key combinations may have no vaild ASCII and produce + NULL. To detect control-key combinations, use virtual key codes, not ASCII + keys. +} + + + +CONST + XPLM_KEY_RETURN = 13; + + XPLM_KEY_ESCAPE = 27; + + XPLM_KEY_TAB = 9; + + XPLM_KEY_DELETE = 8; + + XPLM_KEY_LEFT = 28; + + XPLM_KEY_RIGHT = 29; + + XPLM_KEY_UP = 30; + + XPLM_KEY_DOWN = 31; + + XPLM_KEY_0 = 48; + + XPLM_KEY_1 = 49; + + XPLM_KEY_2 = 50; + + XPLM_KEY_3 = 51; + + XPLM_KEY_4 = 52; + + XPLM_KEY_5 = 53; + + XPLM_KEY_6 = 54; + + XPLM_KEY_7 = 55; + + XPLM_KEY_8 = 56; + + XPLM_KEY_9 = 57; + + XPLM_KEY_DECIMAL = 46; + +{___________________________________________________________________________ + * VIRTUAL KEY CODES + ___________________________________________________________________________} +{ + These are cross-platform defines for every distinct keyboard press on the + computer. Every physical key on the keyboard has a virtual key code. So + the "two" key on the top row of the main keyboard has a different code + from the "two" key on the numeric key pad. But the 'w' and 'W' character + are indistinguishable by virtual key code because they are the same + physical key (one with and one without the shift key). + + Use virtual key codes to detect keystrokes that do not have ASCII + equivalents, allow the user to map the numeric keypad separately from the + main keyboard, and detect control key and other modifier-key combinations + that generate ASCII control key sequences (many of which are not available + directly via character keys in the SDK). + + To assign virtual key codes we started with the Microsoft set but made some + additions and changes. A few differences: + + 1. Modifier keys are not available as virtual key codes. You cannot get + distinct modifier press and release messages. Please do not try to use + modifier keys as regular keys; doing so will almost certainly interfere + with users' abilities to use the native x-plane key bindings. + + 2. Some keys that do not exist on both Mac and PC keyboards are removed. + + 3. Do not assume that the values of these keystrokes are interchangeable + with MS v-keys. +} + + + +CONST + XPLM_VK_BACK = $08; + + XPLM_VK_TAB = $09; + + XPLM_VK_CLEAR = $0C; + + XPLM_VK_RETURN = $0D; + + XPLM_VK_ESCAPE = $1B; + + XPLM_VK_SPACE = $20; + + XPLM_VK_PRIOR = $21; + + XPLM_VK_NEXT = $22; + + XPLM_VK_END = $23; + + XPLM_VK_HOME = $24; + + XPLM_VK_LEFT = $25; + + XPLM_VK_UP = $26; + + XPLM_VK_RIGHT = $27; + + XPLM_VK_DOWN = $28; + + XPLM_VK_SELECT = $29; + + XPLM_VK_PRINT = $2A; + + XPLM_VK_EXECUTE = $2B; + + XPLM_VK_SNAPSHOT = $2C; + + XPLM_VK_INSERT = $2D; + + XPLM_VK_DELETE = $2E; + + XPLM_VK_HELP = $2F; + + { XPLM_VK_0 thru XPLM_VK_9 are the same as ASCII '0' thru '9' (0x30 - 0x39) } + XPLM_VK_0 = $30; + + XPLM_VK_1 = $31; + + XPLM_VK_2 = $32; + + XPLM_VK_3 = $33; + + XPLM_VK_4 = $34; + + XPLM_VK_5 = $35; + + XPLM_VK_6 = $36; + + XPLM_VK_7 = $37; + + XPLM_VK_8 = $38; + + XPLM_VK_9 = $39; + + { XPLM_VK_A thru XPLM_VK_Z are the same as ASCII 'A' thru 'Z' (0x41 - 0x5A) } + XPLM_VK_A = $41; + + XPLM_VK_B = $42; + + XPLM_VK_C = $43; + + XPLM_VK_D = $44; + + XPLM_VK_E = $45; + + XPLM_VK_F = $46; + + XPLM_VK_G = $47; + + XPLM_VK_H = $48; + + XPLM_VK_I = $49; + + XPLM_VK_J = $4A; + + XPLM_VK_K = $4B; + + XPLM_VK_L = $4C; + + XPLM_VK_M = $4D; + + XPLM_VK_N = $4E; + + XPLM_VK_O = $4F; + + XPLM_VK_P = $50; + + XPLM_VK_Q = $51; + + XPLM_VK_R = $52; + + XPLM_VK_S = $53; + + XPLM_VK_T = $54; + + XPLM_VK_U = $55; + + XPLM_VK_V = $56; + + XPLM_VK_W = $57; + + XPLM_VK_X = $58; + + XPLM_VK_Y = $59; + + XPLM_VK_Z = $5A; + + XPLM_VK_NUMPAD0 = $60; + + XPLM_VK_NUMPAD1 = $61; + + XPLM_VK_NUMPAD2 = $62; + + XPLM_VK_NUMPAD3 = $63; + + XPLM_VK_NUMPAD4 = $64; + + XPLM_VK_NUMPAD5 = $65; + + XPLM_VK_NUMPAD6 = $66; + + XPLM_VK_NUMPAD7 = $67; + + XPLM_VK_NUMPAD8 = $68; + + XPLM_VK_NUMPAD9 = $69; + + XPLM_VK_MULTIPLY = $6A; + + XPLM_VK_ADD = $6B; + + XPLM_VK_SEPARATOR = $6C; + + XPLM_VK_SUBTRACT = $6D; + + XPLM_VK_DECIMAL = $6E; + + XPLM_VK_DIVIDE = $6F; + + XPLM_VK_F1 = $70; + + XPLM_VK_F2 = $71; + + XPLM_VK_F3 = $72; + + XPLM_VK_F4 = $73; + + XPLM_VK_F5 = $74; + + XPLM_VK_F6 = $75; + + XPLM_VK_F7 = $76; + + XPLM_VK_F8 = $77; + + XPLM_VK_F9 = $78; + + XPLM_VK_F10 = $79; + + XPLM_VK_F11 = $7A; + + XPLM_VK_F12 = $7B; + + XPLM_VK_F13 = $7C; + + XPLM_VK_F14 = $7D; + + XPLM_VK_F15 = $7E; + + XPLM_VK_F16 = $7F; + + XPLM_VK_F17 = $80; + + XPLM_VK_F18 = $81; + + XPLM_VK_F19 = $82; + + XPLM_VK_F20 = $83; + + XPLM_VK_F21 = $84; + + XPLM_VK_F22 = $85; + + XPLM_VK_F23 = $86; + + XPLM_VK_F24 = $87; + + { The following definitions are extended and are not based on the Microsoft } + { key set. } + XPLM_VK_EQUAL = $B0; + + XPLM_VK_MINUS = $B1; + + XPLM_VK_RBRACE = $B2; + + XPLM_VK_LBRACE = $B3; + + XPLM_VK_QUOTE = $B4; + + XPLM_VK_SEMICOLON = $B5; + + XPLM_VK_BACKSLASH = $B6; + + XPLM_VK_COMMA = $B7; + + XPLM_VK_SLASH = $B8; + + XPLM_VK_PERIOD = $B9; + + XPLM_VK_BACKQUOTE = $BA; + + XPLM_VK_ENTER = $BB; + + XPLM_VK_NUMPAD_ENT = $BC; + + XPLM_VK_NUMPAD_EQ = $BD; + +IMPLEMENTATION +END. diff --git a/GermanAirlinesVA-GAConnector/XPSDK/Delphi/XPLM/XPLMDisplay.pas b/GermanAirlinesVA-GAConnector/XPSDK/Delphi/XPLM/XPLMDisplay.pas new file mode 100644 index 0000000..751b5b5 --- /dev/null +++ b/GermanAirlinesVA-GAConnector/XPSDK/Delphi/XPLM/XPLMDisplay.pas @@ -0,0 +1,835 @@ +{ + Copyright 2005-2012 Sandy Barbour and Ben Supnik + + All rights reserved. See license.txt for usage. + + X-Plane SDK Version: 2.1.1 +} + +UNIT XPLMDisplay; +INTERFACE +{ + XPLM Display APIs - THEORY OF OPERATION + + This API provides the basic hooks to draw in X-Plane and create user + interface. All X-Plane drawing is done in OpenGL. The X-Plane plug-in + manager takes care of properly setting up the OpenGL context and matrices. + You do not decide when in your code's execution to draw; X-Plane tells you + when it is ready to have your plugin draw. + + X-Plane's drawing strategy is straightforward: every "frame" the screen is + rendered by drawing the 3-d scene (dome, ground, objects, airplanes, etc.) + and then drawing the cockpit on top of it. Alpha blending is used to + overlay the cockpit over the world (and the gauges over the panel, etc.). + + There are two ways you can draw: directly and in a window. + + Direct drawing involves drawing to the screen before or after X-Plane + finishes a phase of drawing. When you draw directly, you can specify + whether x-plane is to complete this phase or not. This allows you to do + three things: draw before x-plane does (under it), draw after x-plane does + (over it), or draw instead of x-plane. + + To draw directly, you register a callback and specify what phase you want + to intercept. The plug-in manager will call you over and over to draw that + phase. + + Direct drawing allows you to override scenery, panels, or anything. Note + that you cannot assume that you are the only plug-in drawing at this + phase. + + Window drawing provides slightly higher level functionality. With window + drawing you create a window that takes up a portion of the screen. Window + drawing is always two dimensional. Window drawing is front-to-back + controlled; you can specify that you want your window to be brought on + top, and other plug-ins may put their window on top of you. Window drawing + also allows you to sign up for key presses and receive mouse clicks. + + There are three ways to get keystrokes: + + If you create a window, the window can take keyboard focus. It will then + receive all keystrokes. If no window has focus, X-Plane receives + keystrokes. Use this to implement typing in dialog boxes, etc. Only one + window may have focus at a time; your window will be notified if it loses + focus. + + If you need to associate key strokes with commands/functions in your + plug-in, use a hot key. A hoy is a key-specific callback. Hotkeys are + sent based on virtual key strokes, so any key may be distinctly mapped with + any modifiers. Hot keys can be remapped by other plug-ins. As a plug-in, + you don't have to worry about what your hot key ends up mapped to; other + plug-ins may provide a UI for remapping keystrokes. So hotkeys allow a + user to resolve conflicts and customize keystrokes. + + If you need low level access to the keystroke stream, install a key + sniffer. Key sniffers can be installed above everything or right in front + of the sim. +} + +USES XPLMDefs; + {$A4} +{$IFDEF MSWINDOWS} + {$DEFINE DELPHI} +{$ENDIF} +{___________________________________________________________________________ + * DRAWING CALLBACKS + ___________________________________________________________________________} +{ + Basic drawing callbacks, for low level intercepting of render loop. The + purpose of drawing callbacks is to provide targeted additions or + replacements to x-plane's graphics environment (for example, to add extra + custom objects, or replace drawing of the AI aircraft). Do not assume that + the drawing callbacks will be called in the order implied by the + enumerations. Also do not assume that each drawing phase ends before + another begins; they may be nested. +} + + + + { + XPLMDrawingPhase + + This constant indicates which part of drawing we are in. Drawing is done + from the back to the front. We get a callback before or after each item. + Metaphases provide access to the beginning and end of the 3d (scene) and 2d + (cockpit) drawing in a manner that is independent of new phases added via + x-plane implementation. + + WARNING: As X-Plane's scenery evolves, some drawing phases may cease to + exist and new ones may be invented. If you need a particularly specific + use of these codes, consult Austin and/or be prepared to revise your code + as X-Plane evolves. + } +TYPE + XPLMDrawingPhase = ( + { This is the earliest point at which you can draw in 3-d. } + xplm_Phase_FirstScene = 0 + + { Drawing of land and water. } + ,xplm_Phase_Terrain = 5 + + { Drawing runways and other airport detail. } + ,xplm_Phase_Airports = 10 + + { Drawing roads, trails, trains, etc. } + ,xplm_Phase_Vectors = 15 + + { 3-d objects (houses, smokestacks, etc. } + ,xplm_Phase_Objects = 20 + + { External views of airplanes, both yours and the AI aircraft. } + ,xplm_Phase_Airplanes = 25 + + { This is the last point at which you can draw in 3-d. } + ,xplm_Phase_LastScene = 30 + + { This is the first phase where you can draw in 2-d. } + ,xplm_Phase_FirstCockpit = 35 + + { The non-moving parts of the aircraft panel. } + ,xplm_Phase_Panel = 40 + + { The moving parts of the aircraft panel. } + ,xplm_Phase_Gauges = 45 + + { Floating windows from plugins. } + ,xplm_Phase_Window = 50 + + { The last change to draw in 2d. } + ,xplm_Phase_LastCockpit = 55 + +{$IFDEF XPLM200} + { 3-d Drawing for the local map. Use regular OpenGL coordinates to draw in } + { this phase. } + ,xplm_Phase_LocalMap3D = 100 +{$ENDIF} + +{$IFDEF XPLM200} + { 2-d Drawing of text over the local map. } + ,xplm_Phase_LocalMap2D = 101 +{$ENDIF} + +{$IFDEF XPLM200} + { Drawing of the side-profile view in the local map screen. } + ,xplm_Phase_LocalMapProfile = 102 +{$ENDIF} + + ); + PXPLMDrawingPhase = ^XPLMDrawingPhase; + + { + XPLMDrawCallback_f + + This is the prototype for a low level drawing callback. You are passed in + the phase and whether it is before or after. If you are before the phase, + return 1 to let x-plane draw or 0 to suppress x-plane drawing. If you are + after the phase the return value is ignored. + + Refcon is a unique value that you specify when registering the callback, + allowing you to slip a pointer to your own data to the callback. + + Upon entry the OpenGL context will be correctly set up for you and OpenGL + will be in 'local' coordinates for 3d drawing and panel coordinates for 2d + drawing. The OpenGL state (texturing, etc.) will be unknown. + } + XPLMDrawCallback_f = FUNCTION( + inPhase : XPLMDrawingPhase; + inIsBefore : integer; + inRefcon : pointer) : integer; cdecl; + + { + XPLMKeySniffer_f + + This is the prototype for a low level key-sniffing function. Window-based + UI _should not use this_! The windowing system provides high-level + mediated keyboard access. By comparison, the key sniffer provides low + level keyboard access. + + Key sniffers are provided to allow libraries to provide non-windowed user + interaction. For example, the MUI library uses a key sniffer to do pop-up + text entry. + + inKey is the character pressed, inRefCon is a value you supply during + registration. Return 1 to pass the key on to the next sniffer, the window + mgr, x-plane, or whomever is down stream. Return 0 to consume the key. + + Warning: this API declares virtual keys as a signed character; however the + VKEY #define macros in XPLMDefs.h define the vkeys using unsigned values + (that is 0x80 instead of -0x80). So you may need to cast the incoming vkey + to an unsigned char to get correct comparisons in C. + } + XPLMKeySniffer_f = FUNCTION( + inChar : char; + inFlags : XPLMKeyFlags; + inVirtualKey : char; + inRefcon : pointer) : integer; cdecl; + + { + XPLMRegisterDrawCallback + + This routine registers a low level drawing callback. Pass in the phase you + want to be called for and whether you want to be called before or after. + This routine returns 1 if the registration was successful, or 0 if the + phase does not exist in this version of x-plane. You may register a + callback multiple times for the same or different phases as long as the + refcon is unique each time. + } + FUNCTION XPLMRegisterDrawCallback( + inCallback : XPLMDrawCallback_f; + inPhase : XPLMDrawingPhase; + inWantsBefore : integer; + inRefcon : pointer) : integer; +{$IFDEF DELPHI} + cdecl; external 'XPLM.DLL'; +{$ELSE} + cdecl; external ''; +{$ENDIF} + + { + XPLMUnregisterDrawCallback + + This routine unregisters a draw callback. You must unregister a callback + for each time you register a callback if you have registered it multiple + times with different refcons. The routine returns 1 if it can find the + callback to unregister, 0 otherwise. + } + FUNCTION XPLMUnregisterDrawCallback( + inCallback : XPLMDrawCallback_f; + inPhase : XPLMDrawingPhase; + inWantsBefore : integer; + inRefcon : pointer) : integer; +{$IFDEF DELPHI} + cdecl; external 'XPLM.DLL'; +{$ELSE} + cdecl; external ''; +{$ENDIF} + + { + XPLMRegisterKeySniffer + + This routine registers a key sniffing callback. You specify whether you + want to sniff before the window system, or only sniff keys the window + system does not consume. You should ALMOST ALWAYS sniff non-control keys + after the window system. When the window system consumes a key, it is + because the user has "focused" a window. Consuming the key or taking + action based on the key will produce very weird results. Returns 1 if + successful. + } + FUNCTION XPLMRegisterKeySniffer( + inCallback : XPLMKeySniffer_f; + inBeforeWindows : integer; + inRefcon : pointer) : integer; +{$IFDEF DELPHI} + cdecl; external 'XPLM.DLL'; +{$ELSE} + cdecl; external ''; +{$ENDIF} + + { + XPLMUnregisterKeySniffer + + This routine unregisters a key sniffer. You must unregister a key sniffer + for every time you register one with the exact same signature. Returns 1 + if successful. + } + FUNCTION XPLMUnregisterKeySniffer( + inCallback : XPLMKeySniffer_f; + inBeforeWindows : integer; + inRefcon : pointer) : integer; +{$IFDEF DELPHI} + cdecl; external 'XPLM.DLL'; +{$ELSE} + cdecl; external ''; +{$ENDIF} + +{___________________________________________________________________________ + * WINDOW API + ___________________________________________________________________________} +{ + Window API, for higher level drawing with UI interaction. + + Note: all 2-d (and thus all window drawing) is done in 'cockpit pixels'. + Even when the OpenGL window contains more than 1024x768 pixels, the cockpit + drawing is magnified so that only 1024x768 pixels are available. +} + + + + { + XPLMMouseStatus + + When the mouse is clicked, your mouse click routine is called repeatedly. + It is first called with the mouse down message. It is then called zero or + more times with the mouse-drag message, and finally it is called once with + the mouse up message. All of these messages will be directed to the same + window. + } +TYPE + XPLMMouseStatus = ( + xplm_MouseDown = 1 + + ,xplm_MouseDrag = 2 + + ,xplm_MouseUp = 3 + + ); + PXPLMMouseStatus = ^XPLMMouseStatus; + +{$IFDEF XPLM200} + { + XPLMCursorStatus + + XPLMCursorStatus describes how you would like X-Plane to manage the cursor. + See XPLMHandleCursor_f for more info. + } + XPLMCursorStatus = ( + { X-Plane manages the cursor normally, plugin does not affect the cusrsor. } + xplm_CursorDefault = 0 + + { X-Plane hides the cursor. } + ,xplm_CursorHidden = 1 + + { X-Plane shows the cursor as the default arrow. } + ,xplm_CursorArrow = 2 + + { X-Plane shows the cursor but lets you select an OS cursor. } + ,xplm_CursorCustom = 3 + + ); + PXPLMCursorStatus = ^XPLMCursorStatus; +{$ENDIF} + + { + XPLMWindowID + + This is an opaque identifier for a window. You use it to control your + window. When you create a window, you will specify callbacks to handle + drawing and mouse interaction, etc. + } + XPLMWindowID = pointer; + PXPLMWindowID = ^XPLMWindowID; + + { + XPLMDrawWindow_f + + This function handles drawing. You are passed in your window and its + refcon. Draw the window. You can use XPLM functions to find the current + dimensions of your window, etc. When this callback is called, the OpenGL + context will be set properly for cockpit drawing. NOTE: Because you are + drawing your window over a background, you can make a translucent window + easily by simply not filling in your entire window's bounds. + } + XPLMDrawWindow_f = PROCEDURE( + inWindowID : XPLMWindowID; + inRefcon : pointer); cdecl; + + { + XPLMHandleKey_f + + This function is called when a key is pressed or keyboard focus is taken + away from your window. If losingFocus is 1, you are losign the keyboard + focus, otherwise a key was pressed and inKey contains its character. You + are also passewd your window and a refcon. Warning: this API declares + virtual keys as a signed character; however the VKEY #define macros in + XPLMDefs.h define the vkeys using unsigned values (that is 0x80 instead of + -0x80). So you may need to cast the incoming vkey to an unsigned char to + get correct comparisons in C. + } + XPLMHandleKey_f = PROCEDURE( + inWindowID : XPLMWindowID; + inKey : char; + inFlags : XPLMKeyFlags; + inVirtualKey : char; + inRefcon : pointer; + losingFocus : integer); cdecl; + + { + XPLMHandleMouseClick_f + + You receive this call when the mouse button is pressed down or released. + Between then these two calls is a drag. You receive the x and y of the + click, your window, and a refcon. Return 1 to consume the click, or 0 to + pass it through. + + WARNING: passing clicks through windows (as of this writing) causes mouse + tracking problems in X-Plane; do not use this feature! + } + XPLMHandleMouseClick_f = FUNCTION( + inWindowID : XPLMWindowID; + x : integer; + y : integer; + inMouse : XPLMMouseStatus; + inRefcon : pointer) : integer; cdecl; + +{$IFDEF XPLM200} + { + XPLMHandleCursor_f + + The SDK calls your cursor status callback when the mouse is over your + plugin window. Return a cursor status code to indicate how you would like + X-Plane to manage the cursor. If you return xplm_CursorDefault, the SDK + will try lower-Z-order plugin windows, then let the sim manage the cursor. + + Note: you should never show or hide the cursor yourself - these APIs are + typically reference-counted and thus cannot safely and predictably be used + by the SDK. Instead return one of xplm_CursorHidden to hide the cursor or + xplm_CursorArrow/xplm_CursorCustom to show the cursor. + + If you want to implement a custom cursor by drawing a cursor in OpenGL, use + xplm_CursorHidden to hide the OS cursor and draw the cursor using a 2-d + drawing callback (after xplm_Phase_Window is probably a good choice). If + you want to use a custom OS-based cursor, use xplm_CursorCustom to ask + X-Plane to show the cursor but not affect its image. You can then use an + OS specific call like SetThemeCursor (Mac) or SetCursor/LoadCursor + (Windows). + } + XPLMHandleCursor_f = FUNCTION( + inWindowID : XPLMWindowID; + x : integer; + y : integer; + inRefcon : pointer) : XPLMCursorStatus; cdecl; +{$ENDIF} + +{$IFDEF XPLM200} + { + XPLMHandleMouseWheel_f + + The SDK calls your mouse wheel callback when one of the mouse wheels is + turned within your window. Return 1 to consume the mouse wheel clicks or + 0 to pass them on to a lower window. (You should consume mouse wheel + clicks even if they do nothing if your window appears opaque to the user.) + The number of clicks indicates how far the wheel was turned since the last + callback. The wheel is 0 for the vertical axis or 1 for the horizontal axis + (for OS/mouse combinations that support this). + } + XPLMHandleMouseWheel_f = FUNCTION( + inWindowID : XPLMWindowID; + x : integer; + y : integer; + wheel : integer; + clicks : integer; + inRefcon : pointer) : integer; cdecl; +{$ENDIF} + +{$IFDEF XPLM200} + { + XPLMCreateWindow_t + + The XPMCreateWindow_t structure defines all of the parameters used to + create a window using XPLMCreateWindowEx. The structure will be expanded + in future SDK APIs to include more features. Always set the structSize + member to the size of your struct in bytes! + } + XPLMCreateWindow_t = RECORD + structSize : integer; + left : integer; + top : integer; + right : integer; + bottom : integer; + visible : integer; + drawWindowFunc : XPLMDrawWindow_f; + handleMouseClickFunc : XPLMHandleMouseClick_f; + handleKeyFunc : XPLMHandleKey_f; + handleCursorFunc : XPLMHandleCursor_f; + handleMouseWheelFunc : XPLMHandleMouseWheel_f; + refcon : pointer; + END; + PXPLMCreateWindow_t = ^XPLMCreateWindow_t; +{$ENDIF} + + { + XPLMGetScreenSize + + This routine returns the size of the size of the X-Plane OpenGL window in + pixels. Please note that this is not the size of the screen when doing + 2-d drawing (the 2-d screen is currently always 1024x768, and graphics are + scaled up by OpenGL when doing 2-d drawing for higher-res monitors). This + number can be used to get a rough idea of the amount of detail the user + will be able to see when drawing in 3-d. + } + PROCEDURE XPLMGetScreenSize( + outWidth : Pinteger; { Can be nil } + outHeight : Pinteger); { Can be nil } +{$IFDEF DELPHI} + cdecl; external 'XPLM.DLL'; +{$ELSE} + cdecl; external ''; +{$ENDIF} + + { + XPLMGetMouseLocation + + This routine returns the current mouse location in cockpit pixels. The + bottom left corner of the display is 0,0. Pass NULL to not receive info + about either parameter. + } + PROCEDURE XPLMGetMouseLocation( + outX : Pinteger; { Can be nil } + outY : Pinteger); { Can be nil } +{$IFDEF DELPHI} + cdecl; external 'XPLM.DLL'; +{$ELSE} + cdecl; external ''; +{$ENDIF} + + { + XPLMCreateWindow + + This routine creates a new window. Pass in the dimensions and offsets to + the window's bottom left corner from the bottom left of the screen. You + can specify whether the window is initially visible or not. Also, you pass + in three callbacks to run the window and a refcon. This function returns a + window ID you can use to refer to the new window. + + NOTE: windows do not have "frames"; you are responsible for drawing the + background and frame of the window. Higher level libraries have routines + which make this easy. + } + FUNCTION XPLMCreateWindow( + inLeft : integer; + inTop : integer; + inRight : integer; + inBottom : integer; + inIsVisible : integer; + inDrawCallback : XPLMDrawWindow_f; + inKeyCallback : XPLMHandleKey_f; + inMouseCallback : XPLMHandleMouseClick_f; + inRefcon : pointer) : XPLMWindowID; +{$IFDEF DELPHI} + cdecl; external 'XPLM.DLL'; +{$ELSE} + cdecl; external ''; +{$ENDIF} + +{$IFDEF XPLM200} + { + XPLMCreateWindowEx + + This routine creates a new window - you pass in an XPLMCreateWindow_t + structure with all of the fields set in. You must set the structSize of + the structure to the size of the actual structure you used. Also, you + must provide funtions for every callback - you may not leave them null! + (If you do not support the cursor or mouse wheel, use functions that return + the default values.) The numeric values of the XPMCreateWindow_t structure + correspond to the parameters of XPLMCreateWindow. + } + FUNCTION XPLMCreateWindowEx( + inParams : PXPLMCreateWindow_t) : XPLMWindowID; +{$IFDEF DELPHI} + cdecl; external 'XPLM.DLL'; +{$ELSE} + cdecl; external ''; +{$ENDIF} +{$ENDIF} + + { + XPLMDestroyWindow + + This routine destroys a window. The callbacks are not called after this + call. Keyboard focus is removed from the window before destroying it. + } + PROCEDURE XPLMDestroyWindow( + inWindowID : XPLMWindowID); +{$IFDEF DELPHI} + cdecl; external 'XPLM.DLL'; +{$ELSE} + cdecl; external ''; +{$ENDIF} + + { + XPLMGetWindowGeometry + + This routine returns the position and size of a window in cockpit pixels. + Pass NULL to not receive any paramter. + } + PROCEDURE XPLMGetWindowGeometry( + inWindowID : XPLMWindowID; + outLeft : Pinteger; { Can be nil } + outTop : Pinteger; { Can be nil } + outRight : Pinteger; { Can be nil } + outBottom : Pinteger); { Can be nil } +{$IFDEF DELPHI} + cdecl; external 'XPLM.DLL'; +{$ELSE} + cdecl; external ''; +{$ENDIF} + + { + XPLMSetWindowGeometry + + This routine allows you to set the position or height aspects of a window. + } + PROCEDURE XPLMSetWindowGeometry( + inWindowID : XPLMWindowID; + inLeft : integer; + inTop : integer; + inRight : integer; + inBottom : integer); +{$IFDEF DELPHI} + cdecl; external 'XPLM.DLL'; +{$ELSE} + cdecl; external ''; +{$ENDIF} + + { + XPLMGetWindowIsVisible + + This routine returns whether a window is visible. + } + FUNCTION XPLMGetWindowIsVisible( + inWindowID : XPLMWindowID) : integer; +{$IFDEF DELPHI} + cdecl; external 'XPLM.DLL'; +{$ELSE} + cdecl; external ''; +{$ENDIF} + + { + XPLMSetWindowIsVisible + + This routine shows or hides a window. + } + PROCEDURE XPLMSetWindowIsVisible( + inWindowID : XPLMWindowID; + inIsVisible : integer); +{$IFDEF DELPHI} + cdecl; external 'XPLM.DLL'; +{$ELSE} + cdecl; external ''; +{$ENDIF} + + { + XPLMGetWindowRefCon + + This routine returns a windows refcon, the unique value you can use for + your own purposes. + } + FUNCTION XPLMGetWindowRefCon( + inWindowID : XPLMWindowID) : pointer; +{$IFDEF DELPHI} + cdecl; external 'XPLM.DLL'; +{$ELSE} + cdecl; external ''; +{$ENDIF} + + { + XPLMSetWindowRefCon + + This routine sets a window's reference constant. Use this to pass data to + yourself in the callbacks. + } + PROCEDURE XPLMSetWindowRefCon( + inWindowID : XPLMWindowID; + inRefcon : pointer); +{$IFDEF DELPHI} + cdecl; external 'XPLM.DLL'; +{$ELSE} + cdecl; external ''; +{$ENDIF} + + { + XPLMTakeKeyboardFocus + + This routine gives a specific window keyboard focus. Keystrokes will be + sent to that window. Pass a window ID of 0 to pass keyboard strokes + directly to X-Plane. + } + PROCEDURE XPLMTakeKeyboardFocus( + inWindow : XPLMWindowID); +{$IFDEF DELPHI} + cdecl; external 'XPLM.DLL'; +{$ELSE} + cdecl; external ''; +{$ENDIF} + + { + XPLMBringWindowToFront + + This routine brings the window to the front of the Z-order. Windows are + brought to the front when they are created...beyond that you should make + sure you are front before handling mouse clicks. + } + PROCEDURE XPLMBringWindowToFront( + inWindow : XPLMWindowID); +{$IFDEF DELPHI} + cdecl; external 'XPLM.DLL'; +{$ELSE} + cdecl; external ''; +{$ENDIF} + + { + XPLMIsWindowInFront + + This routine returns true if you pass inthe ID of the frontmost visible + window. + } + FUNCTION XPLMIsWindowInFront( + inWindow : XPLMWindowID) : integer; +{$IFDEF DELPHI} + cdecl; external 'XPLM.DLL'; +{$ELSE} + cdecl; external ''; +{$ENDIF} + +{___________________________________________________________________________ + * HOT KEYS + ___________________________________________________________________________} +{ + Hot Keys - keystrokes that can be managed by others. +} + + + + { + XPLMHotKey_f + + Your hot key callback simply takes a pointer of your choosing. + } +TYPE + XPLMHotKey_f = PROCEDURE( + inRefcon : pointer); cdecl; + + { + XPLMHotKeyID + + Hot keys are identified by opaque IDs. + } + XPLMHotKeyID = pointer; + PXPLMHotKeyID = ^XPLMHotKeyID; + + { + XPLMRegisterHotKey + + This routine registers a hot key. You specify your preferred key stroke + virtual key/flag combination, a description of what your callback does (so + other plug-ins can describe the plug-in to the user for remapping) and a + callback function and opaque pointer to pass in). A new hot key ID is + returned. During execution, the actual key associated with your hot key + may change, but you are insulated from this. + } + FUNCTION XPLMRegisterHotKey( + inVirtualKey : char; + inFlags : XPLMKeyFlags; + inDescription : Pchar; + inCallback : XPLMHotKey_f; + inRefcon : pointer) : XPLMHotKeyID; +{$IFDEF DELPHI} + cdecl; external 'XPLM.DLL'; +{$ELSE} + cdecl; external ''; +{$ENDIF} + + { + XPLMUnregisterHotKey + + This API unregisters a hot key. You can only register your own hot keys. + } + PROCEDURE XPLMUnregisterHotKey( + inHotKey : XPLMHotKeyID); +{$IFDEF DELPHI} + cdecl; external 'XPLM.DLL'; +{$ELSE} + cdecl; external ''; +{$ENDIF} + + { + XPLMCountHotKeys + + Returns the number of current hot keys. + } + FUNCTION XPLMCountHotKeys: integer; +{$IFDEF DELPHI} + cdecl; external 'XPLM.DLL'; +{$ELSE} + cdecl; external ''; +{$ENDIF} + + { + XPLMGetNthHotKey + + Returns a hot key by index, for iteration on all hot keys. + } + FUNCTION XPLMGetNthHotKey( + inIndex : integer) : XPLMHotKeyID; +{$IFDEF DELPHI} + cdecl; external 'XPLM.DLL'; +{$ELSE} + cdecl; external ''; +{$ENDIF} + + { + XPLMGetHotKeyInfo + + Returns information about the hot key. Return NULL for any parameter you + don't want info about. The description should be at least 512 chars long. + } + PROCEDURE XPLMGetHotKeyInfo( + inHotKey : XPLMHotKeyID; + outVirtualKey : Pchar; { Can be nil } + outFlags : PXPLMKeyFlags; { Can be nil } + outDescription : Pchar; { Can be nil } + outPlugin : PXPLMPluginID); { Can be nil } +{$IFDEF DELPHI} + cdecl; external 'XPLM.DLL'; +{$ELSE} + cdecl; external ''; +{$ENDIF} + + { + XPLMSetHotKeyCombination + + XPLMSetHotKeyCombination remaps a hot keys keystrokes. You may remap + another plugin's keystrokes. + } + PROCEDURE XPLMSetHotKeyCombination( + inHotKey : XPLMHotKeyID; + inVirtualKey : char; + inFlags : XPLMKeyFlags); +{$IFDEF DELPHI} + cdecl; external 'XPLM.DLL'; +{$ELSE} + cdecl; external ''; +{$ENDIF} + +IMPLEMENTATION +END. diff --git a/GermanAirlinesVA-GAConnector/XPSDK/Delphi/XPLM/XPLMGraphics.pas b/GermanAirlinesVA-GAConnector/XPSDK/Delphi/XPLM/XPLMGraphics.pas new file mode 100644 index 0000000..713f14a --- /dev/null +++ b/GermanAirlinesVA-GAConnector/XPSDK/Delphi/XPLM/XPLMGraphics.pas @@ -0,0 +1,441 @@ +{ + Copyright 2005-2012 Sandy Barbour and Ben Supnik + + All rights reserved. See license.txt for usage. + + X-Plane SDK Version: 2.1.1 +} + +UNIT XPLMGraphics; +INTERFACE +{ + Graphics routines for X-Plane and OpenGL. + + A few notes on coordinate systems: + + X-Plane uses three kinds of coordinates. Global coordinates are specified + as latitude, longitude and elevation. This coordinate system never changes + but is not very precise. + + OpenGL (or 'local') coordinates are cartesian and shift with the plane. + They offer more precision and are used for 3-d OpenGL drawing. The X axis + is aligned east-west with positive X meaning east. The Y axis is aligned + straight up and down at the point 0,0,0 (but since the earth is round it is + not truly straight up and down at other points). The Z axis is aligned + north-south at 0, 0, 0 with positive Z pointing south (but since the earth + is round it isn't exactly north-south as you move east or west of 0, 0, 0). + One unit is one meter and the point 0,0,0 is on the surface of the earth + at sea level for some latitude and longitude picked by the sim such that + the user's aircraft is reasonably nearby. + + Cockpit coordinates are 2d, with the X axis horizontal and the Y axis + vertical. The point 0,0 is the bottom left and 1024,768 is the upper right + of the screen. This is true no matter what resolution the user's monitor is + in; when running in higher resolution, graphics will be scaled. + + Use X-Plane's routines to convert between global and local coordinates. Do + not attempt to do this conversion yourself; the precise 'roundness' of + X-Plane's physics model may not match your own, and (to make things + weirder) the user can potentially customize the physics of the current + planet. +} + +USES XPLMDefs; + {$A4} +{$IFDEF MSWINDOWS} + {$DEFINE DELPHI} +{$ENDIF} +{___________________________________________________________________________ + * X-PLANE GRAPHICS + ___________________________________________________________________________} +{ + These routines allow you to use OpenGL with X-Plane. +} + + + + { + XPLMTextureID + + XPLM Texture IDs name well-known textures in the sim for you to use. This + allows you to recycle textures from X-Plane, saving VRAM. + } +TYPE + XPLMTextureID = ( + { The bitmap that contains window outlines, button outlines, fonts, etc. } + xplm_Tex_GeneralInterface = 0 + + { The exterior paint for the user's aircraft (daytime). } + ,xplm_Tex_AircraftPaint = 1 + + { The exterior light map for the user's aircraft. } + ,xplm_Tex_AircraftLiteMap = 2 + + ); + PXPLMTextureID = ^XPLMTextureID; + + { + XPLMSetGraphicsState + + XPLMSetGraphicsState changes OpenGL's graphics state in a number of ways: + + inEnableFog - enables or disables fog, equivalent to: glEnable(GL_FOG); + + inNumberTexUnits - enables or disables a number of multitexturing units. If + the number is 0, 2d texturing is disabled entirely, as in + glDisable(GL_TEXTURE_2D); Otherwise, 2d texturing is enabled, and a + number of multitexturing units are enabled sequentially, starting with + unit 0, e.g. glActiveTextureARB(GL_TEXTURE0_ARB); glEnable + (GL_TEXTURE_2D); + + inEnableLighting - enables or disables OpenGL lighting, e.g. + glEnable(GL_LIGHTING); glEnable(GL_LIGHT0); + + inEnableAlphaTesting - enables or disables the alpha test per pixel, e.g. + glEnable(GL_ALPHA_TEST); + + inEnableAlphaBlending - enables or disables alpha blending per pixel, e.g. + glEnable(GL_BLEND); + + inEnableDepthTesting - enables per pixel depth testing, as in + glEnable(GL_DEPTH_TEST); + + inEnableDepthWriting - enables writing back of depth information to the + depth bufffer, as in glDepthMask(GL_TRUE); + + The purpose of this function is to change OpenGL state while keeping + X-Plane aware of the state changes; this keeps X-Plane from getting + surprised by OGL state changes, and prevents X-Plane and plug-ins from + having to set all state before all draws; XPLMSetGraphicsState internally + skips calls to change state that is already properly enabled. + + X-Plane does not have a 'default' OGL state to plug-ins; plug-ins should + totally set OGL state before drawing. Use XPLMSetGraphicsState instead of + any of the above OpenGL calls. + + WARNING: Any routine that performs drawing (e.g. XPLMDrawString or widget + code) may change X-Plane's state. Always set state before drawing after + unknown code has executed. + } + PROCEDURE XPLMSetGraphicsState( + inEnableFog : integer; + inNumberTexUnits : integer; + inEnableLighting : integer; + inEnableAlphaTesting: integer; + inEnableAlphaBlending: integer; + inEnableDepthTesting: integer; + inEnableDepthWriting: integer); +{$IFDEF DELPHI} + cdecl; external 'XPLM.DLL'; +{$ELSE} + cdecl; external ''; +{$ENDIF} + + { + XPLMBindTexture2d + + XPLMBindTexture2d changes what texture is bound to the 2d texturing target. + This routine caches the current 2d texture across all texturing units in + the sim and plug-ins, preventing extraneous binding. For example, consider + several plug-ins running in series; if they all use the 'general interface' + bitmap to do UI, calling this function will skip the rebinding of the + general interface texture on all but the first plug-in, which can provide + better frame rate son some graphics cards. + + inTextureID is the ID of the texture object to bind; inTextureUnit is a + zero-based texture unit (e.g. 0 for the first one), up to a maximum of 4 + units. (This number may increase in future versions of x-plane.) + + Use this routine instead of glBindTexture(GL_TEXTURE_2D, ....); + } + PROCEDURE XPLMBindTexture2d( + inTextureNum : integer; + inTextureUnit : integer); +{$IFDEF DELPHI} + cdecl; external 'XPLM.DLL'; +{$ELSE} + cdecl; external ''; +{$ENDIF} + + { + XPLMGenerateTextureNumbers + + This routine generates unused texture numbers that a plug-in can use to + safely bind textures. Use this routine instead of glGenTextures; + glGenTextures will allocate texture numbers in ranges that X-Plane reserves + for its own use but does not always use; for example, it might provide an + ID within the range of textures reserved for terrain...loading a new .env + file as the plane flies might then cause X-Plane to use this texture ID. + X-Plane will then overwrite the plug-ins texture. This routine returns + texture IDs that are out of X-Plane's usage range. + } + PROCEDURE XPLMGenerateTextureNumbers( + outTextureIDs : Pinteger; + inCount : integer); +{$IFDEF DELPHI} + cdecl; external 'XPLM.DLL'; +{$ELSE} + cdecl; external ''; +{$ENDIF} + + { + XPLMGetTexture + + XPLMGetTexture returns the OpenGL texture enumeration of an X-Plane texture + based on a generic identifying code. For example, you can get the texture + for X-Plane's UI bitmaps. This allows you to build new gauges that take + advantage of x-plane's textures, for smooth artwork integration and also + saving texture memory. Note that the texture might not be loaded yet, + depending on what the plane's panel contains. + + OPEN ISSUE: We really need a way to make sure X-Plane loads this texture if + it isn't around, or at least a way to find out whether it is loaded or not. + } + FUNCTION XPLMGetTexture( + inTexture : XPLMTextureID) : integer; +{$IFDEF DELPHI} + cdecl; external 'XPLM.DLL'; +{$ELSE} + cdecl; external ''; +{$ENDIF} + + { + XPLMWorldToLocal + + This routine translates coordinates from latitude, longitude, and altitude + to local scene coordinates. Latitude and longitude are in decimal degrees, + and altitude is in meters MSL (mean sea level). The XYZ coordinates are in + meters in the local OpenGL coordinate system. + } + PROCEDURE XPLMWorldToLocal( + inLatitude : real; + inLongitude : real; + inAltitude : real; + outX : Preal; + outY : Preal; + outZ : Preal); +{$IFDEF DELPHI} + cdecl; external 'XPLM.DLL'; +{$ELSE} + cdecl; external ''; +{$ENDIF} + + { + XPLMLocalToWorld + + This routine translates a local coordinate triplet back into latitude, + longitude, and altitude. Latitude and longitude are in decimal degrees, + and altitude is in meters MSL (mean sea level). The XYZ coordinates are in + meters in the local OpenGL coordinate system. + + NOTE: world coordinates are less precise than local coordinates; you should + try to avoid round tripping from local to world and back. + } + PROCEDURE XPLMLocalToWorld( + inX : real; + inY : real; + inZ : real; + outLatitude : Preal; + outLongitude : Preal; + outAltitude : Preal); +{$IFDEF DELPHI} + cdecl; external 'XPLM.DLL'; +{$ELSE} + cdecl; external ''; +{$ENDIF} + + { + XPLMDrawTranslucentDarkBox + + This routine draws a translucent dark box, partially obscuring parts of the + screen but making text easy to read. This is the same graphics primitive + used by X-Plane to show text files and ATC info. + } + PROCEDURE XPLMDrawTranslucentDarkBox( + inLeft : integer; + inTop : integer; + inRight : integer; + inBottom : integer); +{$IFDEF DELPHI} + cdecl; external 'XPLM.DLL'; +{$ELSE} + cdecl; external ''; +{$ENDIF} + +{___________________________________________________________________________ + * X-PLANE TEXT + ___________________________________________________________________________} +{ + +} + + + + { + XPLMFontID + + X-Plane features some fixed-character fonts. Each font may have its own + metrics. + + WARNING: Some of these fonts are no longer supported or may have changed + geometries. For maximum copmatibility, see the comments below. + + Note: X-Plane 7 supports proportional-spaced fonts. Since no measuring + routine is available yet, the SDK will normally draw using a fixed-width + font. You can use a dataref to enable proportional font drawing on XP7 if + you want to. + } +TYPE + XPLMFontID = ( + { Mono-spaced font for user interface. Available in all versions of the SDK. } + xplmFont_Basic = 0 + + { Deprecated, do not use. } + ,xplmFont_Menus = 1 + + { Deprecated, do not use. } + ,xplmFont_Metal = 2 + + { Deprecated, do not use. } + ,xplmFont_Led = 3 + + { Deprecated, do not use. } + ,xplmFont_LedWide = 4 + + { Deprecated, do not use. } + ,xplmFont_PanelHUD = 5 + + { Deprecated, do not use. } + ,xplmFont_PanelEFIS = 6 + + { Deprecated, do not use. } + ,xplmFont_PanelGPS = 7 + + { Deprecated, do not use. } + ,xplmFont_RadiosGA = 8 + + { Deprecated, do not use. } + ,xplmFont_RadiosBC = 9 + + { Deprecated, do not use. } + ,xplmFont_RadiosHM = 10 + + { Deprecated, do not use. } + ,xplmFont_RadiosGANarrow = 11 + + { Deprecated, do not use. } + ,xplmFont_RadiosBCNarrow = 12 + + { Deprecated, do not use. } + ,xplmFont_RadiosHMNarrow = 13 + + { Deprecated, do not use. } + ,xplmFont_Timer = 14 + + { Deprecated, do not use. } + ,xplmFont_FullRound = 15 + + { Deprecated, do not use. } + ,xplmFont_SmallRound = 16 + + { Deprecated, do not use. } + ,xplmFont_Menus_Localized = 17 + +{$IFDEF XPLM200} + { Proportional UI font. } + ,xplmFont_Proportional = 18 +{$ENDIF} + + ); + PXPLMFontID = ^XPLMFontID; + + { + XPLMDrawString + + This routine draws a NULL termianted string in a given font. Pass in the + lower left pixel that the character is to be drawn onto. Also pass the + character and font ID. This function returns the x offset plus the width of + all drawn characters. The color to draw in is specified as a pointer to an + array of three floating point colors, representing RGB intensities from 0.0 + to 1.0. + } + PROCEDURE XPLMDrawString( + inColorRGB : Psingle; + inXOffset : integer; + inYOffset : integer; + inChar : Pchar; + inWordWrapWidth : Pinteger; { Can be nil } + inFontID : XPLMFontID); +{$IFDEF DELPHI} + cdecl; external 'XPLM.DLL'; +{$ELSE} + cdecl; external ''; +{$ENDIF} + + { + XPLMDrawNumber + + This routine draws a number similar to the digit editing fields in + PlaneMaker and data output display in X-Plane. Pass in a color, a + position, a floating point value, and formatting info. Specify how many + integer and how many decimal digits to show and whether to show a sign, as + well as a character set. This routine returns the xOffset plus width of the + string drawn. + } + PROCEDURE XPLMDrawNumber( + inColorRGB : Psingle; + inXOffset : integer; + inYOffset : integer; + inValue : real; + inDigits : integer; + inDecimals : integer; + inShowSign : integer; + inFontID : XPLMFontID); +{$IFDEF DELPHI} + cdecl; external 'XPLM.DLL'; +{$ELSE} + cdecl; external ''; +{$ENDIF} + + { + XPLMGetFontDimensions + + This routine returns the width and height of a character in a given font. + It also tells you if the font only supports numeric digits. Pass NULL if + you don't need a given field. Note that for a proportional font the width + will be an arbitrary, hopefully average width. + } + PROCEDURE XPLMGetFontDimensions( + inFontID : XPLMFontID; + outCharWidth : Pinteger; { Can be nil } + outCharHeight : Pinteger; { Can be nil } + outDigitsOnly : Pinteger); { Can be nil } +{$IFDEF DELPHI} + cdecl; external 'XPLM.DLL'; +{$ELSE} + cdecl; external ''; +{$ENDIF} + +{$IFDEF XPLM200} + { + XPLMMeasureString + + This routine returns the width in pixels of a string using a given font. + The string is passed as a pointer plus length (and does not need to be null + terminated); this is used to allow for measuring substrings. The return + value is floating point; it is possible that future font drawing may allow + for fractional pixels. + } + FUNCTION XPLMMeasureString( + inFontID : XPLMFontID; + inChar : Pchar; + inNumChars : integer) : single; +{$IFDEF DELPHI} + cdecl; external 'XPLM.DLL'; +{$ELSE} + cdecl; external ''; +{$ENDIF} +{$ENDIF} + +IMPLEMENTATION +END. diff --git a/GermanAirlinesVA-GAConnector/XPSDK/Delphi/XPLM/XPLMMenus.pas b/GermanAirlinesVA-GAConnector/XPSDK/Delphi/XPLM/XPLMMenus.pas new file mode 100644 index 0000000..d113952 --- /dev/null +++ b/GermanAirlinesVA-GAConnector/XPSDK/Delphi/XPLM/XPLMMenus.pas @@ -0,0 +1,259 @@ +{ + Copyright 2005-2012 Sandy Barbour and Ben Supnik + + All rights reserved. See license.txt for usage. + + X-Plane SDK Version: 2.1.1 +} + +UNIT XPLMMenus; +INTERFACE +{ + XPLMMenus - Theory of Operation + + Plug-ins can create menus in the menu bar of X-Plane. This is done by + creating a menu and then creating items. Menus are referred to by an + opaque ID. Items are referred to by index number. For each menu and item + you specify a void *. Per menu you specify a handler function that is + called with each void * when the menu item is picked. Menu item indices + are zero based. +} + +USES XPLMDefs; + {$A4} +{$IFDEF MSWINDOWS} + {$DEFINE DELPHI} +{$ENDIF} +{___________________________________________________________________________ + * XPLM MENUS + ___________________________________________________________________________} +{ + +} + + + + { + XPLMMenuCheck + + These enumerations define the various 'check' states for an X-Plane menu. + 'checking' in x-plane actually appears as a light which may or may not be + lit. So there are three possible states. + } +TYPE + XPLMMenuCheck = ( + { there is no symbol to the left of the menu item. } + xplm_Menu_NoCheck = 0 + + { the menu has a mark next to it that is unmarked (not lit). } + ,xplm_Menu_Unchecked = 1 + + { the menu has a mark next to it that is checked (lit). } + ,xplm_Menu_Checked = 2 + + ); + PXPLMMenuCheck = ^XPLMMenuCheck; + + { + XPLMMenuID + + This is a unique ID for each menu you create. + } + XPLMMenuID = pointer; + PXPLMMenuID = ^XPLMMenuID; + + { + XPLMMenuHandler_f + + A menu handler function takes two reference pointers, one for the menu + (specified when the menu was created) and one for the item (specified when + the item was created). + } + XPLMMenuHandler_f = PROCEDURE( + inMenuRef : pointer; + inItemRef : pointer); cdecl; + + { + XPLMFindPluginsMenu + + This function returns the ID of the plug-ins menu, which is created for you + at startup. + } + FUNCTION XPLMFindPluginsMenu: XPLMMenuID; +{$IFDEF DELPHI} + cdecl; external 'XPLM.DLL'; +{$ELSE} + cdecl; external ''; +{$ENDIF} + + { + XPLMCreateMenu + + This function creates a new menu and returns its ID. It returns NULL if + the menu cannot be created. Pass in a parent menu ID and an item index to + create a submenu, or NULL for the parent menu to put the menu in the menu + bar. The menu's name is only used if the menu is in the menubar. You also + pass a handler function and a menu reference value. Pass NULL for the + handler if you do not need callbacks from the menu (for example, if it only + contains submenus). + + Important: you must pass a valid, non-empty menu title even if the menu is + a submenu where the title is not visible. + } + FUNCTION XPLMCreateMenu( + inName : Pchar; + inParentMenu : XPLMMenuID; + inParentItem : integer; + inHandler : XPLMMenuHandler_f; + inMenuRef : pointer) : XPLMMenuID; +{$IFDEF DELPHI} + cdecl; external 'XPLM.DLL'; +{$ELSE} + cdecl; external ''; +{$ENDIF} + + { + XPLMDestroyMenu + + This function destroys a menu that you have created. Use this to remove a + submenu if necessary. (Normally this function will not be necessary.) + } + PROCEDURE XPLMDestroyMenu( + inMenuID : XPLMMenuID); +{$IFDEF DELPHI} + cdecl; external 'XPLM.DLL'; +{$ELSE} + cdecl; external ''; +{$ENDIF} + + { + XPLMClearAllMenuItems + + This function removes all menu items from a menu, allowing you to rebuild + it. Use this function if you need to change the number of items on a menu. + } + PROCEDURE XPLMClearAllMenuItems( + inMenuID : XPLMMenuID); +{$IFDEF DELPHI} + cdecl; external 'XPLM.DLL'; +{$ELSE} + cdecl; external ''; +{$ENDIF} + + { + XPLMAppendMenuItem + + This routine appends a new menu item to the bottom of a menu and returns + its index. Pass in the menu to add the item to, the items name, and a void + * ref for this item. If you pass in inForceEnglish, this menu item will be + drawn using the english character set no matter what language x-plane is + running in. Otherwise the menu item will be drawn localized. (An example + of why you'd want to do this is for a proper name.) See XPLMUtilities for + determining the current langauge. + } + FUNCTION XPLMAppendMenuItem( + inMenu : XPLMMenuID; + inItemName : Pchar; + inItemRef : pointer; + inForceEnglish : integer) : integer; +{$IFDEF DELPHI} + cdecl; external 'XPLM.DLL'; +{$ELSE} + cdecl; external ''; +{$ENDIF} + + { + XPLMAppendMenuSeparator + + This routine adds a seperator to the end of a menu. + } + PROCEDURE XPLMAppendMenuSeparator( + inMenu : XPLMMenuID); +{$IFDEF DELPHI} + cdecl; external 'XPLM.DLL'; +{$ELSE} + cdecl; external ''; +{$ENDIF} + + { + XPLMSetMenuItemName + + This routine changes the name of an existing menu item. Pass in the menu + ID and the index of the menu item. + } + PROCEDURE XPLMSetMenuItemName( + inMenu : XPLMMenuID; + inIndex : integer; + inItemName : Pchar; + inForceEnglish : integer); +{$IFDEF DELPHI} + cdecl; external 'XPLM.DLL'; +{$ELSE} + cdecl; external ''; +{$ENDIF} + + { + XPLMCheckMenuItem + + Set whether a menu item is checked. Pass in the menu ID and item index. + } + PROCEDURE XPLMCheckMenuItem( + inMenu : XPLMMenuID; + index : integer; + inCheck : XPLMMenuCheck); +{$IFDEF DELPHI} + cdecl; external 'XPLM.DLL'; +{$ELSE} + cdecl; external ''; +{$ENDIF} + + { + XPLMCheckMenuItemState + + This routine returns whether a menu item is checked or not. A menu item's + check mark may be on or off, or a menu may not have an icon at all. + } + PROCEDURE XPLMCheckMenuItemState( + inMenu : XPLMMenuID; + index : integer; + outCheck : PXPLMMenuCheck); +{$IFDEF DELPHI} + cdecl; external 'XPLM.DLL'; +{$ELSE} + cdecl; external ''; +{$ENDIF} + + { + XPLMEnableMenuItem + + Sets whether this menu item is enabled. Items start out enabled. + } + PROCEDURE XPLMEnableMenuItem( + inMenu : XPLMMenuID; + index : integer; + enabled : integer); +{$IFDEF DELPHI} + cdecl; external 'XPLM.DLL'; +{$ELSE} + cdecl; external ''; +{$ENDIF} + +{$IFDEF XPLM210} + { + XPLMRemoveMenuItem + + Removes one item from a menu. Note that all menu items below are moved up + one; your plugin must track the change in index numbers. + } + PROCEDURE XPLMRemoveMenuItem( + inMenu : XPLMMenuID; + inIndex : integer); +{$IFDEF DELPHI} + cdecl; external 'XPLM.DLL'; +{$ELSE} + cdecl; external ''; +{$ENDIF} +{$ENDIF} + +IMPLEMENTATION +END. diff --git a/GermanAirlinesVA-GAConnector/XPSDK/Delphi/XPLM/XPLMNavigation.pas b/GermanAirlinesVA-GAConnector/XPSDK/Delphi/XPLM/XPLMNavigation.pas new file mode 100644 index 0000000..993ef58 --- /dev/null +++ b/GermanAirlinesVA-GAConnector/XPSDK/Delphi/XPLM/XPLMNavigation.pas @@ -0,0 +1,434 @@ +{ + Copyright 2005-2012 Sandy Barbour and Ben Supnik + + All rights reserved. See license.txt for usage. + + X-Plane SDK Version: 2.1.1 +} + +UNIT XPLMNavigation; +INTERFACE +{ + XPLMNavigation - THEORY OF OPERATION + + The XPLM Navigation APIs give you some access to the navigation databases + inside X-Plane. X-Plane stores all navigation information in RAM, so by + using these APIs you can gain access to most information without having to + go to disk or parse the files yourself. + + You can also use this API to program the FMS. You must use the navigation + APIs to find the nav-aids you want to program into the FMS, since the FMS + is powered internally by x-plane's navigation database. +} + +USES XPLMDefs; + {$A4} +{$IFDEF MSWINDOWS} + {$DEFINE DELPHI} +{$ENDIF} +{___________________________________________________________________________ + * NAVIGATION DATABASE ACCESS + ___________________________________________________________________________} +{ + +} + + + + { + XPLMNavType + + These enumerations define the different types of navaids. They are each + defined with a separate bit so that they may be bit-wise added together to + form sets of nav-aid types. + + NOTE: xplm_Nav_LatLon is a specific lat-lon coordinate entered into the + FMS. It will not exist in the database, and cannot be programmed into the + FMS. Querying the FMS for navaids will return it. Use + XPLMSetFMSEntryLatLon to set a lat/lon waypoint. + } +TYPE + XPLMNavType = ( + xplm_Nav_Unknown = 0 + + ,xplm_Nav_Airport = 1 + + ,xplm_Nav_NDB = 2 + + ,xplm_Nav_VOR = 4 + + ,xplm_Nav_ILS = 8 + + ,xplm_Nav_Localizer = 16 + + ,xplm_Nav_GlideSlope = 32 + + ,xplm_Nav_OuterMarker = 64 + + ,xplm_Nav_MiddleMarker = 128 + + ,xplm_Nav_InnerMarker = 256 + + ,xplm_Nav_Fix = 512 + + ,xplm_Nav_DME = 1024 + + ,xplm_Nav_LatLon = 2048 + + ); + PXPLMNavType = ^XPLMNavType; + + { + XPLMNavRef + + XPLMNavRef is an iterator into the navigation database. The navigation + database is essentially an array, but it is not necessarily densely + populated. The only assumption you can safely make is that like-typed + nav-aids are grouped together. + + Use XPLMNavRef to refer to a nav-aid. + + XPLM_NAV_NOT_FOUND is returned by functions that return an XPLMNavRef when + the iterator must be invalid. + } + XPLMNavRef = integer; + PXPLMNavRef = ^XPLMNavRef; + +CONST + XPLM_NAV_NOT_FOUND = -1; + + { + XPLMGetFirstNavAid + + This returns the very first navaid in the database. Use this to traverse + the entire database. Returns XPLM_NAV_NOT_FOUND if the nav database is + empty. + } + FUNCTION XPLMGetFirstNavAid: XPLMNavRef; +{$IFDEF DELPHI} + cdecl; external 'XPLM.DLL'; +{$ELSE} + cdecl; external ''; +{$ENDIF} + + { + XPLMGetNextNavAid + + Given a nav aid ref, this routine returns the next navaid. It returns + XPLM_NAV_NOT_FOUND if the nav aid passed in was invalid or if the navaid + passed in was the last one in the database. Use this routine to iterate + across all like-typed navaids or the entire database. + + WARNING: due to a bug in the SDK, when fix loading is disabled in the + rendering settings screen, calling this routine with the last airport + returns a bogus nav aid. Using this nav aid can crash x-plane. + } + FUNCTION XPLMGetNextNavAid( + inNavAidRef : XPLMNavRef) : XPLMNavRef; +{$IFDEF DELPHI} + cdecl; external 'XPLM.DLL'; +{$ELSE} + cdecl; external ''; +{$ENDIF} + + { + XPLMFindFirstNavAidOfType + + This routine returns the ref of the first navaid of the given type in the + database or XPLM_NAV_NOT_FOUND if there are no navaids of that type in the + database. You must pass exactly one nav aid type to this routine. + + WARNING: due to a bug in the SDK, when fix loading is disabled in the + rendering settings screen, calling this routine with fixes returns a bogus + nav aid. Using this nav aid can crash x-plane. + } + FUNCTION XPLMFindFirstNavAidOfType( + inType : XPLMNavType) : XPLMNavRef; +{$IFDEF DELPHI} + cdecl; external 'XPLM.DLL'; +{$ELSE} + cdecl; external ''; +{$ENDIF} + + { + XPLMFindLastNavAidOfType + + This routine returns the ref of the last navaid of the given type in the + database or XPLM_NAV_NOT_FOUND if there are no navaids of that type in the + database. You must pass exactly one nav aid type to this routine. + + WARNING: due to a bug in the SDK, when fix loading is disabled in the + rendering settings screen, calling this routine with fixes returns a bogus + nav aid. Using this nav aid can crash x-plane. + } + FUNCTION XPLMFindLastNavAidOfType( + inType : XPLMNavType) : XPLMNavRef; +{$IFDEF DELPHI} + cdecl; external 'XPLM.DLL'; +{$ELSE} + cdecl; external ''; +{$ENDIF} + + { + XPLMFindNavAid + + This routine provides a number of searching capabilities for the nav + database. XPLMFindNavAid will search through every nav aid whose type is + within inType (multiple types may be added together) and return any + nav-aids found based on the following rules: + + If inLat and inLon are not NULL, the navaid nearest to that lat/lon will be + returned, otherwise the last navaid found will be returned. + + If inFrequency is not NULL, then any navaids considered must match this + frequency. Note that this will screen out radio beacons that do not have + frequency data published (like inner markers) but not fixes and airports. + + If inNameFragment is not NULL, only navaids that contain the fragment in + their name will be returned. + + If inIDFragment is not NULL, only navaids that contain the fragment in + their IDs will be returned. + + This routine provides a simple way to do a number of useful searches: + + Find the nearest navaid on this frequency. Find the nearest airport. Find + the VOR whose ID is "KBOS". Find the nearest airport whose name contains + "Chicago". + } + FUNCTION XPLMFindNavAid( + inNameFragment : Pchar; { Can be nil } + inIDFragment : Pchar; { Can be nil } + inLat : Psingle; { Can be nil } + inLon : Psingle; { Can be nil } + inFrequency : Pinteger; { Can be nil } + inType : XPLMNavType) : XPLMNavRef; +{$IFDEF DELPHI} + cdecl; external 'XPLM.DLL'; +{$ELSE} + cdecl; external ''; +{$ENDIF} + + { + XPLMGetNavAidInfo + + This routine returns information about a navaid. Any non-null field is + filled out with information if it is available. + + Frequencies are in the nav.dat convention as described in the X-Plane nav + database FAQ: NDB frequencies are exact, all others are multiplied by 100. + + The buffer for IDs should be at least 6 chars and the buffer for names + should be at least 41 chars, but since these values are likely to go up, I + recommend passing at least 32 chars for IDs and 256 chars for names when + possible. + + The outReg parameter tells if the navaid is within the local "region" of + loaded DSFs. (This information may not be particularly useful to plugins.) + The parameter is a single byte value 1 for true or 0 for false, not a C + string. + } + PROCEDURE XPLMGetNavAidInfo( + inRef : XPLMNavRef; + outType : PXPLMNavType; { Can be nil } + outLatitude : Psingle; { Can be nil } + outLongitude : Psingle; { Can be nil } + outHeight : Psingle; { Can be nil } + outFrequency : Pinteger; { Can be nil } + outHeading : Psingle; { Can be nil } + outID : Pchar; { Can be nil } + outName : Pchar; { Can be nil } + outReg : Pchar); { Can be nil } +{$IFDEF DELPHI} + cdecl; external 'XPLM.DLL'; +{$ELSE} + cdecl; external ''; +{$ENDIF} + +{___________________________________________________________________________ + * FLIGHT MANAGEMENT COMPUTER + ___________________________________________________________________________} +{ + Note: the FMS works based on an array of entries. Indices into the array + are zero-based. Each entry is a nav-aid plus an altitude. The FMS tracks + the currently displayed entry and the entry that it is flying to. + + The FMS must be programmed with contiguous entries, so clearing an entry at + the end shortens the effective flight plan. There is a max of 100 + waypoints in the flight plan. +} + + + + { + XPLMCountFMSEntries + + This routine returns the number of entries in the FMS. + } + FUNCTION XPLMCountFMSEntries: integer; +{$IFDEF DELPHI} + cdecl; external 'XPLM.DLL'; +{$ELSE} + cdecl; external ''; +{$ENDIF} + + { + XPLMGetDisplayedFMSEntry + + This routine returns the index of the entry the pilot is viewing. + } + FUNCTION XPLMGetDisplayedFMSEntry: integer; +{$IFDEF DELPHI} + cdecl; external 'XPLM.DLL'; +{$ELSE} + cdecl; external ''; +{$ENDIF} + + { + XPLMGetDestinationFMSEntry + + This routine returns the index of the entry the FMS is flying to. + } + FUNCTION XPLMGetDestinationFMSEntry: integer; +{$IFDEF DELPHI} + cdecl; external 'XPLM.DLL'; +{$ELSE} + cdecl; external ''; +{$ENDIF} + + { + XPLMSetDisplayedFMSEntry + + This routine changes which entry the FMS is showing to the index specified. + } + PROCEDURE XPLMSetDisplayedFMSEntry( + inIndex : integer); +{$IFDEF DELPHI} + cdecl; external 'XPLM.DLL'; +{$ELSE} + cdecl; external ''; +{$ENDIF} + + { + XPLMSetDestinationFMSEntry + + This routine changes which entry the FMS is flying the aircraft toward. + } + PROCEDURE XPLMSetDestinationFMSEntry( + inIndex : integer); +{$IFDEF DELPHI} + cdecl; external 'XPLM.DLL'; +{$ELSE} + cdecl; external ''; +{$ENDIF} + + { + XPLMGetFMSEntryInfo + + This routine returns information about a given FMS entry. A reference to a + navaid can be returned allowing you to find additional information (such as + a frequency, ILS heading, name, etc.). Some information is available + immediately. For a lat/lon entry, the lat/lon is returned by this routine + but the navaid cannot be looked up (and the reference will be + XPLM_NAV_NOT_FOUND. FMS name entry buffers should be at least 256 chars in + length. + } + PROCEDURE XPLMGetFMSEntryInfo( + inIndex : integer; + outType : PXPLMNavType; { Can be nil } + outID : Pchar; { Can be nil } + outRef : PXPLMNavRef; { Can be nil } + outAltitude : Pinteger; { Can be nil } + outLat : Psingle; { Can be nil } + outLon : Psingle); { Can be nil } +{$IFDEF DELPHI} + cdecl; external 'XPLM.DLL'; +{$ELSE} + cdecl; external ''; +{$ENDIF} + + { + XPLMSetFMSEntryInfo + + This routine changes an entry in the FMS to have the destination navaid + passed in and the altitude specified. Use this only for airports, fixes, + and radio-beacon navaids. Currently of radio beacons, the FMS can only + support VORs and NDBs. Use the routines below to clear or fly to a lat/lon. + } + PROCEDURE XPLMSetFMSEntryInfo( + inIndex : integer; + inRef : XPLMNavRef; + inAltitude : integer); +{$IFDEF DELPHI} + cdecl; external 'XPLM.DLL'; +{$ELSE} + cdecl; external ''; +{$ENDIF} + + { + XPLMSetFMSEntryLatLon + + This routine changes the entry in the FMS to a lat/lon entry with the given + coordinates. + } + PROCEDURE XPLMSetFMSEntryLatLon( + inIndex : integer; + inLat : single; + inLon : single; + inAltitude : integer); +{$IFDEF DELPHI} + cdecl; external 'XPLM.DLL'; +{$ELSE} + cdecl; external ''; +{$ENDIF} + + { + XPLMClearFMSEntry + + This routine clears the given entry, potentially shortening the flight + plan. + } + PROCEDURE XPLMClearFMSEntry( + inIndex : integer); +{$IFDEF DELPHI} + cdecl; external 'XPLM.DLL'; +{$ELSE} + cdecl; external ''; +{$ENDIF} + +{___________________________________________________________________________ + * GPS RECEIVER + ___________________________________________________________________________} +{ + These APIs let you read data from the GPS unit. +} + + + + { + XPLMGetGPSDestinationType + + This routine returns the type of the currently selected GPS destination, + one of fix, airport, VOR or NDB. + } + FUNCTION XPLMGetGPSDestinationType: XPLMNavType; +{$IFDEF DELPHI} + cdecl; external 'XPLM.DLL'; +{$ELSE} + cdecl; external ''; +{$ENDIF} + + { + XPLMGetGPSDestination + + This routine returns the current GPS destination. + } + FUNCTION XPLMGetGPSDestination: XPLMNavRef; +{$IFDEF DELPHI} + cdecl; external 'XPLM.DLL'; +{$ELSE} + cdecl; external ''; +{$ENDIF} + +IMPLEMENTATION +END. diff --git a/GermanAirlinesVA-GAConnector/XPSDK/Delphi/XPLM/XPLMPlanes.pas b/GermanAirlinesVA-GAConnector/XPSDK/Delphi/XPLM/XPLMPlanes.pas new file mode 100644 index 0000000..b5d19a2 --- /dev/null +++ b/GermanAirlinesVA-GAConnector/XPSDK/Delphi/XPLM/XPLMPlanes.pas @@ -0,0 +1,294 @@ +{ + Copyright 2005-2012 Sandy Barbour and Ben Supnik + + All rights reserved. See license.txt for usage. + + X-Plane SDK Version: 2.1.1 +} + +UNIT XPLMPlanes; +INTERFACE +{ + The XPLMPlanes APIs allow you to control the various aircraft in x-plane, + both the user's and the sim's. +} + +USES XPLMDefs; + {$A4} +{$IFDEF MSWINDOWS} + {$DEFINE DELPHI} +{$ENDIF} +{___________________________________________________________________________ + * USER AIRCRAFT ACCESS + ___________________________________________________________________________} +{ + +} + + + { + XPLMSetUsersAircraft + + This routine changes the user's aircraft. Note that this will reinitialize + the user to be on the nearest airport's first runway. Pass in a full path + (hard drive and everything including the .acf extension) to the .acf file. + } + PROCEDURE XPLMSetUsersAircraft( + inAircraftPath : Pchar); +{$IFDEF DELPHI} + cdecl; external 'XPLM.DLL'; +{$ELSE} + cdecl; external ''; +{$ENDIF} + { + XPLMPlaceUserAtAirport + + This routine places the user at a given airport. Specify the airport by + its ICAO code (e.g. 'KBOS'). + } + PROCEDURE XPLMPlaceUserAtAirport( + inAirportCode : Pchar); +{$IFDEF DELPHI} + cdecl; external 'XPLM.DLL'; +{$ELSE} + cdecl; external ''; +{$ENDIF} +{___________________________________________________________________________ + * GLOBAL AIRCRAFT ACCESS + ___________________________________________________________________________} +{ + +} + + +CONST + { The user's aircraft is always index 0. } + XPLM_USER_AIRCRAFT = 0; + { + XPLMPlaneDrawState_t + + This structure contains additional plane parameter info to be passed to + draw plane. Make sure to fill in the size of the structure field with + sizeof(XPLMDrawPlaneState_t) so that the XPLM can tell how many fields you + knew about when compiling your plugin (since more fields may be added + later). + + Most of these fields are ratios from 0 to 1 for control input. X-Plane + calculates what the actual controls look like based on the .acf file for + that airplane. Note for the yoke inputs, this is what the pilot of the + plane has commanded (post artificial stability system if there were one) + and affects aelerons, rudder, etc. It is not necessarily related to the + actual position of the plane! + } +TYPE + XPLMPlaneDrawState_t = RECORD + { The size of the draw state struct. } + structSize : integer; + { A ratio from [0..1] describing how far the landing gear is extended. } + gearPosition : single; + { Ratio of flap deployment, 0 = up, 1 = full deploy. } + flapRatio : single; + { Ratio of spoiler deployment, 0 = none, 1 = full deploy. } + spoilerRatio : single; + { Ratio of speed brake deployment, 0 = none, 1 = full deploy. } + speedBrakeRatio : single; + { Ratio of slat deployment, 0 = none, 1 = full deploy. } + slatRatio : single; + { Wing sweep ratio, 0 = forward, 1 = swept. } + wingSweep : single; + { Thrust power, 0 = none, 1 = full fwd, -1 = full reverse. } + thrust : single; + { Total pitch input for this plane. } + yokePitch : single; + { Total Heading input for this plane. } + yokeHeading : single; + { Total Roll input for this plane. } + yokeRoll : single; + END; + PXPLMPlaneDrawState_t = ^XPLMPlaneDrawState_t; + { + XPLMCountAircraft + + This function returns the number of aircraft X-Plane is capable of having, + as well as the number of aircraft that are currently active. These numbers + count the user's aircraft. It can also return the plugin that is currently + controlling aircraft. In X-Plane 7, this routine reflects the number of + aircraft the user has enabled in the rendering options window. + } + PROCEDURE XPLMCountAircraft( + outTotalAircraft : Pinteger; + outActiveAircraft : Pinteger; + outController : PXPLMPluginID); +{$IFDEF DELPHI} + cdecl; external 'XPLM.DLL'; +{$ELSE} + cdecl; external ''; +{$ENDIF} + { + XPLMGetNthAircraftModel + + This function returns the aircraft model for the Nth aircraft. Indices are + zero based, with zero being the user's aircraft. The file name should be + at least 256 chars in length; the path should be at least 512 chars in + length. + } + PROCEDURE XPLMGetNthAircraftModel( + inIndex : integer; + outFileName : Pchar; + outPath : Pchar); +{$IFDEF DELPHI} + cdecl; external 'XPLM.DLL'; +{$ELSE} + cdecl; external ''; +{$ENDIF} +{___________________________________________________________________________ + * EXCLUSIVE AIRCRAFT ACCESS + ___________________________________________________________________________} +{ + The following routines require exclusive access to the airplane APIs. Only + one plugin may have this access at a time. +} + + + + { + XPLMPlanesAvailable_f + + Your airplanes available callback is called when another plugin gives up + access to the multiplayer planes. Use this to wait for access to + multiplayer. + } +TYPE + XPLMPlanesAvailable_f = PROCEDURE( + inRefcon : pointer); cdecl; + + { + XPLMAcquirePlanes + + XPLMAcquirePlanes grants your plugin exclusive access to the aircraft. It + returns 1 if you gain access, 0 if you do not. inAircraft - pass in an + array of pointers to strings specifying the planes you want loaded. For + any plane index you do not want loaded, pass a 0-length string. Other + strings should be full paths with the .acf extension. NULL terminates this + array, or pass NULL if there are no planes you want loaded. If you pass in + a callback and do not receive access to the planes your callback will be + called when the airplanes are available. If you do receive airplane access, + your callback will not be called. + } + FUNCTION XPLMAcquirePlanes( + inAircraft : PPchar; { Can be nil } + inCallback : XPLMPlanesAvailable_f; + inRefcon : pointer) : integer; +{$IFDEF DELPHI} + cdecl; external 'XPLM.DLL'; +{$ELSE} + cdecl; external ''; +{$ENDIF} + + { + XPLMReleasePlanes + + Call this function to release access to the planes. Note that if you are + disabled, access to planes is released for you and you must reacquire it. + } + PROCEDURE XPLMReleasePlanes; +{$IFDEF DELPHI} + cdecl; external 'XPLM.DLL'; +{$ELSE} + cdecl; external ''; +{$ENDIF} + + { + XPLMSetActiveAircraftCount + + This routine sets the number of active planes. If you pass in a number + higher than the total number of planes availables, only the total number of + planes available is actually used. + } + PROCEDURE XPLMSetActiveAircraftCount( + inCount : integer); +{$IFDEF DELPHI} + cdecl; external 'XPLM.DLL'; +{$ELSE} + cdecl; external ''; +{$ENDIF} + + { + XPLMSetAircraftModel + + This routine loads an aircraft model. It may only be called if you have + exclusive access to the airplane APIs. Pass in the path of the model with + the .acf extension. The index is zero based, but you may not pass in 0 + (use XPLMSetUsersAircraft to load the user's aircracft). + } + PROCEDURE XPLMSetAircraftModel( + inIndex : integer; + inAircraftPath : Pchar); +{$IFDEF DELPHI} + cdecl; external 'XPLM.DLL'; +{$ELSE} + cdecl; external ''; +{$ENDIF} + + { + XPLMDisableAIForPlane + + This routine turns off X-Plane's AI for a given plane. The plane will + continue to draw and be a real plane in X-Plane, but will not move itself. + } + PROCEDURE XPLMDisableAIForPlane( + inPlaneIndex : integer); +{$IFDEF DELPHI} + cdecl; external 'XPLM.DLL'; +{$ELSE} + cdecl; external ''; +{$ENDIF} + + { + XPLMDrawAircraft + + This routine draws an aircraft. It can only be called from a 3-d drawing + callback. Pass in the position of the plane in OpenGL local coordinates + and the orientation of the plane. A 1 for full drawing indicates that the + whole plane must be drawn; a 0 indicates you only need the nav lights + drawn. (This saves rendering time when planes are far away.) + } + PROCEDURE XPLMDrawAircraft( + inPlaneIndex : integer; + inX : single; + inY : single; + inZ : single; + inPitch : single; + inRoll : single; + inYaw : single; + inFullDraw : integer; + inDrawStateInfo : PXPLMPlaneDrawState_t); +{$IFDEF DELPHI} + cdecl; external 'XPLM.DLL'; +{$ELSE} + cdecl; external ''; +{$ENDIF} + + { + XPLMReinitUsersPlane + + This function recomputes the derived flight model data from the aircraft + structure in memory. If you have used the data access layer to modify the + aircraft structure, use this routine to resynchronize x-plane; since + X-plane works at least partly from derived values, the sim will not behave + properly until this is called. + + WARNING: this routine does not necessarily place the airplane at the + airport; use XPLMSetUsersAircraft to be compatible. This routine is + provided to do special experimentation with flight models without resetting + flight. + } + PROCEDURE XPLMReinitUsersPlane; +{$IFDEF DELPHI} + cdecl; external 'XPLM.DLL'; +{$ELSE} + cdecl; external ''; +{$ENDIF} + +IMPLEMENTATION +END. diff --git a/GermanAirlinesVA-GAConnector/XPSDK/Delphi/XPLM/XPLMPlugin.pas b/GermanAirlinesVA-GAConnector/XPSDK/Delphi/XPLM/XPLMPlugin.pas new file mode 100644 index 0000000..f053f80 --- /dev/null +++ b/GermanAirlinesVA-GAConnector/XPSDK/Delphi/XPLM/XPLMPlugin.pas @@ -0,0 +1,381 @@ +{ + Copyright 2005-2012 Sandy Barbour and Ben Supnik + + All rights reserved. See license.txt for usage. + + X-Plane SDK Version: 2.1.1 +} + +UNIT XPLMPlugin; +INTERFACE +{ + These APIs provide facilities to find and work with other plugins and + manage other plugins. +} + +USES XPLMDefs; + {$A4} +{$IFDEF MSWINDOWS} + {$DEFINE DELPHI} +{$ENDIF} +{___________________________________________________________________________ + * FINDING PLUGINS + ___________________________________________________________________________} +{ + These APIs allow you to find another plugin or yourself, or iterate across + all plugins. For example, if you wrote an FMS plugin that needed to talk + to an autopilot plugin, you could use these APIs to locate the autopilot + plugin. +} + + + + { + XPLMGetMyID + + This routine returns the plugin ID of the calling plug-in. Call this to + get your own ID. + } + FUNCTION XPLMGetMyID: XPLMPluginID; +{$IFDEF DELPHI} + cdecl; external 'XPLM.DLL'; +{$ELSE} + cdecl; external ''; +{$ENDIF} + + { + XPLMCountPlugins + + This routine returns the total number of plug-ins that are loaded, both + disabled and enabled. + } + FUNCTION XPLMCountPlugins: integer; +{$IFDEF DELPHI} + cdecl; external 'XPLM.DLL'; +{$ELSE} + cdecl; external ''; +{$ENDIF} + + { + XPLMGetNthPlugin + + This routine returns the ID of a plug-in by index. Index is 0 based from 0 + to XPLMCountPlugins-1, inclusive. Plugins may be returned in any arbitrary + order. + } + FUNCTION XPLMGetNthPlugin( + inIndex : integer) : XPLMPluginID; +{$IFDEF DELPHI} + cdecl; external 'XPLM.DLL'; +{$ELSE} + cdecl; external ''; +{$ENDIF} + + { + XPLMFindPluginByPath + + This routine returns the plug-in ID of the plug-in whose file exists at the + passed in absolute file system path. XPLM_NO_PLUGIN_ID is returned if the + path does not point to a currently loaded plug-in. + } + FUNCTION XPLMFindPluginByPath( + inPath : Pchar) : XPLMPluginID; +{$IFDEF DELPHI} + cdecl; external 'XPLM.DLL'; +{$ELSE} + cdecl; external ''; +{$ENDIF} + + { + XPLMFindPluginBySignature + + This routine returns the plug-in ID of the plug-in whose signature matches + what is passed in or XPLM_NO_PLUGIN_ID if no running plug-in has this + signature. Signatures are the best way to identify another plug-in as they + are independent of the file system path of a plug-in or the human-readable + plug-in name, and should be unique for all plug-ins. Use this routine to + locate another plugin that your plugin interoperates with + } + FUNCTION XPLMFindPluginBySignature( + inSignature : Pchar) : XPLMPluginID; +{$IFDEF DELPHI} + cdecl; external 'XPLM.DLL'; +{$ELSE} + cdecl; external ''; +{$ENDIF} + + { + XPLMGetPluginInfo + + This routine returns information about a plug-in. Each parameter should be + a pointer to a buffer of at least 256 characters, or NULL to not receive + the information. + + outName - the human-readable name of the plug-in. outFilePath - the + absolute file path to the file that contains this plug-in. outSignature - a + unique string that identifies this plug-in. outDescription - a + human-readable description of this plug-in. + } + PROCEDURE XPLMGetPluginInfo( + inPlugin : XPLMPluginID; + outName : Pchar; { Can be nil } + outFilePath : Pchar; { Can be nil } + outSignature : Pchar; { Can be nil } + outDescription : Pchar); { Can be nil } +{$IFDEF DELPHI} + cdecl; external 'XPLM.DLL'; +{$ELSE} + cdecl; external ''; +{$ENDIF} + +{___________________________________________________________________________ + * ENABLING/DISABLING PLUG-INS + ___________________________________________________________________________} +{ + These routines are used to work with plug-ins and manage them. Most + plugins will not need to use these APIs. +} + + + + { + XPLMIsPluginEnabled + + Returns whether the specified plug-in is enabled for running. + } + FUNCTION XPLMIsPluginEnabled( + inPluginID : XPLMPluginID) : integer; +{$IFDEF DELPHI} + cdecl; external 'XPLM.DLL'; +{$ELSE} + cdecl; external ''; +{$ENDIF} + + { + XPLMEnablePlugin + + This routine enables a plug-in if it is not already enabled. It returns 1 + if the plugin was enabled or successfully enables itself, 0 if it does not. + Plugins may fail to enable (for example, if resources cannot be acquired) + by returning 0 from their XPluginEnable callback. + } + FUNCTION XPLMEnablePlugin( + inPluginID : XPLMPluginID) : integer; +{$IFDEF DELPHI} + cdecl; external 'XPLM.DLL'; +{$ELSE} + cdecl; external ''; +{$ENDIF} + + { + XPLMDisablePlugin + + This routine disableds an enabled plug-in. + } + PROCEDURE XPLMDisablePlugin( + inPluginID : XPLMPluginID); +{$IFDEF DELPHI} + cdecl; external 'XPLM.DLL'; +{$ELSE} + cdecl; external ''; +{$ENDIF} + + { + XPLMReloadPlugins + + This routine reloads all plug-ins. Once this routine is called and you + return from the callback you were within (e.g. a menu select callback) you + will receive your XPluginDisable and XPluginStop callbacks and your DLL + will be unloaded, then the start process happens as if the sim was starting + up. + } + PROCEDURE XPLMReloadPlugins; +{$IFDEF DELPHI} + cdecl; external 'XPLM.DLL'; +{$ELSE} + cdecl; external ''; +{$ENDIF} + +{___________________________________________________________________________ + * INTERPLUGIN MESSAGING + ___________________________________________________________________________} +{ + Plugin messages are defined as 32-bit integers. Messages below 0x00FFFFFF + are reserved for X-Plane and the plugin SDK. + + Messages have two conceptual uses: notifications and commands. Commands + are sent from one plugin to another to induce behavior; notifications are + sent from one plugin to all others for informational purposes. It is + important that commands and notifications not have the same values because + this could cause a notification sent by one plugin to accidentally induce a + command in another. + + By convention, plugin-defined notifications should have the high bit set + (e.g. be greater or equal to unsigned 0x8000000) while commands should have + this bit be cleared. + + The following messages are sent to your plugin by x-plane. +} + + + +CONST + { This message is sent to your plugin whenever the user's plane crashes. } + XPLM_MSG_PLANE_CRASHED = 101; + + { This message is sent to your plugin whenever a new plane is loaded. The } + { parameter is the number of the plane being loaded; 0 indicates the user's } + { plane. } + XPLM_MSG_PLANE_LOADED = 102; + + { This messages is called whenever the user's plane is positioned at a new } + { airport. } + XPLM_MSG_AIRPORT_LOADED = 103; + + { This message is sent whenever new scenery is loaded. Use datarefs to } + { determine the new scenery files that were loaded. } + XPLM_MSG_SCENERY_LOADED = 104; + + { This message is sent whenever the user adjusts the number of X-Plane } + { aircraft models. You must use XPLMCountPlanes to find out how many planes } + { are now available. This message will only be sent in XP7 and higher } + { because in XP6 the number of aircraft is not user-adjustable. } + XPLM_MSG_AIRPLANE_COUNT_CHANGED = 105; + +{$IFDEF XPLM200} + { This message is sent to your plugin whenever a plane is unloaded. The } + { parameter is the number of the plane being unloaded; 0 indicates the user's } + { plane. The parameter is of type int, passed as the value of the pointer. } + { (That is: the parameter is an int, not a pointer to an int.) } + XPLM_MSG_PLANE_UNLOADED = 106; +{$ENDIF} + +{$IFDEF XPLM210} + { This message is sent to your plugin right before X-Plane writes its } + { preferences file. You can use this for two purposes: to write your own } + { preferences, and to modify any datarefs to influence preferences output. } + { For example, if your plugin temporarily modifies saved preferences, you can } + { put them back to their default values here to avoid having the tweaks be } + { persisted if your plugin is not loaded on the next invocation of X-Plane. } + XPLM_MSG_WILL_WRITE_PREFS = 107; +{$ENDIF} + +{$IFDEF XPLM210} + { This message is sent to your plugin right after a livery is loaded for an } + { airplane. You can use this to check the new livery (via datarefs) and } + { react accordingly. The parameter is of type int, passed as the value of a } + { pointer and represents the aicraft plane number - 0 is the user's plane. } + XPLM_MSG_LIVERY_LOADED = 108; +{$ENDIF} + + { + XPLMSendMessageToPlugin + + This function sends a message to another plug-in or X-Plane. Pass + XPLM_NO_PLUGIN_ID to broadcast to all plug-ins. Only enabled plug-ins with + a message receive function receive the message. + } + PROCEDURE XPLMSendMessageToPlugin( + inPlugin : XPLMPluginID; + inMessage : integer; + inParam : pointer); +{$IFDEF DELPHI} + cdecl; external 'XPLM.DLL'; +{$ELSE} + cdecl; external ''; +{$ENDIF} + +{$IFDEF XPLM200} +{___________________________________________________________________________ + * Plugin Features API + ___________________________________________________________________________} +{ + The plugin features API allows your plugin to "sign up" for additional + capabilities and plugin system features that are normally disabled for + backward compatibility. This allows advanced plugins to "opt-in" to new + behavior. + + Each feature is defined by a permanent string name. The feature string + names will vary with the particular installation of X-Plane, so plugins + should not expect a feature to be guaranteed present. +} + + + + + { + XPLMFeatureEnumerator_f + + You pass an XPLMFeatureEnumerator_f to get a list of all features supported + by a given version running version of X-Plane. This routine is called once + for each feature. + } +TYPE + XPLMFeatureEnumerator_f = PROCEDURE( + inFeature : Pchar; + inRef : pointer); cdecl; + + { + XPLMHasFeature + + This returns 1 if the given installation of X-Plane supports a feature, or + 0 if it does not. + } + FUNCTION XPLMHasFeature( + inFeature : Pchar) : integer; +{$IFDEF DELPHI} + cdecl; external 'XPLM.DLL'; +{$ELSE} + cdecl; external ''; +{$ENDIF} + + { + XPLMIsFeatureEnabled + + This returns 1 if a feature is currently enabled for your plugin, or 0 if + it is not enabled. It is an error to call this routine with an unsupported + feature. + } + FUNCTION XPLMIsFeatureEnabled( + inFeature : Pchar) : integer; +{$IFDEF DELPHI} + cdecl; external 'XPLM.DLL'; +{$ELSE} + cdecl; external ''; +{$ENDIF} + + { + XPLMEnableFeature + + This routine enables or disables a feature for your plugin. This will + change the running behavior of X-Plane and your plugin in some way, + depending on the feature. + } + PROCEDURE XPLMEnableFeature( + inFeature : Pchar; + inEnable : integer); +{$IFDEF DELPHI} + cdecl; external 'XPLM.DLL'; +{$ELSE} + cdecl; external ''; +{$ENDIF} + + { + XPLMEnumerateFeatures + + This routine calls your enumerator callback once for each feature that this + running version of X-Plane supports. Use this routine to determine all of + the features that X-Plane can support. + } + PROCEDURE XPLMEnumerateFeatures( + inEnumerator : XPLMFeatureEnumerator_f; + inRef : pointer); +{$IFDEF DELPHI} + cdecl; external 'XPLM.DLL'; +{$ELSE} + cdecl; external ''; +{$ENDIF} + +{$ENDIF} +IMPLEMENTATION +END. diff --git a/GermanAirlinesVA-GAConnector/XPSDK/Delphi/XPLM/XPLMProcessing.pas b/GermanAirlinesVA-GAConnector/XPSDK/Delphi/XPLM/XPLMProcessing.pas new file mode 100644 index 0000000..79c7b2e --- /dev/null +++ b/GermanAirlinesVA-GAConnector/XPSDK/Delphi/XPLM/XPLMProcessing.pas @@ -0,0 +1,276 @@ +{ + Copyright 2005-2012 Sandy Barbour and Ben Supnik + + All rights reserved. See license.txt for usage. + + X-Plane SDK Version: 2.1.1 +} + +UNIT XPLMProcessing; +INTERFACE +{ + This API allows you to get regular callbacks during the flight loop, the + part of X-Plane where the plane's position calculates the physics of + flight, etc. Use these APIs to accomplish periodic tasks like logging data + and performing I/O. + + WARNING: Do NOT use these callbacks to draw! You cannot draw during flight + loop callbacks. Use the drawing callbacks (see XPLMDisplay for more info) + for graphics. +} + +USES XPLMDefs; + {$A4} +{$IFDEF MSWINDOWS} + {$DEFINE DELPHI} +{$ENDIF} +{___________________________________________________________________________ + * FLIGHT LOOP CALLBACKS + ___________________________________________________________________________} +{ + +} + + + +{$IFDEF XPLM210} + { + XPLMFlightLoopPhaseType + + You can register a flight loop callback to run either before or after the + flight model is integrated by X-Plane. + } +TYPE + XPLMFlightLoopPhaseType = ( + { Your callback runs before X-Plane integrates the flight model. } + xplm_FlightLoop_Phase_BeforeFlightModel = 0 + + { Your callback runs after X-Plane integrates the flight model. } + ,xplm_FlightLoop_Phase_AfterFlightModel = 1 + + ); + PXPLMFlightLoopPhaseType = ^XPLMFlightLoopPhaseType; +{$ENDIF} + +{$IFDEF XPLM210} + { + XPLMFlightLoopID + + This is an opaque identifier for a flight loop callback. You can use this + identifier to easily track and remove your callbacks, or to use the new + flight loop APIs. + } + XPLMFlightLoopID = pointer; + PXPLMFlightLoopID = ^XPLMFlightLoopID; +{$ENDIF} + + { + XPLMFlightLoop_f + + This is your flight loop callback. Each time the flight loop is iterated + through, you receive this call at the end. You receive a time since you + were last called and a time since the last loop, as well as a loop counter. + The 'phase' parameter is deprecated and should be ignored. + + Your return value controls when you will next be called. Return 0 to stop + receiving callbacks. Pass a positive number to specify how many seconds + until the next callback. (You will be called at or after this time, not + before.) Pass a negative number to specify how many loops must go by until + you are called. For example, -1.0 means call me the very next loop. Try + to run your flight loop as infrequently as is practical, and suspend it + (using return value 0) when you do not need it; lots of flight loop + callbacks that do nothing lowers x-plane's frame rate. + + Your callback will NOT be unregistered if you return 0; it will merely be + inactive. + + The reference constant you passed to your loop is passed back to you. + } + XPLMFlightLoop_f = FUNCTION( + inElapsedSinceLastCall: single; + inElapsedTimeSinceLastFlightLoop: single; + inCounter : integer; + inRefcon : pointer) : single; cdecl; + +{$IFDEF XPLM210} + { + XPLMCreateFlightLoop_t + + XPLMCreateFlightLoop_t contains the parameters to create a new flight loop + callback. The strsucture can be expanded in future SDKs - always set + structSize to the size of your structure in bytes. + } + XPLMCreateFlightLoop_t = RECORD + structSize : integer; + phase : XPLMFlightLoopPhaseType; + callbackFunc : XPLMFlightLoop_f; + refcon : pointer; + END; + PXPLMCreateFlightLoop_t = ^XPLMCreateFlightLoop_t; +{$ENDIF} + + { + XPLMGetElapsedTime + + This routine returns the elapsed time since the sim started up in decimal + seconds. + } + FUNCTION XPLMGetElapsedTime: single; +{$IFDEF DELPHI} + cdecl; external 'XPLM.DLL'; +{$ELSE} + cdecl; external ''; +{$ENDIF} + + { + XPLMGetCycleNumber + + This routine returns a counter starting at zero for each sim cycle + computed/video frame rendered. + } + FUNCTION XPLMGetCycleNumber: integer; +{$IFDEF DELPHI} + cdecl; external 'XPLM.DLL'; +{$ELSE} + cdecl; external ''; +{$ENDIF} + + { + XPLMRegisterFlightLoopCallback + + This routine registers your flight loop callback. Pass in a pointer to a + flight loop function and a refcon. inInterval defines when you will be + called. Pass in a positive number to specify seconds from registration + time to the next callback. Pass in a negative number to indicate when you + will be called (e.g. pass -1 to be called at the next cylcle). Pass 0 to + not be called; your callback will be inactive. + } + PROCEDURE XPLMRegisterFlightLoopCallback( + inFlightLoop : XPLMFlightLoop_f; + inInterval : single; + inRefcon : pointer); +{$IFDEF DELPHI} + cdecl; external 'XPLM.DLL'; +{$ELSE} + cdecl; external ''; +{$ENDIF} + + { + XPLMUnregisterFlightLoopCallback + + This routine unregisters your flight loop callback. Do NOT call it from + your flight loop callback. Once your flight loop callback is + unregistered, it will not be called again. + } + PROCEDURE XPLMUnregisterFlightLoopCallback( + inFlightLoop : XPLMFlightLoop_f; + inRefcon : pointer); +{$IFDEF DELPHI} + cdecl; external 'XPLM.DLL'; +{$ELSE} + cdecl; external ''; +{$ENDIF} + + { + XPLMSetFlightLoopCallbackInterval + + This routine sets when a callback will be called. Do NOT call it from your + callback; use the return value of the callback to change your callback + interval from inside your callback. + + inInterval is formatted the same way as in XPLMRegisterFlightLoopCallback; + positive for seconds, negative for cycles, and 0 for deactivating the + callback. If inRelativeToNow is 1, times are from the time of this call; + otherwise they are from the time the callback was last called (or the time + it was registered if it has never been called. + } + PROCEDURE XPLMSetFlightLoopCallbackInterval( + inFlightLoop : XPLMFlightLoop_f; + inInterval : single; + inRelativeToNow : integer; + inRefcon : pointer); +{$IFDEF DELPHI} + cdecl; external 'XPLM.DLL'; +{$ELSE} + cdecl; external ''; +{$ENDIF} + +{$IFDEF XPLM210} + { + XPLMCreateFlightLoop + + This routine creates a flight loop callback and returns its ID. The flight + loop callback is created using the input param struct, and is inited to be + unscheduled. + } + FUNCTION XPLMCreateFlightLoop( + inParams : PXPLMCreateFlightLoop_t) : XPLMFlightLoopID; +{$IFDEF DELPHI} + cdecl; external 'XPLM.DLL'; +{$ELSE} + cdecl; external ''; +{$ENDIF} +{$ENDIF} + +{$IFDEF XPLM210} + { + XPLMDestroyFlightLoop + + This routine destroys a flight loop callback by ID. + } + PROCEDURE XPLMDestroyFlightLoop( + inFlightLoopID : XPLMFlightLoopID); +{$IFDEF DELPHI} + cdecl; external 'XPLM.DLL'; +{$ELSE} + cdecl; external ''; +{$ENDIF} +{$ENDIF} + +{$IFDEF XPLM210} + { + XPLMScheduleFlightLoop + + This routine schedules a flight loop callback for future execution. If + inInterval is negative, it is run in a certain number of frames based on + the absolute value of the input. If the interval is positive, it is a + duration in seconds. + + If inRelativeToNow is true, ties are interpretted relative to the time this + routine is called; otherwise they are relative to the last call time or the + time the flight loop was registered (if never called). + + THREAD SAFETY: it is legal to call this routine from any thread under the + following conditions: + + 1. The call must be between the beginning of an XPLMEnable and the end of + an XPLMDisable sequence. (That is, you must not call this routine from + thread activity when your plugin was supposed to be disabled. Since + plugins are only enabled while loaded, this also implies you cannot run + this routine outside an XPLMStart/XPLMStop sequence.) + + 2. You may not call this routine re-entrantly for a single flight loop ID. + (That is, you can't enable from multiple threads at the same time.) + + 3. You must call this routine between the time after XPLMCreateFlightLoop + returns a value and the time you call XPLMDestroyFlightLoop. (That is, you + must ensure that your threaded activity is within the life of the object. + The SDK does not check this for you, nor does it synchronize destruction of + the object.) + + 4. The object must be unscheduled if this routine is to be called from a + thread other than the main thread. + } + PROCEDURE XPLMScheduleFlightLoop( + inFlightLoopID : XPLMFlightLoopID; + inInterval : single; + inRelativeToNow : integer); +{$IFDEF DELPHI} + cdecl; external 'XPLM.DLL'; +{$ELSE} + cdecl; external ''; +{$ENDIF} +{$ENDIF} + +IMPLEMENTATION +END. diff --git a/GermanAirlinesVA-GAConnector/XPSDK/Delphi/XPLM/XPLMScenery.pas b/GermanAirlinesVA-GAConnector/XPSDK/Delphi/XPLM/XPLMScenery.pas new file mode 100644 index 0000000..e0c51ac --- /dev/null +++ b/GermanAirlinesVA-GAConnector/XPSDK/Delphi/XPLM/XPLMScenery.pas @@ -0,0 +1,419 @@ +{ + Copyright 2005-2012 Sandy Barbour and Ben Supnik + + All rights reserved. See license.txt for usage. + + X-Plane SDK Version: 2.1.1 +} + +UNIT XPLMScenery; +INTERFACE +{ + This package contains APIs to interact with X-Plane's scenery system. +} + +USES XPLMDefs; + {$A4} +{$IFDEF MSWINDOWS} + {$DEFINE DELPHI} +{$ENDIF} +{$IFDEF XPLM200} +{___________________________________________________________________________ + * Terrain Y-Testing + ___________________________________________________________________________} +{ + The Y-testing API allows you to locate the physical scenery mesh. This + would be used to place dynamic graphics on top of the ground in a + plausible way or do physics interactions. + + The Y-test API works via probe objects, which are allocated by your plugin + and used to query terrain. Probe objects exist both to capture which + algorithm you have requested (see probe types) and also to cache query + information. + + Performance guidelines: It is generally faster to use the same probe for + nearby points and different probes for different points. Try not to + allocate more than "hundreds" of probes at most. Share probes if you need + more. Generally, probing operations are expensive, and should be avoided + via caching when possible. + + Y testing returns a location on the terrain, a normal vectory, and a + velocity vector. The normal vector tells you the slope of the terrain at + that point. The velocity vector tells you if that terrain is moving (and + is in meters/second). For example, if your Y test hits the aircraft carrier + deck, this tells you the velocity of that point on the deck. + + Note: the Y-testing API is limited to probing the loaded scenery area, + which is approximately 300x300 km in X-Plane 9. Probes outside this area + will return the height of a 0 MSL sphere. +} + + + + + { + XPLMProbeType + + XPLMProbeType defines the type of terrain probe - each probe has a + different algorithm. (Only one type of probe is provided right now, but + future APIs will expose more flexible or poewrful or useful probes. + } +TYPE + XPLMProbeType = ( + { The Y probe gives you the location of the tallest physical scenery along } + { the Y axis going through the queried point. } + xplm_ProbeY = 0 + + ); + PXPLMProbeType = ^XPLMProbeType; + + { + XPLMProbeResult + + Probe results - possible results from a probe query. + } + XPLMProbeResult = ( + { The probe hit terrain and returned valid values. } + xplm_ProbeHitTerrain = 0 + + { An error in the API call. Either the probe struct size is bad, or the } + { probe is invalid or the type is mismatched for the specific query call. } + ,xplm_ProbeError = 1 + + { The probe call succeeded but there is no terrain under this point (perhaps } + { it is off the side of the planet?) } + ,xplm_ProbeMissed = 2 + + ); + PXPLMProbeResult = ^XPLMProbeResult; + + { + XPLMProbeRef + + An XPLMProbeRef is an opaque handle to a probe, used for querying the + terrain. + } + XPLMProbeRef = pointer; + PXPLMProbeRef = ^XPLMProbeRef; + + { + XPLMProbeInfo_t + + XPLMProbeInfo_t contains the results of a probe call. Make sure to set + structSize to the size of the struct before using it. + } + XPLMProbeInfo_t = RECORD + { Size of structure in bytes - always set this before calling the XPLM. } + structSize : integer; + { Resulting X location of the terrain point we hit, in local OpenGL } + { coordinates. } + locationX : single; + { Resulting Y location of the terrain point we hit, in local OpenGL } + { coordinates. } + locationY : single; + { Resulting Z location of the terrain point we hit, in local OpenGL } + { coordinates. } + locationZ : single; + { X component of the normal vector to the terrain we found. } + normalX : single; + { Y component of the normal vector to the terrain we found. } + normalY : single; + { Z component of the normal vector to the terrain we found. } + normalZ : single; + { X component of the velocity vector of the terrain we found. } + velocityX : single; + { Y component of the velocity vector of the terrain we found. } + velocityY : single; + { Z component of the velocity vector of the terrain we found. } + velocityZ : single; + { Tells if the surface we hit is water (otherwise it is land). } + is_wet : integer; + END; + PXPLMProbeInfo_t = ^XPLMProbeInfo_t; + + { + XPLMCreateProbe + + Creates a new probe object of a given type and returns. + } + FUNCTION XPLMCreateProbe( + inProbeType : XPLMProbeType) : XPLMProbeRef; +{$IFDEF DELPHI} + cdecl; external 'XPLM.DLL'; +{$ELSE} + cdecl; external ''; +{$ENDIF} + + { + XPLMDestroyProbe + + Deallocates an existing probe object. + } + PROCEDURE XPLMDestroyProbe( + inProbe : XPLMProbeRef); +{$IFDEF DELPHI} + cdecl; external 'XPLM.DLL'; +{$ELSE} + cdecl; external ''; +{$ENDIF} + + { + XPLMProbeTerrainXYZ + + Probes the terrain. Pass in the XYZ coordinate of the probe point, a probe + object, and an XPLMProbeInfo_t struct that has its structSize member set + properly. Other fields are filled in if we hit terrain, and a probe result + is returned. + } + FUNCTION XPLMProbeTerrainXYZ( + inProbe : XPLMProbeRef; + inX : single; + inY : single; + inZ : single; + outInfo : PXPLMProbeInfo_t) : XPLMProbeResult; +{$IFDEF DELPHI} + cdecl; external 'XPLM.DLL'; +{$ELSE} + cdecl; external ''; +{$ENDIF} + +{$ENDIF} +{___________________________________________________________________________ + * Object Drawing + ___________________________________________________________________________} +{ + The object drawing routines let you load and draw X-Plane OBJ files. + Objects are loaded by file path and managed via an opaque handle. X-Plane + naturally reference counts objects, so it is important that you balance + every successful call to XPLMLoadObject with a call to XPLMUnloadObject! +} + + + +{$IFDEF XPLM200} +TYPE + { + XPLMObjectRef + + An XPLMObjectRef is a opaque handle to an .obj file that has been loaded + into memory. + } + XPLMObjectRef = pointer; + PXPLMObjectRef = ^XPLMObjectRef; +{$ENDIF} + +{$IFDEF XPLM200} + { + XPLMDrawInfo_t + + The XPLMDrawInfo_t structure contains positioning info for one object that + is to be drawn. Be sure to set structSize to the size of the structure for + future expansion. + } + XPLMDrawInfo_t = RECORD + { Set this to the size of this structure! } + structSize : integer; + { X location of the object in local coordinates. } + x : single; + { Y location of the object in local coordinates. } + y : single; + { Z location of the object in local coordinates. } + z : single; + { Pitch in degres to rotate the object, positive is up. } + pitch : single; + { Heading in local coordinates to rotate the object, clockwise. } + heading : single; + { Roll to rotate the object. } + roll : single; + END; + PXPLMDrawInfo_t = ^XPLMDrawInfo_t; +{$ENDIF} + +{$IFDEF XPLM210} + { + XPLMObjectLoaded_f + + You provide this callback when loading an object asynchronously; it will be + called once the object is loaded. Your refcon is passed back. The object + ref passed in is the newly loaded object (ready for use) or NULL if an + error occured. + + If your plugin is disabled, this callback will be delivered as soon as the + plugin is re-enabled. If your plugin is unloaded before this callback is + ever called, the SDK will release the object handle for you. + } + XPLMObjectLoaded_f = PROCEDURE( + inObject : XPLMObjectRef; + inRefcon : pointer); cdecl; +{$ENDIF} + +{$IFDEF XPLM200} + { + XPLMLoadObject + + This routine loads an OBJ file and returns a handle to it. If X-plane has + already loaded the object, the handle to the existing object is returned. + Do not assume you will get the same handle back twice, but do make sure to + call unload once for every load to avoid "leaking" objects. The object + will be purged from memory when no plugins and no scenery are using it. + + The path for the object must be relative to the X-System base folder. If + the path is in the root of the X-System folder you may need to prepend ./ + to it; loading objects in the root of the X-System folder is STRONGLY + discouraged - your plugin should not dump art resources in the root folder! + + + XPLMLoadObject will return NULL if the object cannot be loaded (either + because it is not found or the file is misformatted). This routine will + load any object that can be used in the X-Plane scenery system. + + It is important that the datarefs an object uses for animation already be + loaded before you load the object. For this reason it may be necessary to + defer object loading until the sim has fully started. + } + FUNCTION XPLMLoadObject( + inPath : Pchar) : XPLMObjectRef; +{$IFDEF DELPHI} + cdecl; external 'XPLM.DLL'; +{$ELSE} + cdecl; external ''; +{$ENDIF} +{$ENDIF} + +{$IFDEF XPLM210} + { + XPLMLoadObjectAsync + + This routine loads an object asynchronously; control is returned to you + immediately while X-Plane loads the object. The sim will not stop flying + while the object loads. For large objects, it may be several seconds + before the load finishes. + + You provide a callback function that is called once the load has completed. + Note that if the object cannot be loaded, you will not find out until the + callback function is called with a NULL object handle. + + There is no way to cancel an asynchronous object load; you must wait for + the load to complete and then release the object if it is no longer + desired. + } + PROCEDURE XPLMLoadObjectAsync( + inPath : Pchar; + inCallback : XPLMObjectLoaded_f; + inRefcon : pointer); +{$IFDEF DELPHI} + cdecl; external 'XPLM.DLL'; +{$ELSE} + cdecl; external ''; +{$ENDIF} +{$ENDIF} + +{$IFDEF XPLM200} + { + XPLMDrawObjects + + XPLMDrawObjects draws an object from an OBJ file one or more times. You + pass in the object and an array of XPLMDrawInfo_t structs, one for each + place you would like the object to be drawn. + + X-Plane will attempt to cull the objects based on LOD and visibility, and + will pick the appropriate LOD. + + Lighting is a boolean; pass 1 to show the night version of object with + night-only lights lit up. Pass 0 to show the daytime version of the + object. + + earth_relative controls the coordinate system. If this is 1, the rotations + you specify are applied to the object after its coordinate system is + transformed from local to earth-relative coordinates -- that is, an object + with no rotations will point toward true north and the Y axis will be up + against gravity. If this is 0, the object is drawn with your rotations + from local coordanates -- that is, an object with no rotations is drawn + pointing down the -Z axis and the Y axis of the object matches the local + coordinate Y axis. + } + PROCEDURE XPLMDrawObjects( + inObject : XPLMObjectRef; + inCount : integer; + inLocations : PXPLMDrawInfo_t; + lighting : integer; + earth_relative : integer); +{$IFDEF DELPHI} + cdecl; external 'XPLM.DLL'; +{$ELSE} + cdecl; external ''; +{$ENDIF} +{$ENDIF} + +{$IFDEF XPLM200} + { + XPLMUnloadObject + + This routine marks an object as no longer being used by your plugin. + Objects are reference counted: once no plugins are using an object, it is + purged from memory. Make sure to call XPLMUnloadObject once for each + successful call to XPLMLoadObject. + } + PROCEDURE XPLMUnloadObject( + inObject : XPLMObjectRef); +{$IFDEF DELPHI} + cdecl; external 'XPLM.DLL'; +{$ELSE} + cdecl; external ''; +{$ENDIF} +{$ENDIF} + +{$IFDEF XPLM200} +{___________________________________________________________________________ + * Library Access + ___________________________________________________________________________} +{ + The library access routines allow you to locate scenery objects via the + X-Plane library system. Right now library access is only provided for + objects, allowing plugin-drawn objects to be extended using the library + system. +} + + + + + { + XPLMLibraryEnumerator_f + + An XPLMLibraryEnumerator_f is a callback you provide that is called once + for each library element that is located. The returned paths will be + relative to the X-System folder. + } +TYPE + XPLMLibraryEnumerator_f = PROCEDURE( + inFilePath : Pchar; + inRef : pointer); cdecl; + + { + XPLMLookupObjects + + This routine looks up a virtual path in the library system and returns all + matching elements. You provide a callback - one virtual path may match + many objects in the library. XPLMLookupObjects returns the number of + objects found. + + The latitude and longitude parameters specify the location the object will + be used. The library system allows for scenery packages to only provide + objects to certain local locations. Only objects that are allowed at the + latitude/longitude you provide will be returned. + } + FUNCTION XPLMLookupObjects( + inPath : Pchar; + inLatitude : single; + inLongitude : single; + enumerator : XPLMLibraryEnumerator_f; + ref : pointer) : integer; +{$IFDEF DELPHI} + cdecl; external 'XPLM.DLL'; +{$ELSE} + cdecl; external ''; +{$ENDIF} + +{$ENDIF} +IMPLEMENTATION +END. diff --git a/GermanAirlinesVA-GAConnector/XPSDK/Delphi/XPLM/XPLMUtilities.pas b/GermanAirlinesVA-GAConnector/XPSDK/Delphi/XPLM/XPLMUtilities.pas new file mode 100644 index 0000000..0595d1c --- /dev/null +++ b/GermanAirlinesVA-GAConnector/XPSDK/Delphi/XPLM/XPLMUtilities.pas @@ -0,0 +1,927 @@ +{ + Copyright 2005-2012 Sandy Barbour and Ben Supnik + + All rights reserved. See license.txt for usage. + + X-Plane SDK Version: 2.1.1 +} + +UNIT XPLMUtilities; +INTERFACE +{ + +} + +USES XPLMDefs; + {$A4} +{$IFDEF MSWINDOWS} + {$DEFINE DELPHI} +{$ENDIF} +{___________________________________________________________________________ + * X-PLANE USER INTERACTION + ___________________________________________________________________________} +{ + The user interaction APIs let you simulate commands the user can do with a + joystick, keyboard etc. Note that it is generally safer for future + compatibility to use one of these commands than to manipulate the + underlying sim data. +} + + + + { + XPLMCommandKeyID + + These enums represent all the keystrokes available within x-plane. They + can be sent to x-plane directly. For example, you can reverse thrust using + these enumerations. + } +TYPE + XPLMCommandKeyID = ( + xplm_key_pause=0, + xplm_key_revthrust, + xplm_key_jettison, + xplm_key_brakesreg, + xplm_key_brakesmax, + xplm_key_gear, + xplm_key_timedn, + xplm_key_timeup, + xplm_key_fadec, + xplm_key_otto_dis, + xplm_key_otto_atr, + xplm_key_otto_asi, + xplm_key_otto_hdg, + xplm_key_otto_gps, + xplm_key_otto_lev, + xplm_key_otto_hnav, + xplm_key_otto_alt, + xplm_key_otto_vvi, + xplm_key_otto_vnav, + xplm_key_otto_nav1, + xplm_key_otto_nav2, + xplm_key_targ_dn, + xplm_key_targ_up, + xplm_key_hdgdn, + xplm_key_hdgup, + xplm_key_barodn, + xplm_key_baroup, + xplm_key_obs1dn, + xplm_key_obs1up, + xplm_key_obs2dn, + xplm_key_obs2up, + xplm_key_com1_1, + xplm_key_com1_2, + xplm_key_com1_3, + xplm_key_com1_4, + xplm_key_nav1_1, + xplm_key_nav1_2, + xplm_key_nav1_3, + xplm_key_nav1_4, + xplm_key_com2_1, + xplm_key_com2_2, + xplm_key_com2_3, + xplm_key_com2_4, + xplm_key_nav2_1, + xplm_key_nav2_2, + xplm_key_nav2_3, + xplm_key_nav2_4, + xplm_key_adf_1, + xplm_key_adf_2, + xplm_key_adf_3, + xplm_key_adf_4, + xplm_key_adf_5, + xplm_key_adf_6, + xplm_key_transpon_1, + xplm_key_transpon_2, + xplm_key_transpon_3, + xplm_key_transpon_4, + xplm_key_transpon_5, + xplm_key_transpon_6, + xplm_key_transpon_7, + xplm_key_transpon_8, + xplm_key_flapsup, + xplm_key_flapsdn, + xplm_key_cheatoff, + xplm_key_cheaton, + xplm_key_sbrkoff, + xplm_key_sbrkon, + xplm_key_ailtrimL, + xplm_key_ailtrimR, + xplm_key_rudtrimL, + xplm_key_rudtrimR, + xplm_key_elvtrimD, + xplm_key_elvtrimU, + xplm_key_forward, + xplm_key_down, + xplm_key_left, + xplm_key_right, + xplm_key_back, + xplm_key_tower, + xplm_key_runway, + xplm_key_chase, + xplm_key_free1, + xplm_key_free2, + xplm_key_spot, + xplm_key_fullscrn1, + xplm_key_fullscrn2, + xplm_key_tanspan, + xplm_key_smoke, + xplm_key_map, + xplm_key_zoomin, + xplm_key_zoomout, + xplm_key_cycledump, + xplm_key_replay, + xplm_key_tranID, + xplm_key_max + ); + PXPLMCommandKeyID = ^XPLMCommandKeyID; + + { + XPLMCommandButtonID + + These are enumerations for all of the things you can do with a joystick + button in X-Plane. They currently match the buttons menu in the equipment + setup dialog, but these enums will be stable even if they change in + X-Plane. + } + XPLMCommandButtonID = ( + xplm_joy_nothing=0, + xplm_joy_start_all, + xplm_joy_start_0, + xplm_joy_start_1, + xplm_joy_start_2, + xplm_joy_start_3, + xplm_joy_start_4, + xplm_joy_start_5, + xplm_joy_start_6, + xplm_joy_start_7, + xplm_joy_throt_up, + xplm_joy_throt_dn, + xplm_joy_prop_up, + xplm_joy_prop_dn, + xplm_joy_mixt_up, + xplm_joy_mixt_dn, + xplm_joy_carb_tog, + xplm_joy_carb_on, + xplm_joy_carb_off, + xplm_joy_trev, + xplm_joy_trm_up, + xplm_joy_trm_dn, + xplm_joy_rot_trm_up, + xplm_joy_rot_trm_dn, + xplm_joy_rud_lft, + xplm_joy_rud_cntr, + xplm_joy_rud_rgt, + xplm_joy_ail_lft, + xplm_joy_ail_cntr, + xplm_joy_ail_rgt, + xplm_joy_B_rud_lft, + xplm_joy_B_rud_rgt, + xplm_joy_look_up, + xplm_joy_look_dn, + xplm_joy_look_lft, + xplm_joy_look_rgt, + xplm_joy_glance_l, + xplm_joy_glance_r, + xplm_joy_v_fnh, + xplm_joy_v_fwh, + xplm_joy_v_tra, + xplm_joy_v_twr, + xplm_joy_v_run, + xplm_joy_v_cha, + xplm_joy_v_fr1, + xplm_joy_v_fr2, + xplm_joy_v_spo, + xplm_joy_flapsup, + xplm_joy_flapsdn, + xplm_joy_vctswpfwd, + xplm_joy_vctswpaft, + xplm_joy_gear_tog, + xplm_joy_gear_up, + xplm_joy_gear_down, + xplm_joy_lft_brake, + xplm_joy_rgt_brake, + xplm_joy_brakesREG, + xplm_joy_brakesMAX, + xplm_joy_speedbrake, + xplm_joy_ott_dis, + xplm_joy_ott_atr, + xplm_joy_ott_asi, + xplm_joy_ott_hdg, + xplm_joy_ott_alt, + xplm_joy_ott_vvi, + xplm_joy_tim_start, + xplm_joy_tim_reset, + xplm_joy_ecam_up, + xplm_joy_ecam_dn, + xplm_joy_fadec, + xplm_joy_yaw_damp, + xplm_joy_art_stab, + xplm_joy_chute, + xplm_joy_JATO, + xplm_joy_arrest, + xplm_joy_jettison, + xplm_joy_fuel_dump, + xplm_joy_puffsmoke, + xplm_joy_prerotate, + xplm_joy_UL_prerot, + xplm_joy_UL_collec, + xplm_joy_TOGA, + xplm_joy_shutdown, + xplm_joy_con_atc, + xplm_joy_fail_now, + xplm_joy_pause, + xplm_joy_rock_up, + xplm_joy_rock_dn, + xplm_joy_rock_lft, + xplm_joy_rock_rgt, + xplm_joy_rock_for, + xplm_joy_rock_aft, + xplm_joy_idle_hilo, + xplm_joy_lanlights, + xplm_joy_max + ); + PXPLMCommandButtonID = ^XPLMCommandButtonID; + + { + XPLMHostApplicationID + + The plug-in system is based on Austin's cross-platform OpenGL framework and + could theoretically be adapted to run in other apps like WorldMaker. The + plug-in system also runs against a test harness for internal development + and could be adapted to another flight sim (in theory at least). So an ID + is providing allowing plug-ins to indentify what app they are running + under. + } + XPLMHostApplicationID = ( + xplm_Host_Unknown = 0 + + ,xplm_Host_XPlane = 1 + + ,xplm_Host_PlaneMaker = 2 + + ,xplm_Host_WorldMaker = 3 + + ,xplm_Host_Briefer = 4 + + ,xplm_Host_PartMaker = 5 + + ,xplm_Host_YoungsMod = 6 + + ,xplm_Host_XAuto = 7 + + ); + PXPLMHostApplicationID = ^XPLMHostApplicationID; + + { + XPLMLanguageCode + + These enums define what language the sim is running in. These enumerations + do not imply that the sim can or does run in all of these languages; they + simply provide a known encoding in the event that a given sim version is + localized to a certain language. + } + XPLMLanguageCode = ( + xplm_Language_Unknown = 0 + + ,xplm_Language_English = 1 + + ,xplm_Language_French = 2 + + ,xplm_Language_German = 3 + + ,xplm_Language_Italian = 4 + + ,xplm_Language_Spanish = 5 + + ,xplm_Language_Korean = 6 + +{$IFDEF XPLM200} + ,xplm_Language_Russian = 7 +{$ENDIF} + +{$IFDEF XPLM200} + ,xplm_Language_Greek = 8 +{$ENDIF} + +{$IFDEF XPLM200} + ,xplm_Language_Japanese = 9 +{$ENDIF} + +{$IFDEF XPLM200} + ,xplm_Language_Chinese = 10 +{$ENDIF} + + ); + PXPLMLanguageCode = ^XPLMLanguageCode; + +{$IFDEF XPLM200} + { + XPLMDataFileType + + These enums define types of data files you can load or unload using the + SDK. + } + XPLMDataFileType = ( + { A situation (.sit) file, which starts off a flight in a given } + { configuration. } + xplm_DataFile_Situation = 1 + + { A situation movie (.smo) file, which replays a past flight. } + ,xplm_DataFile_ReplayMovie = 2 + + ); + PXPLMDataFileType = ^XPLMDataFileType; +{$ENDIF} + +{$IFDEF XPLM200} + { + XPLMError_f + + An XPLM error callback is a function that you provide to receive debugging + information from the plugin SDK. See XPLMSetErrorCallback for more + information. NOTE: for the sake of debugging, your error callback will be + called even if your plugin is not enabled, allowing you to receive debug + info in your XPluginStart and XPluginStop callbacks. To avoid causing + logic errors in the management code, do not call any other plugin routines + from your error callback - it is only meant for logging! + } + XPLMError_f = PROCEDURE( + inMessage : Pchar); cdecl; +{$ENDIF} + + { + XPLMSimulateKeyPress + + This function simulates a key being pressed for x-plane. The keystroke + goes directly to x-plane; it is never sent to any plug-ins. However, since + this is a raw key stroke it may be mapped by the keys file or enter text + into a field. + + WARNING: This function will be deprecated; do not use it. Instead use + XPLMCommandKeyStroke. + } + PROCEDURE XPLMSimulateKeyPress( + inKeyType : integer; + inKey : integer); +{$IFDEF DELPHI} + cdecl; external 'XPLM.DLL'; +{$ELSE} + cdecl; external ''; +{$ENDIF} + + { + XPLMSpeakString + + This function displays the string in a translucent overlay over the current + display and also speaks the string if text-to-speech is enabled. The + string is spoken asynchronously, this function returns immediately. + } + PROCEDURE XPLMSpeakString( + inString : Pchar); +{$IFDEF DELPHI} + cdecl; external 'XPLM.DLL'; +{$ELSE} + cdecl; external ''; +{$ENDIF} + + { + XPLMCommandKeyStroke + + This routine simulates a command-key stroke. However, the keys are done by + function, not by actual letter, so this function works even if the user has + remapped their keyboard. Examples of things you might do with this include + pausing the simulator. + } + PROCEDURE XPLMCommandKeyStroke( + inKey : XPLMCommandKeyID); +{$IFDEF DELPHI} + cdecl; external 'XPLM.DLL'; +{$ELSE} + cdecl; external ''; +{$ENDIF} + + { + XPLMCommandButtonPress + + This function simulates any of the actions that might be taken by pressing + a joystick button. However, this lets you call the command directly rather + than have to know which button is mapped where. Important: you must + release each button you press. The APIs are separate so that you can 'hold + down' a button for a fixed amount of time. + } + PROCEDURE XPLMCommandButtonPress( + inButton : XPLMCommandButtonID); +{$IFDEF DELPHI} + cdecl; external 'XPLM.DLL'; +{$ELSE} + cdecl; external ''; +{$ENDIF} + + { + XPLMCommandButtonRelease + + This function simulates any of the actions that might be taken by pressing + a joystick button. See XPLMCommandButtonPress + } + PROCEDURE XPLMCommandButtonRelease( + inButton : XPLMCommandButtonID); +{$IFDEF DELPHI} + cdecl; external 'XPLM.DLL'; +{$ELSE} + cdecl; external ''; +{$ENDIF} + + { + XPLMGetVirtualKeyDescription + + Given a virtual key code (as defined in XPLMDefs.h) this routine returns a + human-readable string describing the character. This routine is provided + for showing users what keyboard mappings they have set up. The string may + read 'unknown' or be a blank or NULL string if the virtual key is unknown. + } + FUNCTION XPLMGetVirtualKeyDescription( + inVirtualKey : char) : Pchar; +{$IFDEF DELPHI} + cdecl; external 'XPLM.DLL'; +{$ELSE} + cdecl; external ''; +{$ENDIF} + +{___________________________________________________________________________ + * X-PLANE MISC + ___________________________________________________________________________} +{ + +} + + + + { + XPLMReloadScenery + + XPLMReloadScenery reloads the current set of scenery. You can use this + function in two typical ways: simply call it to reload the scenery, picking + up any new installed scenery, .env files, etc. from disk. Or, change the + lat/ref and lon/ref data refs and then call this function to shift the + scenery environment. + } + PROCEDURE XPLMReloadScenery; +{$IFDEF DELPHI} + cdecl; external 'XPLM.DLL'; +{$ELSE} + cdecl; external ''; +{$ENDIF} + + { + XPLMGetSystemPath + + This function returns the full path to the X-System folder. Note that this + is a directory path, so it ends in a trailing : or /. The buffer you pass + should be at least 512 characters long. + } + PROCEDURE XPLMGetSystemPath( + outSystemPath : Pchar); +{$IFDEF DELPHI} + cdecl; external 'XPLM.DLL'; +{$ELSE} + cdecl; external ''; +{$ENDIF} + + { + XPLMGetPrefsPath + + This routine returns a full path to the proper directory to store + preferences in. It ends in a : or /. The buffer you pass should be at + least 512 characters long. + } + PROCEDURE XPLMGetPrefsPath( + outPrefsPath : Pchar); +{$IFDEF DELPHI} + cdecl; external 'XPLM.DLL'; +{$ELSE} + cdecl; external ''; +{$ENDIF} + + { + XPLMGetDirectorySeparator + + This routine returns a string with one char and a null terminator that is + the directory separator for the current platform. This allows you to write + code that concatinates directory paths without having to #ifdef for + platform. + } + FUNCTION XPLMGetDirectorySeparator: Pchar; +{$IFDEF DELPHI} + cdecl; external 'XPLM.DLL'; +{$ELSE} + cdecl; external ''; +{$ENDIF} + + { + XPLMExtractFileAndPath + + Given a full path to a file, this routine separates the path from the file. + If the path is a partial directory (e.g. ends in : or \) the trailing + directory separator is removed. This routine works in-place; a pointer to + the file part of the buffer is returned; the original buffer still starts + with the path. + } + FUNCTION XPLMExtractFileAndPath( + inFullPath : Pchar) : Pchar; +{$IFDEF DELPHI} + cdecl; external 'XPLM.DLL'; +{$ELSE} + cdecl; external ''; +{$ENDIF} + + { + XPLMGetDirectoryContents + + This routine returns a list of files in a directory (specified by a full + path, no trailing : or \). The output is returned as a list of NULL + terminated strings. An index array (if specified) is filled with pointers + into the strings. This routine The last file is indicated by a zero-length + string (and NULL in the indices). This routine will return 1 if you had + capacity for all files or 0 if you did not. You can also skip a given + number of files. + + inDirectoryPath - a null terminated C string containing the full path to + the directory with no trailing directory char. + + inFirstReturn - the zero-based index of the first file in the directory to + return. (Usually zero to fetch all in one pass.) + + outFileNames - a buffer to receive a series of sequential null terminated + C-string file names. A zero-length C string will be appended to the very + end. + + inFileNameBufSize - the size of the file name buffer in bytes. + + outIndices - a pointer to an array of character pointers that will become + an index into the directory. The last file will be followed by a NULL + value. Pass NULL if you do not want indexing information. + + inIndexCount - the max size of the index in entries. + + outTotalFiles - if not NULL, this is filled in with the number of files in + the directory. + + outReturnedFiles - if not NULL, the number of files returned by this + iteration. + + Return value - 1 if all info could be returned, 0 if there was a buffer + overrun. + + WARNING: Before X-Plane 7 this routine did not properly iterate through + directories. If X-Plane 6 compatibility is needed, use your own code to + iterate directories. + } + FUNCTION XPLMGetDirectoryContents( + inDirectoryPath : Pchar; + inFirstReturn : integer; + outFileNames : Pchar; + inFileNameBufSize : integer; + outIndices : PPchar; { Can be nil } + inIndexCount : integer; + outTotalFiles : Pinteger; { Can be nil } + outReturnedFiles : Pinteger) : integer; { Can be nil } +{$IFDEF DELPHI} + cdecl; external 'XPLM.DLL'; +{$ELSE} + cdecl; external ''; +{$ENDIF} + + { + XPLMInitialized + + This function returns 1 if X-Plane has properly initialized the plug-in + system. If this routine returns 0, many XPLM functions will not work. + + NOTE: Under normal circumstances a plug-in should never be running while + the plug-in manager is not initialized. + + WARNING: This function is generally not needed and may be deprecated in the + future. + } + FUNCTION XPLMInitialized: integer; +{$IFDEF DELPHI} + cdecl; external 'XPLM.DLL'; +{$ELSE} + cdecl; external ''; +{$ENDIF} + + { + XPLMGetVersions + + This routine returns the revision of both X-Plane and the XPLM DLL. All + versions are three-digit decimal numbers (e.g. 606 for version 6.06 of + X-Plane); the current revision of the XPLM is 200 (2.00). This routine + also returns the host ID of the app running us. + + The most common use of this routine is to special-case around x-plane + version-specific behavior. + } + PROCEDURE XPLMGetVersions( + outXPlaneVersion : Pinteger; + outXPLMVersion : Pinteger; + outHostID : PXPLMHostApplicationID); +{$IFDEF DELPHI} + cdecl; external 'XPLM.DLL'; +{$ELSE} + cdecl; external ''; +{$ENDIF} + + { + XPLMGetLanguage + + This routine returns the langauge the sim is running in. + } + FUNCTION XPLMGetLanguage: XPLMLanguageCode; +{$IFDEF DELPHI} + cdecl; external 'XPLM.DLL'; +{$ELSE} + cdecl; external ''; +{$ENDIF} + + { + XPLMDebugString + + This routine outputs a C-style string to the Log.txt file. The file is + immediately flushed so you will not lose data. (This does cause a + performance penalty.) + } + PROCEDURE XPLMDebugString( + inString : Pchar); +{$IFDEF DELPHI} + cdecl; external 'XPLM.DLL'; +{$ELSE} + cdecl; external ''; +{$ENDIF} + +{$IFDEF XPLM200} + { + XPLMSetErrorCallback + + XPLMSetErrorCallback installs an error-reporting callback for your plugin. + Normally the plugin system performs minimum diagnostics to maximize + performance. When you install an error callback, you will receive calls + due to certain plugin errors, such as passing bad parameters or incorrect + data. + + The intention is for you to install the error callback during debug + sections and put a break-point inside your callback. This will cause you + to break into the debugger from within the SDK at the point in your plugin + where you made an illegal call. + + Installing an error callback may activate error checking code that would + not normally run, and this may adversely affect performance, so do not + leave error callbacks installed in shipping plugins. + } + PROCEDURE XPLMSetErrorCallback( + inCallback : XPLMError_f); +{$IFDEF DELPHI} + cdecl; external 'XPLM.DLL'; +{$ELSE} + cdecl; external ''; +{$ENDIF} +{$ENDIF} + +{$IFDEF XPLM200} + { + XPLMFindSymbol + + This routine will attempt to find the symbol passed in the inString + parameter. If the symbol is found a pointer the function is returned, + othewise the function will return NULL. + } + FUNCTION XPLMFindSymbol( + inString : Pchar) : pointer; +{$IFDEF DELPHI} + cdecl; external 'XPLM.DLL'; +{$ELSE} + cdecl; external ''; +{$ENDIF} +{$ENDIF} + +{$IFDEF XPLM200} + { + XPLMLoadDataFile + + Loads a data file of a given type. Paths must be relative to the X-System + folder. To clear the replay, pass a NULL file name (this is only valid with + replay movies, not sit files). + } + FUNCTION XPLMLoadDataFile( + inFileType : XPLMDataFileType; + inFilePath : Pchar) : integer; { Can be nil } +{$IFDEF DELPHI} + cdecl; external 'XPLM.DLL'; +{$ELSE} + cdecl; external ''; +{$ENDIF} +{$ENDIF} + +{$IFDEF XPLM200} + { + XPLMSaveDataFile + + Saves the current situation or replay; paths are relative to the X-System + folder. + } + FUNCTION XPLMSaveDataFile( + inFileType : XPLMDataFileType; + inFilePath : Pchar) : integer; +{$IFDEF DELPHI} + cdecl; external 'XPLM.DLL'; +{$ELSE} + cdecl; external ''; +{$ENDIF} +{$ENDIF} + +{$IFDEF XPLM200} +{___________________________________________________________________________ + * X-PLANE COMMAND MANAGEMENT + ___________________________________________________________________________} +{ + The command management APIs let plugins interact with the command-system in + X-Plane, the abstraction behind keyboard presses and joystick buttons. + This API lets you create new commands and modify the behavior (or get + notification) of existing ones. + + An X-Plane command consists of three phases: a beginning, continuous + repetition, and an ending. The command may be repeated zero times in the + event that the user presses a button only momentarily. +} + + + + + { + XPLMCommandPhase + + The phases of a command. + } +TYPE + XPLMCommandPhase = ( + { The command is being started. } + xplm_CommandBegin = 0 + + { The command is continuing to execute. } + ,xplm_CommandContinue = 1 + + { The command has ended. } + ,xplm_CommandEnd = 2 + + ); + PXPLMCommandPhase = ^XPLMCommandPhase; + + { + XPLMCommandRef + + A command ref is an opaque identifier for an X-Plane command. Command + references stay the same for the life of your plugin but not between + executions of X-Plane. Command refs are used to execute commands, create + commands, and create callbacks for particular commands. + + Note that a command is not "owned" by a particular plugin. Since many + plugins may participate in a command's execution, the command does not go + away if the plugin that created it is unloaded. + } + XPLMCommandRef = pointer; + PXPLMCommandRef = ^XPLMCommandRef; + + { + XPLMCommandCallback_f + + A command callback is a function in your plugin that is called when a + command is pressed. Your callback receives the commadn reference for the + particular command, the phase of the command that is executing, and a + reference pointer that you specify when registering the callback. + + Your command handler should return 1 to let processing of the command + continue to other plugins and X-Plane, or 0 to halt processing, + potentially bypassing X-Plane code. + } + XPLMCommandCallback_f = FUNCTION( + inCommand : XPLMCommandRef; + inPhase : XPLMCommandPhase; + inRefcon : pointer) : integer; cdecl; + + { + XPLMFindCommand + + XPLMFindCommand looks up a command by name, and returns its command + reference or NULL if the command does not exist. + } + FUNCTION XPLMFindCommand( + inName : Pchar) : XPLMCommandRef; +{$IFDEF DELPHI} + cdecl; external 'XPLM.DLL'; +{$ELSE} + cdecl; external ''; +{$ENDIF} + + { + XPLMCommandBegin + + XPLMCommandBegin starts the execution of a command, specified by its + command reference. The command is "held down" until XPLMCommandEnd is + called. + } + PROCEDURE XPLMCommandBegin( + inCommand : XPLMCommandRef); +{$IFDEF DELPHI} + cdecl; external 'XPLM.DLL'; +{$ELSE} + cdecl; external ''; +{$ENDIF} + + { + XPLMCommandEnd + + XPLMCommandEnd ends the execution of a given command that was started with + XPLMCommandBegin. + } + PROCEDURE XPLMCommandEnd( + inCommand : XPLMCommandRef); +{$IFDEF DELPHI} + cdecl; external 'XPLM.DLL'; +{$ELSE} + cdecl; external ''; +{$ENDIF} + + { + XPLMCommandOnce + + This executes a given command momentarily, that is, the command begins and + ends immediately. + } + PROCEDURE XPLMCommandOnce( + inCommand : XPLMCommandRef); +{$IFDEF DELPHI} + cdecl; external 'XPLM.DLL'; +{$ELSE} + cdecl; external ''; +{$ENDIF} + + { + XPLMCreateCommand + + XPLMCreateCommand creates a new command for a given string. If the command + already exists, the existing command reference is returned. The + description may appear in user interface contexts, such as the joystick + configuration screen. + } + FUNCTION XPLMCreateCommand( + inName : Pchar; + inDescription : Pchar) : XPLMCommandRef; +{$IFDEF DELPHI} + cdecl; external 'XPLM.DLL'; +{$ELSE} + cdecl; external ''; +{$ENDIF} + + { + XPLMRegisterCommandHandler + + XPLMRegisterCommandHandler registers a callback to be called when a command + is executed. You provide a callback with a reference pointer. + + If inBefore is true, your command handler callback will be executed before + X-Plane executes the command, and returning 0 from your callback will + disable X-Plane's processing of the command. If inBefore is false, your + callback will run after X-Plane. (You can register a single callback both + before and after a command.) + } + PROCEDURE XPLMRegisterCommandHandler( + inComand : XPLMCommandRef; + inHandler : XPLMCommandCallback_f; + inBefore : integer; + inRefcon : pointer); +{$IFDEF DELPHI} + cdecl; external 'XPLM.DLL'; +{$ELSE} + cdecl; external ''; +{$ENDIF} + + { + XPLMUnregisterCommandHandler + + XPLMUnregisterCommandHandler removes a command callback registered with + XPLMRegisterCommandHandler. + } + PROCEDURE XPLMUnregisterCommandHandler( + inComand : XPLMCommandRef; + inHandler : XPLMCommandCallback_f; + inBefore : integer; + inRefcon : pointer); +{$IFDEF DELPHI} + cdecl; external 'XPLM.DLL'; +{$ELSE} + cdecl; external ''; +{$ENDIF} + +{$ENDIF} +IMPLEMENTATION +END. diff --git a/GermanAirlinesVA-GAConnector/XPSDK/Libraries/Mac/XPLM.framework/XPLM b/GermanAirlinesVA-GAConnector/XPSDK/Libraries/Mac/XPLM.framework/XPLM new file mode 100644 index 0000000000000000000000000000000000000000..c03cf48cfdd294b169567f086fbd4ca180a0f1c8 GIT binary patch literal 650652 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

Y1?-`;RfmXH(_$3 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
l=tw))A4NMlP8@r2z<;Bhc61y6 z_B7#Sew?-R9Poto!PiGdaCiL%@(t*=8vXC*$CNRSZzHt$8$AIT=a*KLX?SlKt?9}m z&zi2T&joy=sH+f%BDRD{AB}XqcNXzWf?x5ueRPWNb$!K&d(~4?WTf+zw_}C*j$4ceTLrBpT@p-iN}s7yTft}@;tT;?gK>qDWo^n4PNQC zmNw0@Rr(d$RtO!BSLYzMXotU1b#Z)s8<+POy686Y>#4~2ro9y&%TCq8_VYu}$+~!c zs9}Ys|9ek3{f5703+bNEqzPSb+GD80`L0`mLl5vv-s@`TLFRGOU}S8XFn@866`x;+ zU&+`6F8wzc4s~A}&-EXtG>Mysog!;z;Ai;o|5D@B*Jv$m+y+`GA8ee$aASWdIZLwX>x~t(yXc$dItcngJp~=!I2&z9e4LNvq4V)BC~^^F;oI0aTaU%3hXT(T z#>RDx#RvO=Zyi_9vrr8kA8-$a$r)lo`Eh;qOPIN!j(K0F{ZGwGT=vNOf%0>i_$f~ zMSygN^_*kjezqg-82L%Vlqs=g*cXw13Bg*F&taPy*Fp5}nr_(JdBBN2{{=b}b87fU zL;Ir39pqZ4wq4O*_k8;0`167e!U-Qq4sbYHbPRnO8|WW+J)7^4J}y6WM#nN~-IUHX z2J`M3z*v6Qb!j{2^g}d4$+kKm-+~8^Sfokc_GRMZ0UaMRJiU)LWpsajnXCKr^S5+=emRab z%QT@|mmYYT=XAKwyI{Nr_UMy-ojv+y-G$%al(=`oX_YR8Z{SmFtPT$rPvLtJyW_QT zb8bih=S{AB<;deT<5`{``h)C8L7$SD2EX@F!m0i49_ZB9MwqMXoR-NR;*7qD*LL7d=R%!%l0kaWOU?byCjzsBln;kk_uW4vL9wZrbl9v#AkweFFm zNiBy{XBv7ug8KW##$vzwI_iW@=R1rz8zOoh*OQ^~_R~2SXROC0SzN=hI&d|=bsXQ? zxZQbXY(LV@X`0(N!b!K9f0Yzq?2pjmz9Fvk)Ign+{@N)go%SNii2npMC$vJI%xzCx zea9U-27E#zzCTv~aGnqH6l42f%aVr+mo+^JJl?$dk)x^@^jOsDQDt1aZbcji_H$KX z4@m*`mB6Myj_&v-uZY_@^>J-){u&Rf>}r2ck?y5)?|t3~c09eas(NZfxZV|Dh8;5hgTU;E@SFeBU0le6R0GP3N|H?Xbi!fDRj`{t~e7KgDrpUvR%c z%fFvx6K<3R9Ix%ybq~9SctkyNZUyqb0lLnhY%yi9E`;&mGs@!rc~`wMpF^3WLKBTD z8+C)nQo2!}e3Jz2OqI0;!X>=9eln)acxPyBWubtPDR5lWBJp=cozSQ#>u`lCg07VC6xc^ z4l^FBZ8e{3P%a$ohaA&&F)wU@XZ5(wf5wzqhccTDjB|XuLLu0iU+fu- z(Rz_1z>n4Z=4s$lV*6-!VNQrxCGat5$ls256pXXR`D;U6WqMHNai;4sA0A_V^dTH; zgf{9m9$p=0%2z_R7Bh`7$F4mS-p-N`>;V{uu%{z1_noE;Z{4}%oDVvI@h179V>eS) zOu!zw2@-$yQ{f-TyW0Fv`7_in%bxrpWc>U_joLq5rDqXm2VN~b zrD@>JF5C+oOkcM7hb)7=Os}oL^K8V(0nQOeCv-!XCGD!?9v9TNg>ds8dH31s)wg&L z+C7Nz;9kQ5$SQt+tN=Vd3bLUH^%Q8n+q(eu7D>OG-+Tvh-0VM6@4_~oC9+KTcJEZ? zp)5cf$I*tw@30=+ufo_(z#hRoO&71cC3&IOk@uutvwl^7UqZcdm~z*Yy9;!cO1){y zb>q1#c+b~rgOl|<0rRIs#A5N>YMHY3+5n*8O+tP{MDo3`oyMq^&p?Me0_Bf z?o*^K>5pfW?*FS#Bi#$U@Vl}FCf=|Bcq^7Tr@UW^J(C~WKTg{#eY-XN9f}#FUm!kW z@6pH@rBBrPelFjm#kZ4_WGotGof0@xhoZ;fC&v);7aj+VkNpoyo1Lmz@Cp91n*U8f z&fja&t6b?RNY6FtMKTtk4~>_fX!_IRfw6n#g~%AZvY+>m4Vz8g^~9OrNpSd+HGI~% z`blH>9psa(e)1rmbK>F+bPsw%T-s~rHQqw0npS@@(W%2cbA3Nm^XP~(;df%ojF9mp zU&F=;!)2ZYF5(#P2-hgWY@P|1SNZ^+Lx1;bow=)oJjwneR)%wE?~9O2Zd>zZ%$?)R zp^7n9+2Er*jfY+5Wgf*iIK-QxzM)Kq44Y-EUA|&FlX^VQ0uRlG-Ta2|9==lz z7{$KL4;8Nv_#~dMM06I?x^;c~9_M&K552GD&B1f{*6)L?AHS74?H8b>xr`T`#X3Pt z1&{@PEk9t(Q8x+S?-_@-i^OjsdU4Ol2tEG7vej;BTj$+fuI2T4%%?*k#A@5HGi9Cw zJlQxG@ODk}dq#wDq3gVY&l)d#JmGhOr`@ENl`-@udr3J@1-yRnWWAw3@^l&Cr5uEv zDf^h@42}HIiNmOa--BW-K_T*0usvrkgE*Tlrj7%ej)tz)bTn)z>ak?p#3mbBk7tRU z)bCSHgr8-v;qF{5i@M&@$R#2I621MQ|=E6_Lb zTYyfBzs7YICtJ%Hi zH|3N~9}LC>G@zaWy%nH7TaWk7gXmKszq_nyV`q1SzJ9(9@SR~g^V@3Y5Z$*w9X9lp z$N7x3*NA<@r3=^DYUn{z5BSUQo6y+KEqpd@YB>|;#hsKhlySD94;ygLqO3GDhIOl- zTw~}XPmk-Bq{~r47c%ZwQjTf55IWgu;%Yk&8oZAN9kd7?#5?N@ei2`>d!B!uYsa3} zc@NCW5B&~%TmNtd--3FJX-&(gS;5(1-I;*zK97g)d_Cu7tc4=BebyGJIDEcJW%Qdr^)D zli)i9(M}wtJZs@|3r@EEjiYUgYhxHcFZL8T-yPLwpCzFVoWsR>kSBTVO<1o(Ij0@a z1E&<)Ju3l!zWpWc0J1tzQ1?Z z2A1a-2(7sM@wV!uk2LJ@g8PJbE*Wf}FyZRAZ3TQu_;$6VJ%u!{N%NYtN0Fw#x150ayUrKHe%ln#NMN!GJth1j`v>}NhV0?Drv3PJ ze`|UcXvBPLT9px&;IAE6vIt87>PupMluh!Ec?4E@KgRVwMStTOI+Jy{^1&C>hBI2Z z{u-J8x%kzgZQ_;mO@7d}P~Td>$8)fRo*C;9OVb!5nU@P4IrJ4vcNoXP=vdl!#Xdv7 zT*Nn^dtNZ|{9VE)aK)@Cn7$0Qzgp(REbG{pq`6=W9}>QcsB16r>#i%NoSf-}^&IZ^ zp)NJwneN*kTQ1(dkg`&MVl+6v$w>fp+W{c?0b=bydj zwC}NCr;N!Udrm(*6WMdxdp7<)rEb{c+sWq_`5oBv)3^r+cGU#&I~#oqyAboSq8YUjlC})%K^rsKKKVSdf30XL?NsV6juG|^ zRcbjo`_&&=_sXGa4N=b>J1)NjiL0i-zu&W2!kH~dg**^r0G3y5U(?e}xd29OX^p(0z=p_-q z(A_BW49*7kVt+sM#l;|b8(6;=3E@X)1bC) zsGcwmX6tg_xWHKoI63z5;M}F*#6I$^*hjwAy^kF0A2YdTH`w_-e+f7R##sIPB+jJR zC2|ciZu&9cGKKUFI?QJ5X~X){TuVHSbXnukvT%Agc>^*+=JvMw(bFc~=;;sMqMUH^ z2YC=vQ0362p-0(k?miPh%iuq1A8EUK6?UxbJx2TVVdVI_;oA_u(m&tJU!(!nAIbh; z$bdqe0l@QnY^Ga#xDU6h5%SE)#b@@IvU5;x4(6H?dm#1*p7TThazX}ohgZo>6qmN!-Uv2fz!$D`y(q=Z#^fT!-G=cA#^BRx;v^E|tobe3fp&NbMpyx2a z2d2l;2lfSRJwyM$)4uqRkoLIK2l&I7-?jGh%u>_#HIAG_-yHwP)-XJ-xhdgsWCYsh zd4g5Y7ggwU1!COx052(!SDApL0`VB|+4W`f9(b;T9Kmx4ekjB|nKZl~PQDSj<(9$l z-4-qP=15GJBO?!ep$=y}B#?Iu3@z-xuQL?7XIILEdp05V{o(6U15ext8Ta&2(E*TI zl+~1heBbaAd?4XGKRSHRMsE)5Y-m5AAh(}y_#WuEQ)T#GM4hG#^Gi9Y_eWc}j-v7X zBRM~jbRmAUZjSqhH%H@moBqD7+RF8HjL|mQrqx38v9Vp0Yxqu~GuEQ3u{KD$=lOJ? z-&=uawhg`e?7eI^LRUX}kUkjTRqy2zSo-K2bB*_p*68uxYSw3ev@|@%F*21hz_$r| z`Y8vXI~;lK3*+p8Og!Y!ku#48>vPyg4!uAwtOh<;0=N3CzDBh&KlI}(SO@4<+dxQTEJl9l zpU)x|rcZRV(Z%;1PMH8&mVK0g^+IRo0pH3%+v!3%2S{+yD`%7NED&4$6ZTylAx)(N zKVjL3bQ9C^gU5MJ9{NOn({vF#=jJo^oVe!QEwJla=xar}k?2!PtCj@?fF(!UKtB-r zhpZa|c#V8`T71Uzdx-qgu&&Z$`t*ZtIpNqe`Jq#1$w!dwPeqUK)46(lx4gw))(Kwb zo|^c5pp8pA2j{#Hx6XKQEZ~z_E#m=u5o3z+cxEZuq#W7S@Vz6PtFB`@?Mc|-d_RX{ zK;4LbtPYf3Ssf_#Jj$~$0!=rHeS~u*dU!4(ZE4-Vt#{#<@_r@DSkm|R_c(Sv$G}!w z7vTMBt^=`8!0j}|*{sHIMTF0`n)4~1I?B8<_A72;-|r3gJ;t7YISzdTmI}&E+Tr=3 zZ5xPV^i$TPG+l42w>lW-0y}Fn{7~ql&}e(;eey%mW^WGK2QTz(=Ci*4uzWxsAWZNB z_~2LIxm~_x@R7nsqOIw+^|TNBhc^?~_?{eWy&n$8{?=sNo7j^d4#he5DR_px_k&)X z^^%4A@j=*hLD+9N?!n)0Qz+Q|zd6bQ)GjF@WBi_9u@e!~k(B@v?M4u%K81YOQr=P_i{{xA$w$(r8 zVxA-ChV$G%)7Nc?FU0<hg9Nan%W5WF1I{)`iIrw$Y7r3@#_9oQ% zU@J2wg81XUU(%!%xRu9*4vVo(<(c|i}@56`V71q`+ zM_$T0KfXb6xk?hB_vNVfGWZlP!+h>C_!}pwJY3^}XX2XYYoy{z!JDTOJJKQNvjheil4$(ckx0n@@0@M1RG~DcT93G1O1rruYZZ zx8dj`<_TMdp+1RGGSA>Q%oRX~wtDI;?neoa>1W!PVk6-_<{nR(81u~wh<~O@`^GN8 z`)3_{v7g`QNw?iPWh&|wyA^%E3wCQ!e7hCjqz4Z2LnqDNmrZ9WL-IpYBxVBXi0c`| zZjHn5+XSAUzv>Z5oFX<1m_Ahw;&>yEcGA`o3nLN?j;P&6d zoM!uPlTPFtNj|J^@fh)g>wGT*NsmjhBgNAY1|r* zr{c-XXdL#gjgQ0s+k9C&SM<*cLoU^Qo%-F@8W%VDAoAKL+u^t1uoJiaR z*JI59It4U08flfJbNm|px$$w*66HZWp1Qy}Oj-03GoGGjT!W{14%61iIZPjU=qHo7 zAJi`};~9HM_#GMgsMgVj#5qh`p)Y44K7Nnreb{?ghdiNmU=Lu9oWlfP-*7y)VNGvu zj?(L54W!vl=Zt`@#kTtXRN`Sm*TtN}^zM4`Z}vZjXiT*hp8{SiSR?_BVVP= zUxw^5cF2cANvFQ(bC@vSzhf%<8~+@p-V>BLxSVsC*#5Bo=P=#j5#B*P20s!vmmivR z%<+8!7l;dUpTjgs>nzyPKCJ6&J@EaJvUVzV#-yjY)+{ldu;DRx+@b59v^M@ZOq1$S zzd46#^S!|LHI#d{+I&ja-7%HVT4qg}PC1Wv{=j5y})WevIBF2^r9YY2>I+E{5lkRk^3(Gl7)Sb>52sjVG6D*znykobEUZo9y zz68Dpo2ARWZXW93J_q0S>6`<)_Fi3m0z6^X>BR0{>EIdh$oske0sRDf<3DCLd@qgX zAq0qP=E3`?O<7y^`m|y12Yr2bk9TY3-T&q8eBi69u6%#;2M7=_Xmp~D?X`_HDk@sE z7ZYrPfeB5}R6>mkC4r=p8X!Wbp$2n-*g}glv1khwXl$_$XLJTTI)g1Bc5nuj&ci;P z4_a)Y#Xf9l2V1D1A?JO6`~11*o_muU`tQwW^5JsN-Fxl5*Is+Awbx#I?S1CRC;r?F z@wfKMkvVe@O!QviarS)0H^kfcd9$9uuP`3Ne$KUS+_CQWF=s#wT|zcvLf>WkV>`>P z5Dh$=LNNj*->Md`^~C!yCfxs6yboi%{zr(-oWWh*WvmbC1Nl#ywShw;V1D+vyI-Vp z>xJ}Ldy_?uj^kV)_6cp9I~ZiU$e+z`ofqUht69?=i}(BNiEh8^2GwtT^Ci?1k1yqY z_QX1%d+Lmwm@&yS_b#~f&Z)8wozlK}XKWw(D8upDur49S`89W3E1WZ28RG+WJgff4 z$L!EEs>6lL4ZxZ4mrQZz2R!hDX^flqP8Gu=f>k_qVq4sYPrAcHdDHZ)eEnXzLUCGo z6B5$CC3`3D;s8$gGDbh!xdwf+nwW@{PFZv3h_Ok&|2i~p^wuX;_V-_O+S*Vq+Lvsv z+7NI5EN}dw)z96t6n#&Z+zTIeRBfQ$^_?sC>%Kg__nP&uy<1~N{ocJG&e|@-tIz4T z%cI1SN435S@+sxVdi+^sADrQg(S9>$$j=Q=MYR6%cm=+D);;%U&K;pY>ZRXP$%(PM zr5{++=-n%xY*g9XhR8P|yTh^N?Ay#*utT!{(^pjI+PSH1mHzAem#0E?4sq*5R(|UE zQsA9__dH}1rNs4LZcD7U@5w;D7Y~GMf}Ri!cxR$yCXp8Zd@5A`H0ci28=F*g*wBbO zj749)mju7PrM1`c4{I%y^&Rf0izVHiCV!FI!`=_bDEH?5^8s9y zC-usXK^{7GT!y^lHj|dG-@G$4-$@&JKWPy+E#ktJlQz~(8{6^NFIDym(o`;L>T}Y3 zAEk$1aE{uk_t0{OB=$~FU+Ela#wR|+=bKi>il2R?v7~*<(b%>rM@!1B()&()U$H0h z#~zU{CN|m3S(TmZjV)#3>+d`Lee?<8028Sf9TnZarNj7WXh*UF9b#sTyn9ueox6xk zeNASbL(YFX-<759Dl7P}zGzj%W|;P}FOOw>h`6${Sfqe z0?8up%{t|LZ+KnpL95E>x+&NhBbV~K((PMrly_7jlcli_V25I>;oFGvJIeb=PdoF7 zoh|w(b}-g4V#F#+(SklKj^$b51 zNRN{4^5O79@=?hTXwF(~u*=~0n0Wnr;+deo8+nr~hvcb;d%&4%{%Hd8qJFLsT}pZw ze`IOpq>Boiv!3|))PLk8`u*>WlgvcLBb*h47O@~59Qk|mHut>XUg!6r2Ut_X`+0Zs zjV?R1jBoVhp(WB0JV%4Nm-LxR52gj>!PB1sz0j>V#gg4O9*A}Ek!>!1c^+RSW5U@r zIoP0aZ%*3>(UzL*rLbXPZSE8? zcXqKZF4diT@U*+9I`U#??)=6Oc(}~0YmHr)^BDb2>DTo1FMhQg<0nQZs^8-EfG^+p zYpd)ZA98T~P@~>K?&(R5dF)=s>k(vKayOhkdRL~+JWtFke$onOt@D%DqxYiQmRs1H zc@OX$k?qBA#dMcRc4T|;yOg}Kl0DKM!^e2S$X)~Me&gHt$%CXF5?>1Ma@m0<{m0H- zQtXlGx8zM{nXBym8;!g@Vu=qcrI$=T_AYtL19>^(yOP^EU!uJfd>OzNxaXmrch8j> z+d}bJt)h2-d=!Px#mD~o;LG%@>)VZt^{VHzza2bNtUV(44)KoHKi1yyUWsQ5baTFN zJa<84#Fmw}iH{iX3fV+%{rKKlOYSId(>S>NP_z=hsIvd@d9B;c{0N@xW1cG*`jaCY z2ivH+()#)-XFWgsT4!u8JSduJF96@Mp^-bL39+}@Cq~~!*Rr>`{35*J@7(fv=+sy6@hZN~;lWT`v3HIv3Qhr;>rtOIhgI4CV(wK@eccz9wMOTD z%bW-E=o>w#zVT_NZ~L{aY07*mMVSuc_X9`xJWagqx~o;*=eJ0FS%V;vxH5^cY;sZ}WeTnBUXdr~988^P4g*yM%ZPvv!cq<{k*iF8ZMx z-ZwF?(tm58H?gniuG1N=&Mt^4&O~-Fwu9zR@+Pw9lnsA5??au${xHAACuU9w`Je~z zDd(Y!Q@j_U*Yn3~uBtJ02K-uv_i5wI`m@hHL&#o0Qh)ZnGuZw}SEP!0KQmn3U)n!y zdz;S$m$2RvZQOAkD6aZN=xXdp&lXOl1OL#v%=q-b7t_y}zxSYMg58pG%u~&E(%t&t zFLCbk6^~#ixc%R%KDl&e?)%%v#Y?_F!{sOWS`5BgSK}klde);~V(jzD2aWyl6J%l2 z5#f2#nX~QXj{Rod8|T>O;g}B1dFV$EFV5OdHnyYmGk0GqZl6!K;q$=!SY=;&0Q`3O z{d4QlS}k7JkERl<$C}|s<$ObnA5GvppE72DhiB(rO}Ae13rv3{qv!#*p6(KCa^f0F zG{;uim#j8xntOFeQ1J|v7@MrGaaA;Wng!t8w9a!f?7zU2AsPKk^^wzVz6nQN`Rpt9Qt3 z4#Ow*C-)4*+W;r66~>vrMxrh%L1!tF}~SLVXigyFPCku4GME5%HGZUmvJzoH;Mv)jdw~UTJ;FwQb6l<2%9+cEjt`w+|hj6TY{f zc;H>KOP9@>j{oc4OIfeQ^o|&{WADoARvUItLAM=?bgz8g+Gf`mciUy-x~uFB%N*Rt zK4Ea*X|)*KfuXHfY|@BEy#q#bcyHOU?#{pamF|k))mwk0`{hTSJ*eK;!S3Fk{oOAw zw-5I2+SmPZgS{UgY1zx=_P&>&$6ogKKfpWw-Vk%Qd`x{&eUh(A>kE9l@4JD{0lGlr zM_zOAy!@m~;|k~Z@U02{fyv)mb zJDQ0rnRHn%xU=`|wu^l?;UX(qPON>$)N|UGU+V7_>7Gx^^{M7?=ErjHZqyygyo>5` zt9vH)mbaG>TCa$=e0&pe-RhLTtj48ByZgJsrPn-ny;ZODl5bsZVgY!6S+jdrZ>81( z@+GkE;Kob%@2?Ns<2vkz8fWp4*>{IWz5PGlkt4hv*-M2t`#Ayr!d_m##Ne2D={mqY{4KWU^xgKo>M(>-K&s?$irSQJR{z-O_H=K3VBcGyom}cE<&Jm5 zH^v`t@EzjrL)qIMek&f^x#FPefmVGw*O7AFZTOgVZxVhhE?L#tW%l)qKCZIAc?zG_ z^U}>#_BRxF;h)`rf7~-vUugE*39Qk*wWQk88b8>U>eE>P^!6y}S+gd7RP3>GN5}54hP8FZ%-+xu!|%X;;-}IF*{^o&xF8?BN(}QQd5U`{ zuHEceqmL5q3zOeMeGwdY*FWRaBq)oTM}Z;#VTX^FUg7hMXvg`xj{DvHI%F(?cP3?R zUH)NseR$$sC{^~lQ!Y((_Z;`Ch^|YYQT=hc-ur?>!=*cvUS%)S8s3S0HuPTl7{C3P zm}pNX^4aFzop`U}5Y4!|yl-T_(rUlk?_+4(4S#7*h!}(vdOh|DbV`-|(213ATwF{H zmSlOi`_7Hs(j}dxFSkeUy%-GwU$ zRVVKZ8(w91Oe8)id*uOVUO`{zU2Wpe@tRx2FZ8JxoW~%mW$Y(wztr77yZ8wEaAlQN z&Md(}L&qiv?V%YOO1Gd#67P()v0>Jlc!b!bj~sSvm<$s$Qi6`IwC*wSW71y^EtbCM z^y8lAtL(4+5F7*Je$SKq=B{$^-RbS;-rGQ$;UlNtOHKTi=*v46%sa>7uh)PH@Wj#= z_^rFmiGM6w=jh)UcY7YhufiEN)^rZdGe#*M5qh6+=AMrnaOdnsqyM&BCdNjx>d0Tl z21lkovLCrKHmc+!rR>q)?hk%sKX?=xePi_X(kq;Hm%QNU^QAgp(TZNpQ9MylZ%fun zt#fD8TQg=P?hP(&u8l>mtL5w+Wox*5#>}y<{kBHF)Kcs3{!V*h_1540{h;rlD%*woXN@t?BEh~3EOAkGdQMtq~M!wS2GaPDTZmA(98_9}+5-#CT4Up{K( zOtS1F-T$h10&Kg@Zk><0bv{O&_fx0N?>uhmWX|{NERxTheq=8%GBGK+-9s5vx8CT# zS-I4G(5st%>;9BpwKLHE;Xt&J?(=jUb!2N^Q!FC<8n|b~-T~dsJm!s8z~`N#I3;M1 z-JOlUm@#;;Nbk904>-%RrmX-s(ls{pDVy^q-u+Al#>`R9eo5}&_ka4XcI73-ehK%^ zB<}wl|0DN*WTynqW1N0QZTGhqVEQ9nOx%G>*R9wZ!8>VmPlCCBj(DwHYy{m+r+ub) zJ4R{n z&RY=2)hZrD&Wq(6qCYM4<6LtWQn}T_d8AyoKP?a5;LOR+JkV?Qmgv*oggyo5XZTUE z3x*fa|G{%wRrcA_LC zd-CP2CA{_7&al7!U!0h47tioJx2w&W*l*d#Ig`;4!_SQzdw0|1y8im(#$W$0oPqi} zYx;Y1_Tzoyw_m%CcQ3Rn);MDvX>WVFIN-l0PW}tncWq`I2j{&--;XWQ^k!)Kp{&(^|U z;bWt&d!X&gwR2YqRiqFrRB~H|M>8 z=_c;b$X#fDSIm?zU*87iUk!gkZ+oKTOJ%(I#q>*iYSIDRO%pud&sn8u#0pN(m>GE{ zUa-m@eTAnR6lcX)KI_{@PX2I5-shY1S5@|?Q|>-RROflbmn+dBq`%eqZ}5@U*YKWG z*LznOy<&J{)br}E>0fBiPxhkcyK#Io@3v^YfKN0U_UZX>pJP2U_kshSynAt5X1yC< zyKW`s6Z?DhWH-LCOtzci&`Q2_L6md0IqDndW3x@{&=2(Py`k4C-Cd`Tm5sqZZZ0&5 zh}QTR%os)Ic0A$T=Urt#(CdwZm*(MRY~cp`@Q)AKC*|Yw){^76o2IkpqCEK<(w9hN~PA%!l`UiMwI75`5icyF_!*V&);Vi?8;nX*+0!yTQSSFClY{8rFlGoL-!b58@GKe7JCaT7m*-GZJF?kyG$ywyw0 zeYh=?VoI;U2B_VWVO75Ps8!Qz)fb@vU9laTXWe{2IASNoahw>y z(Tv$(aol%s8?YfByhu9Mf9K<>A9||7hG7Y2v^nd)%wxjWy%zp0E0=ZH_EuKMxMI z*o_ghc4z&HbVG1$R#Jv6#AU_9(T(5DzR=-4tBkQOa&a3Mlo`oU9JkEV0o-!d&a!gjG`DxT zIGOj@dg~W(iUx2xC>inZu`07ZDtXblQsH>zh1m1xIru5t&=bCme&M_rbr@gZ%5VLy zC4et5{yBA3(uG-RF8G0A4(w`vx zDUXiuf|tIZ^!4!G*h;I#^{xMQtNOd#@v9{CMf?kISn5-3(s`BGEd|Vt`D%}6^?Y?tS?`qWf_+05a$qdigYhONh zx1mwMzBY5va{GwJQ}mII=jpzHeXn?Ybo0u`jc(?>3+7D3PTm6n{;^5#n0+GF%L#qk zS8C<`pI&^8asOb#`^}Xe*U|SJ#4hyntL#;^!p+mg(K3gppjDoD3O`4g^aXqt#a6F? z*NFG-yHI;7(H_ll_N89C9xq7GU-d<7nmNe)w=d^iG}!jUct~$lZ(`1{pe?_(j_aPx zT4l4dzJ>odTURW3&jsG<<~Qrd9GBL)=mV3s{3GzrYU7j1>7J_Ch|f9a^Ie|v?E=cm zAE@%Y>oNx&ohu&Dx{-0uEqT+OKXzL1F8eO{Wu;p*e@Ax#$5_+939+5D$2uE5av;MOOEN<<>*cB3fzPRqoK@*HP_Hx-wW0%e300 z=YsT5|K$7BxPehX(GC~>Ko~y7zRXtbb*_oCh$9A=mcGPAI)lhJ9})-@1>3{SwBX6VrU^g3HfO>U&u~0 z{gqs@cM_m`H}lY{@=Zo3z|W&AXv63Pp5-eydu;TDeS~ukv7W4qvNq_9tBrXeNBzgvW=-1l8e`$D1!Sk>XiXbq4~{c3tGw}& z?Qi^EJMrUEmc6T|Bm>kpPUGdKZFFqg+2^{yA6U5qJT@HBT(U-XGc@UU{r4Pu2mu-x z-Nf1gy*ny*<)v@8aK1aYg!4VLIWyLwdxSbKbnUCMl?OQUyxl6${TAdG^KLy0KSUn# zdpOt!XKdy?Y{t*IV{yOaqtcr5sPRL6KvD?gR?f`e!Lkby_XxU|XF9<9nde#Ctn{l0~Hk~v?pXn0a*k-0lBI3DT;{3Q9; zc{uJR8o9O7`p{FNB{Y`|dg<#(H|tiN*{ZUazF6|8p+l+G3*r&>l*;Ibcn}`Sdl4Kf zJ2w@Jf6aYDl2_g(n|dD-`%SWg%q%sya^J1DMsVk~7`U!0U%`HigVQ>2gm0N6PT5ZGFl)dci0_B@FP}E!e7})^j5a$xtw_lJM@S*k5<|DjMCVW7d2x(H)k{N zFKcq>bhh-F(G#icvrs!mr&rmZ-w~=0KKbam(&e&MpkWR4KW%K03~awihc`$M!=ui= zJ-!syBxT^}&-LJ7bZRObYUJL%-(^cGi6T%&SFbOg@;>DKRWa0-Rh(0Z1|dQ=|yao zdT%WBTRi6D6Ud9}o}o{J{}69nQu^YAU*cNb<$<4PyM1g7%1V{pZsKatO@SDN+syli zjg9lDY>7KA5^j~&ZRd-YRrXBzcLICWw`K4<6r(WxZAT98m`q+^Kl+Yqoq6r@JmAg=fqv9Y6%O%!+-(>|iw#)Cc?7FJT9hH-FXoo-!?%suS&!NK#^CHPa1xwObt8Txst`dw1aen;PN z$#+zK`KrDX*D9T~$+Cr!#jco*AGVLPkC@T9fp@5Eu=bUI6<_fqyDaWz+I?$%-u1el zrt|fTD=C{}o+)ekY9GA9#O1*cypQT`)#;|6t7pZ#$rqut*i>ZbGiT>>*DtX!KRuyz zlQ!vKO$jlTPPy5fsWICN_qrN4<52>^=N;fwjlHgH`sD6SN&zd(^(2 zxc2z;DM!9)-;s_LUa?6(QGAFivl)3onWe74+M{*{zXNNJTSxIbu=e=$X@|e3KPUj&Q@i7C#i4avSnv;i{F!V3 z#;fDP^Z!A4l8Zsau|-s`AIFA0h<$Km*~ANEXB3+H6$eKgtltjzOBg$Du9dM)ekSti zZ;gr3mCYWQe>9f(w0iN&7{65bx0i1Gl`4nb3%?mZGvkYWD?94b_nW(vRvLTexZ3h* z8)%DmwyS=Re~@ira&q_9TYLAauK2sIX1rFL5R;Q>eBzFe{?pv^=ERlsQ+E9TWw*!6 z4tb^CYMT{mcb0JH9b03?_ilTu;$?;x)mvYk8Y**XZLD~F>iD5gS9|pHz6~8^b4g|f zb#DBj<^Mg-jjxp-?tkRDac^w!#iqPd!5g!cyWt7<40*|B<|=puUg$vv#);pFi};~g zPf!mwe;IR&_6*H^@WABooZIoitafLQ&EB{6`^dHQ5PQhtx9^8+ajj_v(Po3+<_dJf zU!=|Vf9?tW!GTf|x?J4XDV zyS~lmcMiXK51sL|<;J?qe#x$G<~dL2Yn>zA=gQ7jcZ@f><7w_okU!QAbpz3Pv!V) zj6Tx&efnIi7#1%siP)M4Tw4Fov4L)WQ12z`++gD3_j~P!ZK3dZF^4}0Y|_0p+*Pz! z_{f$p-+f0}8~i%o=uX#e2*l|0IJms)-gEt&yPmu0w2wz%>`fhR9~0l*1P`+BA|Dd% zzDZwmJX@0AtJObO*T(N=4*B#<|M1Uw{D^%|9D^WdZYBP=i4Wb zJ6#R`91NH9`{Iq;{j3k-F^r1suOW_VDmd4$_N&#oG5Q%*jG?oqeBw21{-}Jj#twJJ zSa&M5nl*vsEHIXSdoJxfnt|in#umm842|+!`s?nAd_GFkK3$Sctoppqz&vap;;sqq zgE;++$1{ev``$KpLR4CRZPv|IeQ&#WSXJw8$CN$`vzF34$XI#!Q|CZD-aKd?59nNv z$NzMES!M1eb@}qOzdT=la>yC;WxqP9Zsd1p(dRiX1gN$WV;9P8_2 ztzon`7k}S{i(~Ke!m;yy_G}EEz0D4u@0fMBk+*>C`tlX$QMaCF&3gf;V*>tP`fIOt z>Up+be_3jM-mCLZ0eybTmBkwsua=^Zr<`}0q64Ente=U0#iyDPuv@yhyT07;9P%oh zltaDFuz8$)j3YiD2k}5Z%eO_lttPIRd4}i4gt1PHm1W&C zWt8x9#^l%)&iA|Xojskumaca6Tt8#&-6JPmr}!SNtI^5A!5J5LDA@M|9SeP^u!u(2|{ zSaq!df@^fG51@_98^6BTv*kO=^71++jp1Xx!hUG3*6SJ{t<`1o1lH?&6!RjzOc=_Qyo)9`{{t(QL<_L!Mf}FApBg>r}kjPU|rJ%6H>+3$_2x z`?i{cxU!aa&ZA3rH^@fodkp(bd|E5~kT=Erl|iFj#6Rab`_NXMbPaV~=-0&>DMekk zh3YcvAL?pT{GIRu$3kPnOI{sX)r(fZ6iBz4JU6}bvug9S&QaI9?*bU>ytl6Wgm_Qm z!n<=;`#71guv_8LTIkws{Pg0b(0a}Ay6caS{?xe-SI@*aTT&-}q_4kT`MgyZ#qXf_ zWazBeQ45~UGh@ENJ-^z(8F%(HxNGVu(a4z(Px^ZY?s4C zqssp6Qis03y<5D)@8Qs6ocK*J{JxFf{yVDpJ=KAG=a3`!oXJ;Q_I>UeAuK!Y{8O^a zjIY*^u3xw8$-(+{J>6y28q6ihw*GI%I8{>%CuX9Gu?!#Or@Py?4Zy&yGKt z-n(IHT<`tz*+g0UGwD6?Yur|J*OGlF#9ta)ttU06vL#sGWt(vg%;koE+;L^z&NFkG zd%j8jTy)B#%q14OQgOn$I_JLj+vsQfH}W?qc35Y3CG*lDdKV`;<;m`)CZ0b>=i5u_ zjn1l3zB4zUo<Ygan;n)_KgtQ@~ibPjdiMhuM32;}H}psp`NvRPbd z-S8>Xc9Git%^`j-cjomQZgb|N=u^%v_hsPCMeIhwQX{ z>Fu;8)~wA0@5{Ui>J{%gm;cG~MxoiQt2=IHAZ_DD;ga>lcCwUc+ld1F zh0bPN!?yL{^;H@>?X9UHeWksH6n0w4rGGws_4E7T17j<8Sb0_laSyeV&a(eFJ8goA zyAz$O?88j~eP#Xkw$pwd)UDcc`6KMKpU?OEjZK@PuD_6-7M&Ki(|-24k5i0zx$T3n z(`2`$w$tiMh`p13L{D9T4b|R{ohF`cm0WS=6I<6=Ul}{?QQ2AVKVx*PXO|g!v+rtC zUxQW4dqUkc=G)IoC%g8T(jWKiF-QL2Uhl~D$0WNwz8w~_I~5P7*aI()LUR#1(>>FO zz8gktN6Z>qwu$&kVk7olWJME6jte(+XvC2}ivntR&{!jQ9gS zK1+D%o+)t1GjlZfGsl@TAAD=>v`p;Wq#cDi2cq9q_DwIYU4~D58MZX@4(Hh^UWRLoZ*QQ4o&ZPdq2FJt|n>a>H=OZ=`i| zJ?lF9=FW-TmDY8u6?3Qg-`RV-=|bT&VUEGqij8#EQ;dnunPvzET=NXwhg(O3u`2XW zYs=zTm6f|}?j4Gy)Ex@Z2S3dC@ZQyqY~urGJVsxtzQQ{-@_R97G2fs40I^cq^E9!H z-w)X{CT1n^tVg%-DfxljDEvLYNToHxi^nR9QMcbtmtD=hA>eoJGtk%A>1q!;XpP2t z@7e}4w=Y)=U+!`r584d+FTB{901b6!3^}ZR3mg=`SgKe=Y>mq3+`cD>VO|o?s<3C=>4Bp);1+3!(iXe(W}Nu@_j;TV;PrF;3&@Q<=(ZomgdmD?>D( zAH)!SZ?`ih89Bi*@pwKZJ;n3zx_oPT$A{s0{2eZDm>B9Rd%B7HFW+fxp^u91uAz_S z9aGV{rw=Q}nf|Ra{gdrS|L9X4eb_<&>UgfEOeJ;dY=Qb$$@$u=6&nOk6)D~=`T=|+ zKfo8k*(&C!Quzz?On=9@{iiiO=pny` z)_N;fJlhLg+1hgaB9~#a>K#wSg-Z|bnrI){HOoF4%go5$wah-YYomQ~*ADD%_dMvX zH?_}~eNpG8{d(_DA@{p&hn6wPX4p3)o(RSIy78pjwz^|tdG&hdD8wh&!bMf~Cr#`) zzuoxa-gU%JPZlp#*^i$F-%@W3Q|c{rY=9SIIuBH`qqm0lt>l)J6OV}BoVwRB4#Y72 z=zep@gKTP{jqph5T`*=mOJ3Y^S^P-lA$5%;?9+k8spnxFH3%5t-+-m9RKE(4@#Cgmi^3$n+UI?k(=~m z@cwN9dT1T>$Bh9xcW`k`XBIn_7{_!v?hil1I3~|VHg{Muf0?<{rKg!c+53^rXy`ik zm+jsfL%K@#)jZ;nJzLS}tO|6NmH1AoK-`nXoo^;?EMeadUFMA;{vIc`gK@;y*Z=!O z`d-=v?5?W5m$p~+yx>w9K(fFVkMG<9iC(;D12; z#^7U=0{#Be$8TIZIS^NL;x8Y+QEcuUmObUha{aM!MUTOA{p>Zo`)KlBgMBq)+W%gI zJFh46#%Xi!YE|F!k2<_jJn{b*Z^#x)j1{}&?)aD@m#nEJmjlL%X)VVXc=DwEEPVcTvt`qrZn=ns z53&Y!^@OJ*WVbkey04o!kV@;KH~qGPc;a7>zZsi2;4AL+$~>Ncw=1*wcFZ{fqtlY= z>b*9xuJ>Pb#`mIG{nWL^$19}{d4IhVQ}ne59bK}=jWzh_DC+xD>5{?66eaaH9Pjv^ z8}AsIpSr*AIq{Cnk^S$%9d}|C65?atdmwQS?ma_?s=gO4qMiQZV+QZjPO}I1`v*ck zZN+-0@M#y#`1AR+fBTweGyLiH;6D6<(VfPped2Mi{y%H%f#fJYC;ef2aGuTx+-Hj1 zX`z8Y8mXuT`{q^rxi*%N=v@T#j*q>uD| zZ(_DKnwWxb|1zIFDPDxjUf)i5LjC~z-PLB@T!B9T+YuXL8Zh$Tu;%}PWW({r1=q^d z@8-L4bQfOg*`o$G=?7v{I(C1|!wntzZjwSEjI8 z``{OpYYSz(e98$d2GB$ZB+Gr@0GudJpOJ-NFMvyV~V`+XOzd)fBHS94_zCV z$KPHQkVp14{u}R!i=W_+K__;RC z{_%gEKRDSgeEZKQ+rN7DPcPdaxGgT*zq$4=BHNl@yx7Y>JkBq^?q`2B#h&k(#Q9D1 z`@Q1-=l<~pqvHF=M}v0H;P#Kj>*zbh5f2dOcY^)i{^I;JU&;2-{($2Ah{gMIlXMb3 z{3!QZniz4jhivrE`~AiFRjUok-tFkKFE=}K|K$tOdtRJhHTj>C{x$q(^xl`t9k|se z9J$Yz{!JO@r}!M%A>KZrsUyD6xs^3uvDqt|YZb&MeY42jmr2+wqwO-;W--M&0vFt~ zL52(5JK>!Bk2W!9%>6lgAAReIe=1?Wp&M{A3B~r zuU%z3t-J|k?5C7j9|HGWo-M_7k$)Ze2gz4jCTVApraQilxoKIX4V%Dya~+fFq7&-5 zgKlcpcP7j-_bwE4jI8;G+DYTCnQ)htQELs|*)b`roxL^gIkIvdn8=~1$k1!3D^^Y{ zlkS9Abs-lbS$^8F%enudocl~mc3Bx)=?~?KN;7Sn-it?bNgqHEx; z851)cptENmS6cbYSH9`e_k;HFTDDy}?-Px!_8#owXjU+8GM8O?PWyUb*B6-Gd9r)z)GG4U4>t^t<4o zoO9Zj-NomV=cumi_1V-{L|u(m#`+3F+am4f>Q0r?pF;n+m*hvgE{R0{?UH%X9_ybg zt@Fl6o=jXFev{zdr&$vrN9^VA<(|?E_L1{?vMp;X`$WpCeM~VQf7Pw`hjctPx|OxY zfe!h~SB`EqW#>j}ymeJ+*@x`!HQvb>tk6~$%PwfKmP z{zvg4oEd#6bFW zC$6tOU$pCoI_EWH2$?$ThqRH>f8@ns7@J%3TR_(vJwIuEYv+mri@1gH>_O#3W42A) z$wuSv+hIk7yL7ee&{)7P2mXzIzg%Bh0?yiNiTjsyf3YQ8iK(40Jy1dnfmvhP_AGQl z#MKAn_dTih_;!6yqulo;^qF^Qk^W+;zM^X4^P2FXZLhDT7QAcOeTt)!OqT8N?uwRd zoIOT7gf7dkjp-fHzUls9zD3b z@SU}9GKb1mXH6a)1E1c~?ecf*|5$s+v-lL?MNgkE7w=Yauju9W$&Sox@;fS!(N_O&MBkf-1DfRET@Ni;g-q%{&GB(Vk%(W}*lhFQA-A^Rk;Fo;nf1SV2b$lZ4 zKYGIr^BdV_X|m`Z2C! z>{syV8yzDXKzh^YK6n`dZBIR8_)+bt{=m8!S&GY{=IVRl%WpV(CvY~g8~dtAW6e3zXWj2-96CO9 zlDo2WCu5Ct5OD6j?h)pd(UWPrL3oI+!kcj(CEQB>)rqMWFF5++)D_|v*&4L5QDg7h zoB4Dn9Ul2`e&;vL`K;X?+52ibE*#xj#+_pw zh5Ktdcc9C>I;8(i%8|kH9d(S0mFL`@h0TAJMI+y{ zS!>zj)E04B)O)g7^f6-(j*8u)?-v5omcRo69bkAsYe3>!HAWq$OWHfXccjMCp}dc3 z4fR*558QQ+uj<{`xU+T*d|>X9mD~YKJMX@3Y+HC9c)`7B5Mz=a=#!kO3 zT#W3fUDqy8kR8dCbUM1+#2a$&v4@W*JJ9DD^_%Y>IdPGh3%6z*kB!21k; zf3^6{$PPGmZaP@Qdg^NKLCx)4&3)}RTBADu{#Wf2BFNSUEB`@v zM*X3^Hw`Vl`6wX&o;>-oggul(md>YqO@FdP{e`9;>Xkg1bIrXa#-8xzbo8#b-Y(Pl zXk3V&d(8Ox#P?czo3XdeSvifD$w!WyvHAUl#ORgDrZ#iTzZGU1xsjcN?k6r&vD|?> z<%Tx%yV~%<&onzDZV>6iXhxbmrX!`U#^A`4x>WlqCbq$?Q*#g7g;04W>Is853 zT(vD+No($prmsJ5x4wSJZhs@gj=gb_z3Po}yZem>d)*t$?VdLtwYR+SyuI~}L-w{G zXV|-be38B9$Go5V$Gofh$II=5KYo;VOFVBM`|%ER*w|Dy-`J&$fQ@um`GJ`_KE#ntt+*RN40y^^=F+N>Zctg@?~NS*goU6uXZ%+z_WJY8iU>Zk9oV9Fgbev)K7U!i|L zEB5Q0m-(HE_$8!U?*Gc)YzfD?FH6XOVDrHFf76&Iza>q6*}(Y^B**I~;P*E<1D9Wu z^bUYf|Mm@B{(+|l&R>(Je-9+TKO+JE2gVOv|5v;_iX*AVZ_TkZ<P=IA{J{CEcBRQ*lO{h+`>WFM-)bvO z{oXz4{fz&rH2Q7T_B8d+OOt;zO@7_L`Cm#SA79##rhI#v{A~m0uNpUS{+Ei<`hGEu{NDd`n)=i9|BKlJm%sl&n*22K*>yNg z`I7_Zccsa{e_fjLJp<3`@`*J0 zv4Qhfq~Xt%Y4~SF8vVWENSgN3)t?5x6=~?VqQz?;mqxy6=f-jPf~esdQ|{(DpKF@icH_eNtu0M$%?lUI<|cSH z>lQ3&X^Av8v^6Yh`s}6rZeH;DhL+~WK$2DAYg*LQc%>DD7r?@M7Bn?R<}8gYUAQE2h56qtYRWBcrW~a#>+|5Z zaMAVG&z?5BdBNhQMQyVimb8-|XuqLl5#3xGiMOYU7cZROv~WRFq^V_b6E!WGgVUp> zY0)AoQ@tbj+&E==+oI+Lch)YPUR%xYt3JK3Wy$=e#aG=@KDFYixeFVcuBxkPX;{!S zy`t)>NlThr8n2qxF!!n}uhhTki{_GBJ|4uks+~UjmdR79C*N2*_2!$VyXiBgPo8~K zdF|9sPo7;H#aRit6@(gkxPcQ0vL(iCZJTF@vY=PYT9 zw9VtU=|yB}h2cVnN5wQ#U55N@Q$yR5MNN?f4f6qRSiG2y&_R)H@`47&Vu}MGJny*a z=GisXGyZz&O|z#~;4i?^~9>yDPS$NN^aN4})JLef#m`7xujvN`e z@_#REW$a9zg9r7xzbl#-3o-xqElqQqknCwqix)TCNwRfo!=eSy07_X_WP0zuw zmXh(dVT4+>&Eq&NeDnoeLL5<}O^)(rA)UMNWq!jj#~I-vHperbT{}lyED* z>SNbjCE-QZEdPNv>#i_bz-noj-@KqKbEHja zYMVPxy>-S0+JG_Xl9*ykfkmZduNtPA-DZjSHO;tGQ&UlGsuS5>#H{G*v(Ou%9 zTbmp2Y-(E^NOYUDJQd*7-PEvH;?yv=Nve2JWI@wCKI1G1$eK`XX_RW78o39(udD@d zfhY`rwRk-;s+;z!r`^&tf1&ty!IG(MP4gr7G{BLLB%<^dBFOORqJ{-`HbqeR^CRe< zrgoLS!te89qX%0THGjULt?8--O>MIq9U)nKRYUXamW6ZgxVUkaRo+JNR`kL`&{31{ zf;%293m3Nfd=#H~JU(zJ64V=c?a}%GN`PA_F6rWr8Xb!C9GlS2k z`P|BO1oKKX`1nL3q8sM%0?i%2(8E;Lb4NYd3@G0Rllh0T_LZqJ0WX;!nyZ!Ng zdcRfNn&C|IMvnE{(OCi0u_bQ2NvAcSzUR-EIeAZW+dN18F#9yOOSRJLscnI>j>J2b zW}u{*qEwlw!YOBD(9A=v4b+=x5lnCRe3OjIDHu3(&Xa8eZbW-P@U-yK*MaIinnV^F z3*1)-GZsjdI%c_Frvo!q^O_5uU_u9``713fT3>fDHO_Bfs_|>DSk!QjQ}<#sF11sl zvzr#k(ETH9-x;;lvzIJrRxMY~vo88@f>QS~W-j=!WzA_=+&tGcU$N+?&z@_PYKruQ z3tSz1(+uWw_0}vvKsvFGMNMYXN=j$7;AUyEV6^AXQ-|4O(|;LXsHwh%t&j3yk8u0R zCdVR?!pT2ZS*O-?1)}PX&cHdU@HJn}pd~S;Ld3N8*lPS_;cHci9BRxl$ zxqn21SnEhX$oF`YuK)5!*SJ_Ke;fJ7`7TY7Uqt$T@XO=7!p|=pUE@&S?>qHm5V5sY zswh=G^fQD0Z`Je=G4=4kpVHNT4O~Geo&Kjxr~f9sHUv-qx2~a{nSpe8A%p&J-A8(* zN!Nca?`+6^WQfa65swkbr4Jcm3?x z$abj&TxOBo_i(WXcPGGBYPf3P_Ihylq=ut!nQeC8*IH>mU+sQLaDl#kW2ld9tBZrm zY_a>kUgMSd%HYZzu>00gHX~Q<{B8O&jB8e&%XdM3q>ij&()WQ!jj9RCa$r25iqBh& zN7hWc@2R6e$9c=`r`yBaz<5M}N0y(Gj5s`^hVmSqb!!!VTkXE@YAk~M2p?zdAssxe zsE?noCd98{{p!A7m8! zWs>xmbdqxON4tYuN?Y`Q{r1Fi9yi8ym`dfi4Hu5?_B0uN%!dEJ3*8g?sPx06i)KXz zA0GHqI{g3L@jM69BbGHJpY$@)`x^(rAphTO9RLPAhA{r$?ExkQ?UFbEe1_2f`}PAL z(y2o>Q_rg@(zgTuL?~VDzDoK!(vx&YQmaO949y09EAT0J+bxmrb2fMm9S{7zP`gU6 zCY|vM<3F?!{0mZ~cL3iVN(cX;50TzM`e5Wn?d}GCRj3}NA3&Zqr$|3edbnNShvky4 zc7yZ>pJ7F$&l@~G!)k$V3)Q3gTS%`DrH>=Mi}Y&JHyi#m3?AfrcMJ;rF;JOp=)-N4 zc{N_fg>&Uo>8KA+A*mlnk;^)g>r<6cT0kMuMouB{qHCOgLvozlMh^4ex_y+{Lf)e3 z0?3Z{ML!EYi8s8L!~D0tlH{#|ckGt|;n9EV_jvWsO<(^(yYCxiUj28ag&&Uo|Hdw_ z{>ACx%j~{KqF(*?4h#=XhqnT+aq9te(MktCYg6{dA$rVxF4GrLS1+o}X1i}g5!p|u zjF~U9zv-9pbfKe3pUVVJW%g5MgV&CkF9T&#w=)9%-SZGwoG75Q$c2imq)<=|FE6ZMzR(K z?E#m7f$C%%jbQ%!hhxCk`Stnpm|wyZ7T`w~Fy9vdU#bNY6nXU5T|dwfp++K7iox;-x(9rLDi@l0+HHtk+Y z&PyzxG-hgRFM5nwyD>{PT6_)EUt6Q#|L-;qqAh4RDvEr8pS7E|TK`%NCh|vs z^~Haq=23SmP;ooUr$bU-;QvwUfNuwWyz2ju>W{B~RNpr8*N`f?bMnLW#pjFhz{~zS z4tzgz%=%$27DfInWAw=Ah~4*3^^`j%6q3i!A2pA=!EH42-_!JAP<@53M>GFDU8LGg z8)^q0C4B?BauqhWcxPd!GW|X#j^{(UE*@k3rLFK_{{N?alp2gomRZ(WjQ_@0WrwT1 zRcg5WE(Kdv%KfANT1)@$M!v)8HKcD(kq$5I zQ#nT_c;JuzS~1d9Pt4S>|6IIX>I9~D1HTpcr_TWXpxyV1Y8_1d$VNsU@U_5e-g0;+ zS95z3HsGF73hb+cted`PwAg(=Dgxe-C)ICk`V4sKM-@B=)0v+$;HB@@^DTLr-zS9n z8CzuqY?Seo*$*Gp@m-{{@AX?&8UA{Pa+&o1=?cni^~-saXaYZ}T!Cj5L5oc0l4msT zZOXCqUjSGAj4$mp*Jrldeg9HJ@_zE>9}dCG-{km>e3hg&o}kQe%4`vMxQ$JjO7$lX zwSg>cJ4m9#qbb@@Qd~uuH7EVwcZ}rFSZFQ%J&j>5W#+e}sLRpU$|y2)88fAmXZ1C! zk+O&Rmadp@1R#l~D(BeQ>oOKT||8<7pxCmmks~#d=;AX4qTt(#}katX@)M@9d_UI;(;}O`2-$I z($ml-8~Oi1En{0pnU-1=4A|KHj{iZeI0`EM-!eO(qs4iTRn+ge%VC*=rav4 zg5L-H(>!nP7v6V22)Ch@-S_XZ2@d=40l9VL(3!WC?{fu1Nm<7KKUzr6F=ct+Pjxbv z{`)rgB0~CIA6Mo8bvn|bqABL0S&w>iQ6c$^#ed}TJ=V0R|Khy|AFIsnd!2R@=49}Z zkNQ7y_}=E1OTtGvaqsrNJbs!!S`Sg@Jf5>nS(B{3Tj-+KYg44}w)QnX zi~_%9knr>&6I;aaNnW52&^j|l`c~>0=eHZ5v{bH#{9WXS`kuM1pLAr=zz1olc8-v~ zoqD1v+F`7+)c;q>pXcX?$0}|Wfmas&e?xK+YA36P^qhX$QMp#~Bjg9^!0)V8q>CqO z{q_@my7VCn{(qwqnDM~e`A-6j^R4RMOa4rynmTykPvs7iF8L6R@8nJg$#7uZn4L}j zJW@mQmR(4CZHjdG|BbRxIyB6#CY|r_x^ZKc%R_MrqOO7O06v-wp9D?cvbO-MzK3z# zMf&&@>HA5KgwloMG14_|rG`fOFHyG#aRgp-kr@~9#b=G*CJ{b90!CJcF#dP#3$;sM zhs>j%LH2dXL%^o!>ky59xUb0j5cHqv>jrRaIuYno!k&ZcC;~V2>m+4X@!Y>|itBmc zhZY0>^dRBs@6bA~MyLjUtI#nz*0&jy;xnM??sDsn>(fLU$2EenDTY2x-96~JV}9Mf ztor&5|A4nOr8VNvBed}lWke$fpFo-PYyM&M|HsED8PX3fuln7Q?J2+ROTcDqN!6BH zqHy%F%%IP874@H_{y4pS{M-`0S+4PuU-v*e@coZpd~Oju{Xei7_`&G+2trW+eByW~ z>LdD@Qwq#c>U@HJ&V59k^>OycA(eHWNZ;^TtsWA3V#gCo+0pmdC#Z zluC?qm_Ez1AsJ8EkcW^xYrCpQa~htiqzn%YvN?g`pY(!$(#N^!d4c-J zO5R9UQkhBDf9|-tqZ-%1X5Pa8VvhjdRC>YJm;OQ&IAHO=*dvO04z`W%&D>3Tgud5> z+fJDCJ#VXHv!Ar>krmWc8ZP7F8?=3B8~=+vvIh8E1J470N@x5{J)!Z*s&mtW;}8M9 zmGo-L*81%x$}v2U^$;)}z(jqR_^eNVvzYVWswBV1&rgy)<@gF;cryMY>q!jq3vFdH z{v&6So~kY7N62sMC!cz=)&Di2dXVW1$H=|>FNuQ~TU|CX7Kvy&uJR-Ldr4zx!{=6J{w2=I`X6BKb?q!<9GEjNziG-_EJVNv>~~S zTOvMpsf}K{?-v^1JwAL&J>nOlzd7*#FM6QuQOew5_SlljJYx3c1HM+3n`ieOsimB3 z`a8~6gZ>)Gf%i<6ytwZY9CMKWxAy|w*dLBcj}M8~967I2M*I@ju^}9j%M8!4`+mu| zm_57OHwN(2V;nc1;IuOwoBx-x4bA{J#WMUV=L~Rz2NcWjEAh%PaJhY~!Ob1d1YVO5 zSed@pnKHuE9G;4y#Tdl8v*~1T*vdSaQdXB4} zovO#j&szhz)QdaL=~r&0ZJ#B&ix=viN+{>T$88wFGyZ2i0ep+#pGXBCUpPd7XZ+7n z|LO&5cn$s#9o*g(1B3p{D^va51fBwK)!PM3E4e3C@8|ogHy)dSo+6gP zK8Nu#>ykPX-{h-l%`c<&lP_Gysm}XVXI!2rH;VqBQ|IxO6I12l9~f^H3+%ZtZllrv zN7j&hMD>c<;xzF4@97l!HX8fq?Fyjw2|gHe6tKmAd1nQ_j z%~*Q6$1mr}$k&GpCNCbC6QO(y?HwmMZpS3@FnvF(+qU!Ri}Cl=8Dl+Aw~JNWJs_?z za(x!^pZ^5U8gHM^T#jcP&cgovme~k7-i@Lkj zUWmrd9({bTR(>Rb<&W<6^cXxa2LAtDE%aGM-fhd#rI$-cQ*F_yKTsuVYmMHTGi!^J}BPfDaBrC*^)%RQQwTGfy-7o_b;FCsBM4b zAm8Ei8q)WY?%==!f9Nr59_f4d9&hT=e+hcdT1CEOI8}ZT>C77+VN3?}zX)!hZ5QRH zffN4d%_8_P$sd#FrU&r{KBJg))gST?$ZurQ!|-*aM?&!MVn(Z*UM3QlF>-mr=S7e6 zjekXcqax&U(Eb&*!Mdraf--|_BQqQL+B0YaeAp|si{{Z*UAP~C`5{Hg7yN$=*lBV13QZQpnXE<%|jl-bX7tzRZlXH#!h zu5Eub=M3rvNBNCDT0@x-j`ACQwDJt=T0>v`z`021i)uA{^v>N;$sld zhrUjW>tdCG|IZU02ja81g=zRB8~#791tjRxH=ev_Lcp?WAkEFax=G)4MY(xpQ}?GCFTeK+aVW~}sIqE3%n?C50b zXZ+9YK_^xE@G0ddZeIv4KW>9EZtRuXMH@)o?bqRtiSKvM^^9uZpciLg?2DmOm_A8k z4h^(ddQ%Rtp}yibvM(+oeK5RGN@`+Vok zmg8w_FR({|?Ma07VjR7GV)+OlXLKw7qhE(-+x8{k*q_Zk9R5EqO8%Y!>y2w6a2byN zKW{H(j`?L$jIr_pelqAayqi88|HJ7ue4lL>t1p9~*KqXzUlq_+T(_pc(OIYY>oe#u zV!Uk^%%ogSyl?T>J1B__3?eitOF<@?)yxb=2;w5?zAw25)A-o8zA# zJ+4drsYLTZ2D~|b5BU+(4iEe(y_EEQJQsx0(ak13Xs-yKx!Kg?%t@viQ%{#|U#lt{ zd5@=~oAv76@IG3`)1<@4N$nz=COwGfINCi7oyvgUnwn0MUFG=p2Q}^) zn_eqg7A5vQlkvZHd?+0ph~u-bEhD|d$01plhV4o9e-&l=o5SIO%w5221EwWhucwLp zh&3~2naAwDslq$R1B?xEeD<{mQlv-hzRKQEI_+jfNk2k*oM#f}BcJhrQT_PzE02fj ziI5KeUptTV0s1K0^xAd6q@Z0=FNNEyz#j&_4VqLLe^nxGaqc#A7IA#`b)reAFG+RN zk8FHem5gTs{b)10k~$)!&kT=4+~@3tsVlB3yB+vycyoI)eB3Y8|GBN~ZMOaKJ+wCn z9nAS`+pzJL)NOhF49{6Z3Mtn{8{_b8-i}W z6#2>!zkaecAS+|e=5(_w6G;`r>#pjjYZJgKb8`G%r!JV=@CB#KT`Pp4?l zX~|y@FqT8}DRT@Qh2AGK1mO3}rB!?ep^c#x=oiVtKEWGjUI;H$;cFK|hoOxB*e=?r zP?--1AXLWl|2Sp6kSh5+iQ}`cSVP%Xl{E?|Wm%Q<$zQ;a#8{&%-|^--_*(Pa4fH+X zjFf((=RW=r-|JMHrT_YuCBdWTZm8uu)(?D0FIek<-weE?XL;Zc`LMRq?$cm=lzOH* zXIVWyjmIZFVypnq#VHS}U;dbFUoV{zmoJY-f%v9JhJ7PPcorMcbWgz;UdtHA8~mV4 zMuFcCue{rTrN_lV@{rL;nUf@M@XG|+av@jrznu6XWnUr%0SoEB zgnMzW@Xx=A_8P-gd{_JJ2XIzefcW4mTjhqme6L9bA3xXRbFSLxvh7c_@%>QhGEOV5 zG^q`EwM^f2so}l3*Qcalk5EQDw5q={N)K$vQ6>XjRknrXW90qyzY4(L2hb1CQuGB^ zV_ReQ-6(p6=E4l-svFhEaC(gN`V{HwNUu(j4iDednj(D<=`&NLqpNPJB;D{N-})1t zCrOX;9Kt6vkMyDx>BXeykshiivy60-6Ve&e%sO6$evI@AQ7VOu`-4L+_++l49z$UR zuQE=0k6TX|&uye104A7TNIm;V-$Qz--)?+nR{k;a5BHzXT{2F8#-}cyHI97nO<6zb zoH?*>f_D<=q4asAM?&eq$yO0v18W(7Uhvn${^Ub>XiNN+ee-yp<9$rjp8=6Hb`o>- z&1Ipsg;Ou-!qw47Jn+ZwZ00JHE?XyI>=OKx{`6+bR8poD=rbwPL7A;*SY|6_j!|aj z0J!-A37q;v|7)b@&Hy*!uk4z-Gb~e0nRRD?8)Gnp@vqrM8AreJz#n5QKU&Rko(DO` z@}udt!|=LBwu-4I*U(E4h9>f()g0luClww2xS{yW0v(5rWnMwIW#mz2(n%HcV<3E9 z4X!uPFGK5XdtxJyTl{tc^GDn^bJpJREqeJk6L@%ui%M4 znkdkkFucD$iAy5*Or^Op(3;e8TB!7e8w0;WNPVF!17&!Qe^#!=?XP zfUgMm%jJ@gJ|12Hd<^)wJ>u(dzl7)SQ~hngZvkF1|A`}Nq<_8={AS>H12xET84my7 ze88=rQBJBqJ|h}kFd`dx(K#m2AbddI$4AoWrx8(js{-hjlxl0 z-2%L1r8W#7&@=wR5IE#|H2nXmRXpdKGCc67^lhYf@ElARPVm3soxzL){XNS9zMFc= z!Z>+-@R_MbO^cV#68~@Dxt%iC_o!h1Is#nJ68|3ts=&0t1Aj_q{!dCTBwhS3c+vIx z&!|vbW2^nA$(O!fr~KK<56?GoDvk&Kux;N`50pVQI8L5F$n9(B9wEhF-Li*r$JIn~ zIk!~YMnp#QYHWKt&~63{rK|SIVxj?b^*eAEUhqFDLXXA)dD&zNM(~ z$lJ{xKo{knP!WTtZk2+|H)|pWY0AXqckshzJ4NYY#4I#0=feM*rQ~0`z{BGrmo~ zoLeG3GeiHg_uF=)a_NWbvGcn=V=W`18UyK^D)U|E3+u;>Vv; zei*Mf@6rEr=zpE`))|h?IrP8oFy#h2Hpt>R*#Ea}{sUwYzRNGL?b~g=)m#)$`m`daDR zNPj3r`aaTQDbk5^9w$8&swcxDy)H#MeD;~cq~`?sf=p#yZ^7f_S$RzJ?AjLZM{a}I}v^uA@g&D zA4K@c9N|R&3AE8!B(fA4vS zhg^Z?l5JzA|q}hy^N{uMJot?(D{-1#MZ{LG7wb|uJ zDR|CYlrYMm=X~1_jI1tnUo$ibX@;`P(8eHp{)sj$Mg2qlNaJ^>vFdJ8rF2Q@7R29z z_`3Xn=XlQ=`%h8%AOe2mzaRd@D_u^>fB4MbXRLSm6FsL8zZ?EV%G5d25kKR~2l>-| z%}~3Ce;dl3=;06f4^?~kZ#eV!n~%8sK_|Uu?dJXPZ_2?pUG^zH^xw_Hh@Zu0@4dfs zq5qI9i*M&ngYmMj9X%nIUgVYC#S({NENdHszMe>O5Yqn2C{33aDKI#8j z#4o1K)3Hw+LHw17@6t6{qZeqW`#HG5<_$<{TH$N#pkKO^~tgpR#RO?OJXKvq$SVgwg z>xL13pX7hD{`_ec_f`JbXa4(iieC(WFn-cLbNf!j?bF>TjT1`puQUCBUczVnog5aVIWh(DcOa+fCn!6uO(ccZ>@?@1edfqU z#B|Nk@XqpV|7nOH7yoK1T^*OQM`&+p7k9wbRd>=>(s=*DaRJdhVanK66(K$|JT;zuZwTUiVtHv#$QpTK*!; z|696|Za*c-ZgctenZ0L0bRI;S)1cGtiw-$4pIzW{eQh%p{GSZ@@7j!#wp!(xSE-aN zkgwI1DL&d?-Sz3W;%jA*pSE`c+9sp@=?;^x9bs>N3q{c4+jkB)rOgVDyKv`TYwl5i z4%(xLp|AVOD5c_)MmOhXEiOpL{b$as+Cni^d`hF%5Okk$)gbUhm;V6#Gw`40^2Z!) zRX_YEx%@Fkt%`g2?}vXo{Pq0NFAV7DResp@Dj)h|_Y2UAJ&Nq|k4}73!O5;>7TQ6DkWwkMQJpnqpXCmU0 zu8=-$KNBP=>>UQhyHd1&4`|n({m}G)Q@>b8rl75~9qD!;U2fXStUZ$&#NUMY`@!qo zpzV4kgbv==I+owNV?FBx+VEYqGl_bXWsl<)A6#RB*-ENz=agb@vKeJ|d+~$jCR@z9 z+VduqNB8yjF}Z>6y7L}?CVjxrsI_Gg!&?IX#ooY`{Kw9Q)l(hH-g23}p3+ zO@?uGg;8={t>N`6@f}9ke51s73U(7rjZtz=zu{{poIzTod(FK1JV0ZW_>LOJ*G>aX zG<^5(hWmuz?XW4F+z7z>y`b8QOFPt!zDFw5N1%O=)Ie!ayxN&;x7@;Z>nyfcLbxeB zQpt8VJ_k+ixcW%7?~x=rCb=`}wA=Sczxpt>?~(Plvi|^-422J>k5T&`*|31!8yB*@ zsgCW<^=xmU?{6diR{91v?4d<$Z$sxG_x5JCchEPv;oiBJ?OiQw?_R?89(7~f_sHI5 z?B3^Rd%wED>U-qCa&{jKuzjeN?ZYeBK5{49!*{WLw2kd!?_m2lebXD|pJ-?MWJuW? zj1IOZh1s4OVY@uac10)K^Sjt?>Snt&#&-KEw&SbW?(boHu$S#k3AVQ;+1`E++dEQh z?^GXO_HEb&B>?(1?CxWG&l^?fc_OS=qKK@>|Pdvo-$w9VHy^rnF4=elq#v^Q(?qqx7mzDj#fq!H7q^~IZ!Q?J> zPkw^!DPLuK>etww1|^C54Q_ps-DOX)UH)~pr|)6A;%T;P$x^?Pa|SVOKLt$vbC~+$ znKKhej90>xsyO(wK^%(CO?t>)%OUADS{?vYE@g58#yBPp!an-L*-JVSX{)@rIJQwV zYCJ21IPrfpoul?9HOGlgv$BMZ(=ZM?N1M)My~=fm*(RZs z#4s}koDqN-^(>Y*UoWp+93(eJw>StJ129aM)Nh960nj3jcG!klS;9(q ztomI6k8&8wh|;Tv1+82ubSeyal)=yv%~@u(cnnggS*GHRS*8lvtf$M$waf}dpD`9F zrKkHDwGyFe0zgC@#0*U%L65010iNIo4KIEeqMRC3MFf2%+kt&Tn~!?5ZvcM~jYGDu z!?&A4cIqJq;g}}TN;Yx`{=$diQaP$%8sA%Ch)VU_gTEAdf?NlX>r?{xO(@47giN6J zo-l(Q_zMRJrMG|JCrzuDXY7YR<#?PT48xE^{Z8ZWB!wj1ARJbxN#|jTLDjKBj=^E2 zqZ(||L-&fqDv#<%KVLikAQRtua>Utzzi@1{970JwJjyAEep_Lv@SWt?CJw^JUKk3o zYEH6ba!kdiP$J%`M6CR_KwJ?fs*eb?k*c-_~#aJ2bhJ$FOpHJ%O%Rs^Sghby# zZ!d*xLtJD~GN00%5(j0k8jwPWHzkq*MY5C<>OviBI*cDi{kG%pN<X!0R2o3mei61m9j&+;h;4A6p~~I{=%`ratLRRTOKIbkKiALOcd z;%j9Gj}Dt9#EMFxQ()9@H~vyOsqK~2tlY^Rx)1dHbI4CzO zlNxbQG1jn5*r^Dp+t$N$QwaU`z)&Xp$Z-f}5&=_&%K^*CO+U(-qEbDTHg-fUgC~Wm zACX6n`Q&PWv7%B)JB$@IBaTh5jRA2Gwpg#Ip>$<1#Bud&$6v}srK9RtIS#=w8OBOS zBFP>ATVN>aJ{UE8Od&wOLok*DJYE1d6=!8kwIRn*7*#8BP%2CL?IXuY7z$D4k42{w z0n=ePGXRsCVPI>#IY^Fr7>c$R#wjVfqV`j01ZD=zE^_RHvD!wDN{wcz@vY?80b@n2 zhJ&IIdFnTazf)i+mNktatR#%0TFo&PkZ4tD%fwL++p1D4IU+FA2$(~oS$h?ACHyH9 z6{-`i{MzuBLfgregpsJD8SDQ4KYpnpq#U(W%%>`!fG!2^O3Q$i7U%lIA$%*Ls3p>E zO16?i*u){5;e#}s!CrQhoTg~|^^lY7m=J+Iftnv_CQ$25K7>?U!j!Xx5P zEJlGgBh(DKhJ%d(*lLTT7F1IPYC zIZ6;;g|xv|GByc7wMREBRR`DuFp3KBK=E5Gz^LFs1gL2jqN=rmwVqKSs&;0Yy@*R` z4pW+A_+yntoZHP=p%ttU(ZNo~lp?{g9G$ zy%gfsJXUxu;!qOG)EYJjQwF5)r^2W}^4kPc3)1V!aRLTOeS}quk%L0ai4maCZ&E=q zmHZ>BniW{nd==uyUkb6(nOso>)WUx!a-TvGPQ!3i_>@}?AsVt{OoUOt2>w!3YA3b4 zpALIFIfh`&OpM*OLvo>bM1lGZ;xEPBPcGsEIfh`Y5nP2(E*bKrs?(&a48|(MY}j^q zDsI<+`dV^qfuU$RT^uqDUob{Fl=x4AhsvJT37cW8><@_J5NvaG0tiPEe-O>Ll^h$` zfxmFAgrbx6k;{qMnLue*d>mGuvKC!WEdV+ zg|a3mM2VFvg_euQ4A|E2tja8$cB-T;qqJE$H%X|ULfggRopYHL3NTLlP&8#AxuMz; zW35FxwU5SKl=s#N)$l5VvAEa@M;pvO>WswXi7Ukuaty+dLxp%sk*Wk`LVTc_s^3cdrF0o`#bKty48d4^ zi?FINMH{C~tZdBUlazHg42mylC&ykG$ZH8nR!I~7pm-HhLUAX-SeeuSGI0RZpyVJP zSX|jbj%_ejG_4y-+oCWPOc^LrIIe_FmC!N@tq_NzAgkp^5K8h}4l@l#{fGrruA+Xc zIILo*KrX;LN9s=AOsUkd_! zEAfYk6W*H)ts!##dMIUNGKB&yIo(Z;{VG4Z{J3%6T`qRJ*b%Y2#g2=e6r0x4 zR8GIx>%|@rdr)kwQdK;xI+eXi?9F0hd8_=liajLuHnF#hy+iDsV($`rx7d5c-YfP# zvGxClf<4Z_7t(F ziaky2GO^3Wo-Xzbu`9%`7Q065`C`|KT`zW%*ezoF#cmb5P3)Cow~HMSyIbtI*h#T7 zV)u)^UhDy}2gTkX_C~QciM?6uEn;sKdr0hUVs96FhuAyC-X->KvG<6*SL}Ua?-%=k z*ayWvB=!-!e-(1<8y5F5oU4)hxcHwG_i1*QOvFA7!b>KLJyq;7v8Rh&A$E<}wPH7k z?H9XE>~^uc#ZHRdFZO`g8^qou_7<^+#NICUPO*23y;to0VjmRyu-L<59~1k8*r(W@ zV2C|Y?8#zJ6}wFA>0(!iT_bj_*iB;l#cmV3UF>eLlVbOaJs|c5u{VjmMeHH5w~M_~ z?A>DT6??zf2gN=t_ORH;#6BVRDYi=uu_uZ>S?sA|mx(=H>E^ZDO~J z-7R)f?0&Ha#NHtGCb74OJtX#av3H8STkO4J?-%=^*oVa)7Ww6UCk^ z_EfRU#GWp8h1fM>*NWXFwqNWvvD?M&7CR~SdhU1U3~>KEX9M@gbD&RNhkkh7B=)~f z=(%o+N@pA#j2Pzc;IkV3ekT&NJojCC499niQrF2HhVi{?%WXV;&`gRr<%~hE;af^^ zc*E693%&5Yq@)G5;7+*|r-YvKk_+JH21U@2| z>itH+sJrj8g2B&{a|Le)o*@`@Eb$B83EVGu7w~g}Pk^_E;FG|&GrnX#a0VE^OKO2X zEqECCn}R9r9~jefhou()58xTZEx^|Z-U@t+;342G`{mk9>V=adUR1w2PEczaGa<0&=3j|xV;&UsdFKkzGp*W(>X=Ltp~&aD
m5X5L^pP{gnKZz#+l? zz@ihb*$ljy{mbIOI|Ngn`vrrBOQ~J(E87S8o5=V&RNykA8Nci11J4(XvM#$*@HSv6 z>-uuw$Jqb+6TqKmT)qeRdB$(r04!zQfO0RN!2WOE34ASMdW`S#TE;il0tW?yw#(nc zc*YdqZwfvJEHe4l$#nY${sTBsL!7B8!P9`hCfE-w{r#;QA%CmH{~+)_#T`eI@Xh#2@relQH6LNIUHr_J3O|+HaZQ&A>!6XnPy#e)ST@3yuRz zUtT!fFs_k4wQxPK$n8SJzeZ$i;UTn>)N3K?Ubda{sVg&#YpLy!e;wjq8xRcIt`)sn zhqTv)2HxKMfcX1?KLL#2vg5$STm0@Q1O6G~<@LDx z;A0#(30%gwwHuh)1wVQ>_6*XK_`L%>pYb8ach>-u%-|P4Ta=04tZ+SiY$K${;+HA|J|OrY@G#@dUc;y&na6Jp_+NDk<9@iS zMEBm?1RP}ld)tBg1S3+F=!f+g;QjC)z@0ksmp-_DJ@6~ykFeQO1#bXu61)eP=%=*c z)of~0;P+JH`okLqLmsN%FL)cUjP>t9+Bt6)|3knc|MySBtC^>;|NSe09}>J3_=Mmc zcty9g%l$`ycZxswcI)35KQIYXW09W+%78^S9%uuWwtHYNUc0|S;)8~H#2?U4Hy!3Z zE*SL8J0>`Z&ksx!jJmvKx!~QvX~D;UrJoKQ2PXNaJi(v0JSP}*zU99eKUiTHx5+%= z!8kC@JrMsvly#fP>Vp~J)#8sfx{dlN#n}bCkMVm!=WV|fj5^N0K=4Xnk`2UvZ#%HG z-Fr_1cd-9M6kqhfL&$T!w8cZGfd7l*yl*qct;+=??OUZyAKn2>GKu^jnTSuw2+fZ` z_HN%J{@XCFR5IS+2Y#Pmq-bvObHjx{Eo^XO9El$ap(=TSt7uZwKmI*T(pZJAl_R{?5#YZIUXM>u%9#7)W?GaQYG35}^^^DntkAq?67V4V@0kJo1Hp*5xI{3R zvN$RD0PqJHKV1qeGXL~^;NOZr+NDMM_0yoIMf%9oXp0t-H{|{FO5h!Ww*Vgzds#9O5l|JL7#wyX=#Kw__{gYQf;4|3Svj`!QD#nRy<0-ti{(e*x`&hw%KxGT@)G z|BE{fW4W~5{wcs8W&dxXF3W}HZ*4Y=!0qh+Z3FmG!R^4ppYI^g)++Y@&QV~Ab6^%Uu@=P6B_3@%N_z|B>+zP_MS>!1(=7@TaYb@eh%@);#{Nf<_HIM)An=`nQTMy4 zEaZ7~*f8EnI+O58;14tYCGuG*dmXffO*(G>gt4)LS^$oRwz;8z&`9(C!Yvhe%!3E9wMKK zrNBJq`p(}3%ww)^QW-FhxxS0QpCq@n@1kSC-JEtZ>XQ5{uwnQvA^)ctU%CyL(!&3; zUBEQ&1%Bf}tRJQ_o(4MasRjlO*G~rKKJL4I3h)=jA8nnQC>ZplxWD^o&m@%=|LMS# zKjl+l80j^FYk*mneAlnXW&Jww9{?6UUq1-^Iq}~B%>Bi8{XWC!BY8uf9MO-zj(o@Gij>hVhWd-YsaOhu$y# zTkwd4=!aWQ083w(RResK)3Fptr`%FV#6=Y5r^%ZAH1P8I0iuw3va;C~Uk&oJIEx@-1S;Fat@yBt{fJR5a< z|Bu8Ua{Ga+1n&hFomP!{eL(774f;Ru9LK3fJN|>@U%eHW=gGb~;MGRy*K-a5f0^UY z-ESC=HZiU#0~R{xO*V`V*0BG)R^Z)&+YIBes|BMjk0ltt1#R@$A;AamfSk~98))7X zVE_50z+YiZ-^AVYXTjjxhsp#G1HVHsc>bXeGQJ)3d`SAp?e$o*iEP}Cw2$*z()YIY zhVhSnj$fMu{xRbPsN-g$$1r@0jsY)V|K=v(xM0+A^Y;a>#2Qc9u6YPp>fXG~Fg|jN z#MuG7N-${t$dioUJ`MP9g2Ahg4hY@~d|WW{+|nW#ZLx*NN8j6zV|_T8{aaASf0D7F zWdQhy_;0{kQFLa@CSaal`C7IB|5D;0|BtASg~_^!k`Z5aPj z!PsvA%lPgu1wJAE6S2O%N$@0K(PMtdz|fHRqh6o9KyVwd8D}T(KJiDnpPIq=4)F6+ zG6%S0AF#;M@(LV#)^eQX8DQzx%MSp{TqQ6SPh4HXaRRNtw+Y@0d=KMR(7A1oV9@hv z={xkT#!rhrX+_;Xb3Vse(F82~Ujdpw^F#K(({C7`oz3_z(EQn6!QlUAg`T?(;W5#7 zv40zA-Y$K)?J)3P*#8~1hVi*O1P=p$gz?=-`?+TrzZ3QP+^+;9pU;b4U0DV!^slS| zj&PinpzZUb>sAgL#usE3;)V--n9q&2p2MbH|n+H9~rl!O?Mm?e9ADsNM)fv zhBgCJe+2FTf4(SsIE*&>;s-f?+WN~Ei~j(ynRXCZ`d25~_sb&No!fxTv_}o&-$W;LwE@rJe7ew%|JK8}dq412 z#;c|PKQDMXu;^HNH~3eiU(TDP6$^3Zx`GGOnrp>yMdn)4E{es<0knJ0Ur>& z2lxjUPA~=x-~HQxUlF|9Fuv*oM*RB^0AD5k!@##)SW5m690gv@_ydGLaN+Ba554c$ z`0A$wlmAnKPXNCp7_W^%^aoLA~w_Z4j^0^MO{k1O$o(lY|V95E`z9+a0_=w;d;NJ+I z5BvwgwZMNBT#wHJP7vG#JVh|tV)r$IBfzr+qg{62CO8hzXHT5L^L# zi(u6K$@zj?fEzEokZ8NU4fqbhp#RBt2?qU7#ss5HpUene5B#9u0pQ03qmEC0UNGwN zEz0UlF_)_^*QZ8OBrR3*HZWnc!jI>ja+yp2@g;GH^5F zdcpz0(}CLs*8;~bqJCujZ^G*t4}*rMHZlG=`sP!gW4!Sw@E*o1lE8-;KMp=Wb(HZO z)a$AL7XKO8Z=J;W$H#!L5xfcbR>nUo1zyVdWH)d~Vc(U5z-h+QDE>b%zI-L{rzOrb z;3pI|9-j~V0{c%s0epn<8x8^gmg8K#g&xso{1=q9=M9Yi2%hYj&bVU;_$`b-d>pt% zVc!(gWlxat1*rR;K92MA8sPV_Kk<3bN7%o!8hAV7XbZ6L?J>yGo&)Uv>`-*DPX z_5z<~JQ3~qw9xjm1Hk3%Uyr&xJ(tsVBcG?68ULvjxSjFPW?<%<@mL%1!|Z=G<@s@m zzYX|Hj2}G>{0)VDjpe`x#h=O=7Q6$PX*0GU?K2m#|Bu1*XRc@b3GnBcIgB6Q3e0>n z9$OFmPUY{rt_)b(^bM5HAjhX~y*~3{#(x+9-YIxH@V5mY1pYDOZB*6?#-E;I7~gn3 z;~$_d-zZbq_Xd>vjSBXEbP}+%Le~9ty-N66CxSI0+ zBI8;6fTc|r{=+HY%LKOp z-^loM5_lowjwaw%#*g;{cM7fn7G8b&DDX#=zwau-BJ<0(0DoQl!Jluw#AzR`2L2EB zzXa{_&EGM;xYjV9y@2Diq1~TlnK#;y_SyODe^&|_#pZBOFp3C+4pmt zYo-E!hVh(zz)wnA)a6;`mGKeEM|4*!r4`-v82IoU%a!k1@Zq_uIR8cDKa+7?1+ehy z(LrG5m9Op?a2J>L!4}|q89zQ9c!OX{EB*1YmB3$S|C7VO-%{AO5IlU2d1YMF3e4^3 zn+iJjUBdBcA7I}M#_yUB+{kG!DhHPKik$`)8r}^W_C3z=|BSlqllD4w5SZJ`cziuD zx0ml?@NnOMa{Qm{1pX7}KV_F;JbxbJ3pW5?!*L!1Z=bJb{3+1${1V20ng|?Y{CDu` z`3D%!+z0$9y3ffrC*%s4g`_-4j89S4>^^>{UK8~Z12J2kBF{JUCxzxypM&M_Ombc2Rtz{1;? zAXgTC3iv?|ca%_?L(ya`KW!^ULSkdA@v=9p~j4n*TyOpO=?t_)ZN6 zH4ND^%YC_5!)rABF#43#>t)D;g} zzE#6-)9@k>Ljy$dmG9w!Q%ku`|~@Fh79#pD;g!ISlh7 zm>eh>2pm_Ndtg!vQ9pJDz21KmI2zhV9g^Ea5&F#j9o?=WXjakPIac0Ni0O7W0R z>A5iH!Ayj~jz#Gt7_7`ou>vl=2xc-29xy4r1m;qh%U~{t!T3@7Mi{(ns`N^jX)ss8 zTn%##Oc~6zFxSCc4^s~FCYT!rKmqL6i~R=RDWL5rx$_ys0q+%k$Y1e>cx$!;@r`&! z{3ISxn}IJ>N7bfiPpXS*Z?m1yZi+_KRka1R549QbjM|TQMr}cSCH{hc#8*|P8-S_3 z&^A;rYA029v##KUYU5wRM%!Ba1+P`xQJee}{@^9G8MO(uF|`Y|v*IuKJz*Gz+L+q> zXD}p7XjjE=v<1nUYA0zUCCen&KY%$1^Af_*o=SdS04@V2`Ft6Tb2a6L#b$_K9mV9kA@SeNJCv! z!x}SAAXA+T#Zt|S18IMyicS%OnFd#^%Gtr?9l=a08V&X)BGKmD>5#BFP#tV&SiTrE zv<4gOqDGKOy@SRPBt+#<@Z2DmnyE3#ZVse#(j3TCRs;jlcr=`;OlK7Jh#QZl(@52T zTB!PHM8tZM@#a8Hu%)9yF-lbxxwx4mY^XU4)Nnmfy~Tlfl0E3m*_t{(bIC<9ak$t@ zvqF_s!8^gVL@L-3N=I`^9C5G`5@E+C269$aqsz*bcy>=HiMDcxu&W7e)+kyu`OeH; zqv}wIe7(%-%3v^^31wp8V5~QmiG|{^d*Mp-21C7(U?iH(r24|jT@i~x78kWFTezSl z7;Fwwmu!snN{8$uIURjwUG=HZ+PY9Y-Vq9~PFp=KO|^q$*n*L6&|9~%${+9RiuHOZ zgqX${G@HuF(iX0C`Ljg%6*(H$nGcCaMGo=EC28I{aIMWWq2`#Q)~aeYS2DIZD&dWR zj+nQQ=BkGz;bL<|g5pt(^c4SsiClS`qUv3;8Cnc?EUCBX(~BB|NCv{)(MVrBx;z?B zgd(O)`YWqR@|Q$=`eykegsL6E54*TPDwQ z7OKY|JzGt+!5ueEd^A~WYW+a4+26RvzovnD6C_z@aIQEyn{&nC3e3sTm#tJ4R`JmF zF*R(?$SgB3ck0jaXTcB&%+FqVqjUkW5c&w{C(~?LeZEbCiO#U^f zNIZraNaY-A?z%)z4@Q%^g~1HT-fS?_yHOX%0-4$AXr`HSQ1h0mplShFS&6cyDMb=M zvl*3HbKq7$XwqWmcOLYiHg=^Tsx+PQ%2TGNMe)Wh9 z0t*U+83kx@PiMhcOkgp#5yOegS|xcVyRhI)RvKsF*(8f=zL2K0by5xp&Yo49Y$zZT zBCbWYOL3VoiROe`TV1H+vXa7DB40mNbh+CI9f}gEt_$r=Ek%876fGrP)1#%%5{(|s zmQnNZ0xTuf3tEnoAqQI8P7J$7nj?Hp4J6q#8BckC0nR&tHNVGQ-%dAs^V2PC`8(CdxPC=z7Y`11U zwk{qW30$K&q~OdsjF*B#3+Cr5&+U+lH37CMi=l^T+@XsY`Por~FjJTC*o8rP_K@mPvRg}|M>yDtX7pg_fc$v{z| zL4LFpG20iAoSDM_$yu(dvR1Nr%yUWNjT(i!H#gnyec(n zaDw_+I@A%5HX&1$Mh~k)#=U(>E39%Z<+mWRsxO`4)c(#u(Eg{&tf4secJHESCgxYA zR%VBE<_wAC4C%lq7F63=ce`^8sIs`~uEG$6!qi5WM=F%2_6REHIf+NAHK5)flkz-* zk*mKmCpkK?uEbzWzPu?|%e!heQO5h{o$0KGsictR^qpvU)Wr{#ajUuK9E?FCLf9R( zJD+QhvO(>RSI(`EcJy^g5lbOW+yu0VU!}H9>_!drb)>_oSVuHvO=^|~w2A1Lx4Gv+ zs#ZtWHTV~2579IyQ@alHg2ArdzF@e&zjAhObZrnjkcqIWX|B!X8i^8Z=0Myo3-ZcU*J7hYs9`|}_BJoI zY4T!aam=Vzbn@yGEN*B3cUyy~wLRWr4#x7zjb)RC4o>wKl zy0ma$cpAEtiU= zN%&H12V)|i z>tHmm2-cZlc_v}hLTfNlP`#@F5xFbf;Gm6-KC}g4a=qDkF)$$sT(Qi)O2|Z zsxG^B=E`nd*OE2CB|+BXuUe5~5ppeU@x!xItgKol^=ANJA)wIq^u&q7<0#dJeAx$OQe(% z@>mby==Us@T{&BX8Iz2A`qT!9RmD85hw%#p$#oz7iY%Iz_p!XM*_y#sYUdVvy~%iJ zT_BuF#N&5$N277IwJW=uyz?t@>iSaYM2drHX2e^~61XJMhyCVwEWBFMs~BpJMvsAO zfn5}VcYoDh^j%nCCf3>;mE0xS*StZ<_W@OwRch0dsYcGujcVQzMPMis?xrh<*hkMr zPkq7>AuIE&4OO*$thQ6JY2TE{ERL?jzN#nycGC?qjaG{saF}AJu-8ZAgkxbUZYkg7 zS{_X&`ckz0)m+83)9y~nO-SBmUmT0a&Dagg{j|owlCUb+ks~*?r;mc2Y-|`^W~wc{ znx(k>l(d<|x6oyx+zs7OS-B*!Cfb^4OeK0V=#es2W5S)8@ZggLN0+UZ{$_Rmp>`fR1D=>j^WXl)6w zQdDK*s0SWBDvt8Nu@ia75g6xyEG2Wva(O^q1F6Kr0;zCv9rh1;!~QTvi8LR8%?`A- zv?l5r1DO;QBl&X)N>8omrE9VEEiLAS(Y|;l24^s%s8B3zkr<1W{$lk-cg6$jdO8yE ztc0kn6l|8+ng9v@#n{9MnqDB9si?-j24pO=EYL;_Bma0$Touj)wl>zZCYHq`W;K;B z+^vZf2ohf&)*7QU0K`)2{`@**oWU)OH0YsG)1FdUSB$BYrGYf&yQ(pQ-7!3`V$Wys z%u1M!wZJlS)fj5-why{;PoTQ*1%Oi5cn`|GZjCrRse2wFGT)J->sN51>)DQ4KBh+tw9!ck_y4a#m? zXe=^72Rg2KHjjteLa|Jmo>a>|Bt>2E-&I4BZLfR_3u2aFNADT8tkj_fEuWb}eZaF&g0~ z8~G-zT5@7>?hciuJJ!K!5R`*GlMnN+c(6XFXr136AOQMS_b5|&Z1MM!8L{+Omv^Ua_N+nXJ zuiBlxqc7SQt&hfISedW$^L~ZtB!00E2vSM8tSWVD6x+qP)tBJ{>Fy}&UazV{F)R8# z`BGQOft7Q3hhkZ8RBsWrJJQfg`@jq88aX7b)meh#aYvA96xlv@Cv${3)A0@>amwU@ z7fVztFtH25om{S>s8X?%Lv(T~XVb=tRWTBO**78o#*i@4>=rBpwC}Q@H$pKaFKM_c zRlXJ+2uJaN=sH&{bx~Z4WsyqTB&sWzSIO-XOmUN@5>^=Bmk2$|n@CL+#bJd!iWg+WW{I-TCmjSK2Y|o8WmA+_=HjT&yy1TiH6q zsl+=OXjKT2ga+g(U+aEQ*(j;$vV@M12CVWn`Cz)B7B@@}huD(4JTfUg* zZs@Ykmo9l1Vn=drXt+~L1&WPsFF7nCipt-bbr(r~?)Vl3S`?RJ$sID%g%SdwKQXe1WurFTH#b~D|7;Qy>et8nsVlMs*fVu32R#l}E}J<)=kppxoR7~X1^ z9BrO4+PPG-H;jLH5K8H6XOGb*!5FVceD>zdO`Qkv?gQqg){=hA!>p?md$6c3dg-S*$=?KWy?g(e20JCCPtv^qL| z*;Q64{f_1z2ayF6S!%g6;JGVRcRbfV`lgr4%K{nm>v5pdLrv>D8TNF~J!x|4j$#kE zoT+g4#C6)`3&g{y`)`|H~3=6G4i=3Q*BN+R!MQy&e z#46uKmrTu_vlY@Y=JN-|Jk8_E(<+OmA1HudSD~cN>&cxlohTGlG&)hihlk8@$d#e+ zXQb0mlmFPtGtagxu6UQ=n3+lBC`6UXxC+`fe>yCz3$6|gp zxixpi^$h&DimV0V(qRv8Nwy{y#S$aNp;z#|34n#)Q1z@#J-i)`ZQYh~+tJfK? zab69}tpxB2M1ARmIXoCAbH6;P+%J6e+Pch>e2rIp41#02B9=vy*INn3TF4r6LltvL z`yQHIRoYiGFCALVXsZ@Szbw4b=DA;yoxNknLhtz_-;?xy2-mJ3?MY@6VD+$ZsoxsP z#m-XS=^S~5ytgG>6~fyjO)W%Q%TPVEmMvy~+PW_{p0j#-8=OT?F^iV5ZcL7}z;Ugt zyWeVcFXDv=V_q%hljcI@7rR56uMBiv$eVg%vVkmYAK*b-65Dazq#ZR0YJO?A3BR3> z9=134q_urrJ8*=vC7x*)f7PJq+GM@jz^;k8T~yrD^StTgW=59mit6yfc zq(qTm>o2u~4Zb_Z09}WTTxEKX0oq=z-OT!CuA8Q;`a+Z0YHe)8RN+@GWR)&0qftDP zMFpztP5Vf$9%f0cbMB?RRKcFa@$v~O0y8ypHAH7o)}At7=2P#?q+V$U>_bqaFrzDRuW&4dxl@g~^zfn(wX0(jJ#PJf5_1s^MHIY4Kt!G;F^^J<=OGM{_B> zK|SEIkRNcV&mN*^&5)B0Zz2jWjTZ6wgjNajUb{B-j^{kpssY{)F5eEoOJV4xv1V7H zc^lYBuP(y=PXjF8{9hCdG@8_odAd42WLPAdO!Gc_rpg!#!;WxA*D9yDst6aeYcM8; zj*tkvh(g%eKuwxW%*fe^Sr|R>VQr$@>{XLbi@+SM;V~mS3rR*iOOeinidm=KmL@LH zf1Pue5hovE_qSg-SuA}yrgVk4&U17=YLnN0Be#X`&JNf`hgARC;W={#8RPNA>ln z^?Dlmunt`=)LyI)H)cuBFLtPTJzEK!Rjl4TIU^2wwNO1ek(J|RbxI4MKtKr zYd_R$e6l|z4o9xSEJzs{o%ULMT6dlm&{o*@f8MM3h-n&qC>q=T( z_ySo8?b&hm?9voQ^?A`OVJxsJ^vKTchbl*EiM$KT!dc`KFHB-dykOC9yb6Na$=92B zZR=GU&2mMv(N`DFMz^pEaK6hJ(r$&2+BC~PYns6-%}ECe#-*vk?^FhN%-MkKo#PO| zx(+$c=M_a1mZjB-A9@^GD+gP&1s0ovf3{q8@h09`GI8O8N~R zjI-IXwdu7vk;p%*rB~Bxcj{@9CUckk>Fk1vnQZe)&{A5(6=BAr2{&huRTQm0Mlk26 zc^##2&f+xb7)P~c&%1d2Bj1*^`KA?nmgWc8!Z4S0MbS{K-YfhTWiUBwd@5cQ=6_xC z*z(TB|03(|+6ftrqLppY!r3i5XTKl6>gDgdXSsTOPb!B_LfQ5q zr=u&Il8c^~cS<&r{jSQwa^|(`b(Y4^{6c3FVop}_&ze|wSxcM(lUP^mv(EW3j*U!i zHJyA~M;PwyM+|SI&tTCd_U!5T_;n|(G6mS|_0o59d@Hoh&|c*3vG$>QYJ+8=%qmIP z`|4q)*HV8&|IvIag)>I zizt?Iw>sAd4u*^9pGseisSuAYXXTe?N-~!RU&oj|nmXP}n`(F=x%bC|F(UcLwhrf^ z%DO+3r$!vpTo9YnbqJX|jlR%SxL1BF6&r@?>OKxO)`$Jx#JxfnOhg6*Y$?$7B*ncV(Af0F;uE| zIO6J32fnHUTAVjzh(ye~ao0)FX_D(WrgZOQAq@$7QDdgxQT&KTM%-D$|1pe=V=X&> zZ#Iu)!FIH<=baVosF}>gg;d0%Ew;R@MFdr9ZvEt{)EI9uxN`HlrjVNyw2ezNJRc0m zl9MVsm227PCWlUZioBLHB565$6clK^Y?kTMH>XGyb5BJ*^{qc4raypJ>>UA+P}DUH zS`?Wi(v#8?etWupKJSu%#OffMGH`+}{y6?_f zTqzp#Lx-9f{~YZutd3P;=01j165b#>nt{i4y~BDXgg(a^ZO)Fn9OIg^>pp|EhYJ13 zpV;V4qV^c0iUq?{~_L$K+&A7#EE)Gy@Yx+d~w;CBh+i-YToGZp?ZGhWqlN zQw;MzQR}D^?JnEIV@Pm4QtOCJElv|iJCc3nz}gSA1JxG4lQQodv@PhOQZvm~iDPYj zZRWto|8w$O!7ixmvT~c9FSp!7Zt=6YtP&TvOT>fIj)u%}>WT%o`-BuNZZ8rn@#UVI z@32)(7$8`VOTaPjaxp@X3~Euw+@Xs&8=zae^gqt9@MIjH;$~G|k2~F5-Kfi{yxJU1_n`LGHCm?g=HYCLMCpns|Kns)K!*&R|V2lL%JM1x4xQfsW=3h_0lM zk(!@-&CsTKhA+`O65`FsNLhn~c~Y65#;&9f$Al(2Ov0lp)7PE|b`LzQ*p(LItZu*WM4 z{=AIF+f#9*OfR7g#-qJmneK+39{Fz8(!2?2Di)9R#4<>rnx$ZDRZ2r~x#QaeOXy0+ zDt!4pgVS#H?e?XGTCOLtCdy4v1W8K4bVR#iy;)xhq1WSuX<3*a&6|zpKrJl=^VO%j zNkuF6*!rDvSBH6d$-VHdjdZX1y~PhpO8le{tUXTIYlcvp*^_L z$2~EZfl5F=+TKN;tZ?Nsnyi`&QAkHKBA-FLUOAYCqMb zjhM2MCjse6ieE(3+4Ma|k-j`RDn*ovCgY)SG?)%`5>tv(!O(QtH)u)ILRQTQF`b#` zn|$Y?h-4mPKyfW|tB_tS)mD7%fnkjLIGm!x25XH&nu6w*n0wHHx_SNC{o!3dKL4&h zqpRKqS@<)$^qo;k11_oSrIdol)^sJwnAr~2WnqepF}V=2VbYkO68X+`ztJZhS`%&b z8!7ZcSixX06YdOFn4mHXSV7q!J93qo+=@Iq%g0JZk?(E|WPbz{epw%Qq_}tUnvgzG z$sa#$m{WI4RV9^$d~(gAIOXiR#(8|+d#nE;2M#5H7sT?I=om!i7hAyhB3r73H(PRdT zb7WRkWw^cOX8C}R?npIRKAw?+tL5{tL_I#C+a=#>#TR3t>E%nQ@NQ0vPdpldGu{Uc zlj*}JJ-g~-sX!Fp{|IFgDLC=clulUm`WwowzNKY(lsp3T{oKBIba^xm8GwhDMRS@` zk!)aUjG!f00#NPINPQ?1f}<&sL8DV0@4`zQ5^D*;!~BM?s(dQ6 zR(CJN3j*TNKr%|%FUP4VIx>A!m|l7bAN7G<*!EkK$X8wo1VjacUX?T8!gwOQTD?2bii*gPu24Nr ze+^T^?2bN?BEJ7c38)wieIyvdK{& zu`nqN(DX!7(^s|86lRcAlCH<48kYnb&`Z}z%tTKQCUy&HI_~u8%VZM0U~t+@EHRZo z`eQVdHcR7>hF+<-G?zv>M}V9|BPUinlP&8FTOLY#Fn>&9AfcwjXLth z=qi{;EYm|xo88pa^K9BCPdqgG#78F(T~U4Ey15bG=O)!5Ww1B%NxTx!0c#<;8s(5( z(QA6+P&{YbkdN7ki7n)|I-lv`s3Rh@VtY3o@548yGxed=>V*m6AAi9`1{$V~y-car z{q!0%^!Aai&O{}x2ynw1lwen?p+A!fg)@yYeD|B*2+aA>7p)yaLLQF3Ngj={R64UX zv}QppvaGXpT~hc-L8Q&RL)h0YhKXLdj$TKc?Hh=7^{Q{QyMxkp+f#Y?W_(8?&XE?; zhq_U7QAOMqQhyS?b$By`-azyvdLAFB4t7NH#4t@wCQ+nsiwjy+3&VD==33(nT%(0T zbn(468W){fh;mg24T;n`5;QcFMvEEZQn@NoIvEeGi$=1tYlw%E>1c!p5FyTt)ZE*d zuqf6V()I%h^%#13)1cHQWRX8WJxgj}#ddnzvH<#6BRR@z!Ha78FsHDRFG=*Jqb-TB zOc#XKCF`2&ttc!vj%=1&XC zkAa~xZObik2w+Ja?G4~~#!44hhnY%`BbErJ73I!o%E{zAW2p>Y=!3BWybh;gNuEUs zTUezniY9uZ))0oW*}FM?XDl64Q)x$Z%zhwLTx3%y?a(OnH6}h(;z~+u+ukDgn8~UM z;KC?0qv%34sil&d)6$6+B@$MADTY;+<;$hGJcayTZIXcctFhPCS2WS3Vn|_eUC4*E ztJ|$^x0{~fP`ov9S0WV`B3dx>=u0}(@)8W@n7QbhnRJX@xT$g-ge%Fdi{m?4c0`OV z;pmEVG_`<+?IgZG$YiL|sWqBPg<`#J@3@;imq)R#Q*6bgPJQUr^zXu(jG`%XB7q4? zoM!OE>*biKP#CddL73h*N(%@_2*wn1{_G5~hf?owy_cBf(4?g|*4b&7Pv?+S!?ZSz z%6v%qhzRkL#UWMfCC@6Dq|x4~$zJvgV8QNeX>%E5S3qKhvD%8?)g6t-?IsAQS!+5C zCDWSV@+EdOvml&_t%;gyLgxR(ya2*vVy`I=_!1#95{OI0NL-@q#U;94T;@n%I<-(+ zkD6N9qLEe&9!edVG^A3Al(XsJYi3~UC(W}ZlxZ>hK6%GuUET0WB+YD^G1{coghX2+ z%A!;#*&Pd~wdpi`Su`M!9S-%65VP%QDQwk2$%n~M%hyYLAqP+GW%=vcOD!d-MI_7a zz6{ooy$&G@#CrPTm;#s@M55wNv8(m|-HLB{B1%UB`;Kaz$MIJ5(n4F;Dl2+Z(&fCm zqaB*vA+@lqE@_8lH;GA!S+3qK?R4&rxuTagr&Y(13_L&kz+p-qwkBxUMa$PU@*2BN zEeC8jMiyGt(+K2G;N8B_6lTxd&SnzQ!43VlvZwVz|3?clL++5p2g zL|0UuRD>dt2LGM>F%TT6rSqS+rRStNk#|GbJikic8ph*dkSAv&{>Zas&rM(-~`_Poap2`U3O}l z{8SX*R;4#j2XS)?xqz=ZYQCHqjk0k9D{niOm#xrQrIk@fj`Vb8h_h(Db15AUg!}tL z9kDf)bRHCrL$HDwtcr2*tTWL-Omjt}DyL(fF(YxmYRTTUq)>v$DvB?0r!rWDP%)t( z2Izj;oMxBmNkJ?D!*tU^MZhG^>5;?)J-CKfM`ol{R5b`WyZZZsc*Sd)ZtBG{>w;_e zKqjGH{AvUv@i1v~0;=5zB%r3rPOk%zof6(jzU3>HHn&w(RLnMltLqw-zM_r#`egVhyc&74y`uloMkm2+k#I#$h$&8?X`GfD6C zO@=ALEaN_UgL(w>t1|W0^Y<9D>Z5CLkb!2J)t64qipM%sL`gIg>MkCgi3AwtDl2AH z-%@c)B}GDJw}hs%|IE%Lo#)+>xY3Yvy+X95Q%p`c(c2m8nw3h=t*EG&<;*RV?lI2? GjsFjNt8Y#K literal 0 HcmV?d00001 diff --git a/GermanAirlinesVA-GAConnector/XPSDK/Libraries/Mac/XPWidgets.framework/XPWidgets b/GermanAirlinesVA-GAConnector/XPSDK/Libraries/Mac/XPWidgets.framework/XPWidgets new file mode 100644 index 0000000000000000000000000000000000000000..aba93db6a058120fe014641b395c679aa30a8827 GIT binary patch literal 210904 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�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�V403WGmiRHX5ue;jwMztd;Q);o%y(dtXYE50 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 literal 0 HcmV?d00001 diff --git a/GermanAirlinesVA-GAConnector/XPSDK/Libraries/Win/XPLM.lib b/GermanAirlinesVA-GAConnector/XPSDK/Libraries/Win/XPLM.lib new file mode 100644 index 0000000000000000000000000000000000000000..c7b00b10f0a9d20583e0f4c37081aa2545a04fa4 GIT binary patch literal 39362 zcmeHQTX5ZFwO=h*Yeht@RSRmt3Z){J(iG4hBu$z&ZIXuU^hzP!+54YlH#>WWy?4^4 zTw2Pl+)8OnDF});M9(=qFpk4GKJer?XPh$* zo#4~S%xeBwm+$x8FY8-@LJ-wY z%K#Sb1K2SO(0>kK;5Pt!HwilUCIHcWzZCQ^01yqmF6jPs07Qo_2rAzWK=kw)L6h$S z5Iyy_pvemUjr7!BK~t9l5Iz0Apz>>IkM#6uL6b{RAL+?|2s*zOfM^W!M|1)6O!V+y z1)aSXfavgILA7525FNlWri8i&koKJr)OZho=#c}0&cBN3BR%?-pbMA|(Y=2Wbovnh zqB+DMdhT68bLa7Iq@zm(ok4q|b0{ae^S6Q?I0`^?&j*6e^q?Nn3ugp9x*c(mPA?a9 z=RveXD*as0;Xh!xkY3y^=-34SqESpgrBVEils_eC8q*~@J}v0zpD=$&XHiac5V46K zdQ;E?SdT;p{w(MTtZSm;`+|nBZHbO!oe||$2zsa+?U62E+C(#$U!vV;M^wK-(9AaE zBR#%E(9v1U4^r`@pi@|Oq6aP$wD0fOPDuB^EU2&lJ@V%av|+rDQFkg7t!I0pxN`-zmOgr7Id-?>jP=(Z-O4K;XH)& z{F{PyZ9;pb-KU5~Mtb`PcMc7YbZ^OZ4fPHV?;IN0JJ{C`BO?R5`ucn+93!z14sY8v zuw$gVbGQ>yqpoVDQLC1_@>5AIk13RdII4)Jlz{JKx9;C1c#g6Ny|(&8^j{lQ&C1x?7Wm zMQ6^S)8Iz}D>8Nz%ws?;a)wX{QWJ&R3xLl?rElfR2E4aa;)9uIkiisp7SIST0dSvu{nR zQ%R#X=ODR4iRQ9Rfe^|SS~$J+-KBbIwCr|bVZ@}C6)pw11O@Y^L{`oeGmtMOBK_g~ zWPE-<{NPb)OSP z9KaEfuC8)cdx3&8DOs7G=Z`vHMi#1%`}(d#=4xv#KRr<@)N>7-U3eid$Bv9FHsky= zoE&M))ROhqQsxLqcWY9?ZBHYS`U5jlqe;zbzAO!4-H?VnS2(aVm$dd&Yvtl_m8Q`$ z*R%PgnW_v|Qvuhs`J~y6GtY1>U#XX83P}a`BeluRRcjv2(ooj926aG=LKcdvv_yrt zT8c|rSlS-!yxpa#q*BM-nNxY5kZk&sd>vayftgO`2uQcLf}6g48JDZU^2~V2PCp7mc*`dsW9m(rwbyJkT%W=gEibwxVko< zG`nVMxa)BBIG40=@vfH3dnS^k?5cVq(%&+Ry~EXH%oI7@`nyVE&n>v5)t^*mTphzp z)0s#LlZItlwaXT$)Os7q)Rsyf=WuJ3QVN!c^mk1cag+|0^Oa-(v)frI4(1yZykBN% zkTv#E(Ph&F>ciD-`AX4SI>IVx$*NORXyFzgS4qQ`IQ?_I-8@?eEm$fajS0~!9VOhI zC_ZTpCFN?q80f!_fONOz>pi&d!U4t8UL%pZ);J9a$p+`wEwx&;7TO>A zGP3Bci#!L~)f16^x`PW8)8>nmWyXU^yE3v6ih-(e1V&f2fa$tIRq;u)yHuwxt5`!sTBKh^ykNu;i_*D6q6lx8lfH7vvC3G(m_M;HqW_Z!k4)gxzadp^PH~3&6t91 zTc>f#JDjnSBGSiRqQ*0gTdwbkNMBDCGy`yLN8sstdjrcrO36yJsLB+Fa3!QYluT7; zlaRJ6Npn9jYA$&stN5?ec$Oy_af+Xq@> z!o+C_(i5DU8F79ST+*U7zf`L?2J*9=C2R6_B~p6;w_`zNE+Ad%L@eo@W8`Ath0Rb< zwtab(tFWmrSC)SE2ug8PInn|LMy1db0@6+Aub%$g7IdzaY#)&)l4;}oF@7d0NY|4QY@y4#GgXW>O2wm1QVZ+cu;jbFH!(s7+fW(QKv#V~ZU9zI>z4 zKJ#Irl!X$KO*%l8fcH5^AoIUvXvlAW=+_)5yUG=2a+2}0Q zrmHpUv>1}gTIeh^O0x;t6l(b~bl##Pg~MT01U1N7E@+*-J=I#eapHynVQPc>Xa#1e zTYSb{IDu;OtKru6%(#l$+S1;wHq zIIq{m*3_Esai_)wq}y4zccxSe=sE&fg3QcNtH~CX8I>j2QqE7;lj1NQ#&~^V<}HcT z?wTu<6Lpp|0}8b*Nt&C&L{gk7Cq3oT_ymrp>NHP37m$*bSU18pzKks7vKKZ92+2ly z4UAD}zZ%n`RE)18o=#kkQo`2pljyCWe|gq+09-_o(i*H)N6|S^tL00Tz5Dj_O7}#h zk1aDfGre>4P*P}Ez0nZ}-F#7KcGl-A1)g>v9zHA)>5CRiVY#lwCOz3qo}$gSbHEcc z;9~Bhvw5II7MoJrRiQJJ(B$daeA3L7re?}`6jG;fuIH8~koK1T2NQeoe za&^)gg}#g|#DOk{UYx}CnmPi~#gVzYRBO!S%LstgS*Vq!1D^Q|9hpKm&Oim+56-cz zpEdYH3S_(GNTZf7;LficI)8_xWMy15)<)4{tFqx*5bz-F)@-TQm#>V^;F*dy8&-{B zlU{c+Iy3IKn8hYN+U4curbesQbkDg;OST_JB{j_^J^9DZO2NvV#ZL9oeYQ3=^)E(~ z7O*ro&omm_bgLCRHmJjk`-2EZVs=*rrhJCBapgiIaUv-GCpb2sHS@| z>OMRdHlH+e`PuZE%+<8{5?yyzx>`nGmo@2Oh68f4RI7okJK+xs-o&^XWNp>}S85tE zTZd9mZHAY9)^&u+Z)`oI?P&W9-D5rvcub1bF)?jFZ6Md-3<>QvmNH|234K#@|bj|BojD z)?$3arZG(a0>ED}t!vK$EIthID~xMcb^!TECoo>@y#~ezJp%A5>c90U>Y)B#?!`Ee z(`Yk?c+X)h75-j&6y;~|?{fgZy%Xbo9su~@9)KR?op}LZJK8Qsn}aC(c?sYTh_(Ag z%=)A2#%BW=73U^V9V1H^j`>vAR9pF%o= ze=kRz-&YVH>;K(n&=%{LZTDh~ z(R0Xa0K9~MFGsxNsIv{zSc~ob)=7Y0@5kSFV_MigE3l3)V7g~8txK_9)?&TBiupT( z`F;CAEDxsJ^E|*m&tmM|IjrwJh>vA@;|S&r^La4Am>}#|-T3zq_JILRcRRMzJIH?r zbtztECD!fhyRdIz+nvYy8pd?{Fdu)zGS;vUy@}~>Lis7w+qa0i=opMc2iyo-VJY;& zLC8Z94#R)LkKsq~2K2)V@B_FMjzJYx!7lhAoP-HD4PSyULpOX6o`3|NgLQB}?1N7D z2s{9r;4FL#z6pC^6!yXp^uTxE`|x>~gfdLQ0k|9PfmdN8JO<0)v+zmy1biGm1D}F> z;b-s?Ov9tlfD-%%%)t@37QPE#gaN3)A$SO`hMmv{cfn8KDtHZUfmh%~SOaU}Yj7ug z8(xMb@G;m8!|)C0g4f{;JPWtMDYzZB!FJdTN8uUxDEud^glphQxEWT%gKz={;Q|!k zr|>vzf&FkFJOV4=3b-6DgXQpPs6!2MFaxvjG;DzDU<8iC^>7p109V2t@I0J{ufsX` zFZdjM1)hTS@KyK%?0{Qg5iI`yn*C5}_7bt94IKB3M^1P?Y3esTwpAlR;36~Y!q~mW z2}VC@U#Yq7(JYf4i^V*u8IH|>*Ccaw6MGl72T_{#p2uAe+21VZ;#P)j!I_%amxtWI+-_)&@WLyOy}?VBQkFRyN>k=>HCpoUWEkoO-{t5K z8Fqb0I^I4v-;JdCu&-7H%ZnmR*`AAtPI$^ap)~YCP%+dN zU;Q1r6(^bS?(5qi!=j>_PA=3$Q;G)4xEpgWQL~Oe-U)#iI$n%&L5zUQTZu02u~wS) zEs)E-*hP-gS7#ym`y#Oqo|lOB+almnMn;N6Ql<>HlPb8GWimUMPlgdn%~@N>0|<@x z)p%`Hs_Kwyjs>p7nN!oVg6DykMj`K+!Zc2QOoBC}E}l|!G^t;g-L^}0p=%YxIV)lc zJW5g8@k6O(S#dUK<+%#tt`IS$nUFP^s$e^DPMEsj^T03nlHGVUL?Pv3VA!(XMv9l@SY*mnue#wE)00j`pg2sKeH9@__R7&^R!RTZO&sMsBOCL#bPoz91~KUfCBd;g zj>HN?@z5k|z}1v%Wjqu&Wx60?$r$+-m)T<_{Ycmu6o6>t!SE~S09NtU}l7(tX7q(GMtq01#IK=^_Jxm3?~ zV7BbbQYI&R`Ii$=ZVS~)K)P8g0m=MpRhdI4v_*3LX&n<$OnzNRY<(M|dVq2B%j5#_ ziD)Rg25xdql&#cPLqkMMNTzd@CAp#53)2qHUYgHmFDEuU7#i1vJDjqU5#;K--s5gD zBlQO)lX*kZ$owV|E347q!_siwf$7EN$KuQENKXI#n{=;(PS1?DbJ$Ba&dJcY6U|xB zjf^o8wxcnI&RLNOq5;VK+-PjP(<2kvL4E;&oAJfO z=S-HII5IjObWa}k!HQ+gQ)cH+Pv&0_SZ7hLZ=FaTfvkW~e2M7fmNPuPCD#iGOUgc} zx&kwxta@grR@cJ2_!D;;VqWqS5qvtwvV_=a)^M#eEoav$#yy-->wN3kcv*GMy39Zv zZKJ^uqH=jTocLjuT=Y#k>mCI>Qk}JR%c_I8#*By4Y4QF=VVu))+b&{Vd9rQ zaB^nJ1tXKASB%zK+N5NisBJbojx`$(W+$NHzih53YCPVOowq~A!SG3S_BIAtCvdJ| zM{8ITd61B&aZhBu6o&^KQpf$6r-vIaj~9FcFr;X|2S_NP-I|@ge|itggDW0E_?tc} z0qZ<(Nz|eeib~54d5paPVISz7nzV(1ATlwL2XbRh{#O2-^S>?gW7D}Wz|!R&0bAht z1zfS(V7YvMg20vvdkQR5VHcv?a%{K zwNE!9?rShy<602aWG(qdXpQPj?*mKL_Caug8*0yGA`kjl&qcD($}3?+wr|4lZ4ZUb zSAL2RHxSIkeHPrr@?02!-nC0p4HSFV6 zKyDqee7V_dsgp0C*i=6JnLtVSaf_$!dPBI(@`+di^jrmczvCa_7Fj|4wy(rkggho( zn*CB%8nYjH10?K2VQG7zo|cT-(OSjvpzp2Xl4mW>l4q^rl1CnQ55!)@Ni)8RlSXV2 zM!DmEu^_XSVKh@B<%_ZHA|4q_(ecYzGSO`;CG)<(Ld+YB<+6(5y4csYHr%>ies}BOvc5%^z>DAh+0G>x z2eTB?pG7woDe7@GMihyk+wm8MWLZCVz!jTsEERF$SiN2emgB?!ApKD?F2Ub-z`D1k z-bTsBm=}!iK~j3ezXMjiy%>Lg6606sXQ?XGb?})hK8g%VjDE=Y%2z(!U&41->(#Nw zsx?E`uj=a^*pW(|e=ftn$&eDjc%$^`3jFsY>63y$^g?xN8nb!jD=)*p{-wZ3pMEG` zi$Rt44h&Qx&V=Hm>b5aWd32j<7UOB-thzVhx|>wgUY|Kt=>#)QVV3dQkSWo z(d>v?e~Uk&-a!P>w&6O9jHnJ-J!y}n5ygMlh}xj|)KmXg{ULuZT-`QPpDPh{Vfx>O zTV?lKMc)FX(b%_$W~i&uaxE2(c-zCRnhVrJv+cIwwlEg;jzu^hrY?8m8c%)C3Ikg1 zB^?{WXxAXxVjs=8B{ZaZXu5ony1Yao+P-}S(Q;jO+#D|5)mXYqHI{!}paEO1&kg!( zl6Ft|0wR7yA+jro_K`Z&hbo;u`6WbJVvy{wg=skTun?{GQH^HZlqiUnTP-%)mU>wB z08pUKmMhjnJ{H6h@qr4bjS;7&WvAU%VY@BUh~6EM22>BtmM~VEAGh$-`9n9DerOs? zEz?ffuEerkrm^ImRC<%8O4CL?M#lChTr74wHV?#%vHcY+-Q__<^-fFsn6dfflMW`` z;>`nTV|cElRrCr6DZLrgQ0k%CUea+>80pK1^eG3)TsA6{)_cl^NXb6!;H4Ls8cIDh zTe8?#`;0;2ccKbHx7h3ro%+baUG_n%?XOW|0*ZnmF?^sMgo( z$c*(l3rqRobg^2;itKzoud%F4YYnCzn(ZC2G4=%;%QzTJleJ#9jJc8aJu7WIax%>a zDKeU`w2{OmxT-ph*=!xg`r%bJl5lcqgf`}=$gcm3AuJ3l&;?u2*7}l0GocFeK#H{1 zmlYBZf6!3sq1o2zi0rFY86-ENLc!?TY!)xJs$A{h*V|n2z3a0fIiy3Hb3*J>>56_U2g6|2YV43_(D zO51p`d2x-#=cL{7Dj8rubbU7_01SQ<<{G+mdGb@N6WOI>d1vD|un#(MrYY&3TQ zX}RaeM)f*_<$n86RiG|q(>0ml3H&_vm76r4j%{ljC+2ZkuW|fvIStryO~zL0n-wAt z!P8Lcq3Jq|%pn^%5?u`9rKfHr{m?8@M+VYrY^@HCLbZ;WF>jIoVv8;g~X>v3;c2iRo63Bu2K3k(>u!qy=va;hDHg4XPfR?llpg@i%=;5z47R zTJA3~-_^G`nv4$BKrQ!@*gCgKA!S6IwvQUSsre6sYDKZOj~4U6+|JPC)FL8dHJo~A zwx?{!@UDIi$KAIbH2j`~yzOseMUCLx;o!{6yBWdhba2?T+;UHh)!SwVr!=2>i>%gN z4i1Jr=>}2{P4|NcPPdE03e+l2Yy@xNIDz0Sh1GiR>&RGLXhrMcs9xCiJTN2kK7H#Y zz28kEy}hrQX;AghY%9jfxy{0K-xF6zt=DaAcI;)CJYv0lwAk#pouR2at~BUc!>Na6 z>oZoi9UP4X)+>zGYch5c=;LU1u)YRV56zY?hS$&V>=6I<=a|@Db|4ckeWgGZO@lXE z#@HEkC&Lss4D;+Q86%!<)&?1te(|C0QpNVLcQPdVT?!4?`f8Wqb6tTY8{&BMeujoo z4-3&&IflYs`A`rVbRn>YIhOhEciUL8*qdD(%Y8AWZN!-WVz-Sb!$~z%>wP1`_e8M( zdu*)v`${srt=A&fUXB&|dWSBedRU0QvX7yP;>~joiPYwPj#X3NtW>3GeZ7gzjdw9D z_BN6RQx6MKhX**8dBI6Rv_7^oc6;PYxSL_AccwH@>wP~mE`*mXSVj&g^x#^Nc#zNxbu|s~VNF9+? zU`!)r{I9JFto2zX1C?Tf#|^4<%cNgEY8xxIznd^v&Wns1uH|_wcB(2FJkdwgdx9EH zJv7@>VrYj9ntY*1zHg~OT5q?=iaM##tXDWSRLk`k+jo@}mi1cbJg_3G+!V)>ubQ@x z6l<@Fk0f4S)o|*e+1?SW!>U1JZ^SBu*5}CB4rtn7@waR>n0jcsT#@o2|8A%-TJIaN`^y=H z7I+PM9*B{h$gDY>@%jFs=OLJPdDt#I0?(Ttgxq7;r8MDagaJFi{N12tow zB;W6xi%P4v{)*m*gL%}$Dr% z?Kc}U#=#9(o98%Q_J?v5Wa}$Iq$Qtc*!H(~G+fJLJ{GTWp5cj2Gyk5?JTN1@=LLqT z!l=`41Zg<+&}?hQR=Eod&Hn6=LTO_xM!eoHGQ5AseZ@;2-iLi(@f{Cw-uD$5qmiP; zU)E?7`C9rP-su6SADZqbkzVbKlE`I z%7+v|{ZRmQfxJi=p5w1!9sk%zT~I$#Y*fDHW6$4{6!8rH#K&6@Us7x)c->&u7hpz> a^q-$?)%vcS!TLX+gf&nA literal 0 HcmV?d00001 diff --git a/GermanAirlinesVA-GAConnector/XPSDK/Libraries/Win/XPLM_64.lib b/GermanAirlinesVA-GAConnector/XPSDK/Libraries/Win/XPLM_64.lib new file mode 100644 index 0000000000000000000000000000000000000000..51fdf7011bde4bbc015cdef5159af7166eb6417f GIT binary patch literal 39060 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 E0YsuO1^@s6 literal 0 HcmV?d00001 diff --git a/GermanAirlinesVA-GAConnector/XPSDK/Libraries/Win/XPWidgets.lib b/GermanAirlinesVA-GAConnector/XPSDK/Libraries/Win/XPWidgets.lib new file mode 100644 index 0000000000000000000000000000000000000000..1eac5bf707a8ee4a8adc9b8d671f9d24b338df27 GIT binary patch literal 10524 zcmcgxOKcQJ5G~u`XABsy@!wwm4I~a2ulXcO3^oP}+lFJ*Co}OWsH5sWqJ5|;F`cqY1UGDxd z<78KUs{KA8KZlPT8A~RQjvhZE^AGu-BO}Mg=+CRQ0B`|d&k{hxeSpSS0Nwj2wcQ0E z)c&4QM*)CP>r+ZCuK@_PPEkrc1|Zb&hEnef07A`sD7DvNKZI^m8mI>#)P0Xq&l&)s zwoXb-4*&>tf27p)41iGo5T&k3{6^|bQA!LWK2qN}rJlFgA5!lnN}V_sLQMmd`X6FH zNPRdTLd|z5wXER0keWYG8n}t$L>f9lY49Zgp`j;~2Hv3@Y48f6g@x%^^D0v!K}jXOc66?7`{(#BaUXQ~<^FKtX0sr-^vv=;Mb&{0T` zHm1}sYeZ?o$Y-*?*$@x2gh^{e!st(5Uqh%|u;vVgZ%0TY zZJf;ct~8O!=NB=E1*@eI3A-392!r9f7>ERYamhn1L?L>)V`f})V!i0vtE&I#WEjuP zqU+c7_Z-%$d1hCqe?$#lwcgWoB7|a!5k7oy;8|1y{#oVeHpbm9zBh_Q>aSz+A^Z0F}cR=xahNonHrZBM`RsI?kF-fi9B;nrl#hI zjE_bd?WTf~>a2oDPKyOWl;f%@{Bk1*=#mId9FmEy91?~cI;0`Fbx0bRcSsbtct|8T zx+IHmccvrW2pBJvZmR+w0GL3NN-~iqYh)sANC<>#GAl^v4(WD*$Aj=Ha#45{#hVj@ zQNsr3hccW%qRVrnK*Ck!aKhP2P`MRdf8dhgTt1Hp)aR;8$wPy7zr%y$5)5Rd5*{x~F_SL3?@vmo;9kR~+gseqeKT8z;%)VhwyvIAO9h}1N`8BkykZfWegMQFFHJNxk8#A3dZC6uzecqhOWk0=6`y>7?E zb)%m44+7Aw)~{QPrzP1^5rZV2CO(3vjWRyb`XR1gH>-A>1RexKNK%i_77-OY*1rx7xc<1skBXTntSo$i#^Wx@OO>x6Hp9E6= zT$BEdI-$(959eCrV}_GS8C3czWu6i1i`Qxl+1~n!xw{g!%SK}dpfW>ZsGBI7ocu}v z<*(@IalOToV6)lB6E3-xq8-(vVL1a2JZ~*Y4o}ndO0kaVv9OeaNF2+*2gqR3S1C5a zf~m4=3B=k)v6TCTgdp2Y33y`>appV3Bb6GwKE~Z!Wbm>hPMqg&=jh6Xs8US+|42Eq zcH@leIHq*dst|E30+H16c5uXqD_n)x$p~yR+nq8tyBk)D7!z4{aYXgfDT7L1C0KDX zA{t2Q!KR}BLkLiK`{}qMMh+Wo=OoT&Qy}Sw^GD#1?ekdwo%M* zX{u7pn5f%MF?BVsN>L*`g_IdO7^+fClOd(A5_~i6bm`=X8-2ROMcXa~_5X;r2?cYb zqHSFC>Gm;$e{e{9S9YZ1B_2(7-9xdII%tJ>F}B+4{s%vmUO4~& literal 0 HcmV?d00001 diff --git a/GermanAirlinesVA-GAConnector/XPSDK/Libraries/Win/XPWidgets_64.lib b/GermanAirlinesVA-GAConnector/XPSDK/Libraries/Win/XPWidgets_64.lib new file mode 100644 index 0000000000000000000000000000000000000000..32c3ae4991a082681f66f655479e97b574cb4932 GIT binary patch literal 10564 zcmcgxOLH7W5>Crcv<8G9dRrR3h4IQr)`)e)hF7*^fv_ZZ$TFV8hUL+8TbkI>v|^^U zU?03UPWuBK#B$@raf1T~g5W@KCicL=#|>hS`~VKHUv+g=*Q2}TW+XZy)#}Ww`s$IH zm6bE}=W?U6bEExgL4T&NU7ITw-;r(oLb9vRdyS}lx zc>CVM`m(cecYU+uJgBKE_#p4`?X-Py6e@ORlnXupVi$xz+|X|!rL_uZGy}WQgy-}HX7y1-!j{$XvD2o zy`WL8XoC*h2!6>~Y?MFbQ?rQ&SK;t`T;s$vG!lCbl6Ds=>~ZU)k3N!}lr{ zDf$bwa)1Pemz*&sn*=cQl!2u z3CFV*>?rC|8^bXqp|(?QVB3w6Kv&~q+&ezjoy|sesIW@TdsWvngDpcAmdd*6sx)=BjyNM!GS~v}V&uat; zGmw&S26wzCTYkCW>XwfQ=z@~7;x|2=CuVC)N{&-2S0eLZ&Qp!2YD<(+-~MP1Fs@u= z0U?*)R46$&-N;QA%C*`S0+L)ITcYflTm=Ck_e@F@ZDoxueMJV}ZFuFtTi9;~{;uI2 z2_nQMuNgG_Cx)ud6}=ityuXN9a_+0&aSSuq&|CHY9_`Gn*gAABw3ezLdG1R2iN7Cv zn8t+8J+J0fg5}3+p67b5Tz8WXO&k&|vI_f&RZRiYZIri-sj9sE`OS>XZ{9+JQ#eQT z@B+~%7m=w95k2iA`mvvA>k@dqL|^p~UBUY^WI;cG_hN+Tr!JzOp|=OU%i~1PS-WAP zGvEb~ox=ZL4ieoMBbvv1Wq@c3?bk=q7BUxod<)($okU+i=R5G-Zld>r^#bqb==0$u zbSH?u$GaWxXCNeFRG^FW8ja8xjnXUBPG{%>out>PgHF+DI!nDYNIld=ee?%9LFcHG z&eJ6tpjWA%hN+u|=nWdD%k&ma(geLp$EfYl`#g?}B+1)SLvqqVmgpa5UTN)Z9RZH7$lnt{v>8DCL}xfl~og;+br2 zB{a#Yq;|^N2WiX^hkVj8k#rca&}yee2?tVg3|6?xj1wbxoW&rtsMgekIazT@4?p-) z!yrDj*oki|0{+%~Uz{qo7YRvJE*J`*uS4vgmPqkZOJ@42rJ#DOC6rcdNu>8$lGukeQL-ls z6(vO%EHe!@`NFpa-%j_0#7^ymB+1)jnUQNM0=^{)>n?rWS~)4PR!+IT2nZu0NVb`l z#Daw6M2!(rQHvCkYs8D}TmDre)j6n=GyRUJ@H}c)%Lh|#tw!xvMZqUhI;gke^lYU0 zsNMbeIQ{!CpWp2~hMWgE345koZ)<;hl%*))vxL9@jQ$s|dFr?|Rdvfjd2~kbkb2R7 zK>v#v$MK%0x4((><{~yS8KM)w6MBq4Pla#V@a{q;#GVdwniF)s<1_@Q#)J>6X!U)1 zZnauz_)Y(DP?%hQv#_$fb|;c+ue11KqhSQ>@V^fHJsJLILSZx&e|HbV?)&s#^y{x` zJ2W6R&NdRWpC<}Oz9Tr{JULpVGs|?)h@?(2<}f}INBOYck#EXxhV@r`9aY6Cul39n zi;DHMh1T;m#>dB-0V>&bX5?wyu+qN3iamlUNh>t2Ea3bGF|J9)V`;Bs4wNOKGu zWijWK5Y4#3Sj(9gaW2IduL7|>M9jJzS@8L-Ck3CyK2}3YE`S)zoF7#r1jag#0QIau z)h>0d&vY&Y^N+xMRbZxE7+Xh|DNw?UU(?XVW%Lj*Ga~Nm0+VlLe9^UF^ICK9^sxQ`p(g7&W=j(lUD1>DLvaD>aaQ$DqL_O}Q_ggjj}M1vM$xu)8_KZT5sqlqgImYUxWSD^m~pAug3BLsGw#G= k98WD{TY$NDG2>1=&hfMgxdoVih8d^I1V=Qg?>6TD0S!6a{Qv*} literal 0 HcmV?d00001 diff --git a/GermanAirlinesVA-GAConnector/XPSDK/README.txt b/GermanAirlinesVA-GAConnector/XPSDK/README.txt new file mode 100644 index 0000000..2316eb5 --- /dev/null +++ b/GermanAirlinesVA-GAConnector/XPSDK/README.txt @@ -0,0 +1,197 @@ +------------------------------------------------------------------------------- + THE X-PLANE PLUGIN SDK +------------------------------------------------------------------------------- + +This download contains the files necessary to build plugins for X-Plane. The +X-Plane plugin website is: + +http://www.xsquawkbox.net/xpsdk/ + +The website contains full documentation on the SDK including tech notes, sample +plugins, sample code, contact information, and links to the latest versions of +this SDK. + +The X-Plane SDK authors can be reached at: + +xplanesdk@xsquawkbox.net + +Please do not email Austin or Laminar Research for SDK questions or support; +the SDK is a third party effort. + +the X-Plane developer mailing list is an unlisted yahoo group frequented by +many X-Plane developers. + +x-plane-dev@yahoogroups.com + +------------------------------------------------------------------------------- + SDK FILES +------------------------------------------------------------------------------- + +license.txt Copyright information for this download. +README.txt This document +CHeaders Header files for compiling C/C++ plugins +Delphi Interfaces for compiling Pascal plugins +Libraries Import libraries for linking on Windows + and frameworks for linking on Mac. + +Note: there are no import/link-time libraries for Linux; on Linux, plugins +simply leave SDK symbols undefined and they are discovered at runtime. The +SDK website explains this process in more detail. + +Mac CFM plugins are not supported by the SDK versions 2.0 and higher; the +2.0 SDK requires X-Plane 9.0 or newer, and X-Plane 9 will not run on +Mac OS 9. Therefore CFM plugins are not useful (and are probably +counterproductive since they cannot support x86 code). If you have a CFM +plugin, continue to use the 1.0 SDK to build it. You will have to port to +Mach-O if you want to use 2.0 features. + +------------------------------------------------------------------------------- + RELEASE NOTES +------------------------------------------------------------------------------- + +This section contains per-release notes for the history of the X-Plane SDK. + +X-Plane SDK Release 2.1.3 11/14/13 + +Fixed XPC Wrappers to use int and intptr_t instead of long. This fixes +crashes for plugins on 64-bit Windows. + +X-Plane SDK Release 2.1.2 RC2 1/15/13 + +Removed headers from frameworks, as they don't work; updated README. + +X-Plane SDK Release 2.1.2 RC1 1/12/13 + +The 2.1.2 SDK adds frameworks for the XPLM and XPWidgets; Mac developers +can link directly against these frameworks and avoid unresolved symbols +and flat namespace problems. The frameworks produce plugins that will +work on X-Plane 8, 9, and 10 depending on the plugin CPU architecture, +minimum system SDK, and XPLM API revision number. + +X-Plane SDK Release 2.1.1 RC1 10/29/12 + +The 2.1.1 update to the SDK provides 64-bit build materials. + +X-Plane SDK Release 2.1.0 RC1 3/31/12 + +This is the first release of the version 2.1 X-Plane SDK. This version of the +SDK exposes new APIs. + +This API also replaces all references to "long" with int or intptr_t, +depending on whether the integer needs to be wide enough to hold coerced +pointers. Most of the time, int is used; the notable exception is the widgets +library where params and properties can contain pointers to user data. + +This change is not an ABI change - compiled plugins will work unmodified. +However for some compilers, you may need to replace long with int or intptr_t +in your code. + +X-Plane SDK Release 2.0.1 RC1 7/21/10 + +This release adds symbol visibility macros for GCC 4 on Linux and corrects a few +function documentation comments. + +X-Plane SDK Release 2.0 RC1 7/11/08 + +This release includes a corrected XPLM.lib for windows with exports for some of +the new 2.0 APIs. + +X-Plane SDK Release 2.0 Beta 2 4/23/08 + +This release includes new APIs for reading and writing data files and drawing +hooks for the local map screen, as well as some minor tweaks: + +- Sim version is 2.0 in the headers. +- unload plane msg marked as 2.0 only. +- New enumerations for additional languages. +- Function level docs improved. + +X-Plane SDK Release 2.0 Beta 1 1/19/08 + +This is the first release of the version 2.0 X-Plane SDK. CFM support has +been removed, and the license has been simplified, reflecting that it only has +to cover the SDK include/import lib files and not the sample code or examples. + +X-Plane SDK Release 1.0.2 1/5/05 + +The headers of the SDK are modified to support Kylix. No changes for Mac, +Windows, or C users. Headers now have SDK version numbers. + +X-Plane SDK Release 1.0.1 12/29/04 + +The headers of this SDK are modified to support Linux complication. No changes +for Mac and Windows users. + +X-Plane SDK Release Candidate 1 + +Only one slight change in the enums: the enum xpProperty_SubWindowHasCloseBoxes +in XPStandardWidgets.h has been changed to xpProperty_MainWindowHasCloseBoxes. +Its value has not been changed, so you will need to search-and-replace your code +when using this version of the SDK, but already-compiled plugins will experience +no different operation. + +The documentation has been revised for all headers to revise changes made to the +SDK over the course of beta. + +X-Plane SDK Beta 5 + +This version of the SDK features a number of enumeration changes to reflect the +X-Plane interface more correctly. This became crucial when X-Plane 7's new user +interface was released. With X-Plane in release candidates hopefully beta 5 of +the SDK could be the last one. Please see: + +www.xsquawkbox.net/xpsdk/newui.html + +For a comprehensive description of all the enumeration changes. For most +plugins (no developers reported using the deprecated enumerations), a simple +search and replace should suffice. Plugins compiled against the beta 4 SDK that +do not use now-unsupported graphics will continue to work correctly. + +X-Plane SDK Beta 4 + +This release corrects two problems with the Pascal headers: function pointer +types are now declared cdecl (since this is how the SDK calls them), and the +import library for the widget callbacks is now XPWIDGETS.DLL as it should be. + +X-Plane SDK Beta 3 + +This release finally features full documentation and a stable widgets API, as +well as a few other minor bug fixes. + +Starting with beta 3, the DLLs necessary to run plugins ship with X-Plane 660. +The SDK will work with X-Plane 660 RC3 and later. The XPWidgets DLL now lives +in the Resources/plugins folder. + +Starting with beta 3, extra plugins, documentation, sample code, and sample +projects are now featured directly on the web in the new X-Plane SDK library. +They are not included in the SDK zip file; the zip file only contains headers +and lib files for the SDK. + +X-Plane SDK Beta 2 + +You must recompile your plugin for the beta 2 plugin SDK! Plugins compiled +against the beta 1 SDK will not work with X-Plane 660 or the new XPLM.DLL. + +A huge number of data refs have been added. Unfortunately the documentation +is thin. Use the data ref tester plugin to view the data refs in real time +and find what you need. + +The data ref APIs have also changed to allow for arrays of integers as well +as floats. Some sim variables are now arrays that were previously many +individual items. + +A new drawing phase is available for replacing aircraft graphics. The +texturing APIs in XPLMGraphics have been revised. The most notable change is +that you cannot use the SDK to load your textures. (This functionality was +broken and never worked in beta 1.) See the x-plane-dev list for sample code +on how to load your own bitmaps. + +X-Plane can reload plugins on the fly. Use the Plugin Enabler plugin to reload +your plugin. On the Mac you can throw the old DLL in the trash and put a new +one in its place to reload a new version of the plugin. On the PC, an alert +comes up; while this alert is up you can swap your plugins' DLL. This allows +you to recompile your plugin without rebooting the sim. + +Delphi Pascal interfaces and sample code are in the SDK. Thanks to Billy +Verreynne for his hard work on this. + diff --git a/GermanAirlinesVA-GAConnector/XPSDK/license.txt b/GermanAirlinesVA-GAConnector/XPSDK/license.txt new file mode 100644 index 0000000..8b9cbfc --- /dev/null +++ b/GermanAirlinesVA-GAConnector/XPSDK/license.txt @@ -0,0 +1,27 @@ +Copyright (c) 2008, Sandy Barbour and Ben Supnik +All rights reserved. + +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: + + * Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + * Neither the names of the authors nor that of X-Plane or Laminar Research + may be used to endorse or promote products derived from this software + without specific prior written permission from the authors or + Laminar Research, respectively. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/GermanAirlinesVA-GAConnector/build.sh b/GermanAirlinesVA-GAConnector/build.sh new file mode 100755 index 0000000..eb68bfa --- /dev/null +++ b/GermanAirlinesVA-GAConnector/build.sh @@ -0,0 +1,37 @@ +#!/bin/bash + +mkdir -p build +cd build +mkdir -p Plugin/WebSocketTest/32 +mkdir -p Plugin/WebSocketTest/64 +rm -f CMakeCache.txt + +case $1 in + "mac") + cmake -DDEBUG=$DEBUG -DCMAKE_TOOLCHAIN_FILE=../toolchain-mac.cmake .. + ;; + "lin32") + cmake -DDEBUG=$DEBUG -DBIT=32 -DCMAKE_TOOLCHAIN_FILE=../toolchain-lin.cmake .. + ;; + "lin64") + cmake -DDEBUG=$DEBUG -DBIT=64 -DCMAKE_TOOLCHAIN_FILE=../toolchain-lin.cmake .. + ;; + "win32") + cmake -DDEBUG=$DEBUG -DBIT=32 -DCMAKE_TOOLCHAIN_FILE=../toolchain-win-32.cmake .. + ;; + "win64") + cmake -DDEBUG=$DEBUG -DBIT=64 -DCMAKE_TOOLCHAIN_FILE=../toolchain-win-64.cmake .. + ;; +esac + +make -j +code=$? +if [ "$code" -ne 0 ] +then + exit $code +fi + +if [ "$1" = "mac" ] && [ "$DEBUG" = "1" ] +then + /opt/osxcross/target/bin/osxcross-llvm-dsymutil Plugin/WebSocketTest/mac.xpl +fi diff --git a/GermanAirlinesVA-GAConnector/ixwebsocket/IXBench.cpp b/GermanAirlinesVA-GAConnector/ixwebsocket/IXBench.cpp new file mode 100644 index 0000000..665f3fe --- /dev/null +++ b/GermanAirlinesVA-GAConnector/ixwebsocket/IXBench.cpp @@ -0,0 +1,56 @@ +/* + * IXBench.cpp + * Author: Benjamin Sergeant + * Copyright (c) 2017-2020 Machine Zone, Inc. All rights reserved. + */ + +#include "IXBench.h" + +#include + +namespace ix +{ +Bench::Bench(const std::string &description) : _description(description) +{ + reset(); +} + +Bench::~Bench() +{ + if (!_reported) { + report(); + } +} + +void Bench::reset() +{ + _start = std::chrono::high_resolution_clock::now(); + _reported = false; +} + +void Bench::report() +{ + auto now = std::chrono::high_resolution_clock::now(); + auto microseconds = + std::chrono::duration_cast(now - _start); + + _duration = microseconds.count(); + std::cerr << _description << " completed in " << _duration << " us" + << std::endl; + + setReported(); +} + +void Bench::record() +{ + auto now = std::chrono::high_resolution_clock::now(); + auto microseconds = + std::chrono::duration_cast(now - _start); + + _duration = microseconds.count(); +} + +void Bench::setReported() { _reported = true; } + +uint64_t Bench::getDuration() const { return _duration; } +} // namespace ix diff --git a/GermanAirlinesVA-GAConnector/ixwebsocket/IXCancellationRequest.cpp b/GermanAirlinesVA-GAConnector/ixwebsocket/IXCancellationRequest.cpp new file mode 100644 index 0000000..ddc58e5 --- /dev/null +++ b/GermanAirlinesVA-GAConnector/ixwebsocket/IXCancellationRequest.cpp @@ -0,0 +1,39 @@ +/* + * IXCancellationRequest.cpp + * Author: Benjamin Sergeant + * Copyright (c) 2019 Machine Zone, Inc. All rights reserved. + */ + +#include "IXCancellationRequest.h" + +#include +#include + +namespace ix +{ +CancellationRequest makeCancellationRequestWithTimeout( + int secs, + std::atomic &requestInitCancellation) +{ + assert(secs > 0); + + auto start = std::chrono::system_clock::now(); + auto timeout = std::chrono::seconds(secs); + + auto isCancellationRequested = + [&requestInitCancellation, start, timeout]() -> bool { + // Was an explicit cancellation requested ? + if (requestInitCancellation) + return true; + + auto now = std::chrono::system_clock::now(); + if ((now - start) > timeout) + return true; + + // No cancellation request + return false; + }; + + return isCancellationRequested; +} +} // namespace ix diff --git a/GermanAirlinesVA-GAConnector/ixwebsocket/IXConnectionState.cpp b/GermanAirlinesVA-GAConnector/ixwebsocket/IXConnectionState.cpp new file mode 100644 index 0000000..43eb9e1 --- /dev/null +++ b/GermanAirlinesVA-GAConnector/ixwebsocket/IXConnectionState.cpp @@ -0,0 +1,54 @@ +/* + * IXConnectionState.cpp + * Author: Benjamin Sergeant + * Copyright (c) 2019 Machine Zone, Inc. All rights reserved. + */ + +#include "IXConnectionState.h" + +namespace ix +{ +std::atomic ConnectionState::_globalId(0); + +ConnectionState::ConnectionState() : _terminated(false) { computeId(); } + +void ConnectionState::computeId() { _id = std::to_string(_globalId++); } + +const std::string &ConnectionState::getId() const { return _id; } + +std::shared_ptr ConnectionState::createConnectionState() +{ + return std::make_shared(); +} + +void ConnectionState::setOnSetTerminatedCallback( + const OnSetTerminatedCallback &callback) +{ + _onSetTerminatedCallback = callback; +} + +bool ConnectionState::isTerminated() const { return _terminated; } + +void ConnectionState::setTerminated() +{ + _terminated = true; + + if (_onSetTerminatedCallback) { + _onSetTerminatedCallback(); + } +} + +const std::string &ConnectionState::getRemoteIp() { return _remoteIp; } + +int ConnectionState::getRemotePort() { return _remotePort; } + +void ConnectionState::setRemoteIp(const std::string &remoteIp) +{ + _remoteIp = remoteIp; +} + +void ConnectionState::setRemotePort(int remotePort) +{ + _remotePort = remotePort; +} +} // namespace ix diff --git a/GermanAirlinesVA-GAConnector/ixwebsocket/IXDNSLookup.cpp b/GermanAirlinesVA-GAConnector/ixwebsocket/IXDNSLookup.cpp new file mode 100644 index 0000000..db0b8d1 --- /dev/null +++ b/GermanAirlinesVA-GAConnector/ixwebsocket/IXDNSLookup.cpp @@ -0,0 +1,190 @@ +/* + * IXDNSLookup.cpp + * Author: Benjamin Sergeant + * Copyright (c) 2018 Machine Zone, Inc. All rights reserved. + */ + +// +// On Windows Universal Platform (uwp), gai_strerror defaults behavior is to +// returns wchar_t which is different from all other platforms. We want the non +// unicode version. See https://github.com/microsoft/vcpkg/pull/11030 We could +// do this in IXNetSystem.cpp but so far we are only using gai_strerror in here. +// +#ifdef _UNICODE +#undef _UNICODE +#endif +#ifdef UNICODE +#undef UNICODE +#endif + +#include "IXDNSLookup.h" + +#include "IXNetSystem.h" +#include +#include +#include + +// mingw build quirks +#if defined(_WIN32) && defined(__GNUC__) +#define AI_NUMERICSERV NI_NUMERICSERV +#define AI_ADDRCONFIG LUP_ADDRCONFIG +#endif + +namespace ix +{ +const int64_t DNSLookup::kDefaultWait = 1; // ms + +DNSLookup::DNSLookup(const std::string &hostname, int port, int64_t wait) + : _hostname(hostname), _port(port), _wait(wait), _res(nullptr), _done(false) +{ + ; +} + +struct addrinfo *DNSLookup::getAddrInfo(const std::string &hostname, + int port, + std::string &errMsg) +{ + struct addrinfo hints; + memset(&hints, 0, sizeof(hints)); + hints.ai_flags = AI_ADDRCONFIG | AI_NUMERICSERV; + hints.ai_family = AF_UNSPEC; + hints.ai_socktype = SOCK_STREAM; + + std::string sport = std::to_string(port); + + struct addrinfo *res; + int getaddrinfo_result = + getaddrinfo(hostname.c_str(), sport.c_str(), &hints, &res); + if (getaddrinfo_result) { + errMsg = gai_strerror(getaddrinfo_result); + res = nullptr; + } + return res; +} + +struct addrinfo * + DNSLookup::resolve(std::string &errMsg, + const CancellationRequest &isCancellationRequested, + bool cancellable) +{ + return cancellable ? resolveCancellable(errMsg, isCancellationRequested) + : resolveUnCancellable(errMsg, isCancellationRequested); +} + +void DNSLookup::release(struct addrinfo *addr) { freeaddrinfo(addr); } + +struct addrinfo *DNSLookup::resolveUnCancellable( + std::string &errMsg, + const CancellationRequest &isCancellationRequested) +{ + errMsg = "no error"; + + // Maybe a cancellation request got in before the background thread + // terminated ? + if (isCancellationRequested()) { + errMsg = "cancellation requested"; + return nullptr; + } + + return getAddrInfo(_hostname, _port, errMsg); +} + +struct addrinfo *DNSLookup::resolveCancellable( + std::string &errMsg, + const CancellationRequest &isCancellationRequested) +{ + errMsg = "no error"; + + // Can only be called once, otherwise we would have to manage a pool + // of background thread which is overkill for our usage. + if (_done) { + return nullptr; // programming error, create a second DNSLookup instance + // if you need a second lookup. + } + + // + // Good resource on thread forced termination + // https://www.bo-yang.net/2017/11/19/cpp-kill-detached-thread + // + auto ptr = shared_from_this(); + std::weak_ptr self(ptr); + + int port = _port; + std::string hostname(_hostname); + + // We make the background thread doing the work a shared pointer + // instead of a member variable, because it can keep running when + // this object goes out of scope, in case of cancellation + auto t = std::make_shared(&DNSLookup::run, + this, + self, + hostname, + port); + t->detach(); + + while (!_done) { + // Wait for 1 milliseconds, to see if the bg thread has terminated. + // We do not use a condition variable to wait, as destroying this one + // if the bg thread is alive can cause undefined behavior. + std::this_thread::sleep_for(std::chrono::milliseconds(_wait)); + + // Were we cancelled ? + if (isCancellationRequested()) { + errMsg = "cancellation requested"; + return nullptr; + } + } + + // Maybe a cancellation request got in before the bg terminated ? + if (isCancellationRequested()) { + errMsg = "cancellation requested"; + return nullptr; + } + + errMsg = getErrMsg(); + return getRes(); +} + +void DNSLookup::run(std::weak_ptr self, + std::string hostname, + int port) // thread runner +{ + // We don't want to read or write into members variables of an object that + // could be gone, so we use temporary variables (res) or we pass in by copy + // everything that getAddrInfo needs to work. + std::string errMsg; + struct addrinfo *res = getAddrInfo(hostname, port, errMsg); + + if (auto lock = self.lock()) { + // Copy result into the member variables + setRes(res); + setErrMsg(errMsg); + + _done = true; + } +} + +void DNSLookup::setErrMsg(const std::string &errMsg) +{ + std::lock_guard lock(_errMsgMutex); + _errMsg = errMsg; +} + +const std::string &DNSLookup::getErrMsg() +{ + std::lock_guard lock(_errMsgMutex); + return _errMsg; +} + +void DNSLookup::setRes(struct addrinfo *addr) +{ + std::lock_guard lock(_resMutex); + _res = addr; +} + +struct addrinfo *DNSLookup::getRes() +{ + std::lock_guard lock(_resMutex); + return _res; +} +} // namespace ix diff --git a/GermanAirlinesVA-GAConnector/ixwebsocket/IXExponentialBackoff.cpp b/GermanAirlinesVA-GAConnector/ixwebsocket/IXExponentialBackoff.cpp new file mode 100644 index 0000000..9a40999 --- /dev/null +++ b/GermanAirlinesVA-GAConnector/ixwebsocket/IXExponentialBackoff.cpp @@ -0,0 +1,30 @@ +/* + * IXExponentialBackoff.cpp + * Author: Benjamin Sergeant + * Copyright (c) 2017-2019 Machine Zone, Inc. All rights reserved. + */ + +#include "IXExponentialBackoff.h" + +#include + +namespace ix +{ +uint32_t + calculateRetryWaitMilliseconds(uint32_t retryCount, + uint32_t maxWaitBetweenReconnectionRetries, + uint32_t minWaitBetweenReconnectionRetries) +{ + uint32_t waitTime = (retryCount < 26) ? (std::pow(2, retryCount) * 100) : 0; + + if (waitTime < minWaitBetweenReconnectionRetries) { + waitTime = minWaitBetweenReconnectionRetries; + } + + if (waitTime > maxWaitBetweenReconnectionRetries || waitTime == 0) { + waitTime = maxWaitBetweenReconnectionRetries; + } + + return waitTime; +} +} // namespace ix diff --git a/GermanAirlinesVA-GAConnector/ixwebsocket/IXGetFreePort.cpp b/GermanAirlinesVA-GAConnector/ixwebsocket/IXGetFreePort.cpp new file mode 100644 index 0000000..d5ac863 --- /dev/null +++ b/GermanAirlinesVA-GAConnector/ixwebsocket/IXGetFreePort.cpp @@ -0,0 +1,95 @@ +/* + * IXGetFreePort.cpp + * Author: Benjamin Sergeant + * Copyright (c) 2019 Machine Zone. All rights reserved. + */ + +// Using inet_addr will trigger an error on uwp without this +// FIXME: use a different api +#ifdef _WIN32 +#ifndef _WINSOCK_DEPRECATED_NO_WARNINGS +#define _WINSOCK_DEPRECATED_NO_WARNINGS +#endif +#endif + +#include "IXGetFreePort.h" + +#include "IXNetSystem.h" +#include "IXSocket.h" +#include +#include + +namespace ix +{ +int getAnyFreePortRandom() +{ + std::random_device rd; + std::uniform_int_distribution dist(1024 + 1, 65535); + + return dist(rd); +} + +int getAnyFreePort() +{ + socket_t sockfd; + if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) < 0) { + return getAnyFreePortRandom(); + } + + int enable = 1; + if (setsockopt(sockfd, + SOL_SOCKET, + SO_REUSEADDR, + (char *)&enable, + sizeof(enable)) < 0) { + return getAnyFreePortRandom(); + } + + // Bind to port 0. This is the standard way to get a free port. + struct sockaddr_in server; // server address information + server.sin_family = AF_INET; + server.sin_port = htons(0); + server.sin_addr.s_addr = inet_addr("127.0.0.1"); + + if (bind(sockfd, (struct sockaddr *)&server, sizeof(server)) < 0) { + Socket::closeSocket(sockfd); + return getAnyFreePortRandom(); + } + + struct sockaddr_in sa; // server address information + socklen_t len = sizeof(sa); + if (getsockname(sockfd, (struct sockaddr *)&sa, &len) < 0) { + Socket::closeSocket(sockfd); + return getAnyFreePortRandom(); + } + + int port = ntohs(sa.sin_port); + Socket::closeSocket(sockfd); + + return port; +} + +int getFreePort() +{ + while (true) { +#if defined(__has_feature) +#if __has_feature(address_sanitizer) + int port = getAnyFreePortRandom(); +#else + int port = getAnyFreePort(); +#endif +#else + int port = getAnyFreePort(); +#endif + // + // Only port above 1024 can be used by non root users, but for some + // reason I got port 7 returned with macOS when binding on port 0... + // + if (port > 1024) { + return port; + } + } + + return -1; +} +} // namespace ix diff --git a/GermanAirlinesVA-GAConnector/ixwebsocket/IXGzipCodec.cpp b/GermanAirlinesVA-GAConnector/ixwebsocket/IXGzipCodec.cpp new file mode 100644 index 0000000..82251f5 --- /dev/null +++ b/GermanAirlinesVA-GAConnector/ixwebsocket/IXGzipCodec.cpp @@ -0,0 +1,186 @@ +/* + * IXGzipCodec.cpp + * Author: Benjamin Sergeant + * Copyright (c) 2020 Machine Zone, Inc. All rights reserved. + */ + +#include "IXGzipCodec.h" + +#include "IXBench.h" +#include +#include + +#ifdef IXWEBSOCKET_USE_ZLIB +#include +#endif + +#ifdef IXWEBSOCKET_USE_DEFLATE +#include +#endif + +namespace ix +{ +std::string gzipCompress(const std::string &str) +{ +#ifndef IXWEBSOCKET_USE_ZLIB + return std::string(); +#else +#ifdef IXWEBSOCKET_USE_DEFLATE + int compressionLevel = 6; + struct libdeflate_compressor *compressor; + + compressor = libdeflate_alloc_compressor(compressionLevel); + + const void *uncompressed_data = str.data(); + size_t uncompressed_size = str.size(); + void *compressed_data; + size_t actual_compressed_size; + size_t max_compressed_size; + + max_compressed_size = + libdeflate_gzip_compress_bound(compressor, uncompressed_size); + compressed_data = malloc(max_compressed_size); + + if (compressed_data == NULL) { + return std::string(); + } + + actual_compressed_size = libdeflate_gzip_compress(compressor, + uncompressed_data, + uncompressed_size, + compressed_data, + max_compressed_size); + + libdeflate_free_compressor(compressor); + + if (actual_compressed_size == 0) { + free(compressed_data); + return std::string(); + } + + std::string out; + out.assign(reinterpret_cast(compressed_data), + actual_compressed_size); + free(compressed_data); + + return out; +#else + z_stream zs; // z_stream is zlib's control structure + memset(&zs, 0, sizeof(zs)); + + // deflateInit2 configure the file format: request gzip instead of deflate + const int windowBits = 15; + const int GZIP_ENCODING = 16; + + deflateInit2(&zs, + Z_DEFAULT_COMPRESSION, + Z_DEFLATED, + windowBits | GZIP_ENCODING, + 8, + Z_DEFAULT_STRATEGY); + + zs.next_in = (Bytef *)str.data(); + zs.avail_in = (uInt)str.size(); // set the z_stream's input + + int ret; + char outbuffer[32768]; + std::string outstring; + + // retrieve the compressed bytes blockwise + do { + zs.next_out = reinterpret_cast(outbuffer); + zs.avail_out = sizeof(outbuffer); + + ret = deflate(&zs, Z_FINISH); + + if (outstring.size() < zs.total_out) { + // append the block to the output string + outstring.append(outbuffer, zs.total_out - outstring.size()); + } + } while (ret == Z_OK); + + deflateEnd(&zs); + + return outstring; +#endif // IXWEBSOCKET_USE_DEFLATE +#endif // IXWEBSOCKET_USE_ZLIB +} + +#ifdef IXWEBSOCKET_USE_DEFLATE +static uint32_t loadDecompressedGzipSize(const uint8_t *p) +{ + return ((uint32_t)p[0] << 0) | ((uint32_t)p[1] << 8) | + ((uint32_t)p[2] << 16) | ((uint32_t)p[3] << 24); +} +#endif + +bool gzipDecompress(const std::string &in, std::string &out) +{ +#ifndef IXWEBSOCKET_USE_ZLIB + return false; +#else +#ifdef IXWEBSOCKET_USE_DEFLATE + struct libdeflate_decompressor *decompressor; + decompressor = libdeflate_alloc_decompressor(); + + const void *compressed_data = in.data(); + size_t compressed_size = in.size(); + + // Retrieve uncompressed size from the trailer of the gziped data + const uint8_t *ptr = reinterpret_cast(&in.front()); + auto uncompressed_size = + loadDecompressedGzipSize(&ptr[compressed_size - 4]); + + // Use it to redimension our output buffer + out.resize(uncompressed_size); + + libdeflate_result result = libdeflate_gzip_decompress(decompressor, + compressed_data, + compressed_size, + &out.front(), + uncompressed_size, + NULL); + + libdeflate_free_decompressor(decompressor); + return result == LIBDEFLATE_SUCCESS; +#else + z_stream inflateState; + memset(&inflateState, 0, sizeof(inflateState)); + + inflateState.zalloc = Z_NULL; + inflateState.zfree = Z_NULL; + inflateState.opaque = Z_NULL; + inflateState.avail_in = 0; + inflateState.next_in = Z_NULL; + + if (inflateInit2(&inflateState, 16 + MAX_WBITS) != Z_OK) { + return false; + } + + inflateState.avail_in = (uInt)in.size(); + inflateState.next_in = (unsigned char *)(const_cast(in.data())); + + const int kBufferSize = 1 << 14; + std::array compressBuffer; + + do { + inflateState.avail_out = (uInt)kBufferSize; + inflateState.next_out = &compressBuffer.front(); + + int ret = inflate(&inflateState, Z_SYNC_FLUSH); + + if (ret == Z_NEED_DICT || ret == Z_DATA_ERROR || ret == Z_MEM_ERROR) { + inflateEnd(&inflateState); + return false; + } + + out.append(reinterpret_cast(&compressBuffer.front()), + kBufferSize - inflateState.avail_out); + } while (inflateState.avail_out == 0); + + inflateEnd(&inflateState); + return true; +#endif // IXWEBSOCKET_USE_DEFLATE +#endif // IXWEBSOCKET_USE_ZLIB +} +} // namespace ix diff --git a/GermanAirlinesVA-GAConnector/ixwebsocket/IXHttp.cpp b/GermanAirlinesVA-GAConnector/ixwebsocket/IXHttp.cpp new file mode 100644 index 0000000..ac87598 --- /dev/null +++ b/GermanAirlinesVA-GAConnector/ixwebsocket/IXHttp.cpp @@ -0,0 +1,208 @@ +/* + * IXHttp.cpp + * Author: Benjamin Sergeant + * Copyright (c) 2019 Machine Zone, Inc. All rights reserved. + */ + +#include "IXHttp.h" + +#include "IXCancellationRequest.h" +#include "IXGzipCodec.h" +#include "IXSocket.h" +#include +#include + +namespace ix +{ +std::string Http::trim(const std::string &str) +{ + std::string out; + for (auto c : str) { + if (c != ' ' && c != '\n' && c != '\r') { + out += c; + } + } + + return out; +} + +std::pair Http::parseStatusLine(const std::string &line) +{ + // Request-Line = Method SP Request-URI SP HTTP-Version CRLF + std::string token; + std::stringstream tokenStream(line); + std::vector tokens; + + // Split by ' ' + while (std::getline(tokenStream, token, ' ')) { + tokens.push_back(token); + } + + std::string httpVersion; + if (tokens.size() >= 1) { + httpVersion = trim(tokens[0]); + } + + int statusCode = -1; + if (tokens.size() >= 2) { + std::stringstream ss; + ss << trim(tokens[1]); + ss >> statusCode; + } + + return std::make_pair(httpVersion, statusCode); +} + +std::tuple + Http::parseRequestLine(const std::string &line) +{ + // Request-Line = Method SP Request-URI SP HTTP-Version CRLF + std::string token; + std::stringstream tokenStream(line); + std::vector tokens; + + // Split by ' ' + while (std::getline(tokenStream, token, ' ')) { + tokens.push_back(token); + } + + std::string method; + if (tokens.size() >= 1) { + method = trim(tokens[0]); + } + + std::string requestUri; + if (tokens.size() >= 2) { + requestUri = trim(tokens[1]); + } + + std::string httpVersion; + if (tokens.size() >= 3) { + httpVersion = trim(tokens[2]); + } + + return std::make_tuple(method, requestUri, httpVersion); +} + +std::tuple + Http::parseRequest(std::unique_ptr &socket, int timeoutSecs) +{ + HttpRequestPtr httpRequest; + + std::atomic requestInitCancellation(false); + + auto isCancellationRequested = + makeCancellationRequestWithTimeout(timeoutSecs, + requestInitCancellation); + + // Read first line + auto lineResult = socket->readLine(isCancellationRequested); + auto lineValid = lineResult.first; + auto line = lineResult.second; + + if (!lineValid) { + return std::make_tuple(false, + "Error reading HTTP request line", + httpRequest); + } + + // Parse request line (GET /foo HTTP/1.1\r\n) + auto requestLine = Http::parseRequestLine(line); + auto method = std::get<0>(requestLine); + auto uri = std::get<1>(requestLine); + auto httpVersion = std::get<2>(requestLine); + + // Retrieve and validate HTTP headers + auto result = parseHttpHeaders(socket, isCancellationRequested); + auto headersValid = result.first; + auto headers = result.second; + + if (!headersValid) { + return std::make_tuple(false, + "Error parsing HTTP headers", + httpRequest); + } + + std::string body; + if (headers.find("Content-Length") != headers.end()) { + int contentLength = 0; + try { + contentLength = std::stoi(headers["Content-Length"]); + } catch (const std::exception &) { + return std::make_tuple(false, + "Error parsing HTTP Header 'Content-Length'", + httpRequest); + } + + if (contentLength < 0) { + return std::make_tuple( + false, + "Error: 'Content-Length' should be a positive integer", + httpRequest); + } + + auto res = + socket->readBytes(contentLength, nullptr, isCancellationRequested); + if (!res.first) { + return std::make_tuple(false, + std::string("Error reading request: ") + + res.second, + httpRequest); + } + body = res.second; + } + + // If the content was compressed with gzip, decode it + if (headers["Content-Encoding"] == "gzip") { +#ifdef IXWEBSOCKET_USE_ZLIB + std::string decompressedPayload; + if (!gzipDecompress(body, decompressedPayload)) { + return std::make_tuple( + false, + std::string("Error during gzip decompression of the body"), + httpRequest); + } + body = decompressedPayload; +#else + std::string errorMsg( + "ixwebsocket was not compiled with gzip support on"); + return std::make_tuple(false, errorMsg, httpRequest); +#endif + } + + httpRequest = + std::make_shared(uri, method, httpVersion, body, headers); + return std::make_tuple(true, "", httpRequest); +} + +bool Http::sendResponse(HttpResponsePtr response, + std::unique_ptr &socket) +{ + // Write the response to the socket + std::stringstream ss; + ss << "HTTP/1.1 "; + ss << response->statusCode; + ss << " "; + ss << response->description; + ss << "\r\n"; + + if (!socket->writeBytes(ss.str(), nullptr)) { + return false; + } + + // Write headers + ss.str(""); + ss << "Content-Length: " << response->body.size() << "\r\n"; + for (auto &&it : response->headers) { + ss << it.first << ": " << it.second << "\r\n"; + } + ss << "\r\n"; + + if (!socket->writeBytes(ss.str(), nullptr)) { + return false; + } + + return response->body.empty() ? true + : socket->writeBytes(response->body, nullptr); +} +} // namespace ix diff --git a/GermanAirlinesVA-GAConnector/ixwebsocket/IXHttpClient.cpp b/GermanAirlinesVA-GAConnector/ixwebsocket/IXHttpClient.cpp new file mode 100644 index 0000000..7deb3d7 --- /dev/null +++ b/GermanAirlinesVA-GAConnector/ixwebsocket/IXHttpClient.cpp @@ -0,0 +1,724 @@ +/* + * IXHttpClient.cpp + * Author: Benjamin Sergeant + * Copyright (c) 2019 Machine Zone, Inc. All rights reserved. + */ + +#include "IXHttpClient.h" + +#include "IXGzipCodec.h" +#include "IXSocketFactory.h" +#include "IXUrlParser.h" +#include "IXUserAgent.h" +#include "IXWebSocketHttpHeaders.h" +#include +#include +#include +#include +#include +#include + +namespace ix +{ +// https://developer.mozilla.org/en-US/docs/Web/HTTP/Methods +const std::string HttpClient::kPost = "POST"; +const std::string HttpClient::kGet = "GET"; +const std::string HttpClient::kHead = "HEAD"; +const std::string HttpClient::kDelete = "DELETE"; +const std::string HttpClient::kPut = "PUT"; +const std::string HttpClient::kPatch = "PATCH"; + +HttpClient::HttpClient(bool async) + : _async(async), _stop(false), _forceBody(false) +{ + if (!_async) + return; + + _thread = std::thread(&HttpClient::run, this); +} + +HttpClient::~HttpClient() +{ + if (!_thread.joinable()) + return; + + _stop = true; + _condition.notify_one(); + _thread.join(); +} + +void HttpClient::setTLSOptions(const SocketTLSOptions &tlsOptions) +{ + _tlsOptions = tlsOptions; +} + +void HttpClient::setForceBody(bool value) { _forceBody = value; } + +HttpRequestArgsPtr HttpClient::createRequest(const std::string &url, + const std::string &verb) +{ + auto request = std::make_shared(); + request->url = url; + request->verb = verb; + return request; +} + +bool HttpClient::performRequest(HttpRequestArgsPtr args, + const OnResponseCallback &onResponseCallback) +{ + assert(_async && "HttpClient needs its async parameter set to true " + "in order to call performRequest"); + if (!_async) + return false; + + // Enqueue the task + { + // acquire lock + std::unique_lock lock(_queueMutex); + + // add the task + _queue.push(std::make_pair(args, onResponseCallback)); + } // release lock + + // wake up one thread + _condition.notify_one(); + + return true; +} + +void HttpClient::run() +{ + while (true) { + HttpRequestArgsPtr args; + OnResponseCallback onResponseCallback; + + { + std::unique_lock lock(_queueMutex); + + while (!_stop && _queue.empty()) { + _condition.wait(lock); + } + + if (_stop) + return; + + auto p = _queue.front(); + _queue.pop(); + + args = p.first; + onResponseCallback = p.second; + } + + if (_stop) + return; + + HttpResponsePtr response = + request(args->url, args->verb, args->body, args); + onResponseCallback(response); + + if (_stop) + return; + } +} + +HttpResponsePtr HttpClient::request(const std::string &url, + const std::string &verb, + const std::string &body, + HttpRequestArgsPtr args, + int redirects) +{ + // We only have one socket connection, so we cannot + // make multiple requests concurrently. + std::lock_guard lock(_mutex); + + uint64_t uploadSize = 0; + uint64_t downloadSize = 0; + int code = 0; + WebSocketHttpHeaders headers; + std::string payload; + std::string description; + + std::string protocol, host, path, query; + int port; + + if (!UrlParser::parse(url, protocol, host, path, query, port)) { + std::stringstream ss; + ss << "Cannot parse url: " << url; + return std::make_shared(code, + description, + HttpErrorCode::UrlMalformed, + headers, + payload, + ss.str(), + uploadSize, + downloadSize); + } + + bool tls = protocol == "https"; + std::string errorMsg; + _socket = createSocket(tls, -1, errorMsg, _tlsOptions); + + if (!_socket) { + return std::make_shared(code, + description, + HttpErrorCode::CannotCreateSocket, + headers, + payload, + errorMsg, + uploadSize, + downloadSize); + } + + // Build request string + std::stringstream ss; + ss << verb << " " << path << " HTTP/1.1\r\n"; + ss << "Host: " << host << "\r\n"; + +#ifdef IXWEBSOCKET_USE_ZLIB + if (args->compress) { + ss << "Accept-Encoding: gzip" + << "\r\n"; + } +#endif + + // Append extra headers + for (auto &&it : args->extraHeaders) { + ss << it.first << ": " << it.second << "\r\n"; + } + + // Set a default Accept header if none is present + if (args->extraHeaders.find("Accept") == args->extraHeaders.end()) { + ss << "Accept: */*" + << "\r\n"; + } + + // Set a default User agent if none is present + if (args->extraHeaders.find("User-Agent") == args->extraHeaders.end()) { + ss << "User-Agent: " << userAgent() << "\r\n"; + } + + if (verb == kPost || verb == kPut || verb == kPatch || _forceBody) { + // Set request compression header +#ifdef IXWEBSOCKET_USE_ZLIB + if (args->compressRequest) { + ss << "Content-Encoding: gzip" + << "\r\n"; + } +#endif + + ss << "Content-Length: " << body.size() << "\r\n"; + + // Set default Content-Type if unspecified + if (args->extraHeaders.find("Content-Type") == + args->extraHeaders.end()) { + if (args->multipartBoundary.empty()) { + ss << "Content-Type: application/x-www-form-urlencoded" + << "\r\n"; + } else { + ss << "Content-Type: multipart/form-data; boundary=" + << args->multipartBoundary << "\r\n"; + } + } + ss << "\r\n"; + ss << body; + } else { + ss << "\r\n"; + } + + std::string req(ss.str()); + std::string errMsg; + + // Make a cancellation object dealing with connection timeout + auto isCancellationRequested = + makeCancellationRequestWithTimeout(args->connectTimeout, _stop); + + bool success = + _socket->connect(host, port, errMsg, isCancellationRequested); + if (!success) { + std::stringstream ss; + ss << "Cannot connect to url: " << url << " / error : " << errMsg; + return std::make_shared(code, + description, + HttpErrorCode::CannotConnect, + headers, + payload, + ss.str(), + uploadSize, + downloadSize); + } + + // Make a new cancellation object dealing with transfer timeout + isCancellationRequested = + makeCancellationRequestWithTimeout(args->transferTimeout, _stop); + + if (args->verbose) { + std::stringstream ss; + ss << "Sending " << verb << " request " + << "to " << host << ":" << port << std::endl + << "request size: " << req.size() << " bytes" << std::endl + << "=============" << std::endl + << req << "=============" << std::endl + << std::endl; + + log(ss.str(), args); + } + + if (!_socket->writeBytes(req, isCancellationRequested)) { + std::string errorMsg("Cannot send request"); + return std::make_shared(code, + description, + HttpErrorCode::SendError, + headers, + payload, + errorMsg, + uploadSize, + downloadSize); + } + + uploadSize = req.size(); + + auto lineResult = _socket->readLine(isCancellationRequested); + auto lineValid = lineResult.first; + auto line = lineResult.second; + + if (!lineValid) { + std::string errorMsg("Cannot retrieve status line"); + return std::make_shared( + code, + description, + HttpErrorCode::CannotReadStatusLine, + headers, + payload, + errorMsg, + uploadSize, + downloadSize); + } + + if (args->verbose) { + std::stringstream ss; + ss << "Status line " << line; + log(ss.str(), args); + } + + if (sscanf(line.c_str(), "HTTP/1.1 %d", &code) != 1) { + std::string errorMsg("Cannot parse response code from status line"); + return std::make_shared(code, + description, + HttpErrorCode::MissingStatus, + headers, + payload, + errorMsg, + uploadSize, + downloadSize); + } + + auto result = parseHttpHeaders(_socket, isCancellationRequested); + auto headersValid = result.first; + headers = result.second; + + if (!headersValid) { + std::string errorMsg("Cannot parse http headers"); + return std::make_shared(code, + description, + HttpErrorCode::HeaderParsingError, + headers, + payload, + errorMsg, + uploadSize, + downloadSize); + } + + // Redirect ? + if ((code >= 301 && code <= 308) && args->followRedirects) { + if (headers.find("Location") == headers.end()) { + std::string errorMsg("Missing location header for redirect"); + return std::make_shared( + code, + description, + HttpErrorCode::MissingLocation, + headers, + payload, + errorMsg, + uploadSize, + downloadSize); + } + + if (redirects >= args->maxRedirects) { + std::stringstream ss; + ss << "Too many redirects: " << redirects; + return std::make_shared( + code, + description, + HttpErrorCode::TooManyRedirects, + headers, + payload, + ss.str(), + uploadSize, + downloadSize); + } + + // Recurse + std::string location = headers["Location"]; + return request(location, verb, body, args, redirects + 1); + } + + if (verb == "HEAD") { + return std::make_shared(code, + description, + HttpErrorCode::Ok, + headers, + payload, + std::string(), + uploadSize, + downloadSize); + } + + // Parse response: + if (headers.find("Content-Length") != headers.end()) { + ssize_t contentLength = -1; + ss.str(""); + ss << headers["Content-Length"]; + ss >> contentLength; + + payload.reserve(contentLength); + + auto chunkResult = _socket->readBytes(contentLength, + args->onProgressCallback, + isCancellationRequested); + if (!chunkResult.first) { + errorMsg = "Cannot read chunk"; + return std::make_shared(code, + description, + HttpErrorCode::ChunkReadError, + headers, + payload, + errorMsg, + uploadSize, + downloadSize); + } + payload += chunkResult.second; + } else if (headers.find("Transfer-Encoding") != headers.end() && + headers["Transfer-Encoding"] == "chunked") { + std::stringstream ss; + + while (true) { + lineResult = _socket->readLine(isCancellationRequested); + line = lineResult.second; + + if (!lineResult.first) { + return std::make_shared( + code, + description, + HttpErrorCode::ChunkReadError, + headers, + payload, + errorMsg, + uploadSize, + downloadSize); + } + + uint64_t chunkSize; + ss.str(""); + ss << std::hex << line; + ss >> chunkSize; + + if (args->verbose) { + std::stringstream oss; + oss << "Reading " << chunkSize << " bytes" << std::endl; + log(oss.str(), args); + } + + payload.reserve(payload.size() + (size_t)chunkSize); + + // Read a chunk + auto chunkResult = _socket->readBytes((size_t)chunkSize, + args->onProgressCallback, + isCancellationRequested); + if (!chunkResult.first) { + errorMsg = "Cannot read chunk"; + return std::make_shared( + code, + description, + HttpErrorCode::ChunkReadError, + headers, + payload, + errorMsg, + uploadSize, + downloadSize); + } + payload += chunkResult.second; + + // Read the line that terminates the chunk (\r\n) + lineResult = _socket->readLine(isCancellationRequested); + + if (!lineResult.first) { + return std::make_shared( + code, + description, + HttpErrorCode::ChunkReadError, + headers, + payload, + errorMsg, + uploadSize, + downloadSize); + } + + if (chunkSize == 0) + break; + } + } else if (code == 204) { + ; // 204 is NoContent response code + } else { + std::string errorMsg("Cannot read http body"); + return std::make_shared(code, + description, + HttpErrorCode::CannotReadBody, + headers, + payload, + errorMsg, + uploadSize, + downloadSize); + } + + downloadSize = payload.size(); + + // If the content was compressed with gzip, decode it + if (headers["Content-Encoding"] == "gzip") { +#ifdef IXWEBSOCKET_USE_ZLIB + std::string decompressedPayload; + if (!gzipDecompress(payload, decompressedPayload)) { + std::string errorMsg("Error decompressing payload"); + return std::make_shared(code, + description, + HttpErrorCode::Gzip, + headers, + payload, + errorMsg, + uploadSize, + downloadSize); + } + payload = decompressedPayload; +#else + std::string errorMsg( + "ixwebsocket was not compiled with gzip support on"); + return std::make_shared(code, + description, + HttpErrorCode::Gzip, + headers, + payload, + errorMsg, + uploadSize, + downloadSize); +#endif + } + + return std::make_shared(code, + description, + HttpErrorCode::Ok, + headers, + payload, + std::string(), + uploadSize, + downloadSize); +} + +HttpResponsePtr HttpClient::get(const std::string &url, HttpRequestArgsPtr args) +{ + return request(url, kGet, std::string(), args); +} + +HttpResponsePtr HttpClient::head(const std::string &url, + HttpRequestArgsPtr args) +{ + return request(url, kHead, std::string(), args); +} + +HttpResponsePtr HttpClient::Delete(const std::string &url, + HttpRequestArgsPtr args) +{ + return request(url, kDelete, std::string(), args); +} + +HttpResponsePtr + HttpClient::request(const std::string &url, + const std::string &verb, + const HttpParameters &httpParameters, + const HttpFormDataParameters &httpFormDataParameters, + HttpRequestArgsPtr args) +{ + std::string body; + + if (httpFormDataParameters.empty()) { + body = serializeHttpParameters(httpParameters); + } else { + std::string multipartBoundary = generateMultipartBoundary(); + args->multipartBoundary = multipartBoundary; + body = serializeHttpFormDataParameters(multipartBoundary, + httpFormDataParameters, + httpParameters); + } + +#ifdef IXWEBSOCKET_USE_ZLIB + if (args->compressRequest) { + body = gzipCompress(body); + } +#endif + + return request(url, verb, body, args); +} + +HttpResponsePtr + HttpClient::post(const std::string &url, + const HttpParameters &httpParameters, + const HttpFormDataParameters &httpFormDataParameters, + HttpRequestArgsPtr args) +{ + return request(url, kPost, httpParameters, httpFormDataParameters, args); +} + +HttpResponsePtr HttpClient::post(const std::string &url, + const std::string &body, + HttpRequestArgsPtr args) +{ + return request(url, kPost, body, args); +} + +HttpResponsePtr + HttpClient::put(const std::string &url, + const HttpParameters &httpParameters, + const HttpFormDataParameters &httpFormDataParameters, + HttpRequestArgsPtr args) +{ + return request(url, kPut, httpParameters, httpFormDataParameters, args); +} + +HttpResponsePtr HttpClient::put(const std::string &url, + const std::string &body, + const HttpRequestArgsPtr args) +{ + return request(url, kPut, body, args); +} + +HttpResponsePtr + HttpClient::patch(const std::string &url, + const HttpParameters &httpParameters, + const HttpFormDataParameters &httpFormDataParameters, + HttpRequestArgsPtr args) +{ + return request(url, kPatch, httpParameters, httpFormDataParameters, args); +} + +HttpResponsePtr HttpClient::patch(const std::string &url, + const std::string &body, + const HttpRequestArgsPtr args) +{ + return request(url, kPatch, body, args); +} + +std::string HttpClient::urlEncode(const std::string &value) +{ + std::ostringstream escaped; + escaped.fill('0'); + escaped << std::hex; + + for (std::string::const_iterator i = value.begin(), n = value.end(); i != n; + ++i) { + std::string::value_type c = (*i); + + // Keep alphanumeric and other accepted characters intact + if (isalnum(c) || c == '-' || c == '_' || c == '.' || c == '~') { + escaped << c; + continue; + } + + // Any other characters are percent-encoded + escaped << std::uppercase; + escaped << '%' << std::setw(2) << int((unsigned char)c); + escaped << std::nouppercase; + } + + return escaped.str(); +} + +std::string + HttpClient::serializeHttpParameters(const HttpParameters &httpParameters) +{ + std::stringstream ss; + size_t count = httpParameters.size(); + size_t i = 0; + + for (auto &&it : httpParameters) { + ss << urlEncode(it.first) << "=" << urlEncode(it.second); + + if (i++ < (count - 1)) { + ss << "&"; + } + } + return ss.str(); +} + +std::string HttpClient::serializeHttpFormDataParameters( + const std::string &multipartBoundary, + const HttpFormDataParameters &httpFormDataParameters, + const HttpParameters &httpParameters) +{ + // + // --AaB03x + // Content-Disposition: form-data; name="submit-name" + + // Larry + // --AaB03x + // Content-Disposition: form-data; name="foo.txt"; filename="file1.txt" + // Content-Type: text/plain + + // ... contents of file1.txt ... + // --AaB03x-- + // + std::stringstream ss; + + for (auto &&it : httpFormDataParameters) { + ss << "--" << multipartBoundary << "\r\n" + << "Content-Disposition:" + << " form-data; name=\"" << it.first << "\";" + << " filename=\"" << it.first << "\"" + << "\r\n" + << "Content-Type: application/octet-stream" + << "\r\n" + << "\r\n" + << it.second << "\r\n"; + } + + for (auto &&it : httpParameters) { + ss << "--" << multipartBoundary << "\r\n" + << "Content-Disposition:" + << " form-data; name=\"" << it.first << "\";" + << "\r\n" + << "\r\n" + << it.second << "\r\n"; + } + + ss << "--" << multipartBoundary << "--\r\n"; + + return ss.str(); +} + +void HttpClient::log(const std::string &msg, HttpRequestArgsPtr args) +{ + if (args->logger) { + args->logger(msg); + } +} + +std::string HttpClient::generateMultipartBoundary() +{ + std::string str( + "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"); + + static std::random_device rd; + static std::mt19937 generator(rd()); + + std::shuffle(str.begin(), str.end(), generator); + + return str; +} +} // namespace ix diff --git a/GermanAirlinesVA-GAConnector/ixwebsocket/IXHttpServer.cpp b/GermanAirlinesVA-GAConnector/ixwebsocket/IXHttpServer.cpp new file mode 100644 index 0000000..743394c --- /dev/null +++ b/GermanAirlinesVA-GAConnector/ixwebsocket/IXHttpServer.cpp @@ -0,0 +1,239 @@ +/* + * IXHttpServer.cpp + * Author: Benjamin Sergeant + * Copyright (c) 2019 Machine Zone, Inc. All rights reserved. + */ + +#include "IXHttpServer.h" + +#include "IXGzipCodec.h" +#include "IXNetSystem.h" +#include "IXSocketConnect.h" +#include "IXUserAgent.h" +#include +#include +#include +#include + +namespace +{ +std::pair> load(const std::string &path) +{ + std::vector memblock; + + std::ifstream file(path); + if (!file.is_open()) + return std::make_pair(false, memblock); + + file.seekg(0, file.end); + std::streamoff size = file.tellg(); + file.seekg(0, file.beg); + + memblock.resize((size_t)size); + file.read((char *)&memblock.front(), static_cast(size)); + + return std::make_pair(true, memblock); +} + +std::pair readAsString(const std::string &path) +{ + auto res = load(path); + auto vec = res.second; + return std::make_pair(res.first, std::string(vec.begin(), vec.end())); +} +} // namespace + +namespace ix +{ +const int HttpServer::kDefaultTimeoutSecs(30); + +HttpServer::HttpServer(int port, + const std::string &host, + int backlog, + size_t maxConnections, + int addressFamily, + int timeoutSecs) + : SocketServer(port, host, backlog, maxConnections, addressFamily), + _connectedClientsCount(0), _timeoutSecs(timeoutSecs) +{ + setDefaultConnectionCallback(); +} + +HttpServer::~HttpServer() { stop(); } + +void HttpServer::stop() +{ + stopAcceptingConnections(); + + // FIXME: cancelling / closing active clients ... + + SocketServer::stop(); +} + +void HttpServer::setOnConnectionCallback(const OnConnectionCallback &callback) +{ + _onConnectionCallback = callback; +} + +void HttpServer::handleConnection( + std::unique_ptr socket, + std::shared_ptr connectionState) +{ + _connectedClientsCount++; + + auto ret = Http::parseRequest(socket, _timeoutSecs); + // FIXME: handle errors in parseRequest + + if (std::get<0>(ret)) { + auto response = + _onConnectionCallback(std::get<2>(ret), connectionState); + if (!Http::sendResponse(response, socket)) { + logError("Cannot send response"); + } + } + connectionState->setTerminated(); + + _connectedClientsCount--; +} + +size_t HttpServer::getConnectedClientsCount() { return _connectedClientsCount; } + +void HttpServer::setDefaultConnectionCallback() +{ + setOnConnectionCallback( + [this](HttpRequestPtr request, + std::shared_ptr connectionState) + -> HttpResponsePtr { + std::string uri(request->uri); + if (uri.empty() || uri == "/") { + uri = "/index.html"; + } + + WebSocketHttpHeaders headers; + headers["Server"] = userAgent(); + + std::string path("." + uri); + auto res = readAsString(path); + bool found = res.first; + if (!found) { + return std::make_shared(404, + "Not Found", + HttpErrorCode::Ok, + WebSocketHttpHeaders(), + std::string()); + } + + std::string content = res.second; + +#ifdef IXWEBSOCKET_USE_ZLIB + std::string acceptEncoding = request->headers["Accept-encoding"]; + if (acceptEncoding == "*" || + acceptEncoding.find("gzip") != std::string::npos) { + content = gzipCompress(content); + headers["Content-Encoding"] = "gzip"; + } +#endif + + // Log request + std::stringstream ss; + ss << connectionState->getRemoteIp() << ":" + << connectionState->getRemotePort() << " " << request->method + << " " << request->headers["User-Agent"] << " " << request->uri + << " " << content.size(); + logInfo(ss.str()); + + // FIXME: check extensions to set the content type + // headers["Content-Type"] = "application/octet-stream"; + headers["Accept-Ranges"] = "none"; + + for (auto &&it : request->headers) { + headers[it.first] = it.second; + } + + return std::make_shared(200, + "OK", + HttpErrorCode::Ok, + headers, + content); + }); +} + +void HttpServer::makeRedirectServer(const std::string &redirectUrl) +{ + // + // See https://developer.mozilla.org/en-US/docs/Web/HTTP/Redirections + // + setOnConnectionCallback( + [this, redirectUrl](HttpRequestPtr request, + std::shared_ptr connectionState) + -> HttpResponsePtr { + WebSocketHttpHeaders headers; + headers["Server"] = userAgent(); + + // Log request + std::stringstream ss; + ss << connectionState->getRemoteIp() << ":" + << connectionState->getRemotePort() << " " << request->method + << " " << request->headers["User-Agent"] << " " << request->uri; + logInfo(ss.str()); + + if (request->method == "POST") { + return std::make_shared(200, + "OK", + HttpErrorCode::Ok, + headers, + std::string()); + } + + headers["Location"] = redirectUrl; + + return std::make_shared(301, + "OK", + HttpErrorCode::Ok, + headers, + std::string()); + }); +} + +// +// Display the client parameter and body on the console +// +void HttpServer::makeDebugServer() +{ + setOnConnectionCallback( + [this](HttpRequestPtr request, + std::shared_ptr connectionState) + -> HttpResponsePtr { + WebSocketHttpHeaders headers; + headers["Server"] = userAgent(); + + // Log request + std::stringstream ss; + ss << connectionState->getRemoteIp() << ":" + << connectionState->getRemotePort() << " " << request->method + << " " << request->headers["User-Agent"] << " " << request->uri; + logInfo(ss.str()); + + logInfo("== Headers == "); + for (auto &&it : request->headers) { + std::ostringstream oss; + oss << it.first << ": " << it.second; + logInfo(oss.str()); + } + logInfo(""); + + logInfo("== Body == "); + logInfo(request->body); + logInfo(""); + + return std::make_shared(200, + "OK", + HttpErrorCode::Ok, + headers, + std::string("OK")); + }); +} + +int HttpServer::getTimeoutSecs() { return _timeoutSecs; } + +} // namespace ix diff --git a/GermanAirlinesVA-GAConnector/ixwebsocket/IXNetSystem.cpp b/GermanAirlinesVA-GAConnector/ixwebsocket/IXNetSystem.cpp new file mode 100644 index 0000000..ea5b105 --- /dev/null +++ b/GermanAirlinesVA-GAConnector/ixwebsocket/IXNetSystem.cpp @@ -0,0 +1,296 @@ +/* + * IXNetSystem.cpp + * Author: Korchynskyi Dmytro + * Copyright (c) 2019 Machine Zone. All rights reserved. + */ + +#include "IXNetSystem.h" +#include +#include + +namespace ix +{ +bool initNetSystem() +{ +#ifdef _WIN32 + WORD wVersionRequested; + WSADATA wsaData; + int err; + + // Use the MAKEWORD(lowbyte, highbyte) macro declared in Windef.h + wVersionRequested = MAKEWORD(2, 2); + err = WSAStartup(wVersionRequested, &wsaData); + + return err == 0; +#else + return true; +#endif +} + +bool uninitNetSystem() +{ +#ifdef _WIN32 + int err = WSACleanup(); + return err == 0; +#else + return true; +#endif +} + +// +// That function could 'return WSAPoll(pfd, nfds, timeout);' +// but WSAPoll is said to have weird behaviors on the internet +// (the curl folks have had problems with it). +// +// So we make it a select wrapper +// +int poll(struct pollfd *fds, nfds_t nfds, int timeout) +{ +#ifdef _WIN32 + socket_t maxfd = 0; + fd_set readfds, writefds, errorfds; + FD_ZERO(&readfds); + FD_ZERO(&writefds); + FD_ZERO(&errorfds); + + for (nfds_t i = 0; i < nfds; ++i) { + struct pollfd *fd = &fds[i]; + + if (fd->fd > maxfd) { + maxfd = fd->fd; + } + if ((fd->events & POLLIN)) { + FD_SET(fd->fd, &readfds); + } + if ((fd->events & POLLOUT)) { + FD_SET(fd->fd, &writefds); + } + if ((fd->events & POLLERR)) { + FD_SET(fd->fd, &errorfds); + } + } + + struct timeval tv; + tv.tv_sec = timeout / 1000; + tv.tv_usec = (timeout % 1000) * 1000; + + int ret = select(maxfd + 1, + &readfds, + &writefds, + &errorfds, + timeout != -1 ? &tv : NULL); + + if (ret < 0) { + return ret; + } + + for (nfds_t i = 0; i < nfds; ++i) { + struct pollfd *fd = &fds[i]; + fd->revents = 0; + + if (FD_ISSET(fd->fd, &readfds)) { + fd->revents |= POLLIN; + } + if (FD_ISSET(fd->fd, &writefds)) { + fd->revents |= POLLOUT; + } + if (FD_ISSET(fd->fd, &errorfds)) { + fd->revents |= POLLERR; + } + } + + return ret; +#else + // + // It was reported that on Android poll can fail and return -1 with + // errno == EINTR, which should be a temp error and should typically + // be handled by retrying in a loop. + // Maybe we need to put all syscall / C functions in + // a new IXSysCalls.cpp and wrap them all. + // + // The style from libuv is as such. + // + int ret = -1; + do { + ret = ::poll(fds, nfds, timeout); + } while (ret == -1 && errno == EINTR); + + return ret; +#endif +} + +// +// mingw does not have inet_ntop, which were taken as is from the musl C +// library. +// +const char *inet_ntop(int af, const void *a0, char *s, socklen_t l) +{ +#if defined(_WIN32) && defined(__GNUC__) + const unsigned char *a = (const unsigned char *)a0; + int i, j, max, best; + char buf[100]; + + switch (af) { + case AF_INET: + if (snprintf(s, l, "%d.%d.%d.%d", a[0], a[1], a[2], a[3]) < l) + return s; + break; + case AF_INET6: + if (memcmp(a, "\0\0\0\0\0\0\0\0\0\0\377\377", 12)) + snprintf(buf, + sizeof buf, + "%x:%x:%x:%x:%x:%x:%x:%x", + 256 * a[0] + a[1], + 256 * a[2] + a[3], + 256 * a[4] + a[5], + 256 * a[6] + a[7], + 256 * a[8] + a[9], + 256 * a[10] + a[11], + 256 * a[12] + a[13], + 256 * a[14] + a[15]); + else + snprintf(buf, + sizeof buf, + "%x:%x:%x:%x:%x:%x:%d.%d.%d.%d", + 256 * a[0] + a[1], + 256 * a[2] + a[3], + 256 * a[4] + a[5], + 256 * a[6] + a[7], + 256 * a[8] + a[9], + 256 * a[10] + a[11], + a[12], + a[13], + a[14], + a[15]); + /* Replace longest /(^0|:)[:0]{2,}/ with "::" */ + for (i = best = 0, max = 2; buf[i]; i++) { + if (i && buf[i] != ':') + continue; + j = strspn(buf + i, ":0"); + if (j > max) + best = i, max = j; + } + if (max > 3) { + buf[best] = buf[best + 1] = ':'; + memmove(buf + best + 2, buf + best + max, i - best - max + 1); + } + if (strlen(buf) < l) { + strcpy(s, buf); + return s; + } + break; + default: + errno = EAFNOSUPPORT; + return 0; + } + errno = ENOSPC; + return 0; +#else + return ::inet_ntop(af, a0, s, l); +#endif +} + +#if defined(_WIN32) && defined(__GNUC__) +static int hexval(unsigned c) +{ + if (c - '0' < 10) + return c - '0'; + c |= 32; + if (c - 'a' < 6) + return c - 'a' + 10; + return -1; +} +#endif + +// +// mingw does not have inet_pton, which were taken as is from the musl C +// library. +// +int inet_pton(int af, const char *s, void *a0) +{ +#if defined(_WIN32) && defined(__GNUC__) + uint16_t ip[8]; + unsigned char *a = (unsigned char *)a0; + int i, j, v, d, brk = -1, need_v4 = 0; + + if (af == AF_INET) { + for (i = 0; i < 4; i++) { + for (v = j = 0; j < 3 && isdigit(s[j]); j++) + v = 10 * v + s[j] - '0'; + if (j == 0 || (j > 1 && s[0] == '0') || v > 255) + return 0; + a[i] = v; + if (s[j] == 0 && i == 3) + return 1; + if (s[j] != '.') + return 0; + s += j + 1; + } + return 0; + } else if (af != AF_INET6) { + errno = EAFNOSUPPORT; + return -1; + } + + if (*s == ':' && *++s != ':') + return 0; + + for (i = 0;; i++) { + if (s[0] == ':' && brk < 0) { + brk = i; + ip[i & 7] = 0; + if (!*++s) + break; + if (i == 7) + return 0; + continue; + } + for (v = j = 0; j < 4 && (d = hexval(s[j])) >= 0; j++) + v = 16 * v + d; + if (j == 0) + return 0; + ip[i & 7] = v; + if (!s[j] && (brk >= 0 || i == 7)) + break; + if (i == 7) + return 0; + if (s[j] != ':') { + if (s[j] != '.' || (i < 6 && brk < 0)) + return 0; + need_v4 = 1; + i++; + break; + } + s += j + 1; + } + if (brk >= 0) { + memmove(ip + brk + 7 - i, ip + brk, 2 * (i + 1 - brk)); + for (j = 0; j < 7 - i; j++) + ip[brk + j] = 0; + } + for (j = 0; j < 8; j++) { + *a++ = ip[j] >> 8; + *a++ = ip[j]; + } + if (need_v4 && inet_pton(AF_INET, (const char *)s, a - 4) <= 0) + return 0; + return 1; +#else + return ::inet_pton(af, s, a0); +#endif +} + +// Convert network bytes to host bytes. Copied from the ASIO library +unsigned short network_to_host_short(unsigned short value) +{ +#if defined(_WIN32) + unsigned char *value_p = reinterpret_cast(&value); + unsigned short result = (static_cast(value_p[0]) << 8) | + static_cast(value_p[1]); + return result; +#else // defined(_WIN32) + return ntohs(value); +#endif // defined(_WIN32) +} + +} // namespace ix diff --git a/GermanAirlinesVA-GAConnector/ixwebsocket/IXSelectInterrupt.cpp b/GermanAirlinesVA-GAConnector/ixwebsocket/IXSelectInterrupt.cpp new file mode 100644 index 0000000..f29a837 --- /dev/null +++ b/GermanAirlinesVA-GAConnector/ixwebsocket/IXSelectInterrupt.cpp @@ -0,0 +1,27 @@ +/* + * IXSelectInterrupt.cpp + * Author: Benjamin Sergeant + * Copyright (c) 2019 Machine Zone, Inc. All rights reserved. + */ + +#include "IXSelectInterrupt.h" + +namespace ix +{ +const uint64_t SelectInterrupt::kSendRequest = 1; +const uint64_t SelectInterrupt::kCloseRequest = 2; + +SelectInterrupt::SelectInterrupt() { ; } + +SelectInterrupt::~SelectInterrupt() { ; } + +bool SelectInterrupt::init(std::string & /*errorMsg*/) { return true; } + +bool SelectInterrupt::notify(uint64_t /*value*/) { return true; } + +uint64_t SelectInterrupt::read() { return 0; } + +bool SelectInterrupt::clear() { return true; } + +int SelectInterrupt::getFd() const { return -1; } +} // namespace ix diff --git a/GermanAirlinesVA-GAConnector/ixwebsocket/IXSelectInterruptFactory.cpp b/GermanAirlinesVA-GAConnector/ixwebsocket/IXSelectInterruptFactory.cpp new file mode 100644 index 0000000..9ab6347 --- /dev/null +++ b/GermanAirlinesVA-GAConnector/ixwebsocket/IXSelectInterruptFactory.cpp @@ -0,0 +1,26 @@ +/* + * IXSelectInterruptFactory.cpp + * Author: Benjamin Sergeant + * Copyright (c) 2019 Machine Zone, Inc. All rights reserved. + */ + +#include "IXSelectInterruptFactory.h" + +#include "IXUniquePtr.h" +#if defined(__linux__) || defined(__APPLE__) +#include "IXSelectInterruptPipe.h" +#else +#include "IXSelectInterrupt.h" +#endif + +namespace ix +{ +SelectInterruptPtr createSelectInterrupt() +{ +#if defined(__linux__) || defined(__APPLE__) + return ix::make_unique(); +#else + return ix::make_unique(); +#endif +} +} // namespace ix diff --git a/GermanAirlinesVA-GAConnector/ixwebsocket/IXSelectInterruptPipe.cpp b/GermanAirlinesVA-GAConnector/ixwebsocket/IXSelectInterruptPipe.cpp new file mode 100644 index 0000000..def317f --- /dev/null +++ b/GermanAirlinesVA-GAConnector/ixwebsocket/IXSelectInterruptPipe.cpp @@ -0,0 +1,156 @@ +/* + * IXSelectInterruptPipe.cpp + * Author: Benjamin Sergeant + * Copyright (c) 2018-2019 Machine Zone, Inc. All rights reserved. + */ + +// +// On UNIX we use pipes to wake up select. There is no way to do that +// on Windows so this file is compiled out on Windows. +// +#ifndef _WIN32 + +#include "IXSelectInterruptPipe.h" + +#include +#include +#include +#include +#include // for strerror +#include // for write + +namespace ix +{ +// File descriptor at index 0 in _fildes is the read end of the pipe +// File descriptor at index 1 in _fildes is the write end of the pipe +const int SelectInterruptPipe::kPipeReadIndex = 0; +const int SelectInterruptPipe::kPipeWriteIndex = 1; + +SelectInterruptPipe::SelectInterruptPipe() +{ + _fildes[kPipeReadIndex] = -1; + _fildes[kPipeWriteIndex] = -1; +} + +SelectInterruptPipe::~SelectInterruptPipe() +{ + ::close(_fildes[kPipeReadIndex]); + ::close(_fildes[kPipeWriteIndex]); + _fildes[kPipeReadIndex] = -1; + _fildes[kPipeWriteIndex] = -1; +} + +bool SelectInterruptPipe::init(std::string &errorMsg) +{ + std::lock_guard lock(_fildesMutex); + + // calling init twice is a programming error + assert(_fildes[kPipeReadIndex] == -1); + assert(_fildes[kPipeWriteIndex] == -1); + + if (pipe(_fildes) < 0) { + std::stringstream ss; + ss << "SelectInterruptPipe::init() failed in pipe() call" + << " : " << strerror(errno); + errorMsg = ss.str(); + return false; + } + + if (fcntl(_fildes[kPipeReadIndex], F_SETFL, O_NONBLOCK) == -1) { + std::stringstream ss; + ss << "SelectInterruptPipe::init() failed in fcntl(..., O_NONBLOCK) " + "call" + << " : " << strerror(errno); + errorMsg = ss.str(); + + _fildes[kPipeReadIndex] = -1; + _fildes[kPipeWriteIndex] = -1; + return false; + } + + if (fcntl(_fildes[kPipeWriteIndex], F_SETFL, O_NONBLOCK) == -1) { + std::stringstream ss; + ss << "SelectInterruptPipe::init() failed in fcntl(..., O_NONBLOCK) " + "call" + << " : " << strerror(errno); + errorMsg = ss.str(); + + _fildes[kPipeReadIndex] = -1; + _fildes[kPipeWriteIndex] = -1; + return false; + } + +#ifdef F_SETNOSIGPIPE + if (fcntl(_fildes[kPipeWriteIndex], F_SETNOSIGPIPE, 1) == -1) { + std::stringstream ss; + ss << "SelectInterruptPipe::init() failed in fcntl(.... " + "F_SETNOSIGPIPE) call" + << " : " << strerror(errno); + errorMsg = ss.str(); + + _fildes[kPipeReadIndex] = -1; + _fildes[kPipeWriteIndex] = -1; + return false; + } + + if (fcntl(_fildes[kPipeWriteIndex], F_SETNOSIGPIPE, 1) == -1) { + std::stringstream ss; + ss << "SelectInterruptPipe::init() failed in fcntl(..., " + "F_SETNOSIGPIPE) call" + << " : " << strerror(errno); + errorMsg = ss.str(); + + _fildes[kPipeReadIndex] = -1; + _fildes[kPipeWriteIndex] = -1; + return false; + } +#endif + + return true; +} + +bool SelectInterruptPipe::notify(uint64_t value) +{ + std::lock_guard lock(_fildesMutex); + + int fd = _fildes[kPipeWriteIndex]; + if (fd == -1) + return false; + + ssize_t ret = -1; + do { + ret = ::write(fd, &value, sizeof(value)); + } while (ret == -1 && errno == EINTR); + + // we should write 8 bytes for an uint64_t + return ret == 8; +} + +// TODO: return max uint64_t for errors ? +uint64_t SelectInterruptPipe::read() +{ + std::lock_guard lock(_fildesMutex); + + int fd = _fildes[kPipeReadIndex]; + + uint64_t value = 0; + + ssize_t ret = -1; + do { + ret = ::read(fd, &value, sizeof(value)); + } while (ret == -1 && errno == EINTR); + + return value; +} + +bool SelectInterruptPipe::clear() { return true; } + +int SelectInterruptPipe::getFd() const +{ + std::lock_guard lock(_fildesMutex); + + return _fildes[kPipeReadIndex]; +} +} // namespace ix + +#endif // !_WIN32 diff --git a/GermanAirlinesVA-GAConnector/ixwebsocket/IXSetThreadName.cpp b/GermanAirlinesVA-GAConnector/ixwebsocket/IXSetThreadName.cpp new file mode 100644 index 0000000..f4f83f8 --- /dev/null +++ b/GermanAirlinesVA-GAConnector/ixwebsocket/IXSetThreadName.cpp @@ -0,0 +1,81 @@ +/* + * IXSetThreadName.cpp + * Author: Benjamin Sergeant + * Copyright (c) 2018 2020 Machine Zone, Inc. All rights reserved. + */ +#include "IXSetThreadName.h" + +// unix systems +#if defined(__APPLE__) || defined(__linux__) || defined(BSD) +#include +#endif + +// freebsd needs this header as well +#if defined(BSD) +#include +#endif + +// Windows +#ifdef _WIN32 +#include +#endif + +namespace ix +{ +#ifdef _WIN32 +const DWORD MS_VC_EXCEPTION = 0x406D1388; + +#pragma pack(push, 8) +typedef struct tagTHREADNAME_INFO { + DWORD dwType; // Must be 0x1000. + LPCSTR szName; // Pointer to name (in user addr space). + DWORD dwThreadID; // Thread ID (-1=caller thread). + DWORD dwFlags; // Reserved for future use, must be zero. +} THREADNAME_INFO; +#pragma pack(pop) + +void SetThreadName(DWORD dwThreadID, const char *threadName) +{ +#ifndef __GNUC__ + THREADNAME_INFO info; + info.dwType = 0x1000; + info.szName = threadName; + info.dwThreadID = dwThreadID; + info.dwFlags = 0; + + __try { + RaiseException(MS_VC_EXCEPTION, + 0, + sizeof(info) / sizeof(ULONG_PTR), + (ULONG_PTR *)&info); + } __except (EXCEPTION_EXECUTE_HANDLER) { + } +#endif +} +#endif + +void setThreadName(const std::string &name) +{ +#if defined(__APPLE__) + // + // Apple reserves 16 bytes for its thread names + // Notice that the Apple version of pthread_setname_np + // does not take a pthread_t argument + // + pthread_setname_np(name.substr(0, 63).c_str()); +#elif defined(__linux__) + // + // Linux only reserves 16 bytes for its thread names + // See prctl and PR_SET_NAME property in + // http://man7.org/linux/man-pages/man2/prctl.2.html + // + pthread_setname_np(pthread_self(), name.substr(0, 15).c_str()); +#elif defined(_WIN32) + SetThreadName(-1, name.c_str()); +#elif defined(BSD) + pthread_set_name_np(pthread_self(), name.substr(0, 15).c_str()); +#else + // ... assert here ? +#endif +} +} // namespace ix diff --git a/GermanAirlinesVA-GAConnector/ixwebsocket/IXSocket.cpp b/GermanAirlinesVA-GAConnector/ixwebsocket/IXSocket.cpp new file mode 100644 index 0000000..1f00d96 --- /dev/null +++ b/GermanAirlinesVA-GAConnector/ixwebsocket/IXSocket.cpp @@ -0,0 +1,373 @@ +/* + * IXSocket.cpp + * Author: Benjamin Sergeant + * Copyright (c) 2017-2018 Machine Zone, Inc. All rights reserved. + */ + +#include "IXSocket.h" + +#include "IXNetSystem.h" +#include "IXSelectInterrupt.h" +#include "IXSelectInterruptFactory.h" +#include "IXSocketConnect.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef min +#undef min +#endif + +namespace ix +{ +const int Socket::kDefaultPollNoTimeout = -1; // No poll timeout by default +const int Socket::kDefaultPollTimeout = kDefaultPollNoTimeout; + +Socket::Socket(int fd) : _sockfd(fd), _selectInterrupt(createSelectInterrupt()) +{ + ; +} + +Socket::~Socket() { close(); } + +PollResultType Socket::poll(bool readyToRead, + int timeoutMs, + int sockfd, + const SelectInterruptPtr &selectInterrupt) +{ + // + // We used to use ::select to poll but on Android 9 we get large fds out of + // ::connect which crash in FD_SET as they are larger than FD_SETSIZE. + // Switching to ::poll does fix that. + // + // However poll isn't as portable as select and has bugs on Windows, so we + // have a shim to fallback to select on those platforms. See + // https://github.com/mpv-player/mpv/pull/5203/files for such a select + // wrapper. + // + nfds_t nfds = 1; + struct pollfd fds[2]; + memset(fds, 0, sizeof(fds)); + + fds[0].fd = sockfd; + fds[0].events = (readyToRead) ? POLLIN : POLLOUT; + + // this is ignored by poll, but our select based poll wrapper on Windows + // needs it + fds[0].events |= POLLERR; + + // File descriptor used to interrupt select when needed + int interruptFd = -1; + if (selectInterrupt) { + interruptFd = selectInterrupt->getFd(); + + if (interruptFd != -1) { + nfds = 2; + fds[1].fd = interruptFd; + fds[1].events = POLLIN; + } + } + + int ret = ix::poll(fds, nfds, timeoutMs); + + PollResultType pollResult = PollResultType::ReadyForRead; + if (ret < 0) { + pollResult = PollResultType::Error; + } else if (ret == 0) { + pollResult = PollResultType::Timeout; + } else if (interruptFd != -1 && fds[1].revents & POLLIN) { + uint64_t value = selectInterrupt->read(); + + if (value == SelectInterrupt::kSendRequest) { + pollResult = PollResultType::SendRequest; + } else if (value == SelectInterrupt::kCloseRequest) { + pollResult = PollResultType::CloseRequest; + } + } else if (sockfd != -1 && readyToRead && fds[0].revents & POLLIN) { + pollResult = PollResultType::ReadyForRead; + } else if (sockfd != -1 && !readyToRead && fds[0].revents & POLLOUT) { + pollResult = PollResultType::ReadyForWrite; + +#ifdef _WIN32 + // On connect error, in async mode, windows will write to the exceptions + // fds + if (fds[0].revents & POLLERR) { + pollResult = PollResultType::Error; + } +#else + int optval = -1; + socklen_t optlen = sizeof(optval); + + // getsockopt() puts the errno value for connect into optval so 0 + // means no-error. + if (getsockopt(sockfd, SOL_SOCKET, SO_ERROR, &optval, &optlen) == -1 || + optval != 0) { + pollResult = PollResultType::Error; + + // set errno to optval so that external callers can have an + // appropriate error description when calling strerror + errno = optval; + } +#endif + } else if (sockfd != -1 && + (fds[0].revents & POLLERR || fds[0].revents & POLLHUP || + fds[0].revents & POLLNVAL)) { + pollResult = PollResultType::Error; + } + + return pollResult; +} + +PollResultType Socket::isReadyToRead(int timeoutMs) +{ + if (_sockfd == -1) { + return PollResultType::Error; + } + + bool readyToRead = true; + return poll(readyToRead, timeoutMs, _sockfd, _selectInterrupt); +} + +PollResultType Socket::isReadyToWrite(int timeoutMs) +{ + if (_sockfd == -1) { + return PollResultType::Error; + } + + bool readyToRead = false; + return poll(readyToRead, timeoutMs, _sockfd, _selectInterrupt); +} + +// Wake up from poll/select by writing to the pipe which is watched by select +bool Socket::wakeUpFromPoll(uint64_t wakeUpCode) +{ + return _selectInterrupt->notify(wakeUpCode); +} + +bool Socket::accept(std::string &errMsg) +{ + if (_sockfd == -1) { + errMsg = "Socket is uninitialized"; + return false; + } + return true; +} + +bool Socket::connect(const std::string &host, + int port, + std::string &errMsg, + const CancellationRequest &isCancellationRequested) +{ + std::lock_guard lock(_socketMutex); + + if (!_selectInterrupt->clear()) + return false; + + _sockfd = + SocketConnect::connect(host, port, errMsg, isCancellationRequested); + return _sockfd != -1; +} + +void Socket::close() +{ + std::lock_guard lock(_socketMutex); + + if (_sockfd == -1) + return; + + closeSocket(_sockfd); + _sockfd = -1; +} + +ssize_t Socket::send(char *buffer, size_t length) +{ + int flags = 0; +#ifdef MSG_NOSIGNAL + flags = MSG_NOSIGNAL; +#endif + + return ::send(_sockfd, buffer, length, flags); +} + +ssize_t Socket::send(const std::string &buffer) +{ + return send((char *)&buffer[0], buffer.size()); +} + +ssize_t Socket::recv(void *buffer, size_t length) +{ + int flags = 0; +#ifdef MSG_NOSIGNAL + flags = MSG_NOSIGNAL; +#endif + + return ::recv(_sockfd, (char *)buffer, length, flags); +} + +int Socket::getErrno() +{ + int err; + +#ifdef _WIN32 + err = WSAGetLastError(); +#else + err = errno; +#endif + + return err; +} + +bool Socket::isWaitNeeded() +{ + int err = getErrno(); + + if (err == EWOULDBLOCK || err == EAGAIN || err == EINPROGRESS) { + return true; + } + + return false; +} + +void Socket::closeSocket(int fd) +{ +#ifdef _WIN32 + closesocket(fd); +#else + ::close(fd); +#endif +} + +bool Socket::init(std::string &errorMsg) +{ + return _selectInterrupt->init(errorMsg); +} + +bool Socket::writeBytes(const std::string &str, + const CancellationRequest &isCancellationRequested) +{ + int offset = 0; + int len = (int)str.size(); + + while (true) { + if (isCancellationRequested && isCancellationRequested()) + return false; + + ssize_t ret = send((char *)&str[offset], len); + + // We wrote some bytes, as needed, all good. + if (ret > 0) { + if (ret == len) { + return true; + } else { + offset += ret; + len -= ret; + continue; + } + } + // There is possibly something to be writen, try again + else if (ret < 0 && Socket::isWaitNeeded()) { + continue; + } + // There was an error during the write, abort + else { + return false; + } + } +} + +bool Socket::readByte(void *buffer, + const CancellationRequest &isCancellationRequested) +{ + while (true) { + if (isCancellationRequested && isCancellationRequested()) + return false; + + ssize_t ret; + ret = recv(buffer, 1); + + // We read one byte, as needed, all good. + if (ret == 1) { + return true; + } + // There is possibly something to be read, try again + else if (ret < 0 && Socket::isWaitNeeded()) { + // Wait with a 1ms timeout until the socket is ready to read. + // This way we are not busy looping + if (isReadyToRead(1) == PollResultType::Error) { + return false; + } + } + // There was an error during the read, abort + else { + return false; + } + } +} + +std::pair + Socket::readLine(const CancellationRequest &isCancellationRequested) +{ + char c; + std::string line; + line.reserve(64); + + for (int i = 0; i < 2 || (line[i - 2] != '\r' && line[i - 1] != '\n'); + ++i) { + if (!readByte(&c, isCancellationRequested)) { + // Return what we were able to read + return std::make_pair(false, line); + } + + line += c; + } + + return std::make_pair(true, line); +} + +std::pair + Socket::readBytes(size_t length, + const OnProgressCallback &onProgressCallback, + const CancellationRequest &isCancellationRequested) +{ + std::array readBuffer; + + std::vector output; + while (output.size() != length) { + if (isCancellationRequested && isCancellationRequested()) { + const std::string errorMsg("Cancellation Requested"); + return std::make_pair(false, errorMsg); + } + + size_t size = std::min(readBuffer.size(), length - output.size()); + ssize_t ret = recv((char *)&readBuffer[0], size); + + if (ret > 0) { + output.insert(output.end(), + readBuffer.begin(), + readBuffer.begin() + ret); + } else if (ret <= 0 && !Socket::isWaitNeeded()) { + const std::string errorMsg("Recv Error"); + return std::make_pair(false, errorMsg); + } + + if (onProgressCallback) + onProgressCallback((int)output.size(), (int)length); + + // Wait with a 1ms timeout until the socket is ready to read. + // This way we are not busy looping + if (isReadyToRead(1) == PollResultType::Error) { + const std::string errorMsg("Poll Error"); + return std::make_pair(false, errorMsg); + } + } + + return std::make_pair(true, std::string(output.begin(), output.end())); +} +} // namespace ix diff --git a/GermanAirlinesVA-GAConnector/ixwebsocket/IXSocketAppleSSL.cpp b/GermanAirlinesVA-GAConnector/ixwebsocket/IXSocketAppleSSL.cpp new file mode 100644 index 0000000..81e14a0 --- /dev/null +++ b/GermanAirlinesVA-GAConnector/ixwebsocket/IXSocketAppleSSL.cpp @@ -0,0 +1,307 @@ +/* + * IXSocketAppleSSL.cpp + * Author: Benjamin Sergeant + * Copyright (c) 2017-2020 Machine Zone, Inc. All rights reserved. + * + * Adapted from Satori SDK Apple SSL code. + */ +#ifdef IXWEBSOCKET_USE_SECURE_TRANSPORT + +#include "IXSocketAppleSSL.h" + +#include "IXSocketConnect.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#define socketerrno errno + +#include + +namespace ix +{ +SocketAppleSSL::SocketAppleSSL(const SocketTLSOptions &tlsOptions, int fd) + : Socket(fd), _sslContext(nullptr), _tlsOptions(tlsOptions) +{ + ; +} + +SocketAppleSSL::~SocketAppleSSL() { SocketAppleSSL::close(); } + +std::string SocketAppleSSL::getSSLErrorDescription(OSStatus status) +{ + std::string errMsg("Unknown SSL error."); + + CFErrorRef error = CFErrorCreate(kCFAllocatorDefault, + kCFErrorDomainOSStatus, + status, + NULL); + if (error) { + CFStringRef message = CFErrorCopyDescription(error); + if (message) { + char localBuffer[128]; + Boolean success; + success = CFStringGetCString(message, + localBuffer, + 128, + kCFStringEncodingUTF8); + if (success) { + errMsg = localBuffer; + } + CFRelease(message); + } + CFRelease(error); + } + + return errMsg; +} + +OSStatus SocketAppleSSL::readFromSocket(SSLConnectionRef connection, + void *data, + size_t *len) +{ + int fd = (int)(long)connection; + if (fd < 0) + return errSSLInternal; + + assert(data != nullptr); + assert(len != nullptr); + + size_t requested_sz = *len; + + ssize_t status = read(fd, data, requested_sz); + + if (status > 0) { + *len = (size_t)status; + if (requested_sz > *len) { + return errSSLWouldBlock; + } else { + return noErr; + } + } else if (status == 0) { + *len = 0; + return errSSLClosedGraceful; + } else { + *len = 0; + switch (errno) { + case ENOENT: + return errSSLClosedGraceful; + + case EAGAIN: + return errSSLWouldBlock; // EWOULDBLOCK is a define for EAGAIN + // on osx + case EINPROGRESS: + return errSSLWouldBlock; + + case ECONNRESET: + return errSSLClosedAbort; + + default: + return errSecIO; + } + } +} + +OSStatus SocketAppleSSL::writeToSocket(SSLConnectionRef connection, + const void *data, + size_t *len) +{ + int fd = (int)(long)connection; + if (fd < 0) + return errSSLInternal; + + assert(data != nullptr); + assert(len != nullptr); + + size_t to_write_sz = *len; + ssize_t status = write(fd, data, to_write_sz); + + if (status > 0) { + *len = (size_t)status; + if (to_write_sz > *len) { + return errSSLWouldBlock; + } else { + return noErr; + } + } else if (status == 0) { + *len = 0; + return errSSLClosedGraceful; + } else { + *len = 0; + switch (errno) { + case ENOENT: + return errSSLClosedGraceful; + + case EAGAIN: + return errSSLWouldBlock; // EWOULDBLOCK is a define for EAGAIN + // on osx + case EINPROGRESS: + return errSSLWouldBlock; + + case ECONNRESET: + return errSSLClosedAbort; + + default: + return errSecIO; + } + } +} + + +bool SocketAppleSSL::accept(std::string &errMsg) +{ + errMsg = "TLS not supported yet in server mode with apple ssl backend"; + return false; +} + +OSStatus SocketAppleSSL::tlsHandShake( + std::string &errMsg, + const CancellationRequest &isCancellationRequested) +{ + OSStatus status; + + do { + status = SSLHandshake(_sslContext); + + // Interrupt the handshake + if (isCancellationRequested()) { + errMsg = "Cancellation requested"; + return errSSLInternal; + } + } while (status == errSSLWouldBlock || status == errSSLServerAuthCompleted); + + return status; +} + +// No wait support +bool SocketAppleSSL::connect(const std::string &host, + int port, + std::string &errMsg, + const CancellationRequest &isCancellationRequested) +{ + OSStatus status; + { + std::lock_guard lock(_mutex); + + _sockfd = + SocketConnect::connect(host, port, errMsg, isCancellationRequested); + if (_sockfd == -1) + return false; + + _sslContext = SSLCreateContext(kCFAllocatorDefault, + kSSLClientSide, + kSSLStreamType); + + SSLSetIOFuncs(_sslContext, + SocketAppleSSL::readFromSocket, + SocketAppleSSL::writeToSocket); + SSLSetConnection(_sslContext, (SSLConnectionRef)(long)_sockfd); + SSLSetProtocolVersionMin(_sslContext, kTLSProtocol12); + SSLSetPeerDomainName(_sslContext, host.c_str(), host.size()); + + if (_tlsOptions.isPeerVerifyDisabled()) { + Boolean option(1); + SSLSetSessionOption(_sslContext, + kSSLSessionOptionBreakOnServerAuth, + option); + + status = tlsHandShake(errMsg, isCancellationRequested); + + if (status == errSSLServerAuthCompleted) { + // proceed with the handshake + status = tlsHandShake(errMsg, isCancellationRequested); + } + } else { + status = tlsHandShake(errMsg, isCancellationRequested); + } + } + + if (status != noErr) { + errMsg = getSSLErrorDescription(status); + close(); + return false; + } + + return true; +} + +void SocketAppleSSL::close() +{ + std::lock_guard lock(_mutex); + + if (_sslContext == nullptr) + return; + + SSLClose(_sslContext); + CFRelease(_sslContext); + _sslContext = nullptr; + + Socket::close(); +} + +ssize_t SocketAppleSSL::send(char *buf, size_t nbyte) +{ + OSStatus status = errSSLWouldBlock; + while (status == errSSLWouldBlock) { + size_t processed = 0; + std::lock_guard lock(_mutex); + status = SSLWrite(_sslContext, buf, nbyte, &processed); + + if (processed > 0) + return (ssize_t)processed; + + // The connection was reset, inform the caller that this + // Socket should close + if (status == errSSLClosedGraceful || status == errSSLClosedNoNotify || + status == errSSLClosedAbort) { + errno = ECONNRESET; + return -1; + } + + if (status == errSSLWouldBlock) { + errno = EWOULDBLOCK; + return -1; + } + } + return -1; +} + +// No wait support +ssize_t SocketAppleSSL::recv(void *buf, size_t nbyte) +{ + OSStatus status = errSSLWouldBlock; + while (status == errSSLWouldBlock) { + size_t processed = 0; + std::lock_guard lock(_mutex); + status = SSLRead(_sslContext, buf, nbyte, &processed); + + if (processed > 0) + return (ssize_t)processed; + + // The connection was reset, inform the caller that this + // Socket should close + if (status == errSSLClosedGraceful || status == errSSLClosedNoNotify || + status == errSSLClosedAbort) { + errno = ECONNRESET; + return -1; + } + + if (status == errSSLWouldBlock) { + errno = EWOULDBLOCK; + return -1; + } + } + return -1; +} + +} // namespace ix + +#endif // IXWEBSOCKET_USE_SECURE_TRANSPORT diff --git a/GermanAirlinesVA-GAConnector/ixwebsocket/IXSocketConnect.cpp b/GermanAirlinesVA-GAConnector/ixwebsocket/IXSocketConnect.cpp new file mode 100644 index 0000000..eb2d793 --- /dev/null +++ b/GermanAirlinesVA-GAConnector/ixwebsocket/IXSocketConnect.cpp @@ -0,0 +1,150 @@ +/* + * IXSocketConnect.cpp + * Author: Benjamin Sergeant + * Copyright (c) 2018 Machine Zone, Inc. All rights reserved. + */ + +#include "IXSocketConnect.h" + +#include "IXDNSLookup.h" +#include "IXNetSystem.h" +#include "IXSelectInterrupt.h" +#include "IXSocket.h" +#include "IXUniquePtr.h" +#include +#include +#include + +// Android needs extra headers for TCP_NODELAY and IPPROTO_TCP +#ifdef ANDROID +#include +#include +#endif + +namespace ix +{ +// +// This function can be cancelled every 50 ms +// This is important so that we don't block the main UI thread when shutting +// down a connection which is already trying to reconnect, and can be blocked +// waiting for +// ::connect to respond. +// +int SocketConnect::connectToAddress( + const struct addrinfo *address, + std::string &errMsg, + const CancellationRequest &isCancellationRequested) +{ + errMsg = "no error"; + + socket_t fd = + socket(address->ai_family, address->ai_socktype, address->ai_protocol); + if (fd < 0) { + errMsg = "Cannot create a socket"; + return -1; + } + + // Set the socket to non blocking mode, so that slow responses cannot + // block us for too long + SocketConnect::configure(fd); + + int res = ::connect(fd, address->ai_addr, address->ai_addrlen); + + if (res == -1 && !Socket::isWaitNeeded()) { + errMsg = strerror(Socket::getErrno()); + Socket::closeSocket(fd); + return -1; + } + + for (;;) { + if (isCancellationRequested && + isCancellationRequested()) // Must handle timeout as well + { + Socket::closeSocket(fd); + errMsg = "Cancelled"; + return -1; + } + + int timeoutMs = 10; + bool readyToRead = false; + auto selectInterrupt = ix::make_unique(); + PollResultType pollResult = + Socket::poll(readyToRead, timeoutMs, fd, selectInterrupt); + + if (pollResult == PollResultType::Timeout) { + continue; + } else if (pollResult == PollResultType::Error) { + Socket::closeSocket(fd); + errMsg = + std::string("Connect error: ") + strerror(Socket::getErrno()); + return -1; + } else if (pollResult == PollResultType::ReadyForWrite) { + return fd; + } else { + Socket::closeSocket(fd); + errMsg = + std::string("Connect error: ") + strerror(Socket::getErrno()); + return -1; + } + } + + Socket::closeSocket(fd); + errMsg = "connect timed out after 60 seconds"; + return -1; +} + +int SocketConnect::connect(const std::string &hostname, + int port, + std::string &errMsg, + const CancellationRequest &isCancellationRequested) +{ + // + // First do DNS resolution + // + auto dnsLookup = std::make_shared(hostname, port); + struct addrinfo *res = dnsLookup->resolve(errMsg, isCancellationRequested); + if (res == nullptr) { + return -1; + } + + int sockfd = -1; + + // iterate through the records to find a working peer + struct addrinfo *address; + for (address = res; address != nullptr; address = address->ai_next) { + // + // Second try to connect to the remote host + // + sockfd = connectToAddress(address, errMsg, isCancellationRequested); + if (sockfd != -1) { + break; + } + } + + freeaddrinfo(res); + return sockfd; +} + +// FIXME: configure is a terrible name +void SocketConnect::configure(int sockfd) +{ + // 1. disable Nagle's algorithm + int flag = 1; + setsockopt(sockfd, IPPROTO_TCP, TCP_NODELAY, (char *)&flag, sizeof(flag)); + + // 2. make socket non blocking +#ifdef _WIN32 + unsigned long nonblocking = 1; + ioctlsocket(sockfd, FIONBIO, &nonblocking); +#else + fcntl(sockfd, F_SETFL, O_NONBLOCK); // make socket non blocking +#endif + + // 3. (apple) prevent SIGPIPE from being emitted when the remote end + // disconnect +#ifdef SO_NOSIGPIPE + int value = 1; + setsockopt(sockfd, SOL_SOCKET, SO_NOSIGPIPE, (void *)&value, sizeof(value)); +#endif +} +} // namespace ix diff --git a/GermanAirlinesVA-GAConnector/ixwebsocket/IXSocketFactory.cpp b/GermanAirlinesVA-GAConnector/ixwebsocket/IXSocketFactory.cpp new file mode 100644 index 0000000..0e8434b --- /dev/null +++ b/GermanAirlinesVA-GAConnector/ixwebsocket/IXSocketFactory.cpp @@ -0,0 +1,60 @@ +/* + * IXSocketFactory.cpp + * Author: Benjamin Sergeant + * Copyright (c) 2019 Machine Zone, Inc. All rights reserved. + */ + +#include "IXSocketFactory.h" + +#include "IXUniquePtr.h" +#ifdef IXWEBSOCKET_USE_TLS + +#ifdef IXWEBSOCKET_USE_MBED_TLS +#include "IXSocketMbedTLS.h" +#elif defined(IXWEBSOCKET_USE_OPEN_SSL) +#include "IXSocketOpenSSL.h" +#elif __APPLE__ +#include "IXSocketAppleSSL.h" +#endif + +#else + +#include "IXSocket.h" + +#endif + +namespace ix +{ +std::unique_ptr createSocket(bool tls, + int fd, + std::string &errorMsg, + const SocketTLSOptions &tlsOptions) +{ + (void)tlsOptions; + errorMsg.clear(); + std::unique_ptr socket; + + if (!tls) { + socket = ix::make_unique(fd); + } else { +#ifdef IXWEBSOCKET_USE_TLS +#if defined(IXWEBSOCKET_USE_MBED_TLS) + socket = ix::make_unique(tlsOptions, fd); +#elif defined(IXWEBSOCKET_USE_OPEN_SSL) + socket = ix::make_unique(tlsOptions, fd); +#elif defined(__APPLE__) + socket = ix::make_unique(tlsOptions, fd); +#endif +#else + errorMsg = "TLS support is not enabled on this platform."; + return nullptr; +#endif + } + + if (!socket->init(errorMsg)) { + socket.reset(); + } + + return socket; +} +} // namespace ix diff --git a/GermanAirlinesVA-GAConnector/ixwebsocket/IXSocketMbedTLS.cpp b/GermanAirlinesVA-GAConnector/ixwebsocket/IXSocketMbedTLS.cpp new file mode 100644 index 0000000..93fa6af --- /dev/null +++ b/GermanAirlinesVA-GAConnector/ixwebsocket/IXSocketMbedTLS.cpp @@ -0,0 +1,350 @@ +/* + * IXSocketMbedTLS.cpp + * Author: Benjamin Sergeant, Max Weisel + * Copyright (c) 2019-2020 Machine Zone, Inc. All rights reserved. + * + * Some code taken from + * https://github.com/rottor12/WsClientLib/blob/master/lib/src/WsClientLib.cpp + * and mini_client.c example from mbedtls + */ +#ifdef IXWEBSOCKET_USE_MBED_TLS + +#include "IXSocketMbedTLS.h" + +#include "IXNetSystem.h" +#include "IXSocket.h" +#include "IXSocketConnect.h" +#include + +#ifdef _WIN32 +// For manipulating the certificate store +#include +#endif + +namespace ix +{ +SocketMbedTLS::SocketMbedTLS(const SocketTLSOptions &tlsOptions, int fd) + : Socket(fd), _tlsOptions(tlsOptions) +{ + initMBedTLS(); +} + +SocketMbedTLS::~SocketMbedTLS() { SocketMbedTLS::close(); } + +void SocketMbedTLS::initMBedTLS() +{ + std::lock_guard lock(_mutex); + + mbedtls_ssl_init(&_ssl); + mbedtls_ssl_config_init(&_conf); + mbedtls_ctr_drbg_init(&_ctr_drbg); + mbedtls_entropy_init(&_entropy); + mbedtls_x509_crt_init(&_cacert); + mbedtls_x509_crt_init(&_cert); + mbedtls_pk_init(&_pkey); +} + +bool SocketMbedTLS::loadSystemCertificates(std::string &errorMsg) +{ +#ifdef _WIN32 + DWORD flags = CERT_STORE_READONLY_FLAG | CERT_STORE_OPEN_EXISTING_FLAG | + CERT_SYSTEM_STORE_CURRENT_USER; + HCERTSTORE systemStore = + CertOpenStore(CERT_STORE_PROV_SYSTEM, 0, 0, flags, L"Root"); + + if (!systemStore) { + errorMsg = "CertOpenStore failed with "; + errorMsg += std::to_string(GetLastError()); + return false; + } + + PCCERT_CONTEXT certificateIterator = NULL; + + int certificateCount = 0; + while (certificateIterator = + CertEnumCertificatesInStore(systemStore, certificateIterator)) { + if (certificateIterator->dwCertEncodingType & X509_ASN_ENCODING) { + int ret = + mbedtls_x509_crt_parse(&_cacert, + certificateIterator->pbCertEncoded, + certificateIterator->cbCertEncoded); + if (ret == 0) { + ++certificateCount; + } + } + } + + CertFreeCertificateContext(certificateIterator); + CertCloseStore(systemStore, 0); + + if (certificateCount == 0) { + errorMsg = "No certificates found"; + return false; + } + + return true; +#else + // On macOS we can query the system cert location from the keychain + // On Linux we could try to fetch some local files based on the distribution + // On Android we could use JNI to get to the system certs + return false; +#endif +} + +bool SocketMbedTLS::init(const std::string &host, + bool isClient, + std::string &errMsg) +{ + initMBedTLS(); + std::lock_guard lock(_mutex); + + const char *pers = "IXSocketMbedTLS"; + + if (mbedtls_ctr_drbg_seed(&_ctr_drbg, + mbedtls_entropy_func, + &_entropy, + (const unsigned char *)pers, + strlen(pers)) != 0) { + errMsg = "Setting entropy seed failed"; + return false; + } + + if (mbedtls_ssl_config_defaults(&_conf, + (isClient) ? MBEDTLS_SSL_IS_CLIENT + : MBEDTLS_SSL_IS_SERVER, + MBEDTLS_SSL_TRANSPORT_STREAM, + MBEDTLS_SSL_PRESET_DEFAULT) != 0) { + errMsg = "Setting config default failed"; + return false; + } + + mbedtls_ssl_conf_rng(&_conf, mbedtls_ctr_drbg_random, &_ctr_drbg); + + if (_tlsOptions.hasCertAndKey()) { + if (mbedtls_x509_crt_parse_file(&_cert, _tlsOptions.certFile.c_str()) < + 0) { + errMsg = "Cannot parse cert file '" + _tlsOptions.certFile + "'"; + return false; + } +#ifdef IXWEBSOCKET_USE_MBED_TLS_MIN_VERSION_3 + if (mbedtls_pk_parse_keyfile(&_pkey, + _tlsOptions.keyFile.c_str(), + "", + mbedtls_ctr_drbg_random, + &_ctr_drbg) < 0) +#else + if (mbedtls_pk_parse_keyfile(&_pkey, _tlsOptions.keyFile.c_str(), "") < + 0) +#endif + { + errMsg = "Cannot parse key file '" + _tlsOptions.keyFile + "'"; + return false; + } + if (mbedtls_ssl_conf_own_cert(&_conf, &_cert, &_pkey) < 0) { + errMsg = "Problem configuring cert '" + _tlsOptions.certFile + "'"; + return false; + } + } + + if (_tlsOptions.isPeerVerifyDisabled()) { + mbedtls_ssl_conf_authmode(&_conf, MBEDTLS_SSL_VERIFY_NONE); + } else { + // FIXME: should we call mbedtls_ssl_conf_verify ? + mbedtls_ssl_conf_authmode(&_conf, MBEDTLS_SSL_VERIFY_REQUIRED); + + if (_tlsOptions.isUsingSystemDefaults()) { + if (!loadSystemCertificates(errMsg)) { + return false; + } + } else { + if (_tlsOptions.isUsingInMemoryCAs()) { + const char *buffer = _tlsOptions.caFile.c_str(); + size_t bufferSize = _tlsOptions.caFile.size() + + 1; // Needs to include null terminating + // character otherwise mbedtls will fail. + if (mbedtls_x509_crt_parse(&_cacert, + (const unsigned char *)buffer, + bufferSize) < 0) { + errMsg = "Cannot parse CA from memory."; + return false; + } + } else if (mbedtls_x509_crt_parse_file(&_cacert, + _tlsOptions.caFile.c_str()) < + 0) { + errMsg = "Cannot parse CA file '" + _tlsOptions.caFile + "'"; + return false; + } + } + + mbedtls_ssl_conf_ca_chain(&_conf, &_cacert, NULL); + } + + if (mbedtls_ssl_setup(&_ssl, &_conf) != 0) { + errMsg = "SSL setup failed"; + return false; + } + + if (!host.empty() && mbedtls_ssl_set_hostname(&_ssl, host.c_str()) != 0) { + errMsg = "SNI setup failed"; + return false; + } + + return true; +} + +bool SocketMbedTLS::accept(std::string &errMsg) +{ + bool isClient = false; + bool initialized = init(std::string(), isClient, errMsg); + if (!initialized) { + close(); + return false; + } + + mbedtls_ssl_set_bio(&_ssl, + &_sockfd, + mbedtls_net_send, + mbedtls_net_recv, + NULL); + + int res; + do { + std::lock_guard lock(_mutex); + res = mbedtls_ssl_handshake(&_ssl); + } while (res == MBEDTLS_ERR_SSL_WANT_READ || + res == MBEDTLS_ERR_SSL_WANT_WRITE); + + if (res != 0) { + char buf[256]; + mbedtls_strerror(res, buf, sizeof(buf)); + + errMsg = "error in handshake : "; + errMsg += buf; + + if (res == MBEDTLS_ERR_X509_CERT_VERIFY_FAILED) { + char verifyBuf[512]; + uint32_t flags = mbedtls_ssl_get_verify_result(&_ssl); + + mbedtls_x509_crt_verify_info(verifyBuf, + sizeof(verifyBuf), + " ! ", + flags); + errMsg += " : "; + errMsg += verifyBuf; + } + + close(); + return false; + } + + return true; +} + +bool SocketMbedTLS::connect(const std::string &host, + int port, + std::string &errMsg, + const CancellationRequest &isCancellationRequested) +{ + { + std::lock_guard lock(_mutex); + _sockfd = + SocketConnect::connect(host, port, errMsg, isCancellationRequested); + if (_sockfd == -1) + return false; + } + + bool isClient = true; + bool initialized = init(host, isClient, errMsg); + if (!initialized) { + close(); + return false; + } + + mbedtls_ssl_set_bio(&_ssl, + &_sockfd, + mbedtls_net_send, + mbedtls_net_recv, + NULL); + + int res; + do { + { + std::lock_guard lock(_mutex); + res = mbedtls_ssl_handshake(&_ssl); + } + + if (isCancellationRequested()) { + errMsg = "Cancellation requested"; + close(); + return false; + } + } while (res == MBEDTLS_ERR_SSL_WANT_READ || + res == MBEDTLS_ERR_SSL_WANT_WRITE); + + if (res != 0) { + char buf[256]; + mbedtls_strerror(res, buf, sizeof(buf)); + + errMsg = "error in handshake : "; + errMsg += buf; + + close(); + return false; + } + + return true; +} + +void SocketMbedTLS::close() +{ + std::lock_guard lock(_mutex); + + mbedtls_ssl_free(&_ssl); + mbedtls_ssl_config_free(&_conf); + mbedtls_ctr_drbg_free(&_ctr_drbg); + mbedtls_entropy_free(&_entropy); + mbedtls_x509_crt_free(&_cacert); + mbedtls_x509_crt_free(&_cert); + + Socket::close(); +} + +ssize_t SocketMbedTLS::send(char *buf, size_t nbyte) +{ + std::lock_guard lock(_mutex); + + ssize_t res = mbedtls_ssl_write(&_ssl, (unsigned char *)buf, nbyte); + + if (res > 0) { + return res; + } else if (res == MBEDTLS_ERR_SSL_WANT_READ || + res == MBEDTLS_ERR_SSL_WANT_WRITE) { + errno = EWOULDBLOCK; + return -1; + } else { + return -1; + } +} + +ssize_t SocketMbedTLS::recv(void *buf, size_t nbyte) +{ + while (true) { + std::lock_guard lock(_mutex); + + ssize_t res = mbedtls_ssl_read(&_ssl, (unsigned char *)buf, (int)nbyte); + + if (res > 0) { + return res; + } + + if (res == MBEDTLS_ERR_SSL_WANT_READ || + res == MBEDTLS_ERR_SSL_WANT_WRITE) { + errno = EWOULDBLOCK; + } + return -1; + } +} + +} // namespace ix + +#endif // IXWEBSOCKET_USE_MBED_TLS diff --git a/GermanAirlinesVA-GAConnector/ixwebsocket/IXSocketOpenSSL.cpp b/GermanAirlinesVA-GAConnector/ixwebsocket/IXSocketOpenSSL.cpp new file mode 100644 index 0000000..4c18538 --- /dev/null +++ b/GermanAirlinesVA-GAConnector/ixwebsocket/IXSocketOpenSSL.cpp @@ -0,0 +1,761 @@ +/* + * IXSocketOpenSSL.cpp + * Author: Benjamin Sergeant, Matt DeBoer, Max Weisel + * Copyright (c) 2017-2020 Machine Zone, Inc. All rights reserved. + * + * Adapted from Satori SDK OpenSSL code. + */ +#ifdef IXWEBSOCKET_USE_OPEN_SSL + +#include "IXSocketOpenSSL.h" + +#include "IXSocketConnect.h" +#include "IXUniquePtr.h" +#include +#include +#include +#ifdef _WIN32 +#include +#else +#include +#endif +#if OPENSSL_VERSION_NUMBER < 0x10100000L +#include +#endif +#define socketerrno errno + +#ifdef _WIN32 +// For manipulating the certificate store +#include +#endif + +#ifdef _WIN32 +namespace +{ +bool loadWindowsSystemCertificates(SSL_CTX *ssl, std::string &errorMsg) +{ + DWORD flags = CERT_STORE_READONLY_FLAG | CERT_STORE_OPEN_EXISTING_FLAG | + CERT_SYSTEM_STORE_CURRENT_USER; + HCERTSTORE systemStore = + CertOpenStore(CERT_STORE_PROV_SYSTEM, 0, 0, flags, L"Root"); + + if (!systemStore) { + errorMsg = "CertOpenStore failed with "; + errorMsg += std::to_string(GetLastError()); + return false; + } + + PCCERT_CONTEXT certificateIterator = NULL; + X509_STORE *opensslStore = SSL_CTX_get_cert_store(ssl); + + int certificateCount = 0; + while (certificateIterator = + CertEnumCertificatesInStore(systemStore, certificateIterator)) { + X509 *x509 = d2i_X509( + NULL, + (const unsigned char **)&certificateIterator->pbCertEncoded, + certificateIterator->cbCertEncoded); + + if (x509) { + if (X509_STORE_add_cert(opensslStore, x509) == 1) { + ++certificateCount; + } + + X509_free(x509); + } + } + + CertFreeCertificateContext(certificateIterator); + CertCloseStore(systemStore, 0); + + if (certificateCount == 0) { + errorMsg = "No certificates found"; + return false; + } + + return true; +} +} // namespace +#endif + +namespace ix +{ +const std::string kDefaultCiphers = + "ECDHE-ECDSA-AES128-GCM-SHA256 ECDHE-ECDSA-AES256-GCM-SHA384 " + "ECDHE-ECDSA-AES128-SHA " + "ECDHE-ECDSA-AES256-SHA ECDHE-ECDSA-AES128-SHA256 " + "ECDHE-ECDSA-AES256-SHA384 " + "ECDHE-RSA-AES128-GCM-SHA256 ECDHE-RSA-AES256-GCM-SHA384 " + "ECDHE-RSA-AES128-SHA " + "ECDHE-RSA-AES256-SHA ECDHE-RSA-AES128-SHA256 ECDHE-RSA-AES256-SHA384 " + "DHE-RSA-AES128-GCM-SHA256 DHE-RSA-AES256-GCM-SHA384 DHE-RSA-AES128-SHA " + "DHE-RSA-AES256-SHA DHE-RSA-AES128-SHA256 DHE-RSA-AES256-SHA256 AES128-SHA"; + +std::atomic SocketOpenSSL::_openSSLInitializationSuccessful(false); +std::once_flag SocketOpenSSL::_openSSLInitFlag; +std::vector> openSSLMutexes; + +SocketOpenSSL::SocketOpenSSL(const SocketTLSOptions &tlsOptions, int fd) + : Socket(fd), _ssl_connection(nullptr), _ssl_context(nullptr), + _tlsOptions(tlsOptions) +{ + std::call_once(_openSSLInitFlag, &SocketOpenSSL::openSSLInitialize, this); +} + +SocketOpenSSL::~SocketOpenSSL() { SocketOpenSSL::close(); } + +void SocketOpenSSL::openSSLInitialize() +{ +#if OPENSSL_VERSION_NUMBER >= 0x10100000L + if (!OPENSSL_init_ssl(OPENSSL_INIT_LOAD_CONFIG, nullptr)) + return; +#else + (void)OPENSSL_config(nullptr); + + if (CRYPTO_get_locking_callback() == nullptr) { + openSSLMutexes.clear(); + for (int i = 0; i < CRYPTO_num_locks(); ++i) { + openSSLMutexes.push_back(ix::make_unique()); + } + CRYPTO_set_locking_callback(SocketOpenSSL::openSSLLockingCallback); + } +#endif + + (void)OpenSSL_add_ssl_algorithms(); + (void)SSL_load_error_strings(); + + _openSSLInitializationSuccessful = true; +} + +void SocketOpenSSL::openSSLLockingCallback(int mode, + int type, + const char * /*file*/, + int /*line*/) +{ + if (mode & CRYPTO_LOCK) { + openSSLMutexes[type]->lock(); + } else { + openSSLMutexes[type]->unlock(); + } +} + +std::string SocketOpenSSL::getSSLError(int ret) +{ + unsigned long e; + + int err = SSL_get_error(_ssl_connection, ret); + + if (err == SSL_ERROR_WANT_CONNECT || err == SSL_ERROR_WANT_ACCEPT) { + return "OpenSSL failed - connection failure"; + } else if (err == SSL_ERROR_WANT_X509_LOOKUP) { + return "OpenSSL failed - x509 error"; + } else if (err == SSL_ERROR_SYSCALL) { + e = ERR_get_error(); + if (e > 0) { + std::string errMsg("OpenSSL failed - "); + errMsg += ERR_error_string(e, nullptr); + return errMsg; + } else if (e == 0 && ret == 0) { + return "OpenSSL failed - received early EOF"; + } else { + return "OpenSSL failed - underlying BIO reported an I/O error"; + } + } else if (err == SSL_ERROR_SSL) { + e = ERR_get_error(); + std::string errMsg("OpenSSL failed - "); + errMsg += ERR_error_string(e, nullptr); + return errMsg; + } else if (err == SSL_ERROR_NONE) { + return "OpenSSL failed - err none"; + } else if (err == SSL_ERROR_ZERO_RETURN) { + return "OpenSSL failed - err zero return"; + } else { + return "OpenSSL failed - unknown error"; + } +} + +SSL_CTX *SocketOpenSSL::openSSLCreateContext(std::string &errMsg) +{ + const SSL_METHOD *method = SSLv23_client_method(); + if (method == nullptr) { + errMsg = "SSLv23_client_method failure"; + return nullptr; + } + _ssl_method = method; + + SSL_CTX *ctx = SSL_CTX_new(_ssl_method); + if (ctx) { + SSL_CTX_set_mode(ctx, + SSL_MODE_ENABLE_PARTIAL_WRITE | + SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER); + + int options = + SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3 | SSL_OP_CIPHER_SERVER_PREFERENCE; + +#ifdef SSL_OP_NO_TLSv1_3 + // (partially?) work around hang in openssl 1.1.1b, by disabling TLS + // V1.3 https://github.com/openssl/openssl/issues/7967 + options |= SSL_OP_NO_TLSv1_3; +#endif + SSL_CTX_set_options(ctx, options); + } + return ctx; +} + +bool SocketOpenSSL::openSSLAddCARootsFromString(const std::string roots) +{ + // Create certificate store + X509_STORE *certificate_store = SSL_CTX_get_cert_store(_ssl_context); + if (certificate_store == nullptr) + return false; + + // Configure to allow intermediate certs + X509_STORE_set_flags(certificate_store, + X509_V_FLAG_TRUSTED_FIRST | X509_V_FLAG_PARTIAL_CHAIN); + + // Create a new buffer and populate it with the roots + BIO *buffer = BIO_new_mem_buf((void *)roots.c_str(), + static_cast(roots.length())); + if (buffer == nullptr) + return false; + + // Read each root in the buffer and add to the certificate store + bool success = true; + size_t number_of_roots = 0; + + while (true) { + // Read the next root in the buffer + X509 *root = + PEM_read_bio_X509_AUX(buffer, nullptr, nullptr, (void *)""); + if (root == nullptr) { + // No more certs left in the buffer, we're done. + ERR_clear_error(); + break; + } + + // Try adding the root to the certificate store + ERR_clear_error(); + if (!X509_STORE_add_cert(certificate_store, root)) { + // Failed to add. If the error is unrelated to the x509 lib or the + // cert already exists, we're safe to continue. + unsigned long error = ERR_get_error(); + if (ERR_GET_LIB(error) != ERR_LIB_X509 || + ERR_GET_REASON(error) != X509_R_CERT_ALREADY_IN_HASH_TABLE) { + // Failed. Clean up and bail. + success = false; + X509_free(root); + break; + } + } + + // Clean up and loop + X509_free(root); + number_of_roots++; + } + + // Clean up buffer + BIO_free(buffer); + + // Make sure we loaded at least one certificate. + if (number_of_roots == 0) + success = false; + + return success; +} + +/** + * Check whether a hostname matches a pattern + */ +bool SocketOpenSSL::checkHost(const std::string &host, const char *pattern) +{ +#ifdef _WIN32 + return PathMatchSpecA(host.c_str(), pattern); +#else + return fnmatch(pattern, host.c_str(), 0) != FNM_NOMATCH; +#endif +} + +bool SocketOpenSSL::openSSLCheckServerCert(SSL *ssl, + const std::string &hostname, + std::string &errMsg) +{ + X509 *server_cert = SSL_get_peer_certificate(ssl); + if (server_cert == nullptr) { + errMsg = "OpenSSL failed - peer didn't present a X509 certificate."; + return false; + } + +#if OPENSSL_VERSION_NUMBER < 0x10100000L + // Check server name + bool hostname_verifies_ok = false; + STACK_OF(GENERAL_NAME) *san_names = (STACK_OF(GENERAL_NAME) *) + X509_get_ext_d2i((X509 *)server_cert, NID_subject_alt_name, NULL, NULL); + if (san_names) { + for (int i = 0; i < sk_GENERAL_NAME_num(san_names); i++) { + const GENERAL_NAME *sk_name = sk_GENERAL_NAME_value(san_names, i); + if (sk_name->type == GEN_DNS) { + char *name = (char *)ASN1_STRING_data(sk_name->d.dNSName); + if ((size_t)ASN1_STRING_length(sk_name->d.dNSName) == + strlen(name) && + checkHost(hostname, name)) { + hostname_verifies_ok = true; + break; + } + } + } + } + sk_GENERAL_NAME_pop_free(san_names, GENERAL_NAME_free); + + if (!hostname_verifies_ok) { + int cn_pos = X509_NAME_get_index_by_NID( + X509_get_subject_name((X509 *)server_cert), + NID_commonName, + -1); + if (cn_pos) { + X509_NAME_ENTRY *cn_entry = + X509_NAME_get_entry(X509_get_subject_name((X509 *)server_cert), + cn_pos); + + if (cn_entry) { + ASN1_STRING *cn_asn1 = X509_NAME_ENTRY_get_data(cn_entry); + char *cn = (char *)ASN1_STRING_data(cn_asn1); + + if ((size_t)ASN1_STRING_length(cn_asn1) == strlen(cn) && + checkHost(hostname, cn)) { + hostname_verifies_ok = true; + } + } + } + } + + if (!hostname_verifies_ok) { + errMsg = + "OpenSSL failed - certificate was issued for a different domain."; + return false; + } +#endif + + X509_free(server_cert); + return true; +} + +bool SocketOpenSSL::openSSLClientHandshake( + const std::string &host, + std::string &errMsg, + const CancellationRequest &isCancellationRequested) +{ + while (true) { + if (_ssl_connection == nullptr || _ssl_context == nullptr) { + return false; + } + + if (isCancellationRequested()) { + errMsg = "Cancellation requested"; + return false; + } + + ERR_clear_error(); + int connect_result = SSL_connect(_ssl_connection); + if (connect_result == 1) { + return openSSLCheckServerCert(_ssl_connection, host, errMsg); + } + int reason = SSL_get_error(_ssl_connection, connect_result); + + bool rc = false; + if (reason == SSL_ERROR_WANT_READ || reason == SSL_ERROR_WANT_WRITE) { + rc = true; + } else { + errMsg = getSSLError(connect_result); + rc = false; + } + + if (!rc) { + return false; + } + } +} + +bool SocketOpenSSL::openSSLServerHandshake(std::string &errMsg) +{ + while (true) { + if (_ssl_connection == nullptr || _ssl_context == nullptr) { + return false; + } + + ERR_clear_error(); + int accept_result = SSL_accept(_ssl_connection); + if (accept_result == 1) { + return true; + } + int reason = SSL_get_error(_ssl_connection, accept_result); + + bool rc = false; + if (reason == SSL_ERROR_WANT_READ || reason == SSL_ERROR_WANT_WRITE) { + rc = true; + } else { + errMsg = getSSLError(accept_result); + rc = false; + } + + if (!rc) { + return false; + } + } +} + +bool SocketOpenSSL::handleTLSOptions(std::string &errMsg) +{ + ERR_clear_error(); + if (_tlsOptions.hasCertAndKey()) { + if (SSL_CTX_use_certificate_chain_file(_ssl_context, + _tlsOptions.certFile.c_str()) != + 1) { + auto sslErr = ERR_get_error(); + errMsg = "OpenSSL failed - SSL_CTX_use_certificate_chain_file(\"" + + _tlsOptions.certFile + "\") failed: "; + errMsg += ERR_error_string(sslErr, nullptr); + } else if (SSL_CTX_use_PrivateKey_file(_ssl_context, + _tlsOptions.keyFile.c_str(), + SSL_FILETYPE_PEM) != 1) { + auto sslErr = ERR_get_error(); + errMsg = "OpenSSL failed - SSL_CTX_use_PrivateKey_file(\"" + + _tlsOptions.keyFile + "\") failed: "; + errMsg += ERR_error_string(sslErr, nullptr); + } else if (!SSL_CTX_check_private_key(_ssl_context)) { + auto sslErr = ERR_get_error(); + errMsg = "OpenSSL failed - cert/key mismatch(\"" + + _tlsOptions.certFile + ", " + _tlsOptions.keyFile + "\")"; + errMsg += ERR_error_string(sslErr, nullptr); + } + } + + ERR_clear_error(); + if (!_tlsOptions.isPeerVerifyDisabled()) { + if (_tlsOptions.isUsingSystemDefaults()) { +#ifdef _WIN32 + if (!loadWindowsSystemCertificates(_ssl_context, errMsg)) { + return false; + } +#else + if (SSL_CTX_set_default_verify_paths(_ssl_context) == 0) { + auto sslErr = ERR_get_error(); + errMsg = "OpenSSL failed - SSL_CTX_default_verify_paths " + "loading failed: "; + errMsg += ERR_error_string(sslErr, nullptr); + return false; + } +#endif + } else { + if (_tlsOptions.isUsingInMemoryCAs()) { + // Load from memory + openSSLAddCARootsFromString(_tlsOptions.caFile); + } else { + if (SSL_CTX_load_verify_locations(_ssl_context, + _tlsOptions.caFile.c_str(), + NULL) != 1) { + auto sslErr = ERR_get_error(); + errMsg = + "OpenSSL failed - SSL_CTX_load_verify_locations(\"" + + _tlsOptions.caFile + "\") failed: "; + errMsg += ERR_error_string(sslErr, nullptr); + return false; + } + } + } + + SSL_CTX_set_verify( + _ssl_context, + SSL_VERIFY_PEER, + [](int preverify, X509_STORE_CTX *) -> int { return preverify; }); + SSL_CTX_set_verify_depth(_ssl_context, 4); + } else { + SSL_CTX_set_verify(_ssl_context, SSL_VERIFY_NONE, nullptr); + } + + if (_tlsOptions.isUsingDefaultCiphers()) { + if (SSL_CTX_set_cipher_list(_ssl_context, kDefaultCiphers.c_str()) != + 1) { + auto sslErr = ERR_get_error(); + errMsg = "OpenSSL failed - SSL_CTX_set_cipher_list(\"" + + kDefaultCiphers + "\") failed: "; + errMsg += ERR_error_string(sslErr, nullptr); + return false; + } + } else if (SSL_CTX_set_cipher_list(_ssl_context, + _tlsOptions.ciphers.c_str()) != 1) { + auto sslErr = ERR_get_error(); + errMsg = "OpenSSL failed - SSL_CTX_set_cipher_list(\"" + + _tlsOptions.ciphers + "\") failed: "; + errMsg += ERR_error_string(sslErr, nullptr); + return false; + } + + return true; +} + +bool SocketOpenSSL::accept(std::string &errMsg) +{ + bool handshakeSuccessful = false; + { + std::lock_guard lock(_mutex); + + if (!_openSSLInitializationSuccessful) { + errMsg = "OPENSSL_init_ssl failure"; + return false; + } + + if (_sockfd == -1) { + return false; + } + + { + const SSL_METHOD *method = SSLv23_server_method(); + if (method == nullptr) { + errMsg = "SSLv23_server_method failure"; + _ssl_context = nullptr; + } else { + _ssl_method = method; + + _ssl_context = SSL_CTX_new(_ssl_method); + if (_ssl_context) { + SSL_CTX_set_mode(_ssl_context, + SSL_MODE_ENABLE_PARTIAL_WRITE); + SSL_CTX_set_mode(_ssl_context, + SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER); + SSL_CTX_set_options(_ssl_context, + SSL_OP_ALL | SSL_OP_NO_SSLv2 | + SSL_OP_NO_SSLv3); + } + } + } + + if (_ssl_context == nullptr) { + return false; + } + + ERR_clear_error(); + if (_tlsOptions.hasCertAndKey()) { + if (SSL_CTX_use_certificate_chain_file( + _ssl_context, + _tlsOptions.certFile.c_str()) != 1) { + auto sslErr = ERR_get_error(); + errMsg = + "OpenSSL failed - SSL_CTX_use_certificate_chain_file(\"" + + _tlsOptions.certFile + "\") failed: "; + errMsg += ERR_error_string(sslErr, nullptr); + } else if (SSL_CTX_use_PrivateKey_file(_ssl_context, + _tlsOptions.keyFile.c_str(), + SSL_FILETYPE_PEM) != 1) { + auto sslErr = ERR_get_error(); + errMsg = "OpenSSL failed - SSL_CTX_use_PrivateKey_file(\"" + + _tlsOptions.keyFile + "\") failed: "; + errMsg += ERR_error_string(sslErr, nullptr); + } + } + + + ERR_clear_error(); + if (!_tlsOptions.isPeerVerifyDisabled()) { + if (_tlsOptions.isUsingSystemDefaults()) { + if (SSL_CTX_set_default_verify_paths(_ssl_context) == 0) { + auto sslErr = ERR_get_error(); + errMsg = "OpenSSL failed - SSL_CTX_default_verify_paths " + "loading failed: "; + errMsg += ERR_error_string(sslErr, nullptr); + } + } else { + if (_tlsOptions.isUsingInMemoryCAs()) { + // Load from memory + openSSLAddCARootsFromString(_tlsOptions.caFile); + } else { + const char *root_ca_file = _tlsOptions.caFile.c_str(); + STACK_OF(X509_NAME) * rootCAs; + rootCAs = SSL_load_client_CA_file(root_ca_file); + if (rootCAs == NULL) { + auto sslErr = ERR_get_error(); + errMsg = "OpenSSL failed - SSL_load_client_CA_file('" + + _tlsOptions.caFile + "') failed: "; + errMsg += ERR_error_string(sslErr, nullptr); + } else { + SSL_CTX_set_client_CA_list(_ssl_context, rootCAs); + if (SSL_CTX_load_verify_locations(_ssl_context, + root_ca_file, + nullptr) != 1) { + auto sslErr = ERR_get_error(); + errMsg = "OpenSSL failed - " + "SSL_CTX_load_verify_locations(\"" + + _tlsOptions.caFile + "\") failed: "; + errMsg += ERR_error_string(sslErr, nullptr); + } + } + } + } + + SSL_CTX_set_verify(_ssl_context, + SSL_VERIFY_PEER | + SSL_VERIFY_FAIL_IF_NO_PEER_CERT, + nullptr); + SSL_CTX_set_verify_depth(_ssl_context, 4); + } else { + SSL_CTX_set_verify(_ssl_context, SSL_VERIFY_NONE, nullptr); + } + if (_tlsOptions.isUsingDefaultCiphers()) { + if (SSL_CTX_set_cipher_list(_ssl_context, + kDefaultCiphers.c_str()) != 1) { + return false; + } + } else if (SSL_CTX_set_cipher_list(_ssl_context, + _tlsOptions.ciphers.c_str()) != 1) { + return false; + } + + _ssl_connection = SSL_new(_ssl_context); + if (_ssl_connection == nullptr) { + errMsg = "OpenSSL failed to connect"; + SSL_CTX_free(_ssl_context); + _ssl_context = nullptr; + return false; + } + + SSL_set_ecdh_auto(_ssl_connection, 1); + + SSL_set_fd(_ssl_connection, _sockfd); + + handshakeSuccessful = openSSLServerHandshake(errMsg); + } + + if (!handshakeSuccessful) { + close(); + return false; + } + + return true; +} + +bool SocketOpenSSL::connect(const std::string &host, + int port, + std::string &errMsg, + const CancellationRequest &isCancellationRequested) +{ + bool handshakeSuccessful = false; + { + std::lock_guard lock(_mutex); + + if (!_openSSLInitializationSuccessful) { + errMsg = "OPENSSL_init_ssl failure"; + return false; + } + + _sockfd = + SocketConnect::connect(host, port, errMsg, isCancellationRequested); + if (_sockfd == -1) + return false; + + _ssl_context = openSSLCreateContext(errMsg); + if (_ssl_context == nullptr) { + return false; + } + + if (!handleTLSOptions(errMsg)) { + return false; + } + + _ssl_connection = SSL_new(_ssl_context); + if (_ssl_connection == nullptr) { + errMsg = "OpenSSL failed to connect"; + SSL_CTX_free(_ssl_context); + _ssl_context = nullptr; + return false; + } + SSL_set_fd(_ssl_connection, _sockfd); + + // SNI support + SSL_set_tlsext_host_name(_ssl_connection, host.c_str()); + +#if OPENSSL_VERSION_NUMBER >= 0x10002000L + // Support for server name verification + // (The docs say that this should work from 1.0.2, and is the default + // from 1.1.0, but it does not. To be on the safe side, the manual test + // below is enabled for all versions prior to 1.1.0.) + X509_VERIFY_PARAM *param = SSL_get0_param(_ssl_connection); + X509_VERIFY_PARAM_set1_host(param, host.c_str(), 0); +#endif + handshakeSuccessful = + openSSLClientHandshake(host, errMsg, isCancellationRequested); + } + + if (!handshakeSuccessful) { + close(); + return false; + } + + return true; +} + +void SocketOpenSSL::close() +{ + std::lock_guard lock(_mutex); + + if (_ssl_connection != nullptr) { + SSL_free(_ssl_connection); + _ssl_connection = nullptr; + } + if (_ssl_context != nullptr) { + SSL_CTX_free(_ssl_context); + _ssl_context = nullptr; + } + + Socket::close(); +} + +ssize_t SocketOpenSSL::send(char *buf, size_t nbyte) +{ + std::lock_guard lock(_mutex); + + if (_ssl_connection == nullptr || _ssl_context == nullptr) { + return 0; + } + + ERR_clear_error(); + ssize_t write_result = SSL_write(_ssl_connection, buf, (int)nbyte); + int reason = SSL_get_error(_ssl_connection, (int)write_result); + + if (reason == SSL_ERROR_NONE) { + return write_result; + } else if (reason == SSL_ERROR_WANT_READ || + reason == SSL_ERROR_WANT_WRITE) { + errno = EWOULDBLOCK; + return -1; + } else { + return -1; + } +} + +ssize_t SocketOpenSSL::recv(void *buf, size_t nbyte) +{ + while (true) { + std::lock_guard lock(_mutex); + + if (_ssl_connection == nullptr || _ssl_context == nullptr) { + return 0; + } + + ERR_clear_error(); + ssize_t read_result = SSL_read(_ssl_connection, buf, (int)nbyte); + + if (read_result > 0) { + return read_result; + } + + int reason = SSL_get_error(_ssl_connection, (int)read_result); + + if (reason == SSL_ERROR_WANT_READ || reason == SSL_ERROR_WANT_WRITE) { + errno = EWOULDBLOCK; + } + return -1; + } +} + +} // namespace ix + +#endif // IXWEBSOCKET_USE_OPEN_SSL diff --git a/GermanAirlinesVA-GAConnector/ixwebsocket/IXSocketServer.cpp b/GermanAirlinesVA-GAConnector/ixwebsocket/IXSocketServer.cpp new file mode 100644 index 0000000..968b48a --- /dev/null +++ b/GermanAirlinesVA-GAConnector/ixwebsocket/IXSocketServer.cpp @@ -0,0 +1,467 @@ +/* + * IXSocketServer.cpp + * Author: Benjamin Sergeant + * Copyright (c) 2018 Machine Zone, Inc. All rights reserved. + */ + +#include "IXSocketServer.h" + +#include "IXNetSystem.h" +#include "IXSelectInterrupt.h" +#include "IXSelectInterruptFactory.h" +#include "IXSetThreadName.h" +#include "IXSocket.h" +#include "IXSocketConnect.h" +#include "IXSocketFactory.h" +#include +#include +#include +#include + +namespace ix +{ +const int SocketServer::kDefaultPort(8080); +const std::string SocketServer::kDefaultHost("127.0.0.1"); +const int SocketServer::kDefaultTcpBacklog(5); +const size_t SocketServer::kDefaultMaxConnections(128); +const int SocketServer::kDefaultAddressFamily(AF_INET); + +SocketServer::SocketServer(int port, + const std::string &host, + int backlog, + size_t maxConnections, + int addressFamily) + : _port(port), _host(host), _backlog(backlog), + _maxConnections(maxConnections), _addressFamily(addressFamily), + _serverFd(-1), _stop(false), _stopGc(false), + _connectionStateFactory(&ConnectionState::createConnectionState), + _acceptSelectInterrupt(createSelectInterrupt()) +{ +} + +SocketServer::~SocketServer() { stop(); } + +void SocketServer::logError(const std::string &str) +{ + std::lock_guard lock(_logMutex); + fprintf(stderr, "%s\n", str.c_str()); +} + +void SocketServer::logInfo(const std::string &str) +{ + std::lock_guard lock(_logMutex); + fprintf(stdout, "%s\n", str.c_str()); +} + +std::pair SocketServer::listen() +{ + std::string acceptSelectInterruptInitErrorMsg; + if (!_acceptSelectInterrupt->init(acceptSelectInterruptInitErrorMsg)) { + std::stringstream ss; + ss << "SocketServer::listen() error in SelectInterrupt::init: " + << acceptSelectInterruptInitErrorMsg; + + return std::make_pair(false, ss.str()); + } + + if (_addressFamily != AF_INET && _addressFamily != AF_INET6) { + std::string errMsg( + "SocketServer::listen() AF_INET and AF_INET6 are currently " + "the only supported address families"); + return std::make_pair(false, errMsg); + } + + // Get a socket for accepting connections. + if ((_serverFd = socket(_addressFamily, SOCK_STREAM, 0)) < 0) { + std::stringstream ss; + ss << "SocketServer::listen() error creating socket): " + << strerror(Socket::getErrno()); + + return std::make_pair(false, ss.str()); + } + + // Make that socket reusable. (allow restarting this server at will) + int enable = 1; + if (setsockopt(_serverFd, + SOL_SOCKET, + SO_REUSEADDR, + (char *)&enable, + sizeof(enable)) < 0) { + std::stringstream ss; + ss << "SocketServer::listen() error calling setsockopt(SO_REUSEADDR) " + << "at address " << _host << ":" << _port << " : " + << strerror(Socket::getErrno()); + + Socket::closeSocket(_serverFd); + return std::make_pair(false, ss.str()); + } + + if (_addressFamily == AF_INET) { + struct sockaddr_in server; + server.sin_family = _addressFamily; + server.sin_port = htons(_port); + + if (ix::inet_pton(_addressFamily, + _host.c_str(), + &server.sin_addr.s_addr) <= 0) { + std::stringstream ss; + ss << "SocketServer::listen() error calling inet_pton " + << "at address " << _host << ":" << _port << " : " + << strerror(Socket::getErrno()); + + Socket::closeSocket(_serverFd); + return std::make_pair(false, ss.str()); + } + + // Bind the socket to the server address. + if (bind(_serverFd, (struct sockaddr *)&server, sizeof(server)) < 0) { + std::stringstream ss; + ss << "SocketServer::listen() error calling bind " + << "at address " << _host << ":" << _port << " : " + << strerror(Socket::getErrno()); + + Socket::closeSocket(_serverFd); + return std::make_pair(false, ss.str()); + } + } else // AF_INET6 + { + struct sockaddr_in6 server; + server.sin6_family = _addressFamily; + server.sin6_port = htons(_port); + + if (ix::inet_pton(_addressFamily, _host.c_str(), &server.sin6_addr) <= + 0) { + std::stringstream ss; + ss << "SocketServer::listen() error calling inet_pton " + << "at address " << _host << ":" << _port << " : " + << strerror(Socket::getErrno()); + + Socket::closeSocket(_serverFd); + return std::make_pair(false, ss.str()); + } + + // Bind the socket to the server address. + if (bind(_serverFd, (struct sockaddr *)&server, sizeof(server)) < 0) { + std::stringstream ss; + ss << "SocketServer::listen() error calling bind " + << "at address " << _host << ":" << _port << " : " + << strerror(Socket::getErrno()); + + Socket::closeSocket(_serverFd); + return std::make_pair(false, ss.str()); + } + } + + // + // Listen for connections. Specify the tcp backlog. + // + if (::listen(_serverFd, _backlog) < 0) { + std::stringstream ss; + ss << "SocketServer::listen() error calling listen " + << "at address " << _host << ":" << _port << " : " + << strerror(Socket::getErrno()); + + Socket::closeSocket(_serverFd); + return std::make_pair(false, ss.str()); + } + + return std::make_pair(true, ""); +} + +void SocketServer::start() +{ + _stop = false; + + if (!_thread.joinable()) { + _thread = std::thread(&SocketServer::run, this); + } + + if (!_gcThread.joinable()) { + _gcThread = std::thread(&SocketServer::runGC, this); + } +} + +void SocketServer::wait() +{ + std::unique_lock lock(_conditionVariableMutex); + _conditionVariable.wait(lock); +} + +void SocketServer::stopAcceptingConnections() { _stop = true; } + +void SocketServer::stop() +{ + // Stop accepting connections, and close the 'accept' thread + if (_thread.joinable()) { + _stop = true; + // Wake up select + if (!_acceptSelectInterrupt->notify(SelectInterrupt::kCloseRequest)) { + logError("SocketServer::stop: Cannot wake up from select"); + } + + _thread.join(); + _stop = false; + } + + // Join all threads and make sure that all connections are terminated + if (_gcThread.joinable()) { + _stopGc = true; + _conditionVariableGC.notify_one(); + _gcThread.join(); + _stopGc = false; + } + + _conditionVariable.notify_one(); + Socket::closeSocket(_serverFd); +} + +void SocketServer::setConnectionStateFactory( + const ConnectionStateFactory &connectionStateFactory) +{ + _connectionStateFactory = connectionStateFactory; +} + +// +// join the threads for connections that have been closed +// +// When a connection is closed by a client, the connection state terminated +// field becomes true, and we can use that to know that we can join that thread +// and remove it from our _connectionsThreads data structure (a list). +// +void SocketServer::closeTerminatedThreads() +{ + std::lock_guard lock(_connectionsThreadsMutex); + auto it = _connectionsThreads.begin(); + auto itEnd = _connectionsThreads.end(); + + while (it != itEnd) { + auto &connectionState = it->first; + auto &thread = it->second; + + if (!connectionState->isTerminated()) { + ++it; + continue; + } + + if (thread.joinable()) + thread.join(); + it = _connectionsThreads.erase(it); + } +} + +void SocketServer::run() +{ + // Set the socket to non blocking mode, so that accept calls are not + // blocking + SocketConnect::configure(_serverFd); + + setThreadName("SocketServer::accept"); + + for (;;) { + if (_stop) + return; + + // Use poll to check whether a new connection is in progress + int timeoutMs = -1; +#ifdef _WIN32 + // select cannot be interrupted on Windows so we need to pass a small + // timeout + timeoutMs = 10; +#endif + + bool readyToRead = true; + PollResultType pollResult = Socket::poll(readyToRead, + timeoutMs, + _serverFd, + _acceptSelectInterrupt); + + if (pollResult == PollResultType::Error) { + std::stringstream ss; + ss << "SocketServer::run() error in select: " << +#ifndef _WIN32 + strerror(Socket::getErrno()); +#else + + Socket::getErrno(); +#endif + logError(ss.str()); + continue; + } + + if (pollResult != PollResultType::ReadyForRead) { + continue; + } + + // Accept a connection. + // FIXME: Is this working for ipv6 ? + struct sockaddr_in client; // client address information + int clientFd; // socket connected to client + socklen_t addressLen = sizeof(client); + memset(&client, 0, sizeof(client)); + + if ((clientFd = + accept(_serverFd, (struct sockaddr *)&client, &addressLen)) < + 0) { + if (!Socket::isWaitNeeded()) { + // FIXME: that error should be propagated + int err = Socket::getErrno(); + std::stringstream ss; + ss << "SocketServer::run() error accepting connection: " << err + << ", " << strerror(err); + logError(ss.str()); + } + continue; + } + + if (getConnectedClientsCount() >= _maxConnections) { + std::stringstream ss; + ss << "SocketServer::run() reached max connections = " + << _maxConnections << ". " + << "Not accepting connection"; + logError(ss.str()); + + Socket::closeSocket(clientFd); + + continue; + } + + // Retrieve connection info, the ip address of the remote peer/client) + std::string remoteIp; + int remotePort; + + if (_addressFamily == AF_INET) { + char remoteIp4[INET_ADDRSTRLEN]; + if (ix::inet_ntop(AF_INET, + &client.sin_addr, + remoteIp4, + INET_ADDRSTRLEN) == nullptr) { + int err = Socket::getErrno(); + std::stringstream ss; + ss << "SocketServer::run() error calling inet_ntop (ipv4): " + << err << ", " << strerror(err); + logError(ss.str()); + + Socket::closeSocket(clientFd); + + continue; + } + + remotePort = ix::network_to_host_short(client.sin_port); + remoteIp = remoteIp4; + } else // AF_INET6 + { + char remoteIp6[INET6_ADDRSTRLEN]; + if (ix::inet_ntop(AF_INET6, + &client.sin_addr, + remoteIp6, + INET6_ADDRSTRLEN) == nullptr) { + int err = Socket::getErrno(); + std::stringstream ss; + ss << "SocketServer::run() error calling inet_ntop (ipv6): " + << err << ", " << strerror(err); + logError(ss.str()); + + Socket::closeSocket(clientFd); + + continue; + } + + remotePort = ix::network_to_host_short(client.sin_port); + remoteIp = remoteIp6; + } + + std::shared_ptr connectionState; + if (_connectionStateFactory) { + connectionState = _connectionStateFactory(); + } + connectionState->setOnSetTerminatedCallback( + [this] { onSetTerminatedCallback(); }); + connectionState->setRemoteIp(remoteIp); + connectionState->setRemotePort(remotePort); + + if (_stop) + return; + + // create socket + std::string errorMsg; + bool tls = _socketTLSOptions.tls; + auto socket = createSocket(tls, clientFd, errorMsg, _socketTLSOptions); + + if (socket == nullptr) { + logError("SocketServer::run() cannot create socket: " + errorMsg); + Socket::closeSocket(clientFd); + continue; + } + + // Set the socket to non blocking mode + other tweaks + SocketConnect::configure(clientFd); + + if (!socket->accept(errorMsg)) { + logError("SocketServer::run() tls accept failed: " + errorMsg); + Socket::closeSocket(clientFd); + continue; + } + + // Launch the handleConnection work asynchronously in its own thread. + std::lock_guard lock(_connectionsThreadsMutex); + _connectionsThreads.push_back( + std::make_pair(connectionState, + std::thread(&SocketServer::handleConnection, + this, + std::move(socket), + connectionState))); + } +} + +size_t SocketServer::getConnectionsThreadsCount() +{ + std::lock_guard lock(_connectionsThreadsMutex); + return _connectionsThreads.size(); +} + +void SocketServer::runGC() +{ + setThreadName("SocketServer::GC"); + + for (;;) { + // Garbage collection to shutdown/join threads for closed connections. + closeTerminatedThreads(); + + // We quit this thread if all connections are closed and we received + // a stop request by setting _stopGc to true. + if (_stopGc && getConnectionsThreadsCount() == 0) { + break; + } + + // Unless we are stopping the server, wait for a connection + // to be terminated to run the threads GC, instead of busy waiting + // with a sleep + if (!_stopGc) { + std::unique_lock lock(_conditionVariableMutexGC); + _conditionVariableGC.wait(lock); + } + } +} + +void SocketServer::setTLSOptions(const SocketTLSOptions &socketTLSOptions) +{ + _socketTLSOptions = socketTLSOptions; +} + +void SocketServer::onSetTerminatedCallback() +{ + // a connection got terminated, we can run the connection thread GC, + // so wake up the thread responsible for that + _conditionVariableGC.notify_one(); +} + +int SocketServer::getPort() { return _port; } + +std::string SocketServer::getHost() { return _host; } + +int SocketServer::getBacklog() { return _backlog; } + +std::size_t SocketServer::getMaxConnections() { return _maxConnections; } + +int SocketServer::getAddressFamily() { return _addressFamily; } +} // namespace ix diff --git a/GermanAirlinesVA-GAConnector/ixwebsocket/IXSocketTLSOptions.cpp b/GermanAirlinesVA-GAConnector/ixwebsocket/IXSocketTLSOptions.cpp new file mode 100644 index 0000000..c0a84f2 --- /dev/null +++ b/GermanAirlinesVA-GAConnector/ixwebsocket/IXSocketTLSOptions.cpp @@ -0,0 +1,86 @@ +/* + * IXSocketTLSOptions.h + * Author: Matt DeBoer + * Copyright (c) 2019 Machine Zone, Inc. All rights reserved. + */ + +#include "IXSocketTLSOptions.h" + +#include +#include +#include + +namespace ix +{ +const char *kTLSCAFileUseSystemDefaults = "SYSTEM"; +const char *kTLSCAFileDisableVerify = "NONE"; +const char *kTLSCiphersUseDefault = "DEFAULT"; +const char *kTLSInMemoryMarker = "-----BEGIN CERTIFICATE-----"; + +bool SocketTLSOptions::isValid() const +{ + if (!_validated) { + if (!certFile.empty() && !std::ifstream(certFile)) { + _errMsg = "certFile not found: " + certFile; + return false; + } + if (!keyFile.empty() && !std::ifstream(keyFile)) { + _errMsg = "keyFile not found: " + keyFile; + return false; + } + if (!caFile.empty() && caFile != kTLSCAFileDisableVerify && + caFile != kTLSCAFileUseSystemDefaults && !std::ifstream(caFile)) { + _errMsg = "caFile not found: " + caFile; + return false; + } + + if (certFile.empty() != keyFile.empty()) { + _errMsg = + "certFile and keyFile must be both present, or both absent"; + return false; + } + + _validated = true; + } + return true; +} + +bool SocketTLSOptions::hasCertAndKey() const +{ + return !certFile.empty() && !keyFile.empty(); +} + +bool SocketTLSOptions::isUsingSystemDefaults() const +{ + return caFile == kTLSCAFileUseSystemDefaults; +} + +bool SocketTLSOptions::isUsingInMemoryCAs() const +{ + return caFile.find(kTLSInMemoryMarker) != std::string::npos; +} + +bool SocketTLSOptions::isPeerVerifyDisabled() const +{ + return caFile == kTLSCAFileDisableVerify; +} + +bool SocketTLSOptions::isUsingDefaultCiphers() const +{ + return ciphers.empty() || ciphers == kTLSCiphersUseDefault; +} + +const std::string &SocketTLSOptions::getErrorMsg() const { return _errMsg; } + +std::string SocketTLSOptions::getDescription() const +{ + std::stringstream ss; + ss << "TLS Options:" << std::endl; + ss << " certFile = " << certFile << std::endl; + ss << " keyFile = " << keyFile << std::endl; + ss << " caFile = " << caFile << std::endl; + ss << " ciphers = " << ciphers << std::endl; + ss << " ciphers = " << ciphers << std::endl; + return ss.str(); +} +} // namespace ix diff --git a/GermanAirlinesVA-GAConnector/ixwebsocket/IXStrCaseCompare.cpp b/GermanAirlinesVA-GAConnector/ixwebsocket/IXStrCaseCompare.cpp new file mode 100644 index 0000000..ca305e7 --- /dev/null +++ b/GermanAirlinesVA-GAConnector/ixwebsocket/IXStrCaseCompare.cpp @@ -0,0 +1,39 @@ +/* + * IXStrCaseCompare.cpp + * Author: Benjamin Sergeant + * Copyright (c) 2020 Machine Zone. All rights reserved. + */ + +#include "IXStrCaseCompare.h" + +#include +#include + +namespace ix +{ +bool CaseInsensitiveLess::NocaseCompare::operator()( + const unsigned char &c1, + const unsigned char &c2) const +{ +#if defined(_WIN32) && !defined(__GNUC__) + return std::tolower(c1, std::locale()) < std::tolower(c2, std::locale()); +#else + return std::tolower(c1) < std::tolower(c2); +#endif +} + +bool CaseInsensitiveLess::cmp(const std::string &s1, const std::string &s2) +{ + return std::lexicographical_compare(s1.begin(), + s1.end(), // source range + s2.begin(), + s2.end(), // dest range + NocaseCompare()); // comparison +} + +bool CaseInsensitiveLess::operator()(const std::string &s1, + const std::string &s2) const +{ + return CaseInsensitiveLess::cmp(s1, s2); +} +} // namespace ix diff --git a/GermanAirlinesVA-GAConnector/ixwebsocket/IXUdpSocket.cpp b/GermanAirlinesVA-GAConnector/ixwebsocket/IXUdpSocket.cpp new file mode 100644 index 0000000..e64efdb --- /dev/null +++ b/GermanAirlinesVA-GAConnector/ixwebsocket/IXUdpSocket.cpp @@ -0,0 +1,125 @@ +/* + * IXUdpSocket.cpp + * Author: Benjamin Sergeant + * Copyright (c) 2020 Machine Zone, Inc. All rights reserved. + */ + +#include "IXUdpSocket.h" + +#include "IXNetSystem.h" +#include +#include + +namespace ix +{ +UdpSocket::UdpSocket(int fd) : _sockfd(fd) { ; } + +UdpSocket::~UdpSocket() { close(); } + +void UdpSocket::close() +{ + if (_sockfd == -1) + return; + + closeSocket(_sockfd); + _sockfd = -1; +} + +int UdpSocket::getErrno() +{ + int err; + +#ifdef _WIN32 + err = WSAGetLastError(); +#else + err = errno; +#endif + + return err; +} + +bool UdpSocket::isWaitNeeded() +{ + int err = getErrno(); + + if (err == EWOULDBLOCK || err == EAGAIN || err == EINPROGRESS) { + return true; + } + + return false; +} + +void UdpSocket::closeSocket(int fd) +{ +#ifdef _WIN32 + closesocket(fd); +#else + ::close(fd); +#endif +} + +bool UdpSocket::init(const std::string &host, int port, std::string &errMsg) +{ + _sockfd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); + if (_sockfd < 0) { + errMsg = "Could not create socket"; + return false; + } + +#ifdef _WIN32 + unsigned long nonblocking = 1; + ioctlsocket(_sockfd, FIONBIO, &nonblocking); +#else + fcntl(_sockfd, F_SETFL, O_NONBLOCK); // make socket non blocking +#endif + + memset(&_server, 0, sizeof(_server)); + _server.sin_family = AF_INET; + _server.sin_port = htons(port); + + // DNS resolution. + struct addrinfo hints, *result = nullptr; + memset(&hints, 0, sizeof(hints)); + hints.ai_family = AF_INET; + hints.ai_socktype = SOCK_DGRAM; + + int ret = getaddrinfo(host.c_str(), nullptr, &hints, &result); + if (ret != 0) { + errMsg = strerror(UdpSocket::getErrno()); + freeaddrinfo(result); + close(); + return false; + } + + struct sockaddr_in *host_addr = (struct sockaddr_in *)result->ai_addr; + memcpy(&_server.sin_addr, &host_addr->sin_addr, sizeof(struct in_addr)); + freeaddrinfo(result); + + return true; +} + +ssize_t UdpSocket::sendto(const std::string &buffer) +{ + return (ssize_t)::sendto(_sockfd, + buffer.data(), + buffer.size(), + 0, + (struct sockaddr *)&_server, + sizeof(_server)); +} + +ssize_t UdpSocket::recvfrom(char *buffer, size_t length) +{ +#ifdef _WIN32 + int addressLen = (int)sizeof(_server); +#else + socklen_t addressLen = (socklen_t)sizeof(_server); +#endif + return (ssize_t)::recvfrom(_sockfd, + buffer, + length, + 0, + (struct sockaddr *)&_server, + &addressLen); +} +} // namespace ix diff --git a/GermanAirlinesVA-GAConnector/ixwebsocket/IXUrlParser.cpp b/GermanAirlinesVA-GAConnector/ixwebsocket/IXUrlParser.cpp new file mode 100644 index 0000000..6cccc5e --- /dev/null +++ b/GermanAirlinesVA-GAConnector/ixwebsocket/IXUrlParser.cpp @@ -0,0 +1,363 @@ +/* + * Lightweight URL & URI parser (RFC 1738, RFC 3986) + * https://github.com/corporateshark/LUrlParser + * + * The MIT License (MIT) + * + * Copyright (C) 2015 Sergey Kosarevsky (sk@linderdaum.com) + * + * 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. + * + * IXUrlParser.cpp + * Author: Benjamin Sergeant + * Copyright (c) 2019 Machine Zone, Inc. All rights reserved. + */ + +#include "IXUrlParser.h" + +#include +#include +#include + +namespace +{ +enum LUrlParserError { + LUrlParserError_Ok = 0, + LUrlParserError_Uninitialized = 1, + LUrlParserError_NoUrlCharacter = 2, + LUrlParserError_InvalidSchemeName = 3, + LUrlParserError_NoDoubleSlash = 4, + LUrlParserError_NoAtSign = 5, + LUrlParserError_UnexpectedEndOfLine = 6, + LUrlParserError_NoSlash = 7, +}; + +class clParseURL +{ +public: + LUrlParserError m_ErrorCode; + std::string m_Scheme; + std::string m_Host; + std::string m_Port; + std::string m_Path; + std::string m_Query; + std::string m_Fragment; + std::string m_UserName; + std::string m_Password; + + clParseURL() : m_ErrorCode(LUrlParserError_Uninitialized) {} + + /// return 'true' if the parsing was successful + bool IsValid() const { return m_ErrorCode == LUrlParserError_Ok; } + + /// helper to convert the port number to int, return 'true' if the port is + /// valid (within the 0..65535 range) + bool GetPort(int *OutPort) const; + + /// parse the URL + static clParseURL ParseURL(const std::string &URL); + +private: + explicit clParseURL(LUrlParserError ErrorCode) : m_ErrorCode(ErrorCode) {} +}; + +static bool IsSchemeValid(const std::string &SchemeName) +{ + for (auto c : SchemeName) { + if (!isalpha(c) && c != '+' && c != '-' && c != '.') + return false; + } + + return true; +} + +bool clParseURL::GetPort(int *OutPort) const +{ + if (!IsValid()) { + return false; + } + + int Port = atoi(m_Port.c_str()); + + if (Port <= 0 || Port > 65535) { + return false; + } + + if (OutPort) { + *OutPort = Port; + } + + return true; +} + +// based on RFC 1738 and RFC 3986 +clParseURL clParseURL::ParseURL(const std::string &URL) +{ + clParseURL Result; + + const char *CurrentString = URL.c_str(); + + /* + * : + * := [a-z\+\-\.]+ + * For resiliency, programs interpreting URLs should treat upper case + *letters as equivalent to lower case in scheme names + */ + + // try to read scheme + { + const char *LocalString = strchr(CurrentString, ':'); + + if (!LocalString) { + return clParseURL(LUrlParserError_NoUrlCharacter); + } + + // save the scheme name + Result.m_Scheme = + std::string(CurrentString, LocalString - CurrentString); + + if (!IsSchemeValid(Result.m_Scheme)) { + return clParseURL(LUrlParserError_InvalidSchemeName); + } + + // scheme should be lowercase + std::transform(Result.m_Scheme.begin(), + Result.m_Scheme.end(), + Result.m_Scheme.begin(), + ::tolower); + + // skip ':' + CurrentString = LocalString + 1; + } + + /* + * //:@:/ + * any ":", "@" and "/" must be normalized + */ + + // skip "//" + if (*CurrentString++ != '/') + return clParseURL(LUrlParserError_NoDoubleSlash); + if (*CurrentString++ != '/') + return clParseURL(LUrlParserError_NoDoubleSlash); + + // check if the user name and password are specified + bool bHasUserName = false; + + const char *LocalString = CurrentString; + + while (*LocalString) { + if (*LocalString == '@') { + // user name and password are specified + bHasUserName = true; + break; + } else if (*LocalString == '/') { + // end of : specification + bHasUserName = false; + break; + } + + LocalString++; + } + + // user name and password + LocalString = CurrentString; + + if (bHasUserName) { + // read user name + while (*LocalString && *LocalString != ':' && *LocalString != '@') + LocalString++; + + Result.m_UserName = + std::string(CurrentString, LocalString - CurrentString); + + // proceed with the current pointer + CurrentString = LocalString; + + if (*CurrentString == ':') { + // skip ':' + CurrentString++; + + // read password + LocalString = CurrentString; + + while (*LocalString && *LocalString != '@') + LocalString++; + + Result.m_Password = + std::string(CurrentString, LocalString - CurrentString); + + CurrentString = LocalString; + } + + // skip '@' + if (*CurrentString != '@') { + return clParseURL(LUrlParserError_NoAtSign); + } + + CurrentString++; + } + + bool bHasBracket = (*CurrentString == '['); + + // go ahead, read the host name + LocalString = CurrentString; + + while (*LocalString) { + if (bHasBracket && *LocalString == ']') { + // end of IPv6 address + LocalString++; + break; + } else if (!bHasBracket && + (*LocalString == ':' || *LocalString == '/')) { + // port number is specified + break; + } + + LocalString++; + } + + Result.m_Host = std::string(CurrentString, LocalString - CurrentString); + + CurrentString = LocalString; + + // is port number specified? + if (*CurrentString == ':') { + CurrentString++; + + // read port number + LocalString = CurrentString; + + while (*LocalString && *LocalString != '/') + LocalString++; + + Result.m_Port = std::string(CurrentString, LocalString - CurrentString); + + CurrentString = LocalString; + } + + // end of string + if (!*CurrentString) { + Result.m_ErrorCode = LUrlParserError_Ok; + + return Result; + } + + // skip '/' + if (*CurrentString != '/') { + return clParseURL(LUrlParserError_NoSlash); + } + + CurrentString++; + + // parse the path + LocalString = CurrentString; + + while (*LocalString && *LocalString != '#' && *LocalString != '?') + LocalString++; + + Result.m_Path = std::string(CurrentString, LocalString - CurrentString); + + CurrentString = LocalString; + + // check for query + if (*CurrentString == '?') { + // skip '?' + CurrentString++; + + // read query + LocalString = CurrentString; + + while (*LocalString && *LocalString != '#') + LocalString++; + + Result.m_Query = + std::string(CurrentString, LocalString - CurrentString); + + CurrentString = LocalString; + } + + // check for fragment + if (*CurrentString == '#') { + // skip '#' + CurrentString++; + + // read fragment + LocalString = CurrentString; + + while (*LocalString) + LocalString++; + + Result.m_Fragment = + std::string(CurrentString, LocalString - CurrentString); + } + + Result.m_ErrorCode = LUrlParserError_Ok; + + return Result; +} +} // namespace + +namespace ix +{ +bool UrlParser::parse(const std::string &url, + std::string &protocol, + std::string &host, + std::string &path, + std::string &query, + int &port) +{ + clParseURL res = clParseURL::ParseURL(url); + + if (!res.IsValid()) { + return false; + } + + protocol = res.m_Scheme; + host = res.m_Host; + path = res.m_Path; + query = res.m_Query; + + if (!res.GetPort(&port)) { + if (protocol == "ws" || protocol == "http") { + port = 80; + } else if (protocol == "wss" || protocol == "https") { + port = 443; + } else { + // Invalid protocol. Should be caught by regex check + // but this missing branch trigger cpplint linter. + return false; + } + } + + if (path.empty()) { + path = "/"; + } else if (path[0] != '/') { + path = '/' + path; + } + + if (!query.empty()) { + path += "?"; + path += query; + } + + return true; +} + +} // namespace ix diff --git a/GermanAirlinesVA-GAConnector/ixwebsocket/IXUserAgent.cpp b/GermanAirlinesVA-GAConnector/ixwebsocket/IXUserAgent.cpp new file mode 100644 index 0000000..aa9a37e --- /dev/null +++ b/GermanAirlinesVA-GAConnector/ixwebsocket/IXUserAgent.cpp @@ -0,0 +1,92 @@ +/* + * IXUserAgent.cpp + * Author: Benjamin Sergeant + * Copyright (c) 2017-2019 Machine Zone, Inc. All rights reserved. + */ + +#include "IXUserAgent.h" + +#include "IXWebSocketVersion.h" +#include +#ifdef IXWEBSOCKET_USE_ZLIB +#include +#endif + +// Platform name +#if defined(_WIN32) +#define PLATFORM_NAME "windows" // Windows +#elif defined(_WIN64) +#define PLATFORM_NAME "windows" // Windows +#elif defined(__CYGWIN__) && !defined(_WIN32) +#define PLATFORM_NAME "windows" // Windows (Cygwin POSIX under Microsoft Window) +#elif defined(__ANDROID__) +#define PLATFORM_NAME \ + "android" // Android (implies Linux, so it must come first) +#elif defined(__linux__) +#define PLATFORM_NAME \ + "linux" // Debian, Ubuntu, Gentoo, Fedora, openSUSE, RedHat, Centos and + // other +#elif defined(__unix__) || !defined(__APPLE__) && defined(__MACH__) +#include +#if defined(BSD) +#define PLATFORM_NAME "bsd" // FreeBSD, NetBSD, OpenBSD, DragonFly BSD +#endif +#elif defined(__hpux) +#define PLATFORM_NAME "hp-ux" // HP-UX +#elif defined(_AIX) +#define PLATFORM_NAME "aix" // IBM AIX +#elif defined(__APPLE__) && defined(__MACH__) // Apple OSX and iOS (Darwin) +#include +#if TARGET_IPHONE_SIMULATOR == 1 +#define PLATFORM_NAME "ios" // Apple iOS +#elif TARGET_OS_IPHONE == 1 +#define PLATFORM_NAME "ios" // Apple iOS +#elif TARGET_OS_MAC == 1 +#define PLATFORM_NAME "macos" // Apple OSX +#endif +#elif defined(__sun) && defined(__SVR4) +#define PLATFORM_NAME "solaris" // Oracle Solaris, Open Indiana +#else +#define PLATFORM_NAME "unknown platform" +#endif + +// SSL +#ifdef IXWEBSOCKET_USE_MBED_TLS +#include +#elif defined(IXWEBSOCKET_USE_OPEN_SSL) +#include +#endif + +namespace ix +{ +std::string userAgent() +{ + std::stringstream ss; + + // IXWebSocket Version + ss << "ixwebsocket/" << IX_WEBSOCKET_VERSION; + + // Platform + ss << " " << PLATFORM_NAME; + + // TLS +#ifdef IXWEBSOCKET_USE_TLS +#ifdef IXWEBSOCKET_USE_MBED_TLS + ss << " ssl/mbedtls " << MBEDTLS_VERSION_STRING; +#elif defined(IXWEBSOCKET_USE_OPEN_SSL) + ss << " ssl/OpenSSL " << OPENSSL_VERSION_TEXT; +#elif __APPLE__ + ss << " ssl/SecureTransport"; +#endif +#else + ss << " nossl"; +#endif + +#ifdef IXWEBSOCKET_USE_ZLIB + // Zlib version + ss << " zlib " << ZLIB_VERSION; +#endif + + return ss.str(); +} +} // namespace ix diff --git a/GermanAirlinesVA-GAConnector/ixwebsocket/IXUuid.cpp b/GermanAirlinesVA-GAConnector/ixwebsocket/IXUuid.cpp new file mode 100644 index 0000000..103bc47 --- /dev/null +++ b/GermanAirlinesVA-GAConnector/ixwebsocket/IXUuid.cpp @@ -0,0 +1,75 @@ +/* + * IXUuid.cpp + * Author: Benjamin Sergeant + * Copyright (c) 2018 Machine Zone. All rights reserved. + */ + +/** + * Generate a random uuid similar to the uuid python module + * + * >>> import uuid + * >>> uuid.uuid4().hex + * 'bec08155b37d4050a1f3c3fa0276bf12' + * + * Code adapted from https://github.com/r-lyeh-archived/sole + */ + +#include "IXUuid.h" + +#include +#include +#include +#include + + +namespace ix +{ +class Uuid +{ +public: + Uuid(); + std::string toString() const; + +private: + uint64_t _ab; + uint64_t _cd; +}; + +Uuid::Uuid() +{ + static std::random_device rd; + static std::uniform_int_distribution dist(0, (uint64_t)(~0)); + + _ab = dist(rd); + _cd = dist(rd); + + _ab = (_ab & 0xFFFFFFFFFFFF0FFFULL) | 0x0000000000004000ULL; + _cd = (_cd & 0x3FFFFFFFFFFFFFFFULL) | 0x8000000000000000ULL; +} + +std::string Uuid::toString() const +{ + std::stringstream ss; + ss << std::hex << std::nouppercase << std::setfill('0'); + + uint32_t a = (_ab >> 32); + uint32_t b = (_ab & 0xFFFFFFFF); + uint32_t c = (_cd >> 32); + uint32_t d = (_cd & 0xFFFFFFFF); + + ss << std::setw(8) << (a); + ss << std::setw(4) << (b >> 16); + ss << std::setw(4) << (b & 0xFFFF); + ss << std::setw(4) << (c >> 16); + ss << std::setw(4) << (c & 0xFFFF); + ss << std::setw(8) << d; + + return ss.str(); +} + +std::string uuid4() +{ + Uuid id; + return id.toString(); +} +} // namespace ix diff --git a/GermanAirlinesVA-GAConnector/ixwebsocket/IXWebSocket.cpp b/GermanAirlinesVA-GAConnector/ixwebsocket/IXWebSocket.cpp new file mode 100644 index 0000000..efb8e5a --- /dev/null +++ b/GermanAirlinesVA-GAConnector/ixwebsocket/IXWebSocket.cpp @@ -0,0 +1,588 @@ +/* + * IXWebSocket.cpp + * Author: Benjamin Sergeant + * Copyright (c) 2017-2018 Machine Zone, Inc. All rights reserved. + */ + +#include "IXWebSocket.h" + +#include "IXExponentialBackoff.h" +#include "IXSetThreadName.h" +#include "IXUniquePtr.h" +#include "IXUtf8Validator.h" +#include "IXWebSocketHandshake.h" +#include +#include + + +namespace +{ +const std::string emptyMsg; +} // namespace + + +namespace ix +{ +OnTrafficTrackerCallback WebSocket::_onTrafficTrackerCallback = nullptr; +const int WebSocket::kDefaultHandShakeTimeoutSecs(60); +const int WebSocket::kDefaultPingIntervalSecs(-1); +const bool WebSocket::kDefaultEnablePong(true); +const uint32_t + WebSocket::kDefaultMaxWaitBetweenReconnectionRetries(10 * 1000); // 10s +const uint32_t WebSocket::kDefaultMinWaitBetweenReconnectionRetries(1); // 1 ms + +WebSocket::WebSocket() + : _onMessageCallback(OnMessageCallback()), _stop(false), + _automaticReconnection(true), + _maxWaitBetweenReconnectionRetries( + kDefaultMaxWaitBetweenReconnectionRetries), + _minWaitBetweenReconnectionRetries( + kDefaultMinWaitBetweenReconnectionRetries), + _handshakeTimeoutSecs(kDefaultHandShakeTimeoutSecs), + _enablePong(kDefaultEnablePong), + _pingIntervalSecs(kDefaultPingIntervalSecs) +{ + _ws.setOnCloseCallback([this](uint16_t code, + const std::string &reason, + size_t wireSize, + bool remote) { + _onMessageCallback(ix::make_unique( + WebSocketMessageType::Close, + emptyMsg, + wireSize, + WebSocketErrorInfo(), + WebSocketOpenInfo(), + WebSocketCloseInfo(code, reason, remote))); + }); +} + +WebSocket::~WebSocket() +{ + stop(); + _ws.setOnCloseCallback(nullptr); +} + +void WebSocket::setUrl(const std::string &url) +{ + std::lock_guard lock(_configMutex); + _url = url; +} + +void WebSocket::setHandshakeTimeout(int handshakeTimeoutSecs) +{ + _handshakeTimeoutSecs = handshakeTimeoutSecs; +} + +void WebSocket::setExtraHeaders(const WebSocketHttpHeaders &headers) +{ + std::lock_guard lock(_configMutex); + _extraHeaders = headers; +} + +const std::string WebSocket::getUrl() const +{ + std::lock_guard lock(_configMutex); + return _url; +} + +void WebSocket::setPerMessageDeflateOptions( + const WebSocketPerMessageDeflateOptions &perMessageDeflateOptions) +{ + std::lock_guard lock(_configMutex); + _perMessageDeflateOptions = perMessageDeflateOptions; +} + +void WebSocket::setTLSOptions(const SocketTLSOptions &socketTLSOptions) +{ + std::lock_guard lock(_configMutex); + _socketTLSOptions = socketTLSOptions; +} + +const WebSocketPerMessageDeflateOptions + WebSocket::getPerMessageDeflateOptions() const +{ + std::lock_guard lock(_configMutex); + return _perMessageDeflateOptions; +} + +void WebSocket::setPingInterval(int pingIntervalSecs) +{ + std::lock_guard lock(_configMutex); + _pingIntervalSecs = pingIntervalSecs; +} + +int WebSocket::getPingInterval() const +{ + std::lock_guard lock(_configMutex); + return _pingIntervalSecs; +} + +void WebSocket::enablePong() +{ + std::lock_guard lock(_configMutex); + _enablePong = true; +} + +void WebSocket::disablePong() +{ + std::lock_guard lock(_configMutex); + _enablePong = false; +} + +void WebSocket::enablePerMessageDeflate() +{ + std::lock_guard lock(_configMutex); + WebSocketPerMessageDeflateOptions perMessageDeflateOptions(true); + _perMessageDeflateOptions = perMessageDeflateOptions; +} + +void WebSocket::disablePerMessageDeflate() +{ + std::lock_guard lock(_configMutex); + WebSocketPerMessageDeflateOptions perMessageDeflateOptions(false); + _perMessageDeflateOptions = perMessageDeflateOptions; +} + +void WebSocket::setMaxWaitBetweenReconnectionRetries( + uint32_t maxWaitBetweenReconnectionRetries) +{ + std::lock_guard lock(_configMutex); + _maxWaitBetweenReconnectionRetries = maxWaitBetweenReconnectionRetries; +} + +void WebSocket::setMinWaitBetweenReconnectionRetries( + uint32_t minWaitBetweenReconnectionRetries) +{ + std::lock_guard lock(_configMutex); + _minWaitBetweenReconnectionRetries = minWaitBetweenReconnectionRetries; +} + +uint32_t WebSocket::getMaxWaitBetweenReconnectionRetries() const +{ + std::lock_guard lock(_configMutex); + return _maxWaitBetweenReconnectionRetries; +} + +uint32_t WebSocket::getMinWaitBetweenReconnectionRetries() const +{ + std::lock_guard lock(_configMutex); + return _minWaitBetweenReconnectionRetries; +} + +void WebSocket::start() +{ + if (_thread.joinable()) + return; // we've already been started + + _thread = std::thread(&WebSocket::run, this); +} + +void WebSocket::stop(uint16_t code, const std::string &reason) +{ + close(code, reason); + + if (_thread.joinable()) { + // wait until working thread will exit + // it will exit after close operation is finished + _stop = true; + _sleepCondition.notify_one(); + _thread.join(); + _stop = false; + } +} + +WebSocketInitResult WebSocket::connect(int timeoutSecs) +{ + { + std::lock_guard lock(_configMutex); + _ws.configure(_perMessageDeflateOptions, + _socketTLSOptions, + _enablePong, + _pingIntervalSecs); + } + + WebSocketHttpHeaders headers(_extraHeaders); + std::string subProtocolsHeader; + auto subProtocols = getSubProtocols(); + if (!subProtocols.empty()) { + // + // Sub Protocol strings are comma separated. + // Python code to do that is: + // >>> ','.join(['json', 'msgpack']) + // 'json,msgpack' + // + int i = 0; + for (auto subProtocol : subProtocols) { + if (i++ != 0) { + subProtocolsHeader += ","; + } + subProtocolsHeader += subProtocol; + } + headers["Sec-WebSocket-Protocol"] = subProtocolsHeader; + } + + WebSocketInitResult status = _ws.connectToUrl(_url, headers, timeoutSecs); + if (!status.success) { + return status; + } + + _onMessageCallback(ix::make_unique( + WebSocketMessageType::Open, + emptyMsg, + 0, + WebSocketErrorInfo(), + WebSocketOpenInfo(status.uri, status.headers, status.protocol), + WebSocketCloseInfo())); + + if (_pingIntervalSecs > 0) { + // Send a heart beat right away + _ws.sendHeartBeat(); + } + + return status; +} + +WebSocketInitResult WebSocket::connectToSocket(std::unique_ptr socket, + int timeoutSecs, + bool enablePerMessageDeflate) +{ + { + std::lock_guard lock(_configMutex); + _ws.configure(_perMessageDeflateOptions, + _socketTLSOptions, + _enablePong, + _pingIntervalSecs); + } + + WebSocketInitResult status = _ws.connectToSocket(std::move(socket), + timeoutSecs, + enablePerMessageDeflate); + if (!status.success) { + return status; + } + + _onMessageCallback(ix::make_unique( + WebSocketMessageType::Open, + emptyMsg, + 0, + WebSocketErrorInfo(), + WebSocketOpenInfo(status.uri, status.headers), + WebSocketCloseInfo())); + + if (_pingIntervalSecs > 0) { + // Send a heart beat right away + _ws.sendHeartBeat(); + } + + return status; +} + +bool WebSocket::isConnected() const +{ + return getReadyState() == ReadyState::Open; +} + +bool WebSocket::isClosing() const +{ + return getReadyState() == ReadyState::Closing; +} + +void WebSocket::close(uint16_t code, const std::string &reason) +{ + _ws.close(code, reason); +} + +void WebSocket::checkConnection(bool firstConnectionAttempt) +{ + using millis = std::chrono::duration; + + uint32_t retries = 0; + millis duration(0); + + // Try to connect perpertually + while (true) { + if (isConnected() || isClosing() || _stop) { + break; + } + + if (!firstConnectionAttempt && !_automaticReconnection) { + // Do not attempt to reconnect + break; + } + + firstConnectionAttempt = false; + + // Only sleep if we are retrying + if (duration.count() > 0) { + std::unique_lock lock(_sleepMutex); + _sleepCondition.wait_for(lock, duration); + } + + if (_stop) { + break; + } + + // Try to connect synchronously + ix::WebSocketInitResult status = connect(_handshakeTimeoutSecs); + + if (!status.success) { + WebSocketErrorInfo connectErr; + + if (_automaticReconnection) { + duration = millis(calculateRetryWaitMilliseconds( + retries++, + _maxWaitBetweenReconnectionRetries, + _minWaitBetweenReconnectionRetries)); + + connectErr.wait_time = duration.count(); + connectErr.retries = retries; + } + + connectErr.reason = status.errorStr; + connectErr.http_status = status.http_status; + + _onMessageCallback( + ix::make_unique(WebSocketMessageType::Error, + emptyMsg, + 0, + connectErr, + WebSocketOpenInfo(), + WebSocketCloseInfo())); + } + } +} + +void WebSocket::run() +{ + setThreadName(getUrl()); + + bool firstConnectionAttempt = true; + + while (true) { + // 1. Make sure we are always connected + checkConnection(firstConnectionAttempt); + + firstConnectionAttempt = false; + + // if here we are closed then checkConnection was not able to connect + if (getReadyState() == ReadyState::Closed) { + break; + } + + // We can avoid to poll if we want to stop and are not closing + if (_stop && !isClosing()) + break; + + // 2. Poll to see if there's any new data available + WebSocketTransport::PollResult pollResult = _ws.poll(); + + // 3. Dispatch the incoming messages + _ws.dispatch( + pollResult, + [this](const std::string &msg, + size_t wireSize, + bool decompressionError, + WebSocketTransport::MessageKind messageKind) { + WebSocketMessageType webSocketMessageType{ + WebSocketMessageType::Error}; + switch (messageKind) { + case WebSocketTransport::MessageKind::MSG_TEXT: + case WebSocketTransport::MessageKind::MSG_BINARY: { + webSocketMessageType = WebSocketMessageType::Message; + } break; + + case WebSocketTransport::MessageKind::PING: { + webSocketMessageType = WebSocketMessageType::Ping; + } break; + + case WebSocketTransport::MessageKind::PONG: { + webSocketMessageType = WebSocketMessageType::Pong; + } break; + + case WebSocketTransport::MessageKind::FRAGMENT: { + webSocketMessageType = WebSocketMessageType::Fragment; + } break; + } + + WebSocketErrorInfo webSocketErrorInfo; + webSocketErrorInfo.decompressionError = decompressionError; + + bool binary = + messageKind == WebSocketTransport::MessageKind::MSG_BINARY; + + _onMessageCallback( + ix::make_unique(webSocketMessageType, + msg, + wireSize, + webSocketErrorInfo, + WebSocketOpenInfo(), + WebSocketCloseInfo(), + binary)); + + WebSocket::invokeTrafficTrackerCallback(wireSize, true); + }); + } +} + +void WebSocket::setOnMessageCallback(const OnMessageCallback &callback) +{ + _onMessageCallback = callback; +} + +bool WebSocket::isOnMessageCallbackRegistered() const +{ + return _onMessageCallback != nullptr; +} + +void WebSocket::setTrafficTrackerCallback( + const OnTrafficTrackerCallback &callback) +{ + _onTrafficTrackerCallback = callback; +} + +void WebSocket::resetTrafficTrackerCallback() +{ + setTrafficTrackerCallback(nullptr); +} + +void WebSocket::invokeTrafficTrackerCallback(size_t size, bool incoming) +{ + if (_onTrafficTrackerCallback) { + _onTrafficTrackerCallback(size, incoming); + } +} + +WebSocketSendInfo WebSocket::send(const std::string &data, + bool binary, + const OnProgressCallback &onProgressCallback) +{ + return (binary) ? sendBinary(data, onProgressCallback) + : sendText(data, onProgressCallback); +} + +WebSocketSendInfo + WebSocket::sendBinary(const std::string &text, + const OnProgressCallback &onProgressCallback) +{ + return sendMessage(text, SendMessageKind::Binary, onProgressCallback); +} + +WebSocketSendInfo + WebSocket::sendText(const std::string &text, + const OnProgressCallback &onProgressCallback) +{ + if (!validateUtf8(text)) { + close(WebSocketCloseConstants::kInvalidFramePayloadData, + WebSocketCloseConstants::kInvalidFramePayloadDataMessage); + return false; + } + return sendMessage(text, SendMessageKind::Text, onProgressCallback); +} + +WebSocketSendInfo WebSocket::ping(const std::string &text) +{ + // Standard limit ping message size + constexpr size_t pingMaxPayloadSize = 125; + if (text.size() > pingMaxPayloadSize) + return WebSocketSendInfo(false); + + return sendMessage(text, SendMessageKind::Ping); +} + +WebSocketSendInfo + WebSocket::sendMessage(const std::string &text, + SendMessageKind sendMessageKind, + const OnProgressCallback &onProgressCallback) +{ + if (!isConnected()) + return WebSocketSendInfo(false); + + // + // It is OK to read and write on the same socket in 2 different threads. + // https://stackoverflow.com/questions/1981372/are-parallel-calls-to-send-recv-on-the-same-socket-valid + // + // This makes it so that messages are sent right away, and we dont need + // a timeout while we poll to keep wake ups to a minimum (which helps + // with battery life), and use the system select call to notify us when + // incoming messages are arriving / there's data to be received. + // + std::lock_guard lock(_writeMutex); + WebSocketSendInfo webSocketSendInfo; + + switch (sendMessageKind) { + case SendMessageKind::Text: { + webSocketSendInfo = _ws.sendText(text, onProgressCallback); + } break; + + case SendMessageKind::Binary: { + webSocketSendInfo = _ws.sendBinary(text, onProgressCallback); + } break; + + case SendMessageKind::Ping: { + webSocketSendInfo = _ws.sendPing(text); + } break; + } + + WebSocket::invokeTrafficTrackerCallback(webSocketSendInfo.wireSize, false); + + return webSocketSendInfo; +} + +ReadyState WebSocket::getReadyState() const +{ + switch (_ws.getReadyState()) { + case ix::WebSocketTransport::ReadyState::OPEN: + return ReadyState::Open; + case ix::WebSocketTransport::ReadyState::CONNECTING: + return ReadyState::Connecting; + case ix::WebSocketTransport::ReadyState::CLOSING: + return ReadyState::Closing; + case ix::WebSocketTransport::ReadyState::CLOSED: + return ReadyState::Closed; + default: + return ReadyState::Closed; + } +} + +std::string WebSocket::readyStateToString(ReadyState readyState) +{ + switch (readyState) { + case ReadyState::Open: + return "OPEN"; + case ReadyState::Connecting: + return "CONNECTING"; + case ReadyState::Closing: + return "CLOSING"; + case ReadyState::Closed: + return "CLOSED"; + default: + return "UNKNOWN"; + } +} + +void WebSocket::enableAutomaticReconnection() { _automaticReconnection = true; } + +void WebSocket::disableAutomaticReconnection() +{ + _automaticReconnection = false; +} + +bool WebSocket::isAutomaticReconnectionEnabled() const +{ + return _automaticReconnection; +} + +size_t WebSocket::bufferedAmount() const { return _ws.bufferedAmount(); } + +void WebSocket::addSubProtocol(const std::string &subProtocol) +{ + std::lock_guard lock(_configMutex); + _subProtocols.push_back(subProtocol); +} + +const std::vector &WebSocket::getSubProtocols() +{ + std::lock_guard lock(_configMutex); + return _subProtocols; +} +} // namespace ix diff --git a/GermanAirlinesVA-GAConnector/ixwebsocket/IXWebSocketCloseConstants.cpp b/GermanAirlinesVA-GAConnector/ixwebsocket/IXWebSocketCloseConstants.cpp new file mode 100644 index 0000000..6c7159c --- /dev/null +++ b/GermanAirlinesVA-GAConnector/ixwebsocket/IXWebSocketCloseConstants.cpp @@ -0,0 +1,46 @@ +/* + * IXWebSocketCloseConstants.cpp + * Author: Benjamin Sergeant + * Copyright (c) 2019 Machine Zone, Inc. All rights reserved. + */ + +#include "IXWebSocketCloseConstants.h" + +namespace ix +{ +const uint16_t WebSocketCloseConstants::kNormalClosureCode(1000); +const uint16_t WebSocketCloseConstants::kInternalErrorCode(1011); +const uint16_t WebSocketCloseConstants::kAbnormalCloseCode(1006); +const uint16_t WebSocketCloseConstants::kInvalidFramePayloadData(1007); +const uint16_t WebSocketCloseConstants::kProtocolErrorCode(1002); +const uint16_t WebSocketCloseConstants::kNoStatusCodeErrorCode(1005); + +const std::string + WebSocketCloseConstants::kNormalClosureMessage("Normal closure"); +const std::string + WebSocketCloseConstants::kInternalErrorMessage("Internal error"); +const std::string + WebSocketCloseConstants::kAbnormalCloseMessage("Abnormal closure"); +const std::string WebSocketCloseConstants::kPingTimeoutMessage("Ping timeout"); +const std::string + WebSocketCloseConstants::kProtocolErrorMessage("Protocol error"); +const std::string + WebSocketCloseConstants::kNoStatusCodeErrorMessage("No status code"); +const std::string + WebSocketCloseConstants::kProtocolErrorReservedBitUsed("Reserved bit used"); +const std::string WebSocketCloseConstants::kProtocolErrorPingPayloadOversized( + "Ping reason control frame with payload length > 125 octets"); +const std::string + WebSocketCloseConstants::kProtocolErrorCodeControlMessageFragmented( + "Control message fragmented"); +const std::string + WebSocketCloseConstants::kProtocolErrorCodeDataOpcodeOutOfSequence( + "Fragmentation: data message out of sequence"); +const std::string + WebSocketCloseConstants::kProtocolErrorCodeContinuationOpCodeOutOfSequence( + "Fragmentation: continuation opcode out of sequence"); +const std::string WebSocketCloseConstants::kInvalidFramePayloadDataMessage( + "Invalid frame payload data"); +const std::string + WebSocketCloseConstants::kInvalidCloseCodeMessage("Invalid close code"); +} // namespace ix diff --git a/GermanAirlinesVA-GAConnector/ixwebsocket/IXWebSocketHandshake.cpp b/GermanAirlinesVA-GAConnector/ixwebsocket/IXWebSocketHandshake.cpp new file mode 100644 index 0000000..5cd7874 --- /dev/null +++ b/GermanAirlinesVA-GAConnector/ixwebsocket/IXWebSocketHandshake.cpp @@ -0,0 +1,365 @@ +/* + * IXWebSocketHandshake.h + * Author: Benjamin Sergeant + * Copyright (c) 2019 Machine Zone, Inc. All rights reserved. + */ + +#include "IXWebSocketHandshake.h" + +#include "IXHttp.h" +#include "IXSocketConnect.h" +#include "IXStrCaseCompare.h" +#include "IXUrlParser.h" +#include "IXUserAgent.h" +#include "IXWebSocketHandshakeKeyGen.h" +#include +#include +#include +#include + + +namespace ix +{ +WebSocketHandshake::WebSocketHandshake( + std::atomic &requestInitCancellation, + std::unique_ptr &socket, + WebSocketPerMessageDeflatePtr &perMessageDeflate, + WebSocketPerMessageDeflateOptions &perMessageDeflateOptions, + std::atomic &enablePerMessageDeflate) + : _requestInitCancellation(requestInitCancellation), _socket(socket), + _perMessageDeflate(perMessageDeflate), + _perMessageDeflateOptions(perMessageDeflateOptions), + _enablePerMessageDeflate(enablePerMessageDeflate) +{ +} + +bool WebSocketHandshake::insensitiveStringCompare(const std::string &a, + const std::string &b) +{ + return CaseInsensitiveLess::cmp(a, b) == 0; +} + +std::string WebSocketHandshake::genRandomString(const int len) +{ + std::string alphanum = "0123456789" + "ABCDEFGH" + "abcdefgh"; + + std::random_device r; + std::default_random_engine e1(r()); + std::uniform_int_distribution dist(0, (int)alphanum.size() - 1); + + std::string s; + s.resize(len); + + for (int i = 0; i < len; ++i) { + int x = dist(e1); + s[i] = alphanum[x]; + } + + return s; +} + +WebSocketInitResult + WebSocketHandshake::sendErrorResponse(int code, const std::string &reason) +{ + std::stringstream ss; + ss << "HTTP/1.1 "; + ss << code; + ss << " "; + ss << reason; + ss << "\r\n"; + ss << "Server: " << userAgent() << "\r\n"; + + // Socket write can only be cancelled through a timeout here, not manually. + static std::atomic requestInitCancellation(false); + auto isCancellationRequested = + makeCancellationRequestWithTimeout(1, requestInitCancellation); + + if (!_socket->writeBytes(ss.str(), isCancellationRequested)) { + return WebSocketInitResult(false, + 500, + "Timed out while sending error response"); + } + + return WebSocketInitResult(false, code, reason); +} + +WebSocketInitResult WebSocketHandshake::clientHandshake( + const std::string &url, + const WebSocketHttpHeaders &extraHeaders, + const std::string &host, + const std::string &path, + int port, + int timeoutSecs) +{ + _requestInitCancellation = false; + + auto isCancellationRequested = + makeCancellationRequestWithTimeout(timeoutSecs, + _requestInitCancellation); + + std::string errMsg; + bool success = + _socket->connect(host, port, errMsg, isCancellationRequested); + if (!success) { + std::stringstream ss; + ss << "Unable to connect to " << host << " on port " << port + << ", error: " << errMsg; + return WebSocketInitResult(false, 0, ss.str()); + } + + // + // Generate a random 24 bytes string which looks like it is base64 encoded + // y3JJHMbDL1EzLkh9GBhXDw== + // 0cb3Vd9HkbpVVumoS3Noka== + // + // See + // https://stackoverflow.com/questions/18265128/what-is-sec-websocket-key-for + // + std::string secWebSocketKey = genRandomString(22); + secWebSocketKey += "=="; + + std::stringstream ss; + ss << "GET " << path << " HTTP/1.1\r\n"; + ss << "Host: " << host << ":" << port << "\r\n"; + ss << "Upgrade: websocket\r\n"; + ss << "Connection: Upgrade\r\n"; + ss << "Sec-WebSocket-Version: 13\r\n"; + ss << "Sec-WebSocket-Key: " << secWebSocketKey << "\r\n"; + + // User-Agent can be customized by users + if (extraHeaders.find("User-Agent") == extraHeaders.end()) { + ss << "User-Agent: " << userAgent() << "\r\n"; + } + + for (auto &it : extraHeaders) { + ss << it.first << ": " << it.second << "\r\n"; + } + + if (_enablePerMessageDeflate) { + ss << _perMessageDeflateOptions.generateHeader(); + } + + ss << "\r\n"; + + if (!_socket->writeBytes(ss.str(), isCancellationRequested)) { + return WebSocketInitResult( + false, + 0, + std::string("Failed sending GET request to ") + url); + } + + // Read HTTP status line + auto lineResult = _socket->readLine(isCancellationRequested); + auto lineValid = lineResult.first; + auto line = lineResult.second; + + if (!lineValid) { + return WebSocketInitResult( + false, + 0, + std::string("Failed reading HTTP status line from ") + url); + } + + // Validate status + auto statusLine = Http::parseStatusLine(line); + std::string httpVersion = statusLine.first; + int status = statusLine.second; + + // HTTP/1.0 is too old. + if (httpVersion != "HTTP/1.1") { + std::stringstream ss; + ss << "Expecting HTTP/1.1, got " << httpVersion << ". " + << "Rejecting connection to " << url << ", status: " << status + << ", HTTP Status line: " << line; + return WebSocketInitResult(false, status, ss.str()); + } + + auto result = parseHttpHeaders(_socket, isCancellationRequested); + auto headersValid = result.first; + auto headers = result.second; + + if (!headersValid) { + return WebSocketInitResult(false, status, "Error parsing HTTP headers"); + } + + // We want an 101 HTTP status for websocket, otherwise it could be + // a redirection (like 301) + if (status != 101) { + std::stringstream ss; + ss << "Expecting status 101 (Switching Protocol), got " << status + << " status connecting to " << url << ", HTTP Status line: " << line; + + return WebSocketInitResult(false, status, ss.str(), headers, path); + } + + // Check the presence of the connection field + if (headers.find("connection") == headers.end()) { + std::string errorMsg("Missing connection value"); + return WebSocketInitResult(false, status, errorMsg); + } + + // Check the value of the connection field + // Some websocket servers (Go/Gorilla?) send lowercase values for the + // connection header, so do a case insensitive comparison + // + // See + // https://github.com/apache/thrift/commit/7c4bdf9914fcba6c89e0f69ae48b9675578f084a + // + if (!insensitiveStringCompare(headers["connection"], "Upgrade")) { + std::stringstream ss; + ss << "Invalid connection value: " << headers["connection"]; + return WebSocketInitResult(false, status, ss.str()); + } + + char output[29] = {}; + WebSocketHandshakeKeyGen::generate(secWebSocketKey, output); + if (std::string(output) != headers["sec-websocket-accept"]) { + std::string errorMsg("Invalid Sec-WebSocket-Accept value"); + return WebSocketInitResult(false, status, errorMsg); + } + + if (_enablePerMessageDeflate) { + // Parse the server response. Does it support deflate ? + std::string header = headers["sec-websocket-extensions"]; + WebSocketPerMessageDeflateOptions webSocketPerMessageDeflateOptions( + header); + + // If the server does not support that extension, disable it. + if (!webSocketPerMessageDeflateOptions.enabled()) { + _enablePerMessageDeflate = false; + } + // Otherwise try to initialize the deflate engine (zlib) + else if (!_perMessageDeflate->init(webSocketPerMessageDeflateOptions)) { + return WebSocketInitResult( + false, + 0, + "Failed to initialize per message deflate engine"); + } + } + + return WebSocketInitResult(true, status, "", headers, path); +} + +WebSocketInitResult + WebSocketHandshake::serverHandshake(int timeoutSecs, + bool enablePerMessageDeflate) +{ + _requestInitCancellation = false; + + auto isCancellationRequested = + makeCancellationRequestWithTimeout(timeoutSecs, + _requestInitCancellation); + + // Read first line + auto lineResult = _socket->readLine(isCancellationRequested); + auto lineValid = lineResult.first; + auto line = lineResult.second; + + if (!lineValid) { + return sendErrorResponse(400, "Error reading HTTP request line"); + } + + // Validate request line (GET /foo HTTP/1.1\r\n) + auto requestLine = Http::parseRequestLine(line); + auto method = std::get<0>(requestLine); + auto uri = std::get<1>(requestLine); + auto httpVersion = std::get<2>(requestLine); + + if (method != "GET") { + return sendErrorResponse(400, + "Invalid HTTP method, need GET, got " + + method); + } + + if (httpVersion != "HTTP/1.1") { + return sendErrorResponse(400, + "Invalid HTTP version, need HTTP/1.1, got: " + + httpVersion); + } + + // Retrieve and validate HTTP headers + auto result = parseHttpHeaders(_socket, isCancellationRequested); + auto headersValid = result.first; + auto headers = result.second; + + if (!headersValid) { + return sendErrorResponse(400, "Error parsing HTTP headers"); + } + + if (headers.find("sec-websocket-key") == headers.end()) { + return sendErrorResponse(400, "Missing Sec-WebSocket-Key value"); + } + + if (headers.find("upgrade") == headers.end()) { + return sendErrorResponse(400, "Missing Upgrade header"); + } + + if (!insensitiveStringCompare(headers["upgrade"], "WebSocket") && + headers["Upgrade"] != "keep-alive, Upgrade") // special case for firefox + { + return sendErrorResponse(400, + "Invalid Upgrade header, " + "need WebSocket, got " + + headers["upgrade"]); + } + + if (headers.find("sec-websocket-version") == headers.end()) { + return sendErrorResponse(400, "Missing Sec-WebSocket-Version value"); + } + + { + std::stringstream ss; + ss << headers["sec-websocket-version"]; + int version; + ss >> version; + + if (version != 13) { + return sendErrorResponse(400, + "Invalid Sec-WebSocket-Version, " + "need 13, got " + + ss.str()); + } + } + + char output[29] = {}; + WebSocketHandshakeKeyGen::generate(headers["sec-websocket-key"], output); + + std::stringstream ss; + ss << "HTTP/1.1 101 Switching Protocols\r\n"; + ss << "Sec-WebSocket-Accept: " << std::string(output) << "\r\n"; + ss << "Upgrade: websocket\r\n"; + ss << "Connection: Upgrade\r\n"; + ss << "Server: " << userAgent() << "\r\n"; + + // Parse the client headers. Does it support deflate ? + std::string header = headers["sec-websocket-extensions"]; + WebSocketPerMessageDeflateOptions webSocketPerMessageDeflateOptions(header); + + // If the client has requested that extension, + if (webSocketPerMessageDeflateOptions.enabled() && + enablePerMessageDeflate) { + _enablePerMessageDeflate = true; + + if (!_perMessageDeflate->init(webSocketPerMessageDeflateOptions)) { + return WebSocketInitResult( + false, + 0, + "Failed to initialize per message deflate engine"); + } + ss << webSocketPerMessageDeflateOptions.generateHeader(); + } + + ss << "\r\n"; + + if (!_socket->writeBytes(ss.str(), isCancellationRequested)) { + return WebSocketInitResult( + false, + 0, + std::string("Failed sending response to remote end")); + } + + return WebSocketInitResult(true, 200, "", headers, uri); +} +} // namespace ix diff --git a/GermanAirlinesVA-GAConnector/ixwebsocket/IXWebSocketHttpHeaders.cpp b/GermanAirlinesVA-GAConnector/ixwebsocket/IXWebSocketHttpHeaders.cpp new file mode 100644 index 0000000..1100bf3 --- /dev/null +++ b/GermanAirlinesVA-GAConnector/ixwebsocket/IXWebSocketHttpHeaders.cpp @@ -0,0 +1,71 @@ +/* + * IXWebSocketHttpHeaders.h + * Author: Benjamin Sergeant + * Copyright (c) 2018 Machine Zone, Inc. All rights reserved. + */ + +#include "IXWebSocketHttpHeaders.h" + +#include "IXSocket.h" +#include +#include + +namespace ix +{ +std::pair + parseHttpHeaders(std::unique_ptr &socket, + const CancellationRequest &isCancellationRequested) +{ + WebSocketHttpHeaders headers; + + char line[1024]; + int i; + + while (true) { + int colon = 0; + + for (i = 0; + i < 2 || (i < 1023 && line[i - 2] != '\r' && line[i - 1] != '\n'); + ++i) { + if (!socket->readByte(line + i, isCancellationRequested)) { + return std::make_pair(false, headers); + } + + if (line[i] == ':' && colon == 0) { + colon = i; + } + } + if (line[0] == '\r' && line[1] == '\n') { + break; + } + + // line is a single header entry. split by ':', and add it to our + // header map. ignore lines with no colon. + if (colon > 0) { + line[i] = '\0'; + std::string lineStr(line); + // colon is ':', usually colon+1 is ' ', and colon+2 is the start of + // the value. some webservers do not put a space after the colon + // character, so the start of the value might be farther than + // colon+2. The spec says that space after the : should be + // discarded. i is end of string (\0), i-colon is length of string + // minus key; subtract 1 for '\0', 1 for '\n', 1 for '\r', 1 for the + // ' ' after the ':', and total is -4 since we use an std::string + // later on and don't account for '\0', plus the optional first + // space, total is -2 + int start = colon + 1; + while (lineStr[start] == ' ') { + start++; + } + + std::string name(lineStr.substr(0, colon)); + std::string value( + lineStr.substr(start, lineStr.size() - start - 2)); + + headers[name] = value; + } + } + + return std::make_pair(true, headers); +} +} // namespace ix diff --git a/GermanAirlinesVA-GAConnector/ixwebsocket/IXWebSocketPerMessageDeflate.cpp b/GermanAirlinesVA-GAConnector/ixwebsocket/IXWebSocketPerMessageDeflate.cpp new file mode 100644 index 0000000..0106598 --- /dev/null +++ b/GermanAirlinesVA-GAConnector/ixwebsocket/IXWebSocketPerMessageDeflate.cpp @@ -0,0 +1,93 @@ +/* + * Copyright (c) 2015, Peter Thorson. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of the WebSocket++ Project nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL PETER THORSON BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/* + * Author: Benjamin Sergeant + * Copyright (c) 2018 Machine Zone, Inc. All rights reserved. + * + * Adapted from websocketpp/extensions/permessage_deflate/enabled.hpp + * (same license as MZ: https://opensource.org/licenses/BSD-3-Clause) + * + * - Reused zlib compression + decompression bits. + * - Refactored to have 2 class for compression and decompression, to allow + * multi-threading and make sure that _compressBuffer is not shared between + * threads. + * - Original code wasn't working for some reason, I had to add checks + * for the presence of the kEmptyUncompressedBlock at the end of buffer so + * that servers would start accepting receiving/decoding compressed messages. + * Original code was probably modifying the passed in buffers before processing + * in enabled.hpp ? + * - Added more documentation. + * + * Per message Deflate RFC: https://tools.ietf.org/html/rfc7692 + * Chrome websocket -> + * https://github.com/chromium/chromium/tree/2ca8c5037021c9d2ecc00b787d58a31ed8fc8bcb/net/websockets + * + */ + +#include "IXWebSocketPerMessageDeflate.h" + +#include "IXUniquePtr.h" +#include "IXWebSocketPerMessageDeflateCodec.h" +#include "IXWebSocketPerMessageDeflateOptions.h" + +namespace ix +{ +WebSocketPerMessageDeflate::WebSocketPerMessageDeflate() + : _compressor(ix::make_unique()), + _decompressor(ix::make_unique()) +{ + ; +} + +WebSocketPerMessageDeflate::~WebSocketPerMessageDeflate() { ; } + +bool WebSocketPerMessageDeflate::init( + const WebSocketPerMessageDeflateOptions &perMessageDeflateOptions) +{ + bool clientNoContextTakeover = + perMessageDeflateOptions.getClientNoContextTakeover(); + + uint8_t deflateBits = perMessageDeflateOptions.getClientMaxWindowBits(); + uint8_t inflateBits = perMessageDeflateOptions.getServerMaxWindowBits(); + + return _compressor->init(deflateBits, clientNoContextTakeover) && + _decompressor->init(inflateBits, clientNoContextTakeover); +} + +bool WebSocketPerMessageDeflate::compress(const std::string &in, + std::string &out) +{ + return _compressor->compress(in, out); +} + +bool WebSocketPerMessageDeflate::decompress(const std::string &in, + std::string &out) +{ + return _decompressor->decompress(in, out); +} + +} // namespace ix diff --git a/GermanAirlinesVA-GAConnector/ixwebsocket/IXWebSocketPerMessageDeflateCodec.cpp b/GermanAirlinesVA-GAConnector/ixwebsocket/IXWebSocketPerMessageDeflateCodec.cpp new file mode 100644 index 0000000..dc41d33 --- /dev/null +++ b/GermanAirlinesVA-GAConnector/ixwebsocket/IXWebSocketPerMessageDeflateCodec.cpp @@ -0,0 +1,253 @@ +/* + * IXWebSocketPerMessageDeflateCodec.cpp + * Author: Benjamin Sergeant + * Copyright (c) 2018-2019 Machine Zone, Inc. All rights reserved. + */ + +#include "IXWebSocketPerMessageDeflateCodec.h" + +#include "IXWebSocketPerMessageDeflateOptions.h" +#include +#include + +namespace +{ +// The passed in size (4) is important, without it the string litteral +// is treated as a char* and the null termination (\x00) makes it +// look like an empty string. +const std::string kEmptyUncompressedBlock = std::string("\x00\x00\xff\xff", 4); +} // namespace + +namespace ix +{ +// +// Compressor +// +WebSocketPerMessageDeflateCompressor::WebSocketPerMessageDeflateCompressor() +{ +#ifdef IXWEBSOCKET_USE_ZLIB + memset(&_deflateState, 0, sizeof(_deflateState)); + + _deflateState.zalloc = Z_NULL; + _deflateState.zfree = Z_NULL; + _deflateState.opaque = Z_NULL; +#endif +} + +WebSocketPerMessageDeflateCompressor::~WebSocketPerMessageDeflateCompressor() +{ +#ifdef IXWEBSOCKET_USE_ZLIB + deflateEnd(&_deflateState); +#endif +} + +bool WebSocketPerMessageDeflateCompressor::init(uint8_t deflateBits, + bool clientNoContextTakeOver) +{ +#ifdef IXWEBSOCKET_USE_ZLIB + int ret = deflateInit2(&_deflateState, + Z_DEFAULT_COMPRESSION, + Z_DEFLATED, + -1 * deflateBits, + 4, // memory level 1-9 + Z_DEFAULT_STRATEGY); + + if (ret != Z_OK) + return false; + + _flush = (clientNoContextTakeOver) ? Z_FULL_FLUSH : Z_SYNC_FLUSH; + + return true; +#else + return false; +#endif +} + +template +bool WebSocketPerMessageDeflateCompressor::endsWithEmptyUnCompressedBlock( + const T &value) +{ + if (kEmptyUncompressedBlock.size() > value.size()) + return false; + auto N = value.size(); + return value[N - 1] == kEmptyUncompressedBlock[3] && + value[N - 2] == kEmptyUncompressedBlock[2] && + value[N - 3] == kEmptyUncompressedBlock[1] && + value[N - 4] == kEmptyUncompressedBlock[0]; +} + +bool WebSocketPerMessageDeflateCompressor::compress(const std::string &in, + std::string &out) +{ + return compressData(in, out); +} + +bool WebSocketPerMessageDeflateCompressor::compress(const std::string &in, + std::vector &out) +{ + return compressData(in, out); +} + +bool WebSocketPerMessageDeflateCompressor::compress( + const std::vector &in, + std::string &out) +{ + return compressData(in, out); +} + +bool WebSocketPerMessageDeflateCompressor::compress( + const std::vector &in, + std::vector &out) +{ + return compressData(in, out); +} + +template +bool WebSocketPerMessageDeflateCompressor::compressData(const T &in, S &out) +{ +#ifdef IXWEBSOCKET_USE_ZLIB + // + // 7.2.1. Compression + // + // An endpoint uses the following algorithm to compress a message. + // + // 1. Compress all the octets of the payload of the message using + // DEFLATE. + // + // 2. If the resulting data does not end with an empty DEFLATE block + // with no compression (the "BTYPE" bits are set to 00), append an + // empty DEFLATE block with no compression to the tail end. + // + // 3. Remove 4 octets (that are 0x00 0x00 0xff 0xff) from the tail end. + // After this step, the last octet of the compressed data contains + // (possibly part of) the DEFLATE header bits with the "BTYPE" bits + // set to 00. + // + size_t output; + + // Clear output + out.clear(); + + if (in.empty()) { + // See issue #167 + // The normal buffer size should be 6 but + // we remove the 4 octets from the tail (#4) + uint8_t buf[2] = {0x02, 0x00}; + out.push_back(buf[0]); + out.push_back(buf[1]); + + return true; + } + + _deflateState.avail_in = (uInt)in.size(); + _deflateState.next_in = (Bytef *)in.data(); + + do { + // Output to local buffer + _deflateState.avail_out = (uInt)_compressBuffer.size(); + _deflateState.next_out = &_compressBuffer.front(); + + deflate(&_deflateState, _flush); + + output = _compressBuffer.size() - _deflateState.avail_out; + + out.insert(out.end(), + _compressBuffer.begin(), + _compressBuffer.begin() + output); + } while (_deflateState.avail_out == 0); + + if (endsWithEmptyUnCompressedBlock(out)) { + out.resize(out.size() - 4); + } + + return true; +#else + return false; +#endif +} + +// +// Decompressor +// +WebSocketPerMessageDeflateDecompressor::WebSocketPerMessageDeflateDecompressor() +{ +#ifdef IXWEBSOCKET_USE_ZLIB + memset(&_inflateState, 0, sizeof(_inflateState)); + + _inflateState.zalloc = Z_NULL; + _inflateState.zfree = Z_NULL; + _inflateState.opaque = Z_NULL; + _inflateState.avail_in = 0; + _inflateState.next_in = Z_NULL; +#endif +} + +WebSocketPerMessageDeflateDecompressor:: + ~WebSocketPerMessageDeflateDecompressor() +{ +#ifdef IXWEBSOCKET_USE_ZLIB + inflateEnd(&_inflateState); +#endif +} + +bool WebSocketPerMessageDeflateDecompressor::init(uint8_t inflateBits, + bool clientNoContextTakeOver) +{ +#ifdef IXWEBSOCKET_USE_ZLIB + int ret = inflateInit2(&_inflateState, -1 * inflateBits); + + if (ret != Z_OK) + return false; + + _flush = (clientNoContextTakeOver) ? Z_FULL_FLUSH : Z_SYNC_FLUSH; + + return true; +#else + return false; +#endif +} + +bool WebSocketPerMessageDeflateDecompressor::decompress(const std::string &in, + std::string &out) +{ +#ifdef IXWEBSOCKET_USE_ZLIB + // + // 7.2.2. Decompression + // + // An endpoint uses the following algorithm to decompress a message. + // + // 1. Append 4 octets of 0x00 0x00 0xff 0xff to the tail end of the + // payload of the message. + // + // 2. Decompress the resulting data using DEFLATE. + // + std::string inFixed(in); + inFixed += kEmptyUncompressedBlock; + + _inflateState.avail_in = (uInt)inFixed.size(); + _inflateState.next_in = + (unsigned char *)(const_cast(inFixed.data())); + + // Clear output + out.clear(); + + do { + _inflateState.avail_out = (uInt)_compressBuffer.size(); + _inflateState.next_out = &_compressBuffer.front(); + + int ret = inflate(&_inflateState, Z_SYNC_FLUSH); + + if (ret == Z_NEED_DICT || ret == Z_DATA_ERROR || ret == Z_MEM_ERROR) { + return false; // zlib error + } + + out.append(reinterpret_cast(&_compressBuffer.front()), + _compressBuffer.size() - _inflateState.avail_out); + } while (_inflateState.avail_out == 0); + + return true; +#else + return false; +#endif +} +} // namespace ix diff --git a/GermanAirlinesVA-GAConnector/ixwebsocket/IXWebSocketPerMessageDeflateOptions.cpp b/GermanAirlinesVA-GAConnector/ixwebsocket/IXWebSocketPerMessageDeflateOptions.cpp new file mode 100644 index 0000000..3f2b4cb --- /dev/null +++ b/GermanAirlinesVA-GAConnector/ixwebsocket/IXWebSocketPerMessageDeflateOptions.cpp @@ -0,0 +1,193 @@ +/* + * IXWebSocketPerMessageDeflateOptions.cpp + * Author: Benjamin Sergeant + * Copyright (c) 2018 Machine Zone, Inc. All rights reserved. + */ + +#include "IXWebSocketPerMessageDeflateOptions.h" + +#include +#include +#include + +namespace ix +{ +/// Default values as defined in the RFC +const uint8_t WebSocketPerMessageDeflateOptions::kDefaultServerMaxWindowBits = + 15; +static const uint8_t minServerMaxWindowBits = 8; +static const uint8_t maxServerMaxWindowBits = 15; + +const uint8_t WebSocketPerMessageDeflateOptions::kDefaultClientMaxWindowBits = + 15; +static const uint8_t minClientMaxWindowBits = 8; +static const uint8_t maxClientMaxWindowBits = 15; + +WebSocketPerMessageDeflateOptions::WebSocketPerMessageDeflateOptions( + bool enabled, + bool clientNoContextTakeover, + bool serverNoContextTakeover, + uint8_t clientMaxWindowBits, + uint8_t serverMaxWindowBits) +{ + _enabled = enabled; + _clientNoContextTakeover = clientNoContextTakeover; + _serverNoContextTakeover = serverNoContextTakeover; + _clientMaxWindowBits = clientMaxWindowBits; + _serverMaxWindowBits = serverMaxWindowBits; + + sanitizeClientMaxWindowBits(); +} + +// +// Four extension parameters are defined for "permessage-deflate" to +// help endpoints manage per-connection resource usage. +// +// - "server_no_context_takeover" +// - "client_no_context_takeover" +// - "server_max_window_bits" +// - "client_max_window_bits" +// +// Server response could look like that: +// +// Sec-WebSocket-Extensions: permessage-deflate; client_no_context_takeover; +// server_no_context_takeover +// +WebSocketPerMessageDeflateOptions::WebSocketPerMessageDeflateOptions( + std::string extension) +{ + extension = removeSpaces(extension); + + _enabled = false; + _clientNoContextTakeover = false; + _serverNoContextTakeover = false; + _clientMaxWindowBits = kDefaultClientMaxWindowBits; + _serverMaxWindowBits = kDefaultServerMaxWindowBits; + +#ifdef IXWEBSOCKET_USE_ZLIB + // Split by ; + std::string token; + std::stringstream tokenStream(extension); + + while (std::getline(tokenStream, token, ';')) { + if (token == "permessage-deflate") { + _enabled = true; + } + + if (token == "server_no_context_takeover") { + _serverNoContextTakeover = true; + } + + if (token == "client_no_context_takeover") { + _clientNoContextTakeover = true; + } + + if (startsWith(token, "server_max_window_bits=")) { + uint8_t x = + strtol(token.substr(token.find_last_of("=") + 1).c_str(), + nullptr, + 10); + + // Sanitize values to be in the proper range [8, 15] in + // case a server would give us bogus values + _serverMaxWindowBits = + std::min(maxServerMaxWindowBits, + std::max(x, minServerMaxWindowBits)); + } + + if (startsWith(token, "client_max_window_bits=")) { + uint8_t x = + strtol(token.substr(token.find_last_of("=") + 1).c_str(), + nullptr, + 10); + + // Sanitize values to be in the proper range [8, 15] in + // case a server would give us bogus values + _clientMaxWindowBits = + std::min(maxClientMaxWindowBits, + std::max(x, minClientMaxWindowBits)); + + sanitizeClientMaxWindowBits(); + } + } +#endif +} + +void WebSocketPerMessageDeflateOptions::sanitizeClientMaxWindowBits() +{ + // zlib/deflate has a bug with windowsbits == 8, so we silently upgrade it + // to 9 See https://bugs.chromium.org/p/chromium/issues/detail?id=691074 + if (_clientMaxWindowBits == 8) { + _clientMaxWindowBits = 9; + } +} + +std::string WebSocketPerMessageDeflateOptions::generateHeader() +{ +#ifdef IXWEBSOCKET_USE_ZLIB + std::stringstream ss; + ss << "Sec-WebSocket-Extensions: permessage-deflate"; + + if (_clientNoContextTakeover) + ss << "; client_no_context_takeover"; + if (_serverNoContextTakeover) + ss << "; server_no_context_takeover"; + + ss << "; server_max_window_bits=" << _serverMaxWindowBits; + ss << "; client_max_window_bits=" << _clientMaxWindowBits; + + ss << "\r\n"; + + return ss.str(); +#else + return std::string(); +#endif +} + +bool WebSocketPerMessageDeflateOptions::enabled() const +{ +#ifdef IXWEBSOCKET_USE_ZLIB + return _enabled; +#else + return false; +#endif +} + +bool WebSocketPerMessageDeflateOptions::getClientNoContextTakeover() const +{ + return _clientNoContextTakeover; +} + +bool WebSocketPerMessageDeflateOptions::getServerNoContextTakeover() const +{ + return _serverNoContextTakeover; +} + +uint8_t WebSocketPerMessageDeflateOptions::getClientMaxWindowBits() const +{ + return _clientMaxWindowBits; +} + +uint8_t WebSocketPerMessageDeflateOptions::getServerMaxWindowBits() const +{ + return _serverMaxWindowBits; +} + +bool WebSocketPerMessageDeflateOptions::startsWith(const std::string &str, + const std::string &start) +{ + return str.compare(0, start.length(), start) == 0; +} + +std::string + WebSocketPerMessageDeflateOptions::removeSpaces(const std::string &str) +{ + std::string out(str); + out.erase(std::remove_if(out.begin(), + out.end(), + [](unsigned char x) { return std::isspace(x); }), + out.end()); + + return out; +} +} // namespace ix diff --git a/GermanAirlinesVA-GAConnector/ixwebsocket/IXWebSocketProxyServer.cpp b/GermanAirlinesVA-GAConnector/ixwebsocket/IXWebSocketProxyServer.cpp new file mode 100644 index 0000000..a4ac231 --- /dev/null +++ b/GermanAirlinesVA-GAConnector/ixwebsocket/IXWebSocketProxyServer.cpp @@ -0,0 +1,117 @@ +/* + * IXWebSocketProxyServer.cpp + * Author: Benjamin Sergeant + * Copyright (c) 2018 Machine Zone, Inc. All rights reserved. + */ + +#include "IXWebSocketProxyServer.h" + +#include "IXWebSocketServer.h" +#include + +namespace ix +{ +class ProxyConnectionState : public ix::ConnectionState +{ +public: + ProxyConnectionState() : _connected(false) {} + + ix::WebSocket &webSocket() { return _serverWebSocket; } + + bool isConnected() { return _connected; } + + void setConnected() { _connected = true; } + +private: + ix::WebSocket _serverWebSocket; + bool _connected; +}; + +int websocket_proxy_server_main(int port, + const std::string &hostname, + const ix::SocketTLSOptions &tlsOptions, + const std::string &remoteUrl, + const RemoteUrlsMapping &remoteUrlsMapping, + bool /*verbose*/) +{ + ix::WebSocketServer server(port, hostname); + server.setTLSOptions(tlsOptions); + + auto factory = []() -> std::shared_ptr { + return std::make_shared(); + }; + server.setConnectionStateFactory(factory); + + server.setOnConnectionCallback( + [remoteUrl, + remoteUrlsMapping](std::weak_ptr webSocket, + std::shared_ptr connectionState) { + auto state = std::dynamic_pointer_cast( + connectionState); + auto remoteIp = connectionState->getRemoteIp(); + + // Server connection + state->webSocket().setOnMessageCallback( + [webSocket, state, remoteIp](const WebSocketMessagePtr &msg) { + if (msg->type == ix::WebSocketMessageType::Close) { + state->setTerminated(); + } else if (msg->type == ix::WebSocketMessageType::Message) { + auto ws = webSocket.lock(); + if (ws) { + ws->send(msg->str, msg->binary); + } + } + }); + + // Client connection + auto ws = webSocket.lock(); + if (ws) { + ws->setOnMessageCallback([state, remoteUrl, remoteUrlsMapping]( + const WebSocketMessagePtr &msg) { + if (msg->type == ix::WebSocketMessageType::Open) { + // Connect to the 'real' server + std::string url(remoteUrl); + + // maybe we want a different url based on the mapping + std::string host = msg->openInfo.headers["Host"]; + auto it = remoteUrlsMapping.find(host); + if (it != remoteUrlsMapping.end()) { + url = it->second; + } + + // append the uri to form the full url + // (say ws://localhost:1234/foo/?bar=baz) + url += msg->openInfo.uri; + + state->webSocket().setUrl(url); + state->webSocket().disableAutomaticReconnection(); + state->webSocket().start(); + + // we should sleep here for a bit until we've + // established the connection with the remote server + while (state->webSocket().getReadyState() != + ReadyState::Open) { + std::this_thread::sleep_for( + std::chrono::milliseconds(10)); + } + } else if (msg->type == ix::WebSocketMessageType::Close) { + state->webSocket().close(msg->closeInfo.code, + msg->closeInfo.reason); + } else if (msg->type == ix::WebSocketMessageType::Message) { + state->webSocket().send(msg->str, msg->binary); + } + }); + } + }); + + auto res = server.listen(); + if (!res.first) { + return 1; + } + + server.start(); + server.wait(); + + return 0; +} +} // namespace ix diff --git a/GermanAirlinesVA-GAConnector/ixwebsocket/IXWebSocketServer.cpp b/GermanAirlinesVA-GAConnector/ixwebsocket/IXWebSocketServer.cpp new file mode 100644 index 0000000..dca3a18 --- /dev/null +++ b/GermanAirlinesVA-GAConnector/ixwebsocket/IXWebSocketServer.cpp @@ -0,0 +1,206 @@ +/* + * IXWebSocketServer.cpp + * Author: Benjamin Sergeant + * Copyright (c) 2018 Machine Zone, Inc. All rights reserved. + */ + +#include "IXWebSocketServer.h" + +#include "IXNetSystem.h" +#include "IXSetThreadName.h" +#include "IXSocketConnect.h" +#include "IXWebSocket.h" +#include "IXWebSocketTransport.h" +#include +#include +#include + +namespace ix +{ +const int WebSocketServer::kDefaultHandShakeTimeoutSecs(3); // 3 seconds +const bool WebSocketServer::kDefaultEnablePong(true); + +WebSocketServer::WebSocketServer(int port, + const std::string &host, + int backlog, + size_t maxConnections, + int handshakeTimeoutSecs, + int addressFamily) + : SocketServer(port, host, backlog, maxConnections, addressFamily), + _handshakeTimeoutSecs(handshakeTimeoutSecs), + _enablePong(kDefaultEnablePong), _enablePerMessageDeflate(true) +{ +} + +WebSocketServer::~WebSocketServer() { stop(); } + +void WebSocketServer::stop() +{ + stopAcceptingConnections(); + + auto clients = getClients(); + for (auto client : clients) { + client->close(); + } + + SocketServer::stop(); +} + +void WebSocketServer::enablePong() { _enablePong = true; } + +void WebSocketServer::disablePong() { _enablePong = false; } + +void WebSocketServer::disablePerMessageDeflate() +{ + _enablePerMessageDeflate = false; +} + +void WebSocketServer::setOnConnectionCallback( + const OnConnectionCallback &callback) +{ + _onConnectionCallback = callback; +} + +void WebSocketServer::setOnClientMessageCallback( + const OnClientMessageCallback &callback) +{ + _onClientMessageCallback = callback; +} + +void WebSocketServer::handleConnection( + std::unique_ptr socket, + std::shared_ptr connectionState) +{ + setThreadName("WebSocketServer::" + connectionState->getId()); + + auto webSocket = std::make_shared(); + if (_onConnectionCallback) { + _onConnectionCallback(webSocket, connectionState); + + if (!webSocket->isOnMessageCallbackRegistered()) { + logError("WebSocketServer Application developer error: Server " + "callback improperly " + "registerered."); + logError("Missing call to setOnMessageCallback inside " + "setOnConnectionCallback."); + connectionState->setTerminated(); + return; + } + } else if (_onClientMessageCallback) { + WebSocket *webSocketRawPtr = webSocket.get(); + webSocket->setOnMessageCallback([this, + webSocketRawPtr, + connectionState]( + const WebSocketMessagePtr &msg) { + _onClientMessageCallback(connectionState, *webSocketRawPtr, msg); + }); + } else { + logError("WebSocketServer Application developer error: No server " + "callback is registerered."); + logError("Missing call to setOnConnectionCallback or " + "setOnClientMessageCallback."); + connectionState->setTerminated(); + return; + } + + webSocket->disableAutomaticReconnection(); + + if (_enablePong) { + webSocket->enablePong(); + } else { + webSocket->disablePong(); + } + + // Add this client to our client set + { + std::lock_guard lock(_clientsMutex); + _clients.insert(webSocket); + } + + auto status = webSocket->connectToSocket(std::move(socket), + _handshakeTimeoutSecs, + _enablePerMessageDeflate); + if (status.success) { + // Process incoming messages and execute callbacks + // until the connection is closed + webSocket->run(); + } else { + std::stringstream ss; + ss << "WebSocketServer::handleConnection() HTTP status: " + << status.http_status << " error: " << status.errorStr; + logError(ss.str()); + } + + webSocket->setOnMessageCallback(nullptr); + + // Remove this client from our client set + { + std::lock_guard lock(_clientsMutex); + if (_clients.erase(webSocket) != 1) { + logError("Cannot delete client"); + } + } + + connectionState->setTerminated(); +} + +std::set> WebSocketServer::getClients() +{ + std::lock_guard lock(_clientsMutex); + return _clients; +} + +size_t WebSocketServer::getConnectedClientsCount() +{ + std::lock_guard lock(_clientsMutex); + return _clients.size(); +} + +// +// Classic servers +// +void WebSocketServer::makeBroadcastServer() +{ + setOnClientMessageCallback( + [this](std::shared_ptr connectionState, + WebSocket &webSocket, + const WebSocketMessagePtr &msg) { + auto remoteIp = connectionState->getRemoteIp(); + if (msg->type == ix::WebSocketMessageType::Message) { + for (auto &&client : getClients()) { + if (client.get() != &webSocket) { + client->send(msg->str, msg->binary); + + // Make sure the OS send buffer is flushed before moving + // on + do { + std::chrono::duration duration( + 500); + std::this_thread::sleep_for(duration); + } while (client->bufferedAmount() != 0); + } + } + } + }); +} + +bool WebSocketServer::listenAndStart() +{ + auto res = listen(); + if (!res.first) { + return false; + } + + start(); + return true; +} + +int WebSocketServer::getHandshakeTimeoutSecs() { return _handshakeTimeoutSecs; } + +bool WebSocketServer::isPongEnabled() { return _enablePong; } + +bool WebSocketServer::isPerMessageDeflateEnabled() +{ + return _enablePerMessageDeflate; +} +} // namespace ix diff --git a/GermanAirlinesVA-GAConnector/ixwebsocket/IXWebSocketTransport.cpp b/GermanAirlinesVA-GAConnector/ixwebsocket/IXWebSocketTransport.cpp new file mode 100644 index 0000000..e35848b --- /dev/null +++ b/GermanAirlinesVA-GAConnector/ixwebsocket/IXWebSocketTransport.cpp @@ -0,0 +1,1130 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2012, 2013 + * + * 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. + */ + +/* + * IXWebSocketTransport.cpp + * Author: Benjamin Sergeant + * Copyright (c) 2017-2019 Machine Zone, Inc. All rights reserved. + */ + +// +// Adapted from https://github.com/dhbaird/easywsclient +// + +#include "IXWebSocketTransport.h" + +#include "IXSocketFactory.h" +#include "IXSocketTLSOptions.h" +#include "IXUniquePtr.h" +#include "IXUrlParser.h" +#include "IXUtf8Validator.h" +#include "IXWebSocketHandshake.h" +#include "IXWebSocketHttpHeaders.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +namespace ix +{ +const std::string WebSocketTransport::kPingMessage("ixwebsocket::heartbeat"); +const int WebSocketTransport::kDefaultPingIntervalSecs(-1); +const bool WebSocketTransport::kDefaultEnablePong(true); +const int WebSocketTransport::kClosingMaximumWaitingDelayInMs(300); +constexpr size_t WebSocketTransport::kChunkSize; + +WebSocketTransport::WebSocketTransport() + : _useMask(true), _blockingSend(false), _receivedMessageCompressed(false), + _readyState(ReadyState::CLOSED), + _closeCode(WebSocketCloseConstants::kInternalErrorCode), + _closeWireSize(0), _closeRemote(false), _enablePerMessageDeflate(false), + _requestInitCancellation(false), + _closingTimePoint(std::chrono::steady_clock::now()), + _enablePong(kDefaultEnablePong), + _pingIntervalSecs(kDefaultPingIntervalSecs), _pongReceived(false), + _pingCount(0), _lastSendPingTimePoint(std::chrono::steady_clock::now()) +{ + setCloseReason(WebSocketCloseConstants::kInternalErrorMessage); + _readbuf.resize(kChunkSize); +} + +WebSocketTransport::~WebSocketTransport() { ; } + +void WebSocketTransport::configure( + const WebSocketPerMessageDeflateOptions &perMessageDeflateOptions, + const SocketTLSOptions &socketTLSOptions, + bool enablePong, + int pingIntervalSecs) +{ + _perMessageDeflateOptions = perMessageDeflateOptions; + _enablePerMessageDeflate = _perMessageDeflateOptions.enabled(); + _socketTLSOptions = socketTLSOptions; + _enablePong = enablePong; + _pingIntervalSecs = pingIntervalSecs; +} + +// Client +WebSocketInitResult + WebSocketTransport::connectToUrl(const std::string &url, + const WebSocketHttpHeaders &headers, + int timeoutSecs) +{ + std::lock_guard lock(_socketMutex); + + std::string protocol, host, path, query; + int port; + std::string remoteUrl(url); + + WebSocketInitResult result; + const int maxRedirections = 10; + + for (int i = 0; i < maxRedirections; ++i) { + if (!UrlParser::parse(remoteUrl, protocol, host, path, query, port)) { + std::stringstream ss; + ss << "Could not parse url: '" << url << "'"; + return WebSocketInitResult(false, 0, ss.str()); + } + + std::string errorMsg; + bool tls = protocol == "wss"; + _socket = createSocket(tls, -1, errorMsg, _socketTLSOptions); + _perMessageDeflate = ix::make_unique(); + + if (!_socket) { + return WebSocketInitResult(false, 0, errorMsg); + } + + WebSocketHandshake webSocketHandshake(_requestInitCancellation, + _socket, + _perMessageDeflate, + _perMessageDeflateOptions, + _enablePerMessageDeflate); + + result = webSocketHandshake.clientHandshake(remoteUrl, + headers, + host, + path, + port, + timeoutSecs); + + if (result.http_status >= 300 && result.http_status < 400) { + auto it = result.headers.find("Location"); + if (it == result.headers.end()) { + std::stringstream ss; + ss << "Missing Location Header for HTTP Redirect response. " + << "Rejecting connection to " << url + << ", status: " << result.http_status; + result.errorStr = ss.str(); + break; + } + + remoteUrl = it->second; + continue; + } + + if (result.success) { + setReadyState(ReadyState::OPEN); + } + return result; + } + + return result; +} + +// Server +WebSocketInitResult + WebSocketTransport::connectToSocket(std::unique_ptr socket, + int timeoutSecs, + bool enablePerMessageDeflate) +{ + std::lock_guard lock(_socketMutex); + + // Server should not mask the data it sends to the client + _useMask = false; + _blockingSend = true; + + _socket = std::move(socket); + _perMessageDeflate = ix::make_unique(); + + WebSocketHandshake webSocketHandshake(_requestInitCancellation, + _socket, + _perMessageDeflate, + _perMessageDeflateOptions, + _enablePerMessageDeflate); + + auto result = webSocketHandshake.serverHandshake(timeoutSecs, + enablePerMessageDeflate); + if (result.success) { + setReadyState(ReadyState::OPEN); + } + return result; +} + +WebSocketTransport::ReadyState WebSocketTransport::getReadyState() const +{ + return _readyState; +} + +void WebSocketTransport::setReadyState(ReadyState readyState) +{ + // No state change, return + if (_readyState == readyState) + return; + + if (readyState == ReadyState::CLOSED) { + if (_onCloseCallback) { + _onCloseCallback(_closeCode, + getCloseReason(), + _closeWireSize, + _closeRemote); + } + setCloseReason(WebSocketCloseConstants::kInternalErrorMessage); + _closeCode = WebSocketCloseConstants::kInternalErrorCode; + _closeWireSize = 0; + _closeRemote = false; + } else if (readyState == ReadyState::OPEN) { + initTimePointsAfterConnect(); + _pongReceived = false; + } + + _readyState = readyState; +} + +void WebSocketTransport::setOnCloseCallback( + const OnCloseCallback &onCloseCallback) +{ + _onCloseCallback = onCloseCallback; +} + +void WebSocketTransport::initTimePointsAfterConnect() +{ + { + std::lock_guard lock(_lastSendPingTimePointMutex); + _lastSendPingTimePoint = std::chrono::steady_clock::now(); + } +} + +// Only consider send PING time points for that computation. +bool WebSocketTransport::pingIntervalExceeded() +{ + if (_pingIntervalSecs <= 0) + return false; + + std::lock_guard lock(_lastSendPingTimePointMutex); + auto now = std::chrono::steady_clock::now(); + return now - _lastSendPingTimePoint > + std::chrono::seconds(_pingIntervalSecs); +} + +WebSocketSendInfo WebSocketTransport::sendHeartBeat() +{ + _pongReceived = false; + std::stringstream ss; + ss << kPingMessage << "::" << _pingIntervalSecs << "s" + << "::" << _pingCount++; + return sendPing(ss.str()); +} + +bool WebSocketTransport::closingDelayExceeded() +{ + std::lock_guard lock(_closingTimePointMutex); + auto now = std::chrono::steady_clock::now(); + return now - _closingTimePoint > + std::chrono::milliseconds(kClosingMaximumWaitingDelayInMs); +} + +WebSocketTransport::PollResult WebSocketTransport::poll() +{ + if (_readyState == ReadyState::OPEN) { + if (pingIntervalExceeded()) { + if (!_pongReceived) { + // ping response (PONG) exceeds the maximum delay, close the + // connection + close(WebSocketCloseConstants::kInternalErrorCode, + WebSocketCloseConstants::kPingTimeoutMessage); + } else { + sendHeartBeat(); + } + } + } + + // No timeout if state is not OPEN, otherwise computed + // pingIntervalOrTimeoutGCD (equals to -1 if no ping and no ping timeout are + // set) + int lastingTimeoutDelayInMs = + (_readyState != ReadyState::OPEN) ? 0 : _pingIntervalSecs; + + if (_pingIntervalSecs > 0) { + // compute lasting delay to wait for next ping / timeout, if at least + // one set + auto now = std::chrono::steady_clock::now(); + int timeSinceLastPingMs = + (int)std::chrono::duration_cast( + now - _lastSendPingTimePoint) + .count(); + lastingTimeoutDelayInMs = + (1000 * _pingIntervalSecs) - timeSinceLastPingMs; + } + +#ifdef _WIN32 + // Windows does not have select interrupt capabilities, so wait with a small + // timeout + if (lastingTimeoutDelayInMs <= 0) { + lastingTimeoutDelayInMs = 20; + } +#endif + + // If we are requesting a cancellation, pass in a positive and small timeout + // to never poll forever without a timeout. + if (_requestInitCancellation) { + lastingTimeoutDelayInMs = 100; + } + + // poll the socket + PollResultType pollResult = _socket->isReadyToRead(lastingTimeoutDelayInMs); + + // Make sure we send all the buffered data + // there can be a lot of it for large messages. + if (pollResult == PollResultType::SendRequest) { + if (!flushSendBuffer()) { + return PollResult::CannotFlushSendBuffer; + } + } else if (pollResult == PollResultType::ReadyForRead) { + if (!receiveFromSocket()) { + return PollResult::AbnormalClose; + } + } else if (pollResult == PollResultType::Error) { + closeSocket(); + } else if (pollResult == PollResultType::CloseRequest) { + closeSocket(); + } + + if (_readyState == ReadyState::CLOSING && closingDelayExceeded()) { + _rxbuf.clear(); + // close code and reason were set when calling close() + closeSocket(); + setReadyState(ReadyState::CLOSED); + } + + return PollResult::Succeeded; +} + +bool WebSocketTransport::isSendBufferEmpty() const +{ + std::lock_guard lock(_txbufMutex); + return _txbuf.empty(); +} + +template +void WebSocketTransport::appendToSendBuffer(const std::vector &header, + Iterator begin, + Iterator end, + uint64_t message_size, + uint8_t masking_key[4]) +{ + std::lock_guard lock(_txbufMutex); + + _txbuf.insert(_txbuf.end(), header.begin(), header.end()); + _txbuf.insert(_txbuf.end(), begin, end); + + if (_useMask) { + for (size_t i = 0; i != (size_t)message_size; ++i) { + *(_txbuf.end() - (size_t)message_size + i) ^= masking_key[i & 0x3]; + } + } +} + +void WebSocketTransport::unmaskReceiveBuffer(const wsheader_type &ws) +{ + if (ws.mask) { + for (size_t j = 0; j != ws.N; ++j) { + _rxbuf[j + ws.header_size] ^= ws.masking_key[j & 0x3]; + } + } +} + +// +// http://tools.ietf.org/html/rfc6455#section-5.2 Base Framing Protocol +// +// 0 1 2 3 +// 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 +// +-+-+-+-+-------+-+-------------+-------------------------------+ +// |F|R|R|R| opcode|M| Payload len | Extended payload length | +// |I|S|S|S| (4) |A| (7) | (16/64) | +// |N|V|V|V| |S| | (if payload len==126/127) | +// | |1|2|3| |K| | | +// +-+-+-+-+-------+-+-------------+ - - - - - - - - - - - - - - - + +// | Extended payload length continued, if payload len == 127 | +// + - - - - - - - - - - - - - - - +-------------------------------+ +// | |Masking-key, if MASK set to 1 | +// +-------------------------------+-------------------------------+ +// | Masking-key (continued) | Payload Data | +// +-------------------------------- - - - - - - - - - - - - - - - + +// : Payload Data continued ... : +// + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + +// | Payload Data continued ... | +// +---------------------------------------------------------------+ +// +void WebSocketTransport::dispatch(WebSocketTransport::PollResult pollResult, + const OnMessageCallback &onMessageCallback) +{ + while (true) { + wsheader_type ws; + if (_rxbuf.size() < 2) + break; /* Need at least 2 */ + const uint8_t *data = (uint8_t *)&_rxbuf[0]; // peek, but don't consume + ws.fin = (data[0] & 0x80) == 0x80; + ws.rsv1 = (data[0] & 0x40) == 0x40; + ws.rsv2 = (data[0] & 0x20) == 0x20; + ws.rsv3 = (data[0] & 0x10) == 0x10; + ws.opcode = (wsheader_type::opcode_type)(data[0] & 0x0f); + ws.mask = (data[1] & 0x80) == 0x80; + ws.N0 = (data[1] & 0x7f); + ws.header_size = 2 + (ws.N0 == 126 ? 2 : 0) + (ws.N0 == 127 ? 8 : 0) + + (ws.mask ? 4 : 0); + if (_rxbuf.size() < ws.header_size) + break; /* Need: ws.header_size - _rxbuf.size() */ + + if ((ws.rsv1 && !_enablePerMessageDeflate) || ws.rsv2 || ws.rsv3) { + close(WebSocketCloseConstants::kProtocolErrorCode, + WebSocketCloseConstants::kProtocolErrorReservedBitUsed, + _rxbuf.size()); + return; + } + + // + // Calculate payload length: + // 0-125 mean the payload is that long. + // 126 means that the following two bytes indicate the length, + // 127 means the next 8 bytes indicate the length. + // + int i = 0; + if (ws.N0 < 126) { + ws.N = ws.N0; + i = 2; + } else if (ws.N0 == 126) { + ws.N = 0; + ws.N |= ((uint64_t)data[2]) << 8; + ws.N |= ((uint64_t)data[3]) << 0; + i = 4; + } else if (ws.N0 == 127) { + ws.N = 0; + ws.N |= ((uint64_t)data[2]) << 56; + ws.N |= ((uint64_t)data[3]) << 48; + ws.N |= ((uint64_t)data[4]) << 40; + ws.N |= ((uint64_t)data[5]) << 32; + ws.N |= ((uint64_t)data[6]) << 24; + ws.N |= ((uint64_t)data[7]) << 16; + ws.N |= ((uint64_t)data[8]) << 8; + ws.N |= ((uint64_t)data[9]) << 0; + i = 10; + } else { + // invalid payload length according to the spec. bail out + return; + } + + if (ws.mask) { + ws.masking_key[0] = ((uint8_t)data[i + 0]) << 0; + ws.masking_key[1] = ((uint8_t)data[i + 1]) << 0; + ws.masking_key[2] = ((uint8_t)data[i + 2]) << 0; + ws.masking_key[3] = ((uint8_t)data[i + 3]) << 0; + } else { + ws.masking_key[0] = 0; + ws.masking_key[1] = 0; + ws.masking_key[2] = 0; + ws.masking_key[3] = 0; + } + + // Prevent integer overflow in the next conditional + const uint64_t maxFrameSize(1ULL << 63); + if (ws.N > maxFrameSize) { + return; + } + + if (_rxbuf.size() < ws.header_size + ws.N) { + return; /* Need: ws.header_size+ws.N - _rxbuf.size() */ + } + + if (!ws.fin && (ws.opcode == wsheader_type::PING || + ws.opcode == wsheader_type::PONG || + ws.opcode == wsheader_type::CLOSE)) { + // Control messages should not be fragmented + close(WebSocketCloseConstants::kProtocolErrorCode, + WebSocketCloseConstants:: + kProtocolErrorCodeControlMessageFragmented); + return; + } + + unmaskReceiveBuffer(ws); + std::string frameData(_rxbuf.begin() + ws.header_size, + _rxbuf.begin() + ws.header_size + (size_t)ws.N); + + // We got a whole message, now do something with it: + if (ws.opcode == wsheader_type::TEXT_FRAME || + ws.opcode == wsheader_type::BINARY_FRAME || + ws.opcode == wsheader_type::CONTINUATION) { + if (ws.opcode != wsheader_type::CONTINUATION) { + _fragmentedMessageKind = + (ws.opcode == wsheader_type::TEXT_FRAME) + ? MessageKind::MSG_TEXT + : MessageKind::MSG_BINARY; + + _receivedMessageCompressed = + _enablePerMessageDeflate && ws.rsv1; + + // Continuation message needs to follow a non-fin TEXT or BINARY + // message + if (!_chunks.empty()) { + close(WebSocketCloseConstants::kProtocolErrorCode, + WebSocketCloseConstants:: + kProtocolErrorCodeDataOpcodeOutOfSequence); + } + } else if (_chunks.empty()) { + // Continuation message need to follow a non-fin TEXT or BINARY + // message + close(WebSocketCloseConstants::kProtocolErrorCode, + WebSocketCloseConstants:: + kProtocolErrorCodeContinuationOpCodeOutOfSequence); + } + + // + // Usual case. Small unfragmented messages + // + if (ws.fin && _chunks.empty()) { + emitMessage(_fragmentedMessageKind, + frameData, + _receivedMessageCompressed, + onMessageCallback); + + _receivedMessageCompressed = false; + } else { + // + // Add intermediary message to our chunk list. + // We use a chunk list instead of a big buffer because resizing + // large buffer can be very costly when we need to re-allocate + // the internal buffer which is slow and can let the internal OS + // receive buffer fill out. + // + _chunks.emplace_back(frameData); + + if (ws.fin) { + emitMessage(_fragmentedMessageKind, + getMergedChunks(), + _receivedMessageCompressed, + onMessageCallback); + + _chunks.clear(); + _receivedMessageCompressed = false; + } else { + emitMessage(MessageKind::FRAGMENT, + std::string(), + false, + onMessageCallback); + } + } + } else if (ws.opcode == wsheader_type::PING) { + // too large + if (frameData.size() > 125) { + // Unexpected frame type + close(WebSocketCloseConstants::kProtocolErrorCode, + WebSocketCloseConstants:: + kProtocolErrorPingPayloadOversized); + return; + } + + if (_enablePong) { + // Reply back right away + bool compress = false; + sendData(wsheader_type::PONG, frameData, compress); + } + + emitMessage(MessageKind::PING, frameData, false, onMessageCallback); + } else if (ws.opcode == wsheader_type::PONG) { + _pongReceived = true; + emitMessage(MessageKind::PONG, frameData, false, onMessageCallback); + } else if (ws.opcode == wsheader_type::CLOSE) { + std::string reason; + uint16_t code = 0; + + if (ws.N >= 2) { + // Extract the close code first, available as the first 2 bytes + code |= ((uint64_t)_rxbuf[ws.header_size]) << 8; + code |= ((uint64_t)_rxbuf[ws.header_size + 1]) << 0; + + // Get the reason. + if (ws.N > 2) { + reason = frameData.substr(2, frameData.size()); + } + + // Validate that the reason is proper utf-8. Autobahn 7.5.1 + if (!validateUtf8(reason)) { + code = WebSocketCloseConstants::kInvalidFramePayloadData; + reason = WebSocketCloseConstants:: + kInvalidFramePayloadDataMessage; + } + + // + // Validate close codes. Autobahn 7.9.* + // 1014, 1015 are debattable. The firefox MSDN has a description + // for them. Full list of status code and status range is + // defined in the dedicated RFC section at + // https://tools.ietf.org/html/rfc6455#page-45 + // + if (code < 1000 || code == 1004 || code == 1006 || + (code > 1013 && code < 3000)) { + // build up an error message containing the bad error code + std::stringstream ss; + ss << WebSocketCloseConstants::kInvalidCloseCodeMessage + << ": " << code; + reason = ss.str(); + + code = WebSocketCloseConstants::kProtocolErrorCode; + } + } else { + // no close code received + code = WebSocketCloseConstants::kNoStatusCodeErrorCode; + reason = WebSocketCloseConstants::kNoStatusCodeErrorMessage; + } + + // We receive a CLOSE frame from remote and are NOT the ones who + // triggered the close + if (_readyState != ReadyState::CLOSING) { + // send back the CLOSE frame + sendCloseFrame(code, reason); + + wakeUpFromPoll(SelectInterrupt::kCloseRequest); + + bool remote = true; + closeSocketAndSwitchToClosedState(code, + reason, + _rxbuf.size(), + remote); + } else { + // we got the CLOSE frame answer from our close, so we can close + // the connection if the code/reason are the same + bool identicalReason = + _closeCode == code && getCloseReason() == reason; + + if (identicalReason) { + bool remote = false; + closeSocketAndSwitchToClosedState(code, + reason, + _rxbuf.size(), + remote); + } + } + } else { + // Unexpected frame type + close(WebSocketCloseConstants::kProtocolErrorCode, + WebSocketCloseConstants::kProtocolErrorMessage, + _rxbuf.size()); + } + + // Erase the message that has been processed from the input/read buffer + _rxbuf.erase(_rxbuf.begin(), + _rxbuf.begin() + ws.header_size + (size_t)ws.N); + } + + // if an abnormal closure was raised in poll, and nothing else triggered a + // CLOSED state in the received and processed data then close the connection + if (pollResult != PollResult::Succeeded) { + _rxbuf.clear(); + + // if we previously closed the connection (CLOSING state), then set + // state to CLOSED (code/reason were set before) + if (_readyState == ReadyState::CLOSING) { + closeSocket(); + setReadyState(ReadyState::CLOSED); + } + // if we weren't closing, then close using abnormal close code and + // message + else if (_readyState != ReadyState::CLOSED) { + closeSocketAndSwitchToClosedState( + WebSocketCloseConstants::kAbnormalCloseCode, + WebSocketCloseConstants::kAbnormalCloseMessage, + 0, + false); + } + } +} + +std::string WebSocketTransport::getMergedChunks() const +{ + size_t length = 0; + for (auto &&chunk : _chunks) { + length += chunk.size(); + } + + std::string msg; + msg.reserve(length); + + for (auto &&chunk : _chunks) { + msg += chunk; + } + + return msg; +} + +void WebSocketTransport::emitMessage(MessageKind messageKind, + const std::string &message, + bool compressedMessage, + const OnMessageCallback &onMessageCallback) +{ + size_t wireSize = message.size(); + + // When the RSV1 bit is 1 it means the message is compressed + if (compressedMessage && messageKind != MessageKind::FRAGMENT) { + bool success = + _perMessageDeflate->decompress(message, _decompressedMessage); + + if (messageKind == MessageKind::MSG_TEXT && + !validateUtf8(_decompressedMessage)) { + close(WebSocketCloseConstants::kInvalidFramePayloadData, + WebSocketCloseConstants::kInvalidFramePayloadDataMessage); + } else { + onMessageCallback(_decompressedMessage, + wireSize, + !success, + messageKind); + } + } else { + if (messageKind == MessageKind::MSG_TEXT && !validateUtf8(message)) { + close(WebSocketCloseConstants::kInvalidFramePayloadData, + WebSocketCloseConstants::kInvalidFramePayloadDataMessage); + } else { + onMessageCallback(message, wireSize, false, messageKind); + } + } +} + +unsigned WebSocketTransport::getRandomUnsigned() +{ + auto now = std::chrono::system_clock::now(); + auto seconds = + std::chrono::duration_cast(now.time_since_epoch()) + .count(); + return static_cast(seconds); +} + +template +WebSocketSendInfo + WebSocketTransport::sendData(wsheader_type::opcode_type type, + const T &message, + bool compress, + const OnProgressCallback &onProgressCallback) +{ + if (_readyState != ReadyState::OPEN && _readyState != ReadyState::CLOSING) { + return WebSocketSendInfo(false); + } + + size_t payloadSize = message.size(); + size_t wireSize = message.size(); + bool compressionError = false; + + auto message_begin = message.cbegin(); + auto message_end = message.cend(); + + if (compress) { + if (!_perMessageDeflate->compress(message, _compressedMessage)) { + bool success = false; + compressionError = true; + payloadSize = 0; + wireSize = 0; + return WebSocketSendInfo(success, + compressionError, + payloadSize, + wireSize); + } + compressionError = false; + wireSize = _compressedMessage.size(); + + message_begin = _compressedMessage.cbegin(); + message_end = _compressedMessage.cend(); + } + + { + std::lock_guard lock(_txbufMutex); + _txbuf.reserve(wireSize); + } + + bool success = true; + + // Common case for most message. No fragmentation required. + if (wireSize < kChunkSize) { + success = + sendFragment(type, true, message_begin, message_end, compress); + + if (onProgressCallback) { + onProgressCallback(0, 1); + } + } else { + // + // Large messages need to be fragmented + // + // Rules: + // First message needs to specify a proper type (BINARY or TEXT) + // Intermediary and last messages need to be of type CONTINUATION + // Last message must set the fin byte. + // + auto steps = wireSize / kChunkSize; + + std::string::const_iterator begin = message_begin; + std::string::const_iterator end = message_end; + + for (uint64_t i = 0; i < steps; ++i) { + bool firstStep = i == 0; + bool lastStep = (i + 1) == steps; + bool fin = lastStep; + + end = begin + kChunkSize; + if (lastStep) { + end = message_end; + } + + auto opcodeType = type; + if (!firstStep) { + opcodeType = wsheader_type::CONTINUATION; + } + + // Send message + if (!sendFragment(opcodeType, fin, begin, end, compress)) { + return WebSocketSendInfo(false); + } + + if (onProgressCallback && !onProgressCallback((int)i, (int)steps)) { + break; + } + + begin += kChunkSize; + } + } + + // Request to flush the send buffer on the background thread if it isn't + // empty + if (!isSendBufferEmpty()) { + wakeUpFromPoll(SelectInterrupt::kSendRequest); + + // FIXME: we should have a timeout when sending large messages: see #131 + if (_blockingSend && !flushSendBuffer()) { + success = false; + } + } + + return WebSocketSendInfo(success, compressionError, payloadSize, wireSize); +} + +template +bool WebSocketTransport::sendFragment(wsheader_type::opcode_type type, + bool fin, + Iterator message_begin, + Iterator message_end, + bool compress) +{ + uint64_t message_size = static_cast(message_end - message_begin); + + unsigned x = getRandomUnsigned(); + uint8_t masking_key[4] = {}; + masking_key[0] = (x >> 24); + masking_key[1] = (x >> 16) & 0xff; + masking_key[2] = (x >> 8) & 0xff; + masking_key[3] = (x)&0xff; + + std::vector header; + header.assign(2 + (message_size >= 126 ? 2 : 0) + + (message_size >= 65536 ? 6 : 0) + (_useMask ? 4 : 0), + 0); + header[0] = type; + + // The fin bit indicate that this is the last fragment. Fin is French for + // end. + if (fin) { + header[0] |= 0x80; + } + + // The rsv1 bit indicate that the frame is compressed + // continuation opcodes should not set it. Autobahn 12.2.10 and others 12.X + if (compress && type != wsheader_type::CONTINUATION) { + header[0] |= 0x40; + } + + if (message_size < 126) { + header[1] = (message_size & 0xff) | (_useMask ? 0x80 : 0); + + if (_useMask) { + header[2] = masking_key[0]; + header[3] = masking_key[1]; + header[4] = masking_key[2]; + header[5] = masking_key[3]; + } + } else if (message_size < 65536) { + header[1] = 126 | (_useMask ? 0x80 : 0); + header[2] = (message_size >> 8) & 0xff; + header[3] = (message_size >> 0) & 0xff; + + if (_useMask) { + header[4] = masking_key[0]; + header[5] = masking_key[1]; + header[6] = masking_key[2]; + header[7] = masking_key[3]; + } + } else { // TODO: run coverage testing here + header[1] = 127 | (_useMask ? 0x80 : 0); + header[2] = (message_size >> 56) & 0xff; + header[3] = (message_size >> 48) & 0xff; + header[4] = (message_size >> 40) & 0xff; + header[5] = (message_size >> 32) & 0xff; + header[6] = (message_size >> 24) & 0xff; + header[7] = (message_size >> 16) & 0xff; + header[8] = (message_size >> 8) & 0xff; + header[9] = (message_size >> 0) & 0xff; + + if (_useMask) { + header[10] = masking_key[0]; + header[11] = masking_key[1]; + header[12] = masking_key[2]; + header[13] = masking_key[3]; + } + } + + // _txbuf will keep growing until it can be transmitted over the socket: + appendToSendBuffer(header, + message_begin, + message_end, + message_size, + masking_key); + + // Now actually send this data + return sendOnSocket(); +} + +WebSocketSendInfo WebSocketTransport::sendPing(const std::string &message) +{ + bool compress = false; + WebSocketSendInfo info = sendData(wsheader_type::PING, message, compress); + + if (info.success) { + std::lock_guard lck(_lastSendPingTimePointMutex); + _lastSendPingTimePoint = std::chrono::steady_clock::now(); + } + + return info; +} + +WebSocketSendInfo + WebSocketTransport::sendBinary(const std::string &message, + const OnProgressCallback &onProgressCallback) + +{ + return sendData(wsheader_type::BINARY_FRAME, + message, + _enablePerMessageDeflate, + onProgressCallback); +} + +WebSocketSendInfo + WebSocketTransport::sendText(const std::string &message, + const OnProgressCallback &onProgressCallback) + +{ + return sendData(wsheader_type::TEXT_FRAME, + message, + _enablePerMessageDeflate, + onProgressCallback); +} + +bool WebSocketTransport::sendOnSocket() +{ + std::lock_guard lock(_txbufMutex); + + while (_txbuf.size()) { + ssize_t ret = 0; + { + std::lock_guard lock(_socketMutex); + ret = _socket->send((char *)&_txbuf[0], _txbuf.size()); + } + + if (ret < 0 && Socket::isWaitNeeded()) { + break; + } else if (ret <= 0) { + closeSocket(); + setReadyState(ReadyState::CLOSED); + return false; + } else { + _txbuf.erase(_txbuf.begin(), _txbuf.begin() + ret); + } + } + + return true; +} + +bool WebSocketTransport::receiveFromSocket() +{ + while (true) { + ssize_t ret = _socket->recv((char *)&_readbuf[0], _readbuf.size()); + + if (ret < 0 && Socket::isWaitNeeded()) { + break; + } else if (ret <= 0) { + // if there are received data pending to be processed, then delay + // the abnormal closure to after dispatch (other close code/reason + // could be read from the buffer) + + closeSocket(); + return false; + } else { + _rxbuf.insert(_rxbuf.end(), + _readbuf.begin(), + _readbuf.begin() + ret); + } + } + + return true; +} + +void WebSocketTransport::sendCloseFrame(uint16_t code, + const std::string &reason) +{ + bool compress = false; + + // if a status is set/was read + if (code != WebSocketCloseConstants::kNoStatusCodeErrorCode) { + // See list of close events here: + // https://developer.mozilla.org/en-US/docs/Web/API/CloseEvent + std::string closure{(char)(code >> 8), (char)(code & 0xff)}; + + // copy reason after code + closure.append(reason); + + sendData(wsheader_type::CLOSE, closure, compress); + } else { + // no close code/reason set + sendData(wsheader_type::CLOSE, std::string(""), compress); + } +} + +void WebSocketTransport::closeSocket() +{ + std::lock_guard lock(_socketMutex); + _socket->close(); +} + +bool WebSocketTransport::wakeUpFromPoll(uint64_t wakeUpCode) +{ + std::lock_guard lock(_socketMutex); + return _socket->wakeUpFromPoll(wakeUpCode); +} + +void WebSocketTransport::closeSocketAndSwitchToClosedState( + uint16_t code, + const std::string &reason, + size_t closeWireSize, + bool remote) +{ + closeSocket(); + + setCloseReason(reason); + _closeCode = code; + _closeWireSize = closeWireSize; + _closeRemote = remote; + + setReadyState(ReadyState::CLOSED); + _requestInitCancellation = false; +} + +void WebSocketTransport::close(uint16_t code, + const std::string &reason, + size_t closeWireSize, + bool remote) +{ + _requestInitCancellation = true; + + if (_readyState == ReadyState::CLOSING || _readyState == ReadyState::CLOSED) + return; + + if (closeWireSize == 0) { + closeWireSize = reason.size(); + } + + setCloseReason(reason); + _closeCode = code; + _closeWireSize = closeWireSize; + _closeRemote = remote; + + { + std::lock_guard lock(_closingTimePointMutex); + _closingTimePoint = std::chrono::steady_clock::now(); + } + setReadyState(ReadyState::CLOSING); + + sendCloseFrame(code, reason); + + // wake up the poll, but do not close yet + wakeUpFromPoll(SelectInterrupt::kSendRequest); +} + +size_t WebSocketTransport::bufferedAmount() const +{ + std::lock_guard lock(_txbufMutex); + return _txbuf.size(); +} + +bool WebSocketTransport::flushSendBuffer() +{ + while (!isSendBufferEmpty() && !_requestInitCancellation) { + // Wait with a 10ms timeout until the socket is ready to write. + // This way we are not busy looping + PollResultType result = _socket->isReadyToWrite(10); + + if (result == PollResultType::Error) { + closeSocket(); + setReadyState(ReadyState::CLOSED); + return false; + } else if (result == PollResultType::ReadyForWrite) { + if (!sendOnSocket()) { + return false; + } + } + } + + return true; +} + +void WebSocketTransport::setCloseReason(const std::string &reason) +{ + std::lock_guard lock(_closeReasonMutex); + _closeReason = reason; +} + +const std::string &WebSocketTransport::getCloseReason() const +{ + std::lock_guard lock(_closeReasonMutex); + return _closeReason; +} +} // namespace ix diff --git a/GermanAirlinesVA-GAConnector/ixwebsocket/License.txt b/GermanAirlinesVA-GAConnector/ixwebsocket/License.txt new file mode 100644 index 0000000..dffb40e --- /dev/null +++ b/GermanAirlinesVA-GAConnector/ixwebsocket/License.txt @@ -0,0 +1,29 @@ +Copyright (c) 2018 Machine Zone, Inc. All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + +1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + +2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the + distribution. + +3. Neither the name of the copyright holder nor the names of its + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. \ No newline at end of file diff --git a/GermanAirlinesVA-GAConnector/ixwebsocket/include/IXBench.h b/GermanAirlinesVA-GAConnector/ixwebsocket/include/IXBench.h new file mode 100644 index 0000000..873e016 --- /dev/null +++ b/GermanAirlinesVA-GAConnector/ixwebsocket/include/IXBench.h @@ -0,0 +1,32 @@ +/* + * IXBench.h + * Author: Benjamin Sergeant + * Copyright (c) 2017-2020 Machine Zone, Inc. All rights reserved. + */ +#pragma once + +#include +#include +#include + +namespace ix +{ +class Bench +{ +public: + Bench(const std::string &description); + ~Bench(); + + void reset(); + void record(); + void report(); + void setReported(); + uint64_t getDuration() const; + +private: + std::string _description; + std::chrono::time_point _start; + uint64_t _duration; + bool _reported; +}; +} // namespace ix diff --git a/GermanAirlinesVA-GAConnector/ixwebsocket/include/IXCancellationRequest.h b/GermanAirlinesVA-GAConnector/ixwebsocket/include/IXCancellationRequest.h new file mode 100644 index 0000000..2a4f048 --- /dev/null +++ b/GermanAirlinesVA-GAConnector/ixwebsocket/include/IXCancellationRequest.h @@ -0,0 +1,19 @@ +/* + * IXCancellationRequest.h + * Author: Benjamin Sergeant + * Copyright (c) 2018 Machine Zone, Inc. All rights reserved. + */ + +#pragma once + +#include +#include + +namespace ix +{ +using CancellationRequest = std::function; + +CancellationRequest makeCancellationRequestWithTimeout( + int seconds, + std::atomic &requestInitCancellation); +} // namespace ix diff --git a/GermanAirlinesVA-GAConnector/ixwebsocket/include/IXConnectionState.h b/GermanAirlinesVA-GAConnector/ixwebsocket/include/IXConnectionState.h new file mode 100644 index 0000000..c561318 --- /dev/null +++ b/GermanAirlinesVA-GAConnector/ixwebsocket/include/IXConnectionState.h @@ -0,0 +1,54 @@ +/* + * IXConnectionState.h + * Author: Benjamin Sergeant + * Copyright (c) 2019 Machine Zone, Inc. All rights reserved. + */ + +#pragma once + +#include +#include +#include +#include +#include + +namespace ix +{ +using OnSetTerminatedCallback = std::function; + +class ConnectionState +{ +public: + ConnectionState(); + virtual ~ConnectionState() = default; + + virtual void computeId(); + virtual const std::string &getId() const; + + void setTerminated(); + bool isTerminated() const; + + const std::string &getRemoteIp(); + int getRemotePort(); + + static std::shared_ptr createConnectionState(); + +private: + void setOnSetTerminatedCallback(const OnSetTerminatedCallback &callback); + + void setRemoteIp(const std::string &remoteIp); + void setRemotePort(int remotePort); + +protected: + std::atomic _terminated; + std::string _id; + OnSetTerminatedCallback _onSetTerminatedCallback; + + static std::atomic _globalId; + + std::string _remoteIp; + int _remotePort; + + friend class SocketServer; +}; +} // namespace ix diff --git a/GermanAirlinesVA-GAConnector/ixwebsocket/include/IXDNSLookup.h b/GermanAirlinesVA-GAConnector/ixwebsocket/include/IXDNSLookup.h new file mode 100644 index 0000000..dea9301 --- /dev/null +++ b/GermanAirlinesVA-GAConnector/ixwebsocket/include/IXDNSLookup.h @@ -0,0 +1,73 @@ +/* + * IXDNSLookup.h + * Author: Benjamin Sergeant + * Copyright (c) 2018 Machine Zone, Inc. All rights reserved. + * + * Resolve a hostname+port to a struct addrinfo obtained with getaddrinfo + * Does this in a background thread so that it can be cancelled, since + * getaddrinfo is a blocking call, and we don't want to block the main thread + * on Mobile. + */ + +#pragma once + +#include "IXCancellationRequest.h" +#include +#include +#include +#include +#include + +struct addrinfo; + +namespace ix +{ +class DNSLookup : public std::enable_shared_from_this +{ +public: + DNSLookup(const std::string &hostname, + int port, + int64_t wait = DNSLookup::kDefaultWait); + ~DNSLookup() = default; + + struct addrinfo *resolve(std::string &errMsg, + const CancellationRequest &isCancellationRequested, + bool cancellable = true); + + void release(struct addrinfo *addr); + +private: + struct addrinfo * + resolveCancellable(std::string &errMsg, + const CancellationRequest &isCancellationRequested); + struct addrinfo *resolveUnCancellable( + std::string &errMsg, + const CancellationRequest &isCancellationRequested); + + static struct addrinfo * + getAddrInfo(const std::string &hostname, int port, std::string &errMsg); + + void run(std::weak_ptr self, + std::string hostname, + int port); // thread runner + + void setErrMsg(const std::string &errMsg); + const std::string &getErrMsg(); + + void setRes(struct addrinfo *addr); + struct addrinfo *getRes(); + + std::string _hostname; + int _port; + int64_t _wait; + const static int64_t kDefaultWait; + + struct addrinfo *_res; + std::mutex _resMutex; + + std::string _errMsg; + std::mutex _errMsgMutex; + + std::atomic _done; +}; +} // namespace ix diff --git a/GermanAirlinesVA-GAConnector/ixwebsocket/include/IXExponentialBackoff.h b/GermanAirlinesVA-GAConnector/ixwebsocket/include/IXExponentialBackoff.h new file mode 100644 index 0000000..4df2387 --- /dev/null +++ b/GermanAirlinesVA-GAConnector/ixwebsocket/include/IXExponentialBackoff.h @@ -0,0 +1,17 @@ +/* + * IXExponentialBackoff.h + * Author: Benjamin Sergeant + * Copyright (c) 2017-2019 Machine Zone, Inc. All rights reserved. + */ + +#pragma once + +#include + +namespace ix +{ +uint32_t + calculateRetryWaitMilliseconds(uint32_t retryCount, + uint32_t maxWaitBetweenReconnectionRetries, + uint32_t minWaitBetweenReconnectionRetries); +} // namespace ix diff --git a/GermanAirlinesVA-GAConnector/ixwebsocket/include/IXGetFreePort.h b/GermanAirlinesVA-GAConnector/ixwebsocket/include/IXGetFreePort.h new file mode 100644 index 0000000..7632922 --- /dev/null +++ b/GermanAirlinesVA-GAConnector/ixwebsocket/include/IXGetFreePort.h @@ -0,0 +1,12 @@ +/* + * IXGetFreePort.h + * Author: Benjamin Sergeant + * Copyright (c) 2019 Machine Zone. All rights reserved. + */ + +#pragma once + +namespace ix +{ +int getFreePort(); +} // namespace ix diff --git a/GermanAirlinesVA-GAConnector/ixwebsocket/include/IXGzipCodec.h b/GermanAirlinesVA-GAConnector/ixwebsocket/include/IXGzipCodec.h new file mode 100644 index 0000000..38e3580 --- /dev/null +++ b/GermanAirlinesVA-GAConnector/ixwebsocket/include/IXGzipCodec.h @@ -0,0 +1,15 @@ +/* + * IXGzipCodec.h + * Author: Benjamin Sergeant + * Copyright (c) 2020 Machine Zone, Inc. All rights reserved. + */ + +#pragma once + +#include + +namespace ix +{ +std::string gzipCompress(const std::string &str); +bool gzipDecompress(const std::string &in, std::string &out); +} // namespace ix diff --git a/GermanAirlinesVA-GAConnector/ixwebsocket/include/IXHttp.h b/GermanAirlinesVA-GAConnector/ixwebsocket/include/IXHttp.h new file mode 100644 index 0000000..942fc7e --- /dev/null +++ b/GermanAirlinesVA-GAConnector/ixwebsocket/include/IXHttp.h @@ -0,0 +1,117 @@ +/* + * IXHttp.h + * Author: Benjamin Sergeant + * Copyright (c) 2019 Machine Zone, Inc. All rights reserved. + */ + +#pragma once + +#include "IXProgressCallback.h" +#include "IXWebSocketHttpHeaders.h" +#include +#include + +namespace ix +{ +enum class HttpErrorCode : int { + Ok = 0, + CannotConnect = 1, + Timeout = 2, + Gzip = 3, + UrlMalformed = 4, + CannotCreateSocket = 5, + SendError = 6, + ReadError = 7, + CannotReadStatusLine = 8, + MissingStatus = 9, + HeaderParsingError = 10, + MissingLocation = 11, + TooManyRedirects = 12, + ChunkReadError = 13, + CannotReadBody = 14, + Invalid = 100 +}; + +struct HttpResponse { + int statusCode; + std::string description; + HttpErrorCode errorCode; + WebSocketHttpHeaders headers; + std::string body; + std::string errorMsg; + uint64_t uploadSize; + uint64_t downloadSize; + + HttpResponse(int s = 0, + const std::string &des = std::string(), + const HttpErrorCode &c = HttpErrorCode::Ok, + const WebSocketHttpHeaders &h = WebSocketHttpHeaders(), + const std::string &b = std::string(), + const std::string &e = std::string(), + uint64_t u = 0, + uint64_t d = 0) + : statusCode(s), description(des), errorCode(c), headers(h), body(b), + errorMsg(e), uploadSize(u), downloadSize(d) + { + ; + } +}; + +using HttpResponsePtr = std::shared_ptr; +using HttpParameters = std::unordered_map; +using HttpFormDataParameters = std::unordered_map; +using Logger = std::function; +using OnResponseCallback = std::function; + +struct HttpRequestArgs { + std::string url; + std::string verb; + WebSocketHttpHeaders extraHeaders; + std::string body; + std::string multipartBoundary; + int connectTimeout = 60; + int transferTimeout = 1800; + bool followRedirects = true; + int maxRedirects = 5; + bool verbose = false; + bool compress = true; + bool compressRequest = false; + Logger logger; + OnProgressCallback onProgressCallback; +}; + +using HttpRequestArgsPtr = std::shared_ptr; + +struct HttpRequest { + std::string uri; + std::string method; + std::string version; + std::string body; + WebSocketHttpHeaders headers; + + HttpRequest(const std::string &u, + const std::string &m, + const std::string &v, + const std::string &b, + const WebSocketHttpHeaders &h = WebSocketHttpHeaders()) + : uri(u), method(m), version(v), body(b), headers(h) + { + } +}; + +using HttpRequestPtr = std::shared_ptr; + +class Http +{ +public: + static std::tuple + parseRequest(std::unique_ptr &socket, int timeoutSecs); + static bool sendResponse(HttpResponsePtr response, + std::unique_ptr &socket); + + static std::pair parseStatusLine(const std::string &line); + static std::tuple + parseRequestLine(const std::string &line); + static std::string trim(const std::string &str); +}; +} // namespace ix diff --git a/GermanAirlinesVA-GAConnector/ixwebsocket/include/IXHttpClient.h b/GermanAirlinesVA-GAConnector/ixwebsocket/include/IXHttpClient.h new file mode 100644 index 0000000..98f47e8 --- /dev/null +++ b/GermanAirlinesVA-GAConnector/ixwebsocket/include/IXHttpClient.h @@ -0,0 +1,126 @@ +/* + * IXHttpClient.h + * Author: Benjamin Sergeant + * Copyright (c) 2019 Machine Zone, Inc. All rights reserved. + */ + +#pragma once + +#include "IXHttp.h" +#include "IXSocket.h" +#include "IXSocketTLSOptions.h" +#include "IXWebSocketHttpHeaders.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace ix +{ +class HttpClient +{ +public: + HttpClient(bool async = false); + ~HttpClient(); + + HttpResponsePtr get(const std::string &url, HttpRequestArgsPtr args); + HttpResponsePtr head(const std::string &url, HttpRequestArgsPtr args); + HttpResponsePtr Delete(const std::string &url, HttpRequestArgsPtr args); + + HttpResponsePtr post(const std::string &url, + const HttpParameters &httpParameters, + const HttpFormDataParameters &httpFormDataParameters, + HttpRequestArgsPtr args); + HttpResponsePtr post(const std::string &url, + const std::string &body, + HttpRequestArgsPtr args); + + HttpResponsePtr put(const std::string &url, + const HttpParameters &httpParameters, + const HttpFormDataParameters &httpFormDataParameters, + HttpRequestArgsPtr args); + HttpResponsePtr put(const std::string &url, + const std::string &body, + HttpRequestArgsPtr args); + + HttpResponsePtr patch(const std::string &url, + const HttpParameters &httpParameters, + const HttpFormDataParameters &httpFormDataParameters, + HttpRequestArgsPtr args); + HttpResponsePtr patch(const std::string &url, + const std::string &body, + HttpRequestArgsPtr args); + + HttpResponsePtr request(const std::string &url, + const std::string &verb, + const std::string &body, + HttpRequestArgsPtr args, + int redirects = 0); + + HttpResponsePtr + request(const std::string &url, + const std::string &verb, + const HttpParameters &httpParameters, + const HttpFormDataParameters &httpFormDataParameters, + HttpRequestArgsPtr args); + + void setForceBody(bool value); + + // Async API + HttpRequestArgsPtr + createRequest(const std::string &url = std::string(), + const std::string &verb = HttpClient::kGet); + + bool performRequest(HttpRequestArgsPtr request, + const OnResponseCallback &onResponseCallback); + + // TLS + void setTLSOptions(const SocketTLSOptions &tlsOptions); + + std::string serializeHttpParameters(const HttpParameters &httpParameters); + + std::string serializeHttpFormDataParameters( + const std::string &multipartBoundary, + const HttpFormDataParameters &httpFormDataParameters, + const HttpParameters &httpParameters = HttpParameters()); + + std::string generateMultipartBoundary(); + + std::string urlEncode(const std::string &value); + + const static std::string kPost; + const static std::string kGet; + const static std::string kHead; + const static std::string kDelete; + const static std::string kPut; + const static std::string kPatch; + +private: + void log(const std::string &msg, HttpRequestArgsPtr args); + + // Async API background thread runner + void run(); + // Async API + bool _async; + std::queue> _queue; + mutable std::mutex _queueMutex; + std::condition_variable _condition; + std::atomic _stop; + std::thread _thread; + + std::unique_ptr _socket; + std::recursive_mutex + _mutex; // to protect accessing the _socket (only one socket per + // client) the mutex needs to be recursive as this function + // might be called recursively to follow HTTP redirections + + SocketTLSOptions _tlsOptions; + + bool _forceBody; +}; +} // namespace ix diff --git a/GermanAirlinesVA-GAConnector/ixwebsocket/include/IXHttpServer.h b/GermanAirlinesVA-GAConnector/ixwebsocket/include/IXHttpServer.h new file mode 100644 index 0000000..f8a76d6 --- /dev/null +++ b/GermanAirlinesVA-GAConnector/ixwebsocket/include/IXHttpServer.h @@ -0,0 +1,62 @@ +/* + * IXHttpServer.h + * Author: Benjamin Sergeant + * Copyright (c) 2018 Machine Zone, Inc. All rights reserved. + */ + +#pragma once + +#include "IXHttp.h" +#include "IXSocketServer.h" +#include "IXWebSocket.h" +#include +#include +#include +#include +#include +#include +#include // pair + +namespace ix +{ +class HttpServer final : public SocketServer +{ +public: + using OnConnectionCallback = + std::function)>; + + HttpServer(int port = SocketServer::kDefaultPort, + const std::string &host = SocketServer::kDefaultHost, + int backlog = SocketServer::kDefaultTcpBacklog, + size_t maxConnections = SocketServer::kDefaultMaxConnections, + int addressFamily = SocketServer::kDefaultAddressFamily, + int timeoutSecs = HttpServer::kDefaultTimeoutSecs); + virtual ~HttpServer(); + virtual void stop() final; + + void setOnConnectionCallback(const OnConnectionCallback &callback); + + void makeRedirectServer(const std::string &redirectUrl); + + void makeDebugServer(); + + int getTimeoutSecs(); + +private: + // Member variables + OnConnectionCallback _onConnectionCallback; + std::atomic _connectedClientsCount; + + const static int kDefaultTimeoutSecs; + int _timeoutSecs; + + // Methods + virtual void handleConnection( + std::unique_ptr, + std::shared_ptr connectionState) final; + virtual size_t getConnectedClientsCount() final; + + void setDefaultConnectionCallback(); +}; +} // namespace ix diff --git a/GermanAirlinesVA-GAConnector/ixwebsocket/include/IXNetSystem.h b/GermanAirlinesVA-GAConnector/ixwebsocket/include/IXNetSystem.h new file mode 100644 index 0000000..3b1258d --- /dev/null +++ b/GermanAirlinesVA-GAConnector/ixwebsocket/include/IXNetSystem.h @@ -0,0 +1,87 @@ +/* + * IXNetSystem.h + * Author: Benjamin Sergeant + * Copyright (c) 2019 Machine Zone. All rights reserved. + */ + +#pragma once + +#ifdef _WIN32 + +#ifndef WIN32_LEAN_AND_MEAN +#define WIN32_LEAN_AND_MEAN +#endif + +#include +#include +#include +#include +#include + +#undef EWOULDBLOCK +#undef EAGAIN +#undef EINPROGRESS +#undef EBADF +#undef EINVAL + +// map to WSA error codes +#define EWOULDBLOCK WSAEWOULDBLOCK +#define EAGAIN WSATRY_AGAIN +#define EINPROGRESS WSAEINPROGRESS +#define EBADF WSAEBADF +#define EINVAL WSAEINVAL + +// Define our own poll on Windows, as a wrapper on top of select +typedef unsigned long int nfds_t; + +// pollfd is not defined by some versions of mingw64 since _WIN32_WINNT is too +// low +#if _WIN32_WINNT < 0x0600 +struct pollfd { + int fd; /* file descriptor */ + short events; /* requested events */ + short revents; /* returned events */ +}; + +#define POLLIN 0x001 /* There is data to read. */ +#define POLLOUT 0x004 /* Writing now will not block. */ +#define POLLERR 0x008 /* Error condition. */ +#define POLLHUP 0x010 /* Hung up. */ +#define POLLNVAL 0x020 /* Invalid polling request. */ +#endif + +#else +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#endif + +#include + +namespace ix +{ +#ifdef _WIN32 +typedef SOCKET socket_t; +#else +typedef int socket_t; +#endif + +bool initNetSystem(); +bool uninitNetSystem(); + +int poll(struct pollfd *fds, nfds_t nfds, int timeout); + +const char *inet_ntop(int af, const void *src, char *dst, socklen_t size); +int inet_pton(int af, const char *src, void *dst); + +unsigned short network_to_host_short(unsigned short value); +} // namespace ix diff --git a/GermanAirlinesVA-GAConnector/ixwebsocket/include/IXProgressCallback.h b/GermanAirlinesVA-GAConnector/ixwebsocket/include/IXProgressCallback.h new file mode 100644 index 0000000..c8b992a --- /dev/null +++ b/GermanAirlinesVA-GAConnector/ixwebsocket/include/IXProgressCallback.h @@ -0,0 +1,14 @@ +/* + * IXProgressCallback.h + * Author: Benjamin Sergeant + * Copyright (c) 2019 Machine Zone, Inc. All rights reserved. + */ + +#pragma once + +#include + +namespace ix +{ +using OnProgressCallback = std::function; +} diff --git a/GermanAirlinesVA-GAConnector/ixwebsocket/include/IXSelectInterrupt.h b/GermanAirlinesVA-GAConnector/ixwebsocket/include/IXSelectInterrupt.h new file mode 100644 index 0000000..d1d2350 --- /dev/null +++ b/GermanAirlinesVA-GAConnector/ixwebsocket/include/IXSelectInterrupt.h @@ -0,0 +1,34 @@ +/* + * IXSelectInterrupt.h + * Author: Benjamin Sergeant + * Copyright (c) 2019 Machine Zone, Inc. All rights reserved. + */ + +#pragma once + +#include +#include +#include + +namespace ix +{ +class SelectInterrupt +{ +public: + SelectInterrupt(); + virtual ~SelectInterrupt(); + + virtual bool init(std::string &errorMsg); + + virtual bool notify(uint64_t value); + virtual bool clear(); + virtual uint64_t read(); + virtual int getFd() const; + + // Used as special codes for pipe communication + static const uint64_t kSendRequest; + static const uint64_t kCloseRequest; +}; + +using SelectInterruptPtr = std::unique_ptr; +} // namespace ix diff --git a/GermanAirlinesVA-GAConnector/ixwebsocket/include/IXSelectInterruptFactory.h b/GermanAirlinesVA-GAConnector/ixwebsocket/include/IXSelectInterruptFactory.h new file mode 100644 index 0000000..cf9a9d2 --- /dev/null +++ b/GermanAirlinesVA-GAConnector/ixwebsocket/include/IXSelectInterruptFactory.h @@ -0,0 +1,16 @@ +/* + * IXSelectInterruptFactory.h + * Author: Benjamin Sergeant + * Copyright (c) 2019 Machine Zone, Inc. All rights reserved. + */ + +#pragma once + +#include + +namespace ix +{ +class SelectInterrupt; +using SelectInterruptPtr = std::unique_ptr; +SelectInterruptPtr createSelectInterrupt(); +} // namespace ix diff --git a/GermanAirlinesVA-GAConnector/ixwebsocket/include/IXSelectInterruptPipe.h b/GermanAirlinesVA-GAConnector/ixwebsocket/include/IXSelectInterruptPipe.h new file mode 100644 index 0000000..6eaacff --- /dev/null +++ b/GermanAirlinesVA-GAConnector/ixwebsocket/include/IXSelectInterruptPipe.h @@ -0,0 +1,40 @@ +/* + * IXSelectInterruptPipe.h + * Author: Benjamin Sergeant + * Copyright (c) 2018-2019 Machine Zone, Inc. All rights reserved. + */ + +#pragma once + +#include "IXSelectInterrupt.h" +#include +#include +#include + +namespace ix +{ +class SelectInterruptPipe final : public SelectInterrupt +{ +public: + SelectInterruptPipe(); + virtual ~SelectInterruptPipe(); + + bool init(std::string &errorMsg) final; + + bool notify(uint64_t value) final; + bool clear() final; + uint64_t read() final; + int getFd() const final; + +private: + // Store file descriptors used by the communication pipe. Communication + // happens between a control thread and a background thread, which is + // blocked on select. + int _fildes[2]; + mutable std::mutex _fildesMutex; + + // Used to identify the read/write idx + static const int kPipeReadIndex; + static const int kPipeWriteIndex; +}; +} // namespace ix diff --git a/GermanAirlinesVA-GAConnector/ixwebsocket/include/IXSetThreadName.h b/GermanAirlinesVA-GAConnector/ixwebsocket/include/IXSetThreadName.h new file mode 100644 index 0000000..1a60bb3 --- /dev/null +++ b/GermanAirlinesVA-GAConnector/ixwebsocket/include/IXSetThreadName.h @@ -0,0 +1,12 @@ +/* + * IXSetThreadName.h + * Author: Benjamin Sergeant + * Copyright (c) 2018 Machine Zone, Inc. All rights reserved. + */ +#pragma once +#include + +namespace ix +{ +void setThreadName(const std::string &name); +} diff --git a/GermanAirlinesVA-GAConnector/ixwebsocket/include/IXSocket.h b/GermanAirlinesVA-GAConnector/ixwebsocket/include/IXSocket.h new file mode 100644 index 0000000..da94916 --- /dev/null +++ b/GermanAirlinesVA-GAConnector/ixwebsocket/include/IXSocket.h @@ -0,0 +1,97 @@ +/* + * IXSocket.h + * Author: Benjamin Sergeant + * Copyright (c) 2017-2018 Machine Zone, Inc. All rights reserved. + */ + +#pragma once + +#include +#include +#include +#include +#include + +#ifdef _WIN32 +#ifndef _SSIZE_T_DEFINED +#include +typedef SSIZE_T ssize_t; +#endif +#endif + +#include "IXCancellationRequest.h" +#include "IXProgressCallback.h" +#include "IXSelectInterrupt.h" + +namespace ix +{ +enum class PollResultType { + ReadyForRead = 0, + ReadyForWrite = 1, + Timeout = 2, + Error = 3, + SendRequest = 4, + CloseRequest = 5 +}; + +class Socket +{ +public: + Socket(int fd = -1); + virtual ~Socket(); + bool init(std::string &errorMsg); + + // Functions to check whether there is activity on the socket + PollResultType poll(int timeoutMs = kDefaultPollTimeout); + bool wakeUpFromPoll(uint64_t wakeUpCode); + + PollResultType isReadyToWrite(int timeoutMs); + PollResultType isReadyToRead(int timeoutMs); + + // Virtual methods + virtual bool accept(std::string &errMsg); + + virtual bool connect(const std::string &host, + int port, + std::string &errMsg, + const CancellationRequest &isCancellationRequested); + virtual void close(); + + virtual ssize_t send(char *buffer, size_t length); + ssize_t send(const std::string &buffer); + virtual ssize_t recv(void *buffer, size_t length); + + // Blocking and cancellable versions, working with socket that can be set + // to non blocking mode. Used during HTTP upgrade. + bool readByte(void *buffer, + const CancellationRequest &isCancellationRequested); + bool writeBytes(const std::string &str, + const CancellationRequest &isCancellationRequested); + + std::pair + readLine(const CancellationRequest &isCancellationRequested); + std::pair + readBytes(size_t length, + const OnProgressCallback &onProgressCallback, + const CancellationRequest &isCancellationRequested); + + static int getErrno(); + static bool isWaitNeeded(); + static void closeSocket(int fd); + + static PollResultType poll(bool readyToRead, + int timeoutMs, + int sockfd, + const SelectInterruptPtr &selectInterrupt); + +protected: + std::atomic _sockfd; + std::mutex _socketMutex; + +private: + static const int kDefaultPollTimeout; + static const int kDefaultPollNoTimeout; + + SelectInterruptPtr _selectInterrupt; +}; +} // namespace ix diff --git a/GermanAirlinesVA-GAConnector/ixwebsocket/include/IXSocketAppleSSL.h b/GermanAirlinesVA-GAConnector/ixwebsocket/include/IXSocketAppleSSL.h new file mode 100644 index 0000000..47ef8d6 --- /dev/null +++ b/GermanAirlinesVA-GAConnector/ixwebsocket/include/IXSocketAppleSSL.h @@ -0,0 +1,56 @@ +/* + * IXSocketAppleSSL.h + * Author: Benjamin Sergeant + * Copyright (c) 2017-2020 Machine Zone, Inc. All rights reserved. + */ +#ifdef IXWEBSOCKET_USE_SECURE_TRANSPORT + +#pragma once + +#include "IXCancellationRequest.h" +#include "IXSocket.h" +#include "IXSocketTLSOptions.h" +#include +#include +#include + +namespace ix +{ +class SocketAppleSSL final : public Socket +{ +public: + SocketAppleSSL(const SocketTLSOptions &tlsOptions, int fd = -1); + ~SocketAppleSSL(); + + virtual bool accept(std::string &errMsg) final; + + virtual bool + connect(const std::string &host, + int port, + std::string &errMsg, + const CancellationRequest &isCancellationRequested) final; + virtual void close() final; + + virtual ssize_t send(char *buffer, size_t length) final; + virtual ssize_t recv(void *buffer, size_t length) final; + +private: + static std::string getSSLErrorDescription(OSStatus status); + static OSStatus writeToSocket(SSLConnectionRef connection, + const void *data, + size_t *len); + static OSStatus + readFromSocket(SSLConnectionRef connection, void *data, size_t *len); + + OSStatus tlsHandShake(std::string &errMsg, + const CancellationRequest &isCancellationRequested); + + SSLContextRef _sslContext; + mutable std::mutex _mutex; // AppleSSL routines are not thread-safe + + SocketTLSOptions _tlsOptions; +}; + +} // namespace ix + +#endif // IXWEBSOCKET_USE_SECURE_TRANSPORT diff --git a/GermanAirlinesVA-GAConnector/ixwebsocket/include/IXSocketConnect.h b/GermanAirlinesVA-GAConnector/ixwebsocket/include/IXSocketConnect.h new file mode 100644 index 0000000..71aac82 --- /dev/null +++ b/GermanAirlinesVA-GAConnector/ixwebsocket/include/IXSocketConnect.h @@ -0,0 +1,32 @@ +/* + * IXSocketConnect.h + * Author: Benjamin Sergeant + * Copyright (c) 2018 Machine Zone, Inc. All rights reserved. + */ + +#pragma once + +#include "IXCancellationRequest.h" +#include + +struct addrinfo; + +namespace ix +{ +class SocketConnect +{ +public: + static int connect(const std::string &hostname, + int port, + std::string &errMsg, + const CancellationRequest &isCancellationRequested); + + static void configure(int sockfd); + +private: + static int + connectToAddress(const struct addrinfo *address, + std::string &errMsg, + const CancellationRequest &isCancellationRequested); +}; +} // namespace ix diff --git a/GermanAirlinesVA-GAConnector/ixwebsocket/include/IXSocketFactory.h b/GermanAirlinesVA-GAConnector/ixwebsocket/include/IXSocketFactory.h new file mode 100644 index 0000000..5e92bc6 --- /dev/null +++ b/GermanAirlinesVA-GAConnector/ixwebsocket/include/IXSocketFactory.h @@ -0,0 +1,21 @@ + +/* + * IXSocketFactory.h + * Author: Benjamin Sergeant + * Copyright (c) 2018 Machine Zone, Inc. All rights reserved. + */ + +#pragma once + +#include "IXSocketTLSOptions.h" +#include +#include + +namespace ix +{ +class Socket; +std::unique_ptr createSocket(bool tls, + int fd, + std::string &errorMsg, + const SocketTLSOptions &tlsOptions); +} // namespace ix diff --git a/GermanAirlinesVA-GAConnector/ixwebsocket/include/IXSocketMbedTLS.h b/GermanAirlinesVA-GAConnector/ixwebsocket/include/IXSocketMbedTLS.h new file mode 100644 index 0000000..8af50fc --- /dev/null +++ b/GermanAirlinesVA-GAConnector/ixwebsocket/include/IXSocketMbedTLS.h @@ -0,0 +1,61 @@ +/* + * IXSocketMbedTLS.h + * Author: Benjamin Sergeant + * Copyright (c) 2019-2020 Machine Zone, Inc. All rights reserved. + */ +#ifdef IXWEBSOCKET_USE_MBED_TLS + +#pragma once + +#include "IXSocket.h" +#include "IXSocketTLSOptions.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace ix +{ +class SocketMbedTLS final : public Socket +{ +public: + SocketMbedTLS(const SocketTLSOptions &tlsOptions, int fd = -1); + ~SocketMbedTLS(); + + virtual bool accept(std::string &errMsg) final; + + virtual bool + connect(const std::string &host, + int port, + std::string &errMsg, + const CancellationRequest &isCancellationRequested) final; + virtual void close() final; + + virtual ssize_t send(char *buffer, size_t length) final; + virtual ssize_t recv(void *buffer, size_t length) final; + +private: + mbedtls_ssl_context _ssl; + mbedtls_ssl_config _conf; + mbedtls_entropy_context _entropy; + mbedtls_ctr_drbg_context _ctr_drbg; + mbedtls_x509_crt _cacert; + mbedtls_x509_crt _cert; + mbedtls_pk_context _pkey; + + std::mutex _mutex; + SocketTLSOptions _tlsOptions; + + bool init(const std::string &host, bool isClient, std::string &errMsg); + void initMBedTLS(); + bool loadSystemCertificates(std::string &errMsg); +}; + +} // namespace ix + +#endif // IXWEBSOCKET_USE_MBED_TLS diff --git a/GermanAirlinesVA-GAConnector/ixwebsocket/include/IXSocketOpenSSL.h b/GermanAirlinesVA-GAConnector/ixwebsocket/include/IXSocketOpenSSL.h new file mode 100644 index 0000000..977fbc6 --- /dev/null +++ b/GermanAirlinesVA-GAConnector/ixwebsocket/include/IXSocketOpenSSL.h @@ -0,0 +1,75 @@ +/* + * IXSocketOpenSSL.h + * Author: Benjamin Sergeant, Matt DeBoer + * Copyright (c) 2017-2020 Machine Zone, Inc. All rights reserved. + */ +#ifdef IXWEBSOCKET_USE_OPEN_SSL + +#pragma once + +#include "IXCancellationRequest.h" +#include "IXSocket.h" +#include "IXSocketTLSOptions.h" +#include +#include +#include +#include +#include +#include + +namespace ix +{ +class SocketOpenSSL final : public Socket +{ +public: + SocketOpenSSL(const SocketTLSOptions &tlsOptions, int fd = -1); + ~SocketOpenSSL(); + + virtual bool accept(std::string &errMsg) final; + + virtual bool + connect(const std::string &host, + int port, + std::string &errMsg, + const CancellationRequest &isCancellationRequested) final; + virtual void close() final; + + virtual ssize_t send(char *buffer, size_t length) final; + virtual ssize_t recv(void *buffer, size_t length) final; + +private: + void openSSLInitialize(); + std::string getSSLError(int ret); + SSL_CTX *openSSLCreateContext(std::string &errMsg); + bool openSSLAddCARootsFromString(const std::string roots); + bool openSSLClientHandshake( + const std::string &hostname, + std::string &errMsg, + const CancellationRequest &isCancellationRequested); + bool openSSLCheckServerCert(SSL *ssl, + const std::string &hostname, + std::string &errMsg); + bool checkHost(const std::string &host, const char *pattern); + bool handleTLSOptions(std::string &errMsg); + bool openSSLServerHandshake(std::string &errMsg); + + // Required for OpenSSL < 1.1 + static void openSSLLockingCallback(int mode, + int type, + const char * /*file*/, + int /*line*/); + + SSL *_ssl_connection; + SSL_CTX *_ssl_context; + const SSL_METHOD *_ssl_method; + SocketTLSOptions _tlsOptions; + + mutable std::mutex _mutex; // OpenSSL routines are not thread-safe + + static std::once_flag _openSSLInitFlag; + static std::atomic _openSSLInitializationSuccessful; +}; + +} // namespace ix + +#endif // IXWEBSOCKET_USE_OPEN_SSL diff --git a/GermanAirlinesVA-GAConnector/ixwebsocket/include/IXSocketServer.h b/GermanAirlinesVA-GAConnector/ixwebsocket/include/IXSocketServer.h new file mode 100644 index 0000000..2ec6a4e --- /dev/null +++ b/GermanAirlinesVA-GAConnector/ixwebsocket/include/IXSocketServer.h @@ -0,0 +1,134 @@ +/* + * IXSocketServer.h + * Author: Benjamin Sergeant + * Copyright (c) 2018 Machine Zone, Inc. All rights reserved. + */ + +#pragma once + +#include "IXConnectionState.h" +#include "IXNetSystem.h" +#include "IXSelectInterrupt.h" +#include "IXSocketTLSOptions.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include // pair + +namespace ix +{ +class Socket; + +class SocketServer +{ +public: + using ConnectionStateFactory = + std::function()>; + + // Each connection is handled by its own worker thread. + // We use a list as we only care about remove and append operations. + using ConnectionThreads = + std::list, std::thread>>; + + SocketServer(int port = SocketServer::kDefaultPort, + const std::string &host = SocketServer::kDefaultHost, + int backlog = SocketServer::kDefaultTcpBacklog, + size_t maxConnections = SocketServer::kDefaultMaxConnections, + int addressFamily = SocketServer::kDefaultAddressFamily); + virtual ~SocketServer(); + virtual void stop(); + + // It is possible to override ConnectionState through inheritance + // this method allows user to change the factory by returning an object + // that inherits from ConnectionState but has its own methods. + void setConnectionStateFactory( + const ConnectionStateFactory &connectionStateFactory); + + const static int kDefaultPort; + const static std::string kDefaultHost; + const static int kDefaultTcpBacklog; + const static size_t kDefaultMaxConnections; + const static int kDefaultAddressFamily; + + void start(); + std::pair listen(); + void wait(); + + void setTLSOptions(const SocketTLSOptions &socketTLSOptions); + + int getPort(); + std::string getHost(); + int getBacklog(); + std::size_t getMaxConnections(); + int getAddressFamily(); + +protected: + // Logging + void logError(const std::string &str); + void logInfo(const std::string &str); + + void stopAcceptingConnections(); + +private: + // Member variables + int _port; + std::string _host; + int _backlog; + size_t _maxConnections; + int _addressFamily; + + // socket for accepting connections + socket_t _serverFd; + + std::atomic _stop; + + std::mutex _logMutex; + + // background thread to wait for incoming connections + std::thread _thread; + void run(); + void onSetTerminatedCallback(); + + // background thread to cleanup (join) terminated threads + std::atomic _stopGc; + std::thread _gcThread; + void runGC(); + + // the list of (connectionState, threads) for each connections + ConnectionThreads _connectionsThreads; + std::mutex _connectionsThreadsMutex; + + // used to have the main control thread for a server + // wait for a 'terminate' notification without busy polling + std::condition_variable _conditionVariable; + std::mutex _conditionVariableMutex; + + // the factory to create ConnectionState objects + ConnectionStateFactory _connectionStateFactory; + + virtual void + handleConnection(std::unique_ptr, + std::shared_ptr connectionState) = 0; + virtual size_t getConnectedClientsCount() = 0; + + // Returns true if all connection threads are joined + void closeTerminatedThreads(); + size_t getConnectionsThreadsCount(); + + SocketTLSOptions _socketTLSOptions; + + // to wake up from select + SelectInterruptPtr _acceptSelectInterrupt; + + // used by the gc thread, to know that a thread needs to be garbage + // collected as a connection + std::condition_variable _conditionVariableGC; + std::mutex _conditionVariableMutexGC; +}; +} // namespace ix diff --git a/GermanAirlinesVA-GAConnector/ixwebsocket/include/IXSocketTLSOptions.h b/GermanAirlinesVA-GAConnector/ixwebsocket/include/IXSocketTLSOptions.h new file mode 100644 index 0000000..b2ae968 --- /dev/null +++ b/GermanAirlinesVA-GAConnector/ixwebsocket/include/IXSocketTLSOptions.h @@ -0,0 +1,53 @@ +/* + * IXSocketTLSOptions.h + * Author: Matt DeBoer + * Copyright (c) 2019 Machine Zone, Inc. All rights reserved. + */ + +#pragma once + +#include + +namespace ix +{ +struct SocketTLSOptions { +public: + // check validity of the object + bool isValid() const; + + // the certificate presented to peers + std::string certFile; + + // the key used for signing/encryption + std::string keyFile; + + // the ca certificate (or certificate bundle) file containing + // certificates to be trusted by peers; use 'SYSTEM' to + // leverage the system defaults, use 'NONE' to disable peer verification + std::string caFile = "SYSTEM"; + + // list of ciphers (rsa, etc...) + std::string ciphers = "DEFAULT"; + + // whether tls is enabled, used for server code + bool tls = false; + + bool hasCertAndKey() const; + + bool isUsingSystemDefaults() const; + + bool isUsingInMemoryCAs() const; + + bool isPeerVerifyDisabled() const; + + bool isUsingDefaultCiphers() const; + + const std::string &getErrorMsg() const; + + std::string getDescription() const; + +private: + mutable std::string _errMsg; + mutable bool _validated = false; +}; +} // namespace ix diff --git a/GermanAirlinesVA-GAConnector/ixwebsocket/include/IXStrCaseCompare.h b/GermanAirlinesVA-GAConnector/ixwebsocket/include/IXStrCaseCompare.h new file mode 100644 index 0000000..5c3d9a4 --- /dev/null +++ b/GermanAirlinesVA-GAConnector/ixwebsocket/include/IXStrCaseCompare.h @@ -0,0 +1,23 @@ +/* + * IXStrCaseCompare.h + * Author: Benjamin Sergeant + * Copyright (c) 2020 Machine Zone. All rights reserved. + */ + +#pragma once + +#include + +namespace ix +{ +struct CaseInsensitiveLess { + // Case Insensitive compare_less binary function + struct NocaseCompare { + bool operator()(const unsigned char &c1, const unsigned char &c2) const; + }; + + static bool cmp(const std::string &s1, const std::string &s2); + + bool operator()(const std::string &s1, const std::string &s2) const; +}; +} // namespace ix diff --git a/GermanAirlinesVA-GAConnector/ixwebsocket/include/IXUdpSocket.h b/GermanAirlinesVA-GAConnector/ixwebsocket/include/IXUdpSocket.h new file mode 100644 index 0000000..75cef02 --- /dev/null +++ b/GermanAirlinesVA-GAConnector/ixwebsocket/include/IXUdpSocket.h @@ -0,0 +1,45 @@ +/* + * IXUdpSocket.h + * Author: Benjamin Sergeant + * Copyright (c) 2020 Machine Zone, Inc. All rights reserved. + */ + +#pragma once + +#include +#include +#include + +#ifdef _WIN32 +#ifndef _SSIZE_T_DEFINED +#include +typedef SSIZE_T ssize_t; +#endif +#endif + +#include "IXNetSystem.h" + +namespace ix +{ +class UdpSocket +{ +public: + UdpSocket(int fd = -1); + ~UdpSocket(); + + // Virtual methods + bool init(const std::string &host, int port, std::string &errMsg); + ssize_t sendto(const std::string &buffer); + ssize_t recvfrom(char *buffer, size_t length); + + void close(); + + static int getErrno(); + static bool isWaitNeeded(); + static void closeSocket(int fd); + +private: + std::atomic _sockfd; + struct sockaddr_in _server; +}; +} // namespace ix diff --git a/GermanAirlinesVA-GAConnector/ixwebsocket/include/IXUniquePtr.h b/GermanAirlinesVA-GAConnector/ixwebsocket/include/IXUniquePtr.h new file mode 100644 index 0000000..0fb530a --- /dev/null +++ b/GermanAirlinesVA-GAConnector/ixwebsocket/include/IXUniquePtr.h @@ -0,0 +1,18 @@ +/* + * IXUniquePtr.h + * Author: Benjamin Sergeant + * Copyright (c) 2020 Machine Zone, Inc. All rights reserved. + */ + +#pragma once + +#include + +namespace ix +{ +template +std::unique_ptr make_unique(Args &&... args) +{ + return std::unique_ptr(new T(std::forward(args)...)); +} +} // namespace ix diff --git a/GermanAirlinesVA-GAConnector/ixwebsocket/include/IXUrlParser.h b/GermanAirlinesVA-GAConnector/ixwebsocket/include/IXUrlParser.h new file mode 100644 index 0000000..e7ed1cc --- /dev/null +++ b/GermanAirlinesVA-GAConnector/ixwebsocket/include/IXUrlParser.h @@ -0,0 +1,23 @@ +/* + * IXUrlParser.h + * Author: Benjamin Sergeant + * Copyright (c) 2019 Machine Zone, Inc. All rights reserved. + */ + +#pragma once + +#include + +namespace ix +{ +class UrlParser +{ +public: + static bool parse(const std::string &url, + std::string &protocol, + std::string &host, + std::string &path, + std::string &query, + int &port); +}; +} // namespace ix diff --git a/GermanAirlinesVA-GAConnector/ixwebsocket/include/IXUserAgent.h b/GermanAirlinesVA-GAConnector/ixwebsocket/include/IXUserAgent.h new file mode 100644 index 0000000..7278494 --- /dev/null +++ b/GermanAirlinesVA-GAConnector/ixwebsocket/include/IXUserAgent.h @@ -0,0 +1,14 @@ +/* + * IXUserAgent.h + * Author: Benjamin Sergeant + * Copyright (c) 2019 Machine Zone, Inc. All rights reserved. + */ + +#pragma once + +#include + +namespace ix +{ +std::string userAgent(); +} // namespace ix diff --git a/GermanAirlinesVA-GAConnector/ixwebsocket/include/IXUtf8Validator.h b/GermanAirlinesVA-GAConnector/ixwebsocket/include/IXUtf8Validator.h new file mode 100644 index 0000000..8e8fb87 --- /dev/null +++ b/GermanAirlinesVA-GAConnector/ixwebsocket/include/IXUtf8Validator.h @@ -0,0 +1,184 @@ +/* + * The following code is adapted from code originally written by Bjoern + * Hoehrmann . See + * http://bjoern.hoehrmann.de/utf-8/decoder/dfa/ for details. + * + * The original license: + * + * Copyright (c) 2008-2009 Bjoern Hoehrmann + * + * 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. + */ + +/* + * IXUtf8Validator.h + * Author: Benjamin Sergeant + * Copyright (c) 2019 Machine Zone, Inc. All rights reserved. + * + * From websocketpp. Tiny modifications made for code style, function names + * etc... + */ + +#pragma once + +#include +#include + +namespace ix +{ +/// State that represents a valid utf8 input sequence +static unsigned int const utf8_accept = 0; +/// State that represents an invalid utf8 input sequence +static unsigned int const utf8_reject = 1; + +/// Lookup table for the UTF8 decode state machine +static uint8_t const utf8d[] = { + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 00..1f + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 20..3f + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 40..5f + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 60..7f + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, // 80..9f + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, // a0..bf + 8, 8, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, // c0..df + 0xa, 0x3, 0x3, 0x3, 0x3, 0x3, 0x3, 0x3, 0x3, 0x3, 0x3, + 0x3, 0x3, 0x4, 0x3, 0x3, // e0..ef + 0xb, 0x6, 0x6, 0x6, 0x5, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, + 0x8, 0x8, 0x8, 0x8, 0x8, // f0..ff + 0x0, 0x1, 0x2, 0x3, 0x5, 0x8, 0x7, 0x1, 0x1, 0x1, 0x4, + 0x6, 0x1, 0x1, 0x1, 0x1, // s0..s0 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, + 1, 0, 1, 0, 1, 1, 1, 1, 1, 1, // s1..s2 + 1, 2, 1, 1, 1, 1, 1, 2, 1, 2, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 2, 1, 1, 1, 1, 1, 1, 1, 1, // s3..s4 + 1, 2, 1, 1, 1, 1, 1, 1, 1, 2, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 3, 1, 3, 1, 1, 1, 1, 1, 1, // s5..s6 + 1, 3, 1, 1, 1, 1, 1, 3, 1, 3, 1, + 1, 1, 1, 1, 1, 1, 3, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // s7..s8 +}; + +/// Decode the next byte of a UTF8 sequence +/** + * @param [out] state The decoder state to advance + * @param [out] codep The codepoint to fill in + * @param [in] byte The byte to input + * @return The ending state of the decode operation + */ +inline uint32_t decodeNextByte(uint32_t *state, uint32_t *codep, uint8_t byte) +{ + uint32_t type = utf8d[byte]; + + *codep = (*state != utf8_accept) ? (byte & 0x3fu) | (*codep << 6) + : (0xff >> type) & (byte); + + *state = utf8d[256 + *state * 16 + type]; + return *state; +} + +/// Provides streaming UTF8 validation functionality +class Utf8Validator +{ +public: + /// Construct and initialize the validator + Utf8Validator() : m_state(utf8_accept), m_codepoint(0) {} + + /// Advance the state of the validator with the next input byte + /** + * @param byte The byte to advance the validation state with + * @return Whether or not the byte resulted in a validation error. + */ + bool consume(uint8_t byte) + { + if (decodeNextByte(&m_state, &m_codepoint, byte) == utf8_reject) { + return false; + } + return true; + } + + /// Advance Validator state with input from an iterator pair + /** + * @param begin Input iterator to the start of the input range + * @param end Input iterator to the end of the input range + * @return Whether or not decoding the bytes resulted in a validation error. + */ + template + bool decode(iterator_type begin, iterator_type end) + { + for (iterator_type it = begin; it != end; ++it) { + unsigned int result = decodeNextByte(&m_state, + &m_codepoint, + static_cast(*it)); + + if (result == utf8_reject) { + return false; + } + } + return true; + } + + /// Return whether the input sequence ended on a valid utf8 codepoint + /** + * @return Whether or not the input sequence ended on a valid codepoint. + */ + bool complete() { return m_state == utf8_accept; } + + /// Reset the Validator to decode another message + void reset() + { + m_state = utf8_accept; + m_codepoint = 0; + } + +private: + uint32_t m_state; + uint32_t m_codepoint; +}; + +/// Validate a UTF8 string +/** + * convenience function that creates a Validator, validates a complete string + * and returns the result. + */ +inline bool validateUtf8(std::string const &s) +{ + Utf8Validator v; + if (!v.decode(s.begin(), s.end())) { + return false; + } + return v.complete(); +} + +} // namespace ix diff --git a/GermanAirlinesVA-GAConnector/ixwebsocket/include/IXUuid.h b/GermanAirlinesVA-GAConnector/ixwebsocket/include/IXUuid.h new file mode 100644 index 0000000..f7c70b8 --- /dev/null +++ b/GermanAirlinesVA-GAConnector/ixwebsocket/include/IXUuid.h @@ -0,0 +1,17 @@ +/* + * IXUuid.h + * Author: Benjamin Sergeant + * Copyright (c) 2017 Machine Zone. All rights reserved. + */ +#pragma once + +#include + +namespace ix +{ +/** + * Generate a random uuid + */ +std::string uuid4(); + +} // namespace ix diff --git a/GermanAirlinesVA-GAConnector/ixwebsocket/include/IXWebSocket.h b/GermanAirlinesVA-GAConnector/ixwebsocket/include/IXWebSocket.h new file mode 100644 index 0000000..1e841f0 --- /dev/null +++ b/GermanAirlinesVA-GAConnector/ixwebsocket/include/IXWebSocket.h @@ -0,0 +1,174 @@ +/* + * IXWebSocket.h + * Author: Benjamin Sergeant + * Copyright (c) 2017-2018 Machine Zone, Inc. All rights reserved. + * + * WebSocket RFC + * https://tools.ietf.org/html/rfc6455 + */ + +#pragma once + +#include "IXProgressCallback.h" +#include "IXSocketTLSOptions.h" +#include "IXWebSocketCloseConstants.h" +#include "IXWebSocketErrorInfo.h" +#include "IXWebSocketHttpHeaders.h" +#include "IXWebSocketMessage.h" +#include "IXWebSocketPerMessageDeflateOptions.h" +#include "IXWebSocketSendInfo.h" +#include "IXWebSocketTransport.h" +#include +#include +#include +#include +#include + +namespace ix +{ +// https://developer.mozilla.org/en-US/docs/Web/API/WebSocket#Ready_state_constants +enum class ReadyState { Connecting = 0, Open = 1, Closing = 2, Closed = 3 }; + +using OnMessageCallback = std::function; + +using OnTrafficTrackerCallback = + std::function; + +class WebSocket +{ +public: + WebSocket(); + ~WebSocket(); + + void setUrl(const std::string &url); + + // send extra headers in client handshake request + void setExtraHeaders(const WebSocketHttpHeaders &headers); + void setPerMessageDeflateOptions( + const WebSocketPerMessageDeflateOptions &perMessageDeflateOptions); + void setTLSOptions(const SocketTLSOptions &socketTLSOptions); + void setPingInterval(int pingIntervalSecs); + void enablePong(); + void disablePong(); + void enablePerMessageDeflate(); + void disablePerMessageDeflate(); + void addSubProtocol(const std::string &subProtocol); + void setHandshakeTimeout(int handshakeTimeoutSecs); + + // Run asynchronously, by calling start and stop. + void start(); + + // stop is synchronous + void stop(uint16_t code = WebSocketCloseConstants::kNormalClosureCode, + const std::string &reason = + WebSocketCloseConstants::kNormalClosureMessage); + + // Run in blocking mode, by connecting first manually, and then calling run. + WebSocketInitResult connect(int timeoutSecs); + void run(); + + // send is in text mode by default + WebSocketSendInfo + send(const std::string &data, + bool binary = false, + const OnProgressCallback &onProgressCallback = nullptr); + WebSocketSendInfo + sendBinary(const std::string &text, + const OnProgressCallback &onProgressCallback = nullptr); + WebSocketSendInfo + sendText(const std::string &text, + const OnProgressCallback &onProgressCallback = nullptr); + WebSocketSendInfo ping(const std::string &text); + + void close(uint16_t code = WebSocketCloseConstants::kNormalClosureCode, + const std::string &reason = + WebSocketCloseConstants::kNormalClosureMessage); + + void setOnMessageCallback(const OnMessageCallback &callback); + bool isOnMessageCallbackRegistered() const; + static void + setTrafficTrackerCallback(const OnTrafficTrackerCallback &callback); + static void resetTrafficTrackerCallback(); + + ReadyState getReadyState() const; + static std::string readyStateToString(ReadyState readyState); + + const std::string getUrl() const; + const WebSocketPerMessageDeflateOptions getPerMessageDeflateOptions() const; + int getPingInterval() const; + size_t bufferedAmount() const; + + void enableAutomaticReconnection(); + void disableAutomaticReconnection(); + bool isAutomaticReconnectionEnabled() const; + void setMaxWaitBetweenReconnectionRetries( + uint32_t maxWaitBetweenReconnectionRetries); + void setMinWaitBetweenReconnectionRetries( + uint32_t minWaitBetweenReconnectionRetries); + uint32_t getMaxWaitBetweenReconnectionRetries() const; + uint32_t getMinWaitBetweenReconnectionRetries() const; + const std::vector &getSubProtocols(); + +private: + WebSocketSendInfo sendMessage(const std::string &text, + SendMessageKind sendMessageKind, + const OnProgressCallback &callback = nullptr); + + bool isConnected() const; + bool isClosing() const; + void checkConnection(bool firstConnectionAttempt); + static void invokeTrafficTrackerCallback(size_t size, bool incoming); + + // Server + WebSocketInitResult connectToSocket(std::unique_ptr, + int timeoutSecs, + bool enablePerMessageDeflate); + + WebSocketTransport _ws; + + std::string _url; + WebSocketHttpHeaders _extraHeaders; + + WebSocketPerMessageDeflateOptions _perMessageDeflateOptions; + + SocketTLSOptions _socketTLSOptions; + + mutable std::mutex _configMutex; // protect all config variables access + + OnMessageCallback _onMessageCallback; + static OnTrafficTrackerCallback _onTrafficTrackerCallback; + + std::atomic _stop; + std::thread _thread; + std::mutex _writeMutex; + + // Automatic reconnection + std::atomic _automaticReconnection; + static const uint32_t kDefaultMaxWaitBetweenReconnectionRetries; + static const uint32_t kDefaultMinWaitBetweenReconnectionRetries; + uint32_t _maxWaitBetweenReconnectionRetries; + uint32_t _minWaitBetweenReconnectionRetries; + + // Make the sleeping in the automatic reconnection cancellable + std::mutex _sleepMutex; + std::condition_variable _sleepCondition; + + std::atomic _handshakeTimeoutSecs; + static const int kDefaultHandShakeTimeoutSecs; + + // enable or disable PONG frame response to received PING frame + bool _enablePong; + static const bool kDefaultEnablePong; + + // Optional ping and pong timeout + int _pingIntervalSecs; + int _pingTimeoutSecs; + static const int kDefaultPingIntervalSecs; + static const int kDefaultPingTimeoutSecs; + + // Subprotocols + std::vector _subProtocols; + + friend class WebSocketServer; +}; +} // namespace ix diff --git a/GermanAirlinesVA-GAConnector/ixwebsocket/include/IXWebSocketCloseConstants.h b/GermanAirlinesVA-GAConnector/ixwebsocket/include/IXWebSocketCloseConstants.h new file mode 100644 index 0000000..d70dfd5 --- /dev/null +++ b/GermanAirlinesVA-GAConnector/ixwebsocket/include/IXWebSocketCloseConstants.h @@ -0,0 +1,36 @@ +/* + * IXWebSocketCloseConstants.h + * Author: Benjamin Sergeant + * Copyright (c) 2019 Machine Zone, Inc. All rights reserved. + */ + +#pragma once + +#include +#include + +namespace ix +{ +struct WebSocketCloseConstants { + static const uint16_t kNormalClosureCode; + static const uint16_t kInternalErrorCode; + static const uint16_t kAbnormalCloseCode; + static const uint16_t kProtocolErrorCode; + static const uint16_t kNoStatusCodeErrorCode; + static const uint16_t kInvalidFramePayloadData; + + static const std::string kNormalClosureMessage; + static const std::string kInternalErrorMessage; + static const std::string kAbnormalCloseMessage; + static const std::string kPingTimeoutMessage; + static const std::string kProtocolErrorMessage; + static const std::string kNoStatusCodeErrorMessage; + static const std::string kProtocolErrorReservedBitUsed; + static const std::string kProtocolErrorPingPayloadOversized; + static const std::string kProtocolErrorCodeControlMessageFragmented; + static const std::string kProtocolErrorCodeDataOpcodeOutOfSequence; + static const std::string kProtocolErrorCodeContinuationOpCodeOutOfSequence; + static const std::string kInvalidFramePayloadDataMessage; + static const std::string kInvalidCloseCodeMessage; +}; +} // namespace ix diff --git a/GermanAirlinesVA-GAConnector/ixwebsocket/include/IXWebSocketCloseInfo.h b/GermanAirlinesVA-GAConnector/ixwebsocket/include/IXWebSocketCloseInfo.h new file mode 100644 index 0000000..fd6abc8 --- /dev/null +++ b/GermanAirlinesVA-GAConnector/ixwebsocket/include/IXWebSocketCloseInfo.h @@ -0,0 +1,27 @@ +/* + * IXWebSocketCloseInfo.h + * Author: Benjamin Sergeant + * Copyright (c) 2017-2019 Machine Zone, Inc. All rights reserved. + */ + +#pragma once + +#include +#include + +namespace ix +{ +struct WebSocketCloseInfo { + uint16_t code; + std::string reason; + bool remote; + + WebSocketCloseInfo(uint16_t c = 0, + const std::string &r = std::string(), + bool rem = false) + : code(c), reason(r), remote(rem) + { + ; + } +}; +} // namespace ix diff --git a/GermanAirlinesVA-GAConnector/ixwebsocket/include/IXWebSocketErrorInfo.h b/GermanAirlinesVA-GAConnector/ixwebsocket/include/IXWebSocketErrorInfo.h new file mode 100644 index 0000000..07cb8e6 --- /dev/null +++ b/GermanAirlinesVA-GAConnector/ixwebsocket/include/IXWebSocketErrorInfo.h @@ -0,0 +1,21 @@ +/* + * IXWebSocketErrorInfo.h + * Author: Benjamin Sergeant + * Copyright (c) 2017-2018 Machine Zone, Inc. All rights reserved. + */ + +#pragma once + +#include +#include + +namespace ix +{ +struct WebSocketErrorInfo { + uint32_t retries = 0; + double wait_time = 0; + int http_status = 0; + std::string reason; + bool decompressionError = false; +}; +} // namespace ix diff --git a/GermanAirlinesVA-GAConnector/ixwebsocket/include/IXWebSocketHandshake.h b/GermanAirlinesVA-GAConnector/ixwebsocket/include/IXWebSocketHandshake.h new file mode 100644 index 0000000..0a86fb8 --- /dev/null +++ b/GermanAirlinesVA-GAConnector/ixwebsocket/include/IXWebSocketHandshake.h @@ -0,0 +1,57 @@ +/* + * IXWebSocketHandshake.h + * Author: Benjamin Sergeant + * Copyright (c) 2019 Machine Zone, Inc. All rights reserved. + */ + +#pragma once + +#include "IXCancellationRequest.h" +#include "IXSocket.h" +#include "IXWebSocketHttpHeaders.h" +#include "IXWebSocketInitResult.h" +#include "IXWebSocketPerMessageDeflate.h" +#include "IXWebSocketPerMessageDeflateOptions.h" +#include +#include +#include +#include + +namespace ix +{ +class WebSocketHandshake +{ +public: + WebSocketHandshake( + std::atomic &requestInitCancellation, + std::unique_ptr &_socket, + WebSocketPerMessageDeflatePtr &perMessageDeflate, + WebSocketPerMessageDeflateOptions &perMessageDeflateOptions, + std::atomic &enablePerMessageDeflate); + + WebSocketInitResult + clientHandshake(const std::string &url, + const WebSocketHttpHeaders &extraHeaders, + const std::string &host, + const std::string &path, + int port, + int timeoutSecs); + + WebSocketInitResult serverHandshake(int timeoutSecs, + bool enablePerMessageDeflate); + +private: + std::string genRandomString(const int len); + + // Parse HTTP headers + WebSocketInitResult sendErrorResponse(int code, const std::string &reason); + + bool insensitiveStringCompare(const std::string &a, const std::string &b); + + std::atomic &_requestInitCancellation; + std::unique_ptr &_socket; + WebSocketPerMessageDeflatePtr &_perMessageDeflate; + WebSocketPerMessageDeflateOptions &_perMessageDeflateOptions; + std::atomic &_enablePerMessageDeflate; +}; +} // namespace ix diff --git a/GermanAirlinesVA-GAConnector/ixwebsocket/include/IXWebSocketHandshakeKeyGen.h b/GermanAirlinesVA-GAConnector/ixwebsocket/include/IXWebSocketHandshakeKeyGen.h new file mode 100644 index 0000000..285cbce --- /dev/null +++ b/GermanAirlinesVA-GAConnector/ixwebsocket/include/IXWebSocketHandshakeKeyGen.h @@ -0,0 +1,174 @@ +// Copyright (c) 2016 Alex Hultman and contributors + +// This software is provided 'as-is', without any express or implied +// warranty. In no event will the authors be held liable for any damages +// arising from the use of this software. + +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it +// freely, subject to the following restrictions: + +// 1. The origin of this software must not be misrepresented; you must not +// claim that you wrote the original software. If you use this software +// in a product, an acknowledgement in the product documentation would be +// appreciated but is not required. +// 2. Altered source versions must be plainly marked as such, and must not be +// misrepresented as being the original software. +// 3. This notice may not be removed or altered from any source distribution. + +#pragma once + +#include +#include +#include +#include + +class WebSocketHandshakeKeyGen +{ + template struct static_for { + void operator()(uint32_t *a, uint32_t *b) + { + static_for()(a, b); + T::template f(a, b); + } + }; + + template struct static_for<0, T> { + void operator()(uint32_t * /*a*/, uint32_t * /*hash*/) {} + }; + + template struct Sha1Loop { + static inline uint32_t rol(uint32_t value, size_t bits) + { + return (value << bits) | (value >> (32 - bits)); + } + static inline uint32_t blk(uint32_t b[16], size_t i) + { + return rol(b[(i + 13) & 15] ^ b[(i + 8) & 15] ^ b[(i + 2) & 15] ^ + b[i], + 1); + } + + template static inline void f(uint32_t *a, uint32_t *b) + { + switch (state) { + case 1: + a[i % 5] += + ((a[(3 + i) % 5] & (a[(2 + i) % 5] ^ a[(1 + i) % 5])) ^ + a[(1 + i) % 5]) + + b[i] + 0x5a827999 + rol(a[(4 + i) % 5], 5); + a[(3 + i) % 5] = rol(a[(3 + i) % 5], 30); + break; + case 2: + b[i] = blk(b, i); + a[(1 + i) % 5] += + ((a[(4 + i) % 5] & (a[(3 + i) % 5] ^ a[(2 + i) % 5])) ^ + a[(2 + i) % 5]) + + b[i] + 0x5a827999 + rol(a[(5 + i) % 5], 5); + a[(4 + i) % 5] = rol(a[(4 + i) % 5], 30); + break; + case 3: + b[(i + 4) % 16] = blk(b, (i + 4) % 16); + a[i % 5] += + (a[(3 + i) % 5] ^ a[(2 + i) % 5] ^ a[(1 + i) % 5]) + + b[(i + 4) % 16] + 0x6ed9eba1 + rol(a[(4 + i) % 5], 5); + a[(3 + i) % 5] = rol(a[(3 + i) % 5], 30); + break; + case 4: + b[(i + 8) % 16] = blk(b, (i + 8) % 16); + a[i % 5] += + (((a[(3 + i) % 5] | a[(2 + i) % 5]) & a[(1 + i) % 5]) | + (a[(3 + i) % 5] & a[(2 + i) % 5])) + + b[(i + 8) % 16] + 0x8f1bbcdc + rol(a[(4 + i) % 5], 5); + a[(3 + i) % 5] = rol(a[(3 + i) % 5], 30); + break; + case 5: + b[(i + 12) % 16] = blk(b, (i + 12) % 16); + a[i % 5] += + (a[(3 + i) % 5] ^ a[(2 + i) % 5] ^ a[(1 + i) % 5]) + + b[(i + 12) % 16] + 0xca62c1d6 + rol(a[(4 + i) % 5], 5); + a[(3 + i) % 5] = rol(a[(3 + i) % 5], 30); + break; + case 6: + b[i] += a[4 - i]; + } + } + }; + + static inline void sha1(uint32_t hash[5], uint32_t b[16]) + { + uint32_t a[5] = {hash[4], hash[3], hash[2], hash[1], hash[0]}; + static_for<16, Sha1Loop<1>>()(a, b); + static_for<4, Sha1Loop<2>>()(a, b); + static_for<20, Sha1Loop<3>>()(a, b); + static_for<20, Sha1Loop<4>>()(a, b); + static_for<20, Sha1Loop<5>>()(a, b); + static_for<5, Sha1Loop<6>>()(a, hash); + } + + static inline void base64(unsigned char *src, char *dst) + { + const char *b64 = + "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; + for (int i = 0; i < 18; i += 3) { + *dst++ = b64[(src[i] >> 2) & 63]; + *dst++ = b64[((src[i] & 3) << 4) | ((src[i + 1] & 240) >> 4)]; + *dst++ = b64[((src[i + 1] & 15) << 2) | ((src[i + 2] & 192) >> 6)]; + *dst++ = b64[src[i + 2] & 63]; + } + *dst++ = b64[(src[18] >> 2) & 63]; + *dst++ = b64[((src[18] & 3) << 4) | ((src[19] & 240) >> 4)]; + *dst++ = b64[((src[19] & 15) << 2)]; + *dst++ = '='; + } + +public: + static inline void generate(const std::string &inputStr, char output[28]) + { + char input[25] = {}; + strncpy(input, inputStr.c_str(), 25 - 1); + input[25 - 1] = '\0'; + + uint32_t b_output[5] = {0x67452301, + 0xefcdab89, + 0x98badcfe, + 0x10325476, + 0xc3d2e1f0}; + uint32_t b_input[16] = {0, + 0, + 0, + 0, + 0, + 0, + 0x32353845, + 0x41464135, + 0x2d453931, + 0x342d3437, + 0x44412d39, + 0x3543412d, + 0x43354142, + 0x30444338, + 0x35423131, + 0x80000000}; + + for (int i = 0; i < 6; i++) { + b_input[i] = (input[4 * i + 3] & 0xff) | + (input[4 * i + 2] & 0xff) << 8 | + (input[4 * i + 1] & 0xff) << 16 | + (input[4 * i + 0] & 0xff) << 24; + } + sha1(b_output, b_input); + uint32_t last_b[16] = + {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 480}; + sha1(b_output, last_b); + for (int i = 0; i < 5; i++) { + uint32_t tmp = b_output[i]; + char *bytes = (char *)&b_output[i]; + bytes[3] = tmp & 0xff; + bytes[2] = (tmp >> 8) & 0xff; + bytes[1] = (tmp >> 16) & 0xff; + bytes[0] = (tmp >> 24) & 0xff; + } + base64((unsigned char *)b_output, output); + } +}; diff --git a/GermanAirlinesVA-GAConnector/ixwebsocket/include/IXWebSocketHttpHeaders.h b/GermanAirlinesVA-GAConnector/ixwebsocket/include/IXWebSocketHttpHeaders.h new file mode 100644 index 0000000..b93034f --- /dev/null +++ b/GermanAirlinesVA-GAConnector/ixwebsocket/include/IXWebSocketHttpHeaders.h @@ -0,0 +1,25 @@ +/* + * IXWebSocketHttpHeaders.h + * Author: Benjamin Sergeant + * Copyright (c) 2018 Machine Zone, Inc. All rights reserved. + */ + +#pragma once + +#include "IXCancellationRequest.h" +#include "IXStrCaseCompare.h" +#include +#include +#include + +namespace ix +{ +class Socket; + +using WebSocketHttpHeaders = + std::map; + +std::pair + parseHttpHeaders(std::unique_ptr &socket, + const CancellationRequest &isCancellationRequested); +} // namespace ix diff --git a/GermanAirlinesVA-GAConnector/ixwebsocket/include/IXWebSocketInitResult.h b/GermanAirlinesVA-GAConnector/ixwebsocket/include/IXWebSocketInitResult.h new file mode 100644 index 0000000..414ae0c --- /dev/null +++ b/GermanAirlinesVA-GAConnector/ixwebsocket/include/IXWebSocketInitResult.h @@ -0,0 +1,35 @@ +/* + * IXWebSocketInitResult.h + * Author: Benjamin Sergeant + * Copyright (c) 2019 Machine Zone, Inc. All rights reserved. + */ + +#pragma once + +#include "IXWebSocketHttpHeaders.h" + +namespace ix +{ +struct WebSocketInitResult { + bool success; + int http_status; + std::string errorStr; + WebSocketHttpHeaders headers; + std::string uri; + std::string protocol; + + WebSocketInitResult(bool s = false, + int status = 0, + const std::string &e = std::string(), + WebSocketHttpHeaders h = WebSocketHttpHeaders(), + const std::string &u = std::string()) + { + success = s; + http_status = status; + errorStr = e; + headers = h; + uri = u; + protocol = h["Sec-WebSocket-Protocol"]; + } +}; +} // namespace ix diff --git a/GermanAirlinesVA-GAConnector/ixwebsocket/include/IXWebSocketMessage.h b/GermanAirlinesVA-GAConnector/ixwebsocket/include/IXWebSocketMessage.h new file mode 100644 index 0000000..006b7f4 --- /dev/null +++ b/GermanAirlinesVA-GAConnector/ixwebsocket/include/IXWebSocketMessage.h @@ -0,0 +1,55 @@ +/* + * IXWebSocketMessage.h + * Author: Benjamin Sergeant + * Copyright (c) 2017-2019 Machine Zone, Inc. All rights reserved. + */ + +#pragma once + +#include "IXWebSocketCloseInfo.h" +#include "IXWebSocketErrorInfo.h" +#include "IXWebSocketMessageType.h" +#include "IXWebSocketOpenInfo.h" +#include +#include + +namespace ix +{ +struct WebSocketMessage { + WebSocketMessageType type; + const std::string &str; + size_t wireSize; + WebSocketErrorInfo errorInfo; + WebSocketOpenInfo openInfo; + WebSocketCloseInfo closeInfo; + bool binary; + + WebSocketMessage(WebSocketMessageType t, + const std::string &s, + size_t w, + WebSocketErrorInfo e, + WebSocketOpenInfo o, + WebSocketCloseInfo c, + bool b = false) + : type(t), str(s), wireSize(w), errorInfo(e), openInfo(o), closeInfo(c), + binary(b) + { + ; + } + + /** + * @brief Deleted overload to prevent binding `str` to a temporary, which + * would cause undefined behavior since class members don't extend lifetime + * beyond the constructor call. + */ + WebSocketMessage(WebSocketMessageType t, + std::string &&s, + size_t w, + WebSocketErrorInfo e, + WebSocketOpenInfo o, + WebSocketCloseInfo c, + bool b = false) = delete; +}; + +using WebSocketMessagePtr = std::unique_ptr; +} // namespace ix diff --git a/GermanAirlinesVA-GAConnector/ixwebsocket/include/IXWebSocketMessageType.h b/GermanAirlinesVA-GAConnector/ixwebsocket/include/IXWebSocketMessageType.h new file mode 100644 index 0000000..6073b9b --- /dev/null +++ b/GermanAirlinesVA-GAConnector/ixwebsocket/include/IXWebSocketMessageType.h @@ -0,0 +1,20 @@ +/* + * IXWebSocketMessageType.h + * Author: Benjamin Sergeant + * Copyright (c) 2017-2019 Machine Zone, Inc. All rights reserved. + */ + +#pragma once + +namespace ix +{ +enum class WebSocketMessageType { + Message = 0, + Open = 1, + Close = 2, + Error = 3, + Ping = 4, + Pong = 5, + Fragment = 6 +}; +} diff --git a/GermanAirlinesVA-GAConnector/ixwebsocket/include/IXWebSocketOpenInfo.h b/GermanAirlinesVA-GAConnector/ixwebsocket/include/IXWebSocketOpenInfo.h new file mode 100644 index 0000000..2221323 --- /dev/null +++ b/GermanAirlinesVA-GAConnector/ixwebsocket/include/IXWebSocketOpenInfo.h @@ -0,0 +1,28 @@ +/* + * IXWebSocketOpenInfo.h + * Author: Benjamin Sergeant + * Copyright (c) 2017-2019 Machine Zone, Inc. All rights reserved. + */ + +#pragma once + +#include "IXWebSocketHttpHeaders.h" +#include +#include + +namespace ix +{ +struct WebSocketOpenInfo { + std::string uri; + WebSocketHttpHeaders headers; + std::string protocol; + + WebSocketOpenInfo(const std::string &u = std::string(), + const WebSocketHttpHeaders &h = WebSocketHttpHeaders(), + const std::string &p = std::string()) + : uri(u), headers(h), protocol(p) + { + ; + } +}; +} // namespace ix diff --git a/GermanAirlinesVA-GAConnector/ixwebsocket/include/IXWebSocketPerMessageDeflate.h b/GermanAirlinesVA-GAConnector/ixwebsocket/include/IXWebSocketPerMessageDeflate.h new file mode 100644 index 0000000..1b6aa21 --- /dev/null +++ b/GermanAirlinesVA-GAConnector/ixwebsocket/include/IXWebSocketPerMessageDeflate.h @@ -0,0 +1,64 @@ +/* + * Copyright (c) 2015, Peter Thorson. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of the WebSocket++ Project nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL PETER THORSON BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/* + * Author: Benjamin Sergeant + * Copyright (c) 2018 Machine Zone, Inc. All rights reserved. + * + * Adapted from websocketpp/extensions/permessage_deflate/enabled.hpp + * (same license as MZ: https://opensource.org/licenses/BSD-3-Clause) + */ + +#pragma once + +#include +#include + +namespace ix +{ +class WebSocketPerMessageDeflateOptions; +class WebSocketPerMessageDeflateCompressor; +class WebSocketPerMessageDeflateDecompressor; + +class WebSocketPerMessageDeflate +{ +public: + WebSocketPerMessageDeflate(); + ~WebSocketPerMessageDeflate(); + + bool + init(const WebSocketPerMessageDeflateOptions &perMessageDeflateOptions); + bool compress(const std::string &in, std::string &out); + bool decompress(const std::string &in, std::string &out); + +private: + std::unique_ptr _compressor; + std::unique_ptr _decompressor; +}; + +using WebSocketPerMessageDeflatePtr = + std::unique_ptr; +} // namespace ix diff --git a/GermanAirlinesVA-GAConnector/ixwebsocket/include/IXWebSocketPerMessageDeflateCodec.h b/GermanAirlinesVA-GAConnector/ixwebsocket/include/IXWebSocketPerMessageDeflateCodec.h new file mode 100644 index 0000000..0399817 --- /dev/null +++ b/GermanAirlinesVA-GAConnector/ixwebsocket/include/IXWebSocketPerMessageDeflateCodec.h @@ -0,0 +1,60 @@ +/* + * IXWebSocketPerMessageDeflateCodec.h + * Author: Benjamin Sergeant + * Copyright (c) 2018-2019 Machine Zone, Inc. All rights reserved. + */ + +#pragma once + +#ifdef IXWEBSOCKET_USE_ZLIB +#include "zlib.h" +#endif +#include +#include +#include + +namespace ix +{ +class WebSocketPerMessageDeflateCompressor +{ +public: + WebSocketPerMessageDeflateCompressor(); + ~WebSocketPerMessageDeflateCompressor(); + + bool init(uint8_t deflateBits, bool clientNoContextTakeOver); + bool compress(const std::string &in, std::string &out); + bool compress(const std::string &in, std::vector &out); + bool compress(const std::vector &in, std::string &out); + bool compress(const std::vector &in, std::vector &out); + +private: + template bool compressData(const T &in, S &out); + template bool endsWithEmptyUnCompressedBlock(const T &value); + + int _flush; + std::array _compressBuffer; + +#ifdef IXWEBSOCKET_USE_ZLIB + z_stream _deflateState; +#endif +}; + +class WebSocketPerMessageDeflateDecompressor +{ +public: + WebSocketPerMessageDeflateDecompressor(); + ~WebSocketPerMessageDeflateDecompressor(); + + bool init(uint8_t inflateBits, bool clientNoContextTakeOver); + bool decompress(const std::string &in, std::string &out); + +private: + int _flush; + std::array _compressBuffer; + +#ifdef IXWEBSOCKET_USE_ZLIB + z_stream _inflateState; +#endif +}; + +} // namespace ix diff --git a/GermanAirlinesVA-GAConnector/ixwebsocket/include/IXWebSocketPerMessageDeflateOptions.h b/GermanAirlinesVA-GAConnector/ixwebsocket/include/IXWebSocketPerMessageDeflateOptions.h new file mode 100644 index 0000000..4938284 --- /dev/null +++ b/GermanAirlinesVA-GAConnector/ixwebsocket/include/IXWebSocketPerMessageDeflateOptions.h @@ -0,0 +1,47 @@ +/* + * IXWebSocketPerMessageDeflateOptions.h + * Author: Benjamin Sergeant + * Copyright (c) 2018 Machine Zone, Inc. All rights reserved. + */ + +#pragma once + +#include + +namespace ix +{ +class WebSocketPerMessageDeflateOptions +{ +public: + WebSocketPerMessageDeflateOptions( + bool enabled = false, + bool clientNoContextTakeover = false, + bool serverNoContextTakeover = false, + uint8_t clientMaxWindowBits = kDefaultClientMaxWindowBits, + uint8_t serverMaxWindowBits = kDefaultServerMaxWindowBits); + + WebSocketPerMessageDeflateOptions(std::string extension); + + std::string generateHeader(); + bool enabled() const; + bool getClientNoContextTakeover() const; + bool getServerNoContextTakeover() const; + uint8_t getServerMaxWindowBits() const; + uint8_t getClientMaxWindowBits() const; + + static bool startsWith(const std::string &str, const std::string &start); + static std::string removeSpaces(const std::string &str); + + static uint8_t const kDefaultClientMaxWindowBits; + static uint8_t const kDefaultServerMaxWindowBits; + +private: + bool _enabled; + bool _clientNoContextTakeover; + bool _serverNoContextTakeover; + uint8_t _clientMaxWindowBits; + uint8_t _serverMaxWindowBits; + + void sanitizeClientMaxWindowBits(); +}; +} // namespace ix diff --git a/GermanAirlinesVA-GAConnector/ixwebsocket/include/IXWebSocketProxyServer.h b/GermanAirlinesVA-GAConnector/ixwebsocket/include/IXWebSocketProxyServer.h new file mode 100644 index 0000000..b2f0da0 --- /dev/null +++ b/GermanAirlinesVA-GAConnector/ixwebsocket/include/IXWebSocketProxyServer.h @@ -0,0 +1,24 @@ +/* + * IXWebSocketProxyServer.h + * Author: Benjamin Sergeant + * Copyright (c) 2019-2020 Machine Zone, Inc. All rights reserved. + */ +#pragma once + +#include "IXSocketTLSOptions.h" +#include +#include +#include +#include + +namespace ix +{ +using RemoteUrlsMapping = std::map; + +int websocket_proxy_server_main(int port, + const std::string &hostname, + const ix::SocketTLSOptions &tlsOptions, + const std::string &remoteUrl, + const RemoteUrlsMapping &remoteUrlsMapping, + bool verbose); +} // namespace ix diff --git a/GermanAirlinesVA-GAConnector/ixwebsocket/include/IXWebSocketSendInfo.h b/GermanAirlinesVA-GAConnector/ixwebsocket/include/IXWebSocketSendInfo.h new file mode 100644 index 0000000..78e1116 --- /dev/null +++ b/GermanAirlinesVA-GAConnector/ixwebsocket/include/IXWebSocketSendInfo.h @@ -0,0 +1,26 @@ +/* + * IXWebSocketSendInfo.h + * Author: Benjamin Sergeant + * Copyright (c) 2018 Machine Zone, Inc. All rights reserved. + */ + +#pragma once + +namespace ix +{ +struct WebSocketSendInfo { + bool success; + bool compressionError; + size_t payloadSize; + size_t wireSize; + + WebSocketSendInfo(bool s = false, + bool c = false, + size_t p = 0, + size_t w = 0) + : success(s), compressionError(c), payloadSize(p), wireSize(w) + { + ; + } +}; +} // namespace ix diff --git a/GermanAirlinesVA-GAConnector/ixwebsocket/include/IXWebSocketServer.h b/GermanAirlinesVA-GAConnector/ixwebsocket/include/IXWebSocketServer.h new file mode 100644 index 0000000..63bb7f8 --- /dev/null +++ b/GermanAirlinesVA-GAConnector/ixwebsocket/include/IXWebSocketServer.h @@ -0,0 +1,84 @@ +/* + * IXWebSocketServer.h + * Author: Benjamin Sergeant + * Copyright (c) 2018 Machine Zone, Inc. All rights reserved. + */ + +#pragma once + +#include "IXSocketServer.h" +#include "IXWebSocket.h" +#include +#include +#include +#include +#include +#include +#include +#include // pair + +namespace ix +{ +class WebSocketServer : public SocketServer +{ +public: + using OnConnectionCallback = + std::function, + std::shared_ptr)>; + + using OnClientMessageCallback = + std::function, + WebSocket &, + const WebSocketMessagePtr &)>; + + WebSocketServer( + int port = SocketServer::kDefaultPort, + const std::string &host = SocketServer::kDefaultHost, + int backlog = SocketServer::kDefaultTcpBacklog, + size_t maxConnections = SocketServer::kDefaultMaxConnections, + int handshakeTimeoutSecs = + WebSocketServer::kDefaultHandShakeTimeoutSecs, + int addressFamily = SocketServer::kDefaultAddressFamily); + virtual ~WebSocketServer(); + virtual void stop() final; + + void enablePong(); + void disablePong(); + void disablePerMessageDeflate(); + + void setOnConnectionCallback(const OnConnectionCallback &callback); + void setOnClientMessageCallback(const OnClientMessageCallback &callback); + + // Get all the connected clients + std::set> getClients(); + + void makeBroadcastServer(); + bool listenAndStart(); + + const static int kDefaultHandShakeTimeoutSecs; + + int getHandshakeTimeoutSecs(); + bool isPongEnabled(); + bool isPerMessageDeflateEnabled(); + +private: + // Member variables + int _handshakeTimeoutSecs; + bool _enablePong; + bool _enablePerMessageDeflate; + + OnConnectionCallback _onConnectionCallback; + OnClientMessageCallback _onClientMessageCallback; + + std::mutex _clientsMutex; + std::set> _clients; + + const static bool kDefaultEnablePong; + + // Methods + virtual void + handleConnection(std::unique_ptr socket, + std::shared_ptr connectionState); + virtual size_t getConnectedClientsCount() final; +}; +} // namespace ix diff --git a/GermanAirlinesVA-GAConnector/ixwebsocket/include/IXWebSocketTransport.h b/GermanAirlinesVA-GAConnector/ixwebsocket/include/IXWebSocketTransport.h new file mode 100644 index 0000000..e58a66d --- /dev/null +++ b/GermanAirlinesVA-GAConnector/ixwebsocket/include/IXWebSocketTransport.h @@ -0,0 +1,261 @@ +/* + * IXWebSocketTransport.h + * Author: Benjamin Sergeant + * Copyright (c) 2017-2018 Machine Zone, Inc. All rights reserved. + */ + +#pragma once + +// +// Adapted from https://github.com/dhbaird/easywsclient +// + +#include "IXCancellationRequest.h" +#include "IXProgressCallback.h" +#include "IXSocketTLSOptions.h" +#include "IXWebSocketCloseConstants.h" +#include "IXWebSocketHandshake.h" +#include "IXWebSocketHttpHeaders.h" +#include "IXWebSocketPerMessageDeflate.h" +#include "IXWebSocketPerMessageDeflateOptions.h" +#include "IXWebSocketSendInfo.h" +#include +#include +#include +#include +#include +#include +#include + +namespace ix +{ +class Socket; + +enum class SendMessageKind { Text, Binary, Ping }; + +class WebSocketTransport +{ +public: + enum class ReadyState { CLOSING, CLOSED, CONNECTING, OPEN }; + + enum class MessageKind { MSG_TEXT, MSG_BINARY, PING, PONG, FRAGMENT }; + + enum class PollResult { Succeeded, AbnormalClose, CannotFlushSendBuffer }; + + using OnMessageCallback = + std::function; + using OnCloseCallback = + std::function; + + WebSocketTransport(); + ~WebSocketTransport(); + + void configure( + const WebSocketPerMessageDeflateOptions &perMessageDeflateOptions, + const SocketTLSOptions &socketTLSOptions, + bool enablePong, + int pingIntervalSecs); + + // Client + WebSocketInitResult connectToUrl(const std::string &url, + const WebSocketHttpHeaders &headers, + int timeoutSecs); + + // Server + WebSocketInitResult connectToSocket(std::unique_ptr socket, + int timeoutSecs, + bool enablePerMessageDeflate); + + PollResult poll(); + WebSocketSendInfo sendBinary(const std::string &message, + const OnProgressCallback &onProgressCallback); + WebSocketSendInfo sendText(const std::string &message, + const OnProgressCallback &onProgressCallback); + WebSocketSendInfo sendPing(const std::string &message); + + void close(uint16_t code = WebSocketCloseConstants::kNormalClosureCode, + const std::string &reason = + WebSocketCloseConstants::kNormalClosureMessage, + size_t closeWireSize = 0, + bool remote = false); + + void closeSocket(); + + ReadyState getReadyState() const; + void setReadyState(ReadyState readyState); + void setOnCloseCallback(const OnCloseCallback &onCloseCallback); + void dispatch(PollResult pollResult, + const OnMessageCallback &onMessageCallback); + size_t bufferedAmount() const; + + // internal + WebSocketSendInfo sendHeartBeat(); + +private: + std::string _url; + + struct wsheader_type { + unsigned header_size; + bool fin; + bool rsv1; + bool rsv2; + bool rsv3; + bool mask; + enum opcode_type { + CONTINUATION = 0x0, + TEXT_FRAME = 0x1, + BINARY_FRAME = 0x2, + CLOSE = 8, + PING = 9, + PONG = 0xa, + } opcode; + int N0; + uint64_t N; + uint8_t masking_key[4]; + }; + + // Tells whether we should mask the data we send. + // client should mask but server should not + std::atomic _useMask; + + // Tells whether we should flush the send buffer before + // saying that a send is complete. This is the mode for server code. + std::atomic _blockingSend; + + // Buffer for reading from our socket. That buffer is never resized. + std::vector _readbuf; + + // Contains all messages that were fetched in the last socket read. + // This could be a mix of control messages (Close, Ping, etc...) and + // data messages. That buffer is resized + std::vector _rxbuf; + + // Contains all messages that are waiting to be sent + std::vector _txbuf; + mutable std::mutex _txbufMutex; + + // Hold fragments for multi-fragments messages in a list. We support + // receiving very large messages (tested messages up to 700M) and we cannot + // put them in a single buffer that is resized, as this operation can be + // slow when a buffer has its size increased 2 fold, while appending to a + // list has a fixed cost. + std::list _chunks; + + // Record the message kind (will be TEXT or BINARY) for a fragmented + // message, present in the first chunk, since the final chunk will be a + // CONTINUATION opcode and doesn't tell the full message kind + MessageKind _fragmentedMessageKind; + + // Ditto for whether a message is compressed + bool _receivedMessageCompressed; + + // Fragments are 32K long + static constexpr size_t kChunkSize = 1 << 15; + + // Underlying TCP socket + std::unique_ptr _socket; + std::mutex _socketMutex; + + // Hold the state of the connection (OPEN, CLOSED, etc...) + std::atomic _readyState; + + OnCloseCallback _onCloseCallback; + std::string _closeReason; + mutable std::mutex _closeReasonMutex; + std::atomic _closeCode; + std::atomic _closeWireSize; + std::atomic _closeRemote; + + // Data used for Per Message Deflate compression (with zlib) + WebSocketPerMessageDeflatePtr _perMessageDeflate; + WebSocketPerMessageDeflateOptions _perMessageDeflateOptions; + std::atomic _enablePerMessageDeflate; + + std::string _decompressedMessage; + std::string _compressedMessage; + + // Used to control TLS connection behavior + SocketTLSOptions _socketTLSOptions; + + // Used to cancel dns lookup + socket connect + http upgrade + std::atomic _requestInitCancellation; + + mutable std::mutex _closingTimePointMutex; + std::chrono::time_point _closingTimePoint; + static const int kClosingMaximumWaitingDelayInMs; + + // enable auto response to ping + std::atomic _enablePong; + static const bool kDefaultEnablePong; + + // Optional ping and pong timeout + int _pingIntervalSecs; + std::atomic _pongReceived; + + static const int kDefaultPingIntervalSecs; + static const std::string kPingMessage; + std::atomic _pingCount; + + // We record when ping are being sent so that we can know when to send the + // next one + mutable std::mutex _lastSendPingTimePointMutex; + std::chrono::time_point _lastSendPingTimePoint; + + // If this function returns true, it is time to send a new ping + bool pingIntervalExceeded(); + void initTimePointsAfterConnect(); + + // after calling close(), if no CLOSE frame answer is received back from the + // remote, we should close the connexion + bool closingDelayExceeded(); + + void sendCloseFrame(uint16_t code, const std::string &reason); + + void closeSocketAndSwitchToClosedState(uint16_t code, + const std::string &reason, + size_t closeWireSize, + bool remote); + + bool wakeUpFromPoll(uint64_t wakeUpCode); + + bool flushSendBuffer(); + bool sendOnSocket(); + bool receiveFromSocket(); + + template + WebSocketSendInfo + sendData(wsheader_type::opcode_type type, + const T &message, + bool compress, + const OnProgressCallback &onProgressCallback = nullptr); + + template + bool sendFragment(wsheader_type::opcode_type type, + bool fin, + Iterator begin, + Iterator end, + bool compress); + + void emitMessage(MessageKind messageKind, + const std::string &message, + bool compressedMessage, + const OnMessageCallback &onMessageCallback); + + bool isSendBufferEmpty() const; + + template + void appendToSendBuffer(const std::vector &header, + Iterator begin, + Iterator end, + uint64_t message_size, + uint8_t masking_key[4]); + + unsigned getRandomUnsigned(); + void unmaskReceiveBuffer(const wsheader_type &ws); + + std::string getMergedChunks() const; + + void setCloseReason(const std::string &reason); + const std::string &getCloseReason() const; +}; +} // namespace ix diff --git a/GermanAirlinesVA-GAConnector/ixwebsocket/include/IXWebSocketVersion.h b/GermanAirlinesVA-GAConnector/ixwebsocket/include/IXWebSocketVersion.h new file mode 100644 index 0000000..ccaec84 --- /dev/null +++ b/GermanAirlinesVA-GAConnector/ixwebsocket/include/IXWebSocketVersion.h @@ -0,0 +1,9 @@ +/* + * IXWebSocketVersion.h + * Author: Benjamin Sergeant + * Copyright (c) 2019 Machine Zone, Inc. All rights reserved. + */ + +#pragma once + +#define IX_WEBSOCKET_VERSION "11.3.2" diff --git a/GermanAirlinesVA-GAConnector/nlohmann/License.txt b/GermanAirlinesVA-GAConnector/nlohmann/License.txt new file mode 100644 index 0000000..d8a3085 --- /dev/null +++ b/GermanAirlinesVA-GAConnector/nlohmann/License.txt @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2013-2021 Niels Lohmann + +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. \ No newline at end of file diff --git a/GermanAirlinesVA-GAConnector/nlohmann/json.hpp b/GermanAirlinesVA-GAConnector/nlohmann/json.hpp new file mode 100644 index 0000000..d3aafeb --- /dev/null +++ b/GermanAirlinesVA-GAConnector/nlohmann/json.hpp @@ -0,0 +1,31780 @@ +/* + __ _____ _____ _____ + __| | __| | | | JSON for Modern C++ +| | |__ | | | | | | version 3.10.4 +|_____|_____|_____|_|___| https://github.com/nlohmann/json + +Licensed under the MIT License . +SPDX-License-Identifier: MIT +Copyright (c) 2013-2019 Niels Lohmann . + +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 INCLUDE_NLOHMANN_JSON_HPP_ +#define INCLUDE_NLOHMANN_JSON_HPP_ + +#define NLOHMANN_JSON_VERSION_MAJOR 3 +#define NLOHMANN_JSON_VERSION_MINOR 10 +#define NLOHMANN_JSON_VERSION_PATCH 4 + +#include // all_of, find, for_each +#include // nullptr_t, ptrdiff_t, size_t +#include // hash, less +#include // initializer_list +#ifndef JSON_NO_IO +#include // istream, ostream +#endif // JSON_NO_IO +#include // random_access_iterator_tag +#include // unique_ptr +#include // accumulate +#include // string, stoi, to_string +#include // declval, forward, move, pair, swap +#include // vector + +// #include + + +#include +#include + +// #include + + +#include // transform +#include // array +#include // forward_list +#include // inserter, front_inserter, end +#include // map +#include // string +#include // tuple, make_tuple +#include // is_arithmetic, is_same, is_enum, underlying_type, is_convertible +#include // unordered_map +#include // pair, declval +#include // valarray + +// #include + + +#include // exception +#include // runtime_error +#include // to_string +#include // vector + +// #include + + +#include // array +#include // size_t +#include // uint8_t +#include // string + +namespace nlohmann +{ +namespace detail +{ +/////////////////////////// +// JSON type enumeration // +/////////////////////////// + +/*! +@brief the JSON type enumeration + +This enumeration collects the different JSON types. It is internally used to +distinguish the stored values, and the functions @ref basic_json::is_null(), +@ref basic_json::is_object(), @ref basic_json::is_array(), +@ref basic_json::is_string(), @ref basic_json::is_boolean(), +@ref basic_json::is_number() (with @ref basic_json::is_number_integer(), +@ref basic_json::is_number_unsigned(), and @ref basic_json::is_number_float()), +@ref basic_json::is_discarded(), @ref basic_json::is_primitive(), and +@ref basic_json::is_structured() rely on it. + +@note There are three enumeration entries (number_integer, number_unsigned, and +number_float), because the library distinguishes these three types for numbers: +@ref basic_json::number_unsigned_t is used for unsigned integers, +@ref basic_json::number_integer_t is used for signed integers, and +@ref basic_json::number_float_t is used for floating-point numbers or to +approximate integers which do not fit in the limits of their respective type. + +@sa see @ref basic_json::basic_json(const value_t value_type) -- create a JSON +value with the default value for a given type + +@since version 1.0.0 +*/ +enum class value_t : std::uint8_t { + null, ///< null value + object, ///< object (unordered set of name/value pairs) + array, ///< array (ordered collection of values) + string, ///< string value + boolean, ///< boolean value + number_integer, ///< number value (signed integer) + number_unsigned, ///< number value (unsigned integer) + number_float, ///< number value (floating-point) + binary, ///< binary array (ordered collection of bytes) + discarded ///< discarded by the parser callback function +}; + +/*! +@brief comparison operator for JSON types + +Returns an ordering that is similar to Python: +- order: null < boolean < number < object < array < string < binary +- furthermore, each type is not smaller than itself +- discarded values are not comparable +- binary is represented as a b"" string in python and directly comparable to a + string; however, making a binary array directly comparable with a string would + be surprising behavior in a JSON file. + +@since version 1.0.0 +*/ +inline bool operator<(const value_t lhs, const value_t rhs) noexcept +{ + static constexpr std::array order = {{ + 0 /* null */, + 3 /* object */, + 4 /* array */, + 5 /* string */, + 1 /* boolean */, + 2 /* integer */, + 2 /* unsigned */, + 2 /* float */, + 6 /* binary */ + }}; + + const auto l_index = static_cast(lhs); + const auto r_index = static_cast(rhs); + return l_index < order.size() && r_index < order.size() && + order[l_index] < order[r_index]; +} +} // namespace detail +} // namespace nlohmann + +// #include + + +#include +// #include + + +#include // declval, pair +// #include + + +/* Hedley - https://nemequ.github.io/hedley + * Created by Evan Nemerson + * + * To the extent possible under law, the author(s) have dedicated all + * copyright and related and neighboring rights to this software to + * the public domain worldwide. This software is distributed without + * any warranty. + * + * For details, see . + * SPDX-License-Identifier: CC0-1.0 + */ + +#if !defined(JSON_HEDLEY_VERSION) || (JSON_HEDLEY_VERSION < 15) +#if defined(JSON_HEDLEY_VERSION) +#undef JSON_HEDLEY_VERSION +#endif +#define JSON_HEDLEY_VERSION 15 + +#if defined(JSON_HEDLEY_STRINGIFY_EX) +#undef JSON_HEDLEY_STRINGIFY_EX +#endif +#define JSON_HEDLEY_STRINGIFY_EX(x) #x + +#if defined(JSON_HEDLEY_STRINGIFY) +#undef JSON_HEDLEY_STRINGIFY +#endif +#define JSON_HEDLEY_STRINGIFY(x) JSON_HEDLEY_STRINGIFY_EX(x) + +#if defined(JSON_HEDLEY_CONCAT_EX) +#undef JSON_HEDLEY_CONCAT_EX +#endif +#define JSON_HEDLEY_CONCAT_EX(a, b) a##b + +#if defined(JSON_HEDLEY_CONCAT) +#undef JSON_HEDLEY_CONCAT +#endif +#define JSON_HEDLEY_CONCAT(a, b) JSON_HEDLEY_CONCAT_EX(a, b) + +#if defined(JSON_HEDLEY_CONCAT3_EX) +#undef JSON_HEDLEY_CONCAT3_EX +#endif +#define JSON_HEDLEY_CONCAT3_EX(a, b, c) a##b##c + +#if defined(JSON_HEDLEY_CONCAT3) +#undef JSON_HEDLEY_CONCAT3 +#endif +#define JSON_HEDLEY_CONCAT3(a, b, c) JSON_HEDLEY_CONCAT3_EX(a, b, c) + +#if defined(JSON_HEDLEY_VERSION_ENCODE) +#undef JSON_HEDLEY_VERSION_ENCODE +#endif +#define JSON_HEDLEY_VERSION_ENCODE(major, minor, revision) \ + (((major)*1000000) + ((minor)*1000) + (revision)) + +#if defined(JSON_HEDLEY_VERSION_DECODE_MAJOR) +#undef JSON_HEDLEY_VERSION_DECODE_MAJOR +#endif +#define JSON_HEDLEY_VERSION_DECODE_MAJOR(version) ((version) / 1000000) + +#if defined(JSON_HEDLEY_VERSION_DECODE_MINOR) +#undef JSON_HEDLEY_VERSION_DECODE_MINOR +#endif +#define JSON_HEDLEY_VERSION_DECODE_MINOR(version) (((version) % 1000000) / 1000) + +#if defined(JSON_HEDLEY_VERSION_DECODE_REVISION) +#undef JSON_HEDLEY_VERSION_DECODE_REVISION +#endif +#define JSON_HEDLEY_VERSION_DECODE_REVISION(version) ((version) % 1000) + +#if defined(JSON_HEDLEY_GNUC_VERSION) +#undef JSON_HEDLEY_GNUC_VERSION +#endif +#if defined(__GNUC__) && defined(__GNUC_PATCHLEVEL__) +#define JSON_HEDLEY_GNUC_VERSION \ + JSON_HEDLEY_VERSION_ENCODE(__GNUC__, __GNUC_MINOR__, __GNUC_PATCHLEVEL__) +#elif defined(__GNUC__) +#define JSON_HEDLEY_GNUC_VERSION \ + JSON_HEDLEY_VERSION_ENCODE(__GNUC__, __GNUC_MINOR__, 0) +#endif + +#if defined(JSON_HEDLEY_GNUC_VERSION_CHECK) +#undef JSON_HEDLEY_GNUC_VERSION_CHECK +#endif +#if defined(JSON_HEDLEY_GNUC_VERSION) +#define JSON_HEDLEY_GNUC_VERSION_CHECK(major, minor, patch) \ + (JSON_HEDLEY_GNUC_VERSION >= \ + JSON_HEDLEY_VERSION_ENCODE(major, minor, patch)) +#else +#define JSON_HEDLEY_GNUC_VERSION_CHECK(major, minor, patch) (0) +#endif + +#if defined(JSON_HEDLEY_MSVC_VERSION) +#undef JSON_HEDLEY_MSVC_VERSION +#endif +#if defined(_MSC_FULL_VER) && (_MSC_FULL_VER >= 140000000) && !defined(__ICL) +#define JSON_HEDLEY_MSVC_VERSION \ + JSON_HEDLEY_VERSION_ENCODE(_MSC_FULL_VER / 10000000, \ + (_MSC_FULL_VER % 10000000) / 100000, \ + (_MSC_FULL_VER % 100000) / 100) +#elif defined(_MSC_FULL_VER) && !defined(__ICL) +#define JSON_HEDLEY_MSVC_VERSION \ + JSON_HEDLEY_VERSION_ENCODE(_MSC_FULL_VER / 1000000, \ + (_MSC_FULL_VER % 1000000) / 10000, \ + (_MSC_FULL_VER % 10000) / 10) +#elif defined(_MSC_VER) && !defined(__ICL) +#define JSON_HEDLEY_MSVC_VERSION \ + JSON_HEDLEY_VERSION_ENCODE(_MSC_VER / 100, _MSC_VER % 100, 0) +#endif + +#if defined(JSON_HEDLEY_MSVC_VERSION_CHECK) +#undef JSON_HEDLEY_MSVC_VERSION_CHECK +#endif +#if !defined(JSON_HEDLEY_MSVC_VERSION) +#define JSON_HEDLEY_MSVC_VERSION_CHECK(major, minor, patch) (0) +#elif defined(_MSC_VER) && (_MSC_VER >= 1400) +#define JSON_HEDLEY_MSVC_VERSION_CHECK(major, minor, patch) \ + (_MSC_FULL_VER >= ((major * 10000000) + (minor * 100000) + (patch))) +#elif defined(_MSC_VER) && (_MSC_VER >= 1200) +#define JSON_HEDLEY_MSVC_VERSION_CHECK(major, minor, patch) \ + (_MSC_FULL_VER >= ((major * 1000000) + (minor * 10000) + (patch))) +#else +#define JSON_HEDLEY_MSVC_VERSION_CHECK(major, minor, patch) \ + (_MSC_VER >= ((major * 100) + (minor))) +#endif + +#if defined(JSON_HEDLEY_INTEL_VERSION) +#undef JSON_HEDLEY_INTEL_VERSION +#endif +#if defined(__INTEL_COMPILER) && defined(__INTEL_COMPILER_UPDATE) && \ + !defined(__ICL) +#define JSON_HEDLEY_INTEL_VERSION \ + JSON_HEDLEY_VERSION_ENCODE(__INTEL_COMPILER / 100, \ + __INTEL_COMPILER % 100, \ + __INTEL_COMPILER_UPDATE) +#elif defined(__INTEL_COMPILER) && !defined(__ICL) +#define JSON_HEDLEY_INTEL_VERSION \ + JSON_HEDLEY_VERSION_ENCODE(__INTEL_COMPILER / 100, \ + __INTEL_COMPILER % 100, \ + 0) +#endif + +#if defined(JSON_HEDLEY_INTEL_VERSION_CHECK) +#undef JSON_HEDLEY_INTEL_VERSION_CHECK +#endif +#if defined(JSON_HEDLEY_INTEL_VERSION) +#define JSON_HEDLEY_INTEL_VERSION_CHECK(major, minor, patch) \ + (JSON_HEDLEY_INTEL_VERSION >= \ + JSON_HEDLEY_VERSION_ENCODE(major, minor, patch)) +#else +#define JSON_HEDLEY_INTEL_VERSION_CHECK(major, minor, patch) (0) +#endif + +#if defined(JSON_HEDLEY_INTEL_CL_VERSION) +#undef JSON_HEDLEY_INTEL_CL_VERSION +#endif +#if defined(__INTEL_COMPILER) && defined(__INTEL_COMPILER_UPDATE) && \ + defined(__ICL) +#define JSON_HEDLEY_INTEL_CL_VERSION \ + JSON_HEDLEY_VERSION_ENCODE(__INTEL_COMPILER, __INTEL_COMPILER_UPDATE, 0) +#endif + +#if defined(JSON_HEDLEY_INTEL_CL_VERSION_CHECK) +#undef JSON_HEDLEY_INTEL_CL_VERSION_CHECK +#endif +#if defined(JSON_HEDLEY_INTEL_CL_VERSION) +#define JSON_HEDLEY_INTEL_CL_VERSION_CHECK(major, minor, patch) \ + (JSON_HEDLEY_INTEL_CL_VERSION >= \ + JSON_HEDLEY_VERSION_ENCODE(major, minor, patch)) +#else +#define JSON_HEDLEY_INTEL_CL_VERSION_CHECK(major, minor, patch) (0) +#endif + +#if defined(JSON_HEDLEY_PGI_VERSION) +#undef JSON_HEDLEY_PGI_VERSION +#endif +#if defined(__PGI) && defined(__PGIC__) && defined(__PGIC_MINOR__) && \ + defined(__PGIC_PATCHLEVEL__) +#define JSON_HEDLEY_PGI_VERSION \ + JSON_HEDLEY_VERSION_ENCODE(__PGIC__, __PGIC_MINOR__, __PGIC_PATCHLEVEL__) +#endif + +#if defined(JSON_HEDLEY_PGI_VERSION_CHECK) +#undef JSON_HEDLEY_PGI_VERSION_CHECK +#endif +#if defined(JSON_HEDLEY_PGI_VERSION) +#define JSON_HEDLEY_PGI_VERSION_CHECK(major, minor, patch) \ + (JSON_HEDLEY_PGI_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch)) +#else +#define JSON_HEDLEY_PGI_VERSION_CHECK(major, minor, patch) (0) +#endif + +#if defined(JSON_HEDLEY_SUNPRO_VERSION) +#undef JSON_HEDLEY_SUNPRO_VERSION +#endif +#if defined(__SUNPRO_C) && (__SUNPRO_C > 0x1000) +#define JSON_HEDLEY_SUNPRO_VERSION \ + JSON_HEDLEY_VERSION_ENCODE( \ + (((__SUNPRO_C >> 16) & 0xf) * 10) + ((__SUNPRO_C >> 12) & 0xf), \ + (((__SUNPRO_C >> 8) & 0xf) * 10) + ((__SUNPRO_C >> 4) & 0xf), \ + (__SUNPRO_C & 0xf) * 10) +#elif defined(__SUNPRO_C) +#define JSON_HEDLEY_SUNPRO_VERSION \ + JSON_HEDLEY_VERSION_ENCODE((__SUNPRO_C >> 8) & 0xf, \ + (__SUNPRO_C >> 4) & 0xf, \ + (__SUNPRO_C)&0xf) +#elif defined(__SUNPRO_CC) && (__SUNPRO_CC > 0x1000) +#define JSON_HEDLEY_SUNPRO_VERSION \ + JSON_HEDLEY_VERSION_ENCODE( \ + (((__SUNPRO_CC >> 16) & 0xf) * 10) + ((__SUNPRO_CC >> 12) & 0xf), \ + (((__SUNPRO_CC >> 8) & 0xf) * 10) + ((__SUNPRO_CC >> 4) & 0xf), \ + (__SUNPRO_CC & 0xf) * 10) +#elif defined(__SUNPRO_CC) +#define JSON_HEDLEY_SUNPRO_VERSION \ + JSON_HEDLEY_VERSION_ENCODE((__SUNPRO_CC >> 8) & 0xf, \ + (__SUNPRO_CC >> 4) & 0xf, \ + (__SUNPRO_CC)&0xf) +#endif + +#if defined(JSON_HEDLEY_SUNPRO_VERSION_CHECK) +#undef JSON_HEDLEY_SUNPRO_VERSION_CHECK +#endif +#if defined(JSON_HEDLEY_SUNPRO_VERSION) +#define JSON_HEDLEY_SUNPRO_VERSION_CHECK(major, minor, patch) \ + (JSON_HEDLEY_SUNPRO_VERSION >= \ + JSON_HEDLEY_VERSION_ENCODE(major, minor, patch)) +#else +#define JSON_HEDLEY_SUNPRO_VERSION_CHECK(major, minor, patch) (0) +#endif + +#if defined(JSON_HEDLEY_EMSCRIPTEN_VERSION) +#undef JSON_HEDLEY_EMSCRIPTEN_VERSION +#endif +#if defined(__EMSCRIPTEN__) +#define JSON_HEDLEY_EMSCRIPTEN_VERSION \ + JSON_HEDLEY_VERSION_ENCODE(__EMSCRIPTEN_major__, \ + __EMSCRIPTEN_minor__, \ + __EMSCRIPTEN_tiny__) +#endif + +#if defined(JSON_HEDLEY_EMSCRIPTEN_VERSION_CHECK) +#undef JSON_HEDLEY_EMSCRIPTEN_VERSION_CHECK +#endif +#if defined(JSON_HEDLEY_EMSCRIPTEN_VERSION) +#define JSON_HEDLEY_EMSCRIPTEN_VERSION_CHECK(major, minor, patch) \ + (JSON_HEDLEY_EMSCRIPTEN_VERSION >= \ + JSON_HEDLEY_VERSION_ENCODE(major, minor, patch)) +#else +#define JSON_HEDLEY_EMSCRIPTEN_VERSION_CHECK(major, minor, patch) (0) +#endif + +#if defined(JSON_HEDLEY_ARM_VERSION) +#undef JSON_HEDLEY_ARM_VERSION +#endif +#if defined(__CC_ARM) && defined(__ARMCOMPILER_VERSION) +#define JSON_HEDLEY_ARM_VERSION \ + JSON_HEDLEY_VERSION_ENCODE(__ARMCOMPILER_VERSION / 1000000, \ + (__ARMCOMPILER_VERSION % 1000000) / 10000, \ + (__ARMCOMPILER_VERSION % 10000) / 100) +#elif defined(__CC_ARM) && defined(__ARMCC_VERSION) +#define JSON_HEDLEY_ARM_VERSION \ + JSON_HEDLEY_VERSION_ENCODE(__ARMCC_VERSION / 1000000, \ + (__ARMCC_VERSION % 1000000) / 10000, \ + (__ARMCC_VERSION % 10000) / 100) +#endif + +#if defined(JSON_HEDLEY_ARM_VERSION_CHECK) +#undef JSON_HEDLEY_ARM_VERSION_CHECK +#endif +#if defined(JSON_HEDLEY_ARM_VERSION) +#define JSON_HEDLEY_ARM_VERSION_CHECK(major, minor, patch) \ + (JSON_HEDLEY_ARM_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch)) +#else +#define JSON_HEDLEY_ARM_VERSION_CHECK(major, minor, patch) (0) +#endif + +#if defined(JSON_HEDLEY_IBM_VERSION) +#undef JSON_HEDLEY_IBM_VERSION +#endif +#if defined(__ibmxl__) +#define JSON_HEDLEY_IBM_VERSION \ + JSON_HEDLEY_VERSION_ENCODE(__ibmxl_version__, \ + __ibmxl_release__, \ + __ibmxl_modification__) +#elif defined(__xlC__) && defined(__xlC_ver__) +#define JSON_HEDLEY_IBM_VERSION \ + JSON_HEDLEY_VERSION_ENCODE(__xlC__ >> 8, \ + __xlC__ & 0xff, \ + (__xlC_ver__ >> 8) & 0xff) +#elif defined(__xlC__) +#define JSON_HEDLEY_IBM_VERSION \ + JSON_HEDLEY_VERSION_ENCODE(__xlC__ >> 8, __xlC__ & 0xff, 0) +#endif + +#if defined(JSON_HEDLEY_IBM_VERSION_CHECK) +#undef JSON_HEDLEY_IBM_VERSION_CHECK +#endif +#if defined(JSON_HEDLEY_IBM_VERSION) +#define JSON_HEDLEY_IBM_VERSION_CHECK(major, minor, patch) \ + (JSON_HEDLEY_IBM_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch)) +#else +#define JSON_HEDLEY_IBM_VERSION_CHECK(major, minor, patch) (0) +#endif + +#if defined(JSON_HEDLEY_TI_VERSION) +#undef JSON_HEDLEY_TI_VERSION +#endif +#if defined(__TI_COMPILER_VERSION__) && \ + (defined(__TMS470__) || defined(__TI_ARM__) || defined(__MSP430__) || \ + defined(__TMS320C2000__)) +#if (__TI_COMPILER_VERSION__ >= 16000000) +#define JSON_HEDLEY_TI_VERSION \ + JSON_HEDLEY_VERSION_ENCODE(__TI_COMPILER_VERSION__ / 1000000, \ + (__TI_COMPILER_VERSION__ % 1000000) / 1000, \ + (__TI_COMPILER_VERSION__ % 1000)) +#endif +#endif + +#if defined(JSON_HEDLEY_TI_VERSION_CHECK) +#undef JSON_HEDLEY_TI_VERSION_CHECK +#endif +#if defined(JSON_HEDLEY_TI_VERSION) +#define JSON_HEDLEY_TI_VERSION_CHECK(major, minor, patch) \ + (JSON_HEDLEY_TI_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch)) +#else +#define JSON_HEDLEY_TI_VERSION_CHECK(major, minor, patch) (0) +#endif + +#if defined(JSON_HEDLEY_TI_CL2000_VERSION) +#undef JSON_HEDLEY_TI_CL2000_VERSION +#endif +#if defined(__TI_COMPILER_VERSION__) && defined(__TMS320C2000__) +#define JSON_HEDLEY_TI_CL2000_VERSION \ + JSON_HEDLEY_VERSION_ENCODE(__TI_COMPILER_VERSION__ / 1000000, \ + (__TI_COMPILER_VERSION__ % 1000000) / 1000, \ + (__TI_COMPILER_VERSION__ % 1000)) +#endif + +#if defined(JSON_HEDLEY_TI_CL2000_VERSION_CHECK) +#undef JSON_HEDLEY_TI_CL2000_VERSION_CHECK +#endif +#if defined(JSON_HEDLEY_TI_CL2000_VERSION) +#define JSON_HEDLEY_TI_CL2000_VERSION_CHECK(major, minor, patch) \ + (JSON_HEDLEY_TI_CL2000_VERSION >= \ + JSON_HEDLEY_VERSION_ENCODE(major, minor, patch)) +#else +#define JSON_HEDLEY_TI_CL2000_VERSION_CHECK(major, minor, patch) (0) +#endif + +#if defined(JSON_HEDLEY_TI_CL430_VERSION) +#undef JSON_HEDLEY_TI_CL430_VERSION +#endif +#if defined(__TI_COMPILER_VERSION__) && defined(__MSP430__) +#define JSON_HEDLEY_TI_CL430_VERSION \ + JSON_HEDLEY_VERSION_ENCODE(__TI_COMPILER_VERSION__ / 1000000, \ + (__TI_COMPILER_VERSION__ % 1000000) / 1000, \ + (__TI_COMPILER_VERSION__ % 1000)) +#endif + +#if defined(JSON_HEDLEY_TI_CL430_VERSION_CHECK) +#undef JSON_HEDLEY_TI_CL430_VERSION_CHECK +#endif +#if defined(JSON_HEDLEY_TI_CL430_VERSION) +#define JSON_HEDLEY_TI_CL430_VERSION_CHECK(major, minor, patch) \ + (JSON_HEDLEY_TI_CL430_VERSION >= \ + JSON_HEDLEY_VERSION_ENCODE(major, minor, patch)) +#else +#define JSON_HEDLEY_TI_CL430_VERSION_CHECK(major, minor, patch) (0) +#endif + +#if defined(JSON_HEDLEY_TI_ARMCL_VERSION) +#undef JSON_HEDLEY_TI_ARMCL_VERSION +#endif +#if defined(__TI_COMPILER_VERSION__) && \ + (defined(__TMS470__) || defined(__TI_ARM__)) +#define JSON_HEDLEY_TI_ARMCL_VERSION \ + JSON_HEDLEY_VERSION_ENCODE(__TI_COMPILER_VERSION__ / 1000000, \ + (__TI_COMPILER_VERSION__ % 1000000) / 1000, \ + (__TI_COMPILER_VERSION__ % 1000)) +#endif + +#if defined(JSON_HEDLEY_TI_ARMCL_VERSION_CHECK) +#undef JSON_HEDLEY_TI_ARMCL_VERSION_CHECK +#endif +#if defined(JSON_HEDLEY_TI_ARMCL_VERSION) +#define JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(major, minor, patch) \ + (JSON_HEDLEY_TI_ARMCL_VERSION >= \ + JSON_HEDLEY_VERSION_ENCODE(major, minor, patch)) +#else +#define JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(major, minor, patch) (0) +#endif + +#if defined(JSON_HEDLEY_TI_CL6X_VERSION) +#undef JSON_HEDLEY_TI_CL6X_VERSION +#endif +#if defined(__TI_COMPILER_VERSION__) && defined(__TMS320C6X__) +#define JSON_HEDLEY_TI_CL6X_VERSION \ + JSON_HEDLEY_VERSION_ENCODE(__TI_COMPILER_VERSION__ / 1000000, \ + (__TI_COMPILER_VERSION__ % 1000000) / 1000, \ + (__TI_COMPILER_VERSION__ % 1000)) +#endif + +#if defined(JSON_HEDLEY_TI_CL6X_VERSION_CHECK) +#undef JSON_HEDLEY_TI_CL6X_VERSION_CHECK +#endif +#if defined(JSON_HEDLEY_TI_CL6X_VERSION) +#define JSON_HEDLEY_TI_CL6X_VERSION_CHECK(major, minor, patch) \ + (JSON_HEDLEY_TI_CL6X_VERSION >= \ + JSON_HEDLEY_VERSION_ENCODE(major, minor, patch)) +#else +#define JSON_HEDLEY_TI_CL6X_VERSION_CHECK(major, minor, patch) (0) +#endif + +#if defined(JSON_HEDLEY_TI_CL7X_VERSION) +#undef JSON_HEDLEY_TI_CL7X_VERSION +#endif +#if defined(__TI_COMPILER_VERSION__) && defined(__C7000__) +#define JSON_HEDLEY_TI_CL7X_VERSION \ + JSON_HEDLEY_VERSION_ENCODE(__TI_COMPILER_VERSION__ / 1000000, \ + (__TI_COMPILER_VERSION__ % 1000000) / 1000, \ + (__TI_COMPILER_VERSION__ % 1000)) +#endif + +#if defined(JSON_HEDLEY_TI_CL7X_VERSION_CHECK) +#undef JSON_HEDLEY_TI_CL7X_VERSION_CHECK +#endif +#if defined(JSON_HEDLEY_TI_CL7X_VERSION) +#define JSON_HEDLEY_TI_CL7X_VERSION_CHECK(major, minor, patch) \ + (JSON_HEDLEY_TI_CL7X_VERSION >= \ + JSON_HEDLEY_VERSION_ENCODE(major, minor, patch)) +#else +#define JSON_HEDLEY_TI_CL7X_VERSION_CHECK(major, minor, patch) (0) +#endif + +#if defined(JSON_HEDLEY_TI_CLPRU_VERSION) +#undef JSON_HEDLEY_TI_CLPRU_VERSION +#endif +#if defined(__TI_COMPILER_VERSION__) && defined(__PRU__) +#define JSON_HEDLEY_TI_CLPRU_VERSION \ + JSON_HEDLEY_VERSION_ENCODE(__TI_COMPILER_VERSION__ / 1000000, \ + (__TI_COMPILER_VERSION__ % 1000000) / 1000, \ + (__TI_COMPILER_VERSION__ % 1000)) +#endif + +#if defined(JSON_HEDLEY_TI_CLPRU_VERSION_CHECK) +#undef JSON_HEDLEY_TI_CLPRU_VERSION_CHECK +#endif +#if defined(JSON_HEDLEY_TI_CLPRU_VERSION) +#define JSON_HEDLEY_TI_CLPRU_VERSION_CHECK(major, minor, patch) \ + (JSON_HEDLEY_TI_CLPRU_VERSION >= \ + JSON_HEDLEY_VERSION_ENCODE(major, minor, patch)) +#else +#define JSON_HEDLEY_TI_CLPRU_VERSION_CHECK(major, minor, patch) (0) +#endif + +#if defined(JSON_HEDLEY_CRAY_VERSION) +#undef JSON_HEDLEY_CRAY_VERSION +#endif +#if defined(_CRAYC) +#if defined(_RELEASE_PATCHLEVEL) +#define JSON_HEDLEY_CRAY_VERSION \ + JSON_HEDLEY_VERSION_ENCODE(_RELEASE_MAJOR, \ + _RELEASE_MINOR, \ + _RELEASE_PATCHLEVEL) +#else +#define JSON_HEDLEY_CRAY_VERSION \ + JSON_HEDLEY_VERSION_ENCODE(_RELEASE_MAJOR, _RELEASE_MINOR, 0) +#endif +#endif + +#if defined(JSON_HEDLEY_CRAY_VERSION_CHECK) +#undef JSON_HEDLEY_CRAY_VERSION_CHECK +#endif +#if defined(JSON_HEDLEY_CRAY_VERSION) +#define JSON_HEDLEY_CRAY_VERSION_CHECK(major, minor, patch) \ + (JSON_HEDLEY_CRAY_VERSION >= \ + JSON_HEDLEY_VERSION_ENCODE(major, minor, patch)) +#else +#define JSON_HEDLEY_CRAY_VERSION_CHECK(major, minor, patch) (0) +#endif + +#if defined(JSON_HEDLEY_IAR_VERSION) +#undef JSON_HEDLEY_IAR_VERSION +#endif +#if defined(__IAR_SYSTEMS_ICC__) +#if __VER__ > 1000 +#define JSON_HEDLEY_IAR_VERSION \ + JSON_HEDLEY_VERSION_ENCODE((__VER__ / 1000000), \ + ((__VER__ / 1000) % 1000), \ + (__VER__ % 1000)) +#else +#define JSON_HEDLEY_IAR_VERSION \ + JSON_HEDLEY_VERSION_ENCODE(__VER__ / 100, __VER__ % 100, 0) +#endif +#endif + +#if defined(JSON_HEDLEY_IAR_VERSION_CHECK) +#undef JSON_HEDLEY_IAR_VERSION_CHECK +#endif +#if defined(JSON_HEDLEY_IAR_VERSION) +#define JSON_HEDLEY_IAR_VERSION_CHECK(major, minor, patch) \ + (JSON_HEDLEY_IAR_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch)) +#else +#define JSON_HEDLEY_IAR_VERSION_CHECK(major, minor, patch) (0) +#endif + +#if defined(JSON_HEDLEY_TINYC_VERSION) +#undef JSON_HEDLEY_TINYC_VERSION +#endif +#if defined(__TINYC__) +#define JSON_HEDLEY_TINYC_VERSION \ + JSON_HEDLEY_VERSION_ENCODE(__TINYC__ / 1000, \ + (__TINYC__ / 100) % 10, \ + __TINYC__ % 100) +#endif + +#if defined(JSON_HEDLEY_TINYC_VERSION_CHECK) +#undef JSON_HEDLEY_TINYC_VERSION_CHECK +#endif +#if defined(JSON_HEDLEY_TINYC_VERSION) +#define JSON_HEDLEY_TINYC_VERSION_CHECK(major, minor, patch) \ + (JSON_HEDLEY_TINYC_VERSION >= \ + JSON_HEDLEY_VERSION_ENCODE(major, minor, patch)) +#else +#define JSON_HEDLEY_TINYC_VERSION_CHECK(major, minor, patch) (0) +#endif + +#if defined(JSON_HEDLEY_DMC_VERSION) +#undef JSON_HEDLEY_DMC_VERSION +#endif +#if defined(__DMC__) +#define JSON_HEDLEY_DMC_VERSION \ + JSON_HEDLEY_VERSION_ENCODE(__DMC__ >> 8, \ + (__DMC__ >> 4) & 0xf, \ + __DMC__ & 0xf) +#endif + +#if defined(JSON_HEDLEY_DMC_VERSION_CHECK) +#undef JSON_HEDLEY_DMC_VERSION_CHECK +#endif +#if defined(JSON_HEDLEY_DMC_VERSION) +#define JSON_HEDLEY_DMC_VERSION_CHECK(major, minor, patch) \ + (JSON_HEDLEY_DMC_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch)) +#else +#define JSON_HEDLEY_DMC_VERSION_CHECK(major, minor, patch) (0) +#endif + +#if defined(JSON_HEDLEY_COMPCERT_VERSION) +#undef JSON_HEDLEY_COMPCERT_VERSION +#endif +#if defined(__COMPCERT_VERSION__) +#define JSON_HEDLEY_COMPCERT_VERSION \ + JSON_HEDLEY_VERSION_ENCODE(__COMPCERT_VERSION__ / 10000, \ + (__COMPCERT_VERSION__ / 100) % 100, \ + __COMPCERT_VERSION__ % 100) +#endif + +#if defined(JSON_HEDLEY_COMPCERT_VERSION_CHECK) +#undef JSON_HEDLEY_COMPCERT_VERSION_CHECK +#endif +#if defined(JSON_HEDLEY_COMPCERT_VERSION) +#define JSON_HEDLEY_COMPCERT_VERSION_CHECK(major, minor, patch) \ + (JSON_HEDLEY_COMPCERT_VERSION >= \ + JSON_HEDLEY_VERSION_ENCODE(major, minor, patch)) +#else +#define JSON_HEDLEY_COMPCERT_VERSION_CHECK(major, minor, patch) (0) +#endif + +#if defined(JSON_HEDLEY_PELLES_VERSION) +#undef JSON_HEDLEY_PELLES_VERSION +#endif +#if defined(__POCC__) +#define JSON_HEDLEY_PELLES_VERSION \ + JSON_HEDLEY_VERSION_ENCODE(__POCC__ / 100, __POCC__ % 100, 0) +#endif + +#if defined(JSON_HEDLEY_PELLES_VERSION_CHECK) +#undef JSON_HEDLEY_PELLES_VERSION_CHECK +#endif +#if defined(JSON_HEDLEY_PELLES_VERSION) +#define JSON_HEDLEY_PELLES_VERSION_CHECK(major, minor, patch) \ + (JSON_HEDLEY_PELLES_VERSION >= \ + JSON_HEDLEY_VERSION_ENCODE(major, minor, patch)) +#else +#define JSON_HEDLEY_PELLES_VERSION_CHECK(major, minor, patch) (0) +#endif + +#if defined(JSON_HEDLEY_MCST_LCC_VERSION) +#undef JSON_HEDLEY_MCST_LCC_VERSION +#endif +#if defined(__LCC__) && defined(__LCC_MINOR__) +#define JSON_HEDLEY_MCST_LCC_VERSION \ + JSON_HEDLEY_VERSION_ENCODE(__LCC__ / 100, __LCC__ % 100, __LCC_MINOR__) +#endif + +#if defined(JSON_HEDLEY_MCST_LCC_VERSION_CHECK) +#undef JSON_HEDLEY_MCST_LCC_VERSION_CHECK +#endif +#if defined(JSON_HEDLEY_MCST_LCC_VERSION) +#define JSON_HEDLEY_MCST_LCC_VERSION_CHECK(major, minor, patch) \ + (JSON_HEDLEY_MCST_LCC_VERSION >= \ + JSON_HEDLEY_VERSION_ENCODE(major, minor, patch)) +#else +#define JSON_HEDLEY_MCST_LCC_VERSION_CHECK(major, minor, patch) (0) +#endif + +#if defined(JSON_HEDLEY_GCC_VERSION) +#undef JSON_HEDLEY_GCC_VERSION +#endif +#if defined(JSON_HEDLEY_GNUC_VERSION) && !defined(__clang__) && \ + !defined(JSON_HEDLEY_INTEL_VERSION) && \ + !defined(JSON_HEDLEY_PGI_VERSION) && !defined(JSON_HEDLEY_ARM_VERSION) && \ + !defined(JSON_HEDLEY_CRAY_VERSION) && !defined(JSON_HEDLEY_TI_VERSION) && \ + !defined(JSON_HEDLEY_TI_ARMCL_VERSION) && \ + !defined(JSON_HEDLEY_TI_CL430_VERSION) && \ + !defined(JSON_HEDLEY_TI_CL2000_VERSION) && \ + !defined(JSON_HEDLEY_TI_CL6X_VERSION) && \ + !defined(JSON_HEDLEY_TI_CL7X_VERSION) && \ + !defined(JSON_HEDLEY_TI_CLPRU_VERSION) && !defined(__COMPCERT__) && \ + !defined(JSON_HEDLEY_MCST_LCC_VERSION) +#define JSON_HEDLEY_GCC_VERSION JSON_HEDLEY_GNUC_VERSION +#endif + +#if defined(JSON_HEDLEY_GCC_VERSION_CHECK) +#undef JSON_HEDLEY_GCC_VERSION_CHECK +#endif +#if defined(JSON_HEDLEY_GCC_VERSION) +#define JSON_HEDLEY_GCC_VERSION_CHECK(major, minor, patch) \ + (JSON_HEDLEY_GCC_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch)) +#else +#define JSON_HEDLEY_GCC_VERSION_CHECK(major, minor, patch) (0) +#endif + +#if defined(JSON_HEDLEY_HAS_ATTRIBUTE) +#undef JSON_HEDLEY_HAS_ATTRIBUTE +#endif +#if defined(__has_attribute) && ((!defined(JSON_HEDLEY_IAR_VERSION) || \ + JSON_HEDLEY_IAR_VERSION_CHECK(8, 5, 9))) +#define JSON_HEDLEY_HAS_ATTRIBUTE(attribute) __has_attribute(attribute) +#else +#define JSON_HEDLEY_HAS_ATTRIBUTE(attribute) (0) +#endif + +#if defined(JSON_HEDLEY_GNUC_HAS_ATTRIBUTE) +#undef JSON_HEDLEY_GNUC_HAS_ATTRIBUTE +#endif +#if defined(__has_attribute) +#define JSON_HEDLEY_GNUC_HAS_ATTRIBUTE(attribute, major, minor, patch) \ + JSON_HEDLEY_HAS_ATTRIBUTE(attribute) +#else +#define JSON_HEDLEY_GNUC_HAS_ATTRIBUTE(attribute, major, minor, patch) \ + JSON_HEDLEY_GNUC_VERSION_CHECK(major, minor, patch) +#endif + +#if defined(JSON_HEDLEY_GCC_HAS_ATTRIBUTE) +#undef JSON_HEDLEY_GCC_HAS_ATTRIBUTE +#endif +#if defined(__has_attribute) +#define JSON_HEDLEY_GCC_HAS_ATTRIBUTE(attribute, major, minor, patch) \ + JSON_HEDLEY_HAS_ATTRIBUTE(attribute) +#else +#define JSON_HEDLEY_GCC_HAS_ATTRIBUTE(attribute, major, minor, patch) \ + JSON_HEDLEY_GCC_VERSION_CHECK(major, minor, patch) +#endif + +#if defined(JSON_HEDLEY_HAS_CPP_ATTRIBUTE) +#undef JSON_HEDLEY_HAS_CPP_ATTRIBUTE +#endif +#if defined(__has_cpp_attribute) && defined(__cplusplus) && \ + (!defined(JSON_HEDLEY_SUNPRO_VERSION) || \ + JSON_HEDLEY_SUNPRO_VERSION_CHECK(5, 15, 0)) +#define JSON_HEDLEY_HAS_CPP_ATTRIBUTE(attribute) __has_cpp_attribute(attribute) +#else +#define JSON_HEDLEY_HAS_CPP_ATTRIBUTE(attribute) (0) +#endif + +#if defined(JSON_HEDLEY_HAS_CPP_ATTRIBUTE_NS) +#undef JSON_HEDLEY_HAS_CPP_ATTRIBUTE_NS +#endif +#if !defined(__cplusplus) || !defined(__has_cpp_attribute) +#define JSON_HEDLEY_HAS_CPP_ATTRIBUTE_NS(ns, attribute) (0) +#elif !defined(JSON_HEDLEY_PGI_VERSION) && \ + !defined(JSON_HEDLEY_IAR_VERSION) && \ + (!defined(JSON_HEDLEY_SUNPRO_VERSION) || \ + JSON_HEDLEY_SUNPRO_VERSION_CHECK(5, 15, 0)) && \ + (!defined(JSON_HEDLEY_MSVC_VERSION) || \ + JSON_HEDLEY_MSVC_VERSION_CHECK(19, 20, 0)) +#define JSON_HEDLEY_HAS_CPP_ATTRIBUTE_NS(ns, attribute) \ + JSON_HEDLEY_HAS_CPP_ATTRIBUTE(ns::attribute) +#else +#define JSON_HEDLEY_HAS_CPP_ATTRIBUTE_NS(ns, attribute) (0) +#endif + +#if defined(JSON_HEDLEY_GNUC_HAS_CPP_ATTRIBUTE) +#undef JSON_HEDLEY_GNUC_HAS_CPP_ATTRIBUTE +#endif +#if defined(__has_cpp_attribute) && defined(__cplusplus) +#define JSON_HEDLEY_GNUC_HAS_CPP_ATTRIBUTE(attribute, major, minor, patch) \ + __has_cpp_attribute(attribute) +#else +#define JSON_HEDLEY_GNUC_HAS_CPP_ATTRIBUTE(attribute, major, minor, patch) \ + JSON_HEDLEY_GNUC_VERSION_CHECK(major, minor, patch) +#endif + +#if defined(JSON_HEDLEY_GCC_HAS_CPP_ATTRIBUTE) +#undef JSON_HEDLEY_GCC_HAS_CPP_ATTRIBUTE +#endif +#if defined(__has_cpp_attribute) && defined(__cplusplus) +#define JSON_HEDLEY_GCC_HAS_CPP_ATTRIBUTE(attribute, major, minor, patch) \ + __has_cpp_attribute(attribute) +#else +#define JSON_HEDLEY_GCC_HAS_CPP_ATTRIBUTE(attribute, major, minor, patch) \ + JSON_HEDLEY_GCC_VERSION_CHECK(major, minor, patch) +#endif + +#if defined(JSON_HEDLEY_HAS_BUILTIN) +#undef JSON_HEDLEY_HAS_BUILTIN +#endif +#if defined(__has_builtin) +#define JSON_HEDLEY_HAS_BUILTIN(builtin) __has_builtin(builtin) +#else +#define JSON_HEDLEY_HAS_BUILTIN(builtin) (0) +#endif + +#if defined(JSON_HEDLEY_GNUC_HAS_BUILTIN) +#undef JSON_HEDLEY_GNUC_HAS_BUILTIN +#endif +#if defined(__has_builtin) +#define JSON_HEDLEY_GNUC_HAS_BUILTIN(builtin, major, minor, patch) \ + __has_builtin(builtin) +#else +#define JSON_HEDLEY_GNUC_HAS_BUILTIN(builtin, major, minor, patch) \ + JSON_HEDLEY_GNUC_VERSION_CHECK(major, minor, patch) +#endif + +#if defined(JSON_HEDLEY_GCC_HAS_BUILTIN) +#undef JSON_HEDLEY_GCC_HAS_BUILTIN +#endif +#if defined(__has_builtin) +#define JSON_HEDLEY_GCC_HAS_BUILTIN(builtin, major, minor, patch) \ + __has_builtin(builtin) +#else +#define JSON_HEDLEY_GCC_HAS_BUILTIN(builtin, major, minor, patch) \ + JSON_HEDLEY_GCC_VERSION_CHECK(major, minor, patch) +#endif + +#if defined(JSON_HEDLEY_HAS_FEATURE) +#undef JSON_HEDLEY_HAS_FEATURE +#endif +#if defined(__has_feature) +#define JSON_HEDLEY_HAS_FEATURE(feature) __has_feature(feature) +#else +#define JSON_HEDLEY_HAS_FEATURE(feature) (0) +#endif + +#if defined(JSON_HEDLEY_GNUC_HAS_FEATURE) +#undef JSON_HEDLEY_GNUC_HAS_FEATURE +#endif +#if defined(__has_feature) +#define JSON_HEDLEY_GNUC_HAS_FEATURE(feature, major, minor, patch) \ + __has_feature(feature) +#else +#define JSON_HEDLEY_GNUC_HAS_FEATURE(feature, major, minor, patch) \ + JSON_HEDLEY_GNUC_VERSION_CHECK(major, minor, patch) +#endif + +#if defined(JSON_HEDLEY_GCC_HAS_FEATURE) +#undef JSON_HEDLEY_GCC_HAS_FEATURE +#endif +#if defined(__has_feature) +#define JSON_HEDLEY_GCC_HAS_FEATURE(feature, major, minor, patch) \ + __has_feature(feature) +#else +#define JSON_HEDLEY_GCC_HAS_FEATURE(feature, major, minor, patch) \ + JSON_HEDLEY_GCC_VERSION_CHECK(major, minor, patch) +#endif + +#if defined(JSON_HEDLEY_HAS_EXTENSION) +#undef JSON_HEDLEY_HAS_EXTENSION +#endif +#if defined(__has_extension) +#define JSON_HEDLEY_HAS_EXTENSION(extension) __has_extension(extension) +#else +#define JSON_HEDLEY_HAS_EXTENSION(extension) (0) +#endif + +#if defined(JSON_HEDLEY_GNUC_HAS_EXTENSION) +#undef JSON_HEDLEY_GNUC_HAS_EXTENSION +#endif +#if defined(__has_extension) +#define JSON_HEDLEY_GNUC_HAS_EXTENSION(extension, major, minor, patch) \ + __has_extension(extension) +#else +#define JSON_HEDLEY_GNUC_HAS_EXTENSION(extension, major, minor, patch) \ + JSON_HEDLEY_GNUC_VERSION_CHECK(major, minor, patch) +#endif + +#if defined(JSON_HEDLEY_GCC_HAS_EXTENSION) +#undef JSON_HEDLEY_GCC_HAS_EXTENSION +#endif +#if defined(__has_extension) +#define JSON_HEDLEY_GCC_HAS_EXTENSION(extension, major, minor, patch) \ + __has_extension(extension) +#else +#define JSON_HEDLEY_GCC_HAS_EXTENSION(extension, major, minor, patch) \ + JSON_HEDLEY_GCC_VERSION_CHECK(major, minor, patch) +#endif + +#if defined(JSON_HEDLEY_HAS_DECLSPEC_ATTRIBUTE) +#undef JSON_HEDLEY_HAS_DECLSPEC_ATTRIBUTE +#endif +#if defined(__has_declspec_attribute) +#define JSON_HEDLEY_HAS_DECLSPEC_ATTRIBUTE(attribute) \ + __has_declspec_attribute(attribute) +#else +#define JSON_HEDLEY_HAS_DECLSPEC_ATTRIBUTE(attribute) (0) +#endif + +#if defined(JSON_HEDLEY_GNUC_HAS_DECLSPEC_ATTRIBUTE) +#undef JSON_HEDLEY_GNUC_HAS_DECLSPEC_ATTRIBUTE +#endif +#if defined(__has_declspec_attribute) +#define JSON_HEDLEY_GNUC_HAS_DECLSPEC_ATTRIBUTE(attribute, \ + major, \ + minor, \ + patch) \ + __has_declspec_attribute(attribute) +#else +#define JSON_HEDLEY_GNUC_HAS_DECLSPEC_ATTRIBUTE(attribute, \ + major, \ + minor, \ + patch) \ + JSON_HEDLEY_GNUC_VERSION_CHECK(major, minor, patch) +#endif + +#if defined(JSON_HEDLEY_GCC_HAS_DECLSPEC_ATTRIBUTE) +#undef JSON_HEDLEY_GCC_HAS_DECLSPEC_ATTRIBUTE +#endif +#if defined(__has_declspec_attribute) +#define JSON_HEDLEY_GCC_HAS_DECLSPEC_ATTRIBUTE(attribute, major, minor, patch) \ + __has_declspec_attribute(attribute) +#else +#define JSON_HEDLEY_GCC_HAS_DECLSPEC_ATTRIBUTE(attribute, major, minor, patch) \ + JSON_HEDLEY_GCC_VERSION_CHECK(major, minor, patch) +#endif + +#if defined(JSON_HEDLEY_HAS_WARNING) +#undef JSON_HEDLEY_HAS_WARNING +#endif +#if defined(__has_warning) +#define JSON_HEDLEY_HAS_WARNING(warning) __has_warning(warning) +#else +#define JSON_HEDLEY_HAS_WARNING(warning) (0) +#endif + +#if defined(JSON_HEDLEY_GNUC_HAS_WARNING) +#undef JSON_HEDLEY_GNUC_HAS_WARNING +#endif +#if defined(__has_warning) +#define JSON_HEDLEY_GNUC_HAS_WARNING(warning, major, minor, patch) \ + __has_warning(warning) +#else +#define JSON_HEDLEY_GNUC_HAS_WARNING(warning, major, minor, patch) \ + JSON_HEDLEY_GNUC_VERSION_CHECK(major, minor, patch) +#endif + +#if defined(JSON_HEDLEY_GCC_HAS_WARNING) +#undef JSON_HEDLEY_GCC_HAS_WARNING +#endif +#if defined(__has_warning) +#define JSON_HEDLEY_GCC_HAS_WARNING(warning, major, minor, patch) \ + __has_warning(warning) +#else +#define JSON_HEDLEY_GCC_HAS_WARNING(warning, major, minor, patch) \ + JSON_HEDLEY_GCC_VERSION_CHECK(major, minor, patch) +#endif + +#if (defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L)) || \ + defined(__clang__) || JSON_HEDLEY_GCC_VERSION_CHECK(3, 0, 0) || \ + JSON_HEDLEY_INTEL_VERSION_CHECK(13, 0, 0) || \ + JSON_HEDLEY_IAR_VERSION_CHECK(8, 0, 0) || \ + JSON_HEDLEY_PGI_VERSION_CHECK(18, 4, 0) || \ + JSON_HEDLEY_ARM_VERSION_CHECK(4, 1, 0) || \ + JSON_HEDLEY_TI_VERSION_CHECK(15, 12, 0) || \ + JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(4, 7, 0) || \ + JSON_HEDLEY_TI_CL430_VERSION_CHECK(2, 0, 1) || \ + JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6, 1, 0) || \ + JSON_HEDLEY_TI_CL6X_VERSION_CHECK(7, 0, 0) || \ + JSON_HEDLEY_TI_CL7X_VERSION_CHECK(1, 2, 0) || \ + JSON_HEDLEY_TI_CLPRU_VERSION_CHECK(2, 1, 0) || \ + JSON_HEDLEY_CRAY_VERSION_CHECK(5, 0, 0) || \ + JSON_HEDLEY_TINYC_VERSION_CHECK(0, 9, 17) || \ + JSON_HEDLEY_SUNPRO_VERSION_CHECK(8, 0, 0) || \ + (JSON_HEDLEY_IBM_VERSION_CHECK(10, 1, 0) && \ + defined(__C99_PRAGMA_OPERATOR)) +#define JSON_HEDLEY_PRAGMA(value) _Pragma(#value) +#elif JSON_HEDLEY_MSVC_VERSION_CHECK(15, 0, 0) +#define JSON_HEDLEY_PRAGMA(value) __pragma(value) +#else +#define JSON_HEDLEY_PRAGMA(value) +#endif + +#if defined(JSON_HEDLEY_DIAGNOSTIC_PUSH) +#undef JSON_HEDLEY_DIAGNOSTIC_PUSH +#endif +#if defined(JSON_HEDLEY_DIAGNOSTIC_POP) +#undef JSON_HEDLEY_DIAGNOSTIC_POP +#endif +#if defined(__clang__) +#define JSON_HEDLEY_DIAGNOSTIC_PUSH _Pragma("clang diagnostic push") +#define JSON_HEDLEY_DIAGNOSTIC_POP _Pragma("clang diagnostic pop") +#elif JSON_HEDLEY_INTEL_VERSION_CHECK(13, 0, 0) +#define JSON_HEDLEY_DIAGNOSTIC_PUSH _Pragma("warning(push)") +#define JSON_HEDLEY_DIAGNOSTIC_POP _Pragma("warning(pop)") +#elif JSON_HEDLEY_GCC_VERSION_CHECK(4, 6, 0) +#define JSON_HEDLEY_DIAGNOSTIC_PUSH _Pragma("GCC diagnostic push") +#define JSON_HEDLEY_DIAGNOSTIC_POP _Pragma("GCC diagnostic pop") +#elif JSON_HEDLEY_MSVC_VERSION_CHECK(15, 0, 0) || \ + JSON_HEDLEY_INTEL_CL_VERSION_CHECK(2021, 1, 0) +#define JSON_HEDLEY_DIAGNOSTIC_PUSH __pragma(warning(push)) +#define JSON_HEDLEY_DIAGNOSTIC_POP __pragma(warning(pop)) +#elif JSON_HEDLEY_ARM_VERSION_CHECK(5, 6, 0) +#define JSON_HEDLEY_DIAGNOSTIC_PUSH _Pragma("push") +#define JSON_HEDLEY_DIAGNOSTIC_POP _Pragma("pop") +#elif JSON_HEDLEY_TI_VERSION_CHECK(15, 12, 0) || \ + JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(5, 2, 0) || \ + JSON_HEDLEY_TI_CL430_VERSION_CHECK(4, 4, 0) || \ + JSON_HEDLEY_TI_CL6X_VERSION_CHECK(8, 1, 0) || \ + JSON_HEDLEY_TI_CL7X_VERSION_CHECK(1, 2, 0) || \ + JSON_HEDLEY_TI_CLPRU_VERSION_CHECK(2, 1, 0) +#define JSON_HEDLEY_DIAGNOSTIC_PUSH _Pragma("diag_push") +#define JSON_HEDLEY_DIAGNOSTIC_POP _Pragma("diag_pop") +#elif JSON_HEDLEY_PELLES_VERSION_CHECK(2, 90, 0) +#define JSON_HEDLEY_DIAGNOSTIC_PUSH _Pragma("warning(push)") +#define JSON_HEDLEY_DIAGNOSTIC_POP _Pragma("warning(pop)") +#else +#define JSON_HEDLEY_DIAGNOSTIC_PUSH +#define JSON_HEDLEY_DIAGNOSTIC_POP +#endif + +/* JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_ is for + HEDLEY INTERNAL USE ONLY. API subject to change without notice. */ +#if defined(JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_) +#undef JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_ +#endif +#if defined(__cplusplus) +#if JSON_HEDLEY_HAS_WARNING("-Wc++98-compat") +#if JSON_HEDLEY_HAS_WARNING("-Wc++17-extensions") +#if JSON_HEDLEY_HAS_WARNING("-Wc++1z-extensions") +#define JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_(xpr) \ + JSON_HEDLEY_DIAGNOSTIC_PUSH \ + _Pragma("clang diagnostic ignored \"-Wc++98-compat\"") \ + _Pragma("clang diagnostic ignored \"-Wc++17-extensions\"") \ + _Pragma("clang diagnostic ignored \"-Wc++1z-extensions\"") \ + xpr JSON_HEDLEY_DIAGNOSTIC_POP +#else +#define JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_(xpr) \ + JSON_HEDLEY_DIAGNOSTIC_PUSH \ + _Pragma("clang diagnostic ignored \"-Wc++98-compat\"") \ + _Pragma("clang diagnostic ignored \"-Wc++17-extensions\"") \ + xpr JSON_HEDLEY_DIAGNOSTIC_POP +#endif +#else +#define JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_(xpr) \ + JSON_HEDLEY_DIAGNOSTIC_PUSH \ + _Pragma("clang diagnostic ignored \"-Wc++98-compat\"") \ + xpr JSON_HEDLEY_DIAGNOSTIC_POP +#endif +#endif +#endif +#if !defined(JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_) +#define JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_(x) x +#endif + +#if defined(JSON_HEDLEY_CONST_CAST) +#undef JSON_HEDLEY_CONST_CAST +#endif +#if defined(__cplusplus) +#define JSON_HEDLEY_CONST_CAST(T, expr) (const_cast(expr)) +#elif JSON_HEDLEY_HAS_WARNING("-Wcast-qual") || \ + JSON_HEDLEY_GCC_VERSION_CHECK(4, 6, 0) || \ + JSON_HEDLEY_INTEL_VERSION_CHECK(13, 0, 0) +#define JSON_HEDLEY_CONST_CAST(T, expr) \ + (__extension__({ \ + JSON_HEDLEY_DIAGNOSTIC_PUSH \ + JSON_HEDLEY_DIAGNOSTIC_DISABLE_CAST_QUAL((T)(expr)); \ + JSON_HEDLEY_DIAGNOSTIC_POP \ + })) +#else +#define JSON_HEDLEY_CONST_CAST(T, expr) ((T)(expr)) +#endif + +#if defined(JSON_HEDLEY_REINTERPRET_CAST) +#undef JSON_HEDLEY_REINTERPRET_CAST +#endif +#if defined(__cplusplus) +#define JSON_HEDLEY_REINTERPRET_CAST(T, expr) (reinterpret_cast(expr)) +#else +#define JSON_HEDLEY_REINTERPRET_CAST(T, expr) ((T)(expr)) +#endif + +#if defined(JSON_HEDLEY_STATIC_CAST) +#undef JSON_HEDLEY_STATIC_CAST +#endif +#if defined(__cplusplus) +#define JSON_HEDLEY_STATIC_CAST(T, expr) (static_cast(expr)) +#else +#define JSON_HEDLEY_STATIC_CAST(T, expr) ((T)(expr)) +#endif + +#if defined(JSON_HEDLEY_CPP_CAST) +#undef JSON_HEDLEY_CPP_CAST +#endif +#if defined(__cplusplus) +#if JSON_HEDLEY_HAS_WARNING("-Wold-style-cast") +#define JSON_HEDLEY_CPP_CAST(T, expr) \ + JSON_HEDLEY_DIAGNOSTIC_PUSH \ + _Pragma("clang diagnostic ignored \"-Wold-style-cast\"")((T)(expr)) \ + JSON_HEDLEY_DIAGNOSTIC_POP +#elif JSON_HEDLEY_IAR_VERSION_CHECK(8, 3, 0) +#define JSON_HEDLEY_CPP_CAST(T, expr) \ + JSON_HEDLEY_DIAGNOSTIC_PUSH \ + _Pragma("diag_suppress=Pe137") JSON_HEDLEY_DIAGNOSTIC_POP +#else +#define JSON_HEDLEY_CPP_CAST(T, expr) ((T)(expr)) +#endif +#else +#define JSON_HEDLEY_CPP_CAST(T, expr) (expr) +#endif + +#if defined(JSON_HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED) +#undef JSON_HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED +#endif +#if JSON_HEDLEY_HAS_WARNING("-Wdeprecated-declarations") +#define JSON_HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED \ + _Pragma("clang diagnostic ignored \"-Wdeprecated-declarations\"") +#elif JSON_HEDLEY_INTEL_VERSION_CHECK(13, 0, 0) +#define JSON_HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED \ + _Pragma("warning(disable:1478 1786)") +#elif JSON_HEDLEY_INTEL_CL_VERSION_CHECK(2021, 1, 0) +#define JSON_HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED \ + __pragma(warning(disable : 1478 1786)) +#elif JSON_HEDLEY_PGI_VERSION_CHECK(20, 7, 0) +#define JSON_HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED \ + _Pragma("diag_suppress 1215,1216,1444,1445") +#elif JSON_HEDLEY_PGI_VERSION_CHECK(17, 10, 0) +#define JSON_HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED \ + _Pragma("diag_suppress 1215,1444") +#elif JSON_HEDLEY_GCC_VERSION_CHECK(4, 3, 0) +#define JSON_HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED \ + _Pragma("GCC diagnostic ignored \"-Wdeprecated-declarations\"") +#elif JSON_HEDLEY_MSVC_VERSION_CHECK(15, 0, 0) +#define JSON_HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED \ + __pragma(warning(disable : 4996)) +#elif JSON_HEDLEY_MCST_LCC_VERSION_CHECK(1, 25, 10) +#define JSON_HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED \ + _Pragma("diag_suppress 1215,1444") +#elif JSON_HEDLEY_TI_VERSION_CHECK(15, 12, 0) || \ + (JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(4, 8, 0) && \ + defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(5, 2, 0) || \ + (JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6, 0, 0) && \ + defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6, 4, 0) || \ + (JSON_HEDLEY_TI_CL430_VERSION_CHECK(4, 0, 0) && \ + defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + JSON_HEDLEY_TI_CL430_VERSION_CHECK(4, 3, 0) || \ + (JSON_HEDLEY_TI_CL6X_VERSION_CHECK(7, 2, 0) && \ + defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + JSON_HEDLEY_TI_CL6X_VERSION_CHECK(7, 5, 0) || \ + JSON_HEDLEY_TI_CL7X_VERSION_CHECK(1, 2, 0) || \ + JSON_HEDLEY_TI_CLPRU_VERSION_CHECK(2, 1, 0) +#define JSON_HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED \ + _Pragma("diag_suppress 1291,1718") +#elif JSON_HEDLEY_SUNPRO_VERSION_CHECK(5, 13, 0) && !defined(__cplusplus) +#define JSON_HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED \ + _Pragma("error_messages(off,E_DEPRECATED_ATT,E_DEPRECATED_ATT_MESS)") +#elif JSON_HEDLEY_SUNPRO_VERSION_CHECK(5, 13, 0) && defined(__cplusplus) +#define JSON_HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED \ + _Pragma("error_messages(off,symdeprecated,symdeprecated2)") +#elif JSON_HEDLEY_IAR_VERSION_CHECK(8, 0, 0) +#define JSON_HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED \ + _Pragma("diag_suppress=Pe1444,Pe1215") +#elif JSON_HEDLEY_PELLES_VERSION_CHECK(2, 90, 0) +#define JSON_HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED _Pragma("warn(disable:2241)") +#else +#define JSON_HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED +#endif + +#if defined(JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS) +#undef JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS +#endif +#if JSON_HEDLEY_HAS_WARNING("-Wunknown-pragmas") +#define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS \ + _Pragma("clang diagnostic ignored \"-Wunknown-pragmas\"") +#elif JSON_HEDLEY_INTEL_VERSION_CHECK(13, 0, 0) +#define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS \ + _Pragma("warning(disable:161)") +#elif JSON_HEDLEY_INTEL_CL_VERSION_CHECK(2021, 1, 0) +#define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS \ + __pragma(warning(disable : 161)) +#elif JSON_HEDLEY_PGI_VERSION_CHECK(17, 10, 0) +#define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS \ + _Pragma("diag_suppress 1675") +#elif JSON_HEDLEY_GCC_VERSION_CHECK(4, 3, 0) +#define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS \ + _Pragma("GCC diagnostic ignored \"-Wunknown-pragmas\"") +#elif JSON_HEDLEY_MSVC_VERSION_CHECK(15, 0, 0) +#define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS \ + __pragma(warning(disable : 4068)) +#elif JSON_HEDLEY_TI_VERSION_CHECK(16, 9, 0) || \ + JSON_HEDLEY_TI_CL6X_VERSION_CHECK(8, 0, 0) || \ + JSON_HEDLEY_TI_CL7X_VERSION_CHECK(1, 2, 0) || \ + JSON_HEDLEY_TI_CLPRU_VERSION_CHECK(2, 3, 0) +#define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS \ + _Pragma("diag_suppress 163") +#elif JSON_HEDLEY_TI_CL6X_VERSION_CHECK(8, 0, 0) +#define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS \ + _Pragma("diag_suppress 163") +#elif JSON_HEDLEY_IAR_VERSION_CHECK(8, 0, 0) +#define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS \ + _Pragma("diag_suppress=Pe161") +#elif JSON_HEDLEY_MCST_LCC_VERSION_CHECK(1, 25, 10) +#define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS \ + _Pragma("diag_suppress 161") +#else +#define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS +#endif + +#if defined(JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_CPP_ATTRIBUTES) +#undef JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_CPP_ATTRIBUTES +#endif +#if JSON_HEDLEY_HAS_WARNING("-Wunknown-attributes") +#define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_CPP_ATTRIBUTES \ + _Pragma("clang diagnostic ignored \"-Wunknown-attributes\"") +#elif JSON_HEDLEY_GCC_VERSION_CHECK(4, 6, 0) +#define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_CPP_ATTRIBUTES \ + _Pragma("GCC diagnostic ignored \"-Wdeprecated-declarations\"") +#elif JSON_HEDLEY_INTEL_VERSION_CHECK(17, 0, 0) +#define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_CPP_ATTRIBUTES \ + _Pragma("warning(disable:1292)") +#elif JSON_HEDLEY_INTEL_CL_VERSION_CHECK(2021, 1, 0) +#define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_CPP_ATTRIBUTES \ + __pragma(warning(disable : 1292)) +#elif JSON_HEDLEY_MSVC_VERSION_CHECK(19, 0, 0) +#define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_CPP_ATTRIBUTES \ + __pragma(warning(disable : 5030)) +#elif JSON_HEDLEY_PGI_VERSION_CHECK(20, 7, 0) +#define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_CPP_ATTRIBUTES \ + _Pragma("diag_suppress 1097,1098") +#elif JSON_HEDLEY_PGI_VERSION_CHECK(17, 10, 0) +#define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_CPP_ATTRIBUTES \ + _Pragma("diag_suppress 1097") +#elif JSON_HEDLEY_SUNPRO_VERSION_CHECK(5, 14, 0) && defined(__cplusplus) +#define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_CPP_ATTRIBUTES \ + _Pragma("error_messages(off,attrskipunsup)") +#elif JSON_HEDLEY_TI_VERSION_CHECK(18, 1, 0) || \ + JSON_HEDLEY_TI_CL6X_VERSION_CHECK(8, 3, 0) || \ + JSON_HEDLEY_TI_CL7X_VERSION_CHECK(1, 2, 0) +#define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_CPP_ATTRIBUTES \ + _Pragma("diag_suppress 1173") +#elif JSON_HEDLEY_IAR_VERSION_CHECK(8, 0, 0) +#define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_CPP_ATTRIBUTES \ + _Pragma("diag_suppress=Pe1097") +#elif JSON_HEDLEY_MCST_LCC_VERSION_CHECK(1, 25, 10) +#define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_CPP_ATTRIBUTES \ + _Pragma("diag_suppress 1097") +#else +#define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_CPP_ATTRIBUTES +#endif + +#if defined(JSON_HEDLEY_DIAGNOSTIC_DISABLE_CAST_QUAL) +#undef JSON_HEDLEY_DIAGNOSTIC_DISABLE_CAST_QUAL +#endif +#if JSON_HEDLEY_HAS_WARNING("-Wcast-qual") +#define JSON_HEDLEY_DIAGNOSTIC_DISABLE_CAST_QUAL \ + _Pragma("clang diagnostic ignored \"-Wcast-qual\"") +#elif JSON_HEDLEY_INTEL_VERSION_CHECK(13, 0, 0) +#define JSON_HEDLEY_DIAGNOSTIC_DISABLE_CAST_QUAL \ + _Pragma("warning(disable:2203 2331)") +#elif JSON_HEDLEY_GCC_VERSION_CHECK(3, 0, 0) +#define JSON_HEDLEY_DIAGNOSTIC_DISABLE_CAST_QUAL \ + _Pragma("GCC diagnostic ignored \"-Wcast-qual\"") +#else +#define JSON_HEDLEY_DIAGNOSTIC_DISABLE_CAST_QUAL +#endif + +#if defined(JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNUSED_FUNCTION) +#undef JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNUSED_FUNCTION +#endif +#if JSON_HEDLEY_HAS_WARNING("-Wunused-function") +#define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNUSED_FUNCTION \ + _Pragma("clang diagnostic ignored \"-Wunused-function\"") +#elif JSON_HEDLEY_GCC_VERSION_CHECK(3, 4, 0) +#define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNUSED_FUNCTION \ + _Pragma("GCC diagnostic ignored \"-Wunused-function\"") +#elif JSON_HEDLEY_MSVC_VERSION_CHECK(1, 0, 0) +#define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNUSED_FUNCTION \ + __pragma(warning(disable : 4505)) +#elif JSON_HEDLEY_MCST_LCC_VERSION_CHECK(1, 25, 10) +#define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNUSED_FUNCTION \ + _Pragma("diag_suppress 3142") +#else +#define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNUSED_FUNCTION +#endif + +#if defined(JSON_HEDLEY_DEPRECATED) +#undef JSON_HEDLEY_DEPRECATED +#endif +#if defined(JSON_HEDLEY_DEPRECATED_FOR) +#undef JSON_HEDLEY_DEPRECATED_FOR +#endif +#if JSON_HEDLEY_MSVC_VERSION_CHECK(14, 0, 0) || \ + JSON_HEDLEY_INTEL_CL_VERSION_CHECK(2021, 1, 0) +#define JSON_HEDLEY_DEPRECATED(since) __declspec(deprecated("Since " #since)) +#define JSON_HEDLEY_DEPRECATED_FOR(since, replacement) \ + __declspec(deprecated("Since " #since "; use " #replacement)) +#elif (JSON_HEDLEY_HAS_EXTENSION(attribute_deprecated_with_message) && \ + !defined(JSON_HEDLEY_IAR_VERSION)) || \ + JSON_HEDLEY_GCC_VERSION_CHECK(4, 5, 0) || \ + JSON_HEDLEY_INTEL_VERSION_CHECK(13, 0, 0) || \ + JSON_HEDLEY_ARM_VERSION_CHECK(5, 6, 0) || \ + JSON_HEDLEY_SUNPRO_VERSION_CHECK(5, 13, 0) || \ + JSON_HEDLEY_PGI_VERSION_CHECK(17, 10, 0) || \ + JSON_HEDLEY_TI_VERSION_CHECK(18, 1, 0) || \ + JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(18, 1, 0) || \ + JSON_HEDLEY_TI_CL6X_VERSION_CHECK(8, 3, 0) || \ + JSON_HEDLEY_TI_CL7X_VERSION_CHECK(1, 2, 0) || \ + JSON_HEDLEY_TI_CLPRU_VERSION_CHECK(2, 3, 0) || \ + JSON_HEDLEY_MCST_LCC_VERSION_CHECK(1, 25, 10) +#define JSON_HEDLEY_DEPRECATED(since) \ + __attribute__((__deprecated__("Since " #since))) +#define JSON_HEDLEY_DEPRECATED_FOR(since, replacement) \ + __attribute__((__deprecated__("Since " #since "; use " #replacement))) +#elif defined(__cplusplus) && (__cplusplus >= 201402L) +#define JSON_HEDLEY_DEPRECATED(since) \ + JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_( \ + [[deprecated("Since " #since)]]) +#define JSON_HEDLEY_DEPRECATED_FOR(since, replacement) \ + JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_( \ + [[deprecated("Since " #since "; use " #replacement)]]) +#elif JSON_HEDLEY_HAS_ATTRIBUTE(deprecated) || \ + JSON_HEDLEY_GCC_VERSION_CHECK(3, 1, 0) || \ + JSON_HEDLEY_ARM_VERSION_CHECK(4, 1, 0) || \ + JSON_HEDLEY_TI_VERSION_CHECK(15, 12, 0) || \ + (JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(4, 8, 0) && \ + defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(5, 2, 0) || \ + (JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6, 0, 0) && \ + defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6, 4, 0) || \ + (JSON_HEDLEY_TI_CL430_VERSION_CHECK(4, 0, 0) && \ + defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + JSON_HEDLEY_TI_CL430_VERSION_CHECK(4, 3, 0) || \ + (JSON_HEDLEY_TI_CL6X_VERSION_CHECK(7, 2, 0) && \ + defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + JSON_HEDLEY_TI_CL6X_VERSION_CHECK(7, 5, 0) || \ + JSON_HEDLEY_TI_CL7X_VERSION_CHECK(1, 2, 0) || \ + JSON_HEDLEY_TI_CLPRU_VERSION_CHECK(2, 1, 0) || \ + JSON_HEDLEY_MCST_LCC_VERSION_CHECK(1, 25, 10) || \ + JSON_HEDLEY_IAR_VERSION_CHECK(8, 10, 0) +#define JSON_HEDLEY_DEPRECATED(since) __attribute__((__deprecated__)) +#define JSON_HEDLEY_DEPRECATED_FOR(since, replacement) \ + __attribute__((__deprecated__)) +#elif JSON_HEDLEY_MSVC_VERSION_CHECK(13, 10, 0) || \ + JSON_HEDLEY_PELLES_VERSION_CHECK(6, 50, 0) || \ + JSON_HEDLEY_INTEL_CL_VERSION_CHECK(2021, 1, 0) +#define JSON_HEDLEY_DEPRECATED(since) __declspec(deprecated) +#define JSON_HEDLEY_DEPRECATED_FOR(since, replacement) __declspec(deprecated) +#elif JSON_HEDLEY_IAR_VERSION_CHECK(8, 0, 0) +#define JSON_HEDLEY_DEPRECATED(since) _Pragma("deprecated") +#define JSON_HEDLEY_DEPRECATED_FOR(since, replacement) _Pragma("deprecated") +#else +#define JSON_HEDLEY_DEPRECATED(since) +#define JSON_HEDLEY_DEPRECATED_FOR(since, replacement) +#endif + +#if defined(JSON_HEDLEY_UNAVAILABLE) +#undef JSON_HEDLEY_UNAVAILABLE +#endif +#if JSON_HEDLEY_HAS_ATTRIBUTE(warning) || \ + JSON_HEDLEY_GCC_VERSION_CHECK(4, 3, 0) || \ + JSON_HEDLEY_INTEL_VERSION_CHECK(13, 0, 0) || \ + JSON_HEDLEY_MCST_LCC_VERSION_CHECK(1, 25, 10) +#define JSON_HEDLEY_UNAVAILABLE(available_since) \ + __attribute__((__warning__("Not available until " #available_since))) +#else +#define JSON_HEDLEY_UNAVAILABLE(available_since) +#endif + +#if defined(JSON_HEDLEY_WARN_UNUSED_RESULT) +#undef JSON_HEDLEY_WARN_UNUSED_RESULT +#endif +#if defined(JSON_HEDLEY_WARN_UNUSED_RESULT_MSG) +#undef JSON_HEDLEY_WARN_UNUSED_RESULT_MSG +#endif +#if JSON_HEDLEY_HAS_ATTRIBUTE(warn_unused_result) || \ + JSON_HEDLEY_GCC_VERSION_CHECK(3, 4, 0) || \ + JSON_HEDLEY_INTEL_VERSION_CHECK(13, 0, 0) || \ + JSON_HEDLEY_TI_VERSION_CHECK(15, 12, 0) || \ + (JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(4, 8, 0) && \ + defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(5, 2, 0) || \ + (JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6, 0, 0) && \ + defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6, 4, 0) || \ + (JSON_HEDLEY_TI_CL430_VERSION_CHECK(4, 0, 0) && \ + defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + JSON_HEDLEY_TI_CL430_VERSION_CHECK(4, 3, 0) || \ + (JSON_HEDLEY_TI_CL6X_VERSION_CHECK(7, 2, 0) && \ + defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + JSON_HEDLEY_TI_CL6X_VERSION_CHECK(7, 5, 0) || \ + JSON_HEDLEY_TI_CL7X_VERSION_CHECK(1, 2, 0) || \ + JSON_HEDLEY_TI_CLPRU_VERSION_CHECK(2, 1, 0) || \ + (JSON_HEDLEY_SUNPRO_VERSION_CHECK(5, 15, 0) && defined(__cplusplus)) || \ + JSON_HEDLEY_PGI_VERSION_CHECK(17, 10, 0) || \ + JSON_HEDLEY_MCST_LCC_VERSION_CHECK(1, 25, 10) +#define JSON_HEDLEY_WARN_UNUSED_RESULT __attribute__((__warn_unused_result__)) +#define JSON_HEDLEY_WARN_UNUSED_RESULT_MSG(msg) \ + __attribute__((__warn_unused_result__)) +#elif (JSON_HEDLEY_HAS_CPP_ATTRIBUTE(nodiscard) >= 201907L) +#define JSON_HEDLEY_WARN_UNUSED_RESULT \ + JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_([[nodiscard]]) +#define JSON_HEDLEY_WARN_UNUSED_RESULT_MSG(msg) \ + JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_([[nodiscard(msg)]]) +#elif JSON_HEDLEY_HAS_CPP_ATTRIBUTE(nodiscard) +#define JSON_HEDLEY_WARN_UNUSED_RESULT \ + JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_([[nodiscard]]) +#define JSON_HEDLEY_WARN_UNUSED_RESULT_MSG(msg) \ + JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_([[nodiscard]]) +#elif defined(_Check_return_) /* SAL */ +#define JSON_HEDLEY_WARN_UNUSED_RESULT _Check_return_ +#define JSON_HEDLEY_WARN_UNUSED_RESULT_MSG(msg) _Check_return_ +#else +#define JSON_HEDLEY_WARN_UNUSED_RESULT +#define JSON_HEDLEY_WARN_UNUSED_RESULT_MSG(msg) +#endif + +#if defined(JSON_HEDLEY_SENTINEL) +#undef JSON_HEDLEY_SENTINEL +#endif +#if JSON_HEDLEY_HAS_ATTRIBUTE(sentinel) || \ + JSON_HEDLEY_GCC_VERSION_CHECK(4, 0, 0) || \ + JSON_HEDLEY_INTEL_VERSION_CHECK(13, 0, 0) || \ + JSON_HEDLEY_ARM_VERSION_CHECK(5, 4, 0) || \ + JSON_HEDLEY_MCST_LCC_VERSION_CHECK(1, 25, 10) +#define JSON_HEDLEY_SENTINEL(position) __attribute__((__sentinel__(position))) +#else +#define JSON_HEDLEY_SENTINEL(position) +#endif + +#if defined(JSON_HEDLEY_NO_RETURN) +#undef JSON_HEDLEY_NO_RETURN +#endif +#if JSON_HEDLEY_IAR_VERSION_CHECK(8, 0, 0) +#define JSON_HEDLEY_NO_RETURN __noreturn +#elif JSON_HEDLEY_INTEL_VERSION_CHECK(13, 0, 0) || \ + JSON_HEDLEY_MCST_LCC_VERSION_CHECK(1, 25, 10) +#define JSON_HEDLEY_NO_RETURN __attribute__((__noreturn__)) +#elif defined(__STDC_VERSION__) && __STDC_VERSION__ >= 201112L +#define JSON_HEDLEY_NO_RETURN _Noreturn +#elif defined(__cplusplus) && (__cplusplus >= 201103L) +#define JSON_HEDLEY_NO_RETURN \ + JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_([[noreturn]]) +#elif JSON_HEDLEY_HAS_ATTRIBUTE(noreturn) || \ + JSON_HEDLEY_GCC_VERSION_CHECK(3, 2, 0) || \ + JSON_HEDLEY_SUNPRO_VERSION_CHECK(5, 11, 0) || \ + JSON_HEDLEY_ARM_VERSION_CHECK(4, 1, 0) || \ + JSON_HEDLEY_IBM_VERSION_CHECK(10, 1, 0) || \ + JSON_HEDLEY_TI_VERSION_CHECK(15, 12, 0) || \ + (JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(4, 8, 0) && \ + defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(5, 2, 0) || \ + (JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6, 0, 0) && \ + defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6, 4, 0) || \ + (JSON_HEDLEY_TI_CL430_VERSION_CHECK(4, 0, 0) && \ + defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + JSON_HEDLEY_TI_CL430_VERSION_CHECK(4, 3, 0) || \ + (JSON_HEDLEY_TI_CL6X_VERSION_CHECK(7, 2, 0) && \ + defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + JSON_HEDLEY_TI_CL6X_VERSION_CHECK(7, 5, 0) || \ + JSON_HEDLEY_TI_CL7X_VERSION_CHECK(1, 2, 0) || \ + JSON_HEDLEY_TI_CLPRU_VERSION_CHECK(2, 1, 0) || \ + JSON_HEDLEY_IAR_VERSION_CHECK(8, 10, 0) +#define JSON_HEDLEY_NO_RETURN __attribute__((__noreturn__)) +#elif JSON_HEDLEY_SUNPRO_VERSION_CHECK(5, 10, 0) +#define JSON_HEDLEY_NO_RETURN _Pragma("does_not_return") +#elif JSON_HEDLEY_MSVC_VERSION_CHECK(13, 10, 0) || \ + JSON_HEDLEY_INTEL_CL_VERSION_CHECK(2021, 1, 0) +#define JSON_HEDLEY_NO_RETURN __declspec(noreturn) +#elif JSON_HEDLEY_TI_CL6X_VERSION_CHECK(6, 0, 0) && defined(__cplusplus) +#define JSON_HEDLEY_NO_RETURN _Pragma("FUNC_NEVER_RETURNS;") +#elif JSON_HEDLEY_COMPCERT_VERSION_CHECK(3, 2, 0) +#define JSON_HEDLEY_NO_RETURN __attribute((noreturn)) +#elif JSON_HEDLEY_PELLES_VERSION_CHECK(9, 0, 0) +#define JSON_HEDLEY_NO_RETURN __declspec(noreturn) +#else +#define JSON_HEDLEY_NO_RETURN +#endif + +#if defined(JSON_HEDLEY_NO_ESCAPE) +#undef JSON_HEDLEY_NO_ESCAPE +#endif +#if JSON_HEDLEY_HAS_ATTRIBUTE(noescape) +#define JSON_HEDLEY_NO_ESCAPE __attribute__((__noescape__)) +#else +#define JSON_HEDLEY_NO_ESCAPE +#endif + +#if defined(JSON_HEDLEY_UNREACHABLE) +#undef JSON_HEDLEY_UNREACHABLE +#endif +#if defined(JSON_HEDLEY_UNREACHABLE_RETURN) +#undef JSON_HEDLEY_UNREACHABLE_RETURN +#endif +#if defined(JSON_HEDLEY_ASSUME) +#undef JSON_HEDLEY_ASSUME +#endif +#if JSON_HEDLEY_MSVC_VERSION_CHECK(13, 10, 0) || \ + JSON_HEDLEY_INTEL_VERSION_CHECK(13, 0, 0) || \ + JSON_HEDLEY_INTEL_CL_VERSION_CHECK(2021, 1, 0) +#define JSON_HEDLEY_ASSUME(expr) __assume(expr) +#elif JSON_HEDLEY_HAS_BUILTIN(__builtin_assume) +#define JSON_HEDLEY_ASSUME(expr) __builtin_assume(expr) +#elif JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6, 2, 0) || \ + JSON_HEDLEY_TI_CL6X_VERSION_CHECK(4, 0, 0) +#if defined(__cplusplus) +#define JSON_HEDLEY_ASSUME(expr) std::_nassert(expr) +#else +#define JSON_HEDLEY_ASSUME(expr) _nassert(expr) +#endif +#endif +#if (JSON_HEDLEY_HAS_BUILTIN(__builtin_unreachable) && \ + (!defined(JSON_HEDLEY_ARM_VERSION))) || \ + JSON_HEDLEY_GCC_VERSION_CHECK(4, 5, 0) || \ + JSON_HEDLEY_PGI_VERSION_CHECK(18, 10, 0) || \ + JSON_HEDLEY_INTEL_VERSION_CHECK(13, 0, 0) || \ + JSON_HEDLEY_IBM_VERSION_CHECK(13, 1, 5) || \ + JSON_HEDLEY_CRAY_VERSION_CHECK(10, 0, 0) || \ + JSON_HEDLEY_MCST_LCC_VERSION_CHECK(1, 25, 10) +#define JSON_HEDLEY_UNREACHABLE() __builtin_unreachable() +#elif defined(JSON_HEDLEY_ASSUME) +#define JSON_HEDLEY_UNREACHABLE() JSON_HEDLEY_ASSUME(0) +#endif +#if !defined(JSON_HEDLEY_ASSUME) +#if defined(JSON_HEDLEY_UNREACHABLE) +#define JSON_HEDLEY_ASSUME(expr) \ + JSON_HEDLEY_STATIC_CAST(void, ((expr) ? 1 : (JSON_HEDLEY_UNREACHABLE(), 1))) +#else +#define JSON_HEDLEY_ASSUME(expr) JSON_HEDLEY_STATIC_CAST(void, expr) +#endif +#endif +#if defined(JSON_HEDLEY_UNREACHABLE) +#if JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6, 2, 0) || \ + JSON_HEDLEY_TI_CL6X_VERSION_CHECK(4, 0, 0) +#define JSON_HEDLEY_UNREACHABLE_RETURN(value) \ + return (JSON_HEDLEY_STATIC_CAST(void, JSON_HEDLEY_ASSUME(0)), (value)) +#else +#define JSON_HEDLEY_UNREACHABLE_RETURN(value) JSON_HEDLEY_UNREACHABLE() +#endif +#else +#define JSON_HEDLEY_UNREACHABLE_RETURN(value) return (value) +#endif +#if !defined(JSON_HEDLEY_UNREACHABLE) +#define JSON_HEDLEY_UNREACHABLE() JSON_HEDLEY_ASSUME(0) +#endif + +JSON_HEDLEY_DIAGNOSTIC_PUSH +#if JSON_HEDLEY_HAS_WARNING("-Wpedantic") +#pragma clang diagnostic ignored "-Wpedantic" +#endif +#if JSON_HEDLEY_HAS_WARNING("-Wc++98-compat-pedantic") && defined(__cplusplus) +#pragma clang diagnostic ignored "-Wc++98-compat-pedantic" +#endif +#if JSON_HEDLEY_GCC_HAS_WARNING("-Wvariadic-macros", 4, 0, 0) +#if defined(__clang__) +#pragma clang diagnostic ignored "-Wvariadic-macros" +#elif defined(JSON_HEDLEY_GCC_VERSION) +#pragma GCC diagnostic ignored "-Wvariadic-macros" +#endif +#endif +#if defined(JSON_HEDLEY_NON_NULL) +#undef JSON_HEDLEY_NON_NULL +#endif +#if JSON_HEDLEY_HAS_ATTRIBUTE(nonnull) || \ + JSON_HEDLEY_GCC_VERSION_CHECK(3, 3, 0) || \ + JSON_HEDLEY_INTEL_VERSION_CHECK(13, 0, 0) || \ + JSON_HEDLEY_ARM_VERSION_CHECK(4, 1, 0) +#define JSON_HEDLEY_NON_NULL(...) __attribute__((__nonnull__(__VA_ARGS__))) +#else +#define JSON_HEDLEY_NON_NULL(...) +#endif +JSON_HEDLEY_DIAGNOSTIC_POP + +#if defined(JSON_HEDLEY_PRINTF_FORMAT) +#undef JSON_HEDLEY_PRINTF_FORMAT +#endif +#if defined(__MINGW32__) && JSON_HEDLEY_GCC_HAS_ATTRIBUTE(format, 4, 4, 0) && \ + !defined(__USE_MINGW_ANSI_STDIO) +#define JSON_HEDLEY_PRINTF_FORMAT(string_idx, first_to_check) \ + __attribute__((__format__(ms_printf, string_idx, first_to_check))) +#elif defined(__MINGW32__) && \ + JSON_HEDLEY_GCC_HAS_ATTRIBUTE(format, 4, 4, 0) && \ + defined(__USE_MINGW_ANSI_STDIO) +#define JSON_HEDLEY_PRINTF_FORMAT(string_idx, first_to_check) \ + __attribute__((__format__(gnu_printf, string_idx, first_to_check))) +#elif JSON_HEDLEY_HAS_ATTRIBUTE(format) || \ + JSON_HEDLEY_GCC_VERSION_CHECK(3, 1, 0) || \ + JSON_HEDLEY_INTEL_VERSION_CHECK(13, 0, 0) || \ + JSON_HEDLEY_ARM_VERSION_CHECK(5, 6, 0) || \ + JSON_HEDLEY_IBM_VERSION_CHECK(10, 1, 0) || \ + JSON_HEDLEY_TI_VERSION_CHECK(15, 12, 0) || \ + (JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(4, 8, 0) && \ + defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(5, 2, 0) || \ + (JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6, 0, 0) && \ + defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6, 4, 0) || \ + (JSON_HEDLEY_TI_CL430_VERSION_CHECK(4, 0, 0) && \ + defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + JSON_HEDLEY_TI_CL430_VERSION_CHECK(4, 3, 0) || \ + (JSON_HEDLEY_TI_CL6X_VERSION_CHECK(7, 2, 0) && \ + defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + JSON_HEDLEY_TI_CL6X_VERSION_CHECK(7, 5, 0) || \ + JSON_HEDLEY_TI_CL7X_VERSION_CHECK(1, 2, 0) || \ + JSON_HEDLEY_TI_CLPRU_VERSION_CHECK(2, 1, 0) || \ + JSON_HEDLEY_MCST_LCC_VERSION_CHECK(1, 25, 10) +#define JSON_HEDLEY_PRINTF_FORMAT(string_idx, first_to_check) \ + __attribute__((__format__(__printf__, string_idx, first_to_check))) +#elif JSON_HEDLEY_PELLES_VERSION_CHECK(6, 0, 0) +#define JSON_HEDLEY_PRINTF_FORMAT(string_idx, first_to_check) \ + __declspec(vaformat(printf, string_idx, first_to_check)) +#else +#define JSON_HEDLEY_PRINTF_FORMAT(string_idx, first_to_check) +#endif + +#if defined(JSON_HEDLEY_CONSTEXPR) +#undef JSON_HEDLEY_CONSTEXPR +#endif +#if defined(__cplusplus) +#if __cplusplus >= 201103L +#define JSON_HEDLEY_CONSTEXPR \ + JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_(constexpr) +#endif +#endif +#if !defined(JSON_HEDLEY_CONSTEXPR) +#define JSON_HEDLEY_CONSTEXPR +#endif + +#if defined(JSON_HEDLEY_PREDICT) +#undef JSON_HEDLEY_PREDICT +#endif +#if defined(JSON_HEDLEY_LIKELY) +#undef JSON_HEDLEY_LIKELY +#endif +#if defined(JSON_HEDLEY_UNLIKELY) +#undef JSON_HEDLEY_UNLIKELY +#endif +#if defined(JSON_HEDLEY_UNPREDICTABLE) +#undef JSON_HEDLEY_UNPREDICTABLE +#endif +#if JSON_HEDLEY_HAS_BUILTIN(__builtin_unpredictable) +#define JSON_HEDLEY_UNPREDICTABLE(expr) __builtin_unpredictable((expr)) +#endif +#if (JSON_HEDLEY_HAS_BUILTIN(__builtin_expect_with_probability) && \ + !defined(JSON_HEDLEY_PGI_VERSION)) || \ + JSON_HEDLEY_GCC_VERSION_CHECK(9, 0, 0) || \ + JSON_HEDLEY_MCST_LCC_VERSION_CHECK(1, 25, 10) +#define JSON_HEDLEY_PREDICT(expr, value, probability) \ + __builtin_expect_with_probability((expr), (value), (probability)) +#define JSON_HEDLEY_PREDICT_TRUE(expr, probability) \ + __builtin_expect_with_probability(!!(expr), 1, (probability)) +#define JSON_HEDLEY_PREDICT_FALSE(expr, probability) \ + __builtin_expect_with_probability(!!(expr), 0, (probability)) +#define JSON_HEDLEY_LIKELY(expr) __builtin_expect(!!(expr), 1) +#define JSON_HEDLEY_UNLIKELY(expr) __builtin_expect(!!(expr), 0) +#elif (JSON_HEDLEY_HAS_BUILTIN(__builtin_expect) && \ + !defined(JSON_HEDLEY_INTEL_CL_VERSION)) || \ + JSON_HEDLEY_GCC_VERSION_CHECK(3, 0, 0) || \ + JSON_HEDLEY_INTEL_VERSION_CHECK(13, 0, 0) || \ + (JSON_HEDLEY_SUNPRO_VERSION_CHECK(5, 15, 0) && defined(__cplusplus)) || \ + JSON_HEDLEY_ARM_VERSION_CHECK(4, 1, 0) || \ + JSON_HEDLEY_IBM_VERSION_CHECK(10, 1, 0) || \ + JSON_HEDLEY_TI_VERSION_CHECK(15, 12, 0) || \ + JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(4, 7, 0) || \ + JSON_HEDLEY_TI_CL430_VERSION_CHECK(3, 1, 0) || \ + JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6, 1, 0) || \ + JSON_HEDLEY_TI_CL6X_VERSION_CHECK(6, 1, 0) || \ + JSON_HEDLEY_TI_CL7X_VERSION_CHECK(1, 2, 0) || \ + JSON_HEDLEY_TI_CLPRU_VERSION_CHECK(2, 1, 0) || \ + JSON_HEDLEY_TINYC_VERSION_CHECK(0, 9, 27) || \ + JSON_HEDLEY_CRAY_VERSION_CHECK(8, 1, 0) || \ + JSON_HEDLEY_MCST_LCC_VERSION_CHECK(1, 25, 10) +#define JSON_HEDLEY_PREDICT(expr, expected, probability) \ + (((probability) >= 0.9) \ + ? __builtin_expect((expr), (expected)) \ + : (JSON_HEDLEY_STATIC_CAST(void, expected), (expr))) +#define JSON_HEDLEY_PREDICT_TRUE(expr, probability) \ + (__extension__({ \ + double hedley_probability_ = (probability); \ + ((hedley_probability_ >= 0.9) \ + ? __builtin_expect(!!(expr), 1) \ + : ((hedley_probability_ <= 0.1) ? __builtin_expect(!!(expr), 0) \ + : !!(expr))); \ + })) +#define JSON_HEDLEY_PREDICT_FALSE(expr, probability) \ + (__extension__({ \ + double hedley_probability_ = (probability); \ + ((hedley_probability_ >= 0.9) \ + ? __builtin_expect(!!(expr), 0) \ + : ((hedley_probability_ <= 0.1) ? __builtin_expect(!!(expr), 1) \ + : !!(expr))); \ + })) +#define JSON_HEDLEY_LIKELY(expr) __builtin_expect(!!(expr), 1) +#define JSON_HEDLEY_UNLIKELY(expr) __builtin_expect(!!(expr), 0) +#else +#define JSON_HEDLEY_PREDICT(expr, expected, probability) \ + (JSON_HEDLEY_STATIC_CAST(void, expected), (expr)) +#define JSON_HEDLEY_PREDICT_TRUE(expr, probability) (!!(expr)) +#define JSON_HEDLEY_PREDICT_FALSE(expr, probability) (!!(expr)) +#define JSON_HEDLEY_LIKELY(expr) (!!(expr)) +#define JSON_HEDLEY_UNLIKELY(expr) (!!(expr)) +#endif +#if !defined(JSON_HEDLEY_UNPREDICTABLE) +#define JSON_HEDLEY_UNPREDICTABLE(expr) JSON_HEDLEY_PREDICT(expr, 1, 0.5) +#endif + +#if defined(JSON_HEDLEY_MALLOC) +#undef JSON_HEDLEY_MALLOC +#endif +#if JSON_HEDLEY_HAS_ATTRIBUTE(malloc) || \ + JSON_HEDLEY_GCC_VERSION_CHECK(3, 1, 0) || \ + JSON_HEDLEY_INTEL_VERSION_CHECK(13, 0, 0) || \ + JSON_HEDLEY_SUNPRO_VERSION_CHECK(5, 11, 0) || \ + JSON_HEDLEY_ARM_VERSION_CHECK(4, 1, 0) || \ + JSON_HEDLEY_IBM_VERSION_CHECK(12, 1, 0) || \ + JSON_HEDLEY_TI_VERSION_CHECK(15, 12, 0) || \ + (JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(4, 8, 0) && \ + defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(5, 2, 0) || \ + (JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6, 0, 0) && \ + defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6, 4, 0) || \ + (JSON_HEDLEY_TI_CL430_VERSION_CHECK(4, 0, 0) && \ + defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + JSON_HEDLEY_TI_CL430_VERSION_CHECK(4, 3, 0) || \ + (JSON_HEDLEY_TI_CL6X_VERSION_CHECK(7, 2, 0) && \ + defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + JSON_HEDLEY_TI_CL6X_VERSION_CHECK(7, 5, 0) || \ + JSON_HEDLEY_TI_CL7X_VERSION_CHECK(1, 2, 0) || \ + JSON_HEDLEY_TI_CLPRU_VERSION_CHECK(2, 1, 0) || \ + JSON_HEDLEY_MCST_LCC_VERSION_CHECK(1, 25, 10) +#define JSON_HEDLEY_MALLOC __attribute__((__malloc__)) +#elif JSON_HEDLEY_SUNPRO_VERSION_CHECK(5, 10, 0) +#define JSON_HEDLEY_MALLOC _Pragma("returns_new_memory") +#elif JSON_HEDLEY_MSVC_VERSION_CHECK(14, 0, 0) || \ + JSON_HEDLEY_INTEL_CL_VERSION_CHECK(2021, 1, 0) +#define JSON_HEDLEY_MALLOC __declspec(restrict) +#else +#define JSON_HEDLEY_MALLOC +#endif + +#if defined(JSON_HEDLEY_PURE) +#undef JSON_HEDLEY_PURE +#endif +#if JSON_HEDLEY_HAS_ATTRIBUTE(pure) || \ + JSON_HEDLEY_GCC_VERSION_CHECK(2, 96, 0) || \ + JSON_HEDLEY_INTEL_VERSION_CHECK(13, 0, 0) || \ + JSON_HEDLEY_SUNPRO_VERSION_CHECK(5, 11, 0) || \ + JSON_HEDLEY_ARM_VERSION_CHECK(4, 1, 0) || \ + JSON_HEDLEY_IBM_VERSION_CHECK(10, 1, 0) || \ + JSON_HEDLEY_TI_VERSION_CHECK(15, 12, 0) || \ + (JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(4, 8, 0) && \ + defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(5, 2, 0) || \ + (JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6, 0, 0) && \ + defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6, 4, 0) || \ + (JSON_HEDLEY_TI_CL430_VERSION_CHECK(4, 0, 0) && \ + defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + JSON_HEDLEY_TI_CL430_VERSION_CHECK(4, 3, 0) || \ + (JSON_HEDLEY_TI_CL6X_VERSION_CHECK(7, 2, 0) && \ + defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + JSON_HEDLEY_TI_CL6X_VERSION_CHECK(7, 5, 0) || \ + JSON_HEDLEY_TI_CL7X_VERSION_CHECK(1, 2, 0) || \ + JSON_HEDLEY_TI_CLPRU_VERSION_CHECK(2, 1, 0) || \ + JSON_HEDLEY_PGI_VERSION_CHECK(17, 10, 0) || \ + JSON_HEDLEY_MCST_LCC_VERSION_CHECK(1, 25, 10) +#define JSON_HEDLEY_PURE __attribute__((__pure__)) +#elif JSON_HEDLEY_SUNPRO_VERSION_CHECK(5, 10, 0) +#define JSON_HEDLEY_PURE _Pragma("does_not_write_global_data") +#elif defined(__cplusplus) && (JSON_HEDLEY_TI_CL430_VERSION_CHECK(2, 0, 1) || \ + JSON_HEDLEY_TI_CL6X_VERSION_CHECK(4, 0, 0) || \ + JSON_HEDLEY_TI_CL7X_VERSION_CHECK(1, 2, 0)) +#define JSON_HEDLEY_PURE _Pragma("FUNC_IS_PURE;") +#else +#define JSON_HEDLEY_PURE +#endif + +#if defined(JSON_HEDLEY_CONST) +#undef JSON_HEDLEY_CONST +#endif +#if JSON_HEDLEY_HAS_ATTRIBUTE(const) || \ + JSON_HEDLEY_GCC_VERSION_CHECK(2, 5, 0) || \ + JSON_HEDLEY_INTEL_VERSION_CHECK(13, 0, 0) || \ + JSON_HEDLEY_SUNPRO_VERSION_CHECK(5, 11, 0) || \ + JSON_HEDLEY_ARM_VERSION_CHECK(4, 1, 0) || \ + JSON_HEDLEY_IBM_VERSION_CHECK(10, 1, 0) || \ + JSON_HEDLEY_TI_VERSION_CHECK(15, 12, 0) || \ + (JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(4, 8, 0) && \ + defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(5, 2, 0) || \ + (JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6, 0, 0) && \ + defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6, 4, 0) || \ + (JSON_HEDLEY_TI_CL430_VERSION_CHECK(4, 0, 0) && \ + defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + JSON_HEDLEY_TI_CL430_VERSION_CHECK(4, 3, 0) || \ + (JSON_HEDLEY_TI_CL6X_VERSION_CHECK(7, 2, 0) && \ + defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + JSON_HEDLEY_TI_CL6X_VERSION_CHECK(7, 5, 0) || \ + JSON_HEDLEY_TI_CL7X_VERSION_CHECK(1, 2, 0) || \ + JSON_HEDLEY_TI_CLPRU_VERSION_CHECK(2, 1, 0) || \ + JSON_HEDLEY_PGI_VERSION_CHECK(17, 10, 0) || \ + JSON_HEDLEY_MCST_LCC_VERSION_CHECK(1, 25, 10) +#define JSON_HEDLEY_CONST __attribute__((__const__)) +#elif JSON_HEDLEY_SUNPRO_VERSION_CHECK(5, 10, 0) +#define JSON_HEDLEY_CONST _Pragma("no_side_effect") +#else +#define JSON_HEDLEY_CONST JSON_HEDLEY_PURE +#endif + +#if defined(JSON_HEDLEY_RESTRICT) +#undef JSON_HEDLEY_RESTRICT +#endif +#if defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) && \ + !defined(__cplusplus) +#define JSON_HEDLEY_RESTRICT restrict +#elif JSON_HEDLEY_GCC_VERSION_CHECK(3, 1, 0) || \ + JSON_HEDLEY_MSVC_VERSION_CHECK(14, 0, 0) || \ + JSON_HEDLEY_INTEL_VERSION_CHECK(13, 0, 0) || \ + JSON_HEDLEY_INTEL_CL_VERSION_CHECK(2021, 1, 0) || \ + JSON_HEDLEY_ARM_VERSION_CHECK(4, 1, 0) || \ + JSON_HEDLEY_IBM_VERSION_CHECK(10, 1, 0) || \ + JSON_HEDLEY_PGI_VERSION_CHECK(17, 10, 0) || \ + JSON_HEDLEY_TI_CL430_VERSION_CHECK(4, 3, 0) || \ + JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6, 2, 4) || \ + JSON_HEDLEY_TI_CL6X_VERSION_CHECK(8, 1, 0) || \ + JSON_HEDLEY_TI_CL7X_VERSION_CHECK(1, 2, 0) || \ + (JSON_HEDLEY_SUNPRO_VERSION_CHECK(5, 14, 0) && defined(__cplusplus)) || \ + JSON_HEDLEY_IAR_VERSION_CHECK(8, 0, 0) || defined(__clang__) || \ + JSON_HEDLEY_MCST_LCC_VERSION_CHECK(1, 25, 10) +#define JSON_HEDLEY_RESTRICT __restrict +#elif JSON_HEDLEY_SUNPRO_VERSION_CHECK(5, 3, 0) && !defined(__cplusplus) +#define JSON_HEDLEY_RESTRICT _Restrict +#else +#define JSON_HEDLEY_RESTRICT +#endif + +#if defined(JSON_HEDLEY_INLINE) +#undef JSON_HEDLEY_INLINE +#endif +#if (defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L)) || \ + (defined(__cplusplus) && (__cplusplus >= 199711L)) +#define JSON_HEDLEY_INLINE inline +#elif defined(JSON_HEDLEY_GCC_VERSION) || JSON_HEDLEY_ARM_VERSION_CHECK(6, 2, 0) +#define JSON_HEDLEY_INLINE __inline__ +#elif JSON_HEDLEY_MSVC_VERSION_CHECK(12, 0, 0) || \ + JSON_HEDLEY_INTEL_CL_VERSION_CHECK(2021, 1, 0) || \ + JSON_HEDLEY_ARM_VERSION_CHECK(4, 1, 0) || \ + JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(5, 1, 0) || \ + JSON_HEDLEY_TI_CL430_VERSION_CHECK(3, 1, 0) || \ + JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6, 2, 0) || \ + JSON_HEDLEY_TI_CL6X_VERSION_CHECK(8, 0, 0) || \ + JSON_HEDLEY_TI_CL7X_VERSION_CHECK(1, 2, 0) || \ + JSON_HEDLEY_TI_CLPRU_VERSION_CHECK(2, 1, 0) || \ + JSON_HEDLEY_MCST_LCC_VERSION_CHECK(1, 25, 10) +#define JSON_HEDLEY_INLINE __inline +#else +#define JSON_HEDLEY_INLINE +#endif + +#if defined(JSON_HEDLEY_ALWAYS_INLINE) +#undef JSON_HEDLEY_ALWAYS_INLINE +#endif +#if JSON_HEDLEY_HAS_ATTRIBUTE(always_inline) || \ + JSON_HEDLEY_GCC_VERSION_CHECK(4, 0, 0) || \ + JSON_HEDLEY_INTEL_VERSION_CHECK(13, 0, 0) || \ + JSON_HEDLEY_SUNPRO_VERSION_CHECK(5, 11, 0) || \ + JSON_HEDLEY_ARM_VERSION_CHECK(4, 1, 0) || \ + JSON_HEDLEY_IBM_VERSION_CHECK(10, 1, 0) || \ + JSON_HEDLEY_TI_VERSION_CHECK(15, 12, 0) || \ + (JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(4, 8, 0) && \ + defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(5, 2, 0) || \ + (JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6, 0, 0) && \ + defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6, 4, 0) || \ + (JSON_HEDLEY_TI_CL430_VERSION_CHECK(4, 0, 0) && \ + defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + JSON_HEDLEY_TI_CL430_VERSION_CHECK(4, 3, 0) || \ + (JSON_HEDLEY_TI_CL6X_VERSION_CHECK(7, 2, 0) && \ + defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + JSON_HEDLEY_TI_CL6X_VERSION_CHECK(7, 5, 0) || \ + JSON_HEDLEY_TI_CL7X_VERSION_CHECK(1, 2, 0) || \ + JSON_HEDLEY_TI_CLPRU_VERSION_CHECK(2, 1, 0) || \ + JSON_HEDLEY_MCST_LCC_VERSION_CHECK(1, 25, 10) || \ + JSON_HEDLEY_IAR_VERSION_CHECK(8, 10, 0) +#define JSON_HEDLEY_ALWAYS_INLINE \ + __attribute__((__always_inline__)) JSON_HEDLEY_INLINE +#elif JSON_HEDLEY_MSVC_VERSION_CHECK(12, 0, 0) || \ + JSON_HEDLEY_INTEL_CL_VERSION_CHECK(2021, 1, 0) +#define JSON_HEDLEY_ALWAYS_INLINE __forceinline +#elif defined(__cplusplus) && (JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(5, 2, 0) || \ + JSON_HEDLEY_TI_CL430_VERSION_CHECK(4, 3, 0) || \ + JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6, 4, 0) || \ + JSON_HEDLEY_TI_CL6X_VERSION_CHECK(6, 1, 0) || \ + JSON_HEDLEY_TI_CL7X_VERSION_CHECK(1, 2, 0) || \ + JSON_HEDLEY_TI_CLPRU_VERSION_CHECK(2, 1, 0)) +#define JSON_HEDLEY_ALWAYS_INLINE _Pragma("FUNC_ALWAYS_INLINE;") +#elif JSON_HEDLEY_IAR_VERSION_CHECK(8, 0, 0) +#define JSON_HEDLEY_ALWAYS_INLINE _Pragma("inline=forced") +#else +#define JSON_HEDLEY_ALWAYS_INLINE JSON_HEDLEY_INLINE +#endif + +#if defined(JSON_HEDLEY_NEVER_INLINE) +#undef JSON_HEDLEY_NEVER_INLINE +#endif +#if JSON_HEDLEY_HAS_ATTRIBUTE(noinline) || \ + JSON_HEDLEY_GCC_VERSION_CHECK(4, 0, 0) || \ + JSON_HEDLEY_INTEL_VERSION_CHECK(13, 0, 0) || \ + JSON_HEDLEY_SUNPRO_VERSION_CHECK(5, 11, 0) || \ + JSON_HEDLEY_ARM_VERSION_CHECK(4, 1, 0) || \ + JSON_HEDLEY_IBM_VERSION_CHECK(10, 1, 0) || \ + JSON_HEDLEY_TI_VERSION_CHECK(15, 12, 0) || \ + (JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(4, 8, 0) && \ + defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(5, 2, 0) || \ + (JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6, 0, 0) && \ + defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6, 4, 0) || \ + (JSON_HEDLEY_TI_CL430_VERSION_CHECK(4, 0, 0) && \ + defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + JSON_HEDLEY_TI_CL430_VERSION_CHECK(4, 3, 0) || \ + (JSON_HEDLEY_TI_CL6X_VERSION_CHECK(7, 2, 0) && \ + defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + JSON_HEDLEY_TI_CL6X_VERSION_CHECK(7, 5, 0) || \ + JSON_HEDLEY_TI_CL7X_VERSION_CHECK(1, 2, 0) || \ + JSON_HEDLEY_TI_CLPRU_VERSION_CHECK(2, 1, 0) || \ + JSON_HEDLEY_MCST_LCC_VERSION_CHECK(1, 25, 10) || \ + JSON_HEDLEY_IAR_VERSION_CHECK(8, 10, 0) +#define JSON_HEDLEY_NEVER_INLINE __attribute__((__noinline__)) +#elif JSON_HEDLEY_MSVC_VERSION_CHECK(13, 10, 0) || \ + JSON_HEDLEY_INTEL_CL_VERSION_CHECK(2021, 1, 0) +#define JSON_HEDLEY_NEVER_INLINE __declspec(noinline) +#elif JSON_HEDLEY_PGI_VERSION_CHECK(10, 2, 0) +#define JSON_HEDLEY_NEVER_INLINE _Pragma("noinline") +#elif JSON_HEDLEY_TI_CL6X_VERSION_CHECK(6, 0, 0) && defined(__cplusplus) +#define JSON_HEDLEY_NEVER_INLINE _Pragma("FUNC_CANNOT_INLINE;") +#elif JSON_HEDLEY_IAR_VERSION_CHECK(8, 0, 0) +#define JSON_HEDLEY_NEVER_INLINE _Pragma("inline=never") +#elif JSON_HEDLEY_COMPCERT_VERSION_CHECK(3, 2, 0) +#define JSON_HEDLEY_NEVER_INLINE __attribute((noinline)) +#elif JSON_HEDLEY_PELLES_VERSION_CHECK(9, 0, 0) +#define JSON_HEDLEY_NEVER_INLINE __declspec(noinline) +#else +#define JSON_HEDLEY_NEVER_INLINE +#endif + +#if defined(JSON_HEDLEY_PRIVATE) +#undef JSON_HEDLEY_PRIVATE +#endif +#if defined(JSON_HEDLEY_PUBLIC) +#undef JSON_HEDLEY_PUBLIC +#endif +#if defined(JSON_HEDLEY_IMPORT) +#undef JSON_HEDLEY_IMPORT +#endif +#if defined(_WIN32) || defined(__CYGWIN__) +#define JSON_HEDLEY_PRIVATE +#define JSON_HEDLEY_PUBLIC __declspec(dllexport) +#define JSON_HEDLEY_IMPORT __declspec(dllimport) +#else +#if JSON_HEDLEY_HAS_ATTRIBUTE(visibility) || \ + JSON_HEDLEY_GCC_VERSION_CHECK(3, 3, 0) || \ + JSON_HEDLEY_SUNPRO_VERSION_CHECK(5, 11, 0) || \ + JSON_HEDLEY_INTEL_VERSION_CHECK(13, 0, 0) || \ + JSON_HEDLEY_ARM_VERSION_CHECK(4, 1, 0) || \ + JSON_HEDLEY_IBM_VERSION_CHECK(13, 1, 0) || \ + (defined(__TI_EABI__) && ((JSON_HEDLEY_TI_CL6X_VERSION_CHECK(7, 2, 0) && \ + defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + JSON_HEDLEY_TI_CL6X_VERSION_CHECK(7, 5, 0))) || \ + JSON_HEDLEY_MCST_LCC_VERSION_CHECK(1, 25, 10) +#define JSON_HEDLEY_PRIVATE __attribute__((__visibility__("hidden"))) +#define JSON_HEDLEY_PUBLIC __attribute__((__visibility__("default"))) +#else +#define JSON_HEDLEY_PRIVATE +#define JSON_HEDLEY_PUBLIC +#endif +#define JSON_HEDLEY_IMPORT extern +#endif + +#if defined(JSON_HEDLEY_NO_THROW) +#undef JSON_HEDLEY_NO_THROW +#endif +#if JSON_HEDLEY_HAS_ATTRIBUTE(nothrow) || \ + JSON_HEDLEY_GCC_VERSION_CHECK(3, 3, 0) || \ + JSON_HEDLEY_INTEL_VERSION_CHECK(13, 0, 0) || \ + JSON_HEDLEY_MCST_LCC_VERSION_CHECK(1, 25, 10) +#define JSON_HEDLEY_NO_THROW __attribute__((__nothrow__)) +#elif JSON_HEDLEY_MSVC_VERSION_CHECK(13, 1, 0) || \ + JSON_HEDLEY_INTEL_CL_VERSION_CHECK(2021, 1, 0) || \ + JSON_HEDLEY_ARM_VERSION_CHECK(4, 1, 0) +#define JSON_HEDLEY_NO_THROW __declspec(nothrow) +#else +#define JSON_HEDLEY_NO_THROW +#endif + +#if defined(JSON_HEDLEY_FALL_THROUGH) +#undef JSON_HEDLEY_FALL_THROUGH +#endif +#if JSON_HEDLEY_HAS_ATTRIBUTE(fallthrough) || \ + JSON_HEDLEY_GCC_VERSION_CHECK(7, 0, 0) || \ + JSON_HEDLEY_MCST_LCC_VERSION_CHECK(1, 25, 10) +#define JSON_HEDLEY_FALL_THROUGH __attribute__((__fallthrough__)) +#elif JSON_HEDLEY_HAS_CPP_ATTRIBUTE_NS(clang, fallthrough) +#define JSON_HEDLEY_FALL_THROUGH \ + JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_([[clang::fallthrough]]) +#elif JSON_HEDLEY_HAS_CPP_ATTRIBUTE(fallthrough) +#define JSON_HEDLEY_FALL_THROUGH \ + JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_([[fallthrough]]) +#elif defined(__fallthrough) /* SAL */ +#define JSON_HEDLEY_FALL_THROUGH __fallthrough +#else +#define JSON_HEDLEY_FALL_THROUGH +#endif + +#if defined(JSON_HEDLEY_RETURNS_NON_NULL) +#undef JSON_HEDLEY_RETURNS_NON_NULL +#endif +#if JSON_HEDLEY_HAS_ATTRIBUTE(returns_nonnull) || \ + JSON_HEDLEY_GCC_VERSION_CHECK(4, 9, 0) || \ + JSON_HEDLEY_MCST_LCC_VERSION_CHECK(1, 25, 10) +#define JSON_HEDLEY_RETURNS_NON_NULL __attribute__((__returns_nonnull__)) +#elif defined(_Ret_notnull_) /* SAL */ +#define JSON_HEDLEY_RETURNS_NON_NULL _Ret_notnull_ +#else +#define JSON_HEDLEY_RETURNS_NON_NULL +#endif + +#if defined(JSON_HEDLEY_ARRAY_PARAM) +#undef JSON_HEDLEY_ARRAY_PARAM +#endif +#if defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) && \ + !defined(__STDC_NO_VLA__) && !defined(__cplusplus) && \ + !defined(JSON_HEDLEY_PGI_VERSION) && !defined(JSON_HEDLEY_TINYC_VERSION) +#define JSON_HEDLEY_ARRAY_PARAM(name) (name) +#else +#define JSON_HEDLEY_ARRAY_PARAM(name) +#endif + +#if defined(JSON_HEDLEY_IS_CONSTANT) +#undef JSON_HEDLEY_IS_CONSTANT +#endif +#if defined(JSON_HEDLEY_REQUIRE_CONSTEXPR) +#undef JSON_HEDLEY_REQUIRE_CONSTEXPR +#endif +/* JSON_HEDLEY_IS_CONSTEXPR_ is for + HEDLEY INTERNAL USE ONLY. API subject to change without notice. */ +#if defined(JSON_HEDLEY_IS_CONSTEXPR_) +#undef JSON_HEDLEY_IS_CONSTEXPR_ +#endif +#if JSON_HEDLEY_HAS_BUILTIN(__builtin_constant_p) || \ + JSON_HEDLEY_GCC_VERSION_CHECK(3, 4, 0) || \ + JSON_HEDLEY_INTEL_VERSION_CHECK(13, 0, 0) || \ + JSON_HEDLEY_TINYC_VERSION_CHECK(0, 9, 19) || \ + JSON_HEDLEY_ARM_VERSION_CHECK(4, 1, 0) || \ + JSON_HEDLEY_IBM_VERSION_CHECK(13, 1, 0) || \ + JSON_HEDLEY_TI_CL6X_VERSION_CHECK(6, 1, 0) || \ + (JSON_HEDLEY_SUNPRO_VERSION_CHECK(5, 10, 0) && !defined(__cplusplus)) || \ + JSON_HEDLEY_CRAY_VERSION_CHECK(8, 1, 0) || \ + JSON_HEDLEY_MCST_LCC_VERSION_CHECK(1, 25, 10) +#define JSON_HEDLEY_IS_CONSTANT(expr) __builtin_constant_p(expr) +#endif +#if !defined(__cplusplus) +#if JSON_HEDLEY_HAS_BUILTIN(__builtin_types_compatible_p) || \ + JSON_HEDLEY_GCC_VERSION_CHECK(3, 4, 0) || \ + JSON_HEDLEY_INTEL_VERSION_CHECK(13, 0, 0) || \ + JSON_HEDLEY_IBM_VERSION_CHECK(13, 1, 0) || \ + JSON_HEDLEY_CRAY_VERSION_CHECK(8, 1, 0) || \ + JSON_HEDLEY_ARM_VERSION_CHECK(5, 4, 0) || \ + JSON_HEDLEY_TINYC_VERSION_CHECK(0, 9, 24) +#if defined(__INTPTR_TYPE__) +#define JSON_HEDLEY_IS_CONSTEXPR_(expr) \ + __builtin_types_compatible_p( \ + __typeof__((1 ? (void *)((__INTPTR_TYPE__)((expr)*0)) : (int *)0)), \ + int *) +#else +#include +#define JSON_HEDLEY_IS_CONSTEXPR_(expr) \ + __builtin_types_compatible_p( \ + __typeof__((1 ? (void *)((intptr_t)((expr)*0)) : (int *)0)), \ + int *) +#endif +#elif (defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 201112L) && \ + !defined(JSON_HEDLEY_SUNPRO_VERSION) && \ + !defined(JSON_HEDLEY_PGI_VERSION) && \ + !defined(JSON_HEDLEY_IAR_VERSION)) || \ + (JSON_HEDLEY_HAS_EXTENSION(c_generic_selections) && \ + !defined(JSON_HEDLEY_IAR_VERSION)) || \ + JSON_HEDLEY_GCC_VERSION_CHECK(4, 9, 0) || \ + JSON_HEDLEY_INTEL_VERSION_CHECK(17, 0, 0) || \ + JSON_HEDLEY_IBM_VERSION_CHECK(12, 1, 0) || \ + JSON_HEDLEY_ARM_VERSION_CHECK(5, 3, 0) +#if defined(__INTPTR_TYPE__) +#define JSON_HEDLEY_IS_CONSTEXPR_(expr) \ + _Generic((1 ? (void *)((__INTPTR_TYPE__)((expr)*0)) : (int *)0), \ + int * : 1, \ + void * : 0) +#else +#include +#define JSON_HEDLEY_IS_CONSTEXPR_(expr) \ + _Generic((1 ? (void *)((intptr_t)*0) : (int *)0), int * : 1, void * : 0) +#endif +#elif defined(JSON_HEDLEY_GCC_VERSION) || \ + defined(JSON_HEDLEY_INTEL_VERSION) || \ + defined(JSON_HEDLEY_TINYC_VERSION) || \ + defined(JSON_HEDLEY_TI_ARMCL_VERSION) || \ + JSON_HEDLEY_TI_CL430_VERSION_CHECK(18, 12, 0) || \ + defined(JSON_HEDLEY_TI_CL2000_VERSION) || \ + defined(JSON_HEDLEY_TI_CL6X_VERSION) || \ + defined(JSON_HEDLEY_TI_CL7X_VERSION) || \ + defined(JSON_HEDLEY_TI_CLPRU_VERSION) || defined(__clang__) +#define JSON_HEDLEY_IS_CONSTEXPR_(expr) \ + (sizeof(void) != sizeof(*(1 ? ((void *)((expr)*0L)) : ((struct { \ + char v[sizeof(void) * 2]; \ + } *)1)))) +#endif +#endif +#if defined(JSON_HEDLEY_IS_CONSTEXPR_) +#if !defined(JSON_HEDLEY_IS_CONSTANT) +#define JSON_HEDLEY_IS_CONSTANT(expr) JSON_HEDLEY_IS_CONSTEXPR_(expr) +#endif +#define JSON_HEDLEY_REQUIRE_CONSTEXPR(expr) \ + (JSON_HEDLEY_IS_CONSTEXPR_(expr) ? (expr) : (-1)) +#else +#if !defined(JSON_HEDLEY_IS_CONSTANT) +#define JSON_HEDLEY_IS_CONSTANT(expr) (0) +#endif +#define JSON_HEDLEY_REQUIRE_CONSTEXPR(expr) (expr) +#endif + +#if defined(JSON_HEDLEY_BEGIN_C_DECLS) +#undef JSON_HEDLEY_BEGIN_C_DECLS +#endif +#if defined(JSON_HEDLEY_END_C_DECLS) +#undef JSON_HEDLEY_END_C_DECLS +#endif +#if defined(JSON_HEDLEY_C_DECL) +#undef JSON_HEDLEY_C_DECL +#endif +#if defined(__cplusplus) +#define JSON_HEDLEY_BEGIN_C_DECLS extern "C" { +#define JSON_HEDLEY_END_C_DECLS } +#define JSON_HEDLEY_C_DECL extern "C" +#else +#define JSON_HEDLEY_BEGIN_C_DECLS +#define JSON_HEDLEY_END_C_DECLS +#define JSON_HEDLEY_C_DECL +#endif + +#if defined(JSON_HEDLEY_STATIC_ASSERT) +#undef JSON_HEDLEY_STATIC_ASSERT +#endif +#if !defined(__cplusplus) && \ + ((defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 201112L)) || \ + (JSON_HEDLEY_HAS_FEATURE(c_static_assert) && \ + !defined(JSON_HEDLEY_INTEL_CL_VERSION)) || \ + JSON_HEDLEY_GCC_VERSION_CHECK(6, 0, 0) || \ + JSON_HEDLEY_INTEL_VERSION_CHECK(13, 0, 0) || defined(_Static_assert)) +#define JSON_HEDLEY_STATIC_ASSERT(expr, message) _Static_assert(expr, message) +#elif (defined(__cplusplus) && (__cplusplus >= 201103L)) || \ + JSON_HEDLEY_MSVC_VERSION_CHECK(16, 0, 0) || \ + JSON_HEDLEY_INTEL_CL_VERSION_CHECK(2021, 1, 0) +#define JSON_HEDLEY_STATIC_ASSERT(expr, message) \ + JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_( \ + static_assert(expr, message)) +#else +#define JSON_HEDLEY_STATIC_ASSERT(expr, message) +#endif + +#if defined(JSON_HEDLEY_NULL) +#undef JSON_HEDLEY_NULL +#endif +#if defined(__cplusplus) +#if __cplusplus >= 201103L +#define JSON_HEDLEY_NULL \ + JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_(nullptr) +#elif defined(NULL) +#define JSON_HEDLEY_NULL NULL +#else +#define JSON_HEDLEY_NULL JSON_HEDLEY_STATIC_CAST(void *, 0) +#endif +#elif defined(NULL) +#define JSON_HEDLEY_NULL NULL +#else +#define JSON_HEDLEY_NULL ((void *)0) +#endif + +#if defined(JSON_HEDLEY_MESSAGE) +#undef JSON_HEDLEY_MESSAGE +#endif +#if JSON_HEDLEY_HAS_WARNING("-Wunknown-pragmas") +#define JSON_HEDLEY_MESSAGE(msg) \ + JSON_HEDLEY_DIAGNOSTIC_PUSH \ + JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS \ + JSON_HEDLEY_PRAGMA(message msg) \ + JSON_HEDLEY_DIAGNOSTIC_POP +#elif JSON_HEDLEY_GCC_VERSION_CHECK(4, 4, 0) || \ + JSON_HEDLEY_INTEL_VERSION_CHECK(13, 0, 0) +#define JSON_HEDLEY_MESSAGE(msg) JSON_HEDLEY_PRAGMA(message msg) +#elif JSON_HEDLEY_CRAY_VERSION_CHECK(5, 0, 0) +#define JSON_HEDLEY_MESSAGE(msg) JSON_HEDLEY_PRAGMA(_CRI message msg) +#elif JSON_HEDLEY_IAR_VERSION_CHECK(8, 0, 0) +#define JSON_HEDLEY_MESSAGE(msg) JSON_HEDLEY_PRAGMA(message(msg)) +#elif JSON_HEDLEY_PELLES_VERSION_CHECK(2, 0, 0) +#define JSON_HEDLEY_MESSAGE(msg) JSON_HEDLEY_PRAGMA(message(msg)) +#else +#define JSON_HEDLEY_MESSAGE(msg) +#endif + +#if defined(JSON_HEDLEY_WARNING) +#undef JSON_HEDLEY_WARNING +#endif +#if JSON_HEDLEY_HAS_WARNING("-Wunknown-pragmas") +#define JSON_HEDLEY_WARNING(msg) \ + JSON_HEDLEY_DIAGNOSTIC_PUSH \ + JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS \ + JSON_HEDLEY_PRAGMA(clang warning msg) \ + JSON_HEDLEY_DIAGNOSTIC_POP +#elif JSON_HEDLEY_GCC_VERSION_CHECK(4, 8, 0) || \ + JSON_HEDLEY_PGI_VERSION_CHECK(18, 4, 0) || \ + JSON_HEDLEY_INTEL_VERSION_CHECK(13, 0, 0) +#define JSON_HEDLEY_WARNING(msg) JSON_HEDLEY_PRAGMA(GCC warning msg) +#elif JSON_HEDLEY_MSVC_VERSION_CHECK(15, 0, 0) || \ + JSON_HEDLEY_INTEL_CL_VERSION_CHECK(2021, 1, 0) +#define JSON_HEDLEY_WARNING(msg) JSON_HEDLEY_PRAGMA(message(msg)) +#else +#define JSON_HEDLEY_WARNING(msg) JSON_HEDLEY_MESSAGE(msg) +#endif + +#if defined(JSON_HEDLEY_REQUIRE) +#undef JSON_HEDLEY_REQUIRE +#endif +#if defined(JSON_HEDLEY_REQUIRE_MSG) +#undef JSON_HEDLEY_REQUIRE_MSG +#endif +#if JSON_HEDLEY_HAS_ATTRIBUTE(diagnose_if) +#if JSON_HEDLEY_HAS_WARNING("-Wgcc-compat") +#define JSON_HEDLEY_REQUIRE(expr) \ + JSON_HEDLEY_DIAGNOSTIC_PUSH \ + _Pragma("clang diagnostic ignored \"-Wgcc-compat\"") \ + __attribute__((diagnose_if(!(expr), #expr, "error"))) \ + JSON_HEDLEY_DIAGNOSTIC_POP +#define JSON_HEDLEY_REQUIRE_MSG(expr, msg) \ + JSON_HEDLEY_DIAGNOSTIC_PUSH \ + _Pragma("clang diagnostic ignored \"-Wgcc-compat\"") \ + __attribute__((diagnose_if(!(expr), msg, "error"))) \ + JSON_HEDLEY_DIAGNOSTIC_POP +#else +#define JSON_HEDLEY_REQUIRE(expr) \ + __attribute__((diagnose_if(!(expr), #expr, "error"))) +#define JSON_HEDLEY_REQUIRE_MSG(expr, msg) \ + __attribute__((diagnose_if(!(expr), msg, "error"))) +#endif +#else +#define JSON_HEDLEY_REQUIRE(expr) +#define JSON_HEDLEY_REQUIRE_MSG(expr, msg) +#endif + +#if defined(JSON_HEDLEY_FLAGS) +#undef JSON_HEDLEY_FLAGS +#endif +#if JSON_HEDLEY_HAS_ATTRIBUTE(flag_enum) && \ + (!defined(__cplusplus) || \ + JSON_HEDLEY_HAS_WARNING("-Wbitfield-enum-conversion")) +#define JSON_HEDLEY_FLAGS __attribute__((__flag_enum__)) +#else +#define JSON_HEDLEY_FLAGS +#endif + +#if defined(JSON_HEDLEY_FLAGS_CAST) +#undef JSON_HEDLEY_FLAGS_CAST +#endif +#if JSON_HEDLEY_INTEL_VERSION_CHECK(19, 0, 0) +#define JSON_HEDLEY_FLAGS_CAST(T, expr) \ + (__extension__({ \ + JSON_HEDLEY_DIAGNOSTIC_PUSH \ + _Pragma("warning(disable:188)")((T)(expr)); \ + JSON_HEDLEY_DIAGNOSTIC_POP \ + })) +#else +#define JSON_HEDLEY_FLAGS_CAST(T, expr) JSON_HEDLEY_STATIC_CAST(T, expr) +#endif + +#if defined(JSON_HEDLEY_EMPTY_BASES) +#undef JSON_HEDLEY_EMPTY_BASES +#endif +#if (JSON_HEDLEY_MSVC_VERSION_CHECK(19, 0, 23918) && \ + !JSON_HEDLEY_MSVC_VERSION_CHECK(20, 0, 0)) || \ + JSON_HEDLEY_INTEL_CL_VERSION_CHECK(2021, 1, 0) +#define JSON_HEDLEY_EMPTY_BASES __declspec(empty_bases) +#else +#define JSON_HEDLEY_EMPTY_BASES +#endif + +/* Remaining macros are deprecated. */ + +#if defined(JSON_HEDLEY_GCC_NOT_CLANG_VERSION_CHECK) +#undef JSON_HEDLEY_GCC_NOT_CLANG_VERSION_CHECK +#endif +#if defined(__clang__) +#define JSON_HEDLEY_GCC_NOT_CLANG_VERSION_CHECK(major, minor, patch) (0) +#else +#define JSON_HEDLEY_GCC_NOT_CLANG_VERSION_CHECK(major, minor, patch) \ + JSON_HEDLEY_GCC_VERSION_CHECK(major, minor, patch) +#endif + +#if defined(JSON_HEDLEY_CLANG_HAS_ATTRIBUTE) +#undef JSON_HEDLEY_CLANG_HAS_ATTRIBUTE +#endif +#define JSON_HEDLEY_CLANG_HAS_ATTRIBUTE(attribute) \ + JSON_HEDLEY_HAS_ATTRIBUTE(attribute) + +#if defined(JSON_HEDLEY_CLANG_HAS_CPP_ATTRIBUTE) +#undef JSON_HEDLEY_CLANG_HAS_CPP_ATTRIBUTE +#endif +#define JSON_HEDLEY_CLANG_HAS_CPP_ATTRIBUTE(attribute) \ + JSON_HEDLEY_HAS_CPP_ATTRIBUTE(attribute) + +#if defined(JSON_HEDLEY_CLANG_HAS_BUILTIN) +#undef JSON_HEDLEY_CLANG_HAS_BUILTIN +#endif +#define JSON_HEDLEY_CLANG_HAS_BUILTIN(builtin) JSON_HEDLEY_HAS_BUILTIN(builtin) + +#if defined(JSON_HEDLEY_CLANG_HAS_FEATURE) +#undef JSON_HEDLEY_CLANG_HAS_FEATURE +#endif +#define JSON_HEDLEY_CLANG_HAS_FEATURE(feature) JSON_HEDLEY_HAS_FEATURE(feature) + +#if defined(JSON_HEDLEY_CLANG_HAS_EXTENSION) +#undef JSON_HEDLEY_CLANG_HAS_EXTENSION +#endif +#define JSON_HEDLEY_CLANG_HAS_EXTENSION(extension) \ + JSON_HEDLEY_HAS_EXTENSION(extension) + +#if defined(JSON_HEDLEY_CLANG_HAS_DECLSPEC_DECLSPEC_ATTRIBUTE) +#undef JSON_HEDLEY_CLANG_HAS_DECLSPEC_DECLSPEC_ATTRIBUTE +#endif +#define JSON_HEDLEY_CLANG_HAS_DECLSPEC_ATTRIBUTE(attribute) \ + JSON_HEDLEY_HAS_DECLSPEC_ATTRIBUTE(attribute) + +#if defined(JSON_HEDLEY_CLANG_HAS_WARNING) +#undef JSON_HEDLEY_CLANG_HAS_WARNING +#endif +#define JSON_HEDLEY_CLANG_HAS_WARNING(warning) JSON_HEDLEY_HAS_WARNING(warning) + +#endif /* !defined(JSON_HEDLEY_VERSION) || (JSON_HEDLEY_VERSION < X) */ + +// #include + + +#include + +// #include + + +namespace nlohmann +{ +namespace detail +{ +template struct make_void { + using type = void; +}; +template using void_t = typename make_void::type; +} // namespace detail +} // namespace nlohmann + + +// https://en.cppreference.com/w/cpp/experimental/is_detected +namespace nlohmann +{ +namespace detail +{ +struct nonesuch { + nonesuch() = delete; + ~nonesuch() = delete; + nonesuch(nonesuch const &) = delete; + nonesuch(nonesuch const &&) = delete; + void operator=(nonesuch const &) = delete; + void operator=(nonesuch &&) = delete; +}; + +template + class Op, + class... Args> +struct detector { + using value_t = std::false_type; + using type = Default; +}; + +template class Op, class... Args> +struct detector>, Op, Args...> { + using value_t = std::true_type; + using type = Op; +}; + +template