diff --git a/.github/instructions/ngmp.instructions.md b/.github/instructions/ngmp.instructions.md new file mode 100644 index 00000000000..81fd357ad23 --- /dev/null +++ b/.github/instructions/ngmp.instructions.md @@ -0,0 +1,70 @@ +--- +applyTo: '**/GeneralsOnline/**,**/NextGenMP/**' +--- + +# NGMP Subsystem Implementation Instructions + +These instructions govern the Next-Gen Multiplayer (NGMP) client protocol integration into **GeneralsX**. All changes in `GeneralsOnline` and `NextGenMP` components must adhere strictly to these guidelines. + +> [!IMPORTANT] +> **GameSpy Online is being discontinued.** NGMP is the sole multiplayer backend going forward. Compatibility with the legacy GameSpy online flow is **NOT a goal** and must NOT block NGMP development. If making NGMP work requires changing or breaking legacy GameSpy online code paths, that is acceptable and expected. Only the following non-online modes must remain fully functional: **Singleplayer campaigns**, **Skirmish vs AI**, and **LAN multiplayer**. + +--- + +## GameSpy Compatibility Policy + +| Mode | Required to keep working | Notes | +|---|---|---| +| Singleplayer / Campaign | ✅ Yes | Must not regress | +| Skirmish (vs AI, offline) | ✅ Yes | Must not regress | +| LAN Multiplayer | ✅ Yes | Must not regress | +| GameSpy Online (WOL) | ❌ No | Being discontinued; may be broken by NGMP changes | +| GameSpy P2P auth/serial | ❌ No | Superseded by NGMP auth | + +When a piece of legacy UI code is in the critical path for NGMP but also serves the legacy GameSpy online flow: +- **Modify it** to work correctly with NGMP, even if that removes or changes the GameSpy online behavior. +- If a function or callback is **only** called in the GameSpy online context (never touched in singleplayer, skirmish, or LAN), it may be stubbed out, simplified, or removed to unblock NGMP work. +- Prefer **replacing** legacy `TheGameSpy*` queue calls with equivalent NGMP interface calls rather than maintaining both paths in parallel. +- Dummy/blackhole implementations (like dummy message queues) are a **last resort** workaround — prefer proper NGMP replacements whenever feasible. + +--- + +## Golden Constraints + +1. **Strict Prohibition of `` & Win32 APIs**: + - Never include ``, ``, ``, ``, or `` in NGMP sources. + - Use standard C++ (``, ``, ``), POSIX networking (``, ``, ``), or SDL3 primitives (`SDL_GetTicks()`, `SDL_Delay()`, `SDL_GetPrefPath()`). + +2. **Platform Layer Isolation**: + - Low-level network socket and OS calls must reside exclusively in `Core/GameEngineDevice/`. + - Higher-level network logic under `GeneralsMD/Code/GameEngine/Source/GameNetwork/GeneralsOnline/` must use pure abstract interfaces and cross-platform abstractions. + +3. **Thread Safety & UI Main Thread Separation**: + - Network callbacks from HTTP/WebSocket/P2P threads **MUST NOT** directly access or mutate UI controls (`GameWindow`, `WOLLobbyMenu`, etc.). + - Network events must be posted to a thread-safe thread/FIFO queue, consumed strictly on the main render thread during `Shell::update()`. + +4. **Credential & Token Storage**: + - Do NOT use Windows Credential Manager. + - Save session JWT tokens in an obfuscated local configuration file under the directory provided by `SDL_GetPrefPath("GeneralsX", "GeneralsOnline")`. + +5. **Server Endpoint Environment**: + - Development backend server target: `ws://192.168.1.120:9001/ws` (WebSocket) and `http://192.168.1.120:9001/api` (REST). + - Server URLs must be configurable via INI/JSON config rather than hardcoded string literals. + +6. **Cross-Platform Math & Endianness**: + - Ensure network packet data serialization handles network byte order (`htons`/`ntohs`, `htonl`/`ntohl`) explicitly to support cross-play between x86_64 Linux and ARM64 macOS. + +7. **Reference repositories**: + - There are two reference repositories for NGMP, take a look on these to understand the protocol and implementation details: + 1. `references/GameClient`: The client-side implementation. + 2. `references/GameServer`: The server-side implementation. + +8. **REST API & Routing Conventions (Lessons Learned)**: + - **Environment/Contract Prefix**: The C# Kestrel backend strictly requires environment and contract version routing. Do **NOT** use `GetServerRESTEndpoint()` directly to build URLs. Always use `NGMP::GetAPIEndpoint("EndpointName")` (e.g. `NGMP::GetAPIEndpoint("Lobbies")`), which appends the required `/env/dev/contract/1/` prefix automatically. + - **Authorization**: Almost all endpoints require authorization. You must inject the `Authorization: Bearer ` HTTP header in all requests (GET, POST, PUT, DELETE). Missing this will result in a `401 Unauthorized` response. + - **HTTP Methods & Payloads**: Backend endpoints have strict method bindings (`[HttpGet]`, `[HttpPut]`, `[HttpPost]`). For example, creating a lobby requires `PUT /Lobbies`, while joining a lobby requires `PUT /Lobby/{id}`. The JSON payloads must also contain all expected fields (even if default or empty), or the server will reject the request with `400 Bad Request`. + +9. **WebSocket Protocol Conventions (Lessons Learned)**: + - **Message ID Routing**: The backend `WebSocketController` strictly uses integer `msg_id` values to route actions, NOT string action types (e.g., `msg_id: 1` for sending chat, `msg_id: 2` for receiving chat, `msg_id: 4` for member list updates). Always include the correct `msg_id` in sent JSON payloads and use it to parse incoming messages. + - **Network Rooms (Lobby Registration)**: The backend requires the client to explicitly register into a network room to receive lobby and player updates. When initializing the global lobby chat, you must send `{"msg_id": 3, "room": 0}` (NETWORK_ROOM_CHANGE_ROOM). If you fail to do this, the server considers you in room `-1`, which causes the HTTP `GET /Lobbies` endpoint to return `0 lobbies` (as it filters by your current room) and prevents you from receiving player list updates (`msg_id: 4`). + - **Heartbeats**: The WebSocket server automatically drops connections if a PING is not received within a timeout window (often 20s). The client must periodically send `{"msg_id": 8}` (ping) at least every 10 seconds to keep the socket alive. diff --git a/.github/workflows/build-linux-flatpak.yml b/.github/workflows/build-linux-flatpak.yml index 4b69428476f..d08444cf522 100644 --- a/.github/workflows/build-linux-flatpak.yml +++ b/.github/workflows/build-linux-flatpak.yml @@ -85,10 +85,17 @@ jobs: flatpak-builder-${{ runner.os }}-${{ inputs.preset }}- - name: Build Flatpak Bundle + env: + NGMP_DEFAULT_HOST: ${{ secrets.NGMP_DEFAULT_HOST }} + NGMP_SERVER_HOST: ${{ secrets.NGMP_DEFAULT_HOST }} + NGMP_SERVER_PORT: ${{ secrets.NGMP_SERVER_PORT }} + NGMP_USE_SSL: ${{ secrets.NGMP_USE_SSL }} + NGMP_WEB_PORTAL_URL: ${{ secrets.NGMP_WEB_PORTAL_URL }} + NGMP_MOTD_URL: ${{ secrets.NGMP_MOTD_URL }} run: | set -o pipefail mkdir -p logs - ./scripts/build/linux/build-linux-flatpak.sh "${{ inputs.preset }}" "${{ matrix.game.value }}" 2>&1 | tee "logs/build_flatpak_${{ matrix.game.log_suffix }}.log" + bash ./scripts/build/linux/build-linux-flatpak.sh "${{ inputs.preset }}" "${{ matrix.game.value }}" 2>&1 | tee "logs/build_flatpak_${{ matrix.game.log_suffix }}.log" - name: Locate generated Flatpak bundle id: bundle diff --git a/.github/workflows/build-linux.yml b/.github/workflows/build-linux.yml index 7304d4a20ce..620931cd4b1 100644 --- a/.github/workflows/build-linux.yml +++ b/.github/workflows/build-linux.yml @@ -159,6 +159,13 @@ jobs: echo "✅ vcpkg ready at: /opt/vcpkg" - name: Configure CMake (Linux) + env: + NGMP_DEFAULT_HOST: ${{ secrets.NGMP_DEFAULT_HOST }} + NGMP_SERVER_HOST: ${{ secrets.NGMP_DEFAULT_HOST }} + NGMP_SERVER_PORT: ${{ secrets.NGMP_SERVER_PORT }} + NGMP_USE_SSL: ${{ secrets.NGMP_USE_SSL }} + NGMP_WEB_PORTAL_URL: ${{ secrets.NGMP_WEB_PORTAL_URL }} + NGMP_MOTD_URL: ${{ secrets.NGMP_MOTD_URL }} run: | mkdir -p logs cmake --preset ${{ inputs.preset }} 2>&1 | tee logs/configure_linux.log diff --git a/.github/workflows/build-macos.yml b/.github/workflows/build-macos.yml index e1dfe0e842b..e671792d351 100644 --- a/.github/workflows/build-macos.yml +++ b/.github/workflows/build-macos.yml @@ -113,6 +113,9 @@ jobs: # Freetype + Fontconfig (required by font rendering) brew install freetype fontconfig + + # Protobuf, Abseil & OpenSSL (required by GameNetworkingSockets / NGMP P2P transport) + brew install protobuf abseil openssl@3 # NOTE: GLM is intentionally NOT installed via Homebrew. # It is fetched via CMake FetchContent in cmake/glm.cmake (tag 1.0.3). @@ -356,6 +359,12 @@ jobs: CXX: clang++ CMAKE_C_COMPILER_LAUNCHER: ccache CMAKE_CXX_COMPILER_LAUNCHER: ccache + NGMP_DEFAULT_HOST: ${{ secrets.NGMP_DEFAULT_HOST }} + NGMP_SERVER_HOST: ${{ secrets.NGMP_DEFAULT_HOST }} + NGMP_SERVER_PORT: ${{ secrets.NGMP_SERVER_PORT }} + NGMP_USE_SSL: ${{ secrets.NGMP_USE_SSL }} + NGMP_WEB_PORTAL_URL: ${{ secrets.NGMP_WEB_PORTAL_URL }} + NGMP_MOTD_URL: ${{ secrets.NGMP_MOTD_URL }} run: | mkdir -p logs echo "VULKAN_SDK=$VULKAN_SDK" diff --git a/.github/workflows/build-windows.yml b/.github/workflows/build-windows.yml index cd42690ac70..5fdff803a8a 100644 --- a/.github/workflows/build-windows.yml +++ b/.github/workflows/build-windows.yml @@ -62,7 +62,7 @@ jobs: uses: actions/cache/restore@v4 with: path: ${{ github.workspace }}/vcpkg-bincache - key: vcpkg-bincache-${{ runner.os }}-x86-${{ hashFiles('vcpkg.json', 'vcpkg-lock.json') }} + key: vcpkg-bincache-${{ runner.os }}-x86-${{ hashFiles('vcpkg.json', 'vcpkg-lock.json', 'cmake/ports/**') }} restore-keys: | vcpkg-bincache-${{ runner.os }}-x86- @@ -73,14 +73,23 @@ jobs: New-Item -ItemType Directory -Force -Path $cacheDir | Out-Null "VCPKG_DEFAULT_BINARY_CACHE=$cacheDir" >> $env:GITHUB_ENV "VCPKG_BINARY_SOURCES=clear;files,$cacheDir,readwrite" >> $env:GITHUB_ENV - "VCPKG_OVERLAY_TRIPLETS=${{ github.workspace }}/triplets" >> $env:GITHUB_ENV + "VCPKG_OVERLAY_TRIPLETS=${{ github.workspace }}/cmake/triplets" >> $env:GITHUB_ENV + "VCPKG_OVERLAY_PORTS=${{ github.workspace }}/cmake/ports" >> $env:GITHUB_ENV "VCPKG_INSTALL_OPTIONS=--x-abi-tools-use-exact-versions" >> $env:GITHUB_ENV - name: Configure shell: pwsh + env: + NGMP_DEFAULT_HOST: ${{ secrets.NGMP_DEFAULT_HOST }} + NGMP_SERVER_HOST: ${{ secrets.NGMP_DEFAULT_HOST }} + NGMP_SERVER_PORT: ${{ secrets.NGMP_SERVER_PORT }} + NGMP_USE_SSL: ${{ secrets.NGMP_USE_SSL }} + NGMP_WEB_PORTAL_URL: ${{ secrets.NGMP_WEB_PORTAL_URL }} + NGMP_MOTD_URL: ${{ secrets.NGMP_MOTD_URL }} run: | $env:VCPKG_ROOT = $env:VCPKG_INSTALLATION_ROOT cmake --preset win32-vcpkg ` + -DVCPKG_OVERLAY_PORTS="${{ github.workspace }}/cmake/ports" ` -DRTS_BUILD_GENERALS=${{ matrix.game.build_generals }} ` -DRTS_BUILD_ZEROHOUR=${{ matrix.game.build_zh }} ` -DRTS_BUILD_CORE_TOOLS=OFF ` @@ -95,7 +104,7 @@ jobs: uses: actions/cache/save@v4 with: path: ${{ github.workspace }}/vcpkg-bincache - key: ${{ steps.vcpkg_cache.outputs.cache-primary-key || format('vcpkg-bincache-{0}-x86-{1}', runner.os, hashFiles('vcpkg.json', 'vcpkg-lock.json')) }} + key: ${{ steps.vcpkg_cache.outputs.cache-primary-key || format('vcpkg-bincache-{0}-x86-{1}', runner.os, hashFiles('vcpkg.json', 'vcpkg-lock.json', 'cmake/ports/**')) }} - name: Build shell: pwsh @@ -108,9 +117,26 @@ jobs: New-Item -ItemType Directory -Force ci-artifacts | Out-Null Copy-Item build/win32-vcpkg/${{ matrix.game.folder }}/Release/${{ matrix.game.exe }} artifacts/ Copy-Item build/win32-vcpkg/${{ matrix.game.folder }}/Release/${{ matrix.game.pdb }} artifacts/ - Copy-Item build/win32-vcpkg/vcpkg_installed/x86-windows/bin/zlib1.dll artifacts/ Copy-Item build/win32-vcpkg/${{ matrix.game.folder }}/Release/${{ matrix.game.exe }} ci-artifacts/ - Copy-Item build/win32-vcpkg/vcpkg_installed/x86-windows/bin/zlib1.dll ci-artifacts/ + + Get-ChildItem -Path @("vcpkg_installed/x86-windows/bin/*.dll", "build/win32-vcpkg/vcpkg_installed/x86-windows/bin/*.dll") -ErrorAction SilentlyContinue | ForEach-Object { + Write-Host "Collecting vcpkg DLL: $($_.FullName)" + Copy-Item $_.FullName artifacts/ + Copy-Item $_.FullName ci-artifacts/ + } + + # Collect Desktop Release CRT DLLs (msvcp140.dll, vcruntime140.dll, etc.) + $vcReleaseDir = Get-ChildItem "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Redist\MSVC" -Directory -Recurse | + Where-Object { $_.FullName -match "\\x86\\" -and $_.FullName -match "Microsoft\.VC143\.CRT$" -and $_.FullName -notmatch "onecore" } | + Select-Object -First 1 + + if ($vcReleaseDir) { + Get-ChildItem -Path (Join-Path $vcReleaseDir.FullName "*.dll") | ForEach-Object { + Write-Host "Collecting Desktop Release CRT DLL: $($_.FullName)" + Copy-Item $_.FullName artifacts/ + Copy-Item $_.FullName ci-artifacts/ + } + } foreach ($name in @("binkw32.dll", "mss32.dll")) { $stub = Get-ChildItem build/win32-vcpkg -Filter $name -Recurse | diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index a42915009aa..c6d05d5779d 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -70,6 +70,7 @@ jobs: with: preset: linux64-deploy checkout_ref: refs/tags/${{ inputs.release_version }} + secrets: inherit build-macos: needs: [create-tag] @@ -77,12 +78,14 @@ jobs: with: preset: macos-vulkan checkout_ref: refs/tags/${{ inputs.release_version }} + secrets: inherit build-windows: needs: [create-tag] uses: ./.github/workflows/build-windows.yml with: checkout_ref: refs/tags/${{ inputs.release_version }} + secrets: inherit # GeneralsX @build BenderAI 21/04/2026 Roll back the pushed tag when anything # downstream of create-tag fails, so a re-run with the same version is possible. diff --git a/.github/workflows/replay-tests-windows.yml b/.github/workflows/replay-tests-windows.yml index 0942ff489af..63c561245e7 100644 --- a/.github/workflows/replay-tests-windows.yml +++ b/.github/workflows/replay-tests-windows.yml @@ -252,6 +252,10 @@ jobs: $output += $stderrOutput $output += $stdoutOutput $output | ForEach-Object { Write-Host $_ } + if (!$timedOut -and $exitCode -is [int] -and $exitCode -ne 0 -and $output.Count -eq 0) { + $hexCode = "0x" + ([int64]$exitCode -band 0xFFFFFFFF).ToString("X8") + Write-Host "Process exited with code $exitCode ($hexCode) and produced no output" + } $source = if ($replay.Name.StartsWith("linux_")) { "Linux" } elseif ($replay.Name.StartsWith("macos_")) { "macOS" } else { "other" } $completionLines = @($stdoutOutput | diff --git a/.gitignore b/.gitignore index 20fa1e0d6fb..d0d75e17385 100644 --- a/.gitignore +++ b/.gitignore @@ -91,5 +91,6 @@ flatpak/*.flatpak #tmp and log files on root folder logs_*.zip *.log +/cmake/ngmp_env.cmake references/GameClient/ references/GameServer/ diff --git a/.gitmodules b/.gitmodules index e0ad1191453..de41ac4b5e4 100644 --- a/.gitmodules +++ b/.gitmodules @@ -2,3 +2,9 @@ path = references/fbraz3-dxvk url = https://github.com/fbraz3/dxvk.git branch = generalsx-macos-v2.6 +[submodule "references/GameClient"] + path = references/GameClient + url = https://github.com/GeneralsOnlineDevelopmentTeam/GameClient.git +[submodule "references/GameServer"] + path = references/GameServer + url = https://github.com/fbraz3/GeneralsOnlineGameServer.git diff --git a/AGENTS.md b/AGENTS.md index d0fa22385bf..24d2f7fe3e1 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -36,6 +36,7 @@ GeneralsX is a cross-platform port of Command & Conquer: Generals Zero Hour for 9. **Update worklog** – Update `docs/WORKLOG/YYYY-MM-DIARY.md` before committing (see [.github/instructions/docs.instructions.md](.github/instructions/docs.instructions.md) for details) 10. **Reference repos** – Study patterns, don't copy-paste 11. **Backport to Generals** – Bugfixes and improvements must be backported to the Generals base game. +12. **NGMP over GameSpy** – The legacy GameSpy online backend is being discontinued. NGMP (`GeneralsOnline`) is the sole online multiplayer target. Singleplayer, Skirmish (vs AI), and LAN multiplayer must remain fully functional. GameSpy online compatibility is explicitly NOT required and must NOT block NGMP work. See [ngmp.instructions.md](.github/instructions/ngmp.instructions.md) for the full compatibility policy. ## Cross-Platform Determinism (Mac vs Linux) To guarantee cross-play between macOS ARM64 and Linux x86_64 without SyncCrash desyncs, you must obey the following rules: @@ -289,5 +290,6 @@ The `**` at applyTo means all files, you MUST load it everytime. | [.github/instructions/platform-macos.instructions.md](.github/instructions/platform-macos.instructions.md) | `scripts/build/macos/**,references/fbraz3-dxvk/**` | macOS/DXVK build notes | | [.github/instructions/docs.instructions.md](.github/instructions/docs.instructions.md) | `**/*.md` | Documentation structure and workflow | | [.github/instructions/scripts.instructions.md](.github/instructions/scripts.instructions.md) | `scripts/**` | Script organization and naming | +| [.github/instructions/ngmp.instructions.md](.github/instructions/ngmp.instructions.md) | `**/GeneralsOnline/**,**/NextGenMP/**` | NGMP cross-platform multiplayer integration guidelines | Update this table when instruction files are added, removed, or renamed. diff --git a/CMakeLists.txt b/CMakeLists.txt index 2fa3022238e..556e614a932 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -106,6 +106,9 @@ include(cmake/miniaudio.cmake) # curl.cmake is self-guarded with if(SAGE_UPDATE_CHECK), so always safe to include. include(cmake/curl.cmake) +# GeneralsX @feature GeneralsOnline NGMP protocol dependency setup +include(cmake/ngmp.cmake) + # GeneralsX @feature fbraz 03/05/2026 Phase 4: Deterministic math library integration # gamemath.cmake integrates fdlibm-based GameMath for cross-platform replay validation. # Upstream reference: Okladnoj, PR #2670 diff --git a/CMakePresets.json b/CMakePresets.json index 9ae40e205cb..e2d897114cf 100644 --- a/CMakePresets.json +++ b/CMakePresets.json @@ -83,7 +83,8 @@ "CMAKE_EXPORT_COMPILE_COMMANDS": "ON", "CMAKE_MSVC_DEBUG_INFORMATION_FORMAT": "$<$:Embedded>", "CMAKE_MSVC_RUNTIME_LIBRARY": "MultiThreaded$<$:Debug>DLL", - "CMAKE_TOOLCHAIN_FILE": "$env{VCPKG_ROOT}/scripts/buildsystems/vcpkg.cmake" + "CMAKE_TOOLCHAIN_FILE": "$env{VCPKG_ROOT}/scripts/buildsystems/vcpkg.cmake", + "VCPKG_OVERLAY_PORTS": "${sourceDir}/cmake/ports" } }, { diff --git a/Core/GameEngine/Include/Common/GameDefines.h b/Core/GameEngine/Include/Common/GameDefines.h index d1fb07b9c7a..11590b196b6 100644 --- a/Core/GameEngine/Include/Common/GameDefines.h +++ b/Core/GameEngine/Include/Common/GameDefines.h @@ -17,7 +17,6 @@ */ #pragma once - #include "WWLib/WWDefines.h" // Note: Retail compatibility must not be broken before this project officially does. diff --git a/Core/GameEngine/Include/Common/UpdateChecker.h b/Core/GameEngine/Include/Common/UpdateChecker.h index c9fb50c2b2f..fad428987ca 100644 --- a/Core/GameEngine/Include/Common/UpdateChecker.h +++ b/Core/GameEngine/Include/Common/UpdateChecker.h @@ -50,6 +50,15 @@ class UpdateChecker // Returns false if still in progress or no update found. static bool poll(const char** outLatestTag); + // Returns true if background update check is finished + static bool isDone(); + + // Returns true if a newer version is available + static bool hasUpdate(); + + // Returns latest tag string or empty + static const char* getLatestTag(); + // GitHub repository used for the API query. static const char* getReleasesUrl(); }; diff --git a/Core/GameEngine/Include/GameNetwork/GameSpy/LobbyUtils.h b/Core/GameEngine/Include/GameNetwork/GameSpy/LobbyUtils.h index bb07bc2f899..68bc345c767 100644 --- a/Core/GameEngine/Include/GameNetwork/GameSpy/LobbyUtils.h +++ b/Core/GameEngine/Include/GameNetwork/GameSpy/LobbyUtils.h @@ -53,3 +53,15 @@ enum GameSortType CPP_11(: Int) Bool HandleSortButton( NameKeyType sortButton ); void PopulateLobbyPlayerListbox(); + +enum LobbyGameModeFilter CPP_11(: Int) +{ + LOBBY_FILTER_ALL = 0, + LOBBY_FILTER_1V1, + LOBBY_FILTER_TEAM, + LOBBY_FILTER_FFA, + LOBBY_FILTER_AOD, +}; + +extern LobbyGameModeFilter theLobbyFilter; +LobbyGameModeFilter detectGameMode(const std::string& name); diff --git a/Core/GameEngine/Include/GameNetwork/GameSpy/PersistentStorageThread.h b/Core/GameEngine/Include/GameNetwork/GameSpy/PersistentStorageThread.h index 7ef79949844..fb53e1201c8 100644 --- a/Core/GameEngine/Include/GameNetwork/GameSpy/PersistentStorageThread.h +++ b/Core/GameEngine/Include/GameNetwork/GameSpy/PersistentStorageThread.h @@ -30,6 +30,13 @@ #include "gamespy/gstats/gpersist.h" +#if defined(min) +#undef min +#endif +#if defined(max) +#undef max +#endif + #define MAX_BUDDY_CHAT_LEN 128 typedef std::map PerGeneralMap; diff --git a/Core/GameEngine/Include/GameNetwork/GameSpyOverlay.h b/Core/GameEngine/Include/GameNetwork/GameSpyOverlay.h index 85eefbbc1d4..127d873ed30 100644 --- a/Core/GameEngine/Include/GameNetwork/GameSpyOverlay.h +++ b/Core/GameEngine/Include/GameNetwork/GameSpyOverlay.h @@ -39,6 +39,7 @@ void ClearGSMessageBoxes(); ///< Tear down any GS message boxes (e.g. in case we void GSMessageBoxOk(UnicodeString titleString,UnicodeString bodyString, GameWinMsgBoxFunc okFunc = nullptr); ///< Display a Message box with Ok button and track it void GSMessageBoxOkCancel(UnicodeString title, UnicodeString message, GameWinMsgBoxFunc okFunc, GameWinMsgBoxFunc cancelFunc); ///< Display a Message box with Ok/Cancel buttons and track it void GSMessageBoxYesNo(UnicodeString title, UnicodeString message, GameWinMsgBoxFunc yesFunc, GameWinMsgBoxFunc noFunc); ///< Display a Message box with Yes/No buttons and track it +void GSMessageBoxCancel(UnicodeString title, UnicodeString message, GameWinMsgBoxFunc cancelFunc = nullptr); ///< Display a Message box with Cancel button and track it void RaiseGSMessageBox(); ///< Bring GS message box to the foreground (if we transition screens while a message box is up) enum GSOverlayType CPP_11(: Int) diff --git a/Core/GameEngine/Include/GameNetwork/Transport.h b/Core/GameEngine/Include/GameNetwork/Transport.h index e9f9d50791d..602afdfb882 100644 --- a/Core/GameEngine/Include/GameNetwork/Transport.h +++ b/Core/GameEngine/Include/GameNetwork/Transport.h @@ -43,20 +43,20 @@ class Transport //: public MemoryPoolObject public: Transport(); - ~Transport(); + virtual ~Transport(); - Bool init( AsciiString ip, UnsignedShort port ); - Bool init( UnsignedInt ip, UnsignedShort port ); - void reset(); - Bool update(); ///< Call this once a GameEngine tick, regardless of whether the frame advances. + virtual Bool init( AsciiString ip, UnsignedShort port ); + virtual Bool init( UnsignedInt ip, UnsignedShort port ); + virtual void reset(); + virtual Bool update(); ///< Call this once a GameEngine tick, regardless of whether the frame advances. - Bool doRecv(); ///< call this to service the receive packets - Bool doSend(); ///< call this to service the send queue. + virtual Bool doRecv(); ///< call this to service the receive packets + virtual Bool doSend(); ///< call this to service the send queue. - Bool queueSend(UnsignedInt addr, UnsignedShort port, const UnsignedByte *buf, Int len /*, + virtual Bool queueSend(UnsignedInt addr, UnsignedShort port, const UnsignedByte *buf, Int len /*, NetMessageFlags flags, Int id */); ///< Queue a packet for sending to the specified address and port. This will be sent on the next update() call. - Bool allowBroadcasts(Bool val) { if (!m_udpsock) return false; return (m_udpsock->AllowBroadcasts(val))?true:false; } + virtual Bool allowBroadcasts(Bool val) { if (!m_udpsock) return false; return (m_udpsock->AllowBroadcasts(val))?true:false; } // Latency insertion and packet loss void setLatency( Bool val ) { m_useLatency = val; } @@ -78,7 +78,7 @@ class Transport //: public MemoryPoolObject #endif UnsignedShort m_port; -private: +protected: Bool m_winsockInit; UDP *m_udpsock; diff --git a/Core/GameEngine/Source/Common/UpdateChecker.cpp b/Core/GameEngine/Source/Common/UpdateChecker.cpp index 535a7603fb0..056d9628049 100644 --- a/Core/GameEngine/Source/Common/UpdateChecker.cpp +++ b/Core/GameEngine/Source/Common/UpdateChecker.cpp @@ -314,6 +314,36 @@ void UpdateChecker::start() return; } +#if defined(NGMP_DEFAULT_HOST) + // In local development environments, skip update check + std::string ngmpHost = NGMP_DEFAULT_HOST; + if (ngmpHost == "localhost" || ngmpHost == "127.0.0.1" || + ngmpHost.rfind("192.168.", 0) == 0 || + ngmpHost.rfind("10.", 0) == 0 || + ngmpHost.rfind("172.16.", 0) == 0 || + ngmpHost.rfind("172.17.", 0) == 0 || + ngmpHost.rfind("172.18.", 0) == 0 || + ngmpHost.rfind("172.19.", 0) == 0 || + ngmpHost.rfind("172.20.", 0) == 0 || + ngmpHost.rfind("172.21.", 0) == 0 || + ngmpHost.rfind("172.22.", 0) == 0 || + ngmpHost.rfind("172.23.", 0) == 0 || + ngmpHost.rfind("172.24.", 0) == 0 || + ngmpHost.rfind("172.25.", 0) == 0 || + ngmpHost.rfind("172.26.", 0) == 0 || + ngmpHost.rfind("172.27.", 0) == 0 || + ngmpHost.rfind("172.28.", 0) == 0 || + ngmpHost.rfind("172.29.", 0) == 0 || + ngmpHost.rfind("172.30.", 0) == 0 || + ngmpHost.rfind("172.31.", 0) == 0) + { + fprintf(stderr, "[UpdateChecker] start() aborted. Running in local development environment (%s).\n", ngmpHost.c_str()); + fflush(stderr); + SDL_SetAtomicInt(&s_done, 1); + return; + } +#endif + SDL_SetAtomicInt(&s_done, 0); SDL_SetAtomicInt(&s_hasUpdate, 0); s_latestTag[0] = '\0'; @@ -355,4 +385,19 @@ bool UpdateChecker::poll(const char** outLatestTag) return true; } +bool UpdateChecker::isDone() +{ + return SDL_GetAtomicInt(&s_done) != 0; +} + +bool UpdateChecker::hasUpdate() +{ + return SDL_GetAtomicInt(&s_hasUpdate) != 0; +} + +const char* UpdateChecker::getLatestTag() +{ + return s_latestTag; +} + #endif // SAGE_UPDATE_CHECK diff --git a/Core/GameEngine/Source/Common/UserPreferences.cpp b/Core/GameEngine/Source/Common/UserPreferences.cpp index afc017cd9c0..5f51beca0d4 100644 --- a/Core/GameEngine/Source/Common/UserPreferences.cpp +++ b/Core/GameEngine/Source/Common/UserPreferences.cpp @@ -51,6 +51,16 @@ #include "GameClient/ChallengeGenerals.h" #include "GameNetwork/GameSpy/PeerDefs.h" +#if defined(SAGE_USE_NGMP) && __has_include("GameNetwork/GeneralsOnline/OnlineServices_Manager.h") +#include "GameNetwork/GeneralsOnline/OnlineServices_Manager.h" +#include "GameNetwork/GeneralsOnline/OnlineServices_Auth.h" +#include "GameNetwork/GeneralsOnline/NGMP_interfaces.h" +#define HAVE_NGMP_PREFS 1 +#endif +#if !defined(_MSC_VER) || (_MSC_VER >= 1914) +#include +#endif + //----------------------------------------------------------------------------- // DEFINES //////////////////////////////////////////////////////////////////// @@ -120,8 +130,26 @@ Bool UserPreferences::load(AsciiString fname) // if (strstr(fname.str(), "\\")) // throw INI_INVALID_DATA; // must be a leaf name + AsciiString normalizedFname = fname; +#ifndef _WIN32 + // Normalize backslashes to forward slashes on POSIX + if (!fname.isEmpty()) + { + std::string s = fname.str(); + for (char &c : s) + { + if (c == '\\') c = '/'; + } + normalizedFname = s.c_str(); + } +#endif + m_filename = TheGlobalData->getPath_UserData(); - m_filename.concat(fname); + if (!m_filename.endsWith("/") && !m_filename.endsWith("\\") && !normalizedFname.startsWith("/") && !normalizedFname.startsWith("\\")) + { + m_filename.concat('/'); + } + m_filename.concat(normalizedFname); FILE *fp = fopen(m_filename.str(), "r"); if (fp) @@ -155,6 +183,17 @@ Bool UserPreferences::write() if (m_filename.isEmpty()) return false; +#if !defined(_MSC_VER) || (_MSC_VER >= 1914) + // GeneralsX @feature fbraz3 03/09/2026 Ensure parent directory exists before writing preferences + std::filesystem::path filePath(m_filename.str()); + std::filesystem::path parentDir = filePath.parent_path(); + if (!parentDir.empty()) + { + std::error_code ec; + std::filesystem::create_directories(parentDir, ec); + } +#endif + FILE *fp = fopen(m_filename.str(), "w"); if (fp) { @@ -242,8 +281,13 @@ void UserPreferences::setAsciiString(AsciiString key, AsciiString val) QuickMatchPreferences::QuickMatchPreferences() { AsciiString userPrefFilename; - Int localProfile = TheGameSpyInfo->getLocalProfileID(); - userPrefFilename.format("GeneralsOnline\\QMPref%d.ini", localProfile); +#if defined(HAVE_NGMP_PREFS) + NGMP_OnlineServices_AuthInterface* pAuthInterface = NGMP_OnlineServicesManager::GetInterface(); + Int localProfile = pAuthInterface != nullptr ? (Int)pAuthInterface->GetUserID() : 0; +#else + Int localProfile = TheGameSpyInfo ? TheGameSpyInfo->getLocalProfileID() : 0; +#endif + userPrefFilename.format("GeneralsOnline/QMPref%d.ini", localProfile); load(userPrefFilename); } @@ -427,8 +471,13 @@ Int QuickMatchPreferences::getSide() CustomMatchPreferences::CustomMatchPreferences() { AsciiString userPrefFilename; - Int localProfile = TheGameSpyInfo->getLocalProfileID(); - userPrefFilename.format("GeneralsOnline\\CustomPref%d.ini", localProfile); +#if defined(HAVE_NGMP_PREFS) + NGMP_OnlineServices_AuthInterface* pAuthInterface = NGMP_OnlineServicesManager::GetInterface(); + Int localProfile = pAuthInterface != nullptr ? (Int)pAuthInterface->GetUserID() : 0; +#else + Int localProfile = TheGameSpyInfo ? TheGameSpyInfo->getLocalProfileID() : 0; +#endif + userPrefFilename.format("GeneralsOnline/CustomPref%d.ini", localProfile); load(userPrefFilename); } @@ -776,8 +825,13 @@ void CustomMatchPreferences::setUseStats( Bool useStats ) GameSpyMiscPreferences::GameSpyMiscPreferences() { AsciiString userPrefFilename; - Int localProfile = TheGameSpyInfo->getLocalProfileID(); - userPrefFilename.format("GeneralsOnline\\GSMiscPref%d.ini", localProfile); +#if defined(HAVE_NGMP_PREFS) + NGMP_OnlineServices_AuthInterface* pAuthInterface = NGMP_OnlineServicesManager::GetInterface(); + Int localProfile = pAuthInterface != nullptr ? (Int)pAuthInterface->GetUserID() : 0; +#else + Int localProfile = TheGameSpyInfo ? TheGameSpyInfo->getLocalProfileID() : 0; +#endif + userPrefFilename.format("GeneralsOnline/GSMiscPref%d.ini", localProfile); load(userPrefFilename); } @@ -824,7 +878,7 @@ IgnorePreferences::IgnorePreferences() AsciiString userPrefFilename; // if(!TheGameSpyInfo) Int localProfile = TheGameSpyInfo->getLocalProfileID(); - userPrefFilename.format("GeneralsOnline\\IgnorePref%d.ini", localProfile); + userPrefFilename.format("GeneralsOnline/IgnorePref%d.ini", localProfile); load(userPrefFilename); } @@ -880,7 +934,7 @@ Bool LadderPreferences::loadProfile( Int profileID ) clear(); m_ladders.clear(); AsciiString userPrefFilename; - userPrefFilename.format("GeneralsOnline\\Ladders%d.ini", profileID); + userPrefFilename.format("GeneralsOnline/Ladders%d.ini", profileID); Bool success = load(userPrefFilename); if (!success) return success; diff --git a/Core/GameEngine/Source/GameClient/GUI/GUICallbacks/InGameChat.cpp b/Core/GameEngine/Source/GameClient/GUI/GUICallbacks/InGameChat.cpp index 8aa625472ad..018612774e6 100644 --- a/Core/GameEngine/Source/GameClient/GUI/GUICallbacks/InGameChat.cpp +++ b/Core/GameEngine/Source/GameClient/GUI/GUICallbacks/InGameChat.cpp @@ -199,7 +199,7 @@ void ToggleInGameChat( Bool immediate ) if (TheGameLogic->isInReplayGame()) return; - if (!TheGameInfo->isMultiPlayer() && TheGlobalData->m_netMinPlayers) + if (TheGameInfo == nullptr || (!TheGameInfo->isMultiPlayer() && TheGlobalData->m_netMinPlayers)) return; if (chatWindow) diff --git a/Core/GameEngine/Source/GameClient/GUI/Gadget/GadgetListBox.cpp b/Core/GameEngine/Source/GameClient/GUI/Gadget/GadgetListBox.cpp index 9cf23d633e9..f9ed9defd30 100644 --- a/Core/GameEngine/Source/GameClient/GUI/Gadget/GadgetListBox.cpp +++ b/Core/GameEngine/Source/GameClient/GUI/Gadget/GadgetListBox.cpp @@ -2478,6 +2478,9 @@ void GadgetListBoxRemoveMultiSelect( GameWindow *listbox ) //============================================================================= void GadgetListBoxSetListLength( GameWindow *listbox, Int newLength ) { + if (!listbox) + return; + ListboxData *listboxData = (ListboxData *)listbox->winGetUserData(); diff --git a/Core/GameEngine/Source/GameClient/GUI/Gadget/GadgetTextEntry.cpp b/Core/GameEngine/Source/GameClient/GUI/Gadget/GadgetTextEntry.cpp index c7e0ade4f25..a04a5ae7304 100644 --- a/Core/GameEngine/Source/GameClient/GUI/Gadget/GadgetTextEntry.cpp +++ b/Core/GameEngine/Source/GameClient/GUI/Gadget/GadgetTextEntry.cpp @@ -151,24 +151,18 @@ WindowMsgHandledType GadgetTextEntryInput( GameWindow *window, UnsignedInt msg, switch( mData1 ) { - /* // -------------------------------------------------------------------- case KEY_KPENTER: case KEY_ENTER: // Done with this edit if( BitIsSet( mData2, KEY_STATE_DOWN ) ) { - if( e->receivedUnichar == FALSE ) - { - TheWindowManager->winSendSystemMsg( window->winGetOwner(), - GEM_EDIT_DONE, - (WindowMsgData)window, - 0 ); - } + TheWindowManager->winSendSystemMsg( window->winGetOwner(), + GEM_EDIT_DONE, + (WindowMsgData)window, + 0 ); } - - break; - */ + return MSG_HANDLED; // -------------------------------------------------------------------- // Don't process these keys case KEY_ESC: diff --git a/Core/GameEngine/Source/GameClient/GUI/GameWindowManager.cpp b/Core/GameEngine/Source/GameClient/GUI/GameWindowManager.cpp index fa70468910e..227bbde28aa 100644 --- a/Core/GameEngine/Source/GameClient/GUI/GameWindowManager.cpp +++ b/Core/GameEngine/Source/GameClient/GUI/GameWindowManager.cpp @@ -105,8 +105,7 @@ void GameWindowManager::processDestroyList() if( m_keyboardFocus == doDestroy ) winSetFocus( nullptr ); - if( (m_modalHead != nullptr) && (doDestroy == m_modalHead->window) ) - winUnsetModal( m_modalHead->window ); + winUnsetModal( doDestroy ); if( m_currMouseRgn == doDestroy ) m_currMouseRgn = nullptr; @@ -551,9 +550,8 @@ void GameWindowManager::windowHiding( GameWindow *window ) if( m_keyboardFocus == window ) m_keyboardFocus = nullptr; - // if this is the modal head, unset it - if( m_modalHead && m_modalHead->window == window ) - winUnsetModal( window ); + // if this window is in the modal stack, unset it + winUnsetModal( window ); // if this is the captor, it shall no longer be if( m_mouseCaptor == window ) @@ -1427,8 +1425,7 @@ Int GameWindowManager::winDestroy( GameWindow *window ) if( m_keyboardFocus == window ) winSetFocus( nullptr ); - if( (m_modalHead != nullptr) && (window == m_modalHead->window) ) - winUnsetModal( m_modalHead->window ); + winUnsetModal( window ); if( m_currMouseRgn == window ) m_currMouseRgn = nullptr; @@ -1529,35 +1526,35 @@ Int GameWindowManager::winSetModal( GameWindow *window ) } -//------------------------------------------------------------------------------------------------- -/** pops window off of the modal stack. If this window is not the top - * of the modal stack an error will occur. */ -//------------------------------------------------------------------------------------------------- +// GeneralsX @bugfix fbraz3 17/08/2026 Remove window from anywhere in modal stack to prevent corrupted dangling pointers when sub-modals close Int GameWindowManager::winUnsetModal( GameWindow *window ) { - ModalWindow *next; - if( window == nullptr ) return WIN_ERR_INVALID_WINDOW; - // verify entry is at top of list - if( (m_modalHead == nullptr) || (m_modalHead->window != window) ) - { - - // return error if not - DEBUG_LOG(( "WinUnsetModal: Invalid window attempting to unset modal (%d)", - window->winGetWindowId() )); - return WIN_ERR_GENERAL_FAILURE; + ModalWindow *curr = m_modalHead; + ModalWindow *prev = nullptr; + while (curr != nullptr) + { + if (curr->window == window) + { + if (prev == nullptr) + { + m_modalHead = curr->next; + } + else + { + prev->next = curr->next; + } + deleteInstance(curr); + return WIN_ERR_OK; + } + prev = curr; + curr = curr->next; } - // remove from top of list - next = m_modalHead->next; - deleteInstance(m_modalHead); - m_modalHead = next; - return WIN_ERR_OK; - } //------------------------------------------------------------------------------------------------- diff --git a/Core/GameEngine/Source/GameClient/GUI/LoadScreen.cpp b/Core/GameEngine/Source/GameClient/GUI/LoadScreen.cpp index 3b2071e4f80..6fe3fdb477a 100644 --- a/Core/GameEngine/Source/GameClient/GUI/LoadScreen.cpp +++ b/Core/GameEngine/Source/GameClient/GUI/LoadScreen.cpp @@ -83,6 +83,11 @@ #include "GameClient/WindowVideoManager.h" #include "GameClient/ChallengeGenerals.h" #include "GameLogic/FPUControl.h" + +#if defined(SAGE_USE_NGMP) && __has_include("GameNetwork/GeneralsOnline/OnlineServices_Manager.h") +#include "GameNetwork/GeneralsOnline/OnlineServices_Manager.h" +#define HAVE_NGMP_LOADSCREEN 1 +#endif #include "GameLogic/GameLogic.h" #include "GameNetwork/GameSpy/PeerDefs.h" #include "GameNetwork/GameSpy/PersistentStorageThread.h" @@ -1284,7 +1289,8 @@ void MultiPlayerLoadScreen::init( GameInfo *game ) m_mapPreview = TheWindowManager->winGetWindowFromId( m_loadScreen,TheNameKeyGenerator->nameToKey( "MultiplayerLoadScreen.wnd:WinMapPreview")); GameSlot *lSlot = game->getSlot(game->getLocalSlotNum()); const PlayerTemplate* pt; - if (lSlot->getPlayerTemplate() >= 0) + // GeneralsX @bugfix fbraz3 30/08/2026 Guard against null lSlot when getLocalSlotNum() returns -1 + if (lSlot != nullptr && lSlot->getPlayerTemplate() >= 0) pt = ThePlayerTemplateStore->getNthPlayerTemplate(lSlot->getPlayerTemplate()); else pt = ThePlayerTemplateStore->findPlayerTemplate( TheNameKeyGenerator->nameToKey("FactionObserver") ); @@ -1549,7 +1555,8 @@ void GameSpyLoadScreen::init( GameInfo *game ) DEBUG_LOG(("NumPlayers %d", TheNetwork->getNumPlayers())); GameSlot *lSlot = game->getSlot(game->getLocalSlotNum()); const PlayerTemplate* pt; - if (lSlot->getPlayerTemplate() >= 0) + // GeneralsX @bugfix fbraz3 30/08/2026 Guard against null lSlot when getLocalSlotNum() returns -1 + if (lSlot != nullptr && lSlot->getPlayerTemplate() >= 0) pt = ThePlayerTemplateStore->getNthPlayerTemplate(lSlot->getPlayerTemplate()); else pt = ThePlayerTemplateStore->findPlayerTemplate( TheNameKeyGenerator->nameToKey("FactionObserver") ); @@ -1837,6 +1844,14 @@ void GameSpyLoadScreen::update( Int percent ) TheNetwork->updateLoadProgress( percent ); TheNetwork->liteupdate(); +#if defined(HAVE_NGMP_LOADSCREEN) + // GeneralsX @bugfix fbraz3 06/09/2026 Tick NGMP during MP load screen to keep WebSocket signaling alive + if (NGMP_OnlineServicesManager::GetInstance() != nullptr) + { + NGMP_OnlineServicesManager::GetInstance()->update(); + } +#endif + //GadgetProgressBarSetProgress(m_progressBars[TheNetwork->getLocalPlayerID()], percent ); TheMouse->setCursorTooltip(UnicodeString::TheEmptyString); @@ -1977,6 +1992,14 @@ void MapTransferLoadScreen::update( Int percent ) TheNetwork->liteupdate(); } +#if defined(HAVE_NGMP_LOADSCREEN) + // GeneralsX @bugfix fbraz3 06/09/2026 Tick NGMP during map transfer screen + if (NGMP_OnlineServicesManager::GetInstance() != nullptr) + { + NGMP_OnlineServicesManager::GetInstance()->update(); + } +#endif + TheMouse->setCursorTooltip(UnicodeString::TheEmptyString); // Do this last! diff --git a/Core/GameEngine/Source/GameClient/MapUtil.cpp b/Core/GameEngine/Source/GameClient/MapUtil.cpp index 9e20c39b051..8dc51dba2d6 100644 --- a/Core/GameEngine/Source/GameClient/MapUtil.cpp +++ b/Core/GameEngine/Source/GameClient/MapUtil.cpp @@ -30,6 +30,12 @@ // INCLUDES /////////////////////////////////////////////////////////////////////////////////////// #include "PreRTS.h" // This must go first in EVERY cpp file in the GameEngine #include +#include + +#if !defined(_WIN32) +#include +static std::set s_failedMapLookups; +#endif #include "Common/crc.h" #include "Common/FileSystem.h" @@ -480,6 +486,29 @@ void MapCache::updateCache() m_doLoadStandardMapCacheINI = TRUE; } +#if !defined(_WIN32) + s_failedMapLookups.clear(); + // GeneralsX @feature fbraz3 03/09/2026 Check user Documents directory for Zero Hour custom maps + // On macOS/Linux, also scan user Documents directory if it exists and differs from userMapDir + const char* homeDir = getenv("HOME"); + if (homeDir) + { + std::vector docMapDirs = { + std::string(homeDir) + "/Documents/Command and Conquer Generals Zero Hour Data/Maps", + std::string(homeDir) + "/Documents/Command & Conquer Generals Zero Hour Data/Maps" + }; + for (const auto& dmd : docMapDirs) + { + std::error_code ec; + if (std::filesystem::exists(dmd, ec) && std::filesystem::is_directory(dmd, ec)) + { + AsciiString docMaps(dmd.c_str()); + loadMapsFromDisk(docMaps, FALSE); + } + } + } +#endif + // Load standard maps from map cache last. // This overwrites matching user maps to prevent munkees getting rowdy :) if (m_doLoadStandardMapCacheINI) @@ -1119,11 +1148,126 @@ Bool isOfficialMap( AsciiString mapName ) const MapMetaData *MapCache::findMap(AsciiString mapName) { - mapName.toLower(); - MapCache::iterator it = find(mapName); - if (it == end()) + if (mapName.isEmpty()) return nullptr; - return &(it->second); + + auto normalizePath = [](const std::string& input) -> std::string { + std::string s = input; + std::transform(s.begin(), s.end(), s.begin(), ::tolower); + for (char &c : s) { + if (c == '\\') c = '/'; + } + while (s.length() > 1 && s.back() == '/') s.pop_back(); + return s; + }; + + auto extractBaseLeaf = [](const std::string& normalized) -> std::string { + size_t lastSlash = normalized.find_last_of('/'); + std::string base = (lastSlash != std::string::npos) ? normalized.substr(lastSlash + 1) : normalized; + if (base.length() > 4 && base.substr(base.length() - 4) == ".map") { + base = base.substr(0, base.length() - 4); + } + return base; + }; + + std::string normQuery = normalizePath(mapName.str()); + std::string baseQuery = extractBaseLeaf(normQuery); + + // Direct lookup with exact key or normalized keys + MapCache::iterator it = find(mapName); + if (it != end()) return &(it->second); + + it = find(AsciiString(normQuery.c_str())); + if (it != end()) return &(it->second); + + std::string normBackslash = normQuery; + for (char &c : normBackslash) { if (c == '/') c = '\\'; } + it = find(AsciiString(normBackslash.c_str())); + if (it != end()) return &(it->second); + + // Comprehensive iterate fallback matching + for (it = begin(); it != end(); ++it) + { + AsciiString asciiDisplay; + asciiDisplay.translate(it->second.m_displayName); + std::string normDisplay = normalizePath(asciiDisplay.str()); + if (normDisplay == normQuery || (!baseQuery.empty() && normDisplay == baseQuery)) + return &(it->second); + + std::string normKey = normalizePath(it->first.str()); + std::string baseKey = extractBaseLeaf(normKey); + if (normKey == normQuery || + (!normQuery.empty() && normKey.length() >= normQuery.length() && normKey.rfind(normQuery) == (normKey.length() - normQuery.length())) || + (!normKey.empty() && normQuery.length() >= normKey.length() && normQuery.rfind(normKey) == (normQuery.length() - normKey.length()))) + { + return &(it->second); + } + + std::string normFn = normalizePath(it->second.m_fileName.str()); + std::string baseFn = extractBaseLeaf(normFn); + if (!normFn.empty() && ( + normFn == normQuery || + (!normQuery.empty() && normFn.length() >= normQuery.length() && normFn.rfind(normQuery) == (normFn.length() - normQuery.length())) || + (!normFn.empty() && normQuery.length() >= normFn.length() && normQuery.rfind(normFn) == (normQuery.length() - normFn.length())))) + { + return &(it->second); + } + + if (!baseQuery.empty() && (baseKey == baseQuery || baseFn == baseQuery)) + { + return &(it->second); + } + } + +#if !defined(_WIN32) + // Fallback 2: Check standard custom map folders on POSIX if not in cache + const char* home = getenv("HOME"); + if (home && !baseQuery.empty() && s_failedMapLookups.find(baseQuery) == s_failedMapLookups.end()) + { + std::vector searchDirs = { + std::string(home) + "/Library/Application Support/GeneralsX/GeneralsZH/Maps", + std::string(home) + "/Documents/Command and Conquer Generals Zero Hour Data/Maps", + std::string(home) + "/Documents/Command & Conquer Generals Zero Hour Data/Maps" + }; + + for (const auto& sdir : searchDirs) + { + std::error_code ec; + if (!std::filesystem::exists(sdir, ec)) continue; + + for (const auto& entry : std::filesystem::recursive_directory_iterator(sdir, std::filesystem::directory_options::skip_permission_denied, ec)) + { + if (ec) break; + if (entry.is_regular_file(ec) && entry.path().extension() == ".map") + { + std::string candidateStem = entry.path().stem().string(); + std::string normCandidateStem = normalizePath(candidateStem); + if (normCandidateStem == baseQuery) + { + FileInfo fileInfo; + AsciiString fullPath(entry.path().string().c_str()); + AsciiString fullPathLower = fullPath; + fullPathLower.toLower(); + if (TheFileSystem->getFileInfo(fullPath, &fileInfo)) + { + AsciiString mapDir(sdir.c_str()); + addMap(mapDir, fullPath, fullPathLower, fileInfo, FALSE); + MapCache::iterator foundIt = find(fullPathLower); + if (foundIt != end()) return &(foundIt->second); + for (MapCache::iterator fit = begin(); fit != end(); ++fit) { + if (fit->second.m_fileName == fullPath) return &(fit->second); + } + } + } + } + } + } + + s_failedMapLookups.insert(baseQuery); + } +#endif + + return nullptr; } // ------------------------------------------------------------------------------------------------ diff --git a/Core/GameEngine/Source/GameNetwork/GameSpy/LadderDefs.cpp b/Core/GameEngine/Source/GameNetwork/GameSpy/LadderDefs.cpp index 2375e07e58a..eb6065133d3 100644 --- a/Core/GameEngine/Source/GameNetwork/GameSpy/LadderDefs.cpp +++ b/Core/GameEngine/Source/GameNetwork/GameSpy/LadderDefs.cpp @@ -442,7 +442,7 @@ const LadderInfoList* LadderList::getLocalLadders() void LadderList::loadLocalLadders() { AsciiString dirname; - dirname.format("%sGeneralsOnline\\Ladders\\", TheGlobalData->getPath_UserData().str()); + dirname.format("%sGeneralsOnline/Ladders/", TheGlobalData->getPath_UserData().str()); FilenameList filenameList; TheFileSystem->getFileListInDirectory(dirname, "*.ini", filenameList, TRUE); diff --git a/Core/GameEngine/Source/GameNetwork/GameSpy/LobbyUtils.cpp b/Core/GameEngine/Source/GameNetwork/GameSpy/LobbyUtils.cpp index f8b8448f317..a51e8dd1227 100644 --- a/Core/GameEngine/Source/GameNetwork/GameSpy/LobbyUtils.cpp +++ b/Core/GameEngine/Source/GameNetwork/GameSpy/LobbyUtils.cpp @@ -139,6 +139,41 @@ static void showSortIcons() } } } +LobbyGameModeFilter theLobbyFilter = LOBBY_FILTER_ALL; + +LobbyGameModeFilter detectGameMode(const std::string& name) +{ + std::string modeName = name; + std::transform(modeName.begin(), modeName.end(), modeName.begin(), ::tolower); + + // remove spaces + modeName.erase(std::remove(modeName.begin(), modeName.end(), ' '), modeName.end()); + + // handle common variations + for (size_t i = 0; i < modeName.size(); ++i) + { + if (modeName.compare(i, 2, "vs") == 0) + { + modeName.erase(i + 1, 1); + continue; + } + + if (modeName[i] == 'x') + modeName[i] = 'v'; + } + + if (modeName.find("aod") != std::string::npos) + return LOBBY_FILTER_AOD; + if (modeName.find("ffa") != std::string::npos || modeName.find("1v1v1") != std::string::npos) + return LOBBY_FILTER_FFA; + if (modeName.find("1v1") != std::string::npos) + return LOBBY_FILTER_1V1; + if (modeName.find("2v2") != std::string::npos || modeName.find("3v3") != std::string::npos || modeName.find("4v4") != std::string::npos) + return LOBBY_FILTER_TEAM; + + return LOBBY_FILTER_ALL; +} + void setSortMode( GameSortType sortType ) { theGameSortType = sortType; showSortIcons(); RefreshGameListBoxes(); } void sortByBuddies( Bool doSort ) { sortBuddies = doSort; showSortIcons(); RefreshGameListBoxes(); } diff --git a/Core/GameEngine/Source/GameNetwork/GameSpy/MainMenuUtils.cpp b/Core/GameEngine/Source/GameNetwork/GameSpy/MainMenuUtils.cpp index c161116a2f3..610c876ecf3 100644 --- a/Core/GameEngine/Source/GameNetwork/GameSpy/MainMenuUtils.cpp +++ b/Core/GameEngine/Source/GameNetwork/GameSpy/MainMenuUtils.cpp @@ -378,7 +378,7 @@ static GHTTPBool configCallback( GHTTPRequest request, GHTTPResult result, configBuffer[bufferLen-1] = 0; AsciiString fname; - fname.format("%sGeneralsOnline\\Config.txt", TheGlobalData->getPath_UserData().str()); + fname.format("%sGeneralsOnline/Config.txt", TheGlobalData->getPath_UserData().str()); FILE *fp = fopen(fname.str(), "wb"); if (fp) { @@ -433,7 +433,7 @@ static GHTTPBool configHeadCallback( GHTTPRequest request, GHTTPResult result, Int serverLen = atoi(val.str()); Int fileLen = 0; AsciiString fname; - fname.format("%sGeneralsOnline\\Config.txt", TheGlobalData->getPath_UserData().str()); + fname.format("%sGeneralsOnline/Config.txt", TheGlobalData->getPath_UserData().str()); FILE *fp = fopen(fname.str(), "rb"); if (fp) { @@ -457,7 +457,7 @@ static GHTTPBool configHeadCallback( GHTTPRequest request, GHTTPResult result, configBuffer = nullptr; AsciiString fname; - fname.format("%sGeneralsOnline\\Config.txt", TheGlobalData->getPath_UserData().str()); + fname.format("%sGeneralsOnline/Config.txt", TheGlobalData->getPath_UserData().str()); FILE *fp = fopen(fname.str(), "rb"); if (fp) { diff --git a/Core/GameEngine/Source/GameNetwork/GameSpy/PeerDefs.cpp b/Core/GameEngine/Source/GameNetwork/GameSpy/PeerDefs.cpp index 60d4be33148..3338377b97b 100644 --- a/Core/GameEngine/Source/GameNetwork/GameSpy/PeerDefs.cpp +++ b/Core/GameEngine/Source/GameNetwork/GameSpy/PeerDefs.cpp @@ -606,7 +606,7 @@ void SetUpGameSpy( const char *motdBuffer, const char *configBuffer ) CreateDirectory(dir.str(), nullptr); dir.format("%sGeneralsOnline", TheGlobalData->getPath_UserData().str()); CreateDirectory(dir.str(), nullptr); - dir.format("%sGeneralsOnline\\Ladders", TheGlobalData->getPath_UserData().str()); + dir.format("%sGeneralsOnline/Ladders", TheGlobalData->getPath_UserData().str()); CreateDirectory(dir.str(), nullptr); TheGameSpyBuddyMessageQueue = GameSpyBuddyMessageQueueInterface::createNewMessageQueue(); diff --git a/Core/GameEngine/Source/GameNetwork/GameSpy/Thread/PersistentStorageThread.cpp b/Core/GameEngine/Source/GameNetwork/GameSpy/Thread/PersistentStorageThread.cpp index 0fc302520b1..e879dfb2946 100644 --- a/Core/GameEngine/Source/GameNetwork/GameSpy/Thread/PersistentStorageThread.cpp +++ b/Core/GameEngine/Source/GameNetwork/GameSpy/Thread/PersistentStorageThread.cpp @@ -678,7 +678,7 @@ static void getPersistentDataCallback(int localid, int profileid, persisttype_t // check if we have discons we should update on the server UserPreferences pref; AsciiString userPrefFilename; - userPrefFilename.format("GeneralsOnline\\MiscPref%d.ini", MESSAGE_QUEUE->getLocalPlayerID()); + userPrefFilename.format("GeneralsOnline/MiscPref%d.ini", MESSAGE_QUEUE->getLocalPlayerID()); DEBUG_LOG(("using the file %s", userPrefFilename.str())); pref.load(userPrefFilename); Int addedInDesyncs2 = pref.getInt("0", 0); @@ -758,7 +758,7 @@ static void setPersistentDataCallback(int localid, int profileid, persisttype_t { UserPreferences pref; AsciiString userPrefFilename; - userPrefFilename.format("GeneralsOnline\\MiscPref%d.ini", profileid); + userPrefFilename.format("GeneralsOnline/MiscPref%d.ini", profileid); DEBUG_LOG(("setPersistentDataCallback - writing stats to file %s", userPrefFilename.str())); pref.load(userPrefFilename); pref.clear(); @@ -910,7 +910,7 @@ void PSThreadClass::Thread_Function() DEBUG_LOG(("Processing PSRequest::PSREQUEST_UPDATEPLAYERSTATS")); UserPreferences pref; AsciiString userPrefFilename; - userPrefFilename.format("GeneralsOnline\\MiscPref%d.ini", MESSAGE_QUEUE->getLocalPlayerID()); + userPrefFilename.format("GeneralsOnline/MiscPref%d.ini", MESSAGE_QUEUE->getLocalPlayerID()); DEBUG_LOG(("using the file %s", userPrefFilename.str())); pref.load(userPrefFilename); Int addedInDesyncs2 = pref.getInt("0", 0); diff --git a/Core/GameEngine/Source/GameNetwork/GameSpyOverlay.cpp b/Core/GameEngine/Source/GameNetwork/GameSpyOverlay.cpp index 140c18e6f72..e3f56f33a68 100644 --- a/Core/GameEngine/Source/GameNetwork/GameSpyOverlay.cpp +++ b/Core/GameEngine/Source/GameNetwork/GameSpyOverlay.cpp @@ -137,6 +137,14 @@ void GSMessageBoxYesNo(UnicodeString title, UnicodeString message, GameWinMsgBox cancelFunc = newNoFunc; } +// GeneralsX @feature fbraz3 17/08/2026 Add GSMessageBoxCancel support for NGMP asynchronous lobby creation +void GSMessageBoxCancel(UnicodeString title, UnicodeString message, GameWinMsgBoxFunc newCancelFunc) +{ + ClearGSMessageBoxes(); + messageBoxWindow = MessageBoxCancel(title, message, messageBoxCancel); + cancelFunc = newCancelFunc; +} + /** * If the screen transitions underneath the dialog box, we * need to raise it to keep it visible. @@ -194,6 +202,7 @@ void GameSpyOpenOverlay( GSOverlayType overlay ) { if (overlay == GSOVERLAY_BUDDY) { +#if !defined(SAGE_USE_NGMP) if (!TheGameSpyBuddyMessageQueue->isConnected()) { // not connected - is it because we were disconnected? @@ -209,6 +218,7 @@ void GameSpyOpenOverlay( GSOverlayType overlay ) } return; } +#endif AudioEventRTS buttonClick("GUICommunicatorOpen"); if( TheAudio ) diff --git a/Core/Libraries/Source/WWVegas/WWLib/bittype.h b/Core/Libraries/Source/WWVegas/WWLib/bittype.h index ff604abdc6a..27f5f6a288b 100644 --- a/Core/Libraries/Source/WWVegas/WWLib/bittype.h +++ b/Core/Libraries/Source/WWVegas/WWLib/bittype.h @@ -46,16 +46,9 @@ typedef unsigned short uint16; typedef signed char sint8; typedef signed short sint16; -// TheSuperHackers @build 10/02/2026 BenderAI -// uint32/sint32: Use fixed-width types on 64-bit platforms (long is 64-bit on Linux/macOS x64) -#if defined(__linux__) || defined(__APPLE__) - typedef uint32_t uint32; - typedef int32_t sint32; -#else - // Windows: long is always 32-bit - typedef unsigned long uint32; - typedef signed long sint32; -#endif +// GeneralsX @build 06/09/2026 fbraz3: Use uint32_t/int32_t on all platforms to match GameNetworkingSockets/Steamworks uint32 (unsigned int) and avoid MSVC C2371 redefinition +typedef uint32_t uint32; +typedef int32_t sint32; typedef unsigned int uint; typedef signed int sint; diff --git a/Generals/Code/CompatLib/Include/types_compat.h b/Generals/Code/CompatLib/Include/types_compat.h index e8d4330aa6a..12a35094e57 100644 --- a/Generals/Code/CompatLib/Include/types_compat.h +++ b/Generals/Code/CompatLib/Include/types_compat.h @@ -96,9 +96,9 @@ typedef float FLOAT; // 64-bit types now defined in bittype.h (_int64, __int64, _uint64, __uint64) // Removed duplicate definitions to avoid conflicts // typedef int64_t _int64; // REMOVED - use bittype.h -// typedef uint64_t _uint64; // REMOVED - use bittype.h -typedef int64_t int64; -typedef uint64_t uint64; +// GeneralsX @bugfix fbraz3 10/09/2026 Match Valve steamtypes.h declaration (long long) to prevent GCC conflicting typedef on Linux +typedef long long int64; +typedef unsigned long long uint64; typedef int32_t *LPARAM; typedef size_t WPARAM; diff --git a/Generals/Code/GameEngine/Source/Common/GameEngine.cpp b/Generals/Code/GameEngine/Source/Common/GameEngine.cpp index 7dc8343816e..24dba34e799 100644 --- a/Generals/Code/GameEngine/Source/Common/GameEngine.cpp +++ b/Generals/Code/GameEngine/Source/Common/GameEngine.cpp @@ -1037,7 +1037,7 @@ void GameEngine::checkAbnormalQuitting() UserPreferences pref; AsciiString userPrefFilename; - userPrefFilename.format("GeneralsOnline\\MiscPref%d.ini", stats.id); + userPrefFilename.format("GeneralsOnline/MiscPref%d.ini", stats.id); DEBUG_LOG(("using the file %s", userPrefFilename.str())); pref.load(userPrefFilename); diff --git a/Generals/Code/GameEngine/Source/Common/GlobalData.cpp b/Generals/Code/GameEngine/Source/Common/GlobalData.cpp index 7ed3e60c0a5..db49f33e9f2 100644 --- a/Generals/Code/GameEngine/Source/Common/GlobalData.cpp +++ b/Generals/Code/GameEngine/Source/Common/GlobalData.cpp @@ -1400,9 +1400,11 @@ AsciiString GlobalData::BuildUserDataPathFromIni() { const char* home = getenv("HOME"); if (home) { - std::filesystem::path path = std::filesystem::path(home) / "Library" / "Application Support" / "GeneralsX" / "Generals" / ""; + std::filesystem::path path = std::filesystem::path(home) / "Library" / "Application Support" / "GeneralsX" / "Generals"; std::filesystem::create_directories(path); userDataDir = path.string().c_str(); + if (!userDataDir.endsWith("/")) + userDataDir.concat('/'); } else { userDataDir = "./"; } @@ -1424,9 +1426,11 @@ AsciiString GlobalData::BuildUserDataPathFromIni() path = "."; } - path = path / "GeneralsX" / "Generals" / ""; + path = path / "GeneralsX" / "Generals"; std::filesystem::create_directories(path); userDataDir = path.string().c_str(); + if (!userDataDir.endsWith("/")) + userDataDir.concat('/'); } #endif diff --git a/Generals/Code/GameEngine/Source/GameClient/GUI/GUICallbacks/Menus/MainMenu.cpp b/Generals/Code/GameEngine/Source/GameClient/GUI/GUICallbacks/Menus/MainMenu.cpp index 45ade0eb6d9..f141231dd88 100644 --- a/Generals/Code/GameEngine/Source/GameClient/GUI/GUICallbacks/Menus/MainMenu.cpp +++ b/Generals/Code/GameEngine/Source/GameClient/GUI/GUICallbacks/Menus/MainMenu.cpp @@ -1464,7 +1464,11 @@ WindowMsgHandledType MainMenuSystem( GameWindow *window, UnsignedInt msg, dropDownWindows[DROPDOWN_MULTIPLAYER]->winHide(FALSE); TheTransitionHandler->reverse("MainMenuMultiPlayerMenuTransitionToNext"); +#if defined(SAGE_USE_NGMP) + TheShell->push( "Menus/GameSpyLoginProfile.wnd" ); +#else StartPatchCheck(); +#endif // localAnimateWindowManager->reverseAnimateWindow(); dropDown = DROPDOWN_NONE; diff --git a/Generals/Code/GameEngine/Source/GameClient/GUI/GUICallbacks/Menus/OptionsMenu.cpp b/Generals/Code/GameEngine/Source/GameClient/GUI/GUICallbacks/Menus/OptionsMenu.cpp index 3e6eeff66f2..9f0495037ce 100644 --- a/Generals/Code/GameEngine/Source/GameClient/GUI/GUICallbacks/Menus/OptionsMenu.cpp +++ b/Generals/Code/GameEngine/Source/GameClient/GUI/GUICallbacks/Menus/OptionsMenu.cpp @@ -1361,7 +1361,11 @@ void OptionsMenuInit( WindowLayout *layout, void *userData ) GameWindow *parent = TheWindowManager->winGetWindowFromId( nullptr, parentID ); TheWindowManager->winSetFocus( parent ); - if( (TheGameLogic->isInGame() && TheGameLogic->getGameMode() != GAME_SHELL) || TheGameSpyInfo ) + // GeneralsX @bugfix fbraz3 12/09/2026 Only disable controls when actually in-game or in an online staging room + Bool inGame = (TheGameLogic->isInGame() && TheGameLogic->getGameMode() != GAME_SHELL); + Bool inOnlineStaging = (TheGameSpyInfo && TheGameSpyInfo->getCurrentStagingRoom() != nullptr); + + if( inGame || inOnlineStaging ) { // disable controls that you can't change the options for in game comboBoxLANIP->winEnable(FALSE); diff --git a/Generals/Code/GameEngine/Source/GameClient/GUI/GUICallbacks/Menus/PopupHostGame.cpp b/Generals/Code/GameEngine/Source/GameClient/GUI/GUICallbacks/Menus/PopupHostGame.cpp index 4990b67408a..e092311da79 100644 --- a/Generals/Code/GameEngine/Source/GameClient/GUI/GUICallbacks/Menus/PopupHostGame.cpp +++ b/Generals/Code/GameEngine/Source/GameClient/GUI/GUICallbacks/Menus/PopupHostGame.cpp @@ -250,7 +250,7 @@ void PopulateCustomLadderComboBox() CustomMatchPreferences pref; AsciiString userPrefFilename; Int localProfile = TheGameSpyInfo->getLocalProfileID(); - userPrefFilename.format("GeneralsOnline\\CustomPref%d.ini", localProfile); + userPrefFilename.format("GeneralsOnline/CustomPref%d.ini", localProfile); pref.load(userPrefFilename); std::set usedLadders; diff --git a/Generals/Code/GameEngine/Source/GameClient/GUI/GUICallbacks/Menus/PopupJoinGame.cpp b/Generals/Code/GameEngine/Source/GameClient/GUI/GUICallbacks/Menus/PopupJoinGame.cpp index 193183b0665..29e2a217736 100644 --- a/Generals/Code/GameEngine/Source/GameClient/GUI/GUICallbacks/Menus/PopupJoinGame.cpp +++ b/Generals/Code/GameEngine/Source/GameClient/GUI/GUICallbacks/Menus/PopupJoinGame.cpp @@ -59,6 +59,9 @@ #include "GameClient/KeyDefs.h" #include "GameClient/GadgetTextEntry.h" #include "GameClient/GadgetStaticText.h" +#include "GameClient/GadgetPushButton.h" +#include "GameClient/GameText.h" +#include "GameClient/GameWindowManager.h" #include "GameNetwork/GameSpy/PeerDefs.h" #include "GameNetwork/GameSpy/PeerThread.h" #include "GameNetwork/GameSpyOverlay.h" @@ -71,9 +74,11 @@ static NameKeyType parentPopupID = NAMEKEY_INVALID; static NameKeyType textEntryGamePasswordID = NAMEKEY_INVALID; static NameKeyType buttonCancelID = NAMEKEY_INVALID; +static NameKeyType buttonOkID = NAMEKEY_INVALID; static GameWindow *parentPopup = nullptr; static GameWindow *textEntryGamePassword = nullptr; +static GameWindow *buttonOk = nullptr; static void joinGame( AsciiString password ); @@ -99,6 +104,29 @@ void PopupJoinGameInit( WindowLayout *layout, void *userData ) buttonCancelID = NAMEKEY("PopupJoinGame.wnd:ButtonCancel"); + buttonOkID = TheNameKeyGenerator->nameToKey("PopupJoinGame.wnd:ButtonOK"); + buttonOk = TheWindowManager->winGetWindowFromId(parentPopup, buttonOkID); + if (!buttonOk && parentPopup) + { + WinInstanceData instData; + instData.init(); + BitSet(instData.m_style, GWS_PUSH_BUTTON | GWS_MOUSE_TRACK); + instData.m_textLabelString = "GUI:OK"; + + buttonOk = TheWindowManager->gogoGadgetPushButton(parentPopup, + WIN_STATUS_ENABLED | WIN_STATUS_IMAGE, + 355, 314, 90, 26, + &instData, nullptr, TRUE); + if (buttonOk) + { + buttonOk->winSetWindowId(buttonOkID); + if (TheGameText) + { + GadgetButtonSetText(buttonOk, TheGameText->fetch("GUI:OK")); + } + } + } + GameSpyStagingRoom *ourRoom = TheGameSpyInfo->findStagingRoomByID(TheGameSpyInfo->getCurrentStagingRoomID()); if (ourRoom) GadgetStaticTextSetText(staticTextGameName, ourRoom->getGameName()); @@ -127,6 +155,28 @@ WindowMsgHandledType PopupJoinGameInput( GameWindow *window, UnsignedInt msg, Wi switch( key ) { + case KEY_ENTER: + case KEY_KPENTER: + { + if( BitIsSet( state, KEY_STATE_UP ) ) + { + if (textEntryGamePassword) + { + UnicodeString txtInput; + txtInput.set(GadgetTextEntryGetText( textEntryGamePassword )); + GadgetTextEntrySetText(textEntryGamePassword, UnicodeString::TheEmptyString); + txtInput.trim(); + if (!txtInput.isEmpty()) + { + AsciiString munkee; + munkee.translate(txtInput); + joinGame(munkee); + } + } + } + return MSG_HANDLED; + } + // ---------------------------------------------------------------------------------------- case KEY_ESC: { @@ -140,6 +190,7 @@ WindowMsgHandledType PopupJoinGameInput( GameWindow *window, UnsignedInt msg, Wi GameSpyCloseOverlay(GSOVERLAY_GAMEPASSWORD); SetLobbyAttemptHostJoin( FALSE ); parentPopup = nullptr; + buttonOk = nullptr; } // don't let key fall through anywhere else @@ -175,7 +226,7 @@ WindowMsgHandledType PopupJoinGameSystem( GameWindow *window, UnsignedInt msg, W //--------------------------------------------------------------------------------------------- case GWM_DESTROY: { - + buttonOk = nullptr; break; } @@ -190,6 +241,23 @@ WindowMsgHandledType PopupJoinGameSystem( GameWindow *window, UnsignedInt msg, W GameSpyCloseOverlay(GSOVERLAY_GAMEPASSWORD); SetLobbyAttemptHostJoin( FALSE ); parentPopup = nullptr; + buttonOk = nullptr; + } + else if (controlID == buttonOkID) + { + if (textEntryGamePassword) + { + UnicodeString txtInput; + txtInput.set(GadgetTextEntryGetText( textEntryGamePassword )); + GadgetTextEntrySetText(textEntryGamePassword, UnicodeString::TheEmptyString); + txtInput.trim(); + if (!txtInput.isEmpty()) + { + AsciiString munkee; + munkee.translate(txtInput); + joinGame(munkee); + } + } } break; } @@ -249,6 +317,7 @@ static void joinGame( AsciiString password ) GameSpyCloseOverlay(GSOVERLAY_GAMEPASSWORD); SetLobbyAttemptHostJoin( FALSE ); parentPopup = nullptr; + buttonOk = nullptr; return; } PeerRequest req; @@ -260,4 +329,5 @@ static void joinGame( AsciiString password ) DEBUG_LOG(("Attempting to join game %d(%ls) with password [%s]", ourRoom->getID(), ourRoom->getGameName().str(), password.str())); GameSpyCloseOverlay(GSOVERLAY_GAMEPASSWORD); parentPopup = nullptr; + buttonOk = nullptr; } diff --git a/Generals/Code/GameEngine/Source/GameClient/GUI/GUICallbacks/Menus/PopupPlayerInfo.cpp b/Generals/Code/GameEngine/Source/GameClient/GUI/GUICallbacks/Menus/PopupPlayerInfo.cpp index 43c25619a25..baa2d5b8ad3 100644 --- a/Generals/Code/GameEngine/Source/GameClient/GUI/GUICallbacks/Menus/PopupPlayerInfo.cpp +++ b/Generals/Code/GameEngine/Source/GameClient/GUI/GUICallbacks/Menus/PopupPlayerInfo.cpp @@ -149,7 +149,7 @@ static Int getTotalDisconnectsFromFile(Int playerID) UserPreferences pref; AsciiString userPrefFilename; - userPrefFilename.format("GeneralsOnline\\MiscPref%d.ini", playerID); + userPrefFilename.format("GeneralsOnline/MiscPref%d.ini", playerID); DEBUG_LOG(("setPersistentDataCallback - reading stats from file %s", userPrefFilename.str())); pref.load(userPrefFilename); @@ -217,7 +217,7 @@ void GetAdditionalDisconnectsFromUserFile(PSPlayerStats *stats) UserPreferences pref; AsciiString userPrefFilename; - userPrefFilename.format("GeneralsOnline\\MiscPref%d.ini", stats->id); + userPrefFilename.format("GeneralsOnline/MiscPref%d.ini", stats->id); DEBUG_LOG(("setPersistentDataCallback - reading stats from file %s", userPrefFilename.str())); pref.load(userPrefFilename); @@ -762,9 +762,12 @@ void PopulatePlayerInfoWindows( AsciiString parentWindowName ) Int currentRank = 0; Int rankPoints = CalculateRank(stats); Int i = 0; - while( rankPoints >= TheRankPointValues->m_ranks[i + 1]) - ++i; - currentRank = i; + if (TheRankPointValues) + { + while (i + 1 < MAX_RANKS && rankPoints >= TheRankPointValues->m_ranks[i + 1]) + ++i; + currentRank = i; + } PerGeneralMap::iterator it; Int numWins = 0; @@ -971,7 +974,15 @@ void PopulatePlayerInfoWindows( AsciiString parentWindowName ) } else { - GadgetProgressBarSetProgress(win, 100 * INT_TO_REAL(rankPoints - TheRankPointValues->m_ranks[currentRank])/( TheRankPointValues->m_ranks[currentRank + 1] - TheRankPointValues->m_ranks[currentRank])); + Int diff = TheRankPointValues->m_ranks[currentRank + 1] - TheRankPointValues->m_ranks[currentRank]; + if (diff > 0) + { + GadgetProgressBarSetProgress(win, 100 * INT_TO_REAL(rankPoints - TheRankPointValues->m_ranks[currentRank]) / INT_TO_REAL(diff)); + } + else + { + GadgetProgressBarSetProgress(win, 100); + } } } win = findWindow(nullptr, parentWindowName, "WinRank"); diff --git a/Generals/Code/GameEngine/Source/GameClient/GUI/GUICallbacks/Menus/WOLLobbyMenu.cpp b/Generals/Code/GameEngine/Source/GameClient/GUI/GUICallbacks/Menus/WOLLobbyMenu.cpp index a3e54b0294d..05ef0610a72 100644 --- a/Generals/Code/GameEngine/Source/GameClient/GUI/GUICallbacks/Menus/WOLLobbyMenu.cpp +++ b/Generals/Code/GameEngine/Source/GameClient/GUI/GUICallbacks/Menus/WOLLobbyMenu.cpp @@ -308,9 +308,12 @@ static void playerTooltip(GameWindow *window, Int rank = 0; Int i = 0; - while( info->m_rankPoints >= TheRankPointValues->m_ranks[i + 1]) - ++i; - rank = i; + if (TheRankPointValues) + { + while (i + 1 < MAX_RANKS && info->m_rankPoints >= TheRankPointValues->m_ranks[i + 1]) + ++i; + rank = i; + } AsciiString sideName = "GUI:RandomSide"; if (info->m_side > 0) { @@ -388,9 +391,12 @@ const Image* LookupSmallRankImage(Int side, Int rankPoints) Int rank = 0; Int i = 0; - while( rankPoints >= TheRankPointValues->m_ranks[i + 1]) - ++i; - rank = i; + if (TheRankPointValues) + { + while (i + 1 < MAX_RANKS && rankPoints >= TheRankPointValues->m_ranks[i + 1]) + ++i; + rank = i; + } if (rank < 0 || rank >= 10) return nullptr; diff --git a/Generals/Code/GameEngine/Source/GameClient/GUI/GUICallbacks/Menus/WOLLoginMenu.cpp b/Generals/Code/GameEngine/Source/GameClient/GUI/GUICallbacks/Menus/WOLLoginMenu.cpp index 6edaba07101..21a2e7e0bac 100644 --- a/Generals/Code/GameEngine/Source/GameClient/GUI/GUICallbacks/Menus/WOLLoginMenu.cpp +++ b/Generals/Code/GameEngine/Source/GameClient/GUI/GUICallbacks/Menus/WOLLoginMenu.cpp @@ -123,9 +123,11 @@ static AsciiString obfuscate( AsciiString in ) if (!*c2) c2 = xorWord; if (*c != *c2) - *c = *c++ ^ *c2++; - else - c++, c2++; + { + *c = *c ^ *c2; + } + c++; + c2++; } AsciiString out = buf; delete[] buf; diff --git a/Generals/Code/GameEngine/Source/GameClient/GUI/GUICallbacks/Menus/WOLWelcomeMenu.cpp b/Generals/Code/GameEngine/Source/GameClient/GUI/GUICallbacks/Menus/WOLWelcomeMenu.cpp index 403d17c9bea..fbde2db81f2 100644 --- a/Generals/Code/GameEngine/Source/GameClient/GUI/GUICallbacks/Menus/WOLWelcomeMenu.cpp +++ b/Generals/Code/GameEngine/Source/GameClient/GUI/GUICallbacks/Menus/WOLWelcomeMenu.cpp @@ -34,6 +34,8 @@ #include "gamespy/peer/peer.h" #include "Common/GameEngine.h" +#include "Common/AudioEventRTS.h" +#include "Common/GameAudio.h" #include "Common/GameSpyMiscPreferences.h" #include "Common/CustomMatchPreferences.h" #include "Common/GlobalData.h" @@ -66,11 +68,80 @@ #include "GameNetwork/GameSpy/MainMenuUtils.h" #include "GameNetwork/WOLBrowser/WebBrowser.h" +#if defined(_WIN32) +#include +#include +#else +#include +#endif + +#include +#include + // PRIVATE DATA /////////////////////////////////////////////////////////////////////////////////// static Bool isShuttingDown = FALSE; static Bool buttonPushed = FALSE; static const char *nextScreen = nullptr; +// GeneralsX @feature fbraz3 03/09/2026 Map MOTD listbox rows to clickable URLs +static std::map s_motdRowUrls; + +// GeneralsX @refactor fbraz3 08/09/2026 Platform URL opening (ShellExecute on Windows, SDL_OpenURL on POSIX) +static void OpenBrowserURL(const std::string& url) +{ +#if defined(_WIN32) + ShellExecuteA(NULL, "open", url.c_str(), NULL, NULL, SW_SHOWNORMAL); +#else + SDL_OpenURL(url.c_str()); +#endif +} + +// GeneralsX @feature fbraz3 03/09/2026 Parse raw URLs or Markdown links [text](url) from MOTD line +static std::string ExtractURLFromLine(std::string& inOutText) +{ + // Check for Markdown link: [display text](http://... or https://...) + size_t openBracket = inOutText.find('['); + size_t closeBracket = (openBracket != std::string::npos) ? inOutText.find(']', openBracket + 1) : std::string::npos; + if (openBracket != std::string::npos && closeBracket != std::string::npos && + closeBracket + 1 < inOutText.length() && inOutText[closeBracket + 1] == '(') + { + size_t openParen = closeBracket + 1; + size_t closeParen = inOutText.find(')', openParen + 1); + if (closeParen != std::string::npos) + { + std::string url = inOutText.substr(openParen + 1, closeParen - openParen - 1); + if (url.rfind("http://", 0) == 0 || url.rfind("https://", 0) == 0) + { + std::string displayText = inOutText.substr(openBracket + 1, closeBracket - openBracket - 1); + inOutText = inOutText.substr(0, openBracket) + displayText + inOutText.substr(closeParen + 1); + return url; + } + } + } + + // Check for raw URL: http:// or https:// + size_t pos = inOutText.find("http://"); + if (pos == std::string::npos) + pos = inOutText.find("https://"); + if (pos == std::string::npos) + return ""; + + size_t end = pos; + while (end < inOutText.length() && !std::isspace(static_cast(inOutText[end])) && + inOutText[end] != '"' && inOutText[end] != '\'' && inOutText[end] != '<' && inOutText[end] != '>' && + inOutText[end] != '`') + { + end++; + } + while (end > pos && (inOutText[end - 1] == '.' || inOutText[end - 1] == ',' || + inOutText[end - 1] == ')' || inOutText[end - 1] == ']' || + inOutText[end - 1] == ';')) + { + end--; + } + return inOutText.substr(pos, end - pos); +} + // window ids ------------------------------------------------------------------------------ static NameKeyType parentWOLWelcomeID = NAMEKEY_INVALID; static NameKeyType buttonBackID = NAMEKEY_INVALID; @@ -109,6 +180,7 @@ static GameWindow *staticTextHighscoreRank = nullptr; static GameWindow *staticTextHighscorePoints = nullptr; static UnicodeString gServerName; +static Bool s_welcomeAudioPlayed = FALSE; void updateServerDisplay(UnicodeString serverName) { if (staticTextServerName) @@ -197,6 +269,10 @@ static void shutdownComplete( WindowLayout *layout ) { TheShell->push(nextScreen); } + else + { + s_welcomeAudioPlayed = FALSE; + } nextScreen = nullptr; @@ -231,6 +307,7 @@ static void updateNumPlayersOnline() if (listboxInfo && TheGameSpyInfo) { + s_motdRowUrls.clear(); GadgetListBoxReset(listboxInfo); AsciiString aLine; UnicodeString line; @@ -267,6 +344,7 @@ static void updateNumPlayersOnline() } Color c = GameSpyColor[GSCOLOR_MOTD]; + bool hasCustomColor = false; if (aLine.startsWith("\\\\")) { aLine = aLine.str()+1; @@ -282,10 +360,28 @@ static void updateNumPlayersOnline() c = GameMakeColor(r, g, b, a); DEBUG_LOG(("MOTD line '%s' has color %X", aLine.str(), c)); aLine = aLine.str() + 9; + hasCustomColor = true; } + + // GeneralsX @feature fbraz3 03/09/2026 Detect clickable URL or Markdown link in MOTD + std::string rawLine(aLine.str()); + std::string detectedUrl = ExtractURLFromLine(rawLine); + if (!detectedUrl.empty()) + { + if (!hasCustomColor) + { + c = GameMakeColor(100, 180, 255, 255); // Link highlight blue + } + aLine = rawLine.c_str(); + } + line = UnicodeString(MultiByteToWideCharSingleLine(aLine.str()).c_str()); - GadgetListBoxAddEntryText(listboxInfo, line, c, -1, -1); + Int row = GadgetListBoxAddEntryText(listboxInfo, line, c, -1, -1); + if (!detectedUrl.empty() && row >= 0) + { + s_motdRowUrls[row] = detectedUrl; + } } } } @@ -541,6 +637,13 @@ void WOLWelcomeMenuInit( WindowLayout *layout, void *userData ) raiseMessageBoxes = TRUE; TheTransitionHandler->setGroup("WOLWelcomeMenuFade"); + // GeneralsX @feature Play classic "Welcome to Generals Online" voice line once per login session + if (!s_welcomeAudioPlayed && !GameSpyIsOverlayOpen(GSOVERLAY_LOCALESELECT) && TheAudio) + { + AudioEventRTS welcomeSound("WelcomeToGeneralsOnline"); + TheAudio->addAudioEvent(&welcomeSound); + s_welcomeAudioPlayed = TRUE; + } } //------------------------------------------------------------------------------------------------- @@ -549,6 +652,7 @@ void WOLWelcomeMenuInit( WindowLayout *layout, void *userData ) void WOLWelcomeMenuShutdown( WindowLayout *layout, void *userData ) { listboxInfo = nullptr; + s_motdRowUrls.clear(); delete TheFirewallHelper; TheFirewallHelper = nullptr; @@ -604,6 +708,14 @@ void WOLWelcomeMenuUpdate( WindowLayout * layout, void *userData) } } + // GeneralsX @feature Play classic "Welcome to Generals Online" once locale overlay is closed + if (!isShuttingDown && !buttonPushed && !s_welcomeAudioPlayed && !GameSpyIsOverlayOpen(GSOVERLAY_LOCALESELECT) && TheAudio) + { + AudioEventRTS welcomeSound("WelcomeToGeneralsOnline"); + TheAudio->addAudioEvent(&welcomeSound); + s_welcomeAudioPlayed = TRUE; + } + if (TheShell->isAnimFinished() && !buttonPushed && TheGameSpyPeerMessageQueue) { HandleBuddyResponses(); @@ -754,6 +866,27 @@ WindowMsgHandledType WOLWelcomeMenuSystem( GameWindow *window, UnsignedInt msg, return MSG_HANDLED; } + // GeneralsX @feature fbraz3 03/09/2026 Open MOTD link in system browser on row click + case GLM_SELECTED: + { + GameWindow *control = (GameWindow *)mData1; + Int controlID = control ? control->winGetWindowId() : NAMEKEY_INVALID; + Int selected = (Int)mData2; + + if (controlID == listboxInfoID && selected >= 0) + { + auto it = s_motdRowUrls.find(selected); + if (it != s_motdRowUrls.end() && !it->second.empty()) + { + fprintf(stderr, "[WOLWelcomeMenu] Opening MOTD URL: %s\n", it->second.c_str()); + fflush(stderr); + OpenBrowserURL(it->second); + GadgetListBoxSetSelected(listboxInfo, -1); + } + } + break; + } + case GBM_SELECTED: { if (buttonPushed) diff --git a/Generals/Code/GameEngine/Source/GameLogic/System/GameLogic.cpp b/Generals/Code/GameEngine/Source/GameLogic/System/GameLogic.cpp index 562b5b231c3..94db893d7c0 100644 --- a/Generals/Code/GameEngine/Source/GameLogic/System/GameLogic.cpp +++ b/Generals/Code/GameEngine/Source/GameLogic/System/GameLogic.cpp @@ -2251,7 +2251,7 @@ void GameLogic::loadMapINI( AsciiString mapName ) char fullFledgeFilename[_MAX_PATH]; - snprintf(fullFledgeFilename, ARRAY_SIZE(fullFledgeFilename), "%s\\map.ini", filename); + snprintf(fullFledgeFilename, ARRAY_SIZE(fullFledgeFilename), "%s/map.ini", filename); if (TheFileSystem->doesFileExist(fullFledgeFilename)) { DEBUG_LOG(("Loading map.ini")); INI ini; @@ -2261,7 +2261,7 @@ void GameLogic::loadMapINI( AsciiString mapName ) // TheSuperHackers @todo Implement ini load directory for map folder. // Requires adjustments in map transfer. - snprintf(fullFledgeFilename, ARRAY_SIZE(fullFledgeFilename), "%s\\solo.ini", filename); + snprintf(fullFledgeFilename, ARRAY_SIZE(fullFledgeFilename), "%s/solo.ini", filename); if (TheFileSystem->doesFileExist(fullFledgeFilename)) { DEBUG_LOG(("Loading solo.ini")); INI ini; diff --git a/Generals/Code/GameEngine/Source/GameNetwork/GUIUtil.cpp b/Generals/Code/GameEngine/Source/GameNetwork/GUIUtil.cpp index 15f74efc4ce..13cd80cfd58 100644 --- a/Generals/Code/GameEngine/Source/GameNetwork/GUIUtil.cpp +++ b/Generals/Code/GameEngine/Source/GameNetwork/GUIUtil.cpp @@ -461,18 +461,25 @@ void UpdateSlotList( GameInfo *myGame, GameWindow *comboPlayer[], GadgetComboBoxSetSelectedPos(comboPlayer[i], slot->getState(), TRUE); if( buttonAccept && buttonAccept[i] ) buttonAccept[i]->winHide(TRUE); + + // GeneralsX @refactor fbraz3 25/08/2026 Support host migration and AI slot names + GadgetComboBoxSetText(comboPlayer[i], slot->getName()); } -/* - if (myGame->getLocalSlotNum() == i && i!=0) + if (myGame->getLocalSlotNum() == i) { if (comboPlayer[i]) - comboPlayer[i]->winEnable( TRUE ); + comboPlayer[i]->winEnable( FALSE ); } - else*/ if (!myGame->amIHost()) + else if (!myGame->amIHost()) { if (comboPlayer[i]) comboPlayer[i]->winEnable( FALSE ); } + else + { + if (comboPlayer[i]) + comboPlayer[i]->winEnable( TRUE ); + } //if( i == myGame->getLocalSlotNum()) if((comboColor[i] != nullptr) && BitIsSet(comboColor[i]->winGetStatus(), WIN_STATUS_ENABLED)) PopulateColorComboBox(i, comboColor, myGame, myGame->getConstSlot(i)->getPlayerTemplate() == PLAYERTEMPLATE_OBSERVER); diff --git a/GeneralsMD/Code/CompatLib/Include/types_compat.h b/GeneralsMD/Code/CompatLib/Include/types_compat.h index e8d4330aa6a..12a35094e57 100644 --- a/GeneralsMD/Code/CompatLib/Include/types_compat.h +++ b/GeneralsMD/Code/CompatLib/Include/types_compat.h @@ -96,9 +96,9 @@ typedef float FLOAT; // 64-bit types now defined in bittype.h (_int64, __int64, _uint64, __uint64) // Removed duplicate definitions to avoid conflicts // typedef int64_t _int64; // REMOVED - use bittype.h -// typedef uint64_t _uint64; // REMOVED - use bittype.h -typedef int64_t int64; -typedef uint64_t uint64; +// GeneralsX @bugfix fbraz3 10/09/2026 Match Valve steamtypes.h declaration (long long) to prevent GCC conflicting typedef on Linux +typedef long long int64; +typedef unsigned long long uint64; typedef int32_t *LPARAM; typedef size_t WPARAM; diff --git a/GeneralsMD/Code/GameEngine/CMakeLists.txt b/GeneralsMD/Code/GameEngine/CMakeLists.txt index 56efe42adae..e3576691e56 100644 --- a/GeneralsMD/Code/GameEngine/CMakeLists.txt +++ b/GeneralsMD/Code/GameEngine/CMakeLists.txt @@ -1111,6 +1111,18 @@ set(GAMEENGINE_SRC # Source/GameNetwork/GameSpy/Thread/ThreadUtils.cpp # Source/GameNetwork/GameSpyOverlay.cpp Source/GameNetwork/GUIUtil.cpp + Include/GameNetwork/GeneralsOnline/OnlineServices_Manager.h + Include/GameNetwork/GeneralsOnline/OnlineServices_Auth.h + Include/GameNetwork/GeneralsOnline/OnlineServices_LobbyInterface.h + Include/GameNetwork/GeneralsOnline/OnlineServices_RoomsInterface.h + Include/GameNetwork/GeneralsOnline/OnlineServices_StatsInterface.h + Include/GameNetwork/GeneralsOnline/OnlineServices_SocialInterface.h + Include/GameNetwork/GeneralsOnline/NGMP_types.h + Include/GameNetwork/GeneralsOnline/NGMP_interfaces.h + Include/GameNetwork/GeneralsOnline/NGMPGame.h + Include/GameNetwork/GeneralsOnline/NGMP_Helpers.h + Include/GameNetwork/GeneralsOnline/NGMPWebSocket.h + Include/GameNetwork/GeneralsOnline/ngmp_curl_utils.h # Source/GameNetwork/IPEnumeration.cpp # Source/GameNetwork/LANAPI.cpp # Source/GameNetwork/LANAPICallbacks.cpp @@ -1148,6 +1160,22 @@ else() ) endif() +if(SAGE_USE_NGMP) + list(APPEND GAMEENGINE_SRC + Source/GameNetwork/GeneralsOnline/OnlineServices_Init.cpp + Source/GameNetwork/GeneralsOnline/OnlineServices_Auth.cpp + Source/GameNetwork/GeneralsOnline/OnlineServices_Manager.cpp + Source/GameNetwork/GeneralsOnline/OnlineServices_WebSocket.cpp + Source/GameNetwork/GeneralsOnline/OnlineServices_LobbyInterface.cpp + Source/GameNetwork/GeneralsOnline/OnlineServices_RoomsInterface.cpp + Source/GameNetwork/GeneralsOnline/OnlineServices_StatsInterface.cpp + Source/GameNetwork/GeneralsOnline/OnlineServices_SocialInterface.cpp + Source/GameNetwork/GeneralsOnline/NGMPGame.cpp + Source/GameNetwork/GeneralsOnline/NGMP_Helpers.cpp + Source/GameNetwork/GeneralsOnline/NetworkMesh.cpp + Source/GameNetwork/GeneralsOnline/NextGenTransport.cpp + ) +endif() add_library(z_gameengine STATIC) diff --git a/GeneralsMD/Code/GameEngine/Include/GameNetwork/GeneralsOnline/NGMPGame.h b/GeneralsMD/Code/GameEngine/Include/GameNetwork/GeneralsOnline/NGMPGame.h new file mode 100644 index 00000000000..03799515cd8 --- /dev/null +++ b/GeneralsMD/Code/GameEngine/Include/GameNetwork/GeneralsOnline/NGMPGame.h @@ -0,0 +1,160 @@ +// GeneralsX @feature GeneralsOnline NGMPGame header +#pragma once + +#include "GameNetwork/GameInfo.h" +#include "GameNetwork/GeneralsOnline/NGMP_types.h" +#include + +struct LobbyEntry; + +class NGMPGameSlot : public GameSlot +{ +public: + NGMPGameSlot(); + Int getProfileID(void) const { return m_profileID; } + void setProfileID(Int id) { m_profileID = id; } + Int getWins(void) const { return m_wins; } + Int getLosses(void) const { return m_losses; } + void setWins(Int wins) { m_wins = wins; } + void setLosses(Int losses) { m_losses = losses; } + + Int getSlotRankPoints(void) const { return m_rankPoints; } + Int getFavoriteSide(void) const { return m_favoriteSide; } + void setSlotRankPoints(Int val) { m_rankPoints = val; } + void setFavoriteSide(Int val) { m_favoriteSide = val; } + + void setPingString(UnicodeString pingStr) { m_pingStr = pingStr; } + void setPingString(AsciiString pingStr) { m_pingStr.translate(pingStr); } + inline UnicodeString getPingString(void) const { return m_pingStr; } + inline Int getPingAsInt(void) const { return m_pingInt; } + + int64_t m_userID = -1; + + void UpdateLatencyFromConnection(UnicodeString pingStr, int ping) + { + m_pingStr = pingStr; + m_pingInt = ping; + } + +protected: + Int m_profileID; + UnicodeString m_pingStr; + Int m_pingInt; + Int m_wins, m_losses; + Int m_rankPoints, m_favoriteSide; +}; + +class NGMPGame : public GameInfo +{ +private: + NGMPGameSlot m_Slots[MAX_SLOTS]; + UnicodeString m_gameName; + Int m_id; + Bool m_requiresPassword; + Bool m_allowObservers; + UnsignedInt m_version; + UnsignedInt m_exeCRC; + UnsignedInt m_iniCRC; + Bool m_isQM; + + AsciiString m_ladderIP; + AsciiString m_pingStr; + Int m_pingInt; + UnsignedShort m_ladderPort; + + Int m_reportedNumPlayers; + Int m_reportedMaxPlayers; + Int m_reportedNumObservers; + + bool m_bHasCommittedOutcome = false; + bool m_bCommittingOutcome = false; + std::chrono::system_clock::time_point matchStartTime; + + bool m_bCountdownStarted = false; + int64_t m_countdownStartTime = -1; + int64_t m_countdownLastCheckTime = -1; + +public: + NGMPGame(); + virtual ~NGMPGame(); + virtual void reset(void); + + bool HasCommittedOutcome() const { return m_bHasCommittedOutcome; } + bool IsCommittingOutcome() const { return m_bCommittingOutcome; } + void SetCommittingOutcome(bool committing) { m_bCommittingOutcome = committing; } + void SetHasCommittedOutcome(bool committed = true) { m_bHasCommittedOutcome = committed; m_bCommittingOutcome = false; } + + void StartCountdown(); + void StopCountdown() + { + m_bCountdownStarted = false; + m_countdownStartTime = -1; + m_countdownLastCheckTime = -1; + } + bool IsCountdownStarted() const { return m_bCountdownStarted; } + int64_t GetCountdownStartTime() const { return m_countdownStartTime; } + void UpdateCountdownLastCheckTime() + { + m_countdownLastCheckTime = std::chrono::duration_cast(std::chrono::system_clock::now().time_since_epoch()).count(); + } + int GetTotalCountdownDuration() const { return 5; } + int64_t GetCountdownLastCheckTime() const { return m_countdownLastCheckTime; } + + void StartMatchTimer() { matchStartTime = std::chrono::system_clock::now(); } + std::chrono::system_clock::time_point GetStartTime() { return matchStartTime; } + + void SyncWithLobby(LobbyEntry& lobby); + void UpdateSlotsFromCurrentLobby(); + + void cleanUpSlotPointers(void); + inline void setID(Int id) { m_id = id; } + inline Int getID(void) const { return m_id; } + + inline void setHasPassword(Bool val) { m_requiresPassword = val; } + inline Bool getHasPassword(void) const { return m_requiresPassword; } + inline void setAllowObservers(Bool val) { m_allowObservers = val; } + inline Bool getAllowObservers(void) const { return m_allowObservers; } + Bool canKickOnObserversDisabled(); + + inline void setVersion(UnsignedInt val) { m_version = val; } + inline UnsignedInt getVersion(void) const { return m_version; } + inline void setExeCRC(UnsignedInt val) { m_exeCRC = val; } + inline UnsignedInt getExeCRC(void) const { return m_exeCRC; } + inline void setIniCRC(UnsignedInt val) { m_iniCRC = val; } + inline UnsignedInt getIniCRC(void) const { return m_iniCRC; } + + inline void setReportedNumPlayers(Int val) { m_reportedNumPlayers = val; } + inline Int getReportedNumPlayers(void) const { return m_reportedNumPlayers; } + inline void setReportedMaxPlayers(Int val) { m_reportedMaxPlayers = val; } + inline Int getReportedMaxPlayers(void) const { return m_reportedMaxPlayers; } + inline void setReportedNumObservers(Int val) { m_reportedNumObservers = val; } + inline Int getReportedNumObservers(void) const { return m_reportedNumObservers; } + + inline void setLadderIP(AsciiString ladderIP) { m_ladderIP = ladderIP; } + inline AsciiString getLadderIP(void) const { return m_ladderIP; } + inline void setLadderPort(UnsignedShort ladderPort) { m_ladderPort = ladderPort; } + inline UnsignedShort getLadderPort(void) const { return m_ladderPort; } + void setPingString(AsciiString pingStr); + inline AsciiString getPingString(void) const { return m_pingStr; } + inline Int getPingAsInt(void) const { return m_pingInt; } + + virtual Bool amIHost(void) const; + + NGMPGameSlot* getGameSpySlot(Int index); + + AsciiString generateGameSpyGameResultsPacket(void); + AsciiString generateLadderGameResultsPacket(void); + void markGameAsQM(void) { m_isQM = TRUE; } + Bool isQMGame(void) { return m_isQM; } + + virtual void init(void); + virtual void resetAccepted(void); + virtual void startGame(Int gameID); + void launchGame(void); + virtual Int getLocalSlotNum(void) const override; + + inline void setGameName(UnicodeString name) { m_gameName = name; } + inline UnicodeString getGameName(void) const { return m_gameName; } +}; + +extern NGMPGame* TheNGMPGame; diff --git a/GeneralsMD/Code/GameEngine/Include/GameNetwork/GeneralsOnline/NGMPWebSocket.h b/GeneralsMD/Code/GameEngine/Include/GameNetwork/GeneralsOnline/NGMPWebSocket.h new file mode 100644 index 00000000000..578e2cfef41 --- /dev/null +++ b/GeneralsMD/Code/GameEngine/Include/GameNetwork/GeneralsOnline/NGMPWebSocket.h @@ -0,0 +1,100 @@ +// GeneralsX @feature GeneralsOnline NGMP Chat WebSocket session header +// Manages a persistent WebSocket connection to the NGMP backend chat server. + +#ifndef NGMP_WEBSOCKET_H +#define NGMP_WEBSOCKET_H + +#include + +#pragma push_macro("min") +#pragma push_macro("max") +#undef min +#undef max + +#include +#include +#include +#include +#include + +#pragma pop_macro("max") +#pragma pop_macro("min") + +namespace NGMP { + +enum class EWebSocketMessageID { + UNKNOWN = -1, + NETWORK_ROOM_CHAT_FROM_CLIENT = 1, + NETWORK_ROOM_CHAT_FROM_SERVER = 2, + NETWORK_ROOM_CHANGE_ROOM = 3, + NETWORK_ROOM_MEMBER_LIST_UPDATE = 4, + NETWORK_ROOM_MARK_READY = 5, + LOBBY_CURRENT_LOBBY_UPDATE = 6, + NETWORK_ROOM_LOBBY_LIST_UPDATE = 7, + ANTICHEAT_MESSAGE = 8, + PLAYER_NAME_CHANGE = 9, + LOBBY_ROOM_CHAT_FROM_CLIENT = 10, + LOBBY_CHAT_FROM_SERVER = 11, + NETWORK_SIGNAL = 12, + START_GAME = 13, + PING = 14, + PONG = 15, + PROBE = 16, + NETWORK_CONNECTION_START_SIGNALLING = 17, + NETWORK_CONNECTION_DISCONNECT_PLAYER = 18, + NETWORK_CONNECTION_CLIENT_REQUEST_SIGNALLING = 19, + MATCHMAKING_ACTION_JOIN_PREARRANGED_LOBBY = 20, + MATCHMAKING_ACTION_START_GAME = 21, + MATCHMAKING_MESSAGE = 22, + START_GAME_COUNTDOWN_STARTED = 23, + LOBBY_REMOVE_PASSWORD = 24, + LOBBY_CHANGE_PASSWORD = 25, + FULL_MESH_CONNECTIVITY_CHECK_HOST_REQUESTS_BEGIN = 26, + FULL_MESH_CONNECTIVITY_CHECK_RESPONSE = 27, + FULL_MESH_CONNECTIVITY_CHECK_RESPONSE_COMPLETE_TO_HOST = 28, + SOCIAL_NEW_FRIEND_REQUEST = 29, + SOCIAL_FRIEND_CHAT_MESSAGE_CLIENT_TO_SERVER = 30, + SOCIAL_FRIEND_CHAT_MESSAGE_SERVER_TO_CLIENT = 31, + SOCIAL_FRIEND_ONLINE_STATUS_CHANGED = 32, + SOCIAL_SUBSCRIBE_REALTIME_UPDATES = 33, + SOCIAL_UNSUBSCRIBE_REALTIME_UPDATES = 34, + SOCIAL_FRIENDS_OVERALL_STATUS_UPDATE = 35, + SOCIAL_FRIEND_FRIEND_REQUEST_ACCEPTED_BY_TARGET = 36, +}; + +using GenericMessageCallback = std::function; + +class NGMPWebSocket { +public: + NGMPWebSocket() = default; + ~NGMPWebSocket(); + + // Connect to the WebSocket endpoint (blocking until connected or failed) + bool connect(const std::string& wsUrl, const std::string& authToken); + + // Disconnect from the WebSocket and stop the receiver thread + void disconnect(); + + // Returns true if currently connected + bool isConnected() const { return m_running.load(); } + + // Send a generic string payload (like a serialized JSON) + bool sendPayload(const std::string& payload); + + // Set the generic callback invoked on the receiver thread when any message arrives + // The callback receives the raw JSON and must post to the NGMP event queue + void setMessageCallback(GenericMessageCallback cb) { m_messageCallback = std::move(cb); } + +private: + void receiveLoop(); + + CURL* m_curl = nullptr; + std::thread m_recvThread; + std::atomic m_running = false; + GenericMessageCallback m_messageCallback; + mutable std::mutex m_sendMutex; +}; + +} // namespace NGMP + +#endif // NGMP_WEBSOCKET_H diff --git a/GeneralsMD/Code/GameEngine/Include/GameNetwork/GeneralsOnline/NGMP_Helpers.h b/GeneralsMD/Code/GameEngine/Include/GameNetwork/GeneralsOnline/NGMP_Helpers.h new file mode 100644 index 00000000000..679d9a52ef5 --- /dev/null +++ b/GeneralsMD/Code/GameEngine/Include/GameNetwork/GeneralsOnline/NGMP_Helpers.h @@ -0,0 +1,96 @@ +// GeneralsX @feature GeneralsOnline NGMP Helpers header +// Cross-platform abstraction for OS primitives, timing, and storage. + +#ifndef NGMP_HELPERS_H +#define NGMP_HELPERS_H + +#include +#include + +#include "Common/UnicodeString.h" + +namespace NGMP { + +#ifndef NGMP_CLIENT_ID +#if defined(__APPLE__) +#define NGMP_CLIENT_ID "generalsx_macos" +#elif defined(__linux__) +#define NGMP_CLIENT_ID "generalsx_linux" +#elif defined(_WIN32) +#define NGMP_CLIENT_ID "generalsx_windows" +#else +#define NGMP_CLIENT_ID "gen_online_30hz" +#endif +#endif + +// Returns time in milliseconds since application start using SDL3/chrono primitives +uint32_t GetTicks(); + +// Pauses execution for the specified milliseconds +void Delay(uint32_t ms); + +// Returns absolute user storage directory path for GeneralsOnline data +std::string GetStoragePath(); + +// Saves authentication token to local user storage +bool SaveAuthToken(const std::string& token); + +// Loads authentication token from local user storage +std::string LoadAuthToken(); + +// Saves refresh token to local user storage +bool SaveRefreshToken(const std::string& token); + +// Loads refresh token from local user storage +std::string LoadRefreshToken(); + +// Returns true if SSL (HTTPS/WSS) is enabled +bool IsSSLEnabled(); + +// Returns default server WS endpoint URL +std::string GetServerWSEndpoint(); + +// Returns default server REST endpoint URL (e.g. http://host:port) +std::string GetServerRESTEndpoint(); + +// Returns true if running in a local development environment (localhost, 192.168.*, 10.*) +bool IsDevelopment(); + +// Returns server environment name ("dev" or "live") based on IsDevelopment() +std::string GetServerEnv(); + +// Returns sanitized URL with hostname masked by '****' in production environments +std::string SanitizeURL(const std::string& url); + +// Returns web portal URL for OAuth login and web features (or defaults to GetServerRESTEndpoint()) +std::string GetWebPortalURL(); + +// Returns the MOTD URL (from NGMP_MOTD_URL env or default ${GetWebPortalURL()}/motd.txt) +std::string GetMOTDURL(); + +// Fetches the MOTD from GetMOTDURL() and sets it into TheGameSpyInfo +void FetchMOTD(); + +// Returns a full named API endpoint URL (e.g. /env/{env}/contract/1/CheckLogin) +std::string GetAPIEndpoint(const char* szEndpoint); + +// Returns the browser login URL for a given gamecode +std::string GetBrowserLoginURL(const std::string& gamecode); + +// Returns the match viewer URL for a given match ID +std::string GetMatchViewURL(uint64_t matchId); + +// Generates a UUIDv4 gamecode +std::string GenerateGamecode(); + +// Opens a URL in the default browser (cross-platform: ShellExecute on Windows, SDL_OpenURL on Linux/macOS) +void OpenURL(const std::string& url); + +// UTF-8 conversion helpers for UnicodeString +std::string UnicodeToUTF8(const UnicodeString& ustr); +UnicodeString UTF8ToUnicode(const std::string& utf8Str); + +} // namespace NGMP + +#endif // NGMP_HELPERS_H + diff --git a/GeneralsMD/Code/GameEngine/Include/GameNetwork/GeneralsOnline/NGMP_interfaces.h b/GeneralsMD/Code/GameEngine/Include/GameNetwork/GeneralsOnline/NGMP_interfaces.h new file mode 100644 index 00000000000..d82921f55b7 --- /dev/null +++ b/GeneralsMD/Code/GameEngine/Include/GameNetwork/GeneralsOnline/NGMP_interfaces.h @@ -0,0 +1,11 @@ +// GeneralsX @feature GeneralsOnline NGMP interfaces umbrella header +#pragma once + +#include "GameNetwork/GeneralsOnline/NGMP_types.h" +#include "GameNetwork/GeneralsOnline/OnlineServices_Manager.h" +#include "GameNetwork/GeneralsOnline/OnlineServices_Auth.h" +#include "GameNetwork/GeneralsOnline/OnlineServices_LobbyInterface.h" +#include "GameNetwork/GeneralsOnline/OnlineServices_RoomsInterface.h" +#include "GameNetwork/GeneralsOnline/OnlineServices_StatsInterface.h" +#include "GameNetwork/GeneralsOnline/OnlineServices_SocialInterface.h" +#include "GameNetwork/GeneralsOnline/NGMPGame.h" diff --git a/GeneralsMD/Code/GameEngine/Include/GameNetwork/GeneralsOnline/NGMP_json.h b/GeneralsMD/Code/GameEngine/Include/GameNetwork/GeneralsOnline/NGMP_json.h new file mode 100644 index 00000000000..0e33942b2de --- /dev/null +++ b/GeneralsMD/Code/GameEngine/Include/GameNetwork/GeneralsOnline/NGMP_json.h @@ -0,0 +1,34 @@ +#ifndef NGMP_JSON_H +#define NGMP_JSON_H + +#pragma push_macro("min") +#pragma push_macro("max") +#pragma push_macro("snprintf") +#pragma push_macro("vsnprintf") +#pragma push_macro("_snprintf") +#pragma push_macro("_vsnprintf") +#undef min +#undef max +#undef snprintf +#undef vsnprintf +#undef _snprintf +#undef _vsnprintf + +#if __has_include() +#include +#elif __has_include("GameNetwork/GeneralsOnline/json.hpp") +#include "GameNetwork/GeneralsOnline/json.hpp" +#elif __has_include("json.hpp") +#include "json.hpp" +#else +#include "GameNetwork/GeneralsOnline/json.hpp" +#endif + +#pragma pop_macro("_vsnprintf") +#pragma pop_macro("_snprintf") +#pragma pop_macro("vsnprintf") +#pragma pop_macro("snprintf") +#pragma pop_macro("max") +#pragma pop_macro("min") + +#endif // NGMP_JSON_H diff --git a/GeneralsMD/Code/GameEngine/Include/GameNetwork/GeneralsOnline/NGMP_types.h b/GeneralsMD/Code/GameEngine/Include/GameNetwork/GeneralsOnline/NGMP_types.h new file mode 100644 index 00000000000..18b72505dc5 --- /dev/null +++ b/GeneralsMD/Code/GameEngine/Include/GameNetwork/GeneralsOnline/NGMP_types.h @@ -0,0 +1,25 @@ +// GeneralsX @feature GeneralsOnline NGMP types definition +#pragma once + +#include +#include + +class NetworkMemberBase +{ +public: + int64_t user_id = -1; + std::string display_name; + + bool m_bIsHost = false; + bool m_bIsReady = false; + bool m_bIsAdmin = false; + + std::string sort_key; +}; + +enum class ELoginResult +{ + Success, + Failed, + UserCancelled +}; diff --git a/GeneralsMD/Code/GameEngine/Include/GameNetwork/GeneralsOnline/NetworkMesh.h b/GeneralsMD/Code/GameEngine/Include/GameNetwork/GeneralsOnline/NetworkMesh.h new file mode 100644 index 00000000000..9b4c24bc6cd --- /dev/null +++ b/GeneralsMD/Code/GameEngine/Include/GameNetwork/GeneralsOnline/NetworkMesh.h @@ -0,0 +1,239 @@ +// GeneralsX @feature GeneralsOnline NetworkMesh header +#pragma once + +#ifdef _WIN32 +#include +#endif +#include +#include +#include +#include +#include +#include +#include +#include + +#if defined(SAGE_USE_GAMENETWORKINGSOCKETS) +#include +#include +#include +#else +typedef uint32_t HSteamNetConnection; +const HSteamNetConnection k_HSteamNetConnection_Invalid = 0; +typedef uint32_t HSteamListenSocket; +const HSteamListenSocket k_HSteamListenSocket_Invalid = 0; +struct SteamNetworkingMessage_t { void* m_pData; uint32_t m_cbSize; void Release() {} const void* GetData() const { return m_pData; } }; +struct SteamNetworkingIdentity { void Clear() {} const char* GetGenericString() const { return ""; } }; +struct SteamNetConnectionInfo_t { char m_szConnectionDescription[128]; struct { bool IsIPv4() const { return true; } } m_addrRemote; }; +typedef char SteamNetworkingErrMsg[1024]; +class ISteamNetworkingConnectionSignaling { public: virtual ~ISteamNetworkingConnectionSignaling() {} virtual void Release() {} }; +#endif + +#include "GameNetwork/GeneralsOnline/PluginInterfaces.h" +#include "Common/AsciiString.h" + +// Trivial signalling client interface +class ISignalingClient +{ +public: + virtual ~ISignalingClient() = default; + virtual ISteamNetworkingConnectionSignaling* CreateSignalingForConnection(const SteamNetworkingIdentity& identityPeer, SteamNetworkingErrMsg& errMsg) = 0; + virtual void PushIncomingSignal(const std::vector& signalPayload) = 0; + virtual void Poll() = 0; + virtual void Release() = 0; +}; + +enum class EConnectionType +{ + Unknown = -1, + BuiltIn_ValveSockets = 0, + MiddlewarePluginGeneric = 1 +}; + +class NetworkMesh; + +class PlayerConnection +{ +public: + PlayerConnection() + { + m_ConnectionType = EConnectionType::Unknown; + m_hSteamConnection = k_HSteamNetConnection_Invalid; + m_strMiddlewareID = std::string("NOT SET"); + } + + PlayerConnection(int64_t userID, HSteamNetConnection hSteamConnection); + PlayerConnection(int64_t userID, const char* szMiddlewareID); + + EConnectionState GetState() const { return m_State; } + + int SendGamePacket(void* pBuffer, uint32_t totalDataSize); + void SendACPacket(const void* pData, uint32_t dataLen); + void UpdateLatencyHistogram(); + void Close(); + + bool IsIPV4(); + bool IsDirect() + { + std::string strConnectionType = GetConnectionType(); + return strConnectionType.find("Relayed") == std::string::npos; + } + + bool IsValid() const + { + return m_State != EConnectionState::NOT_CONNECTED && + m_State != EConnectionState::CONNECTION_FAILED && + m_State != EConnectionState::CONNECTION_DISCONNECTED; + } + + int Recv(SteamNetworkingMessage_t** pMsg); + + int GetHighestHistoricalLatency() + { + int highestLatency = 0; + for (int latencyHistory : m_vecLatencyHistory) + { + if (latencyHistory > highestLatency) + { + highestLatency = latencyHistory; + } + } + return highestLatency; + } + + std::vector m_vecLatencyHistory; + std::vector m_vecQualityHistory; + std::string GetStats(); + std::string GetConnectionType(); + + void UpdateState(EConnectionState newState, NetworkMesh* pOwningMesh); + void SetDisconnected(bool bWasError, NetworkMesh* pOwningMesh, bool bIsRetrying); + + int64_t m_userID = -1; + EConnectionType m_ConnectionType = EConnectionType::Unknown; + EConnectionState m_State = EConnectionState::NOT_CONNECTED; + int64_t pingSent = -1; + int m_SignallingAttempts = 0; + + int GetLatency(); + int GetJitter(); + float GetConnectionQuality(); + int ComputeConnectionScore(); + + HSteamNetConnection m_hSteamConnection = k_HSteamNetConnection_Invalid; + std::string m_strMiddlewareID = std::string("NOT SET"); + + void LiteUpdateForAC(); +}; + +class NetworkMesh +{ +public: + NetworkMesh(); + ~NetworkMesh() + { + StopLoadingKeepalive(); + Disconnect(); + if (m_pSignaling != nullptr) + { + delete m_pSignaling; + m_pSignaling = nullptr; + } + } + + void Flush(); + void RegisterConnectivity(int64_t userID); + void UpdateConnectivity(PlayerConnection* connection); + + std::function m_cbOnConnected = nullptr; + void RegisterForConnectionEvents(std::function cb) + { + m_cbOnConnected = cb; + } + + void DeregisterForConnectionEvents() + { + m_cbOnConnected = nullptr; + } + + int getMaximumLatency() + { + int highestLatency = 0; + for (auto& kvPair : m_mapConnections) + { + PlayerConnection& conn = kvPair.second; + if (conn.GetLatency() > highestLatency) + { + highestLatency = conn.GetLatency(); + } + } + return highestLatency; + } + + float getMaximumHistoricalLatency() + { + int highestLatency = 0; + for (auto& kvPair : m_mapConnections) + { + PlayerConnection& conn = kvPair.second; + if (conn.GetHighestHistoricalLatency() > highestLatency) + { + highestLatency = conn.GetHighestHistoricalLatency(); + } + } + return static_cast(highestLatency); + } + + int SendGamePacket(void* pBuffer, uint32_t totalDataSize, int64_t userID); + void SendACPacket(uint32_t userID, const void* pData, uint32_t dataLen); + + void StartConnectionSignalling(const char* szMiddlewareID, int64_t remoteUserID, uint16_t preferredPort); + void PushIncomingSignal(const std::vector& signalPayload); + void SetTURNCredentials(const std::string& username, const std::string& token); + void DisconnectUser(int64_t remoteUserID); + void Disconnect(); + + void Tick(); + + // GeneralsX @feature fbraz3 09/09/2026 Background keepalive thread during loading screens + void StartLoadingKeepalive(); + void StopLoadingKeepalive(); + + HSteamListenSocket GetListenSocketHandle() const { return m_hListenSock; } + + std::map& GetAllConnections() + { + return m_mapConnections; + } + + std::recursive_mutex& GetConnectionsMutex() const { return m_mapConnectionsMutex; } + + PlayerConnection* GetConnectionForUser(int64_t user_id) + { + std::lock_guard lock(m_mapConnectionsMutex); + auto it = m_mapConnections.find(user_id); + if (it != m_mapConnections.end()) + { + return &it->second; + } + return nullptr; + } + +private: + std::map m_mapConnections; + mutable std::recursive_mutex m_mapConnectionsMutex; + mutable std::recursive_mutex m_tickMutex; + + ISignalingClient* m_pSignaling = nullptr; + HSteamListenSocket m_hListenSock = k_HSteamListenSocket_Invalid; + bool m_bDisconnected = false; + + std::thread m_keepaliveThread; + std::atomic m_bKeepaliveRunning{ false }; + std::atomic m_bLoadingActive{ false }; + + std::string m_strTurnUsername; + std::string m_strTurnToken; + std::string m_strTurnUsernameString; + std::string m_strTurnTokenString; +}; diff --git a/GeneralsMD/Code/GameEngine/Include/GameNetwork/GeneralsOnline/NextGenTransport.h b/GeneralsMD/Code/GameEngine/Include/GameNetwork/GeneralsOnline/NextGenTransport.h new file mode 100644 index 00000000000..8e9b8f276f2 --- /dev/null +++ b/GeneralsMD/Code/GameEngine/Include/GameNetwork/GeneralsOnline/NextGenTransport.h @@ -0,0 +1,46 @@ +// GeneralsX @feature GeneralsOnline NextGenTransport header +#pragma once + +#include "GameNetwork/udp.h" +#include "GameNetwork/NetworkDefs.h" +#include "GameNetwork/Transport.h" +#include "GameNetwork/GeneralsOnline/PluginInterfaces.h" + +// Struct to track retry state for outgoing packets +struct OutgoingPacketState +{ + Int retryCount = 0; + static constexpr Int MAX_RETRIES = 3; +}; + +class NextGenTransport : public Transport +{ +public: + NextGenTransport(); + ~NextGenTransport() override; + + Bool init(AsciiString ip, UnsignedShort port) override; + Bool init(UnsignedInt ip, UnsignedShort port) override; + void reset(void) override; + Bool update(void) override; + + Bool doRecv(void) override; + Bool doSend(void) override; + + Bool queueSend(UnsignedInt addr, UnsignedShort port, const UnsignedByte *buf, Int len) override; + + inline Bool allowBroadcasts(Bool) override { return false; } + + void clearInBufferSlot(int slotIndex) + { + if (slotIndex >= 0 && slotIndex < MAX_MESSAGES) + { + m_inBuffer[slotIndex].length = 0; + m_inBufferOccupied[slotIndex] = false; + } + } + +private: + OutgoingPacketState m_outPacketState[MAX_MESSAGES]; + bool m_inBufferOccupied[MAX_MESSAGES]; +}; diff --git a/GeneralsMD/Code/GameEngine/Include/GameNetwork/GeneralsOnline/OnlineServices_Auth.h b/GeneralsMD/Code/GameEngine/Include/GameNetwork/GeneralsOnline/OnlineServices_Auth.h new file mode 100644 index 00000000000..8eb8cae10d6 --- /dev/null +++ b/GeneralsMD/Code/GameEngine/Include/GameNetwork/GeneralsOnline/OnlineServices_Auth.h @@ -0,0 +1,41 @@ +// GeneralsX @feature GeneralsOnline AuthInterface header +#pragma once + +#include "GameNetwork/GeneralsOnline/NGMP_types.h" +#include +#include +#include + +class NGMP_OnlineServices_AuthInterface +{ +public: + NGMP_OnlineServices_AuthInterface(); + + std::string GetDisplayName(); + std::wstring GetDisplayNameW(); + int64_t GetUserID() const; + std::string GetAuthToken() const; + + bool IsLoggedIn() const; + + void BeginLogin(); + void LogoutOfMyAccount(); + + void RegisterForLoginCallback(std::function callback) + { + m_cb_LoginPendingCallback = callback; + } + void DeregisterForLoginCallback() + { + m_cb_LoginPendingCallback = nullptr; + } + + void InvokeLoginCallback(ELoginResult result) + { + if (m_cb_LoginPendingCallback) + m_cb_LoginPendingCallback(result); + } + +private: + std::function m_cb_LoginPendingCallback = nullptr; +}; diff --git a/GeneralsMD/Code/GameEngine/Include/GameNetwork/GeneralsOnline/OnlineServices_LobbyInterface.h b/GeneralsMD/Code/GameEngine/Include/GameNetwork/GeneralsOnline/OnlineServices_LobbyInterface.h new file mode 100644 index 00000000000..3cb931a3dd4 --- /dev/null +++ b/GeneralsMD/Code/GameEngine/Include/GameNetwork/GeneralsOnline/OnlineServices_LobbyInterface.h @@ -0,0 +1,200 @@ +// GeneralsX @feature GeneralsOnline LobbyInterface header +#pragma once + +#include "GameNetwork/GeneralsOnline/NGMP_types.h" +#include "GameNetwork/GameInfo.h" +#include +#include +#include +#include +#include + +class NGMPGame; + +struct LobbyMemberEntry : public NetworkMemberBase +{ + int side = -1; + int color = -1; + int team = -1; + int startpos = -1; + bool has_map = false; + + uint16_t m_SlotIndex = 9999; + uint16_t m_SlotState = SlotState::SLOT_OPEN; + + std::string region; + int latency = 0; + + bool IsHuman() const + { + return user_id != -1 && m_SlotState == SlotState::SLOT_PLAYER; + } +}; + +enum class ELobbyType +{ + UNKNOWN = -1, + CustomGame = 0, + QuickMatch = 1 +}; + +struct LobbyEntry +{ + int64_t lobbyID = -1; + int64_t owner = -1; + std::string name; + std::string map_name; + std::string map_path; + bool map_official = false; + int current_players = 0; + int max_players = 0; + bool vanilla_teams = false; + uint32_t starting_cash = 0; + bool limit_superweapons = false; + bool track_stats = false; + bool allow_observers = false; + + uint32_t exe_crc = 0; + uint32_t ini_crc = 0; + uint64_t match_id = 0; + ELobbyType lobby_type = ELobbyType::CustomGame; + int rng_seed = -1; + + bool passworded = false; + std::string password; + + std::vector members; + std::string region; + int latency = 0; +}; + +enum class EJoinLobbyResult +{ + JoinLobbyResult_Success, + JoinLobbyResult_FullRoom, + JoinLobbyResult_BadPassword, + JoinLobbyResult_JoinFailed, + JoinLobbyResult_AnticheatMismatch +}; + +enum class ELobbyJoinability +{ + LobbyJoinability_Public, + LobbyJoinability_FriendsOnly, +}; + +class NGMP_OnlineServices_LobbyInterface +{ +public: + NGMP_OnlineServices_LobbyInterface(); + + void StopMatchStartCountdownIfRunning(); + void SearchForLobbies(std::function onStartCallback, std::function)> onCompleteCallback); + void DeregisterForSearchForLobbiesCallback() { m_fnCallbackSearchForLobbiesComplete = nullptr; } + + // Updates + void UpdateCurrentLobby_Map(AsciiString strMap, AsciiString strMapPath, bool bIsOfficial, int newMaxPlayers); + void UpdateCurrentLobby_LimitSuperweapons(bool bLimitSuperweapons); + void UpdateCurrentLobby_StartingCash(UnsignedInt startingCashValue); + void UpdateCurrentLobby_HasMap(); + + void UpdateCurrentLobby_MySide(int side, int updatedStartPos); + void UpdateCurrentLobby_MyColor(int color); + void UpdateCurrentLobby_MyStartPos(int startPos); + void UpdateCurrentLobby_MyTeam(int team); + + // AI + void UpdateCurrentLobby_AIColor(int slot, int color); + void UpdateCurrentLobby_AISide(int slot, int side, int updatedStartPos); + void UpdateCurrentLobby_AITeam(int slot, int team); + void UpdateCurrentLobby_AIStartPos(int slot, int startpos); + + void UpdateCurrentLobby_KickUser(int64_t userID, UnicodeString name); + void UpdateCurrentLobby_SetSlotState(uint16_t slotIndex, uint16_t slotState); + void UpdateCurrentLobby_ForceReady(); + + void SetLobbyListDirty() { m_bLobbyListDirty = true; } + void ConsumeLobbyListDirtyFlag() { m_bLobbyListDirty = false; } + bool IsLobbyListDirty() const { return m_bLobbyListDirty; } + + void CreateLobby(UnicodeString strLobbyName, UnicodeString strInitialMapName, AsciiString strInitialMapPath, bool bIsOfficial, int initialMaxSize, bool bVanillaTeamsOnly, bool bTrackStats, uint32_t startingCash, bool bPassworded, std::string strPassword, bool bAllowObservers); + void JoinLobby(LobbyEntry lobby, std::string strPassword); + void LeaveCurrentLobby(); + + UnicodeString GetCurrentLobbyDisplayName(); + UnicodeString GetCurrentLobbyMapDisplayName(); + AsciiString GetCurrentLobbyMapPath(); + + void SendChatMessageToCurrentLobby(UnicodeString& strChatMsgUnicode, bool bIsAction); + + LobbyEntry& GetCurrentLobby() { return m_CurrentLobby; } + const LobbyEntry& GetCurrentLobby() const { return m_CurrentLobby; } + NGMPGame* GetCurrentGame(); + + void RegisterForRosterNeedsRefreshCallback(std::function cb) + { + std::scoped_lock lock(m_rosterCallbackMutex); + m_RosterNeedsRefreshCallback = cb; + } + void DeregisterForRosterNeedsRefreshCallback() + { + std::scoped_lock lock(m_rosterCallbackMutex); + m_RosterNeedsRefreshCallback = nullptr; + } + + void RegisterForCreateLobbyCallback(std::function callback) { m_cb_CreateLobbyPendingCallback = callback; } + void DeregisterForCreateLobbyCallback() { m_cb_CreateLobbyPendingCallback = nullptr; } + + void RegisterForJoinLobbyCallback(std::function cb) { m_callbackJoinedLobby = cb; } + void DeregisterForJoinLobbyCallback() { m_callbackJoinedLobby = nullptr; } + + void RegisterForChatCallback(std::function cb) { m_OnChatCallback = cb; } + void DeregisterForChatCallback() { m_OnChatCallback = nullptr; } + + std::function m_OnCannotConnectToLobbyCallback = nullptr; + void RegisterForCannotConnectCallback(std::function cb) { m_OnCannotConnectToLobbyCallback = cb; } + void DeregisterForCannotConnectCallback() { m_OnCannotConnectToLobbyCallback = nullptr; } + + bool IsHost(); + bool IsInLobby() const { return m_CurrentLobby.lobbyID != -1; } + uint64_t GetCurrentMatchID() const { return m_CurrentLobby.match_id; } + void SetJoinability(ELobbyJoinability joinability) {} + + int64_t GetCurrentLobbyOwnerID() const { return m_CurrentLobby.owner; } + + LobbyMemberEntry GetRoomMemberFromIndex(int index); + LobbyMemberEntry GetRoomMemberFromID(int64_t userid); + std::vector& GetMembersListForCurrentRoom() { return m_CurrentLobby.members; } + + void UpdateRoomDataCache(std::function fnCallback = nullptr); + void ResetCachedRoomData(); + + void ClearAutoReadyCountdown() { m_timeStartAutoReadyCountdown = -1; } + bool HasAutoReadyCountdown() const { return m_timeStartAutoReadyCountdown != -1; } + + void SetLobbyTryingToJoin(LobbyEntry lobby) { m_LobbyTryingToJoin = lobby; } + void ResetLobbyTryingToJoin() { m_LobbyTryingToJoin = LobbyEntry(); } + LobbyEntry GetLobbyTryingToJoin() const { return m_LobbyTryingToJoin; } + + void Tick(); + + // Internal callback dispatchers + void InvokeCreateLobbyCallback(bool bSuccess); + void InvokeJoinLobbyCallback(EJoinLobbyResult result); + void InvokeChatCallback(const UnicodeString& strMessage, Color color); + + std::vector m_vecLobbies; + +private: + std::function m_cb_CreateLobbyPendingCallback = nullptr; + std::function m_callbackJoinedLobby = nullptr; + std::function)> m_fnCallbackSearchForLobbiesComplete = nullptr; + std::function m_OnChatCallback = nullptr; + std::function m_RosterNeedsRefreshCallback = nullptr; + mutable std::mutex m_rosterCallbackMutex; + + LobbyEntry m_CurrentLobby; + LobbyEntry m_LobbyTryingToJoin; + bool m_bLobbyListDirty = false; + int64_t m_timeStartAutoReadyCountdown = -1; +}; diff --git a/GeneralsMD/Code/GameEngine/Include/GameNetwork/GeneralsOnline/OnlineServices_Manager.h b/GeneralsMD/Code/GameEngine/Include/GameNetwork/GeneralsOnline/OnlineServices_Manager.h new file mode 100644 index 00000000000..c2da78afb86 --- /dev/null +++ b/GeneralsMD/Code/GameEngine/Include/GameNetwork/GeneralsOnline/OnlineServices_Manager.h @@ -0,0 +1,304 @@ +// GeneralsX @feature GeneralsOnline NGMP OnlineServices Manager header +// Thread-safe manager for Next-Gen Multiplayer protocol lifecycle and event dispatching. + +#ifndef ONLINE_SERVICES_MANAGER_H +#define ONLINE_SERVICES_MANAGER_H + +#include "GameNetwork/GeneralsOnline/NGMPWebSocket.h" +#include "Common/GameDefines.h" +#include "GameNetwork/GameSpy/PersistentStorageThread.h" + +#if defined(min) +#undef min +#endif +#if defined(max) +#undef max +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +class NGMP_OnlineServices_AuthInterface; +class NGMP_OnlineServices_LobbyInterface; +class NGMP_OnlineServices_RoomsInterface; +class NGMP_OnlineServices_StatsInterface; +class NGMP_OnlineServices_SocialInterface; +class NetworkMesh; + +struct NGMPEvent { + enum Type { + EVENT_NONE, + EVENT_AUTH_SUCCESS, + EVENT_AUTH_FAILURE, + EVENT_AUTH_CANCELLED, + EVENT_AUTH_FALLBACK_BROWSER, + EVENT_LOBBY_LIST_UPDATED, + EVENT_CHAT_MESSAGE_RECEIVED, + EVENT_CHAT_CONNECTED, + EVENT_CHAT_DISCONNECTED, + EVENT_DISCONNECTED, + EVENT_GLOBAL_STATS_RECEIVED, + EVENT_PLAYER_STATS_RECEIVED, + EVENT_WEBSOCKET_MESSAGE, + EVENT_PLAYLISTS_UPDATED, + EVENT_LOBBY_JOINED, + EVENT_LOBBY_JOIN_FAILED, + EVENT_LOBBY_CREATED, + EVENT_LOBBY_CREATE_FAILED, + EVENT_LOBBY_LEFT, + EVENT_HOST_MIGRATED, + EVENT_GAME_START, // GeneralsX @feature fbraz3 27/08/2026 START_GAME broadcast + EVENT_PLAYERS_UPDATED, + EVENT_MATCHMAKING_MATCH_FOUND, + EVENT_MATCHMAKING_MESSAGE, + EVENT_MOTD_FETCHED, + EVENT_OUTCOME_COMMITTED + }; + + Type type = EVENT_NONE; + std::string payload; +}; + +struct NGMPLobby { + int64_t id = -1; + std::string name; + std::string mapName; + std::string mapPath; + bool isOfficial = true; + int maxPlayers = 8; + int currentPlayers = 0; + bool hasPassword = false; + int anticheatID = -1; +}; + +struct NGMPLobbyPlayer { + int64_t id = -1; + std::string name; + bool isAdmin = false; +}; + +struct GlobalStats { + std::vector wins; + std::vector matches; +}; + +struct PlaylistMapEntry { + std::string Name; + std::string Path; + bool Custom = false; +}; + +struct PlaylistEntry { + uint16_t PlaylistID = -1; + std::string Name; + int MinPlayers = -1; + int DesiredPlayers = -1; + int MinSelectedMaps = 0; + bool AllowTeams = false; + int TeamSize = -1; + bool AllowArmySelection = false; + uint16_t GracePeriodAtMinPlayersMSec = 0; + std::vector Maps; +}; + +class WebSocket { +public: + void SendData_ChangeName(UnicodeString& strNewName); + void SendData_RoomChatMessage(UnicodeString& msg, bool bIsAction); + void SendData_FriendMessage(UnicodeString& msg, int64_t target_user_id); + void SendData_LobbyChatMessage(UnicodeString& msg, bool bIsAction, bool bIsAnnouncement, bool bShowAnnouncementToHost); + void SendData_JoinNetworkRoom(int roomID); + void SendData_LeaveNetworkRoom(); + void SendData_MarkReady(bool bReady); + void SendData_StartGame(); + void SendData_CountdownStarted(); + void SendData_RequestSignalling(int64_t target_user_id); +}; + +class NGMP_OnlineServicesManager { +public: + static NGMP_OnlineServicesManager& getInstance(); + static NGMP_OnlineServicesManager* GetInstance() { return &getInstance(); } + + template + static T* GetInterface() + { + NGMP_OnlineServicesManager& mgr = getInstance(); + if constexpr (std::is_same_v) + return mgr.m_pAuthInterface; + else if constexpr (std::is_same_v) + return mgr.m_pLobbyInterface; + else if constexpr (std::is_same_v) + return mgr.m_pRoomInterface; + else if constexpr (std::is_same_v) + return mgr.m_pStatsInterface; + else if constexpr (std::is_same_v) + return mgr.m_pSocialInterface; + return nullptr; + } + + static std::shared_ptr GetWebSocket() + { + return getInstance().m_pWebSocketWrapper; + } + + bool init(); + std::vector pollEvents(); // Main thread UI tick dispatch + void update(); // Main thread internal state tick + void Tick() { update(); } + + void shutdown(); + + // Main entry point for login (tries silent refresh token first, falls back to browser) + void beginLogin(); + + // Browser-based gamecode login flow (macOS/Linux: uses SDL_OpenURL) + void beginBrowserLogin(); + void cancelBrowserLogin(); + void tickBrowserLogin(); + bool isWaitingBrowserLogin() const { return m_waitingBrowserLogin.load(); } + + // Token-based silent re-login + void loginWithRefreshToken(const std::string& refreshToken); + + void logout(); + bool ensureWebSocketConnected(); + + // Async lobby fetch — result delivered via EVENT_LOBBY_LIST_UPDATED + void requestLobbyListAsync(); + void createLobbyAsync(const std::string& name, const std::string& mapName, const std::string& mapPath, bool isOfficial = true, int maxPlayers = 8, bool vanillaTeamsOnly = false, bool trackStats = false, uint32_t startingCash = 10000, bool isPassworded = false, const std::string& password = "", bool allowObservers = true); + void joinLobbyAsync(int64_t lobbyId, const std::string& password); + + // Staging room / lobby details synchronization + int64_t getCurrentLobbyId() const { return m_currentLobbyId; } + void setCurrentLobbyId(int64_t id) { m_currentLobbyId = id; } + bool isLobbyOwner() const { return m_isLobbyOwner; } + + void requestLobbyDetailsAsync(int64_t lobbyId = -1); + + // Staging room modification methods (matching ELobbyUpdateField) + void updateLobbyMap(const std::string& mapName, const std::string& mapPath, bool isOfficial, int maxPlayers); + void updateLobbyStartingCash(int startingCash); + void updateLobbyLimitSuperweapons(bool limit); + void updateLobbyMySide(int side, int startPos); + void updateLobbyMyColor(int color); + void updateLobbyMyTeam(int team); + void updateLobbyMyStartPos(int startPos); + void updateLobbySlotState(int slotIndex, int slotState); + void updateLobbyAISide(int slot, int side, int startPos = -1); + void updateLobbyAIColor(int slot, int color); + void updateLobbyAITeam(int slot, int team); + void updateLobbyAIStartPos(int slot, int startPos); + void updateLobbyHasMap(bool hasMap); + void updateLobbyForceStart(); + void updateLobbyLeave(int64_t lobbyId = -1); + + // Async playlists fetch + void requestPlaylistsAsync(); + const std::vector& getPlaylists() const { return m_playlists; } + void startMatchmakingAsync(uint16_t playlistID, const std::vector& selectedMapIndexes); + void cancelMatchmakingAsync(); + void widenMatchmakingAsync(); + + // Async stats fetch + void requestGlobalStatsAsync(); + bool hasGlobalStats() const; + uint32_t getGlobalStatsVersion() const { return m_globalStatsVersion; } + GlobalStats getGlobalStats() const; + + void requestPlayerStatsAsync(int64_t userID); + bool getCachedPlayerStats(int64_t userID, PSPlayerStats& outStats) const; + + bool sendChatMessage(const std::string& room, const std::string& message); + bool sendRawWebSocketPayload(const std::string& rawPayload); + void changeNetworkRoom(int16_t roomID); + + bool isLoggedIn() const { return m_isLoggedIn; } + std::string getAuthToken() const { return m_authToken; } + std::string getUsername() const { return m_username; } + int64_t getUserId() const { return m_userId; } + const std::vector& getLobbies() const { return m_lobbies; } + const std::vector& getLobbyPlayers() const { return m_lobbyPlayers; } + + static NetworkMesh* GetNetworkMesh(); + NetworkMesh* getNetworkMesh() { return m_pNetworkMesh.get(); } + + // Internal thread-safe event poster (called from worker threads) + void postEvent(const NGMPEvent& event); + + NGMP_OnlineServices_AuthInterface* m_pAuthInterface = nullptr; + NGMP_OnlineServices_LobbyInterface* m_pLobbyInterface = nullptr; + NGMP_OnlineServices_RoomsInterface* m_pRoomInterface = nullptr; + NGMP_OnlineServices_StatsInterface* m_pStatsInterface = nullptr; + NGMP_OnlineServices_SocialInterface* m_pSocialInterface = nullptr; + std::shared_ptr m_pWebSocketWrapper; + +private: + NGMP_OnlineServicesManager(); + ~NGMP_OnlineServicesManager(); + + NGMP_OnlineServicesManager(const NGMP_OnlineServicesManager&) = delete; + NGMP_OnlineServicesManager& operator=(const NGMP_OnlineServicesManager&) = delete; + + std::unique_ptr m_pNetworkMesh; + + bool m_initialized = false; + bool m_isLoggedIn = false; + std::string m_username; + int64_t m_userId = 0; + std::string m_authToken; + std::string m_wsUri; + std::vector m_lobbies; + std::vector m_lobbyPlayers; + + // Staging room state + int64_t m_currentLobbyId = -1; + int64_t m_hostUserId = -1; + bool m_isLobbyOwner = false; + std::string m_turnUsername; + std::string m_turnToken; + + // Browser-based login state + std::atomic m_waitingBrowserLogin = false; + std::string m_gamecode; + std::chrono::steady_clock::time_point m_lastPollTime; + std::thread m_pollThread; + std::atomic m_pollThreadRunning = false; + + // Async lobby request state + std::atomic m_lobbyRequestInFlight = false; + std::thread m_lobbyThread; + + // Matchmaking state + std::atomic m_playlistsRequestInFlight = false; + std::vector m_playlists; + std::thread m_playlistsThread; + + // Async stats state + std::atomic m_hasGlobalStats = false; + std::atomic m_globalStatsVersion = 0; // GeneralsX @feature Increment on each global stats fetch + std::atomic m_statsRequestInFlight = false; + std::mutex m_statsMutex; + GlobalStats m_globalStats; + std::thread m_statsThread; + + mutable std::mutex m_playerStatsMutex; + std::unordered_map m_cachedPlayerStats; + + // Chat WebSocket session + std::unique_ptr m_chatSession; + + mutable std::mutex m_eventMutex; + std::queue m_eventQueue; + std::queue m_uiEventQueue; +}; + +#endif // ONLINE_SERVICES_MANAGER_H diff --git a/GeneralsMD/Code/GameEngine/Include/GameNetwork/GeneralsOnline/OnlineServices_RoomsInterface.h b/GeneralsMD/Code/GameEngine/Include/GameNetwork/GeneralsOnline/OnlineServices_RoomsInterface.h new file mode 100644 index 00000000000..21b08eba6c3 --- /dev/null +++ b/GeneralsMD/Code/GameEngine/Include/GameNetwork/GeneralsOnline/OnlineServices_RoomsInterface.h @@ -0,0 +1,106 @@ +// GeneralsX @feature GeneralsOnline RoomsInterface header +#pragma once + +#include "GameNetwork/GeneralsOnline/NGMP_types.h" +#include "Common/GameDefines.h" +#include +#include +#include +#include +#include +#include + +enum class ERoomFlags : int +{ + ROOM_FLAGS_DEFAULT = 0, + ROOM_FLAGS_SHOW_ALL_MATCHES = 1 +}; + +class NetworkRoom +{ +public: + NetworkRoom(int roomID, std::string strRoomName, ERoomFlags roomFlags) + { + m_RoomID = roomID; + m_strRoomDisplayName.translate(AsciiString(strRoomName.c_str())); + m_RoomFlags = roomFlags; + } + + int GetRoomID() const { return m_RoomID; } + UnicodeString GetRoomDisplayName() const { return m_strRoomDisplayName; } + ERoomFlags GetRoomFlags() const { return m_RoomFlags; } + +private: + int m_RoomID; + UnicodeString m_strRoomDisplayName; + ERoomFlags m_RoomFlags = ERoomFlags::ROOM_FLAGS_DEFAULT; +}; + +class NetworkRoomMember : public NetworkMemberBase +{ +public: + bool IsValid() const { return user_id != -1; } +}; + +class NGMP_OnlineServices_RoomsInterface +{ +public: + NGMP_OnlineServices_RoomsInterface(); + + void GetRoomList(std::function cb); + void JoinRoom(int roomIndex, std::function onStartCallback, std::function onCompleteCallback); + void LeaveRoom(); + + void RegisterForChatCallback(std::function cb) + { + m_OnChatCallback = cb; + } + void DeregisterForChatCallback() + { + m_OnChatCallback = nullptr; + } + + void RegisterForRosterNeedsRefreshCallback(std::function cb) + { + std::scoped_lock lock(m_rosterCallbackMutex); + m_RosterNeedsRefreshCallback = cb; + } + void DeregisterForRosterNeedsRefreshCallback() + { + std::scoped_lock lock(m_rosterCallbackMutex); + m_RosterNeedsRefreshCallback = nullptr; + } + + NetworkRoomMember* GetRoomMemberFromIndex(int index); + NetworkRoomMember* GetRoomMemberFromID(int64_t puid); + + std::unordered_map& GetMembersListForCurrentRoom() { return m_mapMembers; } + void SendChatMessageToCurrentRoom(UnicodeString& strChatMsg, bool bIsAction); + + void ResetCachedRoomData() + { + m_mapMembers.clear(); + std::scoped_lock lock(m_rosterCallbackMutex); + if (m_RosterNeedsRefreshCallback != nullptr) + { + m_RosterNeedsRefreshCallback(); + } + } + + void Tick() {} + + std::vector GetGroupRooms() { return m_vecRooms; } + void OnRosterUpdated(const std::unordered_map& mapMembers); + int GetCurrentRoomID() const { return m_CurrentRoomID; } + + // Internal callback + void InvokeChatCallback(const UnicodeString& strMessage, Color color); + +private: + int m_CurrentRoomID = 0; + std::vector m_vecRooms; + std::unordered_map m_mapMembers; + std::function m_OnChatCallback = nullptr; + std::function m_RosterNeedsRefreshCallback = nullptr; + mutable std::mutex m_rosterCallbackMutex; +}; diff --git a/GeneralsMD/Code/GameEngine/Include/GameNetwork/GeneralsOnline/OnlineServices_SocialInterface.h b/GeneralsMD/Code/GameEngine/Include/GameNetwork/GeneralsOnline/OnlineServices_SocialInterface.h new file mode 100644 index 00000000000..68269fd1b02 --- /dev/null +++ b/GeneralsMD/Code/GameEngine/Include/GameNetwork/GeneralsOnline/OnlineServices_SocialInterface.h @@ -0,0 +1,27 @@ +// GeneralsX @feature GeneralsOnline SocialInterface header +#pragma once + +#include "Common/GameDefines.h" +#include +#include +#include +#include + +class NGMP_OnlineServices_SocialInterface +{ +public: + NGMP_OnlineServices_SocialInterface(); + + bool IsUserFriend(int64_t target_user_id) const; + bool IsUserIgnored(int64_t target_user_id) const; + + void AddFriend(int64_t target_user_id); + void RemoveFriend(int64_t target_user_id); + + void IgnoreUser(int64_t target_user_id); + void UnignoreUser(int64_t target_user_id); + +private: + std::unordered_set m_friends; + std::unordered_set m_ignored; +}; diff --git a/GeneralsMD/Code/GameEngine/Include/GameNetwork/GeneralsOnline/OnlineServices_StatsInterface.h b/GeneralsMD/Code/GameEngine/Include/GameNetwork/GeneralsOnline/OnlineServices_StatsInterface.h new file mode 100644 index 00000000000..a8a31b1ea67 --- /dev/null +++ b/GeneralsMD/Code/GameEngine/Include/GameNetwork/GeneralsOnline/OnlineServices_StatsInterface.h @@ -0,0 +1,33 @@ +// GeneralsX @feature GeneralsOnline StatsInterface header +#pragma once + +#include +#include +#include "GameNetwork/RankPointValue.h" +#include "GameNetwork/GameSpy/PersistentStorageThread.h" + +#if defined(min) +#undef min +#endif +#if defined(max) +#undef max +#endif + +enum class EStatsRequestPolicy +{ + CACHED_ONLY, + RESPECT_CACHE_ALLOW_REQUEST, + BYPASS_CACHE_FORCE_REQUEST +}; + +class ScoreKeeper; + +class NGMP_OnlineServices_StatsInterface +{ +public: + NGMP_OnlineServices_StatsInterface(); + + void findPlayerStatsByID(int64_t userID, std::function callback, EStatsRequestPolicy policy = EStatsRequestPolicy::RESPECT_CACHE_ALLOW_REQUEST); + void CommitMyOutcome(ScoreKeeper* pScoreKeeper, bool bWon); + void UpdateMyStats(PSPlayerStats stats) {} +}; diff --git a/GeneralsMD/Code/GameEngine/Include/GameNetwork/GeneralsOnline/PluginInterfaces.h b/GeneralsMD/Code/GameEngine/Include/GameNetwork/GeneralsOnline/PluginInterfaces.h new file mode 100644 index 00000000000..18f64652cab --- /dev/null +++ b/GeneralsMD/Code/GameEngine/Include/GameNetwork/GeneralsOnline/PluginInterfaces.h @@ -0,0 +1,59 @@ +// GeneralsX @feature GeneralsOnline PluginInterfaces & connection state definitions +#pragma once + +#include +#include + +enum class EConnectionState : uint8_t +{ + NOT_CONNECTED, + CONNECTING_DIRECT, + FINDING_ROUTE, + CONNECTED_DIRECT, + CONNECTION_FAILED, + CONNECTION_DISCONNECTED +}; + +enum class ENetworkChannels : uint8_t +{ + Game = 0, + Anticheat, + Signalling +}; + +enum class EPacketReliability : int32_t +{ + PACKET_RELIABILITY_UNRELIABLE_UNORDERED = 0, + PACKET_RELIABILITY_RELIABLE_UNORDERED = 1, + PACKET_RELIABILITY_RELIABLE_ORDERED = 2 +}; + +enum class EAnticheatActionType : int32_t +{ + NONE = 0, + KICK = 1 +}; + +enum class EAnticheatActionReason : int32_t +{ + Unknown = 0, + InternalError = 1, + InvalidMessage = 2, + AuthFailure = 3, + ACNotRunning = 4, + HeartbeatTimedOut = 5, + ClientViolation = 6, + BackendViolation = 7, + TempCooldown = 8, + TempBanned = 9, + PermaBanned = 10 +}; + +class AnticheatPlugInterface +{ +public: + static bool DoesACPluginProvideSecureGameTransport() { return false; } + static int GetNextRecvPacketSize(uint8_t) { return 0; } + static bool RecvPacket(uint8_t**, uint8_t) { return false; } + static void AC_NetworkMessageArrived(uint32_t, void*, uint32_t) {} +}; diff --git a/GeneralsMD/Code/GameEngine/Include/GameNetwork/GeneralsOnline/json.hpp b/GeneralsMD/Code/GameEngine/Include/GameNetwork/GeneralsOnline/json.hpp new file mode 100644 index 00000000000..ed423e41ff8 --- /dev/null +++ b/GeneralsMD/Code/GameEngine/Include/GameNetwork/GeneralsOnline/json.hpp @@ -0,0 +1,25510 @@ +// __ _____ _____ _____ +// __| | __| | | | JSON for Modern C++ +// | | |__ | | | | | | version 3.11.3 +// |_____|_____|_____|_|___| https://github.com/nlohmann/json +// +// SPDX-FileCopyrightText: 2013 - 2025 Niels Lohmann +// SPDX-License-Identifier: MIT + +/****************************************************************************\ + * Note on documentation: The source files contain links to the online * + * documentation of the public API at https://json.nlohmann.me. This URL * + * contains the most recent documentation and should also be applicable to * + * previous versions; documentation for deprecated functions is not * + * removed, but marked deprecated. See "Generate documentation" section in * + * file docs/README.md. * +\****************************************************************************/ + +#ifndef INCLUDE_NLOHMANN_JSON_HPP_ +#define INCLUDE_NLOHMANN_JSON_HPP_ + +#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 // string, stoi, to_string +#include // declval, forward, move, pair, swap +#include // vector + +// #include +// __ _____ _____ _____ +// __| | __| | | | JSON for Modern C++ +// | | |__ | | | | | | version 3.11.3 +// |_____|_____|_____|_|___| https://github.com/nlohmann/json +// +// SPDX-FileCopyrightText: 2013 - 2025 Niels Lohmann +// SPDX-License-Identifier: MIT + + + +#include + +// #include +// __ _____ _____ _____ +// __| | __| | | | JSON for Modern C++ +// | | |__ | | | | | | version 3.11.3 +// |_____|_____|_____|_|___| https://github.com/nlohmann/json +// +// SPDX-FileCopyrightText: 2013 - 2025 Niels Lohmann +// SPDX-License-Identifier: MIT + + + +// This file contains all macro definitions affecting or depending on the ABI + +#ifndef JSON_SKIP_LIBRARY_VERSION_CHECK + #if defined(NLOHMANN_JSON_VERSION_MAJOR) && defined(NLOHMANN_JSON_VERSION_MINOR) && defined(NLOHMANN_JSON_VERSION_PATCH) + #if NLOHMANN_JSON_VERSION_MAJOR != 3 || NLOHMANN_JSON_VERSION_MINOR != 11 || NLOHMANN_JSON_VERSION_PATCH != 3 + #warning "Already included a different version of the library!" + #endif + #endif +#endif + +#define NLOHMANN_JSON_VERSION_MAJOR 3 // NOLINT(modernize-macro-to-enum) +#define NLOHMANN_JSON_VERSION_MINOR 11 // NOLINT(modernize-macro-to-enum) +#define NLOHMANN_JSON_VERSION_PATCH 3 // NOLINT(modernize-macro-to-enum) + +#ifndef JSON_DIAGNOSTICS + #define JSON_DIAGNOSTICS 0 +#endif + +#ifndef JSON_DIAGNOSTIC_POSITIONS + #define JSON_DIAGNOSTIC_POSITIONS 0 +#endif + +#ifndef JSON_USE_LEGACY_DISCARDED_VALUE_COMPARISON + #define JSON_USE_LEGACY_DISCARDED_VALUE_COMPARISON 0 +#endif + +#if JSON_DIAGNOSTICS + #define NLOHMANN_JSON_ABI_TAG_DIAGNOSTICS _diag +#else + #define NLOHMANN_JSON_ABI_TAG_DIAGNOSTICS +#endif + +#if JSON_DIAGNOSTIC_POSITIONS + #define NLOHMANN_JSON_ABI_TAG_DIAGNOSTIC_POSITIONS _dp +#else + #define NLOHMANN_JSON_ABI_TAG_DIAGNOSTIC_POSITIONS +#endif + +#if JSON_USE_LEGACY_DISCARDED_VALUE_COMPARISON + #define NLOHMANN_JSON_ABI_TAG_LEGACY_DISCARDED_VALUE_COMPARISON _ldvcmp +#else + #define NLOHMANN_JSON_ABI_TAG_LEGACY_DISCARDED_VALUE_COMPARISON +#endif + +#ifndef NLOHMANN_JSON_NAMESPACE_NO_VERSION + #define NLOHMANN_JSON_NAMESPACE_NO_VERSION 0 +#endif + +// Construct the namespace ABI tags component +#define NLOHMANN_JSON_ABI_TAGS_CONCAT_EX(a, b, c) json_abi ## a ## b ## c +#define NLOHMANN_JSON_ABI_TAGS_CONCAT(a, b, c) \ + NLOHMANN_JSON_ABI_TAGS_CONCAT_EX(a, b, c) + +#define NLOHMANN_JSON_ABI_TAGS \ + NLOHMANN_JSON_ABI_TAGS_CONCAT( \ + NLOHMANN_JSON_ABI_TAG_DIAGNOSTICS, \ + NLOHMANN_JSON_ABI_TAG_LEGACY_DISCARDED_VALUE_COMPARISON, \ + NLOHMANN_JSON_ABI_TAG_DIAGNOSTIC_POSITIONS) + +// Construct the namespace version component +#define NLOHMANN_JSON_NAMESPACE_VERSION_CONCAT_EX(major, minor, patch) \ + _v ## major ## _ ## minor ## _ ## patch +#define NLOHMANN_JSON_NAMESPACE_VERSION_CONCAT(major, minor, patch) \ + NLOHMANN_JSON_NAMESPACE_VERSION_CONCAT_EX(major, minor, patch) + +#if NLOHMANN_JSON_NAMESPACE_NO_VERSION +#define NLOHMANN_JSON_NAMESPACE_VERSION +#else +#define NLOHMANN_JSON_NAMESPACE_VERSION \ + NLOHMANN_JSON_NAMESPACE_VERSION_CONCAT(NLOHMANN_JSON_VERSION_MAJOR, \ + NLOHMANN_JSON_VERSION_MINOR, \ + NLOHMANN_JSON_VERSION_PATCH) +#endif + +// Combine namespace components +#define NLOHMANN_JSON_NAMESPACE_CONCAT_EX(a, b) a ## b +#define NLOHMANN_JSON_NAMESPACE_CONCAT(a, b) \ + NLOHMANN_JSON_NAMESPACE_CONCAT_EX(a, b) + +#ifndef NLOHMANN_JSON_NAMESPACE +#define NLOHMANN_JSON_NAMESPACE \ + nlohmann::NLOHMANN_JSON_NAMESPACE_CONCAT( \ + NLOHMANN_JSON_ABI_TAGS, \ + NLOHMANN_JSON_NAMESPACE_VERSION) +#endif + +#ifndef NLOHMANN_JSON_NAMESPACE_BEGIN +#define NLOHMANN_JSON_NAMESPACE_BEGIN \ + namespace nlohmann \ + { \ + inline namespace NLOHMANN_JSON_NAMESPACE_CONCAT( \ + NLOHMANN_JSON_ABI_TAGS, \ + NLOHMANN_JSON_NAMESPACE_VERSION) \ + { +#endif + +#ifndef NLOHMANN_JSON_NAMESPACE_END +#define NLOHMANN_JSON_NAMESPACE_END \ + } /* namespace (inline namespace) NOLINT(readability/namespace) */ \ + } // namespace nlohmann +#endif + +// #include +// __ _____ _____ _____ +// __| | __| | | | JSON for Modern C++ +// | | |__ | | | | | | version 3.11.3 +// |_____|_____|_____|_|___| https://github.com/nlohmann/json +// +// SPDX-FileCopyrightText: 2013 - 2025 Niels Lohmann +// SPDX-License-Identifier: MIT + + + +#include // transform +#include // array +#include // forward_list +#include // inserter, front_inserter, end +#include // map +#ifdef JSON_HAS_CPP_17 + #include // optional +#endif +#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 +// __ _____ _____ _____ +// __| | __| | | | JSON for Modern C++ +// | | |__ | | | | | | version 3.11.3 +// |_____|_____|_____|_|___| https://github.com/nlohmann/json +// +// SPDX-FileCopyrightText: 2013 - 2025 Niels Lohmann +// SPDX-License-Identifier: MIT + + + +#include // nullptr_t +#include // exception +#if JSON_DIAGNOSTICS + #include // accumulate +#endif +#include // runtime_error +#include // to_string +#include // vector + +// #include +// __ _____ _____ _____ +// __| | __| | | | JSON for Modern C++ +// | | |__ | | | | | | version 3.11.3 +// |_____|_____|_____|_|___| https://github.com/nlohmann/json +// +// SPDX-FileCopyrightText: 2013 - 2025 Niels Lohmann +// SPDX-License-Identifier: MIT + + + +#include // array +#include // size_t +#include // uint8_t +#include // string + +// #include +// __ _____ _____ _____ +// __| | __| | | | JSON for Modern C++ +// | | |__ | | | | | | version 3.11.3 +// |_____|_____|_____|_|___| https://github.com/nlohmann/json +// +// SPDX-FileCopyrightText: 2013 - 2025 Niels Lohmann +// SPDX-License-Identifier: MIT + + + +#include // declval, pair +// #include +// __ _____ _____ _____ +// __| | __| | | | JSON for Modern C++ +// | | |__ | | | | | | version 3.11.3 +// |_____|_____|_____|_|___| https://github.com/nlohmann/json +// +// SPDX-FileCopyrightText: 2013 - 2025 Niels Lohmann +// SPDX-License-Identifier: MIT + + + +#include + +// #include +// __ _____ _____ _____ +// __| | __| | | | JSON for Modern C++ +// | | |__ | | | | | | version 3.11.3 +// |_____|_____|_____|_|___| https://github.com/nlohmann/json +// +// SPDX-FileCopyrightText: 2013 - 2025 Niels Lohmann +// SPDX-License-Identifier: MIT + + + +// #include + + +NLOHMANN_JSON_NAMESPACE_BEGIN +namespace detail +{ + +template struct make_void +{ + using type = void; +}; +template using void_t = typename make_void::type; + +} // namespace detail +NLOHMANN_JSON_NAMESPACE_END + + +NLOHMANN_JSON_NAMESPACE_BEGIN +namespace detail +{ + +// https://en.cppreference.com/w/cpp/experimental/is_detected +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 class Op, class... Args> +using is_detected = typename detector::value_t; + +template class Op, class... Args> +struct is_detected_lazy : is_detected { }; + +template class Op, class... Args> +using detected_t = typename detector::type; + +template class Op, class... Args> +using detected_or = detector; + +template class Op, class... Args> +using detected_or_t = typename detected_or::type; + +template class Op, class... Args> +using is_detected_exact = std::is_same>; + +template class Op, class... Args> +using is_detected_convertible = + std::is_convertible, To>; + +} // namespace detail +NLOHMANN_JSON_NAMESPACE_END + +// #include + + +// __ _____ _____ _____ +// __| | __| | | | JSON for Modern C++ +// | | |__ | | | | | | version 3.11.3 +// |_____|_____|_____|_|___| https://github.com/nlohmann/json +// +// SPDX-FileCopyrightText: 2013 - 2025 Niels Lohmann +// SPDX-FileCopyrightText: 2016 - 2021 Evan Nemerson +// SPDX-License-Identifier: MIT + +/* Hedley - https://nemequ.github.io/hedley + * Created by Evan Nemerson + */ + +#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) */ + + +// This file contains all internal macro definitions (except those affecting ABI) +// You MUST include macro_unscope.hpp at the end of json.hpp to undef all of them + +// #include + + +// exclude unsupported compilers +#if !defined(JSON_SKIP_UNSUPPORTED_COMPILER_CHECK) + #if defined(__clang__) + #if (__clang_major__ * 10000 + __clang_minor__ * 100 + __clang_patchlevel__) < 30400 + #error "unsupported Clang version - see https://github.com/nlohmann/json#supported-compilers" + #endif + #elif defined(__GNUC__) && !(defined(__ICC) || defined(__INTEL_COMPILER)) + #if (__GNUC__ * 10000 + __GNUC_MINOR__ * 100 + __GNUC_PATCHLEVEL__) < 40800 + #error "unsupported GCC version - see https://github.com/nlohmann/json#supported-compilers" + #endif + #endif +#endif + +// C++ language standard detection +// if the user manually specified the used c++ version this is skipped +#if !defined(JSON_HAS_CPP_20) && !defined(JSON_HAS_CPP_17) && !defined(JSON_HAS_CPP_14) && !defined(JSON_HAS_CPP_11) + #if (defined(__cplusplus) && __cplusplus >= 202002L) || (defined(_MSVC_LANG) && _MSVC_LANG >= 202002L) + #define JSON_HAS_CPP_20 + #define JSON_HAS_CPP_17 + #define JSON_HAS_CPP_14 + #elif (defined(__cplusplus) && __cplusplus >= 201703L) || (defined(_HAS_CXX17) && _HAS_CXX17 == 1) // fix for issue #464 + #define JSON_HAS_CPP_17 + #define JSON_HAS_CPP_14 + #elif (defined(__cplusplus) && __cplusplus >= 201402L) || (defined(_HAS_CXX14) && _HAS_CXX14 == 1) + #define JSON_HAS_CPP_14 + #endif + // the cpp 11 flag is always specified because it is the minimal required version + #define JSON_HAS_CPP_11 +#endif + +#ifdef __has_include + #if __has_include() + #include + #endif +#endif + +#if !defined(JSON_HAS_FILESYSTEM) && !defined(JSON_HAS_EXPERIMENTAL_FILESYSTEM) + #ifdef JSON_HAS_CPP_17 + #if defined(__cpp_lib_filesystem) + #define JSON_HAS_FILESYSTEM 1 + #elif defined(__cpp_lib_experimental_filesystem) + #define JSON_HAS_EXPERIMENTAL_FILESYSTEM 1 + #elif !defined(__has_include) + #define JSON_HAS_EXPERIMENTAL_FILESYSTEM 1 + #elif __has_include() + #define JSON_HAS_FILESYSTEM 1 + #elif __has_include() + #define JSON_HAS_EXPERIMENTAL_FILESYSTEM 1 + #endif + + // std::filesystem does not work on MinGW GCC 8: https://sourceforge.net/p/mingw-w64/bugs/737/ + #if defined(__MINGW32__) && defined(__GNUC__) && __GNUC__ == 8 + #undef JSON_HAS_FILESYSTEM + #undef JSON_HAS_EXPERIMENTAL_FILESYSTEM + #endif + + // no filesystem support before GCC 8: https://en.cppreference.com/w/cpp/compiler_support + #if defined(__GNUC__) && !defined(__clang__) && __GNUC__ < 8 + #undef JSON_HAS_FILESYSTEM + #undef JSON_HAS_EXPERIMENTAL_FILESYSTEM + #endif + + // no filesystem support before Clang 7: https://en.cppreference.com/w/cpp/compiler_support + #if defined(__clang_major__) && __clang_major__ < 7 + #undef JSON_HAS_FILESYSTEM + #undef JSON_HAS_EXPERIMENTAL_FILESYSTEM + #endif + + // no filesystem support before MSVC 19.14: https://en.cppreference.com/w/cpp/compiler_support + #if defined(_MSC_VER) && _MSC_VER < 1914 + #undef JSON_HAS_FILESYSTEM + #undef JSON_HAS_EXPERIMENTAL_FILESYSTEM + #endif + + // no filesystem support before iOS 13 + #if defined(__IPHONE_OS_VERSION_MIN_REQUIRED) && __IPHONE_OS_VERSION_MIN_REQUIRED < 130000 + #undef JSON_HAS_FILESYSTEM + #undef JSON_HAS_EXPERIMENTAL_FILESYSTEM + #endif + + // no filesystem support before macOS Catalina + #if defined(__MAC_OS_X_VERSION_MIN_REQUIRED) && __MAC_OS_X_VERSION_MIN_REQUIRED < 101500 + #undef JSON_HAS_FILESYSTEM + #undef JSON_HAS_EXPERIMENTAL_FILESYSTEM + #endif + #endif +#endif + +#ifndef JSON_HAS_EXPERIMENTAL_FILESYSTEM + #define JSON_HAS_EXPERIMENTAL_FILESYSTEM 0 +#endif + +#ifndef JSON_HAS_FILESYSTEM + #define JSON_HAS_FILESYSTEM 0 +#endif + +#ifndef JSON_HAS_THREE_WAY_COMPARISON + #if defined(__cpp_impl_three_way_comparison) && __cpp_impl_three_way_comparison >= 201907L \ + && defined(__cpp_lib_three_way_comparison) && __cpp_lib_three_way_comparison >= 201907L + #define JSON_HAS_THREE_WAY_COMPARISON 1 + #else + #define JSON_HAS_THREE_WAY_COMPARISON 0 + #endif +#endif + +#ifndef JSON_HAS_RANGES + // ranges header shipping in GCC 11.1.0 (released 2021-04-27) has syntax error + #if defined(__GLIBCXX__) && __GLIBCXX__ == 20210427 + #define JSON_HAS_RANGES 0 + #elif defined(__cpp_lib_ranges) + #define JSON_HAS_RANGES 1 + #else + #define JSON_HAS_RANGES 0 + #endif +#endif + +#ifndef JSON_HAS_STATIC_RTTI + #if !defined(_HAS_STATIC_RTTI) || _HAS_STATIC_RTTI != 0 + #define JSON_HAS_STATIC_RTTI 1 + #else + #define JSON_HAS_STATIC_RTTI 0 + #endif +#endif + +#ifdef JSON_HAS_CPP_17 + #define JSON_INLINE_VARIABLE inline +#else + #define JSON_INLINE_VARIABLE +#endif + +#if JSON_HEDLEY_HAS_ATTRIBUTE(no_unique_address) + #define JSON_NO_UNIQUE_ADDRESS [[no_unique_address]] +#else + #define JSON_NO_UNIQUE_ADDRESS +#endif + +// disable documentation warnings on clang +#if defined(__clang__) + #pragma clang diagnostic push + #pragma clang diagnostic ignored "-Wdocumentation" + #pragma clang diagnostic ignored "-Wdocumentation-unknown-command" +#endif + +// allow disabling exceptions +#if (defined(__cpp_exceptions) || defined(__EXCEPTIONS) || defined(_CPPUNWIND)) && !defined(JSON_NOEXCEPTION) + #define JSON_THROW(exception) throw exception + #define JSON_TRY try + #define JSON_CATCH(exception) catch(exception) + #define JSON_INTERNAL_CATCH(exception) catch(exception) +#else + #include + #define JSON_THROW(exception) std::abort() + #define JSON_TRY if(true) + #define JSON_CATCH(exception) if(false) + #define JSON_INTERNAL_CATCH(exception) if(false) +#endif + +// override exception macros +#if defined(JSON_THROW_USER) + #undef JSON_THROW + #define JSON_THROW JSON_THROW_USER +#endif +#if defined(JSON_TRY_USER) + #undef JSON_TRY + #define JSON_TRY JSON_TRY_USER +#endif +#if defined(JSON_CATCH_USER) + #undef JSON_CATCH + #define JSON_CATCH JSON_CATCH_USER + #undef JSON_INTERNAL_CATCH + #define JSON_INTERNAL_CATCH JSON_CATCH_USER +#endif +#if defined(JSON_INTERNAL_CATCH_USER) + #undef JSON_INTERNAL_CATCH + #define JSON_INTERNAL_CATCH JSON_INTERNAL_CATCH_USER +#endif + +// allow overriding assert +#if !defined(JSON_ASSERT) + #include // assert + #define JSON_ASSERT(x) assert(x) +#endif + +// allow to access some private functions (needed by the test suite) +#if defined(JSON_TESTS_PRIVATE) + #define JSON_PRIVATE_UNLESS_TESTED public +#else + #define JSON_PRIVATE_UNLESS_TESTED private +#endif + +/*! +@brief macro to briefly define a mapping between an enum and JSON +@def NLOHMANN_JSON_SERIALIZE_ENUM +@since version 3.4.0 +*/ +#define NLOHMANN_JSON_SERIALIZE_ENUM(ENUM_TYPE, ...) \ + template \ + inline void to_json(BasicJsonType& j, const ENUM_TYPE& e) \ + { \ + /* NOLINTNEXTLINE(modernize-type-traits) we use C++11 */ \ + static_assert(std::is_enum::value, #ENUM_TYPE " must be an enum!"); \ + /* NOLINTNEXTLINE(modernize-avoid-c-arrays) we don't want to depend on */ \ + static const std::pair m[] = __VA_ARGS__; \ + auto it = std::find_if(std::begin(m), std::end(m), \ + [e](const std::pair& ej_pair) -> bool \ + { \ + return ej_pair.first == e; \ + }); \ + j = ((it != std::end(m)) ? it : std::begin(m))->second; \ + } \ + template \ + inline void from_json(const BasicJsonType& j, ENUM_TYPE& e) \ + { \ + /* NOLINTNEXTLINE(modernize-type-traits) we use C++11 */ \ + static_assert(std::is_enum::value, #ENUM_TYPE " must be an enum!"); \ + /* NOLINTNEXTLINE(modernize-avoid-c-arrays) we don't want to depend on */ \ + static const std::pair m[] = __VA_ARGS__; \ + auto it = std::find_if(std::begin(m), std::end(m), \ + [&j](const std::pair& ej_pair) -> bool \ + { \ + return ej_pair.second == j; \ + }); \ + e = ((it != std::end(m)) ? it : std::begin(m))->first; \ + } + +// Ugly macros to avoid uglier copy-paste when specializing basic_json. They +// may be removed in the future once the class is split. + +#define NLOHMANN_BASIC_JSON_TPL_DECLARATION \ + template class ObjectType, \ + template class ArrayType, \ + class StringType, class BooleanType, class NumberIntegerType, \ + class NumberUnsignedType, class NumberFloatType, \ + template class AllocatorType, \ + template class JSONSerializer, \ + class BinaryType, \ + class CustomBaseClass> + +#define NLOHMANN_BASIC_JSON_TPL \ + basic_json + +// Macros to simplify conversion from/to types + +#define NLOHMANN_JSON_EXPAND( x ) x +#define NLOHMANN_JSON_GET_MACRO(_1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, _18, _19, _20, _21, _22, _23, _24, _25, _26, _27, _28, _29, _30, _31, _32, _33, _34, _35, _36, _37, _38, _39, _40, _41, _42, _43, _44, _45, _46, _47, _48, _49, _50, _51, _52, _53, _54, _55, _56, _57, _58, _59, _60, _61, _62, _63, _64, NAME,...) NAME +#define NLOHMANN_JSON_PASTE(...) NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_GET_MACRO(__VA_ARGS__, \ + NLOHMANN_JSON_PASTE64, \ + NLOHMANN_JSON_PASTE63, \ + NLOHMANN_JSON_PASTE62, \ + NLOHMANN_JSON_PASTE61, \ + NLOHMANN_JSON_PASTE60, \ + NLOHMANN_JSON_PASTE59, \ + NLOHMANN_JSON_PASTE58, \ + NLOHMANN_JSON_PASTE57, \ + NLOHMANN_JSON_PASTE56, \ + NLOHMANN_JSON_PASTE55, \ + NLOHMANN_JSON_PASTE54, \ + NLOHMANN_JSON_PASTE53, \ + NLOHMANN_JSON_PASTE52, \ + NLOHMANN_JSON_PASTE51, \ + NLOHMANN_JSON_PASTE50, \ + NLOHMANN_JSON_PASTE49, \ + NLOHMANN_JSON_PASTE48, \ + NLOHMANN_JSON_PASTE47, \ + NLOHMANN_JSON_PASTE46, \ + NLOHMANN_JSON_PASTE45, \ + NLOHMANN_JSON_PASTE44, \ + NLOHMANN_JSON_PASTE43, \ + NLOHMANN_JSON_PASTE42, \ + NLOHMANN_JSON_PASTE41, \ + NLOHMANN_JSON_PASTE40, \ + NLOHMANN_JSON_PASTE39, \ + NLOHMANN_JSON_PASTE38, \ + NLOHMANN_JSON_PASTE37, \ + NLOHMANN_JSON_PASTE36, \ + NLOHMANN_JSON_PASTE35, \ + NLOHMANN_JSON_PASTE34, \ + NLOHMANN_JSON_PASTE33, \ + NLOHMANN_JSON_PASTE32, \ + NLOHMANN_JSON_PASTE31, \ + NLOHMANN_JSON_PASTE30, \ + NLOHMANN_JSON_PASTE29, \ + NLOHMANN_JSON_PASTE28, \ + NLOHMANN_JSON_PASTE27, \ + NLOHMANN_JSON_PASTE26, \ + NLOHMANN_JSON_PASTE25, \ + NLOHMANN_JSON_PASTE24, \ + NLOHMANN_JSON_PASTE23, \ + NLOHMANN_JSON_PASTE22, \ + NLOHMANN_JSON_PASTE21, \ + NLOHMANN_JSON_PASTE20, \ + NLOHMANN_JSON_PASTE19, \ + NLOHMANN_JSON_PASTE18, \ + NLOHMANN_JSON_PASTE17, \ + NLOHMANN_JSON_PASTE16, \ + NLOHMANN_JSON_PASTE15, \ + NLOHMANN_JSON_PASTE14, \ + NLOHMANN_JSON_PASTE13, \ + NLOHMANN_JSON_PASTE12, \ + NLOHMANN_JSON_PASTE11, \ + NLOHMANN_JSON_PASTE10, \ + NLOHMANN_JSON_PASTE9, \ + NLOHMANN_JSON_PASTE8, \ + NLOHMANN_JSON_PASTE7, \ + NLOHMANN_JSON_PASTE6, \ + NLOHMANN_JSON_PASTE5, \ + NLOHMANN_JSON_PASTE4, \ + NLOHMANN_JSON_PASTE3, \ + NLOHMANN_JSON_PASTE2, \ + NLOHMANN_JSON_PASTE1)(__VA_ARGS__)) +#define NLOHMANN_JSON_PASTE2(func, v1) func(v1) +#define NLOHMANN_JSON_PASTE3(func, v1, v2) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE2(func, v2) +#define NLOHMANN_JSON_PASTE4(func, v1, v2, v3) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE3(func, v2, v3) +#define NLOHMANN_JSON_PASTE5(func, v1, v2, v3, v4) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE4(func, v2, v3, v4) +#define NLOHMANN_JSON_PASTE6(func, v1, v2, v3, v4, v5) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE5(func, v2, v3, v4, v5) +#define NLOHMANN_JSON_PASTE7(func, v1, v2, v3, v4, v5, v6) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE6(func, v2, v3, v4, v5, v6) +#define NLOHMANN_JSON_PASTE8(func, v1, v2, v3, v4, v5, v6, v7) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE7(func, v2, v3, v4, v5, v6, v7) +#define NLOHMANN_JSON_PASTE9(func, v1, v2, v3, v4, v5, v6, v7, v8) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE8(func, v2, v3, v4, v5, v6, v7, v8) +#define NLOHMANN_JSON_PASTE10(func, v1, v2, v3, v4, v5, v6, v7, v8, v9) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE9(func, v2, v3, v4, v5, v6, v7, v8, v9) +#define NLOHMANN_JSON_PASTE11(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE10(func, v2, v3, v4, v5, v6, v7, v8, v9, v10) +#define NLOHMANN_JSON_PASTE12(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE11(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11) +#define NLOHMANN_JSON_PASTE13(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE12(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12) +#define NLOHMANN_JSON_PASTE14(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE13(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13) +#define NLOHMANN_JSON_PASTE15(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE14(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14) +#define NLOHMANN_JSON_PASTE16(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE15(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15) +#define NLOHMANN_JSON_PASTE17(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE16(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16) +#define NLOHMANN_JSON_PASTE18(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE17(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17) +#define NLOHMANN_JSON_PASTE19(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE18(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18) +#define NLOHMANN_JSON_PASTE20(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE19(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19) +#define NLOHMANN_JSON_PASTE21(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE20(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20) +#define NLOHMANN_JSON_PASTE22(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE21(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21) +#define NLOHMANN_JSON_PASTE23(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE22(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22) +#define NLOHMANN_JSON_PASTE24(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE23(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23) +#define NLOHMANN_JSON_PASTE25(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE24(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24) +#define NLOHMANN_JSON_PASTE26(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE25(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25) +#define NLOHMANN_JSON_PASTE27(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE26(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26) +#define NLOHMANN_JSON_PASTE28(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE27(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27) +#define NLOHMANN_JSON_PASTE29(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE28(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28) +#define NLOHMANN_JSON_PASTE30(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE29(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29) +#define NLOHMANN_JSON_PASTE31(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE30(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30) +#define NLOHMANN_JSON_PASTE32(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE31(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31) +#define NLOHMANN_JSON_PASTE33(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE32(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32) +#define NLOHMANN_JSON_PASTE34(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE33(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33) +#define NLOHMANN_JSON_PASTE35(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE34(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34) +#define NLOHMANN_JSON_PASTE36(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE35(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35) +#define NLOHMANN_JSON_PASTE37(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE36(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36) +#define NLOHMANN_JSON_PASTE38(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE37(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37) +#define NLOHMANN_JSON_PASTE39(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE38(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38) +#define NLOHMANN_JSON_PASTE40(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE39(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39) +#define NLOHMANN_JSON_PASTE41(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE40(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40) +#define NLOHMANN_JSON_PASTE42(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE41(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41) +#define NLOHMANN_JSON_PASTE43(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE42(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42) +#define NLOHMANN_JSON_PASTE44(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE43(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43) +#define NLOHMANN_JSON_PASTE45(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE44(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44) +#define NLOHMANN_JSON_PASTE46(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE45(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45) +#define NLOHMANN_JSON_PASTE47(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE46(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46) +#define NLOHMANN_JSON_PASTE48(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE47(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47) +#define NLOHMANN_JSON_PASTE49(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE48(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48) +#define NLOHMANN_JSON_PASTE50(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE49(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49) +#define NLOHMANN_JSON_PASTE51(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE50(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50) +#define NLOHMANN_JSON_PASTE52(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE51(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51) +#define NLOHMANN_JSON_PASTE53(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE52(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52) +#define NLOHMANN_JSON_PASTE54(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE53(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53) +#define NLOHMANN_JSON_PASTE55(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53, v54) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE54(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53, v54) +#define NLOHMANN_JSON_PASTE56(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53, v54, v55) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE55(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53, v54, v55) +#define NLOHMANN_JSON_PASTE57(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53, v54, v55, v56) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE56(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53, v54, v55, v56) +#define NLOHMANN_JSON_PASTE58(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53, v54, v55, v56, v57) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE57(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53, v54, v55, v56, v57) +#define NLOHMANN_JSON_PASTE59(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53, v54, v55, v56, v57, v58) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE58(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53, v54, v55, v56, v57, v58) +#define NLOHMANN_JSON_PASTE60(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53, v54, v55, v56, v57, v58, v59) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE59(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53, v54, v55, v56, v57, v58, v59) +#define NLOHMANN_JSON_PASTE61(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53, v54, v55, v56, v57, v58, v59, v60) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE60(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53, v54, v55, v56, v57, v58, v59, v60) +#define NLOHMANN_JSON_PASTE62(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53, v54, v55, v56, v57, v58, v59, v60, v61) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE61(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53, v54, v55, v56, v57, v58, v59, v60, v61) +#define NLOHMANN_JSON_PASTE63(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53, v54, v55, v56, v57, v58, v59, v60, v61, v62) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE62(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53, v54, v55, v56, v57, v58, v59, v60, v61, v62) +#define NLOHMANN_JSON_PASTE64(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53, v54, v55, v56, v57, v58, v59, v60, v61, v62, v63) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE63(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53, v54, v55, v56, v57, v58, v59, v60, v61, v62, v63) + +#define NLOHMANN_JSON_TO(v1) nlohmann_json_j[#v1] = nlohmann_json_t.v1; +#define NLOHMANN_JSON_FROM(v1) nlohmann_json_j.at(#v1).get_to(nlohmann_json_t.v1); +#define NLOHMANN_JSON_FROM_WITH_DEFAULT(v1) nlohmann_json_t.v1 = !nlohmann_json_j.is_null() ? nlohmann_json_j.value(#v1, nlohmann_json_default_obj.v1) : nlohmann_json_default_obj.v1; + +/*! +@brief macro +@def NLOHMANN_DEFINE_TYPE_INTRUSIVE +@since version 3.9.0 +@sa https://json.nlohmann.me/api/macros/nlohmann_define_type_intrusive/ +*/ +#define NLOHMANN_DEFINE_TYPE_INTRUSIVE(Type, ...) \ + template::value, int> = 0> \ + friend void to_json(BasicJsonType& nlohmann_json_j, const Type& nlohmann_json_t) { NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_PASTE(NLOHMANN_JSON_TO, __VA_ARGS__)) } \ + template::value, int> = 0> \ + friend void from_json(const BasicJsonType& nlohmann_json_j, Type& nlohmann_json_t) { NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_PASTE(NLOHMANN_JSON_FROM, __VA_ARGS__)) } + +/*! +@brief macro +@def NLOHMANN_DEFINE_TYPE_INTRUSIVE_WITH_DEFAULT +@since version 3.11.0 +@sa https://json.nlohmann.me/api/macros/nlohmann_define_type_intrusive/ +*/ +#define NLOHMANN_DEFINE_TYPE_INTRUSIVE_WITH_DEFAULT(Type, ...) \ + template::value, int> = 0> \ + friend void to_json(BasicJsonType& nlohmann_json_j, const Type& nlohmann_json_t) { NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_PASTE(NLOHMANN_JSON_TO, __VA_ARGS__)) } \ + template::value, int> = 0> \ + friend void from_json(const BasicJsonType& nlohmann_json_j, Type& nlohmann_json_t) { const Type nlohmann_json_default_obj{}; NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_PASTE(NLOHMANN_JSON_FROM_WITH_DEFAULT, __VA_ARGS__)) } + +/*! +@brief macro +@def NLOHMANN_DEFINE_TYPE_INTRUSIVE_ONLY_SERIALIZE +@since version 3.11.3 +@sa https://json.nlohmann.me/api/macros/nlohmann_define_type_intrusive/ +*/ +#define NLOHMANN_DEFINE_TYPE_INTRUSIVE_ONLY_SERIALIZE(Type, ...) \ + template::value, int> = 0> \ + friend void to_json(BasicJsonType& nlohmann_json_j, const Type& nlohmann_json_t) { NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_PASTE(NLOHMANN_JSON_TO, __VA_ARGS__)) } + +/*! +@brief macro +@def NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE +@since version 3.9.0 +@sa https://json.nlohmann.me/api/macros/nlohmann_define_type_non_intrusive/ +*/ +#define NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE(Type, ...) \ + template::value, int> = 0> \ + void to_json(BasicJsonType& nlohmann_json_j, const Type& nlohmann_json_t) { NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_PASTE(NLOHMANN_JSON_TO, __VA_ARGS__)) } \ + template::value, int> = 0> \ + void from_json(const BasicJsonType& nlohmann_json_j, Type& nlohmann_json_t) { NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_PASTE(NLOHMANN_JSON_FROM, __VA_ARGS__)) } + +/*! +@brief macro +@def NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE_WITH_DEFAULT +@since version 3.11.0 +@sa https://json.nlohmann.me/api/macros/nlohmann_define_type_non_intrusive/ +*/ +#define NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE_WITH_DEFAULT(Type, ...) \ + template::value, int> = 0> \ + void to_json(BasicJsonType& nlohmann_json_j, const Type& nlohmann_json_t) { NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_PASTE(NLOHMANN_JSON_TO, __VA_ARGS__)) } \ + template::value, int> = 0> \ + void from_json(const BasicJsonType& nlohmann_json_j, Type& nlohmann_json_t) { const Type nlohmann_json_default_obj{}; NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_PASTE(NLOHMANN_JSON_FROM_WITH_DEFAULT, __VA_ARGS__)) } + +/*! +@brief macro +@def NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE_ONLY_SERIALIZE +@since version 3.11.3 +@sa https://json.nlohmann.me/api/macros/nlohmann_define_type_non_intrusive/ +*/ +#define NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE_ONLY_SERIALIZE(Type, ...) \ + template::value, int> = 0> \ + void to_json(BasicJsonType& nlohmann_json_j, const Type& nlohmann_json_t) { NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_PASTE(NLOHMANN_JSON_TO, __VA_ARGS__)) } + +/*! +@brief macro +@def NLOHMANN_DEFINE_DERIVED_TYPE_INTRUSIVE +@since version 3.11.x +@sa https://json.nlohmann.me/api/macros/nlohmann_define_derived_type/ +*/ +#define NLOHMANN_DEFINE_DERIVED_TYPE_INTRUSIVE(Type, BaseType, ...) \ + template::value, int> = 0> \ + friend void to_json(BasicJsonType& nlohmann_json_j, const Type& nlohmann_json_t) { nlohmann::to_json(nlohmann_json_j, static_cast(nlohmann_json_t)); NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_PASTE(NLOHMANN_JSON_TO, __VA_ARGS__)) } \ + template::value, int> = 0> \ + friend void from_json(const BasicJsonType& nlohmann_json_j, Type& nlohmann_json_t) { nlohmann::from_json(nlohmann_json_j, static_cast(nlohmann_json_t)); NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_PASTE(NLOHMANN_JSON_FROM, __VA_ARGS__)) } + +/*! +@brief macro +@def NLOHMANN_DEFINE_DERIVED_TYPE_INTRUSIVE_WITH_DEFAULT +@since version 3.11.x +@sa https://json.nlohmann.me/api/macros/nlohmann_define_derived_type/ +*/ +#define NLOHMANN_DEFINE_DERIVED_TYPE_INTRUSIVE_WITH_DEFAULT(Type, BaseType, ...) \ + template::value, int> = 0> \ + friend void to_json(BasicJsonType& nlohmann_json_j, const Type& nlohmann_json_t) { nlohmann::to_json(nlohmann_json_j, static_cast(nlohmann_json_t)); NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_PASTE(NLOHMANN_JSON_TO, __VA_ARGS__)) } \ + template::value, int> = 0> \ + friend void from_json(const BasicJsonType& nlohmann_json_j, Type& nlohmann_json_t) { nlohmann::from_json(nlohmann_json_j, static_cast(nlohmann_json_t)); const Type nlohmann_json_default_obj{}; NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_PASTE(NLOHMANN_JSON_FROM_WITH_DEFAULT, __VA_ARGS__)) } + +/*! +@brief macro +@def NLOHMANN_DEFINE_DERIVED_TYPE_INTRUSIVE_ONLY_SERIALIZE +@since version 3.11.x +@sa https://json.nlohmann.me/api/macros/nlohmann_define_derived_type/ +*/ +#define NLOHMANN_DEFINE_DERIVED_TYPE_INTRUSIVE_ONLY_SERIALIZE(Type, BaseType, ...) \ + template::value, int> = 0> \ + friend void to_json(BasicJsonType& nlohmann_json_j, const Type& nlohmann_json_t) { nlohmann::to_json(nlohmann_json_j, static_cast(nlohmann_json_t)); NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_PASTE(NLOHMANN_JSON_TO, __VA_ARGS__)) } + +/*! +@brief macro +@def NLOHMANN_DEFINE_DERIVED_TYPE_NON_INTRUSIVE +@since version 3.11.x +@sa https://json.nlohmann.me/api/macros/nlohmann_define_derived_type/ +*/ +#define NLOHMANN_DEFINE_DERIVED_TYPE_NON_INTRUSIVE(Type, BaseType, ...) \ + template::value, int> = 0> \ + void to_json(BasicJsonType& nlohmann_json_j, const Type& nlohmann_json_t) { nlohmann::to_json(nlohmann_json_j, static_cast(nlohmann_json_t)); NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_PASTE(NLOHMANN_JSON_TO, __VA_ARGS__)) } \ + template::value, int> = 0> \ + void from_json(const BasicJsonType& nlohmann_json_j, Type& nlohmann_json_t) { nlohmann::from_json(nlohmann_json_j, static_cast(nlohmann_json_t)); NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_PASTE(NLOHMANN_JSON_FROM, __VA_ARGS__)) } + +/*! +@brief macro +@def NLOHMANN_DEFINE_DERIVED_TYPE_NON_INTRUSIVE_WITH_DEFAULT +@since version 3.11.x +@sa https://json.nlohmann.me/api/macros/nlohmann_define_derived_type/ +*/ +#define NLOHMANN_DEFINE_DERIVED_TYPE_NON_INTRUSIVE_WITH_DEFAULT(Type, BaseType, ...) \ + template::value, int> = 0> \ + void to_json(BasicJsonType& nlohmann_json_j, const Type& nlohmann_json_t) { nlohmann::to_json(nlohmann_json_j, static_cast(nlohmann_json_t)); NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_PASTE(NLOHMANN_JSON_TO, __VA_ARGS__)) } \ + template::value, int> = 0> \ + void from_json(const BasicJsonType& nlohmann_json_j, Type& nlohmann_json_t) { nlohmann::from_json(nlohmann_json_j, static_cast(nlohmann_json_t)); const Type nlohmann_json_default_obj{}; NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_PASTE(NLOHMANN_JSON_FROM_WITH_DEFAULT, __VA_ARGS__)) } + +/*! +@brief macro +@def NLOHMANN_DEFINE_DERIVED_TYPE_NON_INTRUSIVE_ONLY_SERIALIZE +@since version 3.11.x +@sa https://json.nlohmann.me/api/macros/nlohmann_define_derived_type/ +*/ +#define NLOHMANN_DEFINE_DERIVED_TYPE_NON_INTRUSIVE_ONLY_SERIALIZE(Type, BaseType, ...) \ + template::value, int> = 0> \ + void to_json(BasicJsonType& nlohmann_json_j, const Type& nlohmann_json_t) { nlohmann::to_json(nlohmann_json_j, static_cast(nlohmann_json_t)); NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_PASTE(NLOHMANN_JSON_TO, __VA_ARGS__)) } + +// inspired from https://stackoverflow.com/a/26745591 +// allows to call any std function as if (e.g. with begin): +// using std::begin; begin(x); +// +// it allows using the detected idiom to retrieve the return type +// of such an expression +#define NLOHMANN_CAN_CALL_STD_FUNC_IMPL(std_name) \ + namespace detail { \ + using std::std_name; \ + \ + template \ + using result_of_##std_name = decltype(std_name(std::declval()...)); \ + } \ + \ + namespace detail2 { \ + struct std_name##_tag \ + { \ + }; \ + \ + template \ + std_name##_tag std_name(T&&...); \ + \ + template \ + using result_of_##std_name = decltype(std_name(std::declval()...)); \ + \ + template \ + struct would_call_std_##std_name \ + { \ + static constexpr auto const value = ::nlohmann::detail:: \ + is_detected_exact::value; \ + }; \ + } /* namespace detail2 */ \ + \ + template \ + struct would_call_std_##std_name : detail2::would_call_std_##std_name \ + { \ + } + +#ifndef JSON_USE_IMPLICIT_CONVERSIONS + #define JSON_USE_IMPLICIT_CONVERSIONS 1 +#endif + +#if JSON_USE_IMPLICIT_CONVERSIONS + #define JSON_EXPLICIT +#else + #define JSON_EXPLICIT explicit +#endif + +#ifndef JSON_DISABLE_ENUM_SERIALIZATION + #define JSON_DISABLE_ENUM_SERIALIZATION 0 +#endif + +#ifndef JSON_USE_GLOBAL_UDLS + #define JSON_USE_GLOBAL_UDLS 1 +#endif + +#if JSON_HAS_THREE_WAY_COMPARISON + #include // partial_ordering +#endif + +NLOHMANN_JSON_NAMESPACE_BEGIN +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 +*/ +#if JSON_HAS_THREE_WAY_COMPARISON + inline std::partial_ordering operator<=>(const value_t lhs, const value_t rhs) noexcept // *NOPAD* +#else + inline bool operator<(const value_t lhs, const value_t rhs) noexcept +#endif +{ + 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); +#if JSON_HAS_THREE_WAY_COMPARISON + if (l_index < order.size() && r_index < order.size()) + { + return order[l_index] <=> order[r_index]; // *NOPAD* + } + return std::partial_ordering::unordered; +#else + return l_index < order.size() && r_index < order.size() && order[l_index] < order[r_index]; +#endif +} + +// GCC selects the built-in operator< over an operator rewritten from +// a user-defined spaceship operator +// Clang, MSVC, and ICC select the rewritten candidate +// (see GCC bug https://gcc.gnu.org/bugzilla/show_bug.cgi?id=105200) +#if JSON_HAS_THREE_WAY_COMPARISON && defined(__GNUC__) +inline bool operator<(const value_t lhs, const value_t rhs) noexcept +{ + return std::is_lt(lhs <=> rhs); // *NOPAD* +} +#endif + +} // namespace detail +NLOHMANN_JSON_NAMESPACE_END + +// #include +// __ _____ _____ _____ +// __| | __| | | | JSON for Modern C++ +// | | |__ | | | | | | version 3.11.3 +// |_____|_____|_____|_|___| https://github.com/nlohmann/json +// +// SPDX-FileCopyrightText: 2013 - 2025 Niels Lohmann +// SPDX-License-Identifier: MIT + + + +// #include + + +NLOHMANN_JSON_NAMESPACE_BEGIN +namespace detail +{ + +/*! +@brief replace all occurrences of a substring by another string + +@param[in,out] s the string to manipulate; changed so that all + occurrences of @a f are replaced with @a t +@param[in] f the substring to replace with @a t +@param[in] t the string to replace @a f + +@pre The search string @a f must not be empty. **This precondition is +enforced with an assertion.** + +@since version 2.0.0 +*/ +template +inline void replace_substring(StringType& s, const StringType& f, + const StringType& t) +{ + JSON_ASSERT(!f.empty()); + for (auto pos = s.find(f); // find first occurrence of f + pos != StringType::npos; // make sure f was found + s.replace(pos, f.size(), t), // replace with t, and + pos = s.find(f, pos + t.size())) // find next occurrence of f + {} +} + +/*! + * @brief string escaping as described in RFC 6901 (Sect. 4) + * @param[in] s string to escape + * @return escaped string + * + * Note the order of escaping "~" to "~0" and "/" to "~1" is important. + */ +template +inline StringType escape(StringType s) +{ + replace_substring(s, StringType{"~"}, StringType{"~0"}); + replace_substring(s, StringType{"/"}, StringType{"~1"}); + return s; +} + +/*! + * @brief string unescaping as described in RFC 6901 (Sect. 4) + * @param[in] s string to unescape + * @return unescaped string + * + * Note the order of escaping "~1" to "/" and "~0" to "~" is important. + */ +template +static void unescape(StringType& s) +{ + replace_substring(s, StringType{"~1"}, StringType{"/"}); + replace_substring(s, StringType{"~0"}, StringType{"~"}); +} + +} // namespace detail +NLOHMANN_JSON_NAMESPACE_END + +// #include +// __ _____ _____ _____ +// __| | __| | | | JSON for Modern C++ +// | | |__ | | | | | | version 3.11.3 +// |_____|_____|_____|_|___| https://github.com/nlohmann/json +// +// SPDX-FileCopyrightText: 2013 - 2025 Niels Lohmann +// SPDX-License-Identifier: MIT + + + +#include // size_t + +// #include + + +NLOHMANN_JSON_NAMESPACE_BEGIN +namespace detail +{ + +/// struct to capture the start position of the current token +struct position_t +{ + /// the total number of characters read + std::size_t chars_read_total = 0; + /// the number of characters read in the current line + std::size_t chars_read_current_line = 0; + /// the number of lines read + std::size_t lines_read = 0; + + /// conversion to size_t to preserve SAX interface + constexpr operator size_t() const + { + return chars_read_total; + } +}; + +} // namespace detail +NLOHMANN_JSON_NAMESPACE_END + +// #include + +// #include +// __ _____ _____ _____ +// __| | __| | | | JSON for Modern C++ +// | | |__ | | | | | | version 3.11.3 +// |_____|_____|_____|_|___| https://github.com/nlohmann/json +// +// SPDX-FileCopyrightText: 2013 - 2025 Niels Lohmann +// SPDX-FileCopyrightText: 2018 The Abseil Authors +// SPDX-License-Identifier: MIT + + + +#include // array +#include // size_t +#include // conditional, enable_if, false_type, integral_constant, is_constructible, is_integral, is_same, remove_cv, remove_reference, true_type +#include // index_sequence, make_index_sequence, index_sequence_for + +// #include + + +NLOHMANN_JSON_NAMESPACE_BEGIN +namespace detail +{ + +template +using uncvref_t = typename std::remove_cv::type>::type; + +#ifdef JSON_HAS_CPP_14 + +// the following utilities are natively available in C++14 +using std::enable_if_t; +using std::index_sequence; +using std::make_index_sequence; +using std::index_sequence_for; + +#else + +// alias templates to reduce boilerplate +template +using enable_if_t = typename std::enable_if::type; + +// The following code is taken from https://github.com/abseil/abseil-cpp/blob/10cb35e459f5ecca5b2ff107635da0bfa41011b4/absl/utility/utility.h +// which is part of Google Abseil (https://github.com/abseil/abseil-cpp), licensed under the Apache License 2.0. + +//// START OF CODE FROM GOOGLE ABSEIL + +// integer_sequence +// +// Class template representing a compile-time integer sequence. An instantiation +// of `integer_sequence` has a sequence of integers encoded in its +// type through its template arguments (which is a common need when +// working with C++11 variadic templates). `absl::integer_sequence` is designed +// to be a drop-in replacement for C++14's `std::integer_sequence`. +// +// Example: +// +// template< class T, T... Ints > +// void user_function(integer_sequence); +// +// int main() +// { +// // user_function's `T` will be deduced to `int` and `Ints...` +// // will be deduced to `0, 1, 2, 3, 4`. +// user_function(make_integer_sequence()); +// } +template +struct integer_sequence +{ + using value_type = T; + static constexpr std::size_t size() noexcept + { + return sizeof...(Ints); + } +}; + +// index_sequence +// +// A helper template for an `integer_sequence` of `size_t`, +// `absl::index_sequence` is designed to be a drop-in replacement for C++14's +// `std::index_sequence`. +template +using index_sequence = integer_sequence; + +namespace utility_internal +{ + +template +struct Extend; + +// Note that SeqSize == sizeof...(Ints). It's passed explicitly for efficiency. +template +struct Extend, SeqSize, 0> +{ + using type = integer_sequence < T, Ints..., (Ints + SeqSize)... >; +}; + +template +struct Extend, SeqSize, 1> +{ + using type = integer_sequence < T, Ints..., (Ints + SeqSize)..., 2 * SeqSize >; +}; + +// Recursion helper for 'make_integer_sequence'. +// 'Gen::type' is an alias for 'integer_sequence'. +template +struct Gen +{ + using type = + typename Extend < typename Gen < T, N / 2 >::type, N / 2, N % 2 >::type; +}; + +template +struct Gen +{ + using type = integer_sequence; +}; + +} // namespace utility_internal + +// Compile-time sequences of integers + +// make_integer_sequence +// +// This template alias is equivalent to +// `integer_sequence`, and is designed to be a drop-in +// replacement for C++14's `std::make_integer_sequence`. +template +using make_integer_sequence = typename utility_internal::Gen::type; + +// make_index_sequence +// +// This template alias is equivalent to `index_sequence<0, 1, ..., N-1>`, +// and is designed to be a drop-in replacement for C++14's +// `std::make_index_sequence`. +template +using make_index_sequence = make_integer_sequence; + +// index_sequence_for +// +// Converts a typename pack into an index sequence of the same length, and +// is designed to be a drop-in replacement for C++14's +// `std::index_sequence_for()` +template +using index_sequence_for = make_index_sequence; + +//// END OF CODE FROM GOOGLE ABSEIL + +#endif + +// dispatch utility (taken from ranges-v3) +template struct priority_tag : priority_tag < N - 1 > {}; +template<> struct priority_tag<0> {}; + +// taken from ranges-v3 +template +struct static_const +{ + static JSON_INLINE_VARIABLE constexpr T value{}; +}; + +#ifndef JSON_HAS_CPP_17 + template + constexpr T static_const::value; +#endif + +template +constexpr std::array make_array(Args&& ... args) +{ + return std::array {{static_cast(std::forward(args))...}}; +} + +} // namespace detail +NLOHMANN_JSON_NAMESPACE_END + +// #include +// __ _____ _____ _____ +// __| | __| | | | JSON for Modern C++ +// | | |__ | | | | | | version 3.11.3 +// |_____|_____|_____|_|___| https://github.com/nlohmann/json +// +// SPDX-FileCopyrightText: 2013 - 2025 Niels Lohmann +// SPDX-License-Identifier: MIT + + + +#include // numeric_limits +#include // char_traits +#include // tuple +#include // false_type, is_constructible, is_integral, is_same, true_type +#include // declval + +// #include +// __ _____ _____ _____ +// __| | __| | | | JSON for Modern C++ +// | | |__ | | | | | | version 3.11.3 +// |_____|_____|_____|_|___| https://github.com/nlohmann/json +// +// SPDX-FileCopyrightText: 2013 - 2025 Niels Lohmann +// SPDX-License-Identifier: MIT + + + +#include // random_access_iterator_tag + +// #include + +// #include + +// #include + + +NLOHMANN_JSON_NAMESPACE_BEGIN +namespace detail +{ + +template +struct iterator_types {}; + +template +struct iterator_types < + It, + void_t> +{ + using difference_type = typename It::difference_type; + using value_type = typename It::value_type; + using pointer = typename It::pointer; + using reference = typename It::reference; + using iterator_category = typename It::iterator_category; +}; + +// This is required as some compilers implement std::iterator_traits in a way that +// doesn't work with SFINAE. See https://github.com/nlohmann/json/issues/1341. +template +struct iterator_traits +{ +}; + +template +struct iterator_traits < T, enable_if_t < !std::is_pointer::value >> + : iterator_types +{ +}; + +template +struct iterator_traits::value>> +{ + using iterator_category = std::random_access_iterator_tag; + using value_type = T; + using difference_type = ptrdiff_t; + using pointer = T*; + using reference = T&; +}; + +} // namespace detail +NLOHMANN_JSON_NAMESPACE_END + +// #include + +// #include +// __ _____ _____ _____ +// __| | __| | | | JSON for Modern C++ +// | | |__ | | | | | | version 3.11.3 +// |_____|_____|_____|_|___| https://github.com/nlohmann/json +// +// SPDX-FileCopyrightText: 2013 - 2025 Niels Lohmann +// SPDX-License-Identifier: MIT + + + +// #include + + +NLOHMANN_JSON_NAMESPACE_BEGIN + +NLOHMANN_CAN_CALL_STD_FUNC_IMPL(begin); + +NLOHMANN_JSON_NAMESPACE_END + +// #include +// __ _____ _____ _____ +// __| | __| | | | JSON for Modern C++ +// | | |__ | | | | | | version 3.11.3 +// |_____|_____|_____|_|___| https://github.com/nlohmann/json +// +// SPDX-FileCopyrightText: 2013 - 2025 Niels Lohmann +// SPDX-License-Identifier: MIT + + + +// #include + + +NLOHMANN_JSON_NAMESPACE_BEGIN + +NLOHMANN_CAN_CALL_STD_FUNC_IMPL(end); + +NLOHMANN_JSON_NAMESPACE_END + +// #include + +// #include + +// #include +// __ _____ _____ _____ +// __| | __| | | | JSON for Modern C++ +// | | |__ | | | | | | version 3.11.3 +// |_____|_____|_____|_|___| https://github.com/nlohmann/json +// +// SPDX-FileCopyrightText: 2013 - 2025 Niels Lohmann +// SPDX-License-Identifier: MIT + +#ifndef INCLUDE_NLOHMANN_JSON_FWD_HPP_ + #define INCLUDE_NLOHMANN_JSON_FWD_HPP_ + + #include // int64_t, uint64_t + #include // map + #include // allocator + #include // string + #include // vector + + // #include + + + /*! + @brief namespace for Niels Lohmann + @see https://github.com/nlohmann + @since version 1.0.0 + */ + NLOHMANN_JSON_NAMESPACE_BEGIN + + /*! + @brief default JSONSerializer template argument + + This serializer ignores the template arguments and uses ADL + ([argument-dependent lookup](https://en.cppreference.com/w/cpp/language/adl)) + for serialization. + */ + template + struct adl_serializer; + + /// a class to store JSON values + /// @sa https://json.nlohmann.me/api/basic_json/ + template class ObjectType = + std::map, + template class ArrayType = std::vector, + class StringType = std::string, class BooleanType = bool, + class NumberIntegerType = std::int64_t, + class NumberUnsignedType = std::uint64_t, + class NumberFloatType = double, + template class AllocatorType = std::allocator, + template class JSONSerializer = + adl_serializer, + class BinaryType = std::vector, // cppcheck-suppress syntaxError + class CustomBaseClass = void> + class basic_json; + + /// @brief JSON Pointer defines a string syntax for identifying a specific value within a JSON document + /// @sa https://json.nlohmann.me/api/json_pointer/ + template + class json_pointer; + + /*! + @brief default specialization + @sa https://json.nlohmann.me/api/json/ + */ + using json = basic_json<>; + + /// @brief a minimal map-like container that preserves insertion order + /// @sa https://json.nlohmann.me/api/ordered_map/ + template + struct ordered_map; + + /// @brief specialization that maintains the insertion order of object keys + /// @sa https://json.nlohmann.me/api/ordered_json/ + using ordered_json = basic_json; + + NLOHMANN_JSON_NAMESPACE_END + +#endif // INCLUDE_NLOHMANN_JSON_FWD_HPP_ + + +NLOHMANN_JSON_NAMESPACE_BEGIN +/*! +@brief detail namespace with internal helper functions + +This namespace collects functions that should not be exposed, +implementations of some @ref basic_json methods, and meta-programming helpers. + +@since version 2.1.0 +*/ +namespace detail +{ + +///////////// +// helpers // +///////////// + +// Note to maintainers: +// +// Every trait in this file expects a non CV-qualified type. +// The only exceptions are in the 'aliases for detected' section +// (i.e. those of the form: decltype(T::member_function(std::declval()))) +// +// In this case, T has to be properly CV-qualified to constraint the function arguments +// (e.g. to_json(BasicJsonType&, const T&)) + +template struct is_basic_json : std::false_type {}; + +NLOHMANN_BASIC_JSON_TPL_DECLARATION +struct is_basic_json : std::true_type {}; + +// used by exceptions create() member functions +// true_type for pointer to possibly cv-qualified basic_json or std::nullptr_t +// false_type otherwise +template +struct is_basic_json_context : + std::integral_constant < bool, + is_basic_json::type>::type>::value + || std::is_same::value > +{}; + +////////////////////// +// json_ref helpers // +////////////////////// + +template +class json_ref; + +template +struct is_json_ref : std::false_type {}; + +template +struct is_json_ref> : std::true_type {}; + +////////////////////////// +// aliases for detected // +////////////////////////// + +template +using mapped_type_t = typename T::mapped_type; + +template +using key_type_t = typename T::key_type; + +template +using value_type_t = typename T::value_type; + +template +using difference_type_t = typename T::difference_type; + +template +using pointer_t = typename T::pointer; + +template +using reference_t = typename T::reference; + +template +using iterator_category_t = typename T::iterator_category; + +template +using to_json_function = decltype(T::to_json(std::declval()...)); + +template +using from_json_function = decltype(T::from_json(std::declval()...)); + +template +using get_template_function = decltype(std::declval().template get()); + +// trait checking if JSONSerializer::from_json(json const&, udt&) exists +template +struct has_from_json : std::false_type {}; + +// trait checking if j.get is valid +// use this trait instead of std::is_constructible or std::is_convertible, +// both rely on, or make use of implicit conversions, and thus fail when T +// has several constructors/operator= (see https://github.com/nlohmann/json/issues/958) +template +struct is_getable +{ + static constexpr bool value = is_detected::value; +}; + +template +struct has_from_json < BasicJsonType, T, enable_if_t < !is_basic_json::value >> +{ + using serializer = typename BasicJsonType::template json_serializer; + + static constexpr bool value = + is_detected_exact::value; +}; + +// This trait checks if JSONSerializer::from_json(json const&) exists +// this overload is used for non-default-constructible user-defined-types +template +struct has_non_default_from_json : std::false_type {}; + +template +struct has_non_default_from_json < BasicJsonType, T, enable_if_t < !is_basic_json::value >> +{ + using serializer = typename BasicJsonType::template json_serializer; + + static constexpr bool value = + is_detected_exact::value; +}; + +// This trait checks if BasicJsonType::json_serializer::to_json exists +// Do not evaluate the trait when T is a basic_json type, to avoid template instantiation infinite recursion. +template +struct has_to_json : std::false_type {}; + +template +struct has_to_json < BasicJsonType, T, enable_if_t < !is_basic_json::value >> +{ + using serializer = typename BasicJsonType::template json_serializer; + + static constexpr bool value = + is_detected_exact::value; +}; + +template +using detect_key_compare = typename T::key_compare; + +template +struct has_key_compare : std::integral_constant::value> {}; + +// obtains the actual object key comparator +template +struct actual_object_comparator +{ + using object_t = typename BasicJsonType::object_t; + using object_comparator_t = typename BasicJsonType::default_object_comparator_t; + using type = typename std::conditional < has_key_compare::value, + typename object_t::key_compare, object_comparator_t>::type; +}; + +template +using actual_object_comparator_t = typename actual_object_comparator::type; + +///////////////// +// char_traits // +///////////////// + +// Primary template of char_traits calls std char_traits +template +struct char_traits : std::char_traits +{}; + +// Explicitly define char traits for unsigned char since it is not standard +template<> +struct char_traits : std::char_traits +{ + using char_type = unsigned char; + using int_type = uint64_t; + + // Redefine to_int_type function + static int_type to_int_type(char_type c) noexcept + { + return static_cast(c); + } + + static char_type to_char_type(int_type i) noexcept + { + return static_cast(i); + } + + static constexpr int_type eof() noexcept + { + return static_cast(std::char_traits::eof()); + } +}; + +// Explicitly define char traits for signed char since it is not standard +template<> +struct char_traits : std::char_traits +{ + using char_type = signed char; + using int_type = uint64_t; + + // Redefine to_int_type function + static int_type to_int_type(char_type c) noexcept + { + return static_cast(c); + } + + static char_type to_char_type(int_type i) noexcept + { + return static_cast(i); + } + + static constexpr int_type eof() noexcept + { + return static_cast(std::char_traits::eof()); + } +}; + +/////////////////// +// is_ functions // +/////////////////// + +// https://en.cppreference.com/w/cpp/types/conjunction +template struct conjunction : std::true_type { }; +template struct conjunction : B { }; +template +struct conjunction +: std::conditional(B::value), conjunction, B>::type {}; + +// https://en.cppreference.com/w/cpp/types/negation +template struct negation : std::integral_constant < bool, !B::value > { }; + +// Reimplementation of is_constructible and is_default_constructible, due to them being broken for +// std::pair and std::tuple until LWG 2367 fix (see https://cplusplus.github.io/LWG/lwg-defects.html#2367). +// This causes compile errors in e.g. clang 3.5 or gcc 4.9. +template +struct is_default_constructible : std::is_default_constructible {}; + +template +struct is_default_constructible> + : conjunction, is_default_constructible> {}; + +template +struct is_default_constructible> + : conjunction, is_default_constructible> {}; + +template +struct is_default_constructible> + : conjunction...> {}; + +template +struct is_default_constructible> + : conjunction...> {}; + +template +struct is_constructible : std::is_constructible {}; + +template +struct is_constructible> : is_default_constructible> {}; + +template +struct is_constructible> : is_default_constructible> {}; + +template +struct is_constructible> : is_default_constructible> {}; + +template +struct is_constructible> : is_default_constructible> {}; + +template +struct is_iterator_traits : std::false_type {}; + +template +struct is_iterator_traits> +{ + private: + using traits = iterator_traits; + + public: + static constexpr auto value = + is_detected::value && + is_detected::value && + is_detected::value && + is_detected::value && + is_detected::value; +}; + +template +struct is_range +{ + private: + using t_ref = typename std::add_lvalue_reference::type; + + using iterator = detected_t; + using sentinel = detected_t; + + // to be 100% correct, it should use https://en.cppreference.com/w/cpp/iterator/input_or_output_iterator + // and https://en.cppreference.com/w/cpp/iterator/sentinel_for + // but reimplementing these would be too much work, as a lot of other concepts are used underneath + static constexpr auto is_iterator_begin = + is_iterator_traits>::value; + + public: + static constexpr bool value = !std::is_same::value && !std::is_same::value && is_iterator_begin; +}; + +template +using iterator_t = enable_if_t::value, result_of_begin())>>; + +template +using range_value_t = value_type_t>>; + +// The following implementation of is_complete_type is taken from +// https://blogs.msdn.microsoft.com/vcblog/2015/12/02/partial-support-for-expression-sfinae-in-vs-2015-update-1/ +// and is written by Xiang Fan who agreed to using it in this library. + +template +struct is_complete_type : std::false_type {}; + +template +struct is_complete_type : std::true_type {}; + +template +struct is_compatible_object_type_impl : std::false_type {}; + +template +struct is_compatible_object_type_impl < + BasicJsonType, CompatibleObjectType, + enable_if_t < is_detected::value&& + is_detected::value >> +{ + using object_t = typename BasicJsonType::object_t; + + // macOS's is_constructible does not play well with nonesuch... + static constexpr bool value = + is_constructible::value && + is_constructible::value; +}; + +template +struct is_compatible_object_type + : is_compatible_object_type_impl {}; + +template +struct is_constructible_object_type_impl : std::false_type {}; + +template +struct is_constructible_object_type_impl < + BasicJsonType, ConstructibleObjectType, + enable_if_t < is_detected::value&& + is_detected::value >> +{ + using object_t = typename BasicJsonType::object_t; + + static constexpr bool value = + (is_default_constructible::value && + (std::is_move_assignable::value || + std::is_copy_assignable::value) && + (is_constructible::value && + std::is_same < + typename object_t::mapped_type, + typename ConstructibleObjectType::mapped_type >::value)) || + (has_from_json::value || + has_non_default_from_json < + BasicJsonType, + typename ConstructibleObjectType::mapped_type >::value); +}; + +template +struct is_constructible_object_type + : is_constructible_object_type_impl {}; + +template +struct is_compatible_string_type +{ + static constexpr auto value = + is_constructible::value; +}; + +template +struct is_constructible_string_type +{ + // launder type through decltype() to fix compilation failure on ICPC +#ifdef __INTEL_COMPILER + using laundered_type = decltype(std::declval()); +#else + using laundered_type = ConstructibleStringType; +#endif + + static constexpr auto value = + conjunction < + is_constructible, + is_detected_exact>::value; +}; + +template +struct is_compatible_array_type_impl : std::false_type {}; + +template +struct is_compatible_array_type_impl < + BasicJsonType, CompatibleArrayType, + enable_if_t < + is_detected::value&& + is_iterator_traits>>::value&& +// special case for types like std::filesystem::path whose iterator's value_type are themselves +// c.f. https://github.com/nlohmann/json/pull/3073 + !std::is_same>::value >> +{ + static constexpr bool value = + is_constructible>::value; +}; + +template +struct is_compatible_array_type + : is_compatible_array_type_impl {}; + +template +struct is_constructible_array_type_impl : std::false_type {}; + +template +struct is_constructible_array_type_impl < + BasicJsonType, ConstructibleArrayType, + enable_if_t::value >> + : std::true_type {}; + +template +struct is_constructible_array_type_impl < + BasicJsonType, ConstructibleArrayType, + enable_if_t < !std::is_same::value&& + !is_compatible_string_type::value&& + is_default_constructible::value&& +(std::is_move_assignable::value || + std::is_copy_assignable::value)&& +is_detected::value&& +is_iterator_traits>>::value&& +is_detected::value&& +// special case for types like std::filesystem::path whose iterator's value_type are themselves +// c.f. https://github.com/nlohmann/json/pull/3073 +!std::is_same>::value&& +is_complete_type < +detected_t>::value >> +{ + using value_type = range_value_t; + + static constexpr bool value = + std::is_same::value || + has_from_json::value || + has_non_default_from_json < + BasicJsonType, + value_type >::value; +}; + +template +struct is_constructible_array_type + : is_constructible_array_type_impl {}; + +template +struct is_compatible_integer_type_impl : std::false_type {}; + +template +struct is_compatible_integer_type_impl < + RealIntegerType, CompatibleNumberIntegerType, + enable_if_t < std::is_integral::value&& + std::is_integral::value&& + !std::is_same::value >> +{ + // is there an assert somewhere on overflows? + using RealLimits = std::numeric_limits; + using CompatibleLimits = std::numeric_limits; + + static constexpr auto value = + is_constructible::value && + CompatibleLimits::is_integer && + RealLimits::is_signed == CompatibleLimits::is_signed; +}; + +template +struct is_compatible_integer_type + : is_compatible_integer_type_impl {}; + +template +struct is_compatible_type_impl: std::false_type {}; + +template +struct is_compatible_type_impl < + BasicJsonType, CompatibleType, + enable_if_t::value >> +{ + static constexpr bool value = + has_to_json::value; +}; + +template +struct is_compatible_type + : is_compatible_type_impl {}; + +template +struct is_constructible_tuple : std::false_type {}; + +template +struct is_constructible_tuple> : conjunction...> {}; + +template +struct is_json_iterator_of : std::false_type {}; + +template +struct is_json_iterator_of : std::true_type {}; + +template +struct is_json_iterator_of : std::true_type +{}; + +// checks if a given type T is a template specialization of Primary +template