summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.gitmodules12
-rw-r--r--CMakeLists.txt23
-rw-r--r--CMakeModules/CopyCitraQt5Deps.cmake2
-rw-r--r--dist/citra-qt.640
-rw-r--r--dist/citra.649
-rw-r--r--dist/citra.desktop14
-rw-r--r--dist/citra.icnsbin211056 -> 0 bytes
-rw-r--r--dist/citra.icobin370070 -> 0 bytes
-rw-r--r--dist/citra.svg2
-rw-r--r--dist/citra.xml59
-rw-r--r--dist/doc-icon.pngbin7768 -> 0 bytes
-rw-r--r--dist/icons/checked.pngbin451 -> 0 bytes
-rw-r--r--dist/icons/failed.pngbin428 -> 0 bytes
-rw-r--r--dist/icons/icons.qrc6
-rw-r--r--dist/qt_themes/qdarkstyle/rc/Hmovetoolbar.pngbin220 -> 0 bytes
-rw-r--r--dist/qt_themes/qdarkstyle/rc/Hsepartoolbar.pngbin172 -> 0 bytes
-rw-r--r--dist/qt_themes/qdarkstyle/rc/Vmovetoolbar.pngbin228 -> 0 bytes
-rw-r--r--dist/qt_themes/qdarkstyle/rc/Vsepartoolbar.pngbin187 -> 0 bytes
-rw-r--r--dist/qt_themes/qdarkstyle/rc/branch_closed-on.pngbin147 -> 0 bytes
-rw-r--r--dist/qt_themes/qdarkstyle/rc/branch_closed.pngbin160 -> 0 bytes
-rw-r--r--dist/qt_themes/qdarkstyle/rc/branch_open-on.pngbin150 -> 0 bytes
-rw-r--r--dist/qt_themes/qdarkstyle/rc/branch_open.pngbin166 -> 0 bytes
-rw-r--r--dist/qt_themes/qdarkstyle/rc/checkbox_checked.pngbin492 -> 0 bytes
-rw-r--r--dist/qt_themes/qdarkstyle/rc/checkbox_checked_disabled.pngbin491 -> 0 bytes
-rw-r--r--dist/qt_themes/qdarkstyle/rc/checkbox_checked_focus.pngbin252 -> 0 bytes
-rw-r--r--dist/qt_themes/qdarkstyle/rc/checkbox_indeterminate.pngbin493 -> 0 bytes
-rw-r--r--dist/qt_themes/qdarkstyle/rc/checkbox_indeterminate_disabled.pngbin492 -> 0 bytes
-rw-r--r--dist/qt_themes/qdarkstyle/rc/checkbox_indeterminate_focus.pngbin249 -> 0 bytes
-rw-r--r--dist/qt_themes/qdarkstyle/rc/checkbox_unchecked.pngbin464 -> 0 bytes
-rw-r--r--dist/qt_themes/qdarkstyle/rc/checkbox_unchecked_disabled.pngbin464 -> 0 bytes
-rw-r--r--dist/qt_themes/qdarkstyle/rc/checkbox_unchecked_focus.pngbin240 -> 0 bytes
-rw-r--r--dist/qt_themes/qdarkstyle/rc/close-hover.pngbin598 -> 0 bytes
-rw-r--r--dist/qt_themes/qdarkstyle/rc/close-pressed.pngbin598 -> 0 bytes
-rw-r--r--dist/qt_themes/qdarkstyle/rc/close.pngbin586 -> 0 bytes
-rw-r--r--dist/qt_themes/qdarkstyle/rc/down_arrow.pngbin165 -> 0 bytes
-rw-r--r--dist/qt_themes/qdarkstyle/rc/down_arrow_disabled.pngbin166 -> 0 bytes
-rw-r--r--dist/qt_themes/qdarkstyle/rc/left_arrow.pngbin166 -> 0 bytes
-rw-r--r--dist/qt_themes/qdarkstyle/rc/left_arrow_disabled.pngbin166 -> 0 bytes
-rw-r--r--dist/qt_themes/qdarkstyle/rc/radio_checked.pngbin940 -> 0 bytes
-rw-r--r--dist/qt_themes/qdarkstyle/rc/radio_checked_disabled.pngbin972 -> 0 bytes
-rw-r--r--dist/qt_themes/qdarkstyle/rc/radio_checked_focus.pngbin846 -> 0 bytes
-rw-r--r--dist/qt_themes/qdarkstyle/rc/radio_unchecked.pngbin728 -> 0 bytes
-rw-r--r--dist/qt_themes/qdarkstyle/rc/radio_unchecked_disabled.pngbin760 -> 0 bytes
-rw-r--r--dist/qt_themes/qdarkstyle/rc/radio_unchecked_focus.pngbin646 -> 0 bytes
-rw-r--r--dist/qt_themes/qdarkstyle/rc/right_arrow.pngbin160 -> 0 bytes
-rw-r--r--dist/qt_themes/qdarkstyle/rc/right_arrow_disabled.pngbin160 -> 0 bytes
-rw-r--r--dist/qt_themes/qdarkstyle/rc/sizegrip.pngbin129 -> 0 bytes
-rw-r--r--dist/qt_themes/qdarkstyle/rc/stylesheet-branch-end.pngbin224 -> 0 bytes
-rw-r--r--dist/qt_themes/qdarkstyle/rc/stylesheet-branch-more.pngbin182 -> 0 bytes
-rw-r--r--dist/qt_themes/qdarkstyle/rc/stylesheet-vline.pngbin239 -> 0 bytes
-rw-r--r--dist/qt_themes/qdarkstyle/rc/transparent.pngbin195 -> 0 bytes
-rw-r--r--dist/qt_themes/qdarkstyle/rc/undock.pngbin578 -> 0 bytes
-rw-r--r--dist/qt_themes/qdarkstyle/rc/up_arrow.pngbin158 -> 0 bytes
-rw-r--r--dist/qt_themes/qdarkstyle/rc/up_arrow_disabled.pngbin159 -> 0 bytes
-rw-r--r--dist/qt_themes/qdarkstyle/style.qrc46
-rw-r--r--dist/qt_themes/qdarkstyle/style.qss1268
-rw-r--r--externals/CMakeLists.txt37
-rw-r--r--externals/json/README.md7
-rw-r--r--externals/json/json.hpp14516
-rw-r--r--src/CMakeLists.txt9
-rw-r--r--src/audio_core/CMakeLists.txt44
-rw-r--r--src/audio_core/audio_core.cpp61
-rw-r--r--src/audio_core/audio_core.h31
-rw-r--r--src/audio_core/codec.cpp127
-rw-r--r--src/audio_core/codec.h51
-rw-r--r--src/audio_core/hle/common.h34
-rw-r--r--src/audio_core/hle/dsp.cpp172
-rw-r--r--src/audio_core/hle/dsp.h595
-rw-r--r--src/audio_core/hle/filter.cpp117
-rw-r--r--src/audio_core/hle/filter.h117
-rw-r--r--src/audio_core/hle/mixers.cpp210
-rw-r--r--src/audio_core/hle/mixers.h61
-rw-r--r--src/audio_core/hle/pipe.cpp177
-rw-r--r--src/audio_core/hle/pipe.h63
-rw-r--r--src/audio_core/hle/source.cpp349
-rw-r--r--src/audio_core/hle/source.h149
-rw-r--r--src/audio_core/interpolate.cpp76
-rw-r--r--src/audio_core/interpolate.h49
-rw-r--r--src/audio_core/null_sink.h34
-rw-r--r--src/audio_core/sdl2_sink.cpp147
-rw-r--r--src/audio_core/sdl2_sink.h34
-rw-r--r--src/audio_core/sink.h45
-rw-r--r--src/audio_core/sink_details.cpp42
-rw-r--r--src/audio_core/sink_details.h29
-rw-r--r--src/audio_core/time_stretch.cpp143
-rw-r--r--src/audio_core/time_stretch.h60
-rw-r--r--src/network/CMakeLists.txt18
-rw-r--r--src/network/network.cpp50
-rw-r--r--src/network/network.h25
-rw-r--r--src/network/packet.cpp263
-rw-r--r--src/network/packet.h166
-rw-r--r--src/network/room.cpp497
-rw-r--r--src/network/room.h101
-rw-r--r--src/network/room_member.cpp490
-rw-r--r--src/network/room_member.h182
-rw-r--r--src/web_service/CMakeLists.txt16
-rw-r--r--src/web_service/telemetry_json.cpp86
-rw-r--r--src/web_service/telemetry_json.h59
-rw-r--r--src/web_service/verify_login.cpp28
-rw-r--r--src/web_service/verify_login.h24
-rw-r--r--src/web_service/web_backend.cpp140
-rw-r--r--src/web_service/web_backend.h39
-rw-r--r--src/yuzu/CMakeLists.txt (renamed from src/citra_qt/CMakeLists.txt)22
-rw-r--r--src/yuzu/Info.plist (renamed from src/citra_qt/Info.plist)0
-rw-r--r--src/yuzu/bootmanager.cpp (renamed from src/citra_qt/bootmanager.cpp)0
-rw-r--r--src/yuzu/bootmanager.h (renamed from src/citra_qt/bootmanager.h)0
-rw-r--r--src/yuzu/citra-qt.rc (renamed from src/citra_qt/citra-qt.rc)0
-rw-r--r--src/yuzu/configuration/config.cpp (renamed from src/citra_qt/configuration/config.cpp)0
-rw-r--r--src/yuzu/configuration/config.h (renamed from src/citra_qt/configuration/config.h)0
-rw-r--r--src/yuzu/configuration/configure.ui (renamed from src/citra_qt/configuration/configure.ui)0
-rw-r--r--src/yuzu/configuration/configure_audio.cpp (renamed from src/citra_qt/configuration/configure_audio.cpp)0
-rw-r--r--src/yuzu/configuration/configure_audio.h (renamed from src/citra_qt/configuration/configure_audio.h)0
-rw-r--r--src/yuzu/configuration/configure_audio.ui (renamed from src/citra_qt/configuration/configure_audio.ui)0
-rw-r--r--src/yuzu/configuration/configure_debug.cpp (renamed from src/citra_qt/configuration/configure_debug.cpp)0
-rw-r--r--src/yuzu/configuration/configure_debug.h (renamed from src/citra_qt/configuration/configure_debug.h)0
-rw-r--r--src/yuzu/configuration/configure_debug.ui (renamed from src/citra_qt/configuration/configure_debug.ui)0
-rw-r--r--src/yuzu/configuration/configure_dialog.cpp (renamed from src/citra_qt/configuration/configure_dialog.cpp)0
-rw-r--r--src/yuzu/configuration/configure_dialog.h (renamed from src/citra_qt/configuration/configure_dialog.h)0
-rw-r--r--src/yuzu/configuration/configure_general.cpp (renamed from src/citra_qt/configuration/configure_general.cpp)0
-rw-r--r--src/yuzu/configuration/configure_general.h (renamed from src/citra_qt/configuration/configure_general.h)0
-rw-r--r--src/yuzu/configuration/configure_general.ui (renamed from src/citra_qt/configuration/configure_general.ui)0
-rw-r--r--src/yuzu/configuration/configure_graphics.cpp (renamed from src/citra_qt/configuration/configure_graphics.cpp)0
-rw-r--r--src/yuzu/configuration/configure_graphics.h (renamed from src/citra_qt/configuration/configure_graphics.h)0
-rw-r--r--src/yuzu/configuration/configure_graphics.ui (renamed from src/citra_qt/configuration/configure_graphics.ui)0
-rw-r--r--src/yuzu/configuration/configure_input.cpp (renamed from src/citra_qt/configuration/configure_input.cpp)0
-rw-r--r--src/yuzu/configuration/configure_input.h (renamed from src/citra_qt/configuration/configure_input.h)0
-rw-r--r--src/yuzu/configuration/configure_input.ui (renamed from src/citra_qt/configuration/configure_input.ui)0
-rw-r--r--src/yuzu/configuration/configure_system.cpp (renamed from src/citra_qt/configuration/configure_system.cpp)0
-rw-r--r--src/yuzu/configuration/configure_system.h (renamed from src/citra_qt/configuration/configure_system.h)0
-rw-r--r--src/yuzu/configuration/configure_system.ui (renamed from src/citra_qt/configuration/configure_system.ui)0
-rw-r--r--src/yuzu/configuration/configure_web.cpp (renamed from src/citra_qt/configuration/configure_web.cpp)0
-rw-r--r--src/yuzu/configuration/configure_web.h (renamed from src/citra_qt/configuration/configure_web.h)0
-rw-r--r--src/yuzu/configuration/configure_web.ui (renamed from src/citra_qt/configuration/configure_web.ui)0
-rw-r--r--src/yuzu/debugger/graphics/graphics.cpp (renamed from src/citra_qt/debugger/graphics/graphics.cpp)0
-rw-r--r--src/yuzu/debugger/graphics/graphics.h (renamed from src/citra_qt/debugger/graphics/graphics.h)0
-rw-r--r--src/yuzu/debugger/graphics/graphics_breakpoint_observer.cpp (renamed from src/citra_qt/debugger/graphics/graphics_breakpoint_observer.cpp)0
-rw-r--r--src/yuzu/debugger/graphics/graphics_breakpoint_observer.h (renamed from src/citra_qt/debugger/graphics/graphics_breakpoint_observer.h)0
-rw-r--r--src/yuzu/debugger/graphics/graphics_breakpoints.cpp (renamed from src/citra_qt/debugger/graphics/graphics_breakpoints.cpp)0
-rw-r--r--src/yuzu/debugger/graphics/graphics_breakpoints.h (renamed from src/citra_qt/debugger/graphics/graphics_breakpoints.h)0
-rw-r--r--src/yuzu/debugger/graphics/graphics_breakpoints_p.h (renamed from src/citra_qt/debugger/graphics/graphics_breakpoints_p.h)0
-rw-r--r--src/yuzu/debugger/graphics/graphics_cmdlists.cpp (renamed from src/citra_qt/debugger/graphics/graphics_cmdlists.cpp)0
-rw-r--r--src/yuzu/debugger/graphics/graphics_cmdlists.h (renamed from src/citra_qt/debugger/graphics/graphics_cmdlists.h)0
-rw-r--r--src/yuzu/debugger/graphics/graphics_surface.cpp (renamed from src/citra_qt/debugger/graphics/graphics_surface.cpp)0
-rw-r--r--src/yuzu/debugger/graphics/graphics_surface.h (renamed from src/citra_qt/debugger/graphics/graphics_surface.h)0
-rw-r--r--src/yuzu/debugger/graphics/graphics_tracing.cpp (renamed from src/citra_qt/debugger/graphics/graphics_tracing.cpp)0
-rw-r--r--src/yuzu/debugger/graphics/graphics_tracing.h (renamed from src/citra_qt/debugger/graphics/graphics_tracing.h)0
-rw-r--r--src/yuzu/debugger/graphics/graphics_vertex_shader.cpp (renamed from src/citra_qt/debugger/graphics/graphics_vertex_shader.cpp)0
-rw-r--r--src/yuzu/debugger/graphics/graphics_vertex_shader.h (renamed from src/citra_qt/debugger/graphics/graphics_vertex_shader.h)0
-rw-r--r--src/yuzu/debugger/profiler.cpp (renamed from src/citra_qt/debugger/profiler.cpp)0
-rw-r--r--src/yuzu/debugger/profiler.h (renamed from src/citra_qt/debugger/profiler.h)0
-rw-r--r--src/yuzu/debugger/registers.cpp (renamed from src/citra_qt/debugger/registers.cpp)0
-rw-r--r--src/yuzu/debugger/registers.h (renamed from src/citra_qt/debugger/registers.h)0
-rw-r--r--src/yuzu/debugger/registers.ui (renamed from src/citra_qt/debugger/registers.ui)0
-rw-r--r--src/yuzu/debugger/wait_tree.cpp (renamed from src/citra_qt/debugger/wait_tree.cpp)0
-rw-r--r--src/yuzu/debugger/wait_tree.h (renamed from src/citra_qt/debugger/wait_tree.h)0
-rw-r--r--src/yuzu/game_list.cpp (renamed from src/citra_qt/game_list.cpp)0
-rw-r--r--src/yuzu/game_list.h (renamed from src/citra_qt/game_list.h)0
-rw-r--r--src/yuzu/game_list_p.h (renamed from src/citra_qt/game_list_p.h)0
-rw-r--r--src/yuzu/hotkeys.cpp (renamed from src/citra_qt/hotkeys.cpp)0
-rw-r--r--src/yuzu/hotkeys.h (renamed from src/citra_qt/hotkeys.h)0
-rw-r--r--src/yuzu/hotkeys.ui (renamed from src/citra_qt/hotkeys.ui)0
-rw-r--r--src/yuzu/main.cpp (renamed from src/citra_qt/main.cpp)0
-rw-r--r--src/yuzu/main.h (renamed from src/citra_qt/main.h)0
-rw-r--r--src/yuzu/main.ui (renamed from src/citra_qt/main.ui)0
-rw-r--r--src/yuzu/ui_settings.cpp (renamed from src/citra_qt/ui_settings.cpp)0
-rw-r--r--src/yuzu/ui_settings.h (renamed from src/citra_qt/ui_settings.h)0
-rw-r--r--src/yuzu/util/spinbox.cpp (renamed from src/citra_qt/util/spinbox.cpp)0
-rw-r--r--src/yuzu/util/spinbox.h (renamed from src/citra_qt/util/spinbox.h)0
-rw-r--r--src/yuzu/util/util.cpp (renamed from src/citra_qt/util/util.cpp)0
-rw-r--r--src/yuzu/util/util.h (renamed from src/citra_qt/util/util.h)0
-rw-r--r--src/yuzu_cmd/CMakeLists.txt (renamed from src/citra/CMakeLists.txt)16
-rw-r--r--src/yuzu_cmd/citra.cpp (renamed from src/citra/citra.cpp)0
-rw-r--r--src/yuzu_cmd/citra.rc (renamed from src/citra/citra.rc)0
-rw-r--r--src/yuzu_cmd/config.cpp (renamed from src/citra/config.cpp)0
-rw-r--r--src/yuzu_cmd/config.h (renamed from src/citra/config.h)0
-rw-r--r--src/yuzu_cmd/default_ini.h (renamed from src/citra/default_ini.h)0
-rw-r--r--src/yuzu_cmd/emu_window/emu_window_sdl2.cpp (renamed from src/citra/emu_window/emu_window_sdl2.cpp)0
-rw-r--r--src/yuzu_cmd/emu_window/emu_window_sdl2.h (renamed from src/citra/emu_window/emu_window_sdl2.h)0
-rw-r--r--src/yuzu_cmd/resource.h (renamed from src/citra/resource.h)0
179 files changed, 23 insertions, 21306 deletions
diff --git a/.gitmodules b/.gitmodules
index 87d156035..07479dd78 100644
--- a/.gitmodules
+++ b/.gitmodules
@@ -4,12 +4,6 @@
4[submodule "boost"] 4[submodule "boost"]
5 path = externals/boost 5 path = externals/boost
6 url = https://github.com/yuzu-emu/ext-boost.git 6 url = https://github.com/yuzu-emu/ext-boost.git
7[submodule "nihstro"]
8 path = externals/nihstro
9 url = https://github.com/neobrain/nihstro.git
10[submodule "soundtouch"]
11 path = externals/soundtouch
12 url = https://github.com/citra-emu/ext-soundtouch.git
13[submodule "catch"] 7[submodule "catch"]
14 path = externals/catch 8 path = externals/catch
15 url = https://github.com/philsquared/Catch.git 9 url = https://github.com/philsquared/Catch.git
@@ -22,12 +16,6 @@
22[submodule "fmt"] 16[submodule "fmt"]
23 path = externals/fmt 17 path = externals/fmt
24 url = https://github.com/fmtlib/fmt.git 18 url = https://github.com/fmtlib/fmt.git
25[submodule "enet"]
26 path = externals/enet
27 url = https://github.com/lsalzman/enet
28[submodule "cpr"]
29 path = externals/cpr
30 url = https://github.com/whoshuu/cpr.git
31[submodule "lz4"] 19[submodule "lz4"]
32 path = externals/lz4 20 path = externals/lz4
33 url = http://github.com/lz4/lz4.git 21 url = http://github.com/lz4/lz4.git
diff --git a/CMakeLists.txt b/CMakeLists.txt
index b2fd0ca81..5dd11b6a4 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -4,7 +4,7 @@ list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/CMakeModules")
4list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/externals/cmake-modules") 4list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/externals/cmake-modules")
5include(DownloadExternals) 5include(DownloadExternals)
6 6
7project(citra) 7project(yuzu)
8 8
9option(ENABLE_SDL2 "Enable the SDL2 frontend" ON) 9option(ENABLE_SDL2 "Enable the SDL2 frontend" ON)
10option(CITRA_USE_BUNDLED_SDL2 "Download bundled SDL2 binaries" OFF) 10option(CITRA_USE_BUNDLED_SDL2 "Download bundled SDL2 binaries" OFF)
@@ -14,17 +14,6 @@ option(CITRA_USE_BUNDLED_QT "Download bundled Qt binaries" OFF)
14 14
15option(YUZU_USE_BUNDLED_UNICORN "Download bundled Unicorn binaries" OFF) 15option(YUZU_USE_BUNDLED_UNICORN "Download bundled Unicorn binaries" OFF)
16 16
17option(ENABLE_WEB_SERVICE "Enable web services (telemetry, etc.)" ON)
18option(CITRA_USE_BUNDLED_CURL "FOR MINGW ONLY: Download curl configured against winssl instead of openssl" OFF)
19if (ENABLE_WEB_SERVICE AND CITRA_USE_BUNDLED_CURL AND WINDOWS AND MSVC)
20 message("Turning off use bundled curl as msvc can compile curl on cpr")
21 SET(CITRA_USE_BUNDLED_CURL OFF CACHE BOOL "" FORCE)
22endif()
23if (ENABLE_WEB_SERVICE AND NOT CITRA_USE_BUNDLED_CURL AND MINGW)
24 message(AUTHOR_WARNING "Turning on CITRA_USE_BUNDLED_CURL. Override it only if you know what you are doing.")
25 SET(CITRA_USE_BUNDLED_CURL ON CACHE BOOL "" FORCE)
26endif()
27
28if(NOT EXISTS ${CMAKE_SOURCE_DIR}/.git/hooks/pre-commit) 17if(NOT EXISTS ${CMAKE_SOURCE_DIR}/.git/hooks/pre-commit)
29 message(STATUS "Copying pre-commit hook") 18 message(STATUS "Copying pre-commit hook")
30 file(COPY hooks/pre-commit 19 file(COPY hooks/pre-commit
@@ -154,7 +143,6 @@ if(CMAKE_SYSTEM_NAME STREQUAL "Linux")
154 add_definitions(-D_FILE_OFFSET_BITS=64) 143 add_definitions(-D_FILE_OFFSET_BITS=64)
155endif() 144endif()
156 145
157add_definitions(-DSINGLETHREADED)
158# CMake seems to only define _DEBUG on Windows 146# CMake seems to only define _DEBUG on Windows
159set_property(DIRECTORY APPEND PROPERTY 147set_property(DIRECTORY APPEND PROPERTY
160 COMPILE_DEFINITIONS $<$<CONFIG:Debug>:_DEBUG> $<$<NOT:$<CONFIG:Debug>>:NDEBUG>) 148 COMPILE_DEFINITIONS $<$<CONFIG:Debug>:_DEBUG> $<$<NOT:$<CONFIG:Debug>>:NDEBUG>)
@@ -163,11 +151,6 @@ set_property(DIRECTORY APPEND PROPERTY
163# System imported libraries 151# System imported libraries
164# ====================== 152# ======================
165 153
166find_package(PNG QUIET)
167if (NOT PNG_FOUND)
168 message(STATUS "libpng not found. Some debugging features have been disabled.")
169endif()
170
171find_package(Boost 1.63.0 QUIET) 154find_package(Boost 1.63.0 QUIET)
172if (NOT Boost_FOUND) 155if (NOT Boost_FOUND)
173 message(STATUS "Boost 1.63.0 or newer not found, falling back to externals") 156 message(STATUS "Boost 1.63.0 or newer not found, falling back to externals")
@@ -264,10 +247,6 @@ if (ENABLE_QT)
264 find_package(Qt5 REQUIRED COMPONENTS Widgets OpenGL ${QT_PREFIX_HINT}) 247 find_package(Qt5 REQUIRED COMPONENTS Widgets OpenGL ${QT_PREFIX_HINT})
265endif() 248endif()
266 249
267if (ENABLE_WEB_SERVICE)
268 add_definitions(-DENABLE_WEB_SERVICE)
269endif()
270
271# Platform-specific library requirements 250# Platform-specific library requirements
272# ====================================== 251# ======================================
273 252
diff --git a/CMakeModules/CopyCitraQt5Deps.cmake b/CMakeModules/CopyCitraQt5Deps.cmake
index 05f58cf9a..342d0b915 100644
--- a/CMakeModules/CopyCitraQt5Deps.cmake
+++ b/CMakeModules/CopyCitraQt5Deps.cmake
@@ -13,5 +13,5 @@ function(copy_citra_Qt5_deps target_dir)
13 Qt5OpenGL$<$<CONFIG:Debug>:d>.* 13 Qt5OpenGL$<$<CONFIG:Debug>:d>.*
14 Qt5Widgets$<$<CONFIG:Debug>:d>.* 14 Qt5Widgets$<$<CONFIG:Debug>:d>.*
15 ) 15 )
16 windows_copy_files(citra-qt ${Qt5_PLATFORMS_DIR} ${PLATFORMS} qwindows$<$<CONFIG:Debug>:d>.*) 16 windows_copy_files(yuzu ${Qt5_PLATFORMS_DIR} ${PLATFORMS} qwindows$<$<CONFIG:Debug>:d>.*)
17endfunction(copy_citra_Qt5_deps) 17endfunction(copy_citra_Qt5_deps)
diff --git a/dist/citra-qt.6 b/dist/citra-qt.6
deleted file mode 100644
index d09e96b5d..000000000
--- a/dist/citra-qt.6
+++ /dev/null
@@ -1,40 +0,0 @@
1.Dd November 22 2016
2.Dt citra-qt 6
3.Os
4.Sh NAME
5.Nm Citra-Qt
6.Nd Nintendo 3DS Emulator/Debugger (Qt)
7.Sh SYNOPSIS
8.Nm citra-qt
9.Op Ar file
10.Sh DESCRIPTION
11Citra is an experimental open-source Nintendo 3DS emulator/debugger.
12.Pp
13.Nm citra-qt
14is the Qt implementation.
15.Sh FILES
16.Bl -tag -width Ds
17.It Pa $XDG_DATA_HOME/citra-emu
18Emulator storage.
19.It Pa $XDG_CONFIG_HOME/citra-emu
20Configuration files.
21.El
22.Sh AUTHORS
23This document is made available to you under the CC-BY license.
24.Pp
25Citra is made by a team of volunteers. These contributors are listed
26 at <\fBhttps://github.com/citra-emu/citra/contributors\fR>.
27.Pp
28.Sh SEE ALSO
29.Bl -tag -width Ds
30.It Xr citra 6
31The SDL frontend of the application
32.El
33.Pp
34Resources are available for this project:
35.Bl -tag -width Ds
36.It <\fBhttps://citra-emu.org\fR>
37The main homepage of the project.
38.It <\fBhttps://github.com/citra-emu/citra\fR>
39The main source code repository for the Citra emulator.
40.Pp
diff --git a/dist/citra.6 b/dist/citra.6
deleted file mode 100644
index 72483b1dd..000000000
--- a/dist/citra.6
+++ /dev/null
@@ -1,49 +0,0 @@
1.Dd November 22 2016
2.Dt citra 6
3.Os
4.Sh NAME
5.Nm Citra
6.Nd Nintendo 3DS Emulator/Debugger (SDL)
7.Sh SYNOPSIS
8.Nm citra
9.Op Ar options
10.Op Ar file
11.Sh OPTIONS
12.Bl -tag -width Ds
13.It Fl g Ar port , Fl Fl gdbport Ar port
14Starts the GDB stub on the specified port
15.It Fl h , Fl Fl help
16Shows syntax help and exits
17.It Fl v , Fl Fl version
18Describes the installed version and exits
19.Sh DESCRIPTION
20Citra is an experimental open-source Nintendo 3DS emulator/debugger.
21.Pp
22.Nm citra
23is the Simple DirectMedia Layer (SDL) implementation.
24.Sh FILES
25.Bl -tag -width Ds
26.It Pa $XDG_DATA_HOME/citra-emu
27Emulator storage.
28.It Pa $XDG_CONFIG_HOME/citra-emu
29Configuration files.
30.El
31.Sh AUTHORS
32This document is made available to you under the CC-BY license.
33.Pp
34Citra is made by a team of volunteers. These contributors are listed
35 at <\fBhttps://github.com/citra-emu/citra/contributors\fR>.
36.Pp
37.Sh SEE ALSO
38.Bl -tag -width Ds
39.It Xr citra-qt 6
40The Qt frontend of the application
41.El
42.Pp
43Resources are available for this project:
44.Bl -tag -width Ds
45.It <\fBhttps://citra-emu.org\fR>
46The main homepage of the project.
47.It <\fBhttps://github.com/citra-emu/citra\fR>
48The main source code repository for the Citra emulator.
49.Pp
diff --git a/dist/citra.desktop b/dist/citra.desktop
deleted file mode 100644
index 1300d62c2..000000000
--- a/dist/citra.desktop
+++ /dev/null
@@ -1,14 +0,0 @@
1[Desktop Entry]
2Version=1.0
3Type=Application
4Name=Citra
5GenericName=3DS Emulator
6GenericName[fr]=Émulateur 3DS
7Comment=Nintendo 3DS video game console emulator
8Comment[fr]=Émulateur de console de jeu Nintendo 3DS
9Icon=citra
10TryExec=citra-qt
11Exec=citra-qt %f
12Categories=Game;Emulator;Qt;
13MimeType=application/x-ctr-3dsx;application/x-ctr-cci;application/x-ctr-cia;application/x-ctr-cxi;
14Keywords=3DS;Nintendo;
diff --git a/dist/citra.icns b/dist/citra.icns
deleted file mode 100644
index ef7bf4e6e..000000000
--- a/dist/citra.icns
+++ /dev/null
Binary files differ
diff --git a/dist/citra.ico b/dist/citra.ico
deleted file mode 100644
index 2c408b935..000000000
--- a/dist/citra.ico
+++ /dev/null
Binary files differ
diff --git a/dist/citra.svg b/dist/citra.svg
deleted file mode 100644
index b6abc1ccf..000000000
--- a/dist/citra.svg
+++ /dev/null
@@ -1,2 +0,0 @@
1<?xml version="1.0" encoding="UTF-8"?>
2<svg version="1.1" viewBox="0 0 433.93 397.43" xml:space="preserve" xmlns="http://www.w3.org/2000/svg" xmlns:cc="http://creativecommons.org/ns#" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns:xlink="http://www.w3.org/1999/xlink"><metadata><rdf:RDF><cc:Work rdf:about=""><dc:format>image/svg+xml</dc:format><dc:type rdf:resource="http://purl.org/dc/dcmitype/StillImage"/><dc:title/></cc:Work></rdf:RDF></metadata><defs><linearGradient id="linearGradient7230"><stop stop-color="#f15a24" offset="0"/><stop stop-color="#f15a24" stop-opacity="0" offset="1"/></linearGradient><radialGradient id="radialGradient4297" cx="0" cy="0" r="1" fx=".33908" fy="-.55275" gradientTransform="matrix(135.72 53.102 32.823 -83.888 479.47 287.23)" gradientUnits="userSpaceOnUse"><stop stop-color="#ffff87" offset="0"/><stop stop-color="#ffff87" offset=".12648"/><stop stop-color="#ffc503" offset=".14449"/><stop stop-color="#ffc503" offset=".21612"/><stop stop-color="#ffc503" offset=".39528"/><stop stop-color="#ffc503" offset=".4406"/><stop stop-color="#ffc003" offset=".49983"/><stop stop-color="#ffc003" offset=".62818"/><stop stop-color="#ffc003" offset=".72864"/><stop stop-color="#ff8904" stop-opacity=".86935" offset=".84938"/><stop stop-color="#ff8904" offset=".98742"/><stop stop-color="#ff8904" offset="1"/></radialGradient><radialGradient id="radialGradient4331" cx="-.042447" cy=".042662" r="1" gradientTransform="matrix(97.003 -81.357 -81.357 -97.003 516.33 432.83)" gradientUnits="userSpaceOnUse"><stop stop-color="#ff0" offset="0"/><stop stop-color="#ffba05" offset=".66567"/><stop stop-color="#ffba05" offset="1"/></radialGradient><radialGradient id="radialGradient4351" cx="0" cy="0" r="1" gradientTransform="matrix(-12.353 -91.85 -91.85 12.353 493.83 420.5)" gradientUnits="userSpaceOnUse"><stop stop-color="#ff0" offset="0"/><stop stop-color="#ffba05" offset="1"/></radialGradient><radialGradient id="radialGradient4371" cx="0" cy="0" r="1" fx="-.89202" fy="-.452" gradientTransform="matrix(58.797 44.174 44.174 -58.797 591.5 452.83)" gradientUnits="userSpaceOnUse"><stop stop-color="#ff0" offset="0"/><stop stop-color="#ffba05" offset="1"/></radialGradient><radialGradient id="radialGradient4391" cx="0" cy="0" r="1" gradientTransform="matrix(-63.936 -51.968 -51.968 63.936 480.5 419.5)" gradientUnits="userSpaceOnUse"><stop stop-color="#ff0" offset="0"/><stop stop-color="#ffba05" offset="1"/></radialGradient><radialGradient id="radialGradient4413" cx="-.27681" cy="-.01256" r="1" gradientTransform="matrix(166.21 117.68 75.941 -107.26 545.45 466.23)" gradientUnits="userSpaceOnUse"><stop stop-color="#ff0" offset="0"/><stop stop-color="#ffee05" offset=".49699"/><stop stop-color="#ffba05" offset="1"/></radialGradient><radialGradient id="radialGradient4433" cx=".0693" cy=".0013088" r="1" gradientTransform="matrix(92.166 1.56 1.3981 -82.601 484.17 431.17)" gradientUnits="userSpaceOnUse"><stop stop-color="#ff0" offset="0"/><stop stop-color="#ffba05" offset="1"/></radialGradient><radialGradient id="radialGradient4453" cx="0" cy="0" r="1" gradientTransform="matrix(112.47 78.731 51.056 -72.937 527.5 460.5)" gradientUnits="userSpaceOnUse"><stop stop-color="#ff0" offset="0"/><stop stop-color="#ffba05" offset="1"/></radialGradient><radialGradient id="radialGradient4475" cx=".13237" cy="-.0012055" r="1" fx="-.080444" fy=".038791" gradientTransform="matrix(64.042 -58.572 -66.76 -72.994 505.91 439.83)" gradientUnits="userSpaceOnUse"><stop stop-color="#ff0" offset="0"/><stop stop-color="#ffcf05" offset=".62977"/><stop stop-color="#ffcf05" offset="1"/></radialGradient><linearGradient id="linearGradient7248-9" x1="382.8" x2="662.93" y1="393.32" y2="393.32" gradientUnits="userSpaceOnUse" xlink:href="#linearGradient7230"/><clipPath id="clipPath4307-2"><path d="m640.25 512.56c0.366-0.686 1.015-1.901 1.507-3.229 0.237-0.588 0.284-0.774 0.375-1.057 0.174-0.52 0.277-0.819 0.368-1.099 0.09-0.28 0.019-0.115 0.107-0.392 0.087-0.277 0.181-0.577 0.264-0.852 0.082-0.276 0.15-0.659 0.224-0.934 0.076-0.276 0.167-0.604 0.233-0.881 0.066-0.276 0.257-1.337 0.312-1.615 0.316-1.599 0.241-2.12 0.401-3.701 0.16-1.58 0.244-3.151 0.26-4.712 0.016-1.563-0.038-3.115-0.154-4.66-0.117-1.545-0.296-3.081-0.533-4.61-0.237-1.528-0.531-3.049-0.877-4.562-0.345-1.513-0.742-3.02-1.184-4.518-0.442-1.5-0.93-2.992-1.457-4.478-0.527-1.485-1.094-2.964-1.694-4.438-1.181-2.896-2.451-5.732-3.805-8.51-1.353-2.778-2.789-5.5-4.302-8.169-1.512-2.671-3.099-5.288-4.755-7.858-1.656-2.571-3.38-5.093-5.165-7.574-1.785-2.48-3.631-4.918-5.53-7.318-1.9-2.4-3.853-4.762-5.852-7.09s-4.044-4.624-6.129-6.89c-2.084-2.267-4.207-4.506-6.362-6.72-2.218-2.28-4.472-4.518-6.76-6.714-2.287-2.197-4.608-4.353-6.961-6.47s-4.737-4.196-7.152-6.237-4.86-4.046-7.334-6.016c-2.473-1.969-4.975-3.904-7.504-5.806-2.528-1.902-5.084-3.771-7.664-5.609-2.581-1.838-5.187-3.645-7.816-5.423-2.63-1.778-5.282-3.527-7.957-5.247-3.325-2.142-6.677-4.217-10.058-6.225-3.381-2.007-6.792-3.946-10.232-5.813-3.441-1.867-6.912-3.661-10.416-5.38s-7.041-3.362-10.611-4.924c-3.571-1.563-7.177-3.046-10.818-4.446-1.846-0.709-3.702-1.398-5.566-2.064-1.814-0.648-3.636-1.274-5.468-1.88-3.716-1.228-7.47-2.37-11.263-3.42-3.794-1.049-7.627-2.009-11.502-2.872-1.624-0.362-3.249-0.695-4.876-1-1.627-0.304-3.255-0.578-4.886-0.823-1.631-0.244-3.262-0.457-4.896-0.638s-3.269-0.33-4.907-0.445c-1.636-0.116-3.275-0.197-4.915-0.245-1.639-0.046-3.28-0.058-4.923-0.034-1.641 0.024-3.285 0.085-4.929 0.183-1.645 0.097-3.29 0.233-4.937 0.408-1.337 0.142-2.664 0.317-3.979 0.531s-2.617 0.466-3.906 0.759c-1.288 0.294-2.562 0.627-3.819 1.007-1.256 0.38-2.496 0.805-3.717 1.278-1.22 0.475-2.422 0.997-3.602 1.571-1.179 0.575-2.337 1.201-3.471 1.884-1.133 0.683-2.244 1.421-3.326 2.22-1.084 0.798-2.656 1.973-3.685 2.893l-3.143-7.259c-3.143-7.26 1.5-6 3.143-8.5 1.644-2.5 0.357-9 0.217-15s6.64-11.5 9.64-14.5c3-3.001 10-10.5 14.5-11.82 4.5-1.319 23.5-16.18 30-18.181 6.5-1.999 13.5-6.999 22-8.499s19-3 27.5-3 26.5-0.5 38.5 0 27 3 33 4 20 2.5 27.5 4.5 23.5 8 27 11.5 28 13.999 33.5 20c5.5 6 24 39.5 25 45.5s14 47.499 17 53c3 5.5 0 39.499 0 45.5 0 6-10 45-10 45l-13.5 28.5-14 14.5z"/></clipPath><radialGradient id="radialGradient7556" cx="698.21" cy="478.94" r="186.38" gradientTransform="matrix(1.2034 -.41433 .38181 1.1089 -338.27 245.75)" gradientUnits="userSpaceOnUse"><stop stop-color="#f15a24" stop-opacity="0" offset="0"/><stop stop-color="#f15a24" stop-opacity="0" offset=".68534"/><stop stop-color="#f14a24" offset="1"/></radialGradient></defs><g transform="translate(-265.81 -357.85)"><g transform="translate(-206,70)"><path d="m651.83 684.53c-17.986-2.258-43.941-8.1382-59.303-13.436-45.416-15.66-91.627-51.387-112.29-86.813-7.3922-12.675-9.8553-29.065-7.6405-50.846 1.5707-15.448 4.2385-24.955 10.938-38.978 20.81-43.561 55.611-85.05 100.64-119.99 33.898-26.298 69.589-47.881 101.64-61.46 27.534-11.666 61.915-21.532 84.068-24.123 27.343-3.1985 56.096 1.1638 74.647 11.325 18.752 10.271 30.61 25.375 43.922 55.939 12.492 28.684 17.312 55.294 17.291 95.461-0.0151 34.075-4.1728 58.552-14.29 84.174-8.402 21.279-21.718 44.014-36.542 62.391-6.6008 8.1824-26.727 28.053-35.45 35-19.832 15.793-45.654 30.387-66.248 37.441-17.156 5.8765-39.99 11.132-59.144 13.612-9.676 1.253-33.307 1.4198-42.243 0.29802z" fill="#fff" stroke-width=".75166"/><g transform="matrix(1.3333 0 0 -1.3333 0 1024)"><path d="m508.37 418.38c-1.948-9.873-2.175-19.875-2.148-30.734 0.105-4.803-8e-3 -10.436 0.607-16.082 1.248-11.467 5.143-14.109 15.617-9.51 17.862 7.84 33.696 18.829 47.854 32.241 3.988 3.779 8.185 7.422 11.089 12.202 2.673 4.397 2.097 6.88-2.266 9.608-1.396 0.873-2.949 1.54-4.502 2.103-5.181 1.881-10.542 3.121-15.918 4.281-12.621 2.721-25.222 5.644-38.216 5.823-0.08 1e-3 -0.159 1e-3 -0.239 1e-3 -6.452 0-10.63-3.605-11.878-9.933" fill="url(#radialGradient4331)"/></g><g transform="matrix(1.3333 0 0 -1.3333 0 1024)"><path d="m492.04 416.52c-3.243-1.617-5.823-4.156-8.361-6.684-16.977-16.905-32.998-34.704-48.672-52.819-4.26-4.924-8.651-9.823-11.376-15.886-1.919-4.27-0.934-6.454 3.654-7.668 4.725-1.249 9.544-1.787 14.436-1.358 11.696 1.026 22.799 4.32 33.655 8.677 10.044 4.032 16.339 11.18 18.544 21.838 2.891 13.979 3.907 28.175 4.618 42.392 0 2.182 0.021 4.364-0.013 6.545-0.01 0.636-0.15 1.274-0.276 1.902-0.545 2.722-1.447 4.01-3.104 4.01-0.83 0-1.848-0.323-3.105-0.949" fill="url(#radialGradient4351)"/></g><g transform="matrix(1.3333 0 0 -1.3333 0 1024)"><path d="m623.43 485.96c-2.879-0.515-5.736-1.318-8.503-2.282-15.719-5.482-30.649-12.847-45.782-19.703-12.92-5.855-25.833-11.785-38.083-19.013-2.413-1.425-5.354-3.1-4.765-6.319 0.504-2.751 3.758-2.789 6.016-3.319 17.339-4.073 35.01-5.712 51.316-7.058 10.474 0.119 18.926 1.786 25.516 8.829 6.88 7.354 12.632 15.489 16.919 24.601 2.691 5.72 4.477 11.786 4.479 18.169 2e-3 4.153-1.835 6.272-5.267 6.272-0.571 0-1.188-0.059-1.846-0.177" fill="url(#radialGradient4371)"/></g><g transform="matrix(1.3333 0 0 -1.3333 0 1024)"><path d="m475.92 419.25c-0.367-0.104-0.71-0.292-1.065-0.437-22.555-9.166-44.21-20.249-65.865-31.321-5.464-2.792-10.748-5.939-15.684-9.652-5.297-3.984-8.316-8.98-7.651-15.694 0-0.89-0.035-1.662 5e-3 -2.431 0.397-7.627 4.249-12.981 10.812-16.559 6.098-3.323 11.35-1.172 16.365 2.52 1.236 0.911 2.498 1.799 3.649 2.811 22.843 20.104 43.28 42.565 63.347 65.381 1.264 1.437 3.447 3.141 2.012 5.299-0.613 0.922-1.333 1.232-2.102 1.231-1.232 0-2.589-0.797-3.823-1.148" fill="url(#radialGradient4391)"/></g><g transform="matrix(1.3333 0 0 -1.3333 0 1024)"><path d="m589.81 520.12c-2.155-1.598-4.18-3.381-6.195-5.159-14.338-12.647-27.085-26.892-40.259-40.697-5.472-5.734-10.87-11.588-15.617-17.981-0.828-1.116-1.856-2.369-0.83-3.824 0.972-1.379 2.519-1.147 3.87-0.737 1.831 0.556 3.62 1.272 5.386 2.018 23.705 10.024 46.647 21.655 69.496 33.464 6.568 3.394 13.185 6.854 18.588 12.131 2.02 1.974 3.277 4.24 3.342 7.436-0.072 2.307-0.943 4.698-2.221 6.96-4.063 7.191-12.308 11.156-20.705 11.156-5.215 0-10.489-1.53-14.855-4.767" fill="url(#radialGradient4413)"/></g><g transform="matrix(1.3333 0 0 -1.3333 0 1024)"><path d="m413.44 432.07c-5.861-6.67-11.407-13.524-15.914-21.172-2.874-4.876-5.175-10.064-6.355-15.632-0.819-3.866 0.412-5.458 3.711-5.517 2.078 0.023 4.038 0.607 5.971 1.3 18.942 6.786 36.964 15.693 55.17 24.173 7.774 3.62 15.486 7.375 22.781 11.914 2.187 1.361 4.634 2.997 4.191 5.914-0.396 2.604-3.356 2.319-5.257 3.169-0.692 0.308-1.469 0.436-2.215 0.612-11.727 2.765-23.679 4.039-35.625 5.305-1.381 0.147-2.734 0.221-4.058 0.221-8.707 0-16.182-3.211-22.4-10.287" fill="url(#radialGradient4433)"/></g><g transform="matrix(1.3333 0 0 -1.3333 0 1024)"><path d="m567.31 526.82c-14.169-1.46-27.39-6.06-40.199-12.109-7.73-3.652-12.567-9.493-14.146-17.954-1.793-9.597-3.042-19.253-2.904-29.045 0-2.697-0.068-5.395 0.022-8.089 0.067-1.997-0.399-4.391 1.83-5.503 2.219-1.108 4.351 0.084 6.055 1.392 2.834 2.177 5.567 4.529 8.099 7.054 14.061 14.024 27.283 28.841 40.42 43.726 4.051 4.589 8.321 9.1 10.964 14.772 1.594 3.423 0.812 4.978-2.88 5.7-1.112 0.218-2.231 0.3-3.353 0.3-1.302 0-2.607-0.11-3.908-0.244" fill="url(#radialGradient4453)"/></g><g transform="matrix(1.3333 0 0 -1.3333 0 1024)"><path d="m493.43 497.7c-3.943-1.236-7.454-3.334-11.002-5.368-14.602-8.364-28.162-18.128-39.782-30.405-5.392-5.696-4.536-9.429 2.935-11.564 13.892-3.97 27.998-7.036 42.519-7.395 7.646-0.189 11.495 3.378 12.86 10.836 1.395 7.615 1.69 15.275 1.485 25.395-0.22 3.072 0.784 8.645-0.687 14.051-0.943 3.472-2.527 5.026-5.134 5.025-0.929 0-1.988-0.197-3.194-0.575" fill="url(#radialGradient4475)"/></g><g transform="matrix(1.3333 0 0 -1.3333 0 1024)"><path d="m641.75 509.34c0.237-0.588 0.284-0.774 0.375-1.057 0.174-0.52 0.277-0.819 0.368-1.099 0.09-0.28 0.019-0.115 0.107-0.392 0.087-0.277 0.181-0.577 0.264-0.852 0.082-0.276 0.15-0.659 0.224-0.934 0.076-0.276 0.167-0.604 0.233-0.881 0.066-0.276 0.257-1.337 0.312-1.615 0.316-1.599 0.241-2.12 0.401-3.701 0.16-1.58 0.244-3.151 0.26-4.712 0.016-1.563-0.038-3.115-0.154-4.66-0.117-1.545-0.296-3.081-0.533-4.61-0.237-1.528-0.531-3.049-0.877-4.562-0.345-1.513-0.742-3.02-1.184-4.518-0.442-1.5-0.93-2.992-1.457-4.478-0.527-1.485-1.094-2.964-1.694-4.438-1.181-2.896-2.451-5.732-3.805-8.51-1.353-2.778-2.789-5.5-4.302-8.169-1.512-2.671-3.099-5.288-4.755-7.858-1.656-2.571-3.38-5.093-5.165-7.574-1.785-2.48-3.631-4.918-5.53-7.318-1.9-2.4-3.853-4.762-5.852-7.09s-4.044-4.624-6.129-6.89c-2.084-2.267-4.207-4.506-6.362-6.72-2.218-2.28-4.472-4.518-6.76-6.714-2.287-2.197-4.608-4.353-6.961-6.47s-4.737-4.196-7.152-6.237-4.86-4.046-7.334-6.016c-2.473-1.969-4.975-3.904-7.504-5.806-2.528-1.902-5.084-3.771-7.664-5.609-2.581-1.838-5.187-3.645-7.816-5.423-2.63-1.778-5.282-3.527-7.957-5.247-3.325-2.142-6.677-4.217-10.058-6.225-3.381-2.007-6.792-3.946-10.232-5.813-3.441-1.867-6.912-3.661-10.416-5.38s-7.041-3.362-10.611-4.924c-3.571-1.563-7.177-3.046-10.818-4.446-1.846-0.709-3.702-1.398-5.566-2.064-1.814-0.648-3.636-1.274-5.468-1.88-3.716-1.228-7.47-2.37-11.263-3.42-3.794-1.049-7.627-2.009-11.502-2.872-1.624-0.362-3.249-0.695-4.876-1-1.627-0.304-3.255-0.578-4.886-0.823-1.631-0.244-3.262-0.457-4.896-0.638s-3.269-0.33-4.907-0.445c-1.636-0.116-3.275-0.197-4.915-0.245-1.639-0.046-3.28-0.058-4.923-0.034-1.641 0.024-3.285 0.085-4.929 0.183-1.645 0.097-3.29 0.233-4.937 0.408-1.337 0.142-2.664 0.317-3.979 0.531s-2.617 0.466-3.906 0.759c-1.288 0.294-2.562 0.627-3.819 1.007-1.256 0.38-2.496 0.805-3.717 1.278-1.22 0.475-2.422 0.997-3.602 1.571-0.749 0.365-1.489 0.751-2.22 1.159-0.522 0.286-1.038 0.583-1.55 0.891-1.134 0.683-2.243 1.421-3.327 2.219-0.744 0.549-1.475 1.125-2.194 1.731-0.282 0.225-0.554 0.448-0.806 0.662 5.18-5.701 10.508-11.008 15.987-15.904 5.538-4.95 11.227-9.48 17.07-13.573 5.843-4.094 11.839-7.751 17.987-10.956 6.148-3.204 12.449-5.954 18.901-8.236 6.453-2.28 13.059-4.091 19.816-5.415 6.758-1.325 13.668-2.162 20.731-2.495s14.278-0.163 21.645 0.528c7.368 0.692 14.887 1.904 22.56 3.654 8.186 1.866 15.978 4.164 23.376 6.884 7.397 2.719 14.401 5.861 21.012 9.414 6.611 3.555 12.828 7.522 18.655 11.891 5.826 4.371 11.261 9.143 16.304 14.311 5.045 5.167 9.698 10.729 13.962 16.675 4.264 5.947 8.14 12.278 11.626 18.985 3.487 6.707 6.586 13.789 9.296 21.238 2.712 7.449 5.037 15.264 6.975 23.436 0.548 2.31 1.025 4.624 1.432 6.944 0.408 2.318 0.747 4.641 1.023 6.968 0.275 2.327 0.486 4.658 0.637 6.991 0.15 2.333 0.241 4.671 0.276 7.01 0.034 2.339 0.013 4.681-0.061 7.024-0.074 2.345-0.2 4.69-0.374 7.037-0.174 2.348-0.396 4.697-0.664 7.046-0.266 2.349-0.577 4.699-0.928 7.049-0.39 2.617-0.912 5.345-1.535 8.125-0.623 2.779-1.346 5.609-2.142 8.427-0.795 2.819-1.66 5.626-2.569 8.359-0.907 2.733-1.855 5.391-2.816 7.915-0.959 2.523-1.931 4.909-2.883 7.098-0.953 2.189-1.888 4.179-2.773 5.909-0.886 1.73-1.723 3.199-2.481 4.346-0.475 0.717-1.25 1.831-1.946 2.775 0.215-0.462 0.433-0.967 0.627-1.49" fill="url(#radialGradient4297)"/></g><g transform="matrix(1.3333 0 0 -1.3333 0 1024)" fill="url(#linearGradient7248-9)"><g clip-path="url(#clipPath4307-2)" fill="url(#linearGradient7248-9)"><g transform="translate(382.92 331.6)" fill="url(#linearGradient7248-9)"><path d="m0 0c6.615-7.221 13.678-14.033 21.222-20.267 7.539-6.237 15.577-11.868 24.046-16.747 8.468-4.879 17.397-8.961 26.656-12.07 9.256-3.117 18.837-5.252 28.533-6.374 9.697-1.126 19.503-1.24 29.23-0.453 9.731 0.785 19.379 2.465 28.846 4.853 18.922 4.75 37.215 12.333 53.364 23.285 8.065 5.472 15.569 11.768 22.33 18.787 6.768 7.012 12.789 14.739 18.015 22.967 10.462 16.478 17.733 34.859 22.474 53.789l0.439 1.778 0.209 0.872 0.186 0.899 0.747 3.597 0.373 1.798 0.093 0.45 0.024 0.112c-7e-3 -0.038 7e-3 0.055 0.01 0.076l0.034 0.227 0.134 0.908 0.539 3.634 0.269 1.817c0.077 0.534 0.118 1.199 0.18 1.791l0.338 3.658 0.164 1.796 0.075 1.835 0.15 3.671c0.264 9.752-0.472 19.521-1.882 29.184-1.502 9.646-4.173 19.05-7.353 28.281l-1.228 3.463-0.307 0.865-0.144 0.409-0.173 0.426-0.689 1.702-1.379 3.405-0.685 1.671-0.778 1.664-1.557 3.327-0.371 0.788-0.455 0.798-0.909 1.596-1.8039 3.187c-12.883 30.325-179.5-236.54-259.07-177.56zm-8e-3 8e-3c92.186-40.479 231.35 107.76 257.54 180.96 0.828-0.982 1.523-1.975 2.238-2.986 0.351-0.52 0.707-0.981 1.036-1.569l0.913-1.594 0.912-1.594 0.457-0.797c0.183-0.358 0.275-0.576 0.417-0.871l2.346-4.986c0.271-0.617 0.473-1.148 0.713-1.726l1.387-3.402 0.693-1.701 0.173-0.425 0.164-0.457 0.309-0.865 1.235-3.459c3.22-9.271 5.937-18.782 7.475-28.508 1.444-9.716 2.213-19.555 1.972-29.393l-0.14-3.671-0.069-1.836-0.164-1.863-0.329-3.659c-0.063-0.625-0.09-1.185-0.183-1.864l-0.264-1.818-0.528-3.635-0.132-0.909-0.033-0.227-0.024-0.152-0.023-0.112-0.092-0.45-0.369-1.8-0.736-3.599-0.185-0.9-0.216-0.915-0.436-1.79c-2.367-9.534-5.355-18.932-9.077-28.033-3.717-9.105-8.196-17.911-13.474-26.221-5.276-8.31-11.358-16.118-18.197-23.206-6.832-7.094-14.416-13.459-22.563-18.989-8.15-5.528-16.852-10.229-25.9-14.096-9.054-3.857-18.44-6.901-27.983-9.247-9.54-2.354-19.27-3.997-29.075-4.737-9.804-0.741-19.683-0.576-29.444 0.61-9.761 1.181-19.397 3.381-28.694 6.565-9.3 3.177-18.256 7.329-26.737 12.275-8.488 4.941-16.474 10.71-23.972 17.028-7.497 6.325-14.5 13.22-21.044 20.512z" fill="url(#linearGradient7248-9)"/></g></g></g><path d="m853.83 340.91z" fill="none" stroke="#000" stroke-width="1px"/><path d="m512.59 583.25c24.074 19.047 61.695 18.896 102.99 7.7902 41.299-11.105 86.278-33.164 124.63-62.438 43.462-33.178 74.436-61.06 97.049-98.852 10.211-17.065 16.881-32.679 20.405-47.4 3.5243-14.721 2.1355-27.046-3.4171-40.626 0 0 22.052 31.822 28.025 81.607 2.9864 24.893 1.4477 59.407-11.26 93.337-11.843 31.622-27.743 61.223-54.874 85.55-1.0301 0.92357-12.207 12.478-32.938 24.374-25.596 14.688-46.884 22.5-75.534 27.634-34.926 6.2583-59.469 4.4522-85.833-1.8111-36.815-8.7462-71.794-28.542-110.24-69.041" fill="url(#radialGradient7556)"/></g></g></svg>
diff --git a/dist/citra.xml b/dist/citra.xml
deleted file mode 100644
index 6d47c8760..000000000
--- a/dist/citra.xml
+++ /dev/null
@@ -1,59 +0,0 @@
1<?xml version="1.0" encoding="UTF-8"?>
2<mime-info xmlns="http://www.freedesktop.org/standards/shared-mime-info">
3 <mime-type type="application/x-ctr-3dsx">
4 <comment>Nintendo 3DS homebrew executable</comment>
5 <comment xml:lang="fr">Exécutable non-officiel pour Nintendo 3DS </comment>
6 <acronym>3DSX</acronym>
7 <icon name="citra"/>
8 <glob pattern="*.3dsx"/>
9 <magic><match value="3DSX" type="string" offset="0"/></magic>
10 </mime-type>
11
12 <mime-type type="application/x-ctr-cci">
13 <comment>Nintendo 3DS cartridge image</comment>
14 <comment xml:lang="fr">Image de cartouche Nintendo 3DS</comment>
15 <acronym>CCI</acronym>
16 <expanded-acronym>CTR Cart Image</expanded-acronym>
17 <icon name="citra"/>
18 <glob pattern="*.cci"/>
19 <glob pattern="*.3ds"/>
20 <magic><match value="NCSD" type="string" offset="256"/></magic>
21 </mime-type>
22
23 <mime-type type="application/x-ctr-cxi">
24 <comment>Nintendo 3DS executable</comment>
25 <comment xml:lang="fr">Exécutable Nintendo 3DS</comment>
26 <acronym>CXI</acronym>
27 <expanded-acronym>CTR eXecutable Image</expanded-acronym>
28 <icon name="citra"/>
29 <glob pattern="*.cxi"/>
30 <magic><match value="NCCH" type="string" offset="256"/></magic>
31 </mime-type>
32
33 <mime-type type="application/x-ctr-cia">
34 <comment>Nintendo 3DS importable archive</comment>
35 <comment xml:lang="fr">Archive installable Nintendo 3DS</comment>
36 <acronym>CIA</acronym>
37 <expanded-acronym>CTR Importable Archive</expanded-acronym>
38 <icon name="citra"/>
39 <glob pattern="*.cia"/>
40 </mime-type>
41
42 <mime-type type="application/x-ctr-smdh">
43 <comment>Nintendo 3DS icon and metadata</comment>
44 <comment xml:lang="fr">Icône et métadonnées Nintendo 3DS</comment>
45 <acronym>SMDH</acronym>
46 <expanded-acronym>System Menu Data Header</expanded-acronym>
47 <glob pattern="*.smdh"/>
48 <magic><match value="SMDH" type="string" offset="0"/></magic>
49 </mime-type>
50
51 <mime-type type="application/x-ctr-cbmd">
52 <comment>Nintendo 3DS banner</comment>
53 <comment xml:lang="fr">Bannière Nintendo 3DS</comment>
54 <acronym>CBMD</acronym>
55 <expanded-acronym>CTR Banner Model Data</expanded-acronym>
56 <glob pattern="*.cbmd"/>
57 <magic><match value="CBMD" type="string" offset="0"/></magic>
58 </mime-type>
59</mime-info>
diff --git a/dist/doc-icon.png b/dist/doc-icon.png
deleted file mode 100644
index 9b5773214..000000000
--- a/dist/doc-icon.png
+++ /dev/null
Binary files differ
diff --git a/dist/icons/checked.png b/dist/icons/checked.png
deleted file mode 100644
index c277e6b40..000000000
--- a/dist/icons/checked.png
+++ /dev/null
Binary files differ
diff --git a/dist/icons/failed.png b/dist/icons/failed.png
deleted file mode 100644
index ac10f174a..000000000
--- a/dist/icons/failed.png
+++ /dev/null
Binary files differ
diff --git a/dist/icons/icons.qrc b/dist/icons/icons.qrc
deleted file mode 100644
index f0c44862f..000000000
--- a/dist/icons/icons.qrc
+++ /dev/null
@@ -1,6 +0,0 @@
1<RCC>
2 <qresource prefix="icons">
3 <file>checked.png</file>
4 <file>failed.png</file>
5 </qresource>
6</RCC>
diff --git a/dist/qt_themes/qdarkstyle/rc/Hmovetoolbar.png b/dist/qt_themes/qdarkstyle/rc/Hmovetoolbar.png
deleted file mode 100644
index cead99ed1..000000000
--- a/dist/qt_themes/qdarkstyle/rc/Hmovetoolbar.png
+++ /dev/null
Binary files differ
diff --git a/dist/qt_themes/qdarkstyle/rc/Hsepartoolbar.png b/dist/qt_themes/qdarkstyle/rc/Hsepartoolbar.png
deleted file mode 100644
index 7f183c8b3..000000000
--- a/dist/qt_themes/qdarkstyle/rc/Hsepartoolbar.png
+++ /dev/null
Binary files differ
diff --git a/dist/qt_themes/qdarkstyle/rc/Vmovetoolbar.png b/dist/qt_themes/qdarkstyle/rc/Vmovetoolbar.png
deleted file mode 100644
index 512edcecd..000000000
--- a/dist/qt_themes/qdarkstyle/rc/Vmovetoolbar.png
+++ /dev/null
Binary files differ
diff --git a/dist/qt_themes/qdarkstyle/rc/Vsepartoolbar.png b/dist/qt_themes/qdarkstyle/rc/Vsepartoolbar.png
deleted file mode 100644
index d9dc1561b..000000000
--- a/dist/qt_themes/qdarkstyle/rc/Vsepartoolbar.png
+++ /dev/null
Binary files differ
diff --git a/dist/qt_themes/qdarkstyle/rc/branch_closed-on.png b/dist/qt_themes/qdarkstyle/rc/branch_closed-on.png
deleted file mode 100644
index d081e9b3b..000000000
--- a/dist/qt_themes/qdarkstyle/rc/branch_closed-on.png
+++ /dev/null
Binary files differ
diff --git a/dist/qt_themes/qdarkstyle/rc/branch_closed.png b/dist/qt_themes/qdarkstyle/rc/branch_closed.png
deleted file mode 100644
index d652159a3..000000000
--- a/dist/qt_themes/qdarkstyle/rc/branch_closed.png
+++ /dev/null
Binary files differ
diff --git a/dist/qt_themes/qdarkstyle/rc/branch_open-on.png b/dist/qt_themes/qdarkstyle/rc/branch_open-on.png
deleted file mode 100644
index ec372b27d..000000000
--- a/dist/qt_themes/qdarkstyle/rc/branch_open-on.png
+++ /dev/null
Binary files differ
diff --git a/dist/qt_themes/qdarkstyle/rc/branch_open.png b/dist/qt_themes/qdarkstyle/rc/branch_open.png
deleted file mode 100644
index 66f8e1ac6..000000000
--- a/dist/qt_themes/qdarkstyle/rc/branch_open.png
+++ /dev/null
Binary files differ
diff --git a/dist/qt_themes/qdarkstyle/rc/checkbox_checked.png b/dist/qt_themes/qdarkstyle/rc/checkbox_checked.png
deleted file mode 100644
index 830cfee65..000000000
--- a/dist/qt_themes/qdarkstyle/rc/checkbox_checked.png
+++ /dev/null
Binary files differ
diff --git a/dist/qt_themes/qdarkstyle/rc/checkbox_checked_disabled.png b/dist/qt_themes/qdarkstyle/rc/checkbox_checked_disabled.png
deleted file mode 100644
index cb63cc2fa..000000000
--- a/dist/qt_themes/qdarkstyle/rc/checkbox_checked_disabled.png
+++ /dev/null
Binary files differ
diff --git a/dist/qt_themes/qdarkstyle/rc/checkbox_checked_focus.png b/dist/qt_themes/qdarkstyle/rc/checkbox_checked_focus.png
deleted file mode 100644
index 671be273b..000000000
--- a/dist/qt_themes/qdarkstyle/rc/checkbox_checked_focus.png
+++ /dev/null
Binary files differ
diff --git a/dist/qt_themes/qdarkstyle/rc/checkbox_indeterminate.png b/dist/qt_themes/qdarkstyle/rc/checkbox_indeterminate.png
deleted file mode 100644
index 41024f768..000000000
--- a/dist/qt_themes/qdarkstyle/rc/checkbox_indeterminate.png
+++ /dev/null
Binary files differ
diff --git a/dist/qt_themes/qdarkstyle/rc/checkbox_indeterminate_disabled.png b/dist/qt_themes/qdarkstyle/rc/checkbox_indeterminate_disabled.png
deleted file mode 100644
index abdc01d90..000000000
--- a/dist/qt_themes/qdarkstyle/rc/checkbox_indeterminate_disabled.png
+++ /dev/null
Binary files differ
diff --git a/dist/qt_themes/qdarkstyle/rc/checkbox_indeterminate_focus.png b/dist/qt_themes/qdarkstyle/rc/checkbox_indeterminate_focus.png
deleted file mode 100644
index 415f9b6e1..000000000
--- a/dist/qt_themes/qdarkstyle/rc/checkbox_indeterminate_focus.png
+++ /dev/null
Binary files differ
diff --git a/dist/qt_themes/qdarkstyle/rc/checkbox_unchecked.png b/dist/qt_themes/qdarkstyle/rc/checkbox_unchecked.png
deleted file mode 100644
index 2159aca9a..000000000
--- a/dist/qt_themes/qdarkstyle/rc/checkbox_unchecked.png
+++ /dev/null
Binary files differ
diff --git a/dist/qt_themes/qdarkstyle/rc/checkbox_unchecked_disabled.png b/dist/qt_themes/qdarkstyle/rc/checkbox_unchecked_disabled.png
deleted file mode 100644
index ade721e81..000000000
--- a/dist/qt_themes/qdarkstyle/rc/checkbox_unchecked_disabled.png
+++ /dev/null
Binary files differ
diff --git a/dist/qt_themes/qdarkstyle/rc/checkbox_unchecked_focus.png b/dist/qt_themes/qdarkstyle/rc/checkbox_unchecked_focus.png
deleted file mode 100644
index e4258cc47..000000000
--- a/dist/qt_themes/qdarkstyle/rc/checkbox_unchecked_focus.png
+++ /dev/null
Binary files differ
diff --git a/dist/qt_themes/qdarkstyle/rc/close-hover.png b/dist/qt_themes/qdarkstyle/rc/close-hover.png
deleted file mode 100644
index 657943a66..000000000
--- a/dist/qt_themes/qdarkstyle/rc/close-hover.png
+++ /dev/null
Binary files differ
diff --git a/dist/qt_themes/qdarkstyle/rc/close-pressed.png b/dist/qt_themes/qdarkstyle/rc/close-pressed.png
deleted file mode 100644
index 937d00598..000000000
--- a/dist/qt_themes/qdarkstyle/rc/close-pressed.png
+++ /dev/null
Binary files differ
diff --git a/dist/qt_themes/qdarkstyle/rc/close.png b/dist/qt_themes/qdarkstyle/rc/close.png
deleted file mode 100644
index bc0f57610..000000000
--- a/dist/qt_themes/qdarkstyle/rc/close.png
+++ /dev/null
Binary files differ
diff --git a/dist/qt_themes/qdarkstyle/rc/down_arrow.png b/dist/qt_themes/qdarkstyle/rc/down_arrow.png
deleted file mode 100644
index e271f7f90..000000000
--- a/dist/qt_themes/qdarkstyle/rc/down_arrow.png
+++ /dev/null
Binary files differ
diff --git a/dist/qt_themes/qdarkstyle/rc/down_arrow_disabled.png b/dist/qt_themes/qdarkstyle/rc/down_arrow_disabled.png
deleted file mode 100644
index 5805d9842..000000000
--- a/dist/qt_themes/qdarkstyle/rc/down_arrow_disabled.png
+++ /dev/null
Binary files differ
diff --git a/dist/qt_themes/qdarkstyle/rc/left_arrow.png b/dist/qt_themes/qdarkstyle/rc/left_arrow.png
deleted file mode 100644
index f808d2d72..000000000
--- a/dist/qt_themes/qdarkstyle/rc/left_arrow.png
+++ /dev/null
Binary files differ
diff --git a/dist/qt_themes/qdarkstyle/rc/left_arrow_disabled.png b/dist/qt_themes/qdarkstyle/rc/left_arrow_disabled.png
deleted file mode 100644
index f5b9af8a3..000000000
--- a/dist/qt_themes/qdarkstyle/rc/left_arrow_disabled.png
+++ /dev/null
Binary files differ
diff --git a/dist/qt_themes/qdarkstyle/rc/radio_checked.png b/dist/qt_themes/qdarkstyle/rc/radio_checked.png
deleted file mode 100644
index 235e6b0ba..000000000
--- a/dist/qt_themes/qdarkstyle/rc/radio_checked.png
+++ /dev/null
Binary files differ
diff --git a/dist/qt_themes/qdarkstyle/rc/radio_checked_disabled.png b/dist/qt_themes/qdarkstyle/rc/radio_checked_disabled.png
deleted file mode 100644
index bf0051ede..000000000
--- a/dist/qt_themes/qdarkstyle/rc/radio_checked_disabled.png
+++ /dev/null
Binary files differ
diff --git a/dist/qt_themes/qdarkstyle/rc/radio_checked_focus.png b/dist/qt_themes/qdarkstyle/rc/radio_checked_focus.png
deleted file mode 100644
index 700c6b525..000000000
--- a/dist/qt_themes/qdarkstyle/rc/radio_checked_focus.png
+++ /dev/null
Binary files differ
diff --git a/dist/qt_themes/qdarkstyle/rc/radio_unchecked.png b/dist/qt_themes/qdarkstyle/rc/radio_unchecked.png
deleted file mode 100644
index 9a4def65c..000000000
--- a/dist/qt_themes/qdarkstyle/rc/radio_unchecked.png
+++ /dev/null
Binary files differ
diff --git a/dist/qt_themes/qdarkstyle/rc/radio_unchecked_disabled.png b/dist/qt_themes/qdarkstyle/rc/radio_unchecked_disabled.png
deleted file mode 100644
index 6ece890e7..000000000
--- a/dist/qt_themes/qdarkstyle/rc/radio_unchecked_disabled.png
+++ /dev/null
Binary files differ
diff --git a/dist/qt_themes/qdarkstyle/rc/radio_unchecked_focus.png b/dist/qt_themes/qdarkstyle/rc/radio_unchecked_focus.png
deleted file mode 100644
index 564e022d3..000000000
--- a/dist/qt_themes/qdarkstyle/rc/radio_unchecked_focus.png
+++ /dev/null
Binary files differ
diff --git a/dist/qt_themes/qdarkstyle/rc/right_arrow.png b/dist/qt_themes/qdarkstyle/rc/right_arrow.png
deleted file mode 100644
index 9b0a4e6a7..000000000
--- a/dist/qt_themes/qdarkstyle/rc/right_arrow.png
+++ /dev/null
Binary files differ
diff --git a/dist/qt_themes/qdarkstyle/rc/right_arrow_disabled.png b/dist/qt_themes/qdarkstyle/rc/right_arrow_disabled.png
deleted file mode 100644
index 5c0bee402..000000000
--- a/dist/qt_themes/qdarkstyle/rc/right_arrow_disabled.png
+++ /dev/null
Binary files differ
diff --git a/dist/qt_themes/qdarkstyle/rc/sizegrip.png b/dist/qt_themes/qdarkstyle/rc/sizegrip.png
deleted file mode 100644
index 350583aaa..000000000
--- a/dist/qt_themes/qdarkstyle/rc/sizegrip.png
+++ /dev/null
Binary files differ
diff --git a/dist/qt_themes/qdarkstyle/rc/stylesheet-branch-end.png b/dist/qt_themes/qdarkstyle/rc/stylesheet-branch-end.png
deleted file mode 100644
index cb5d3b51f..000000000
--- a/dist/qt_themes/qdarkstyle/rc/stylesheet-branch-end.png
+++ /dev/null
Binary files differ
diff --git a/dist/qt_themes/qdarkstyle/rc/stylesheet-branch-more.png b/dist/qt_themes/qdarkstyle/rc/stylesheet-branch-more.png
deleted file mode 100644
index 62711409d..000000000
--- a/dist/qt_themes/qdarkstyle/rc/stylesheet-branch-more.png
+++ /dev/null
Binary files differ
diff --git a/dist/qt_themes/qdarkstyle/rc/stylesheet-vline.png b/dist/qt_themes/qdarkstyle/rc/stylesheet-vline.png
deleted file mode 100644
index 87536cce1..000000000
--- a/dist/qt_themes/qdarkstyle/rc/stylesheet-vline.png
+++ /dev/null
Binary files differ
diff --git a/dist/qt_themes/qdarkstyle/rc/transparent.png b/dist/qt_themes/qdarkstyle/rc/transparent.png
deleted file mode 100644
index 483df2513..000000000
--- a/dist/qt_themes/qdarkstyle/rc/transparent.png
+++ /dev/null
Binary files differ
diff --git a/dist/qt_themes/qdarkstyle/rc/undock.png b/dist/qt_themes/qdarkstyle/rc/undock.png
deleted file mode 100644
index 88691d779..000000000
--- a/dist/qt_themes/qdarkstyle/rc/undock.png
+++ /dev/null
Binary files differ
diff --git a/dist/qt_themes/qdarkstyle/rc/up_arrow.png b/dist/qt_themes/qdarkstyle/rc/up_arrow.png
deleted file mode 100644
index abcc72452..000000000
--- a/dist/qt_themes/qdarkstyle/rc/up_arrow.png
+++ /dev/null
Binary files differ
diff --git a/dist/qt_themes/qdarkstyle/rc/up_arrow_disabled.png b/dist/qt_themes/qdarkstyle/rc/up_arrow_disabled.png
deleted file mode 100644
index b9c8e3b53..000000000
--- a/dist/qt_themes/qdarkstyle/rc/up_arrow_disabled.png
+++ /dev/null
Binary files differ
diff --git a/dist/qt_themes/qdarkstyle/style.qrc b/dist/qt_themes/qdarkstyle/style.qrc
deleted file mode 100644
index ac14bc501..000000000
--- a/dist/qt_themes/qdarkstyle/style.qrc
+++ /dev/null
@@ -1,46 +0,0 @@
1<RCC>
2 <qresource prefix="qss_icons">
3 <file>rc/up_arrow_disabled.png</file>
4 <file>rc/Hmovetoolbar.png</file>
5 <file>rc/stylesheet-branch-end.png</file>
6 <file>rc/branch_closed-on.png</file>
7 <file>rc/stylesheet-vline.png</file>
8 <file>rc/branch_closed.png</file>
9 <file>rc/branch_open-on.png</file>
10 <file>rc/transparent.png</file>
11 <file>rc/right_arrow_disabled.png</file>
12 <file>rc/sizegrip.png</file>
13 <file>rc/close.png</file>
14 <file>rc/close-hover.png</file>
15 <file>rc/close-pressed.png</file>
16 <file>rc/down_arrow.png</file>
17 <file>rc/Vmovetoolbar.png</file>
18 <file>rc/left_arrow.png</file>
19 <file>rc/stylesheet-branch-more.png</file>
20 <file>rc/up_arrow.png</file>
21 <file>rc/right_arrow.png</file>
22 <file>rc/left_arrow_disabled.png</file>
23 <file>rc/Hsepartoolbar.png</file>
24 <file>rc/branch_open.png</file>
25 <file>rc/Vsepartoolbar.png</file>
26 <file>rc/down_arrow_disabled.png</file>
27 <file>rc/undock.png</file>
28 <file>rc/checkbox_checked_disabled.png</file>
29 <file>rc/checkbox_checked_focus.png</file>
30 <file>rc/checkbox_checked.png</file>
31 <file>rc/checkbox_indeterminate.png</file>
32 <file>rc/checkbox_indeterminate_focus.png</file>
33 <file>rc/checkbox_unchecked_disabled.png</file>
34 <file>rc/checkbox_unchecked_focus.png</file>
35 <file>rc/checkbox_unchecked.png</file>
36 <file>rc/radio_checked_disabled.png</file>
37 <file>rc/radio_checked_focus.png</file>
38 <file>rc/radio_checked.png</file>
39 <file>rc/radio_unchecked_disabled.png</file>
40 <file>rc/radio_unchecked_focus.png</file>
41 <file>rc/radio_unchecked.png</file>
42 </qresource>
43 <qresource prefix="qdarkstyle">
44 <file>style.qss</file>
45 </qresource>
46</RCC>
diff --git a/dist/qt_themes/qdarkstyle/style.qss b/dist/qt_themes/qdarkstyle/style.qss
deleted file mode 100644
index c8e50312a..000000000
--- a/dist/qt_themes/qdarkstyle/style.qss
+++ /dev/null
@@ -1,1268 +0,0 @@
1/*
2 * The MIT License (MIT)
3 *
4 * Copyright (c) <2013-2014> <Colin Duquesnoy>
5 *
6 * Permission is hereby granted, free of charge, to any person obtaining a copy
7 * of this software and associated documentation files (the "Software"), to deal
8 * in the Software without restriction, including without limitation the rights
9 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 * copies of the Software, and to permit persons to whom the Software is
11 * furnished to do so, subject to the following conditions:
12
13 * The above copyright notice and this permission notice shall be included in
14 * all copies or substantial portions of the Software.
15
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22 * THE SOFTWARE.
23 */
24QToolTip
25{
26 border: 1px solid #76797C;
27 background-color: rgb(90, 102, 117);;
28 color: white;
29 padding: 5px;
30 opacity: 200;
31}
32
33QWidget
34{
35 color: #eff0f1;
36 background-color: #31363b;
37 selection-background-color:#3daee9;
38 selection-color: #eff0f1;
39 background-clip: border;
40 border-image: none;
41 border: 0px transparent black;
42 outline: 0;
43}
44
45QWidget:item:hover
46{
47 background-color: #18465d;
48 color: #eff0f1;
49}
50
51QWidget:item:selected
52{
53 background-color: #18465d;
54}
55
56QCheckBox
57{
58 spacing: 5px;
59 outline: none;
60 color: #eff0f1;
61 margin-bottom: 2px;
62}
63
64QCheckBox:disabled
65{
66 color: #76797C;
67}
68
69QCheckBox::indicator,
70QGroupBox::indicator
71{
72 width: 18px;
73 height: 18px;
74}
75QGroupBox::indicator
76{
77 margin-left: 2px;
78}
79
80QCheckBox::indicator:unchecked
81{
82 image: url(:/qss_icons/rc/checkbox_unchecked.png);
83}
84
85QCheckBox::indicator:unchecked:hover,
86QCheckBox::indicator:unchecked:focus,
87QCheckBox::indicator:unchecked:pressed,
88QGroupBox::indicator:unchecked:hover,
89QGroupBox::indicator:unchecked:focus,
90QGroupBox::indicator:unchecked:pressed
91{
92 border: none;
93 image: url(:/qss_icons/rc/checkbox_unchecked_focus.png);
94}
95
96QCheckBox::indicator:checked
97{
98 image: url(:/qss_icons/rc/checkbox_checked.png);
99}
100
101QCheckBox::indicator:checked:hover,
102QCheckBox::indicator:checked:focus,
103QCheckBox::indicator:checked:pressed,
104QGroupBox::indicator:checked:hover,
105QGroupBox::indicator:checked:focus,
106QGroupBox::indicator:checked:pressed
107{
108 border: none;
109 image: url(:/qss_icons/rc/checkbox_checked_focus.png);
110}
111
112
113QCheckBox::indicator:indeterminate
114{
115 image: url(:/qss_icons/rc/checkbox_indeterminate.png);
116}
117
118QCheckBox::indicator:indeterminate:focus,
119QCheckBox::indicator:indeterminate:hover,
120QCheckBox::indicator:indeterminate:pressed
121{
122 image: url(:/qss_icons/rc/checkbox_indeterminate_focus.png);
123}
124
125QCheckBox::indicator:checked:disabled,
126QGroupBox::indicator:checked:disabled
127{
128 image: url(:/qss_icons/rc/checkbox_checked_disabled.png);
129}
130
131QCheckBox::indicator:unchecked:disabled,
132QGroupBox::indicator:unchecked:disabled
133{
134 image: url(:/qss_icons/rc/checkbox_unchecked_disabled.png);
135}
136
137QRadioButton
138{
139 spacing: 5px;
140 outline: none;
141 color: #eff0f1;
142 margin-bottom: 2px;
143}
144
145QRadioButton:disabled
146{
147 color: #76797C;
148}
149QRadioButton::indicator
150{
151 width: 21px;
152 height: 21px;
153}
154
155QRadioButton::indicator:unchecked
156{
157 image: url(:/qss_icons/rc/radio_unchecked.png);
158}
159
160
161QRadioButton::indicator:unchecked:hover,
162QRadioButton::indicator:unchecked:focus,
163QRadioButton::indicator:unchecked:pressed
164{
165 border: none;
166 outline: none;
167 image: url(:/qss_icons/rc/radio_unchecked_focus.png);
168}
169
170QRadioButton::indicator:checked
171{
172 border: none;
173 outline: none;
174 image: url(:/qss_icons/rc/radio_checked.png);
175}
176
177QRadioButton::indicator:checked:hover,
178QRadioButton::indicator:checked:focus,
179QRadioButton::indicator:checked:pressed
180{
181 border: none;
182 outline: none;
183 image: url(:/qss_icons/rc/radio_checked_focus.png);
184}
185
186QRadioButton::indicator:checked:disabled
187{
188 outline: none;
189 image: url(:/qss_icons/rc/radio_checked_disabled.png);
190}
191
192QRadioButton::indicator:unchecked:disabled
193{
194 image: url(:/qss_icons/rc/radio_unchecked_disabled.png);
195}
196
197
198QMenuBar
199{
200 background-color: #31363b;
201 color: #eff0f1;
202}
203
204QMenuBar::item
205{
206 background: transparent;
207}
208
209QMenuBar::item:selected
210{
211 background: transparent;
212 border: 1px solid #76797C;
213}
214
215QMenuBar::item:pressed
216{
217 border: 1px solid #76797C;
218 background-color: #3daee9;
219 color: #eff0f1;
220 margin-bottom:-1px;
221 padding-bottom:1px;
222}
223
224QMenu
225{
226 border: 1px solid #76797C;
227 color: #eff0f1;
228 margin: 2px;
229}
230
231QMenu::icon
232{
233 margin: 5px;
234}
235
236QMenu::item
237{
238 padding: 5px 30px 5px 30px;
239 margin-left: 5px;
240 border: 1px solid transparent; /* reserve space for selection border */
241}
242
243QMenu::item:selected
244{
245 color: #eff0f1;
246}
247
248QMenu::separator {
249 height: 2px;
250 background: lightblue;
251 margin-left: 10px;
252 margin-right: 5px;
253}
254
255QMenu::indicator {
256 width: 18px;
257 height: 18px;
258}
259
260/* non-exclusive indicator = check box style indicator
261 (see QActionGroup::setExclusive) */
262QMenu::indicator:non-exclusive:unchecked {
263 image: url(:/qss_icons/rc/checkbox_unchecked.png);
264}
265
266QMenu::indicator:non-exclusive:unchecked:selected {
267 image: url(:/qss_icons/rc/checkbox_unchecked_disabled.png);
268}
269
270QMenu::indicator:non-exclusive:checked {
271 image: url(:/qss_icons/rc/checkbox_checked.png);
272}
273
274QMenu::indicator:non-exclusive:checked:selected {
275 image: url(:/qss_icons/rc/checkbox_checked_disabled.png);
276}
277
278/* exclusive indicator = radio button style indicator (see QActionGroup::setExclusive) */
279QMenu::indicator:exclusive:unchecked {
280 image: url(:/qss_icons/rc/radio_unchecked.png);
281}
282
283QMenu::indicator:exclusive:unchecked:selected {
284 image: url(:/qss_icons/rc/radio_unchecked_disabled.png);
285}
286
287QMenu::indicator:exclusive:checked {
288 image: url(:/qss_icons/rc/radio_checked.png);
289}
290
291QMenu::indicator:exclusive:checked:selected {
292 image: url(:/qss_icons/rc/radio_checked_disabled.png);
293}
294
295QMenu::right-arrow {
296 margin: 5px;
297 image: url(:/qss_icons/rc/right_arrow.png)
298}
299
300
301QWidget:disabled
302{
303 color: #454545;
304 background-color: #31363b;
305}
306
307QAbstractItemView
308{
309 alternate-background-color: #31363b;
310 color: #eff0f1;
311 border: 1px solid 3A3939;
312 border-radius: 2px;
313}
314
315QWidget:focus, QMenuBar:focus
316{
317 border: 1px solid #3daee9;
318}
319
320QTabWidget:focus, QCheckBox:focus, QRadioButton:focus, QSlider:focus
321{
322 border: none;
323}
324
325QLineEdit
326{
327 background-color: #232629;
328 padding: 5px;
329 border-style: solid;
330 border: 1px solid #76797C;
331 border-radius: 2px;
332 color: #eff0f1;
333}
334
335QAbstractItemView QLineEdit
336{
337 padding: 0;
338}
339
340QGroupBox {
341 border:1px solid #76797C;
342 border-radius: 2px;
343 margin-top: 20px;
344}
345
346QGroupBox::title {
347 subcontrol-origin: margin;
348 subcontrol-position: top center;
349 padding-left: 10px;
350 padding-right: 10px;
351 padding-top: 10px;
352}
353
354QAbstractScrollArea
355{
356 border-radius: 2px;
357 border: 1px solid #76797C;
358 background-color: transparent;
359}
360
361QScrollBar:horizontal
362{
363 height: 15px;
364 margin: 3px 15px 3px 15px;
365 border: 1px transparent #2A2929;
366 border-radius: 4px;
367 background-color: #2A2929;
368}
369
370QScrollBar::handle:horizontal
371{
372 background-color: #605F5F;
373 min-width: 5px;
374 border-radius: 4px;
375}
376
377QScrollBar::add-line:horizontal
378{
379 margin: 0px 3px 0px 3px;
380 border-image: url(:/qss_icons/rc/right_arrow_disabled.png);
381 width: 10px;
382 height: 10px;
383 subcontrol-position: right;
384 subcontrol-origin: margin;
385}
386
387QScrollBar::sub-line:horizontal
388{
389 margin: 0px 3px 0px 3px;
390 border-image: url(:/qss_icons/rc/left_arrow_disabled.png);
391 height: 10px;
392 width: 10px;
393 subcontrol-position: left;
394 subcontrol-origin: margin;
395}
396
397QScrollBar::add-line:horizontal:hover,QScrollBar::add-line:horizontal:on
398{
399 border-image: url(:/qss_icons/rc/right_arrow.png);
400 height: 10px;
401 width: 10px;
402 subcontrol-position: right;
403 subcontrol-origin: margin;
404}
405
406
407QScrollBar::sub-line:horizontal:hover, QScrollBar::sub-line:horizontal:on
408{
409 border-image: url(:/qss_icons/rc/left_arrow.png);
410 height: 10px;
411 width: 10px;
412 subcontrol-position: left;
413 subcontrol-origin: margin;
414}
415
416QScrollBar::up-arrow:horizontal, QScrollBar::down-arrow:horizontal
417{
418 background: none;
419}
420
421
422QScrollBar::add-page:horizontal, QScrollBar::sub-page:horizontal
423{
424 background: none;
425}
426
427QScrollBar:vertical
428{
429 background-color: #2A2929;
430 width: 15px;
431 margin: 15px 3px 15px 3px;
432 border: 1px transparent #2A2929;
433 border-radius: 4px;
434}
435
436QScrollBar::handle:vertical
437{
438 background-color: #605F5F;
439 min-height: 5px;
440 border-radius: 4px;
441}
442
443QScrollBar::sub-line:vertical
444{
445 margin: 3px 0px 3px 0px;
446 border-image: url(:/qss_icons/rc/up_arrow_disabled.png);
447 height: 10px;
448 width: 10px;
449 subcontrol-position: top;
450 subcontrol-origin: margin;
451}
452
453QScrollBar::add-line:vertical
454{
455 margin: 3px 0px 3px 0px;
456 border-image: url(:/qss_icons/rc/down_arrow_disabled.png);
457 height: 10px;
458 width: 10px;
459 subcontrol-position: bottom;
460 subcontrol-origin: margin;
461}
462
463QScrollBar::sub-line:vertical:hover,QScrollBar::sub-line:vertical:on
464{
465
466 border-image: url(:/qss_icons/rc/up_arrow.png);
467 height: 10px;
468 width: 10px;
469 subcontrol-position: top;
470 subcontrol-origin: margin;
471}
472
473
474QScrollBar::add-line:vertical:hover, QScrollBar::add-line:vertical:on
475{
476 border-image: url(:/qss_icons/rc/down_arrow.png);
477 height: 10px;
478 width: 10px;
479 subcontrol-position: bottom;
480 subcontrol-origin: margin;
481}
482
483QScrollBar::up-arrow:vertical, QScrollBar::down-arrow:vertical
484{
485 background: none;
486}
487
488
489QScrollBar::add-page:vertical, QScrollBar::sub-page:vertical
490{
491 background: none;
492}
493
494QTextEdit
495{
496 background-color: #232629;
497 color: #eff0f1;
498 border: 1px solid #76797C;
499}
500
501QPlainTextEdit
502{
503 background-color: #232629;;
504 color: #eff0f1;
505 border-radius: 2px;
506 border: 1px solid #76797C;
507}
508
509QHeaderView::section
510{
511 background-color: #76797C;
512 color: #eff0f1;
513 padding: 5px;
514 border: 1px solid #76797C;
515}
516
517QSizeGrip {
518 image: url(:/qss_icons/rc/sizegrip.png);
519 width: 12px;
520 height: 12px;
521}
522
523
524QMainWindow::separator
525{
526 background-color: #31363b;
527 color: white;
528 padding-left: 4px;
529 spacing: 2px;
530 border: 1px dashed #76797C;
531}
532
533QMainWindow::separator:hover
534{
535
536 background-color: #787876;
537 color: white;
538 padding-left: 4px;
539 border: 1px solid #76797C;
540 spacing: 2px;
541}
542
543
544QMenu::separator
545{
546 height: 1px;
547 background-color: #76797C;
548 color: white;
549 padding-left: 4px;
550 margin-left: 10px;
551 margin-right: 5px;
552}
553
554
555QFrame
556{
557 border-radius: 2px;
558 border: 1px solid #76797C;
559}
560
561QFrame[frameShape="0"]
562{
563 border-radius: 2px;
564 border: 1px transparent #76797C;
565}
566
567QStackedWidget
568{
569 border: 1px transparent black;
570}
571
572QToolBar {
573 border: 1px transparent #393838;
574 background: 1px solid #31363b;
575 font-weight: bold;
576}
577
578QToolBar::handle:horizontal {
579 image: url(:/qss_icons/rc/Hmovetoolbar.png);
580}
581QToolBar::handle:vertical {
582 image: url(:/qss_icons/rc/Vmovetoolbar.png);
583}
584QToolBar::separator:horizontal {
585 image: url(:/qss_icons/rc/Hsepartoolbar.png);
586}
587QToolBar::separator:vertical {
588 image: url(:/qss_icons/rc/Vsepartoolbar.png);
589}
590QToolButton#qt_toolbar_ext_button {
591 background: #58595a
592}
593
594QPushButton
595{
596 color: #eff0f1;
597 background-color: #31363b;
598 border-width: 1px;
599 border-color: #76797C;
600 border-style: solid;
601 padding: 5px;
602 border-radius: 2px;
603 outline: none;
604}
605
606QPushButton:disabled
607{
608 background-color: #31363b;
609 border-width: 1px;
610 border-color: #454545;
611 border-style: solid;
612 padding-top: 5px;
613 padding-bottom: 5px;
614 padding-left: 10px;
615 padding-right: 10px;
616 border-radius: 2px;
617 color: #454545;
618}
619
620QPushButton:focus {
621 background-color: #3daee9;
622 color: white;
623}
624
625QPushButton:pressed
626{
627 background-color: #3daee9;
628 padding-top: -15px;
629 padding-bottom: -17px;
630}
631
632QComboBox
633{
634 selection-background-color: #3daee9;
635 border-style: solid;
636 border: 1px solid #76797C;
637 border-radius: 2px;
638 padding: 5px;
639 min-width: 75px;
640}
641
642QPushButton:checked{
643 background-color: #76797C;
644 border-color: #6A6969;
645}
646
647QComboBox:hover,QPushButton:hover,QAbstractSpinBox:hover,QLineEdit:hover,QTextEdit:hover,QPlainTextEdit:hover,QAbstractView:hover,QTreeView:hover
648{
649 border: 1px solid #3daee9;
650 color: #eff0f1;
651}
652
653QComboBox:on
654{
655 padding-top: 3px;
656 padding-left: 4px;
657 selection-background-color: #4a4a4a;
658}
659
660QComboBox QAbstractItemView
661{
662 background-color: #232629;
663 border-radius: 2px;
664 border: 1px solid #76797C;
665 selection-background-color: #18465d;
666}
667
668QComboBox::drop-down
669{
670 subcontrol-origin: padding;
671 subcontrol-position: top right;
672 width: 15px;
673
674 border-left-width: 0px;
675 border-left-color: darkgray;
676 border-left-style: solid;
677 border-top-right-radius: 3px;
678 border-bottom-right-radius: 3px;
679}
680
681QComboBox::down-arrow
682{
683 image: url(:/qss_icons/rc/down_arrow_disabled.png);
684}
685
686QComboBox::down-arrow:on, QComboBox::down-arrow:hover,
687QComboBox::down-arrow:focus
688{
689 image: url(:/qss_icons/rc/down_arrow.png);
690}
691
692QAbstractSpinBox {
693 padding: 5px;
694 border: 1px solid #76797C;
695 background-color: #232629;
696 color: #eff0f1;
697 border-radius: 2px;
698 min-width: 75px;
699}
700
701QAbstractSpinBox:up-button
702{
703 background-color: transparent;
704 subcontrol-origin: border;
705 subcontrol-position: center right;
706}
707
708QAbstractSpinBox:down-button
709{
710 background-color: transparent;
711 subcontrol-origin: border;
712 subcontrol-position: center left;
713}
714
715QAbstractSpinBox::up-arrow,QAbstractSpinBox::up-arrow:disabled,QAbstractSpinBox::up-arrow:off {
716 image: url(:/qss_icons/rc/up_arrow_disabled.png);
717 width: 10px;
718 height: 10px;
719}
720QAbstractSpinBox::up-arrow:hover
721{
722 image: url(:/qss_icons/rc/up_arrow.png);
723}
724
725
726QAbstractSpinBox::down-arrow,QAbstractSpinBox::down-arrow:disabled,QAbstractSpinBox::down-arrow:off
727{
728 image: url(:/qss_icons/rc/down_arrow_disabled.png);
729 width: 10px;
730 height: 10px;
731}
732QAbstractSpinBox::down-arrow:hover
733{
734 image: url(:/qss_icons/rc/down_arrow.png);
735}
736
737
738QLabel
739{
740 border: 0px solid black;
741}
742
743QTabWidget{
744 border: 0px transparent black;
745}
746
747QTabWidget::pane {
748 border: 1px solid #76797C;
749 padding: 5px;
750 margin: 0px;
751}
752
753QTabWidget::tab-bar {
754 left: 5px; /* move to the right by 5px */
755}
756
757QTabBar
758{
759 qproperty-drawBase: 0;
760 border-radius: 3px;
761}
762
763QTabBar:focus
764{
765 border: 0px transparent black;
766}
767
768QTabBar::close-button {
769 image: url(:/qss_icons/rc/close.png);
770 background: transparent;
771}
772
773QTabBar::close-button:hover
774{
775 image: url(:/qss_icons/rc/close-hover.png);
776 background: transparent;
777}
778
779QTabBar::close-button:pressed {
780 image: url(:/qss_icons/rc/close-pressed.png);
781 background: transparent;
782}
783
784/* TOP TABS */
785QTabBar::tab:top {
786 color: #eff0f1;
787 border: 1px solid #76797C;
788 border-bottom: 1px transparent black;
789 background-color: #31363b;
790 padding: 5px;
791 min-width: 50px;
792 border-top-left-radius: 2px;
793 border-top-right-radius: 2px;
794}
795
796QTabBar::tab:top:!selected
797{
798 color: #eff0f1;
799 background-color: #54575B;
800 border: 1px solid #76797C;
801 border-bottom: 1px transparent black;
802 border-top-left-radius: 2px;
803 border-top-right-radius: 2px;
804}
805
806QTabBar::tab:top:!selected:hover {
807 background-color: #3daee9;
808}
809
810/* BOTTOM TABS */
811QTabBar::tab:bottom {
812 color: #eff0f1;
813 border: 1px solid #76797C;
814 border-top: 1px transparent black;
815 background-color: #31363b;
816 padding: 5px;
817 border-bottom-left-radius: 2px;
818 border-bottom-right-radius: 2px;
819 min-width: 50px;
820}
821
822QTabBar::tab:bottom:!selected
823{
824 color: #eff0f1;
825 background-color: #54575B;
826 border: 1px solid #76797C;
827 border-top: 1px transparent black;
828 border-bottom-left-radius: 2px;
829 border-bottom-right-radius: 2px;
830}
831
832QTabBar::tab:bottom:!selected:hover {
833 background-color: #3daee9;
834}
835
836/* LEFT TABS */
837QTabBar::tab:left {
838 color: #eff0f1;
839 border: 1px solid #76797C;
840 border-left: 1px transparent black;
841 background-color: #31363b;
842 padding: 5px;
843 border-top-right-radius: 2px;
844 border-bottom-right-radius: 2px;
845 min-height: 50px;
846}
847
848QTabBar::tab:left:!selected
849{
850 color: #eff0f1;
851 background-color: #54575B;
852 border: 1px solid #76797C;
853 border-left: 1px transparent black;
854 border-top-right-radius: 2px;
855 border-bottom-right-radius: 2px;
856}
857
858QTabBar::tab:left:!selected:hover {
859 background-color: #3daee9;
860}
861
862
863/* RIGHT TABS */
864QTabBar::tab:right {
865 color: #eff0f1;
866 border: 1px solid #76797C;
867 border-right: 1px transparent black;
868 background-color: #31363b;
869 padding: 5px;
870 border-top-left-radius: 2px;
871 border-bottom-left-radius: 2px;
872 min-height: 50px;
873}
874
875QTabBar::tab:right:!selected
876{
877 color: #eff0f1;
878 background-color: #54575B;
879 border: 1px solid #76797C;
880 border-right: 1px transparent black;
881 border-top-left-radius: 2px;
882 border-bottom-left-radius: 2px;
883}
884
885QTabBar::tab:right:!selected:hover {
886 background-color: #3daee9;
887}
888
889QTabBar QToolButton::right-arrow:enabled {
890 image: url(:/qss_icons/rc/right_arrow.png);
891 }
892
893 QTabBar QToolButton::left-arrow:enabled {
894 image: url(:/qss_icons/rc/left_arrow.png);
895 }
896
897QTabBar QToolButton::right-arrow:disabled {
898 image: url(:/qss_icons/rc/right_arrow_disabled.png);
899 }
900
901 QTabBar QToolButton::left-arrow:disabled {
902 image: url(:/qss_icons/rc/left_arrow_disabled.png);
903 }
904
905
906QDockWidget {
907 background: #31363b;
908 border: 1px solid #403F3F;
909 titlebar-close-icon: url(:/qss_icons/rc/close.png);
910 titlebar-normal-icon: url(:/qss_icons/rc/undock.png);
911}
912
913QDockWidget::close-button, QDockWidget::float-button {
914 border: 1px solid transparent;
915 border-radius: 2px;
916 background: transparent;
917}
918
919QDockWidget::close-button:hover, QDockWidget::float-button:hover {
920 background: rgba(255, 255, 255, 10);
921}
922
923QDockWidget::close-button:pressed, QDockWidget::float-button:pressed {
924 padding: 1px -1px -1px 1px;
925 background: rgba(255, 255, 255, 10);
926}
927
928QTreeView, QListView
929{
930 border: 1px solid #76797C;
931 background-color: #232629;
932}
933
934QTreeView:branch:selected, QTreeView:branch:hover
935{
936 background: url(:/qss_icons/rc/transparent.png);
937}
938
939QTreeView::branch:has-siblings:!adjoins-item {
940 border-image: url(:/qss_icons/rc/transparent.png);
941}
942
943QTreeView::branch:has-siblings:adjoins-item {
944 border-image: url(:/qss_icons/rc/transparent.png);
945}
946
947QTreeView::branch:!has-children:!has-siblings:adjoins-item {
948 border-image: url(:/qss_icons/rc/transparent.png);
949}
950
951QTreeView::branch:has-children:!has-siblings:closed,
952QTreeView::branch:closed:has-children:has-siblings {
953 image: url(:/qss_icons/rc/branch_closed.png);
954}
955
956QTreeView::branch:open:has-children:!has-siblings,
957QTreeView::branch:open:has-children:has-siblings {
958 image: url(:/qss_icons/rc/branch_open.png);
959}
960
961QTreeView::branch:has-children:!has-siblings:closed:hover,
962QTreeView::branch:closed:has-children:has-siblings:hover {
963 image: url(:/qss_icons/rc/branch_closed-on.png);
964 }
965
966QTreeView::branch:open:has-children:!has-siblings:hover,
967QTreeView::branch:open:has-children:has-siblings:hover {
968 image: url(:/qss_icons/rc/branch_open-on.png);
969 }
970
971QListView::item:!selected:hover, QTreeView::item:!selected:hover {
972 background: #18465d;
973 outline: 0;
974 color: #eff0f1
975}
976
977QListView::item:selected:hover, QTreeView::item:selected:hover {
978 background: #287399;
979 color: #eff0f1;
980}
981
982QSlider::groove:horizontal {
983 border: 1px solid #565a5e;
984 height: 4px;
985 background: #565a5e;
986 margin: 0px;
987 border-radius: 2px;
988}
989
990QSlider::handle:horizontal {
991 background: #232629;
992 border: 1px solid #565a5e;
993 width: 16px;
994 height: 16px;
995 margin: -8px 0;
996 border-radius: 9px;
997}
998
999QSlider::groove:vertical {
1000 border: 1px solid #565a5e;
1001 width: 4px;
1002 background: #565a5e;
1003 margin: 0px;
1004 border-radius: 3px;
1005}
1006
1007QSlider::handle:vertical {
1008 background: #232629;
1009 border: 1px solid #565a5e;
1010 width: 16px;
1011 height: 16px;
1012 margin: 0 -8px;
1013 border-radius: 9px;
1014}
1015
1016QToolButton {
1017 background-color: transparent;
1018 border: 1px transparent #76797C;
1019 border-radius: 2px;
1020 margin: 3px;
1021 padding: 5px;
1022}
1023
1024QToolButton[popupMode="1"] { /* only for MenuButtonPopup */
1025 padding-right: 20px; /* make way for the popup button */
1026 border: 1px #76797C;
1027 border-radius: 5px;
1028}
1029
1030QToolButton[popupMode="2"] { /* only for InstantPopup */
1031 padding-right: 10px; /* make way for the popup button */
1032 border: 1px #76797C;
1033}
1034
1035
1036QToolButton:hover, QToolButton::menu-button:hover {
1037 background-color: transparent;
1038 border: 1px solid #3daee9;
1039 padding: 5px;
1040}
1041
1042QToolButton:checked, QToolButton:pressed,
1043 QToolButton::menu-button:pressed {
1044 background-color: #3daee9;
1045 border: 1px solid #3daee9;
1046 padding: 5px;
1047}
1048
1049/* the subcontrol below is used only in the InstantPopup or DelayedPopup mode */
1050QToolButton::menu-indicator {
1051 image: url(:/qss_icons/rc/down_arrow.png);
1052 top: -7px; left: -2px; /* shift it a bit */
1053}
1054
1055/* the subcontrols below are used only in the MenuButtonPopup mode */
1056QToolButton::menu-button {
1057 border: 1px transparent #76797C;
1058 border-top-right-radius: 6px;
1059 border-bottom-right-radius: 6px;
1060 /* 16px width + 4px for border = 20px allocated above */
1061 width: 16px;
1062 outline: none;
1063}
1064
1065QToolButton::menu-arrow {
1066 image: url(:/qss_icons/rc/down_arrow.png);
1067}
1068
1069QToolButton::menu-arrow:open {
1070 border: 1px solid #76797C;
1071}
1072
1073QPushButton::menu-indicator {
1074 subcontrol-origin: padding;
1075 subcontrol-position: bottom right;
1076 left: 8px;
1077}
1078
1079QTableView
1080{
1081 border: 1px solid #76797C;
1082 gridline-color: #31363b;
1083 background-color: #232629;
1084}
1085
1086
1087QTableView, QHeaderView
1088{
1089 border-radius: 0px;
1090}
1091
1092QTableView::item:pressed, QListView::item:pressed, QTreeView::item:pressed {
1093 background: #18465d;
1094 color: #eff0f1;
1095}
1096
1097QTableView::item:selected:active, QTreeView::item:selected:active, QListView::item:selected:active {
1098 background: #287399;
1099 color: #eff0f1;
1100}
1101
1102
1103QHeaderView
1104{
1105 background-color: #31363b;
1106 border: 1px transparent;
1107 border-radius: 0px;
1108 margin: 0px;
1109 padding: 0px;
1110
1111}
1112
1113QHeaderView::section {
1114 background-color: #31363b;
1115 color: #eff0f1;
1116 padding: 5px;
1117 border: 1px solid #76797C;
1118 border-radius: 0px;
1119 text-align: center;
1120}
1121
1122QHeaderView::section::vertical::first, QHeaderView::section::vertical::only-one
1123{
1124 border-top: 1px solid #76797C;
1125}
1126
1127QHeaderView::section::vertical
1128{
1129 border-top: transparent;
1130}
1131
1132QHeaderView::section::horizontal::first, QHeaderView::section::horizontal::only-one
1133{
1134 border-left: 1px solid #76797C;
1135}
1136
1137QHeaderView::section::horizontal
1138{
1139 border-left: transparent;
1140}
1141
1142
1143QHeaderView::section:checked
1144 {
1145 color: white;
1146 background-color: #334e5e;
1147 }
1148
1149 /* style the sort indicator */
1150QHeaderView::down-arrow {
1151 image: url(:/qss_icons/rc/down_arrow.png);
1152}
1153
1154QHeaderView::up-arrow {
1155 image: url(:/qss_icons/rc/up_arrow.png);
1156}
1157
1158
1159QTableCornerButton::section {
1160 background-color: #31363b;
1161 border: 1px transparent #76797C;
1162 border-radius: 0px;
1163}
1164
1165QToolBox {
1166 padding: 5px;
1167 border: 1px transparent black;
1168}
1169
1170QToolBox::tab {
1171 color: #eff0f1;
1172 background-color: #31363b;
1173 border: 1px solid #76797C;
1174 border-bottom: 1px transparent #31363b;
1175 border-top-left-radius: 5px;
1176 border-top-right-radius: 5px;
1177}
1178
1179QToolBox::tab:selected { /* italicize selected tabs */
1180 font: italic;
1181 background-color: #31363b;
1182 border-color: #3daee9;
1183 }
1184
1185QStatusBar::item {
1186 border: 0px transparent dark;
1187 }
1188
1189
1190QFrame[height="3"], QFrame[width="3"] {
1191 background-color: #76797C;
1192}
1193
1194
1195QSplitter::handle {
1196 border: 1px dashed #76797C;
1197}
1198
1199QSplitter::handle:hover {
1200 background-color: #787876;
1201 border: 1px solid #76797C;
1202}
1203
1204QSplitter::handle:horizontal {
1205 width: 1px;
1206}
1207
1208QSplitter::handle:vertical {
1209 height: 1px;
1210}
1211
1212QProgressBar {
1213 border: 1px solid #76797C;
1214 border-radius: 5px;
1215 text-align: center;
1216}
1217
1218QProgressBar::chunk {
1219 background-color: #05B8CC;
1220}
1221
1222QDateEdit
1223{
1224 selection-background-color: #3daee9;
1225 border-style: solid;
1226 border: 1px solid #3375A3;
1227 border-radius: 2px;
1228 padding: 1px;
1229 min-width: 75px;
1230}
1231
1232QDateEdit:on
1233{
1234 padding-top: 3px;
1235 padding-left: 4px;
1236 selection-background-color: #4a4a4a;
1237}
1238
1239QDateEdit QAbstractItemView
1240{
1241 background-color: #232629;
1242 border-radius: 2px;
1243 border: 1px solid #3375A3;
1244 selection-background-color: #3daee9;
1245}
1246
1247QDateEdit::drop-down
1248{
1249 subcontrol-origin: padding;
1250 subcontrol-position: top right;
1251 width: 15px;
1252 border-left-width: 0px;
1253 border-left-color: darkgray;
1254 border-left-style: solid;
1255 border-top-right-radius: 3px;
1256 border-bottom-right-radius: 3px;
1257}
1258
1259QDateEdit::down-arrow
1260{
1261 image: url(:/qss_icons/rc/down_arrow_disabled.png);
1262}
1263
1264QDateEdit::down-arrow:on, QDateEdit::down-arrow:hover,
1265QDateEdit::down-arrow:focus
1266{
1267 image: url(:/qss_icons/rc/down_arrow.png);
1268}
diff --git a/externals/CMakeLists.txt b/externals/CMakeLists.txt
index 347641c10..ec3c70779 100644
--- a/externals/CMakeLists.txt
+++ b/externals/CMakeLists.txt
@@ -38,15 +38,6 @@ target_include_directories(lz4_static INTERFACE ./lz4/lib)
38add_library(microprofile INTERFACE) 38add_library(microprofile INTERFACE)
39target_include_directories(microprofile INTERFACE ./microprofile) 39target_include_directories(microprofile INTERFACE ./microprofile)
40 40
41# Nihstro
42add_library(nihstro-headers INTERFACE)
43target_include_directories(nihstro-headers INTERFACE ./nihstro/include)
44
45# SoundTouch
46add_subdirectory(soundtouch)
47# The SoundTouch target doesn't export the necessary include paths as properties by default
48target_include_directories(SoundTouch INTERFACE ./soundtouch/include)
49
50# Unicorn 41# Unicorn
51add_library(unicorn-headers INTERFACE) 42add_library(unicorn-headers INTERFACE)
52target_include_directories(unicorn-headers INTERFACE ./unicorn/include) 43target_include_directories(unicorn-headers INTERFACE ./unicorn/include)
@@ -58,31 +49,3 @@ if (ARCHITECTURE_x86_64)
58 target_include_directories(xbyak INTERFACE ./xbyak/xbyak) 49 target_include_directories(xbyak INTERFACE ./xbyak/xbyak)
59 target_compile_definitions(xbyak INTERFACE XBYAK_NO_OP_NAMES) 50 target_compile_definitions(xbyak INTERFACE XBYAK_NO_OP_NAMES)
60endif() 51endif()
61
62# ENet
63add_subdirectory(enet)
64target_include_directories(enet INTERFACE ./enet/include)
65
66if (ENABLE_WEB_SERVICE)
67 # msys installed curl is configured to use openssl, but that isn't portable
68 # since it relies on having the bundled certs install in the home folder for SSL
69 # by default on mingw, download the precompiled curl thats linked against windows native ssl
70 if (MINGW AND CITRA_USE_BUNDLED_CURL)
71 download_bundled_external("curl/" "curl-7_55_1" CURL_PREFIX)
72 set(CURL_PREFIX "${CMAKE_BINARY_DIR}/externals/curl-7_55_1")
73 set(CURL_FOUND YES)
74 set(CURL_INCLUDE_DIR "${CURL_PREFIX}/include" CACHE PATH "Path to curl headers")
75 set(CURL_LIBRARY "${CURL_PREFIX}/lib/libcurldll.a" CACHE PATH "Path to curl library")
76 set(CURL_DLL_DIR "${CURL_PREFIX}/lib/" CACHE PATH "Path to curl.dll")
77 set(USE_SYSTEM_CURL ON CACHE BOOL "")
78 endif()
79 # CPR
80 set(BUILD_TESTING OFF CACHE BOOL "")
81 set(BUILD_CPR_TESTS OFF CACHE BOOL "")
82 add_subdirectory(cpr)
83 target_include_directories(cpr INTERFACE ./cpr/include)
84
85 # JSON
86 add_library(json-headers INTERFACE)
87 target_include_directories(json-headers INTERFACE ./json)
88endif()
diff --git a/externals/json/README.md b/externals/json/README.md
deleted file mode 100644
index 764d5a1c0..000000000
--- a/externals/json/README.md
+++ /dev/null
@@ -1,7 +0,0 @@
1JSON for Modern C++
2===================
3
4This is a mirror providing the single required header file.
5
6The original repository can be found at
7 https://github.com/nlohmann/json/commit/21d23982cafe826cae088b2bb37cb40c8e7a81fe
diff --git a/externals/json/json.hpp b/externals/json/json.hpp
deleted file mode 100644
index 1bde08ced..000000000
--- a/externals/json/json.hpp
+++ /dev/null
@@ -1,14516 +0,0 @@
1/*
2 __ _____ _____ _____
3 __| | __| | | | JSON for Modern C++
4| | |__ | | | | | | version 2.1.1
5|_____|_____|_____|_|___| https://github.com/nlohmann/json
6
7Licensed under the MIT License <http://opensource.org/licenses/MIT>.
8Copyright (c) 2013-2017 Niels Lohmann <http://nlohmann.me>.
9
10Permission is hereby granted, free of charge, to any person obtaining a copy
11of this software and associated documentation files (the "Software"), to deal
12in the Software without restriction, including without limitation the rights
13to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
14copies of the Software, and to permit persons to whom the Software is
15furnished to do so, subject to the following conditions:
16
17The above copyright notice and this permission notice shall be included in all
18copies or substantial portions of the Software.
19
20THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
21IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
22FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
23AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
24LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
25OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
26SOFTWARE.
27*/
28
29#ifndef NLOHMANN_JSON_HPP
30#define NLOHMANN_JSON_HPP
31
32#include <algorithm> // all_of, copy, fill, find, for_each, none_of, remove, reverse, transform
33#include <array> // array
34#include <cassert> // assert
35#include <ciso646> // and, not, or
36#include <clocale> // lconv, localeconv
37#include <cmath> // isfinite, labs, ldexp, signbit
38#include <cstddef> // nullptr_t, ptrdiff_t, size_t
39#include <cstdint> // int64_t, uint64_t
40#include <cstdlib> // abort, strtod, strtof, strtold, strtoul, strtoll, strtoull
41#include <cstring> // memcpy, strlen
42#include <forward_list> // forward_list
43#include <functional> // function, hash, less
44#include <initializer_list> // initializer_list
45#include <iomanip> // hex
46#include <iosfwd> // istream, ostream
47#include <iterator> // advance, begin, back_inserter, bidirectional_iterator_tag, distance, end, inserter, iterator, iterator_traits, next, random_access_iterator_tag, reverse_iterator
48#include <limits> // numeric_limits
49#include <locale> // locale
50#include <map> // map
51#include <memory> // addressof, allocator, allocator_traits, unique_ptr
52#include <numeric> // accumulate
53#include <sstream> // stringstream
54#include <string> // getline, stoi, string, to_string
55#include <type_traits> // add_pointer, conditional, decay, enable_if, false_type, integral_constant, is_arithmetic, is_base_of, is_const, is_constructible, is_convertible, is_default_constructible, is_enum, is_floating_point, is_integral, is_nothrow_move_assignable, is_nothrow_move_constructible, is_pointer, is_reference, is_same, is_scalar, is_signed, remove_const, remove_cv, remove_pointer, remove_reference, true_type, underlying_type
56#include <utility> // declval, forward, make_pair, move, pair, swap
57#include <vector> // vector
58
59// exclude unsupported compilers
60#if defined(__clang__)
61 #if (__clang_major__ * 10000 + __clang_minor__ * 100 + __clang_patchlevel__) < 30400
62 #error "unsupported Clang version - see https://github.com/nlohmann/json#supported-compilers"
63 #endif
64#elif defined(__GNUC__)
65 #if (__GNUC__ * 10000 + __GNUC_MINOR__ * 100 + __GNUC_PATCHLEVEL__) < 40900
66 #error "unsupported GCC version - see https://github.com/nlohmann/json#supported-compilers"
67 #endif
68#endif
69
70// disable float-equal warnings on GCC/clang
71#if defined(__clang__) || defined(__GNUC__) || defined(__GNUG__)
72 #pragma GCC diagnostic push
73 #pragma GCC diagnostic ignored "-Wfloat-equal"
74#endif
75
76// disable documentation warnings on clang
77#if defined(__clang__)
78 #pragma GCC diagnostic push
79 #pragma GCC diagnostic ignored "-Wdocumentation"
80#endif
81
82// allow for portable deprecation warnings
83#if defined(__clang__) || defined(__GNUC__) || defined(__GNUG__)
84 #define JSON_DEPRECATED __attribute__((deprecated))
85#elif defined(_MSC_VER)
86 #define JSON_DEPRECATED __declspec(deprecated)
87#else
88 #define JSON_DEPRECATED
89#endif
90
91// allow to disable exceptions
92#if (defined(__cpp_exceptions) || defined(__EXCEPTIONS) || defined(_CPPUNWIND)) && not defined(JSON_NOEXCEPTION)
93 #define JSON_THROW(exception) throw exception
94 #define JSON_TRY try
95 #define JSON_CATCH(exception) catch(exception)
96#else
97 #define JSON_THROW(exception) std::abort()
98 #define JSON_TRY if(true)
99 #define JSON_CATCH(exception) if(false)
100#endif
101
102// manual branch prediction
103#if defined(__clang__) || defined(__GNUC__) || defined(__GNUG__)
104 #define JSON_LIKELY(x) __builtin_expect(!!(x), 1)
105 #define JSON_UNLIKELY(x) __builtin_expect(!!(x), 0)
106#else
107 #define JSON_LIKELY(x) x
108 #define JSON_UNLIKELY(x) x
109#endif
110
111/*!
112@brief namespace for Niels Lohmann
113@see https://github.com/nlohmann
114@since version 1.0.0
115*/
116namespace nlohmann
117{
118
119/*!
120@brief unnamed namespace with internal helper functions
121
122This namespace collects some functions that could not be defined inside the
123@ref basic_json class.
124
125@since version 2.1.0
126*/
127namespace detail
128{
129////////////////
130// exceptions //
131////////////////
132
133/*!
134@brief general exception of the @ref basic_json class
135
136Extension of std::exception objects with a member @a id for exception ids.
137
138@note To have nothrow-copy-constructible exceptions, we internally use
139 std::runtime_error which can cope with arbitrary-length error messages.
140 Intermediate strings are built with static functions and then passed to
141 the actual constructor.
142
143@since version 3.0.0
144*/
145class exception : public std::exception
146{
147 public:
148 /// returns the explanatory string
149 virtual const char* what() const noexcept override
150 {
151 return m.what();
152 }
153
154 /// the id of the exception
155 const int id;
156
157 protected:
158 exception(int id_, const char* what_arg)
159 : id(id_), m(what_arg)
160 {}
161
162 static std::string name(const std::string& ename, int id)
163 {
164 return "[json.exception." + ename + "." + std::to_string(id) + "] ";
165 }
166
167 private:
168 /// an exception object as storage for error messages
169 std::runtime_error m;
170};
171
172/*!
173@brief exception indicating a parse error
174
175This excpetion is thrown by the library when a parse error occurs. Parse
176errors can occur during the deserialization of JSON text as well as when
177using JSON Patch.
178
179Member @a byte holds the byte index of the last read character in the input
180file.
181
182@note For an input with n bytes, 1 is the index of the first character
183 and n+1 is the index of the terminating null byte or the end of
184 file. This also holds true when reading a byte vector (CBOR or
185 MessagePack).
186
187Exceptions have ids 1xx.
188
189name / id | example massage | description
190------------------------------ | --------------- | -------------------------
191json.exception.parse_error.101 | parse error at 2: unexpected end of input; expected string literal | This error indicates a syntax error while deserializing a JSON text. The error message describes that an unexpected token (character) was encountered, and the member @a byte indicates the error position.
192json.exception.parse_error.102 | parse error at 14: missing or wrong low surrogate | JSON uses the `\uxxxx` format to describe Unicode characters. Code points above above 0xFFFF are split into two `\uxxxx` entries ("surrogate pairs"). This error indicates that the surrogate pair is incomplete or contains an invalid code point.
193json.exception.parse_error.103 | parse error: code points above 0x10FFFF are invalid | Unicode supports code points up to 0x10FFFF. Code points above 0x10FFFF are invalid.
194json.exception.parse_error.104 | parse error: JSON patch must be an array of objects | [RFC 6902](https://tools.ietf.org/html/rfc6902) requires a JSON Patch document to be a JSON document that represents an array of objects.
195json.exception.parse_error.105 | parse error: operation must have string member 'op' | An operation of a JSON Patch document must contain exactly one "op" member, whose value indicates the operation to perform. Its value must be one of "add", "remove", "replace", "move", "copy", or "test"; other values are errors.
196json.exception.parse_error.106 | parse error: array index '01' must not begin with '0' | An array index in a JSON Pointer ([RFC 6901](https://tools.ietf.org/html/rfc6901)) may be `0` or any number wihtout a leading `0`.
197json.exception.parse_error.107 | parse error: JSON pointer must be empty or begin with '/' - was: 'foo' | A JSON Pointer must be a Unicode string containing a sequence of zero or more reference tokens, each prefixed by a `/` character.
198json.exception.parse_error.108 | parse error: escape character '~' must be followed with '0' or '1' | In a JSON Pointer, only `~0` and `~1` are valid escape sequences.
199json.exception.parse_error.109 | parse error: array index 'one' is not a number | A JSON Pointer array index must be a number.
200json.exception.parse_error.110 | parse error at 1: cannot read 2 bytes from vector | When parsing CBOR or MessagePack, the byte vector ends before the complete value has been read.
201json.exception.parse_error.112 | parse error at 1: error reading CBOR; last byte: 0xf8 | Not all types of CBOR or MessagePack are supported. This exception occurs if an unsupported byte was read.
202json.exception.parse_error.113 | parse error at 2: expected a CBOR string; last byte: 0x98 | While parsing a map key, a value that is not a string has been read.
203
204@since version 3.0.0
205*/
206class parse_error : public exception
207{
208 public:
209 /*!
210 @brief create a parse error exception
211 @param[in] id the id of the exception
212 @param[in] byte_ the byte index where the error occurred (or 0 if
213 the position cannot be determined)
214 @param[in] what_arg the explanatory string
215 @return parse_error object
216 */
217 static parse_error create(int id, size_t byte_, const std::string& what_arg)
218 {
219 std::string w = exception::name("parse_error", id) + "parse error" +
220 (byte_ != 0 ? (" at " + std::to_string(byte_)) : "") +
221 ": " + what_arg;
222 return parse_error(id, byte_, w.c_str());
223 }
224
225 /*!
226 @brief byte index of the parse error
227
228 The byte index of the last read character in the input file.
229
230 @note For an input with n bytes, 1 is the index of the first character
231 and n+1 is the index of the terminating null byte or the end of
232 file. This also holds true when reading a byte vector (CBOR or
233 MessagePack).
234 */
235 const size_t byte;
236
237 private:
238 parse_error(int id_, size_t byte_, const char* what_arg)
239 : exception(id_, what_arg), byte(byte_)
240 {}
241};
242
243/*!
244@brief exception indicating errors with iterators
245
246Exceptions have ids 2xx.
247
248name / id | example massage | description
249----------------------------------- | --------------- | -------------------------
250json.exception.invalid_iterator.201 | iterators are not compatible | The iterators passed to constructor @ref basic_json(InputIT first, InputIT last) are not compatible, meaning they do not belong to the same container. Therefore, the range (@a first, @a last) is invalid.
251json.exception.invalid_iterator.202 | iterator does not fit current value | In an erase or insert function, the passed iterator @a pos does not belong to the JSON value for which the function was called. It hence does not define a valid position for the deletion/insertion.
252json.exception.invalid_iterator.203 | iterators do not fit current value | Either iterator passed to function @ref erase(IteratorType first, IteratorType last) does not belong to the JSON value from which values shall be erased. It hence does not define a valid range to delete values from.
253json.exception.invalid_iterator.204 | iterators out of range | When an iterator range for a primitive type (number, boolean, or string) is passed to a constructor or an erase function, this range has to be exactly (@ref begin(), @ref end()), because this is the only way the single stored value is expressed. All other ranges are invalid.
254json.exception.invalid_iterator.205 | iterator out of range | When an iterator for a primitive type (number, boolean, or string) is passed to an erase function, the iterator has to be the @ref begin() iterator, because it is the only way to address the stored value. All other iterators are invalid.
255json.exception.invalid_iterator.206 | cannot construct with iterators from null | The iterators passed to constructor @ref basic_json(InputIT first, InputIT last) belong to a JSON null value and hence to not define a valid range.
256json.exception.invalid_iterator.207 | cannot use key() for non-object iterators | The key() member function can only be used on iterators belonging to a JSON object, because other types do not have a concept of a key.
257json.exception.invalid_iterator.208 | cannot use operator[] for object iterators | The operator[] to specify a concrete offset cannot be used on iterators belonging to a JSON object, because JSON objects are unordered.
258json.exception.invalid_iterator.209 | cannot use offsets with object iterators | The offset operators (+, -, +=, -=) cannot be used on iterators belonging to a JSON object, because JSON objects are unordered.
259json.exception.invalid_iterator.210 | iterators do not fit | The iterator range passed to the insert function are not compatible, meaning they do not belong to the same container. Therefore, the range (@a first, @a last) is invalid.
260json.exception.invalid_iterator.211 | passed iterators may not belong to container | The iterator range passed to the insert function must not be a subrange of the container to insert to.
261json.exception.invalid_iterator.212 | cannot compare iterators of different containers | When two iterators are compared, they must belong to the same container.
262json.exception.invalid_iterator.213 | cannot compare order of object iterators | The order of object iterators cannot be compared, because JSON objects are unordered.
263json.exception.invalid_iterator.214 | cannot get value | Cannot get value for iterator: Either the iterator belongs to a null value or it is an iterator to a primitive type (number, boolean, or string), but the iterator is different to @ref begin().
264
265@since version 3.0.0
266*/
267class invalid_iterator : public exception
268{
269 public:
270 static invalid_iterator create(int id, const std::string& what_arg)
271 {
272 std::string w = exception::name("invalid_iterator", id) + what_arg;
273 return invalid_iterator(id, w.c_str());
274 }
275
276 private:
277 invalid_iterator(int id_, const char* what_arg)
278 : exception(id_, what_arg)
279 {}
280};
281
282/*!
283@brief exception indicating executing a member function with a wrong type
284
285Exceptions have ids 3xx.
286
287name / id | example message | description
288----------------------------- | --------------- | -------------------------
289json.exception.type_error.301 | cannot create object from initializer list | To create an object from an initializer list, the initializer list must consist only of a list of pairs whose first element is a string. When this constraint is violated, an array is created instead.
290json.exception.type_error.302 | type must be object, but is array | During implicit or explicit value conversion, the JSON type must be compatible to the target type. For instance, a JSON string can only be converted into string types, but not into numbers or boolean types.
291json.exception.type_error.303 | incompatible ReferenceType for get_ref, actual type is object | To retrieve a reference to a value stored in a @ref basic_json object with @ref get_ref, the type of the reference must match the value type. For instance, for a JSON array, the @a ReferenceType must be @ref array_t&.
292json.exception.type_error.304 | cannot use at() with string | The @ref at() member functions can only be executed for certain JSON types.
293json.exception.type_error.305 | cannot use operator[] with string | The @ref operator[] member functions can only be executed for certain JSON types.
294json.exception.type_error.306 | cannot use value() with string | The @ref value() member functions can only be executed for certain JSON types.
295json.exception.type_error.307 | cannot use erase() with string | The @ref erase() member functions can only be executed for certain JSON types.
296json.exception.type_error.308 | cannot use push_back() with string | The @ref push_back() and @ref operator+= member functions can only be executed for certain JSON types.
297json.exception.type_error.309 | cannot use insert() with | The @ref insert() member functions can only be executed for certain JSON types.
298json.exception.type_error.310 | cannot use swap() with number | The @ref swap() member functions can only be executed for certain JSON types.
299json.exception.type_error.311 | cannot use emplace_back() with string | The @ref emplace_back() member function can only be executed for certain JSON types.
300json.exception.type_error.313 | invalid value to unflatten | The @ref unflatten function converts an object whose keys are JSON Pointers back into an arbitrary nested JSON value. The JSON Pointers must not overlap, because then the resulting value would not be well defined.
301json.exception.type_error.314 | only objects can be unflattened | The @ref unflatten function only works for an object whose keys are JSON Pointers.
302json.exception.type_error.315 | values in object must be primitive | The @ref unflatten function only works for an object whose keys are JSON Pointers and whose values are primitive.
303
304@since version 3.0.0
305*/
306class type_error : public exception
307{
308 public:
309 static type_error create(int id, const std::string& what_arg)
310 {
311 std::string w = exception::name("type_error", id) + what_arg;
312 return type_error(id, w.c_str());
313 }
314
315 private:
316 type_error(int id_, const char* what_arg)
317 : exception(id_, what_arg)
318 {}
319};
320
321/*!
322@brief exception indicating access out of the defined range
323
324Exceptions have ids 4xx.
325
326name / id | example message | description
327------------------------------- | --------------- | -------------------------
328json.exception.out_of_range.401 | array index 3 is out of range | The provided array index @a i is larger than @a size-1.
329json.exception.out_of_range.402 | array index '-' (3) is out of range | The special array index `-` in a JSON Pointer never describes a valid element of the array, but the index past the end. That is, it can only be used to add elements at this position, but not to read it.
330json.exception.out_of_range.403 | key 'foo' not found | The provided key was not found in the JSON object.
331json.exception.out_of_range.404 | unresolved reference token 'foo' | A reference token in a JSON Pointer could not be resolved.
332json.exception.out_of_range.405 | JSON pointer has no parent | The JSON Patch operations 'remove' and 'add' can not be applied to the root element of the JSON value.
333json.exception.out_of_range.406 | number overflow parsing '10E1000' | A parsed number could not be stored as without changing it to NaN or INF.
334
335@since version 3.0.0
336*/
337class out_of_range : public exception
338{
339 public:
340 static out_of_range create(int id, const std::string& what_arg)
341 {
342 std::string w = exception::name("out_of_range", id) + what_arg;
343 return out_of_range(id, w.c_str());
344 }
345
346 private:
347 out_of_range(int id_, const char* what_arg)
348 : exception(id_, what_arg)
349 {}
350};
351
352/*!
353@brief exception indicating other errors
354
355Exceptions have ids 5xx.
356
357name / id | example message | description
358------------------------------ | --------------- | -------------------------
359json.exception.other_error.501 | unsuccessful: {"op":"test","path":"/baz", "value":"bar"} | A JSON Patch operation 'test' failed. The unsuccessful operation is also printed.
360json.exception.other_error.502 | invalid object size for conversion | Some conversions to user-defined types impose constraints on the object size (e.g. std::pair)
361
362@since version 3.0.0
363*/
364class other_error : public exception
365{
366 public:
367 static other_error create(int id, const std::string& what_arg)
368 {
369 std::string w = exception::name("other_error", id) + what_arg;
370 return other_error(id, w.c_str());
371 }
372
373 private:
374 other_error(int id_, const char* what_arg)
375 : exception(id_, what_arg)
376 {}
377};
378
379
380
381///////////////////////////
382// JSON type enumeration //
383///////////////////////////
384
385/*!
386@brief the JSON type enumeration
387
388This enumeration collects the different JSON types. It is internally used to
389distinguish the stored values, and the functions @ref basic_json::is_null(),
390@ref basic_json::is_object(), @ref basic_json::is_array(),
391@ref basic_json::is_string(), @ref basic_json::is_boolean(),
392@ref basic_json::is_number() (with @ref basic_json::is_number_integer(),
393@ref basic_json::is_number_unsigned(), and @ref basic_json::is_number_float()),
394@ref basic_json::is_discarded(), @ref basic_json::is_primitive(), and
395@ref basic_json::is_structured() rely on it.
396
397@note There are three enumeration entries (number_integer, number_unsigned, and
398number_float), because the library distinguishes these three types for numbers:
399@ref basic_json::number_unsigned_t is used for unsigned integers,
400@ref basic_json::number_integer_t is used for signed integers, and
401@ref basic_json::number_float_t is used for floating-point numbers or to
402approximate integers which do not fit in the limits of their respective type.
403
404@sa @ref basic_json::basic_json(const value_t value_type) -- create a JSON
405value with the default value for a given type
406
407@since version 1.0.0
408*/
409enum class value_t : uint8_t
410{
411 null, ///< null value
412 object, ///< object (unordered set of name/value pairs)
413 array, ///< array (ordered collection of values)
414 string, ///< string value
415 boolean, ///< boolean value
416 number_integer, ///< number value (signed integer)
417 number_unsigned, ///< number value (unsigned integer)
418 number_float, ///< number value (floating-point)
419 discarded ///< discarded by the the parser callback function
420};
421
422/*!
423@brief comparison operator for JSON types
424
425Returns an ordering that is similar to Python:
426- order: null < boolean < number < object < array < string
427- furthermore, each type is not smaller than itself
428
429@since version 1.0.0
430*/
431inline bool operator<(const value_t lhs, const value_t rhs) noexcept
432{
433 static constexpr std::array<uint8_t, 8> order = {{
434 0, // null
435 3, // object
436 4, // array
437 5, // string
438 1, // boolean
439 2, // integer
440 2, // unsigned
441 2, // float
442 }
443 };
444
445 // discarded values are not comparable
446 if (lhs == value_t::discarded or rhs == value_t::discarded)
447 {
448 return false;
449 }
450
451 return order[static_cast<std::size_t>(lhs)] <
452 order[static_cast<std::size_t>(rhs)];
453}
454
455
456/////////////
457// helpers //
458/////////////
459
460// alias templates to reduce boilerplate
461template<bool B, typename T = void>
462using enable_if_t = typename std::enable_if<B, T>::type;
463
464template<typename T>
465using uncvref_t = typename std::remove_cv<typename std::remove_reference<T>::type>::type;
466
467// implementation of C++14 index_sequence and affiliates
468// source: https://stackoverflow.com/a/32223343
469template <std::size_t... Ints>
470struct index_sequence
471{
472 using type = index_sequence;
473 using value_type = std::size_t;
474 static constexpr std::size_t size() noexcept
475 {
476 return sizeof...(Ints);
477 }
478};
479
480template <class Sequence1, class Sequence2>
481struct merge_and_renumber;
482
483template <std::size_t... I1, std::size_t... I2>
484struct merge_and_renumber<index_sequence<I1...>, index_sequence<I2...>>
485 : index_sequence < I1..., (sizeof...(I1) + I2)... >
486 { };
487
488template <std::size_t N>
489struct make_index_sequence
490 : merge_and_renumber < typename make_index_sequence < N / 2 >::type,
491 typename make_index_sequence < N - N / 2 >::type >
492{ };
493
494template<> struct make_index_sequence<0> : index_sequence<> { };
495template<> struct make_index_sequence<1> : index_sequence<0> { };
496
497template<typename... Ts>
498using index_sequence_for = make_index_sequence<sizeof...(Ts)>;
499
500/*
501Implementation of two C++17 constructs: conjunction, negation. This is needed
502to avoid evaluating all the traits in a condition
503
504For example: not std::is_same<void, T>::value and has_value_type<T>::value
505will not compile when T = void (on MSVC at least). Whereas
506conjunction<negation<std::is_same<void, T>>, has_value_type<T>>::value will
507stop evaluating if negation<...>::value == false
508
509Please note that those constructs must be used with caution, since symbols can
510become very long quickly (which can slow down compilation and cause MSVC
511internal compiler errors). Only use it when you have to (see example ahead).
512*/
513template<class...> struct conjunction : std::true_type {};
514template<class B1> struct conjunction<B1> : B1 {};
515template<class B1, class... Bn>
516struct conjunction<B1, Bn...> : std::conditional<bool(B1::value), conjunction<Bn...>, B1>::type {};
517
518template<class B> struct negation : std::integral_constant < bool, !B::value > {};
519
520// dispatch utility (taken from ranges-v3)
521template<unsigned N> struct priority_tag : priority_tag < N - 1 > {};
522template<> struct priority_tag<0> {};
523
524
525//////////////////
526// constructors //
527//////////////////
528
529template<value_t> struct external_constructor;
530
531template<>
532struct external_constructor<value_t::boolean>
533{
534 template<typename BasicJsonType>
535 static void construct(BasicJsonType& j, typename BasicJsonType::boolean_t b) noexcept
536 {
537 j.m_type = value_t::boolean;
538 j.m_value = b;
539 j.assert_invariant();
540 }
541};
542
543template<>
544struct external_constructor<value_t::string>
545{
546 template<typename BasicJsonType>
547 static void construct(BasicJsonType& j, const typename BasicJsonType::string_t& s)
548 {
549 j.m_type = value_t::string;
550 j.m_value = s;
551 j.assert_invariant();
552 }
553};
554
555template<>
556struct external_constructor<value_t::number_float>
557{
558 template<typename BasicJsonType>
559 static void construct(BasicJsonType& j, typename BasicJsonType::number_float_t val) noexcept
560 {
561 j.m_type = value_t::number_float;
562 j.m_value = val;
563 j.assert_invariant();
564 }
565};
566
567template<>
568struct external_constructor<value_t::number_unsigned>
569{
570 template<typename BasicJsonType>
571 static void construct(BasicJsonType& j, typename BasicJsonType::number_unsigned_t val) noexcept
572 {
573 j.m_type = value_t::number_unsigned;
574 j.m_value = val;
575 j.assert_invariant();
576 }
577};
578
579template<>
580struct external_constructor<value_t::number_integer>
581{
582 template<typename BasicJsonType>
583 static void construct(BasicJsonType& j, typename BasicJsonType::number_integer_t val) noexcept
584 {
585 j.m_type = value_t::number_integer;
586 j.m_value = val;
587 j.assert_invariant();
588 }
589};
590
591template<>
592struct external_constructor<value_t::array>
593{
594 template<typename BasicJsonType>
595 static void construct(BasicJsonType& j, const typename BasicJsonType::array_t& arr)
596 {
597 j.m_type = value_t::array;
598 j.m_value = arr;
599 j.assert_invariant();
600 }
601
602 template<typename BasicJsonType, typename CompatibleArrayType,
603 enable_if_t<not std::is_same<CompatibleArrayType,
604 typename BasicJsonType::array_t>::value,
605 int> = 0>
606 static void construct(BasicJsonType& j, const CompatibleArrayType& arr)
607 {
608 using std::begin;
609 using std::end;
610 j.m_type = value_t::array;
611 j.m_value.array = j.template create<typename BasicJsonType::array_t>(begin(arr), end(arr));
612 j.assert_invariant();
613 }
614
615 template<typename BasicJsonType>
616 static void construct(BasicJsonType& j, const std::vector<bool>& arr)
617 {
618 j.m_type = value_t::array;
619 j.m_value = value_t::array;
620 j.m_value.array->reserve(arr.size());
621 for (bool x : arr)
622 {
623 j.m_value.array->push_back(x);
624 }
625 j.assert_invariant();
626 }
627};
628
629template<>
630struct external_constructor<value_t::object>
631{
632 template<typename BasicJsonType>
633 static void construct(BasicJsonType& j, const typename BasicJsonType::object_t& obj)
634 {
635 j.m_type = value_t::object;
636 j.m_value = obj;
637 j.assert_invariant();
638 }
639
640 template<typename BasicJsonType, typename CompatibleObjectType,
641 enable_if_t<not std::is_same<CompatibleObjectType,
642 typename BasicJsonType::object_t>::value,
643 int> = 0>
644 static void construct(BasicJsonType& j, const CompatibleObjectType& obj)
645 {
646 using std::begin;
647 using std::end;
648
649 j.m_type = value_t::object;
650 j.m_value.object = j.template create<typename BasicJsonType::object_t>(begin(obj), end(obj));
651 j.assert_invariant();
652 }
653};
654
655
656////////////////////////
657// has_/is_ functions //
658////////////////////////
659
660/*!
661@brief Helper to determine whether there's a key_type for T.
662
663This helper is used to tell associative containers apart from other containers
664such as sequence containers. For instance, `std::map` passes the test as it
665contains a `mapped_type`, whereas `std::vector` fails the test.
666
667@sa http://stackoverflow.com/a/7728728/266378
668@since version 1.0.0, overworked in version 2.0.6
669*/
670#define NLOHMANN_JSON_HAS_HELPER(type) \
671 template<typename T> struct has_##type { \
672 private: \
673 template<typename U, typename = typename U::type> \
674 static int detect(U &&); \
675 static void detect(...); \
676 public: \
677 static constexpr bool value = \
678 std::is_integral<decltype(detect(std::declval<T>()))>::value; \
679 }
680
681NLOHMANN_JSON_HAS_HELPER(mapped_type);
682NLOHMANN_JSON_HAS_HELPER(key_type);
683NLOHMANN_JSON_HAS_HELPER(value_type);
684NLOHMANN_JSON_HAS_HELPER(iterator);
685
686#undef NLOHMANN_JSON_HAS_HELPER
687
688
689template<bool B, class RealType, class CompatibleObjectType>
690struct is_compatible_object_type_impl : std::false_type {};
691
692template<class RealType, class CompatibleObjectType>
693struct is_compatible_object_type_impl<true, RealType, CompatibleObjectType>
694{
695 static constexpr auto value =
696 std::is_constructible<typename RealType::key_type,
697 typename CompatibleObjectType::key_type>::value and
698 std::is_constructible<typename RealType::mapped_type,
699 typename CompatibleObjectType::mapped_type>::value;
700};
701
702template<class BasicJsonType, class CompatibleObjectType>
703struct is_compatible_object_type
704{
705 static auto constexpr value = is_compatible_object_type_impl <
706 conjunction<negation<std::is_same<void, CompatibleObjectType>>,
707 has_mapped_type<CompatibleObjectType>,
708 has_key_type<CompatibleObjectType>>::value,
709 typename BasicJsonType::object_t, CompatibleObjectType >::value;
710};
711
712template<typename BasicJsonType, typename T>
713struct is_basic_json_nested_type
714{
715 static auto constexpr value = std::is_same<T, typename BasicJsonType::iterator>::value or
716 std::is_same<T, typename BasicJsonType::const_iterator>::value or
717 std::is_same<T, typename BasicJsonType::reverse_iterator>::value or
718 std::is_same<T, typename BasicJsonType::const_reverse_iterator>::value or
719 std::is_same<T, typename BasicJsonType::json_pointer>::value;
720};
721
722template<class BasicJsonType, class CompatibleArrayType>
723struct is_compatible_array_type
724{
725 static auto constexpr value =
726 conjunction<negation<std::is_same<void, CompatibleArrayType>>,
727 negation<is_compatible_object_type<
728 BasicJsonType, CompatibleArrayType>>,
729 negation<std::is_constructible<typename BasicJsonType::string_t,
730 CompatibleArrayType>>,
731 negation<is_basic_json_nested_type<BasicJsonType, CompatibleArrayType>>,
732 has_value_type<CompatibleArrayType>,
733 has_iterator<CompatibleArrayType>>::value;
734};
735
736template<bool, typename, typename>
737struct is_compatible_integer_type_impl : std::false_type {};
738
739template<typename RealIntegerType, typename CompatibleNumberIntegerType>
740struct is_compatible_integer_type_impl<true, RealIntegerType, CompatibleNumberIntegerType>
741{
742 // is there an assert somewhere on overflows?
743 using RealLimits = std::numeric_limits<RealIntegerType>;
744 using CompatibleLimits = std::numeric_limits<CompatibleNumberIntegerType>;
745
746 static constexpr auto value =
747 std::is_constructible<RealIntegerType,
748 CompatibleNumberIntegerType>::value and
749 CompatibleLimits::is_integer and
750 RealLimits::is_signed == CompatibleLimits::is_signed;
751};
752
753template<typename RealIntegerType, typename CompatibleNumberIntegerType>
754struct is_compatible_integer_type
755{
756 static constexpr auto value =
757 is_compatible_integer_type_impl <
758 std::is_integral<CompatibleNumberIntegerType>::value and
759 not std::is_same<bool, CompatibleNumberIntegerType>::value,
760 RealIntegerType, CompatibleNumberIntegerType > ::value;
761};
762
763
764// trait checking if JSONSerializer<T>::from_json(json const&, udt&) exists
765template<typename BasicJsonType, typename T>
766struct has_from_json
767{
768 private:
769 // also check the return type of from_json
770 template<typename U, typename = enable_if_t<std::is_same<void, decltype(uncvref_t<U>::from_json(
771 std::declval<BasicJsonType>(), std::declval<T&>()))>::value>>
772 static int detect(U&&);
773 static void detect(...);
774
775 public:
776 static constexpr bool value = std::is_integral<decltype(
777 detect(std::declval<typename BasicJsonType::template json_serializer<T, void>>()))>::value;
778};
779
780// This trait checks if JSONSerializer<T>::from_json(json const&) exists
781// this overload is used for non-default-constructible user-defined-types
782template<typename BasicJsonType, typename T>
783struct has_non_default_from_json
784{
785 private:
786 template <
787 typename U,
788 typename = enable_if_t<std::is_same<
789 T, decltype(uncvref_t<U>::from_json(std::declval<BasicJsonType>()))>::value >>
790 static int detect(U&&);
791 static void detect(...);
792
793 public:
794 static constexpr bool value = std::is_integral<decltype(detect(
795 std::declval<typename BasicJsonType::template json_serializer<T, void>>()))>::value;
796};
797
798// This trait checks if BasicJsonType::json_serializer<T>::to_json exists
799template<typename BasicJsonType, typename T>
800struct has_to_json
801{
802 private:
803 template<typename U, typename = decltype(uncvref_t<U>::to_json(
804 std::declval<BasicJsonType&>(), std::declval<T>()))>
805 static int detect(U&&);
806 static void detect(...);
807
808 public:
809 static constexpr bool value = std::is_integral<decltype(detect(
810 std::declval<typename BasicJsonType::template json_serializer<T, void>>()))>::value;
811};
812
813
814/////////////
815// to_json //
816/////////////
817
818template<typename BasicJsonType, typename T, enable_if_t<
819 std::is_same<T, typename BasicJsonType::boolean_t>::value, int> = 0>
820void to_json(BasicJsonType& j, T b) noexcept
821{
822 external_constructor<value_t::boolean>::construct(j, b);
823}
824
825template<typename BasicJsonType, typename CompatibleString,
826 enable_if_t<std::is_constructible<typename BasicJsonType::string_t,
827 CompatibleString>::value, int> = 0>
828void to_json(BasicJsonType& j, const CompatibleString& s)
829{
830 external_constructor<value_t::string>::construct(j, s);
831}
832
833template<typename BasicJsonType, typename FloatType,
834 enable_if_t<std::is_floating_point<FloatType>::value, int> = 0>
835void to_json(BasicJsonType& j, FloatType val) noexcept
836{
837 external_constructor<value_t::number_float>::construct(j, static_cast<typename BasicJsonType::number_float_t>(val));
838}
839
840template <
841 typename BasicJsonType, typename CompatibleNumberUnsignedType,
842 enable_if_t<is_compatible_integer_type<typename BasicJsonType::number_unsigned_t,
843 CompatibleNumberUnsignedType>::value, int> = 0 >
844void to_json(BasicJsonType& j, CompatibleNumberUnsignedType val) noexcept
845{
846 external_constructor<value_t::number_unsigned>::construct(j, static_cast<typename BasicJsonType::number_unsigned_t>(val));
847}
848
849template <
850 typename BasicJsonType, typename CompatibleNumberIntegerType,
851 enable_if_t<is_compatible_integer_type<typename BasicJsonType::number_integer_t,
852 CompatibleNumberIntegerType>::value, int> = 0 >
853void to_json(BasicJsonType& j, CompatibleNumberIntegerType val) noexcept
854{
855 external_constructor<value_t::number_integer>::construct(j, static_cast<typename BasicJsonType::number_integer_t>(val));
856}
857
858template<typename BasicJsonType, typename EnumType,
859 enable_if_t<std::is_enum<EnumType>::value, int> = 0>
860void to_json(BasicJsonType& j, EnumType e) noexcept
861{
862 using underlying_type = typename std::underlying_type<EnumType>::type;
863 external_constructor<value_t::number_integer>::construct(j, static_cast<underlying_type>(e));
864}
865
866template<typename BasicJsonType>
867void to_json(BasicJsonType& j, const std::vector<bool>& e)
868{
869 external_constructor<value_t::array>::construct(j, e);
870}
871
872template <
873 typename BasicJsonType, typename CompatibleArrayType,
874 enable_if_t <
875 is_compatible_array_type<BasicJsonType, CompatibleArrayType>::value or
876 std::is_same<typename BasicJsonType::array_t, CompatibleArrayType>::value,
877 int > = 0 >
878void to_json(BasicJsonType& j, const CompatibleArrayType& arr)
879{
880 external_constructor<value_t::array>::construct(j, arr);
881}
882
883template <
884 typename BasicJsonType, typename CompatibleObjectType,
885 enable_if_t<is_compatible_object_type<BasicJsonType, CompatibleObjectType>::value,
886 int> = 0 >
887void to_json(BasicJsonType& j, const CompatibleObjectType& arr)
888{
889 external_constructor<value_t::object>::construct(j, arr);
890}
891
892template <typename BasicJsonType, typename T, std::size_t N,
893 enable_if_t<not std::is_constructible<
894 typename BasicJsonType::string_t, T (&)[N]>::value,
895 int> = 0>
896void to_json(BasicJsonType& j, T (&arr)[N])
897{
898 external_constructor<value_t::array>::construct(j, arr);
899}
900
901template <typename BasicJsonType, typename... Args>
902void to_json(BasicJsonType& j, const std::pair<Args...>& p)
903{
904 j = {p.first, p.second};
905}
906
907template <typename BasicJsonType, typename Tuple, std::size_t... Idx>
908void to_json_tuple_impl(BasicJsonType& j, const Tuple& t, index_sequence<Idx...>)
909{
910 j = {std::get<Idx>(t)...};
911}
912
913template <typename BasicJsonType, typename... Args>
914void to_json(BasicJsonType& j, const std::tuple<Args...>& t)
915{
916 to_json_tuple_impl(j, t, index_sequence_for<Args...> {});
917}
918
919///////////////
920// from_json //
921///////////////
922
923// overloads for basic_json template parameters
924template<typename BasicJsonType, typename ArithmeticType,
925 enable_if_t<std::is_arithmetic<ArithmeticType>::value and
926 not std::is_same<ArithmeticType,
927 typename BasicJsonType::boolean_t>::value,
928 int> = 0>
929void get_arithmetic_value(const BasicJsonType& j, ArithmeticType& val)
930{
931 switch (static_cast<value_t>(j))
932 {
933 case value_t::number_unsigned:
934 {
935 val = static_cast<ArithmeticType>(
936 *j.template get_ptr<const typename BasicJsonType::number_unsigned_t*>());
937 break;
938 }
939 case value_t::number_integer:
940 {
941 val = static_cast<ArithmeticType>(
942 *j.template get_ptr<const typename BasicJsonType::number_integer_t*>());
943 break;
944 }
945 case value_t::number_float:
946 {
947 val = static_cast<ArithmeticType>(
948 *j.template get_ptr<const typename BasicJsonType::number_float_t*>());
949 break;
950 }
951 default:
952 {
953 JSON_THROW(type_error::create(302, "type must be number, but is " + j.type_name()));
954 }
955 }
956}
957
958template<typename BasicJsonType>
959void from_json(const BasicJsonType& j, typename BasicJsonType::boolean_t& b)
960{
961 if (not j.is_boolean())
962 {
963 JSON_THROW(type_error::create(302, "type must be boolean, but is " + j.type_name()));
964 }
965 b = *j.template get_ptr<const typename BasicJsonType::boolean_t*>();
966}
967
968template<typename BasicJsonType>
969void from_json(const BasicJsonType& j, typename BasicJsonType::string_t& s)
970{
971 if (not j.is_string())
972 {
973 JSON_THROW(type_error::create(302, "type must be string, but is " + j.type_name()));
974 }
975 s = *j.template get_ptr<const typename BasicJsonType::string_t*>();
976}
977
978template<typename BasicJsonType>
979void from_json(const BasicJsonType& j, typename BasicJsonType::number_float_t& val)
980{
981 get_arithmetic_value(j, val);
982}
983
984template<typename BasicJsonType>
985void from_json(const BasicJsonType& j, typename BasicJsonType::number_unsigned_t& val)
986{
987 get_arithmetic_value(j, val);
988}
989
990template<typename BasicJsonType>
991void from_json(const BasicJsonType& j, typename BasicJsonType::number_integer_t& val)
992{
993 get_arithmetic_value(j, val);
994}
995
996template<typename BasicJsonType, typename EnumType,
997 enable_if_t<std::is_enum<EnumType>::value, int> = 0>
998void from_json(const BasicJsonType& j, EnumType& e)
999{
1000 typename std::underlying_type<EnumType>::type val;
1001 get_arithmetic_value(j, val);
1002 e = static_cast<EnumType>(val);
1003}
1004
1005template<typename BasicJsonType>
1006void from_json(const BasicJsonType& j, typename BasicJsonType::array_t& arr)
1007{
1008 if (not j.is_array())
1009 {
1010 JSON_THROW(type_error::create(302, "type must be array, but is " + j.type_name()));
1011 }
1012 arr = *j.template get_ptr<const typename BasicJsonType::array_t*>();
1013}
1014
1015// forward_list doesn't have an insert method
1016template<typename BasicJsonType, typename T, typename Allocator,
1017 enable_if_t<std::is_convertible<BasicJsonType, T>::value, int> = 0>
1018void from_json(const BasicJsonType& j, std::forward_list<T, Allocator>& l)
1019{
1020 if (not j.is_array())
1021 {
1022 JSON_THROW(type_error::create(302, "type must be array, but is " + j.type_name()));
1023 }
1024
1025 for (auto it = j.rbegin(), end = j.rend(); it != end; ++it)
1026 {
1027 l.push_front(it->template get<T>());
1028 }
1029}
1030
1031template<typename BasicJsonType, typename CompatibleArrayType>
1032void from_json_array_impl(const BasicJsonType& j, CompatibleArrayType& arr, priority_tag<0>)
1033{
1034 using std::begin;
1035 using std::end;
1036
1037 std::transform(j.begin(), j.end(),
1038 std::inserter(arr, end(arr)), [](const BasicJsonType & i)
1039 {
1040 // get<BasicJsonType>() returns *this, this won't call a from_json
1041 // method when value_type is BasicJsonType
1042 return i.template get<typename CompatibleArrayType::value_type>();
1043 });
1044}
1045
1046template<typename BasicJsonType, typename CompatibleArrayType>
1047auto from_json_array_impl(const BasicJsonType& j, CompatibleArrayType& arr, priority_tag<1>)
1048-> decltype(
1049 arr.reserve(std::declval<typename CompatibleArrayType::size_type>()),
1050 void())
1051{
1052 using std::begin;
1053 using std::end;
1054
1055 arr.reserve(j.size());
1056 std::transform(j.begin(), j.end(),
1057 std::inserter(arr, end(arr)), [](const BasicJsonType & i)
1058 {
1059 // get<BasicJsonType>() returns *this, this won't call a from_json
1060 // method when value_type is BasicJsonType
1061 return i.template get<typename CompatibleArrayType::value_type>();
1062 });
1063}
1064
1065template <typename BasicJsonType, typename T, std::size_t N>
1066void from_json_array_impl(const BasicJsonType& j, std::array<T, N>& arr, priority_tag<2>)
1067{
1068 for (std::size_t i = 0; i < N; ++i)
1069 {
1070 arr[i] = j.at(i).template get<T>();
1071 }
1072}
1073
1074template<typename BasicJsonType, typename CompatibleArrayType,
1075 enable_if_t<is_compatible_array_type<BasicJsonType, CompatibleArrayType>::value and
1076 std::is_convertible<BasicJsonType, typename CompatibleArrayType::value_type>::value and
1077 not std::is_same<typename BasicJsonType::array_t, CompatibleArrayType>::value, int> = 0>
1078void from_json(const BasicJsonType& j, CompatibleArrayType& arr)
1079{
1080 if (not j.is_array())
1081 {
1082 JSON_THROW(type_error::create(302, "type must be array, but is " + j.type_name()));
1083 }
1084
1085 from_json_array_impl(j, arr, priority_tag<2> {});
1086}
1087
1088template<typename BasicJsonType, typename CompatibleObjectType,
1089 enable_if_t<is_compatible_object_type<BasicJsonType, CompatibleObjectType>::value, int> = 0>
1090void from_json(const BasicJsonType& j, CompatibleObjectType& obj)
1091{
1092 if (not j.is_object())
1093 {
1094 JSON_THROW(type_error::create(302, "type must be object, but is " + j.type_name()));
1095 }
1096
1097 auto inner_object = j.template get_ptr<const typename BasicJsonType::object_t*>();
1098 using std::begin;
1099 using std::end;
1100 using value_type = typename CompatibleObjectType::value_type;
1101 std::transform(
1102 inner_object->begin(), inner_object->end(),
1103 std::inserter(obj, obj.begin()),
1104 [](typename BasicJsonType::object_t::value_type const & p)
1105 {
1106 return value_type(
1107 p.first,
1108 p.second
1109 .template get<typename CompatibleObjectType::mapped_type>());
1110 });
1111}
1112
1113// overload for arithmetic types, not chosen for basic_json template arguments
1114// (BooleanType, etc..); note: Is it really necessary to provide explicit
1115// overloads for boolean_t etc. in case of a custom BooleanType which is not
1116// an arithmetic type?
1117template<typename BasicJsonType, typename ArithmeticType,
1118 enable_if_t <
1119 std::is_arithmetic<ArithmeticType>::value and
1120 not std::is_same<ArithmeticType, typename BasicJsonType::number_unsigned_t>::value and
1121 not std::is_same<ArithmeticType, typename BasicJsonType::number_integer_t>::value and
1122 not std::is_same<ArithmeticType, typename BasicJsonType::number_float_t>::value and
1123 not std::is_same<ArithmeticType, typename BasicJsonType::boolean_t>::value,
1124 int> = 0>
1125void from_json(const BasicJsonType& j, ArithmeticType& val)
1126{
1127 switch (static_cast<value_t>(j))
1128 {
1129 case value_t::number_unsigned:
1130 {
1131 val = static_cast<ArithmeticType>(*j.template get_ptr<const typename BasicJsonType::number_unsigned_t*>());
1132 break;
1133 }
1134 case value_t::number_integer:
1135 {
1136 val = static_cast<ArithmeticType>(*j.template get_ptr<const typename BasicJsonType::number_integer_t*>());
1137 break;
1138 }
1139 case value_t::number_float:
1140 {
1141 val = static_cast<ArithmeticType>(*j.template get_ptr<const typename BasicJsonType::number_float_t*>());
1142 break;
1143 }
1144 case value_t::boolean:
1145 {
1146 val = static_cast<ArithmeticType>(*j.template get_ptr<const typename BasicJsonType::boolean_t*>());
1147 break;
1148 }
1149 default:
1150 {
1151 JSON_THROW(type_error::create(302, "type must be number, but is " + j.type_name()));
1152 }
1153 }
1154}
1155
1156template <typename BasicJsonType, typename... Args>
1157void from_json(const BasicJsonType& j, std::pair<Args...>& p)
1158{
1159 p = {j.at(0), j.at(1)};
1160}
1161
1162template <typename BasicJsonType, typename Tuple, std::size_t... Idx>
1163void from_json_tuple_impl(const BasicJsonType& j, Tuple& t, index_sequence<Idx...>)
1164{
1165 t = std::make_tuple(j.at(Idx)...);
1166}
1167
1168template <typename BasicJsonType, typename... Args>
1169void from_json(const BasicJsonType& j, std::tuple<Args...>& t)
1170{
1171 from_json_tuple_impl(j, t, index_sequence_for<Args...> {});
1172}
1173
1174struct to_json_fn
1175{
1176 private:
1177 template<typename BasicJsonType, typename T>
1178 auto call(BasicJsonType& j, T&& val, priority_tag<1>) const noexcept(noexcept(to_json(j, std::forward<T>(val))))
1179 -> decltype(to_json(j, std::forward<T>(val)), void())
1180 {
1181 return to_json(j, std::forward<T>(val));
1182 }
1183
1184 template<typename BasicJsonType, typename T>
1185 void call(BasicJsonType&, T&&, priority_tag<0>) const noexcept
1186 {
1187 static_assert(sizeof(BasicJsonType) == 0,
1188 "could not find to_json() method in T's namespace");
1189 }
1190
1191 public:
1192 template<typename BasicJsonType, typename T>
1193 void operator()(BasicJsonType& j, T&& val) const
1194 noexcept(noexcept(std::declval<to_json_fn>().call(j, std::forward<T>(val), priority_tag<1> {})))
1195 {
1196 return call(j, std::forward<T>(val), priority_tag<1> {});
1197 }
1198};
1199
1200struct from_json_fn
1201{
1202 private:
1203 template<typename BasicJsonType, typename T>
1204 auto call(const BasicJsonType& j, T& val, priority_tag<1>) const
1205 noexcept(noexcept(from_json(j, val)))
1206 -> decltype(from_json(j, val), void())
1207 {
1208 return from_json(j, val);
1209 }
1210
1211 template<typename BasicJsonType, typename T>
1212 void call(const BasicJsonType&, T&, priority_tag<0>) const noexcept
1213 {
1214 static_assert(sizeof(BasicJsonType) == 0,
1215 "could not find from_json() method in T's namespace");
1216 }
1217
1218 public:
1219 template<typename BasicJsonType, typename T>
1220 void operator()(const BasicJsonType& j, T& val) const
1221 noexcept(noexcept(std::declval<from_json_fn>().call(j, val, priority_tag<1> {})))
1222 {
1223 return call(j, val, priority_tag<1> {});
1224 }
1225};
1226
1227// taken from ranges-v3
1228template<typename T>
1229struct static_const
1230{
1231 static constexpr T value{};
1232};
1233
1234template<typename T>
1235constexpr T static_const<T>::value;
1236} // namespace detail
1237
1238
1239/// namespace to hold default `to_json` / `from_json` functions
1240namespace
1241{
1242constexpr const auto& to_json = detail::static_const<detail::to_json_fn>::value;
1243constexpr const auto& from_json = detail::static_const<detail::from_json_fn>::value;
1244}
1245
1246
1247/*!
1248@brief default JSONSerializer template argument
1249
1250This serializer ignores the template arguments and uses ADL
1251([argument-dependent lookup](http://en.cppreference.com/w/cpp/language/adl))
1252for serialization.
1253*/
1254template<typename = void, typename = void>
1255struct adl_serializer
1256{
1257 /*!
1258 @brief convert a JSON value to any value type
1259
1260 This function is usually called by the `get()` function of the
1261 @ref basic_json class (either explicit or via conversion operators).
1262
1263 @param[in] j JSON value to read from
1264 @param[in,out] val value to write to
1265 */
1266 template<typename BasicJsonType, typename ValueType>
1267 static void from_json(BasicJsonType&& j, ValueType& val) noexcept(
1268 noexcept(::nlohmann::from_json(std::forward<BasicJsonType>(j), val)))
1269 {
1270 ::nlohmann::from_json(std::forward<BasicJsonType>(j), val);
1271 }
1272
1273 /*!
1274 @brief convert any value type to a JSON value
1275
1276 This function is usually called by the constructors of the @ref basic_json
1277 class.
1278
1279 @param[in,out] j JSON value to write to
1280 @param[in] val value to read from
1281 */
1282 template<typename BasicJsonType, typename ValueType>
1283 static void to_json(BasicJsonType& j, ValueType&& val) noexcept(
1284 noexcept(::nlohmann::to_json(j, std::forward<ValueType>(val))))
1285 {
1286 ::nlohmann::to_json(j, std::forward<ValueType>(val));
1287 }
1288};
1289
1290
1291/*!
1292@brief a class to store JSON values
1293
1294@tparam ObjectType type for JSON objects (`std::map` by default; will be used
1295in @ref object_t)
1296@tparam ArrayType type for JSON arrays (`std::vector` by default; will be used
1297in @ref array_t)
1298@tparam StringType type for JSON strings and object keys (`std::string` by
1299default; will be used in @ref string_t)
1300@tparam BooleanType type for JSON booleans (`bool` by default; will be used
1301in @ref boolean_t)
1302@tparam NumberIntegerType type for JSON integer numbers (`int64_t` by
1303default; will be used in @ref number_integer_t)
1304@tparam NumberUnsignedType type for JSON unsigned integer numbers (@c
1305`uint64_t` by default; will be used in @ref number_unsigned_t)
1306@tparam NumberFloatType type for JSON floating-point numbers (`double` by
1307default; will be used in @ref number_float_t)
1308@tparam AllocatorType type of the allocator to use (`std::allocator` by
1309default)
1310@tparam JSONSerializer the serializer to resolve internal calls to `to_json()`
1311and `from_json()` (@ref adl_serializer by default)
1312
1313@requirement The class satisfies the following concept requirements:
1314- Basic
1315 - [DefaultConstructible](http://en.cppreference.com/w/cpp/concept/DefaultConstructible):
1316 JSON values can be default constructed. The result will be a JSON null
1317 value.
1318 - [MoveConstructible](http://en.cppreference.com/w/cpp/concept/MoveConstructible):
1319 A JSON value can be constructed from an rvalue argument.
1320 - [CopyConstructible](http://en.cppreference.com/w/cpp/concept/CopyConstructible):
1321 A JSON value can be copy-constructed from an lvalue expression.
1322 - [MoveAssignable](http://en.cppreference.com/w/cpp/concept/MoveAssignable):
1323 A JSON value van be assigned from an rvalue argument.
1324 - [CopyAssignable](http://en.cppreference.com/w/cpp/concept/CopyAssignable):
1325 A JSON value can be copy-assigned from an lvalue expression.
1326 - [Destructible](http://en.cppreference.com/w/cpp/concept/Destructible):
1327 JSON values can be destructed.
1328- Layout
1329 - [StandardLayoutType](http://en.cppreference.com/w/cpp/concept/StandardLayoutType):
1330 JSON values have
1331 [standard layout](http://en.cppreference.com/w/cpp/language/data_members#Standard_layout):
1332 All non-static data members are private and standard layout types, the
1333 class has no virtual functions or (virtual) base classes.
1334- Library-wide
1335 - [EqualityComparable](http://en.cppreference.com/w/cpp/concept/EqualityComparable):
1336 JSON values can be compared with `==`, see @ref
1337 operator==(const_reference,const_reference).
1338 - [LessThanComparable](http://en.cppreference.com/w/cpp/concept/LessThanComparable):
1339 JSON values can be compared with `<`, see @ref
1340 operator<(const_reference,const_reference).
1341 - [Swappable](http://en.cppreference.com/w/cpp/concept/Swappable):
1342 Any JSON lvalue or rvalue of can be swapped with any lvalue or rvalue of
1343 other compatible types, using unqualified function call @ref swap().
1344 - [NullablePointer](http://en.cppreference.com/w/cpp/concept/NullablePointer):
1345 JSON values can be compared against `std::nullptr_t` objects which are used
1346 to model the `null` value.
1347- Container
1348 - [Container](http://en.cppreference.com/w/cpp/concept/Container):
1349 JSON values can be used like STL containers and provide iterator access.
1350 - [ReversibleContainer](http://en.cppreference.com/w/cpp/concept/ReversibleContainer);
1351 JSON values can be used like STL containers and provide reverse iterator
1352 access.
1353
1354@invariant The member variables @a m_value and @a m_type have the following
1355relationship:
1356- If `m_type == value_t::object`, then `m_value.object != nullptr`.
1357- If `m_type == value_t::array`, then `m_value.array != nullptr`.
1358- If `m_type == value_t::string`, then `m_value.string != nullptr`.
1359The invariants are checked by member function assert_invariant().
1360
1361@internal
1362@note ObjectType trick from http://stackoverflow.com/a/9860911
1363@endinternal
1364
1365@see [RFC 7159: The JavaScript Object Notation (JSON) Data Interchange
1366Format](http://rfc7159.net/rfc7159)
1367
1368@since version 1.0.0
1369
1370@nosubgrouping
1371*/
1372template <
1373 template<typename U, typename V, typename... Args> class ObjectType = std::map,
1374 template<typename U, typename... Args> class ArrayType = std::vector,
1375 class StringType = std::string,
1376 class BooleanType = bool,
1377 class NumberIntegerType = std::int64_t,
1378 class NumberUnsignedType = std::uint64_t,
1379 class NumberFloatType = double,
1380 template<typename U> class AllocatorType = std::allocator,
1381 template<typename T, typename SFINAE = void> class JSONSerializer = adl_serializer
1382 >
1383class basic_json
1384{
1385 private:
1386 template<detail::value_t> friend struct detail::external_constructor;
1387 /// workaround type for MSVC
1388 using basic_json_t = basic_json<ObjectType, ArrayType, StringType,
1389 BooleanType, NumberIntegerType, NumberUnsignedType, NumberFloatType,
1390 AllocatorType, JSONSerializer>;
1391
1392 public:
1393 using value_t = detail::value_t;
1394 // forward declarations
1395 template<typename U> class iter_impl;
1396 template<typename Base> class json_reverse_iterator;
1397 class json_pointer;
1398 template<typename T, typename SFINAE>
1399 using json_serializer = JSONSerializer<T, SFINAE>;
1400
1401
1402 ////////////////
1403 // exceptions //
1404 ////////////////
1405
1406 /// @name exceptions
1407 /// Classes to implement user-defined exceptions.
1408 /// @{
1409
1410 /// @copydoc detail::exception
1411 using exception = detail::exception;
1412 /// @copydoc detail::parse_error
1413 using parse_error = detail::parse_error;
1414 /// @copydoc detail::invalid_iterator
1415 using invalid_iterator = detail::invalid_iterator;
1416 /// @copydoc detail::type_error
1417 using type_error = detail::type_error;
1418 /// @copydoc detail::out_of_range
1419 using out_of_range = detail::out_of_range;
1420 /// @copydoc detail::other_error
1421 using other_error = detail::other_error;
1422
1423 /// @}
1424
1425
1426 /////////////////////
1427 // container types //
1428 /////////////////////
1429
1430 /// @name container types
1431 /// The canonic container types to use @ref basic_json like any other STL
1432 /// container.
1433 /// @{
1434
1435 /// the type of elements in a basic_json container
1436 using value_type = basic_json;
1437
1438 /// the type of an element reference
1439 using reference = value_type&;
1440 /// the type of an element const reference
1441 using const_reference = const value_type&;
1442
1443 /// a type to represent differences between iterators
1444 using difference_type = std::ptrdiff_t;
1445 /// a type to represent container sizes
1446 using size_type = std::size_t;
1447
1448 /// the allocator type
1449 using allocator_type = AllocatorType<basic_json>;
1450
1451 /// the type of an element pointer
1452 using pointer = typename std::allocator_traits<allocator_type>::pointer;
1453 /// the type of an element const pointer
1454 using const_pointer = typename std::allocator_traits<allocator_type>::const_pointer;
1455
1456 /// an iterator for a basic_json container
1457 using iterator = iter_impl<basic_json>;
1458 /// a const iterator for a basic_json container
1459 using const_iterator = iter_impl<const basic_json>;
1460 /// a reverse iterator for a basic_json container
1461 using reverse_iterator = json_reverse_iterator<typename basic_json::iterator>;
1462 /// a const reverse iterator for a basic_json container
1463 using const_reverse_iterator = json_reverse_iterator<typename basic_json::const_iterator>;
1464
1465 /// @}
1466
1467
1468 /*!
1469 @brief returns the allocator associated with the container
1470 */
1471 static allocator_type get_allocator()
1472 {
1473 return allocator_type();
1474 }
1475
1476 /*!
1477 @brief returns version information on the library
1478
1479 This function returns a JSON object with information about the library,
1480 including the version number and information on the platform and compiler.
1481
1482 @return JSON object holding version information
1483 key | description
1484 ----------- | ---------------
1485 `compiler` | Information on the used compiler. It is an object with the following keys: `c++` (the used C++ standard), `family` (the compiler family; possible values are `clang`, `icc`, `gcc`, `ilecpp`, `msvc`, `pgcpp`, `sunpro`, and `unknown`), and `version` (the compiler version).
1486 `copyright` | The copyright line for the library as string.
1487 `name` | The name of the library as string.
1488 `platform` | The used platform as string. Possible values are `win32`, `linux`, `apple`, `unix`, and `unknown`.
1489 `url` | The URL of the project as string.
1490 `version` | The version of the library. It is an object with the following keys: `major`, `minor`, and `patch` as defined by [Semantic Versioning](http://semver.org), and `string` (the version string).
1491
1492 @liveexample{The following code shows an example output of the `meta()`
1493 function.,meta}
1494
1495 @complexity Constant.
1496
1497 @since 2.1.0
1498 */
1499 static basic_json meta()
1500 {
1501 basic_json result;
1502
1503 result["copyright"] = "(C) 2013-2017 Niels Lohmann";
1504 result["name"] = "JSON for Modern C++";
1505 result["url"] = "https://github.com/nlohmann/json";
1506 result["version"] =
1507 {
1508 {"string", "2.1.1"}, {"major", 2}, {"minor", 1}, {"patch", 1}
1509 };
1510
1511#ifdef _WIN32
1512 result["platform"] = "win32";
1513#elif defined __linux__
1514 result["platform"] = "linux";
1515#elif defined __APPLE__
1516 result["platform"] = "apple";
1517#elif defined __unix__
1518 result["platform"] = "unix";
1519#else
1520 result["platform"] = "unknown";
1521#endif
1522
1523#if defined(__clang__)
1524 result["compiler"] = {{"family", "clang"}, {"version", __clang_version__}};
1525#elif defined(__ICC) || defined(__INTEL_COMPILER)
1526 result["compiler"] = {{"family", "icc"}, {"version", __INTEL_COMPILER}};
1527#elif defined(__GNUC__) || defined(__GNUG__)
1528 result["compiler"] = {{"family", "gcc"}, {"version", std::to_string(__GNUC__) + "." + std::to_string(__GNUC_MINOR__) + "." + std::to_string(__GNUC_PATCHLEVEL__)}};
1529#elif defined(__HP_cc) || defined(__HP_aCC)
1530 result["compiler"] = "hp"
1531#elif defined(__IBMCPP__)
1532 result["compiler"] = {{"family", "ilecpp"}, {"version", __IBMCPP__}};
1533#elif defined(_MSC_VER)
1534 result["compiler"] = {{"family", "msvc"}, {"version", _MSC_VER}};
1535#elif defined(__PGI)
1536 result["compiler"] = {{"family", "pgcpp"}, {"version", __PGI}};
1537#elif defined(__SUNPRO_CC)
1538 result["compiler"] = {{"family", "sunpro"}, {"version", __SUNPRO_CC}};
1539#else
1540 result["compiler"] = {{"family", "unknown"}, {"version", "unknown"}};
1541#endif
1542
1543#ifdef __cplusplus
1544 result["compiler"]["c++"] = std::to_string(__cplusplus);
1545#else
1546 result["compiler"]["c++"] = "unknown";
1547#endif
1548 return result;
1549 }
1550
1551
1552 ///////////////////////////
1553 // JSON value data types //
1554 ///////////////////////////
1555
1556 /// @name JSON value data types
1557 /// The data types to store a JSON value. These types are derived from
1558 /// the template arguments passed to class @ref basic_json.
1559 /// @{
1560
1561 /*!
1562 @brief a type for an object
1563
1564 [RFC 7159](http://rfc7159.net/rfc7159) describes JSON objects as follows:
1565 > An object is an unordered collection of zero or more name/value pairs,
1566 > where a name is a string and a value is a string, number, boolean, null,
1567 > object, or array.
1568
1569 To store objects in C++, a type is defined by the template parameters
1570 described below.
1571
1572 @tparam ObjectType the container to store objects (e.g., `std::map` or
1573 `std::unordered_map`)
1574 @tparam StringType the type of the keys or names (e.g., `std::string`).
1575 The comparison function `std::less<StringType>` is used to order elements
1576 inside the container.
1577 @tparam AllocatorType the allocator to use for objects (e.g.,
1578 `std::allocator`)
1579
1580 #### Default type
1581
1582 With the default values for @a ObjectType (`std::map`), @a StringType
1583 (`std::string`), and @a AllocatorType (`std::allocator`), the default
1584 value for @a object_t is:
1585
1586 @code {.cpp}
1587 std::map<
1588 std::string, // key_type
1589 basic_json, // value_type
1590 std::less<std::string>, // key_compare
1591 std::allocator<std::pair<const std::string, basic_json>> // allocator_type
1592 >
1593 @endcode
1594
1595 #### Behavior
1596
1597 The choice of @a object_t influences the behavior of the JSON class. With
1598 the default type, objects have the following behavior:
1599
1600 - When all names are unique, objects will be interoperable in the sense
1601 that all software implementations receiving that object will agree on
1602 the name-value mappings.
1603 - When the names within an object are not unique, later stored name/value
1604 pairs overwrite previously stored name/value pairs, leaving the used
1605 names unique. For instance, `{"key": 1}` and `{"key": 2, "key": 1}` will
1606 be treated as equal and both stored as `{"key": 1}`.
1607 - Internally, name/value pairs are stored in lexicographical order of the
1608 names. Objects will also be serialized (see @ref dump) in this order.
1609 For instance, `{"b": 1, "a": 2}` and `{"a": 2, "b": 1}` will be stored
1610 and serialized as `{"a": 2, "b": 1}`.
1611 - When comparing objects, the order of the name/value pairs is irrelevant.
1612 This makes objects interoperable in the sense that they will not be
1613 affected by these differences. For instance, `{"b": 1, "a": 2}` and
1614 `{"a": 2, "b": 1}` will be treated as equal.
1615
1616 #### Limits
1617
1618 [RFC 7159](http://rfc7159.net/rfc7159) specifies:
1619 > An implementation may set limits on the maximum depth of nesting.
1620
1621 In this class, the object's limit of nesting is not constraint explicitly.
1622 However, a maximum depth of nesting may be introduced by the compiler or
1623 runtime environment. A theoretical limit can be queried by calling the
1624 @ref max_size function of a JSON object.
1625
1626 #### Storage
1627
1628 Objects are stored as pointers in a @ref basic_json type. That is, for any
1629 access to object values, a pointer of type `object_t*` must be
1630 dereferenced.
1631
1632 @sa @ref array_t -- type for an array value
1633
1634 @since version 1.0.0
1635
1636 @note The order name/value pairs are added to the object is *not*
1637 preserved by the library. Therefore, iterating an object may return
1638 name/value pairs in a different order than they were originally stored. In
1639 fact, keys will be traversed in alphabetical order as `std::map` with
1640 `std::less` is used by default. Please note this behavior conforms to [RFC
1641 7159](http://rfc7159.net/rfc7159), because any order implements the
1642 specified "unordered" nature of JSON objects.
1643 */
1644 using object_t = ObjectType<StringType,
1645 basic_json,
1646 std::less<StringType>,
1647 AllocatorType<std::pair<const StringType,
1648 basic_json>>>;
1649
1650 /*!
1651 @brief a type for an array
1652
1653 [RFC 7159](http://rfc7159.net/rfc7159) describes JSON arrays as follows:
1654 > An array is an ordered sequence of zero or more values.
1655
1656 To store objects in C++, a type is defined by the template parameters
1657 explained below.
1658
1659 @tparam ArrayType container type to store arrays (e.g., `std::vector` or
1660 `std::list`)
1661 @tparam AllocatorType allocator to use for arrays (e.g., `std::allocator`)
1662
1663 #### Default type
1664
1665 With the default values for @a ArrayType (`std::vector`) and @a
1666 AllocatorType (`std::allocator`), the default value for @a array_t is:
1667
1668 @code {.cpp}
1669 std::vector<
1670 basic_json, // value_type
1671 std::allocator<basic_json> // allocator_type
1672 >
1673 @endcode
1674
1675 #### Limits
1676
1677 [RFC 7159](http://rfc7159.net/rfc7159) specifies:
1678 > An implementation may set limits on the maximum depth of nesting.
1679
1680 In this class, the array's limit of nesting is not constraint explicitly.
1681 However, a maximum depth of nesting may be introduced by the compiler or
1682 runtime environment. A theoretical limit can be queried by calling the
1683 @ref max_size function of a JSON array.
1684
1685 #### Storage
1686
1687 Arrays are stored as pointers in a @ref basic_json type. That is, for any
1688 access to array values, a pointer of type `array_t*` must be dereferenced.
1689
1690 @sa @ref object_t -- type for an object value
1691
1692 @since version 1.0.0
1693 */
1694 using array_t = ArrayType<basic_json, AllocatorType<basic_json>>;
1695
1696 /*!
1697 @brief a type for a string
1698
1699 [RFC 7159](http://rfc7159.net/rfc7159) describes JSON strings as follows:
1700 > A string is a sequence of zero or more Unicode characters.
1701
1702 To store objects in C++, a type is defined by the template parameter
1703 described below. Unicode values are split by the JSON class into
1704 byte-sized characters during deserialization.
1705
1706 @tparam StringType the container to store strings (e.g., `std::string`).
1707 Note this container is used for keys/names in objects, see @ref object_t.
1708
1709 #### Default type
1710
1711 With the default values for @a StringType (`std::string`), the default
1712 value for @a string_t is:
1713
1714 @code {.cpp}
1715 std::string
1716 @endcode
1717
1718 #### Encoding
1719
1720 Strings are stored in UTF-8 encoding. Therefore, functions like
1721 `std::string::size()` or `std::string::length()` return the number of
1722 bytes in the string rather than the number of characters or glyphs.
1723
1724 #### String comparison
1725
1726 [RFC 7159](http://rfc7159.net/rfc7159) states:
1727 > Software implementations are typically required to test names of object
1728 > members for equality. Implementations that transform the textual
1729 > representation into sequences of Unicode code units and then perform the
1730 > comparison numerically, code unit by code unit, are interoperable in the
1731 > sense that implementations will agree in all cases on equality or
1732 > inequality of two strings. For example, implementations that compare
1733 > strings with escaped characters unconverted may incorrectly find that
1734 > `"a\\b"` and `"a\u005Cb"` are not equal.
1735
1736 This implementation is interoperable as it does compare strings code unit
1737 by code unit.
1738
1739 #### Storage
1740
1741 String values are stored as pointers in a @ref basic_json type. That is,
1742 for any access to string values, a pointer of type `string_t*` must be
1743 dereferenced.
1744
1745 @since version 1.0.0
1746 */
1747 using string_t = StringType;
1748
1749 /*!
1750 @brief a type for a boolean
1751
1752 [RFC 7159](http://rfc7159.net/rfc7159) implicitly describes a boolean as a
1753 type which differentiates the two literals `true` and `false`.
1754
1755 To store objects in C++, a type is defined by the template parameter @a
1756 BooleanType which chooses the type to use.
1757
1758 #### Default type
1759
1760 With the default values for @a BooleanType (`bool`), the default value for
1761 @a boolean_t is:
1762
1763 @code {.cpp}
1764 bool
1765 @endcode
1766
1767 #### Storage
1768
1769 Boolean values are stored directly inside a @ref basic_json type.
1770
1771 @since version 1.0.0
1772 */
1773 using boolean_t = BooleanType;
1774
1775 /*!
1776 @brief a type for a number (integer)
1777
1778 [RFC 7159](http://rfc7159.net/rfc7159) describes numbers as follows:
1779 > The representation of numbers is similar to that used in most
1780 > programming languages. A number is represented in base 10 using decimal
1781 > digits. It contains an integer component that may be prefixed with an
1782 > optional minus sign, which may be followed by a fraction part and/or an
1783 > exponent part. Leading zeros are not allowed. (...) Numeric values that
1784 > cannot be represented in the grammar below (such as Infinity and NaN)
1785 > are not permitted.
1786
1787 This description includes both integer and floating-point numbers.
1788 However, C++ allows more precise storage if it is known whether the number
1789 is a signed integer, an unsigned integer or a floating-point number.
1790 Therefore, three different types, @ref number_integer_t, @ref
1791 number_unsigned_t and @ref number_float_t are used.
1792
1793 To store integer numbers in C++, a type is defined by the template
1794 parameter @a NumberIntegerType which chooses the type to use.
1795
1796 #### Default type
1797
1798 With the default values for @a NumberIntegerType (`int64_t`), the default
1799 value for @a number_integer_t is:
1800
1801 @code {.cpp}
1802 int64_t
1803 @endcode
1804
1805 #### Default behavior
1806
1807 - The restrictions about leading zeros is not enforced in C++. Instead,
1808 leading zeros in integer literals lead to an interpretation as octal
1809 number. Internally, the value will be stored as decimal number. For
1810 instance, the C++ integer literal `010` will be serialized to `8`.
1811 During deserialization, leading zeros yield an error.
1812 - Not-a-number (NaN) values will be serialized to `null`.
1813
1814 #### Limits
1815
1816 [RFC 7159](http://rfc7159.net/rfc7159) specifies:
1817 > An implementation may set limits on the range and precision of numbers.
1818
1819 When the default type is used, the maximal integer number that can be
1820 stored is `9223372036854775807` (INT64_MAX) and the minimal integer number
1821 that can be stored is `-9223372036854775808` (INT64_MIN). Integer numbers
1822 that are out of range will yield over/underflow when used in a
1823 constructor. During deserialization, too large or small integer numbers
1824 will be automatically be stored as @ref number_unsigned_t or @ref
1825 number_float_t.
1826
1827 [RFC 7159](http://rfc7159.net/rfc7159) further states:
1828 > Note that when such software is used, numbers that are integers and are
1829 > in the range \f$[-2^{53}+1, 2^{53}-1]\f$ are interoperable in the sense
1830 > that implementations will agree exactly on their numeric values.
1831
1832 As this range is a subrange of the exactly supported range [INT64_MIN,
1833 INT64_MAX], this class's integer type is interoperable.
1834
1835 #### Storage
1836
1837 Integer number values are stored directly inside a @ref basic_json type.
1838
1839 @sa @ref number_float_t -- type for number values (floating-point)
1840
1841 @sa @ref number_unsigned_t -- type for number values (unsigned integer)
1842
1843 @since version 1.0.0
1844 */
1845 using number_integer_t = NumberIntegerType;
1846
1847 /*!
1848 @brief a type for a number (unsigned)
1849
1850 [RFC 7159](http://rfc7159.net/rfc7159) describes numbers as follows:
1851 > The representation of numbers is similar to that used in most
1852 > programming languages. A number is represented in base 10 using decimal
1853 > digits. It contains an integer component that may be prefixed with an
1854 > optional minus sign, which may be followed by a fraction part and/or an
1855 > exponent part. Leading zeros are not allowed. (...) Numeric values that
1856 > cannot be represented in the grammar below (such as Infinity and NaN)
1857 > are not permitted.
1858
1859 This description includes both integer and floating-point numbers.
1860 However, C++ allows more precise storage if it is known whether the number
1861 is a signed integer, an unsigned integer or a floating-point number.
1862 Therefore, three different types, @ref number_integer_t, @ref
1863 number_unsigned_t and @ref number_float_t are used.
1864
1865 To store unsigned integer numbers in C++, a type is defined by the
1866 template parameter @a NumberUnsignedType which chooses the type to use.
1867
1868 #### Default type
1869
1870 With the default values for @a NumberUnsignedType (`uint64_t`), the
1871 default value for @a number_unsigned_t is:
1872
1873 @code {.cpp}
1874 uint64_t
1875 @endcode
1876
1877 #### Default behavior
1878
1879 - The restrictions about leading zeros is not enforced in C++. Instead,
1880 leading zeros in integer literals lead to an interpretation as octal
1881 number. Internally, the value will be stored as decimal number. For
1882 instance, the C++ integer literal `010` will be serialized to `8`.
1883 During deserialization, leading zeros yield an error.
1884 - Not-a-number (NaN) values will be serialized to `null`.
1885
1886 #### Limits
1887
1888 [RFC 7159](http://rfc7159.net/rfc7159) specifies:
1889 > An implementation may set limits on the range and precision of numbers.
1890
1891 When the default type is used, the maximal integer number that can be
1892 stored is `18446744073709551615` (UINT64_MAX) and the minimal integer
1893 number that can be stored is `0`. Integer numbers that are out of range
1894 will yield over/underflow when used in a constructor. During
1895 deserialization, too large or small integer numbers will be automatically
1896 be stored as @ref number_integer_t or @ref number_float_t.
1897
1898 [RFC 7159](http://rfc7159.net/rfc7159) further states:
1899 > Note that when such software is used, numbers that are integers and are
1900 > in the range \f$[-2^{53}+1, 2^{53}-1]\f$ are interoperable in the sense
1901 > that implementations will agree exactly on their numeric values.
1902
1903 As this range is a subrange (when considered in conjunction with the
1904 number_integer_t type) of the exactly supported range [0, UINT64_MAX],
1905 this class's integer type is interoperable.
1906
1907 #### Storage
1908
1909 Integer number values are stored directly inside a @ref basic_json type.
1910
1911 @sa @ref number_float_t -- type for number values (floating-point)
1912 @sa @ref number_integer_t -- type for number values (integer)
1913
1914 @since version 2.0.0
1915 */
1916 using number_unsigned_t = NumberUnsignedType;
1917
1918 /*!
1919 @brief a type for a number (floating-point)
1920
1921 [RFC 7159](http://rfc7159.net/rfc7159) describes numbers as follows:
1922 > The representation of numbers is similar to that used in most
1923 > programming languages. A number is represented in base 10 using decimal
1924 > digits. It contains an integer component that may be prefixed with an
1925 > optional minus sign, which may be followed by a fraction part and/or an
1926 > exponent part. Leading zeros are not allowed. (...) Numeric values that
1927 > cannot be represented in the grammar below (such as Infinity and NaN)
1928 > are not permitted.
1929
1930 This description includes both integer and floating-point numbers.
1931 However, C++ allows more precise storage if it is known whether the number
1932 is a signed integer, an unsigned integer or a floating-point number.
1933 Therefore, three different types, @ref number_integer_t, @ref
1934 number_unsigned_t and @ref number_float_t are used.
1935
1936 To store floating-point numbers in C++, a type is defined by the template
1937 parameter @a NumberFloatType which chooses the type to use.
1938
1939 #### Default type
1940
1941 With the default values for @a NumberFloatType (`double`), the default
1942 value for @a number_float_t is:
1943
1944 @code {.cpp}
1945 double
1946 @endcode
1947
1948 #### Default behavior
1949
1950 - The restrictions about leading zeros is not enforced in C++. Instead,
1951 leading zeros in floating-point literals will be ignored. Internally,
1952 the value will be stored as decimal number. For instance, the C++
1953 floating-point literal `01.2` will be serialized to `1.2`. During
1954 deserialization, leading zeros yield an error.
1955 - Not-a-number (NaN) values will be serialized to `null`.
1956
1957 #### Limits
1958
1959 [RFC 7159](http://rfc7159.net/rfc7159) states:
1960 > This specification allows implementations to set limits on the range and
1961 > precision of numbers accepted. Since software that implements IEEE
1962 > 754-2008 binary64 (double precision) numbers is generally available and
1963 > widely used, good interoperability can be achieved by implementations
1964 > that expect no more precision or range than these provide, in the sense
1965 > that implementations will approximate JSON numbers within the expected
1966 > precision.
1967
1968 This implementation does exactly follow this approach, as it uses double
1969 precision floating-point numbers. Note values smaller than
1970 `-1.79769313486232e+308` and values greater than `1.79769313486232e+308`
1971 will be stored as NaN internally and be serialized to `null`.
1972
1973 #### Storage
1974
1975 Floating-point number values are stored directly inside a @ref basic_json
1976 type.
1977
1978 @sa @ref number_integer_t -- type for number values (integer)
1979
1980 @sa @ref number_unsigned_t -- type for number values (unsigned integer)
1981
1982 @since version 1.0.0
1983 */
1984 using number_float_t = NumberFloatType;
1985
1986 /// @}
1987
1988 private:
1989
1990 /// helper for exception-safe object creation
1991 template<typename T, typename... Args>
1992 static T* create(Args&& ... args)
1993 {
1994 AllocatorType<T> alloc;
1995 auto deleter = [&](T * object)
1996 {
1997 alloc.deallocate(object, 1);
1998 };
1999 std::unique_ptr<T, decltype(deleter)> object(alloc.allocate(1), deleter);
2000 alloc.construct(object.get(), std::forward<Args>(args)...);
2001 assert(object != nullptr);
2002 return object.release();
2003 }
2004
2005 ////////////////////////
2006 // JSON value storage //
2007 ////////////////////////
2008
2009 /*!
2010 @brief a JSON value
2011
2012 The actual storage for a JSON value of the @ref basic_json class. This
2013 union combines the different storage types for the JSON value types
2014 defined in @ref value_t.
2015
2016 JSON type | value_t type | used type
2017 --------- | --------------- | ------------------------
2018 object | object | pointer to @ref object_t
2019 array | array | pointer to @ref array_t
2020 string | string | pointer to @ref string_t
2021 boolean | boolean | @ref boolean_t
2022 number | number_integer | @ref number_integer_t
2023 number | number_unsigned | @ref number_unsigned_t
2024 number | number_float | @ref number_float_t
2025 null | null | *no value is stored*
2026
2027 @note Variable-length types (objects, arrays, and strings) are stored as
2028 pointers. The size of the union should not exceed 64 bits if the default
2029 value types are used.
2030
2031 @since version 1.0.0
2032 */
2033 union json_value
2034 {
2035 /// object (stored with pointer to save storage)
2036 object_t* object;
2037 /// array (stored with pointer to save storage)
2038 array_t* array;
2039 /// string (stored with pointer to save storage)
2040 string_t* string;
2041 /// boolean
2042 boolean_t boolean;
2043 /// number (integer)
2044 number_integer_t number_integer;
2045 /// number (unsigned integer)
2046 number_unsigned_t number_unsigned;
2047 /// number (floating-point)
2048 number_float_t number_float;
2049
2050 /// default constructor (for null values)
2051 json_value() = default;
2052 /// constructor for booleans
2053 json_value(boolean_t v) noexcept : boolean(v) {}
2054 /// constructor for numbers (integer)
2055 json_value(number_integer_t v) noexcept : number_integer(v) {}
2056 /// constructor for numbers (unsigned)
2057 json_value(number_unsigned_t v) noexcept : number_unsigned(v) {}
2058 /// constructor for numbers (floating-point)
2059 json_value(number_float_t v) noexcept : number_float(v) {}
2060 /// constructor for empty values of a given type
2061 json_value(value_t t)
2062 {
2063 switch (t)
2064 {
2065 case value_t::object:
2066 {
2067 object = create<object_t>();
2068 break;
2069 }
2070
2071 case value_t::array:
2072 {
2073 array = create<array_t>();
2074 break;
2075 }
2076
2077 case value_t::string:
2078 {
2079 string = create<string_t>("");
2080 break;
2081 }
2082
2083 case value_t::boolean:
2084 {
2085 boolean = boolean_t(false);
2086 break;
2087 }
2088
2089 case value_t::number_integer:
2090 {
2091 number_integer = number_integer_t(0);
2092 break;
2093 }
2094
2095 case value_t::number_unsigned:
2096 {
2097 number_unsigned = number_unsigned_t(0);
2098 break;
2099 }
2100
2101 case value_t::number_float:
2102 {
2103 number_float = number_float_t(0.0);
2104 break;
2105 }
2106
2107 case value_t::null:
2108 {
2109 break;
2110 }
2111
2112 default:
2113 {
2114 if (JSON_UNLIKELY(t == value_t::null))
2115 {
2116 JSON_THROW(other_error::create(500, "961c151d2e87f2686a955a9be24d316f1362bf21 2.1.1")); // LCOV_EXCL_LINE
2117 }
2118 break;
2119 }
2120 }
2121 }
2122
2123 /// constructor for strings
2124 json_value(const string_t& value)
2125 {
2126 string = create<string_t>(value);
2127 }
2128
2129 /// constructor for objects
2130 json_value(const object_t& value)
2131 {
2132 object = create<object_t>(value);
2133 }
2134
2135 /// constructor for arrays
2136 json_value(const array_t& value)
2137 {
2138 array = create<array_t>(value);
2139 }
2140 };
2141
2142 /*!
2143 @brief checks the class invariants
2144
2145 This function asserts the class invariants. It needs to be called at the
2146 end of every constructor to make sure that created objects respect the
2147 invariant. Furthermore, it has to be called each time the type of a JSON
2148 value is changed, because the invariant expresses a relationship between
2149 @a m_type and @a m_value.
2150 */
2151 void assert_invariant() const
2152 {
2153 assert(m_type != value_t::object or m_value.object != nullptr);
2154 assert(m_type != value_t::array or m_value.array != nullptr);
2155 assert(m_type != value_t::string or m_value.string != nullptr);
2156 }
2157
2158 public:
2159 //////////////////////////
2160 // JSON parser callback //
2161 //////////////////////////
2162
2163 /*!
2164 @brief JSON callback events
2165
2166 This enumeration lists the parser events that can trigger calling a
2167 callback function of type @ref parser_callback_t during parsing.
2168
2169 @image html callback_events.png "Example when certain parse events are triggered"
2170
2171 @since version 1.0.0
2172 */
2173 enum class parse_event_t : uint8_t
2174 {
2175 /// the parser read `{` and started to process a JSON object
2176 object_start,
2177 /// the parser read `}` and finished processing a JSON object
2178 object_end,
2179 /// the parser read `[` and started to process a JSON array
2180 array_start,
2181 /// the parser read `]` and finished processing a JSON array
2182 array_end,
2183 /// the parser read a key of a value in an object
2184 key,
2185 /// the parser finished reading a JSON value
2186 value
2187 };
2188
2189 /*!
2190 @brief per-element parser callback type
2191
2192 With a parser callback function, the result of parsing a JSON text can be
2193 influenced. When passed to @ref parse(std::istream&, const
2194 parser_callback_t) or @ref parse(const CharT, const parser_callback_t),
2195 it is called on certain events (passed as @ref parse_event_t via parameter
2196 @a event) with a set recursion depth @a depth and context JSON value
2197 @a parsed. The return value of the callback function is a boolean
2198 indicating whether the element that emitted the callback shall be kept or
2199 not.
2200
2201 We distinguish six scenarios (determined by the event type) in which the
2202 callback function can be called. The following table describes the values
2203 of the parameters @a depth, @a event, and @a parsed.
2204
2205 parameter @a event | description | parameter @a depth | parameter @a parsed
2206 ------------------ | ----------- | ------------------ | -------------------
2207 parse_event_t::object_start | the parser read `{` and started to process a JSON object | depth of the parent of the JSON object | a JSON value with type discarded
2208 parse_event_t::key | the parser read a key of a value in an object | depth of the currently parsed JSON object | a JSON string containing the key
2209 parse_event_t::object_end | the parser read `}` and finished processing a JSON object | depth of the parent of the JSON object | the parsed JSON object
2210 parse_event_t::array_start | the parser read `[` and started to process a JSON array | depth of the parent of the JSON array | a JSON value with type discarded
2211 parse_event_t::array_end | the parser read `]` and finished processing a JSON array | depth of the parent of the JSON array | the parsed JSON array
2212 parse_event_t::value | the parser finished reading a JSON value | depth of the value | the parsed JSON value
2213
2214 @image html callback_events.png "Example when certain parse events are triggered"
2215
2216 Discarding a value (i.e., returning `false`) has different effects
2217 depending on the context in which function was called:
2218
2219 - Discarded values in structured types are skipped. That is, the parser
2220 will behave as if the discarded value was never read.
2221 - In case a value outside a structured type is skipped, it is replaced
2222 with `null`. This case happens if the top-level element is skipped.
2223
2224 @param[in] depth the depth of the recursion during parsing
2225
2226 @param[in] event an event of type parse_event_t indicating the context in
2227 the callback function has been called
2228
2229 @param[in,out] parsed the current intermediate parse result; note that
2230 writing to this value has no effect for parse_event_t::key events
2231
2232 @return Whether the JSON value which called the function during parsing
2233 should be kept (`true`) or not (`false`). In the latter case, it is either
2234 skipped completely or replaced by an empty discarded object.
2235
2236 @sa @ref parse(std::istream&, parser_callback_t) or
2237 @ref parse(const CharT, const parser_callback_t) for examples
2238
2239 @since version 1.0.0
2240 */
2241 using parser_callback_t = std::function<bool(int depth,
2242 parse_event_t event,
2243 basic_json& parsed)>;
2244
2245
2246 //////////////////
2247 // constructors //
2248 //////////////////
2249
2250 /// @name constructors and destructors
2251 /// Constructors of class @ref basic_json, copy/move constructor, copy
2252 /// assignment, static functions creating objects, and the destructor.
2253 /// @{
2254
2255 /*!
2256 @brief create an empty value with a given type
2257
2258 Create an empty JSON value with a given type. The value will be default
2259 initialized with an empty value which depends on the type:
2260
2261 Value type | initial value
2262 ----------- | -------------
2263 null | `null`
2264 boolean | `false`
2265 string | `""`
2266 number | `0`
2267 object | `{}`
2268 array | `[]`
2269
2270 @param[in] v the type of the value to create
2271
2272 @complexity Constant.
2273
2274 @liveexample{The following code shows the constructor for different @ref
2275 value_t values,basic_json__value_t}
2276
2277 @since version 1.0.0
2278 */
2279 basic_json(const value_t v)
2280 : m_type(v), m_value(v)
2281 {
2282 assert_invariant();
2283 }
2284
2285 /*!
2286 @brief create a null object
2287
2288 Create a `null` JSON value. It either takes a null pointer as parameter
2289 (explicitly creating `null`) or no parameter (implicitly creating `null`).
2290 The passed null pointer itself is not read -- it is only used to choose
2291 the right constructor.
2292
2293 @complexity Constant.
2294
2295 @exceptionsafety No-throw guarantee: this constructor never throws
2296 exceptions.
2297
2298 @liveexample{The following code shows the constructor with and without a
2299 null pointer parameter.,basic_json__nullptr_t}
2300
2301 @since version 1.0.0
2302 */
2303 basic_json(std::nullptr_t = nullptr) noexcept
2304 : basic_json(value_t::null)
2305 {
2306 assert_invariant();
2307 }
2308
2309 /*!
2310 @brief create a JSON value
2311
2312 This is a "catch all" constructor for all compatible JSON types; that is,
2313 types for which a `to_json()` method exsits. The constructor forwards the
2314 parameter @a val to that method (to `json_serializer<U>::to_json` method
2315 with `U = uncvref_t<CompatibleType>`, to be exact).
2316
2317 Template type @a CompatibleType includes, but is not limited to, the
2318 following types:
2319 - **arrays**: @ref array_t and all kinds of compatible containers such as
2320 `std::vector`, `std::deque`, `std::list`, `std::forward_list`,
2321 `std::array`, `std::set`, `std::unordered_set`, `std::multiset`, and
2322 `unordered_multiset` with a `value_type` from which a @ref basic_json
2323 value can be constructed.
2324 - **objects**: @ref object_t and all kinds of compatible associative
2325 containers such as `std::map`, `std::unordered_map`, `std::multimap`,
2326 and `std::unordered_multimap` with a `key_type` compatible to
2327 @ref string_t and a `value_type` from which a @ref basic_json value can
2328 be constructed.
2329 - **strings**: @ref string_t, string literals, and all compatible string
2330 containers can be used.
2331 - **numbers**: @ref number_integer_t, @ref number_unsigned_t,
2332 @ref number_float_t, and all convertible number types such as `int`,
2333 `size_t`, `int64_t`, `float` or `double` can be used.
2334 - **boolean**: @ref boolean_t / `bool` can be used.
2335
2336 See the examples below.
2337
2338 @tparam CompatibleType a type such that:
2339 - @a CompatibleType is not derived from `std::istream`,
2340 - @a CompatibleType is not @ref basic_json (to avoid hijacking copy/move
2341 constructors),
2342 - @a CompatibleType is not a @ref basic_json nested type (e.g.,
2343 @ref json_pointer, @ref iterator, etc ...)
2344 - @ref @ref json_serializer<U> has a
2345 `to_json(basic_json_t&, CompatibleType&&)` method
2346
2347 @tparam U = `uncvref_t<CompatibleType>`
2348
2349 @param[in] val the value to be forwarded
2350
2351 @complexity Usually linear in the size of the passed @a val, also
2352 depending on the implementation of the called `to_json()`
2353 method.
2354
2355 @throw what `json_serializer<U>::to_json()` throws
2356
2357 @liveexample{The following code shows the constructor with several
2358 compatible types.,basic_json__CompatibleType}
2359
2360 @since version 2.1.0
2361 */
2362 template<typename CompatibleType, typename U = detail::uncvref_t<CompatibleType>,
2363 detail::enable_if_t<not std::is_base_of<std::istream, U>::value and
2364 not std::is_same<U, basic_json_t>::value and
2365 not detail::is_basic_json_nested_type<
2366 basic_json_t, U>::value and
2367 detail::has_to_json<basic_json, U>::value,
2368 int> = 0>
2369 basic_json(CompatibleType && val) noexcept(noexcept(JSONSerializer<U>::to_json(
2370 std::declval<basic_json_t&>(), std::forward<CompatibleType>(val))))
2371 {
2372 JSONSerializer<U>::to_json(*this, std::forward<CompatibleType>(val));
2373 assert_invariant();
2374 }
2375
2376 /*!
2377 @brief create a container (array or object) from an initializer list
2378
2379 Creates a JSON value of type array or object from the passed initializer
2380 list @a init. In case @a type_deduction is `true` (default), the type of
2381 the JSON value to be created is deducted from the initializer list @a init
2382 according to the following rules:
2383
2384 1. If the list is empty, an empty JSON object value `{}` is created.
2385 2. If the list consists of pairs whose first element is a string, a JSON
2386 object value is created where the first elements of the pairs are
2387 treated as keys and the second elements are as values.
2388 3. In all other cases, an array is created.
2389
2390 The rules aim to create the best fit between a C++ initializer list and
2391 JSON values. The rationale is as follows:
2392
2393 1. The empty initializer list is written as `{}` which is exactly an empty
2394 JSON object.
2395 2. C++ has now way of describing mapped types other than to list a list of
2396 pairs. As JSON requires that keys must be of type string, rule 2 is the
2397 weakest constraint one can pose on initializer lists to interpret them
2398 as an object.
2399 3. In all other cases, the initializer list could not be interpreted as
2400 JSON object type, so interpreting it as JSON array type is safe.
2401
2402 With the rules described above, the following JSON values cannot be
2403 expressed by an initializer list:
2404
2405 - the empty array (`[]`): use @ref array(std::initializer_list<basic_json>)
2406 with an empty initializer list in this case
2407 - arrays whose elements satisfy rule 2: use @ref
2408 array(std::initializer_list<basic_json>) with the same initializer list
2409 in this case
2410
2411 @note When used without parentheses around an empty initializer list, @ref
2412 basic_json() is called instead of this function, yielding the JSON null
2413 value.
2414
2415 @param[in] init initializer list with JSON values
2416
2417 @param[in] type_deduction internal parameter; when set to `true`, the type
2418 of the JSON value is deducted from the initializer list @a init; when set
2419 to `false`, the type provided via @a manual_type is forced. This mode is
2420 used by the functions @ref array(std::initializer_list<basic_json>) and
2421 @ref object(std::initializer_list<basic_json>).
2422
2423 @param[in] manual_type internal parameter; when @a type_deduction is set
2424 to `false`, the created JSON value will use the provided type (only @ref
2425 value_t::array and @ref value_t::object are valid); when @a type_deduction
2426 is set to `true`, this parameter has no effect
2427
2428 @throw type_error.301 if @a type_deduction is `false`, @a manual_type is
2429 `value_t::object`, but @a init contains an element which is not a pair
2430 whose first element is a string. In this case, the constructor could not
2431 create an object. If @a type_deduction would have be `true`, an array
2432 would have been created. See @ref object(std::initializer_list<basic_json>)
2433 for an example.
2434
2435 @complexity Linear in the size of the initializer list @a init.
2436
2437 @liveexample{The example below shows how JSON values are created from
2438 initializer lists.,basic_json__list_init_t}
2439
2440 @sa @ref array(std::initializer_list<basic_json>) -- create a JSON array
2441 value from an initializer list
2442 @sa @ref object(std::initializer_list<basic_json>) -- create a JSON object
2443 value from an initializer list
2444
2445 @since version 1.0.0
2446 */
2447 basic_json(std::initializer_list<basic_json> init,
2448 bool type_deduction = true,
2449 value_t manual_type = value_t::array)
2450 {
2451 // check if each element is an array with two elements whose first
2452 // element is a string
2453 bool is_an_object = std::all_of(init.begin(), init.end(),
2454 [](const basic_json & element)
2455 {
2456 return element.is_array() and element.size() == 2 and element[0].is_string();
2457 });
2458
2459 // adjust type if type deduction is not wanted
2460 if (not type_deduction)
2461 {
2462 // if array is wanted, do not create an object though possible
2463 if (manual_type == value_t::array)
2464 {
2465 is_an_object = false;
2466 }
2467
2468 // if object is wanted but impossible, throw an exception
2469 if (manual_type == value_t::object and not is_an_object)
2470 {
2471 JSON_THROW(type_error::create(301, "cannot create object from initializer list"));
2472 }
2473 }
2474
2475 if (is_an_object)
2476 {
2477 // the initializer list is a list of pairs -> create object
2478 m_type = value_t::object;
2479 m_value = value_t::object;
2480
2481 std::for_each(init.begin(), init.end(), [this](const basic_json & element)
2482 {
2483 m_value.object->emplace(*(element[0].m_value.string), element[1]);
2484 });
2485 }
2486 else
2487 {
2488 // the initializer list describes an array -> create array
2489 m_type = value_t::array;
2490 m_value.array = create<array_t>(init);
2491 }
2492
2493 assert_invariant();
2494 }
2495
2496 /*!
2497 @brief explicitly create an array from an initializer list
2498
2499 Creates a JSON array value from a given initializer list. That is, given a
2500 list of values `a, b, c`, creates the JSON value `[a, b, c]`. If the
2501 initializer list is empty, the empty array `[]` is created.
2502
2503 @note This function is only needed to express two edge cases that cannot
2504 be realized with the initializer list constructor (@ref
2505 basic_json(std::initializer_list<basic_json>, bool, value_t)). These cases
2506 are:
2507 1. creating an array whose elements are all pairs whose first element is a
2508 string -- in this case, the initializer list constructor would create an
2509 object, taking the first elements as keys
2510 2. creating an empty array -- passing the empty initializer list to the
2511 initializer list constructor yields an empty object
2512
2513 @param[in] init initializer list with JSON values to create an array from
2514 (optional)
2515
2516 @return JSON array value
2517
2518 @complexity Linear in the size of @a init.
2519
2520 @liveexample{The following code shows an example for the `array`
2521 function.,array}
2522
2523 @sa @ref basic_json(std::initializer_list<basic_json>, bool, value_t) --
2524 create a JSON value from an initializer list
2525 @sa @ref object(std::initializer_list<basic_json>) -- create a JSON object
2526 value from an initializer list
2527
2528 @since version 1.0.0
2529 */
2530 static basic_json array(std::initializer_list<basic_json> init =
2531 std::initializer_list<basic_json>())
2532 {
2533 return basic_json(init, false, value_t::array);
2534 }
2535
2536 /*!
2537 @brief explicitly create an object from an initializer list
2538
2539 Creates a JSON object value from a given initializer list. The initializer
2540 lists elements must be pairs, and their first elements must be strings. If
2541 the initializer list is empty, the empty object `{}` is created.
2542
2543 @note This function is only added for symmetry reasons. In contrast to the
2544 related function @ref array(std::initializer_list<basic_json>), there are
2545 no cases which can only be expressed by this function. That is, any
2546 initializer list @a init can also be passed to the initializer list
2547 constructor @ref basic_json(std::initializer_list<basic_json>, bool, value_t).
2548
2549 @param[in] init initializer list to create an object from (optional)
2550
2551 @return JSON object value
2552
2553 @throw type_error.301 if @a init is not a list of pairs whose first
2554 elements are strings. In this case, no object can be created. When such a
2555 value is passed to @ref basic_json(std::initializer_list<basic_json>, bool, value_t),
2556 an array would have been created from the passed initializer list @a init.
2557 See example below.
2558
2559 @complexity Linear in the size of @a init.
2560
2561 @liveexample{The following code shows an example for the `object`
2562 function.,object}
2563
2564 @sa @ref basic_json(std::initializer_list<basic_json>, bool, value_t) --
2565 create a JSON value from an initializer list
2566 @sa @ref array(std::initializer_list<basic_json>) -- create a JSON array
2567 value from an initializer list
2568
2569 @since version 1.0.0
2570 */
2571 static basic_json object(std::initializer_list<basic_json> init =
2572 std::initializer_list<basic_json>())
2573 {
2574 return basic_json(init, false, value_t::object);
2575 }
2576
2577 /*!
2578 @brief construct an array with count copies of given value
2579
2580 Constructs a JSON array value by creating @a cnt copies of a passed value.
2581 In case @a cnt is `0`, an empty array is created. As postcondition,
2582 `std::distance(begin(),end()) == cnt` holds.
2583
2584 @param[in] cnt the number of JSON copies of @a val to create
2585 @param[in] val the JSON value to copy
2586
2587 @complexity Linear in @a cnt.
2588
2589 @liveexample{The following code shows examples for the @ref
2590 basic_json(size_type\, const basic_json&)
2591 constructor.,basic_json__size_type_basic_json}
2592
2593 @since version 1.0.0
2594 */
2595 basic_json(size_type cnt, const basic_json& val)
2596 : m_type(value_t::array)
2597 {
2598 m_value.array = create<array_t>(cnt, val);
2599 assert_invariant();
2600 }
2601
2602 /*!
2603 @brief construct a JSON container given an iterator range
2604
2605 Constructs the JSON value with the contents of the range `[first, last)`.
2606 The semantics depends on the different types a JSON value can have:
2607 - In case of primitive types (number, boolean, or string), @a first must
2608 be `begin()` and @a last must be `end()`. In this case, the value is
2609 copied. Otherwise, invalid_iterator.204 is thrown.
2610 - In case of structured types (array, object), the constructor behaves as
2611 similar versions for `std::vector`.
2612 - In case of a null type, invalid_iterator.206 is thrown.
2613
2614 @tparam InputIT an input iterator type (@ref iterator or @ref
2615 const_iterator)
2616
2617 @param[in] first begin of the range to copy from (included)
2618 @param[in] last end of the range to copy from (excluded)
2619
2620 @pre Iterators @a first and @a last must be initialized. **This
2621 precondition is enforced with an assertion.**
2622
2623 @pre Range `[first, last)` is valid. Usually, this precondition cannot be
2624 checked efficiently. Only certain edge cases are detected; see the
2625 description of the exceptions below.
2626
2627 @throw invalid_iterator.201 if iterators @a first and @a last are not
2628 compatible (i.e., do not belong to the same JSON value). In this case,
2629 the range `[first, last)` is undefined.
2630 @throw invalid_iterator.204 if iterators @a first and @a last belong to a
2631 primitive type (number, boolean, or string), but @a first does not point
2632 to the first element any more. In this case, the range `[first, last)` is
2633 undefined. See example code below.
2634 @throw invalid_iterator.206 if iterators @a first and @a last belong to a
2635 null value. In this case, the range `[first, last)` is undefined.
2636
2637 @complexity Linear in distance between @a first and @a last.
2638
2639 @liveexample{The example below shows several ways to create JSON values by
2640 specifying a subrange with iterators.,basic_json__InputIt_InputIt}
2641
2642 @since version 1.0.0
2643 */
2644 template<class InputIT, typename std::enable_if<
2645 std::is_same<InputIT, typename basic_json_t::iterator>::value or
2646 std::is_same<InputIT, typename basic_json_t::const_iterator>::value, int>::type = 0>
2647 basic_json(InputIT first, InputIT last)
2648 {
2649 assert(first.m_object != nullptr);
2650 assert(last.m_object != nullptr);
2651
2652 // make sure iterator fits the current value
2653 if (first.m_object != last.m_object)
2654 {
2655 JSON_THROW(invalid_iterator::create(201, "iterators are not compatible"));
2656 }
2657
2658 // copy type from first iterator
2659 m_type = first.m_object->m_type;
2660
2661 // check if iterator range is complete for primitive values
2662 switch (m_type)
2663 {
2664 case value_t::boolean:
2665 case value_t::number_float:
2666 case value_t::number_integer:
2667 case value_t::number_unsigned:
2668 case value_t::string:
2669 {
2670 if (not first.m_it.primitive_iterator.is_begin() or not last.m_it.primitive_iterator.is_end())
2671 {
2672 JSON_THROW(invalid_iterator::create(204, "iterators out of range"));
2673 }
2674 break;
2675 }
2676
2677 default:
2678 {
2679 break;
2680 }
2681 }
2682
2683 switch (m_type)
2684 {
2685 case value_t::number_integer:
2686 {
2687 m_value.number_integer = first.m_object->m_value.number_integer;
2688 break;
2689 }
2690
2691 case value_t::number_unsigned:
2692 {
2693 m_value.number_unsigned = first.m_object->m_value.number_unsigned;
2694 break;
2695 }
2696
2697 case value_t::number_float:
2698 {
2699 m_value.number_float = first.m_object->m_value.number_float;
2700 break;
2701 }
2702
2703 case value_t::boolean:
2704 {
2705 m_value.boolean = first.m_object->m_value.boolean;
2706 break;
2707 }
2708
2709 case value_t::string:
2710 {
2711 m_value = *first.m_object->m_value.string;
2712 break;
2713 }
2714
2715 case value_t::object:
2716 {
2717 m_value.object = create<object_t>(first.m_it.object_iterator,
2718 last.m_it.object_iterator);
2719 break;
2720 }
2721
2722 case value_t::array:
2723 {
2724 m_value.array = create<array_t>(first.m_it.array_iterator,
2725 last.m_it.array_iterator);
2726 break;
2727 }
2728
2729 default:
2730 {
2731 JSON_THROW(invalid_iterator::create(206, "cannot construct with iterators from " +
2732 first.m_object->type_name()));
2733 }
2734 }
2735
2736 assert_invariant();
2737 }
2738
2739
2740 ///////////////////////////////////////
2741 // other constructors and destructor //
2742 ///////////////////////////////////////
2743
2744 /*!
2745 @brief copy constructor
2746
2747 Creates a copy of a given JSON value.
2748
2749 @param[in] other the JSON value to copy
2750
2751 @complexity Linear in the size of @a other.
2752
2753 @requirement This function helps `basic_json` satisfying the
2754 [Container](http://en.cppreference.com/w/cpp/concept/Container)
2755 requirements:
2756 - The complexity is linear.
2757 - As postcondition, it holds: `other == basic_json(other)`.
2758
2759 @liveexample{The following code shows an example for the copy
2760 constructor.,basic_json__basic_json}
2761
2762 @since version 1.0.0
2763 */
2764 basic_json(const basic_json& other)
2765 : m_type(other.m_type)
2766 {
2767 // check of passed value is valid
2768 other.assert_invariant();
2769
2770 switch (m_type)
2771 {
2772 case value_t::object:
2773 {
2774 m_value = *other.m_value.object;
2775 break;
2776 }
2777
2778 case value_t::array:
2779 {
2780 m_value = *other.m_value.array;
2781 break;
2782 }
2783
2784 case value_t::string:
2785 {
2786 m_value = *other.m_value.string;
2787 break;
2788 }
2789
2790 case value_t::boolean:
2791 {
2792 m_value = other.m_value.boolean;
2793 break;
2794 }
2795
2796 case value_t::number_integer:
2797 {
2798 m_value = other.m_value.number_integer;
2799 break;
2800 }
2801
2802 case value_t::number_unsigned:
2803 {
2804 m_value = other.m_value.number_unsigned;
2805 break;
2806 }
2807
2808 case value_t::number_float:
2809 {
2810 m_value = other.m_value.number_float;
2811 break;
2812 }
2813
2814 default:
2815 {
2816 break;
2817 }
2818 }
2819
2820 assert_invariant();
2821 }
2822
2823 /*!
2824 @brief move constructor
2825
2826 Move constructor. Constructs a JSON value with the contents of the given
2827 value @a other using move semantics. It "steals" the resources from @a
2828 other and leaves it as JSON null value.
2829
2830 @param[in,out] other value to move to this object
2831
2832 @post @a other is a JSON null value
2833
2834 @complexity Constant.
2835
2836 @liveexample{The code below shows the move constructor explicitly called
2837 via std::move.,basic_json__moveconstructor}
2838
2839 @since version 1.0.0
2840 */
2841 basic_json(basic_json&& other) noexcept
2842 : m_type(std::move(other.m_type)),
2843 m_value(std::move(other.m_value))
2844 {
2845 // check that passed value is valid
2846 other.assert_invariant();
2847
2848 // invalidate payload
2849 other.m_type = value_t::null;
2850 other.m_value = {};
2851
2852 assert_invariant();
2853 }
2854
2855 /*!
2856 @brief copy assignment
2857
2858 Copy assignment operator. Copies a JSON value via the "copy and swap"
2859 strategy: It is expressed in terms of the copy constructor, destructor,
2860 and the swap() member function.
2861
2862 @param[in] other value to copy from
2863
2864 @complexity Linear.
2865
2866 @requirement This function helps `basic_json` satisfying the
2867 [Container](http://en.cppreference.com/w/cpp/concept/Container)
2868 requirements:
2869 - The complexity is linear.
2870
2871 @liveexample{The code below shows and example for the copy assignment. It
2872 creates a copy of value `a` which is then swapped with `b`. Finally\, the
2873 copy of `a` (which is the null value after the swap) is
2874 destroyed.,basic_json__copyassignment}
2875
2876 @since version 1.0.0
2877 */
2878 reference& operator=(basic_json other) noexcept (
2879 std::is_nothrow_move_constructible<value_t>::value and
2880 std::is_nothrow_move_assignable<value_t>::value and
2881 std::is_nothrow_move_constructible<json_value>::value and
2882 std::is_nothrow_move_assignable<json_value>::value
2883 )
2884 {
2885 // check that passed value is valid
2886 other.assert_invariant();
2887
2888 using std::swap;
2889 swap(m_type, other.m_type);
2890 swap(m_value, other.m_value);
2891
2892 assert_invariant();
2893 return *this;
2894 }
2895
2896 /*!
2897 @brief destructor
2898
2899 Destroys the JSON value and frees all allocated memory.
2900
2901 @complexity Linear.
2902
2903 @requirement This function helps `basic_json` satisfying the
2904 [Container](http://en.cppreference.com/w/cpp/concept/Container)
2905 requirements:
2906 - The complexity is linear.
2907 - All stored elements are destroyed and all memory is freed.
2908
2909 @since version 1.0.0
2910 */
2911 ~basic_json()
2912 {
2913 assert_invariant();
2914
2915 switch (m_type)
2916 {
2917 case value_t::object:
2918 {
2919 AllocatorType<object_t> alloc;
2920 alloc.destroy(m_value.object);
2921 alloc.deallocate(m_value.object, 1);
2922 break;
2923 }
2924
2925 case value_t::array:
2926 {
2927 AllocatorType<array_t> alloc;
2928 alloc.destroy(m_value.array);
2929 alloc.deallocate(m_value.array, 1);
2930 break;
2931 }
2932
2933 case value_t::string:
2934 {
2935 AllocatorType<string_t> alloc;
2936 alloc.destroy(m_value.string);
2937 alloc.deallocate(m_value.string, 1);
2938 break;
2939 }
2940
2941 default:
2942 {
2943 // all other types need no specific destructor
2944 break;
2945 }
2946 }
2947 }
2948
2949 /// @}
2950
2951 public:
2952 ///////////////////////
2953 // object inspection //
2954 ///////////////////////
2955
2956 /// @name object inspection
2957 /// Functions to inspect the type of a JSON value.
2958 /// @{
2959
2960 /*!
2961 @brief serialization
2962
2963 Serialization function for JSON values. The function tries to mimic
2964 Python's `json.dumps()` function, and currently supports its @a indent
2965 parameter.
2966
2967 @param[in] indent If indent is nonnegative, then array elements and object
2968 members will be pretty-printed with that indent level. An indent level of
2969 `0` will only insert newlines. `-1` (the default) selects the most compact
2970 representation.
2971 @param[in] indent_char The character to use for indentation if @a indent is
2972 greater than `0`. The default is ` ` (space).
2973
2974 @return string containing the serialization of the JSON value
2975
2976 @complexity Linear.
2977
2978 @liveexample{The following example shows the effect of different @a indent
2979 parameters to the result of the serialization.,dump}
2980
2981 @see https://docs.python.org/2/library/json.html#json.dump
2982
2983 @since version 1.0.0; indentation character added in version 3.0.0
2984 */
2985 string_t dump(const int indent = -1, const char indent_char = ' ') const
2986 {
2987 string_t result;
2988 serializer s(output_adapter<char>::create(result), indent_char);
2989
2990 if (indent >= 0)
2991 {
2992 s.dump(*this, true, static_cast<unsigned int>(indent));
2993 }
2994 else
2995 {
2996 s.dump(*this, false, 0);
2997 }
2998
2999 return result;
3000 }
3001
3002 /*!
3003 @brief return the type of the JSON value (explicit)
3004
3005 Return the type of the JSON value as a value from the @ref value_t
3006 enumeration.
3007
3008 @return the type of the JSON value
3009
3010 @complexity Constant.
3011
3012 @exceptionsafety No-throw guarantee: this member function never throws
3013 exceptions.
3014
3015 @liveexample{The following code exemplifies `type()` for all JSON
3016 types.,type}
3017
3018 @since version 1.0.0
3019 */
3020 constexpr value_t type() const noexcept
3021 {
3022 return m_type;
3023 }
3024
3025 /*!
3026 @brief return whether type is primitive
3027
3028 This function returns true iff the JSON type is primitive (string, number,
3029 boolean, or null).
3030
3031 @return `true` if type is primitive (string, number, boolean, or null),
3032 `false` otherwise.
3033
3034 @complexity Constant.
3035
3036 @exceptionsafety No-throw guarantee: this member function never throws
3037 exceptions.
3038
3039 @liveexample{The following code exemplifies `is_primitive()` for all JSON
3040 types.,is_primitive}
3041
3042 @sa @ref is_structured() -- returns whether JSON value is structured
3043 @sa @ref is_null() -- returns whether JSON value is `null`
3044 @sa @ref is_string() -- returns whether JSON value is a string
3045 @sa @ref is_boolean() -- returns whether JSON value is a boolean
3046 @sa @ref is_number() -- returns whether JSON value is a number
3047
3048 @since version 1.0.0
3049 */
3050 constexpr bool is_primitive() const noexcept
3051 {
3052 return is_null() or is_string() or is_boolean() or is_number();
3053 }
3054
3055 /*!
3056 @brief return whether type is structured
3057
3058 This function returns true iff the JSON type is structured (array or
3059 object).
3060
3061 @return `true` if type is structured (array or object), `false` otherwise.
3062
3063 @complexity Constant.
3064
3065 @exceptionsafety No-throw guarantee: this member function never throws
3066 exceptions.
3067
3068 @liveexample{The following code exemplifies `is_structured()` for all JSON
3069 types.,is_structured}
3070
3071 @sa @ref is_primitive() -- returns whether value is primitive
3072 @sa @ref is_array() -- returns whether value is an array
3073 @sa @ref is_object() -- returns whether value is an object
3074
3075 @since version 1.0.0
3076 */
3077 constexpr bool is_structured() const noexcept
3078 {
3079 return is_array() or is_object();
3080 }
3081
3082 /*!
3083 @brief return whether value is null
3084
3085 This function returns true iff the JSON value is null.
3086
3087 @return `true` if type is null, `false` otherwise.
3088
3089 @complexity Constant.
3090
3091 @exceptionsafety No-throw guarantee: this member function never throws
3092 exceptions.
3093
3094 @liveexample{The following code exemplifies `is_null()` for all JSON
3095 types.,is_null}
3096
3097 @since version 1.0.0
3098 */
3099 constexpr bool is_null() const noexcept
3100 {
3101 return m_type == value_t::null;
3102 }
3103
3104 /*!
3105 @brief return whether value is a boolean
3106
3107 This function returns true iff the JSON value is a boolean.
3108
3109 @return `true` if type is boolean, `false` otherwise.
3110
3111 @complexity Constant.
3112
3113 @exceptionsafety No-throw guarantee: this member function never throws
3114 exceptions.
3115
3116 @liveexample{The following code exemplifies `is_boolean()` for all JSON
3117 types.,is_boolean}
3118
3119 @since version 1.0.0
3120 */
3121 constexpr bool is_boolean() const noexcept
3122 {
3123 return m_type == value_t::boolean;
3124 }
3125
3126 /*!
3127 @brief return whether value is a number
3128
3129 This function returns true iff the JSON value is a number. This includes
3130 both integer and floating-point values.
3131
3132 @return `true` if type is number (regardless whether integer, unsigned
3133 integer or floating-type), `false` otherwise.
3134
3135 @complexity Constant.
3136
3137 @exceptionsafety No-throw guarantee: this member function never throws
3138 exceptions.
3139
3140 @liveexample{The following code exemplifies `is_number()` for all JSON
3141 types.,is_number}
3142
3143 @sa @ref is_number_integer() -- check if value is an integer or unsigned
3144 integer number
3145 @sa @ref is_number_unsigned() -- check if value is an unsigned integer
3146 number
3147 @sa @ref is_number_float() -- check if value is a floating-point number
3148
3149 @since version 1.0.0
3150 */
3151 constexpr bool is_number() const noexcept
3152 {
3153 return is_number_integer() or is_number_float();
3154 }
3155
3156 /*!
3157 @brief return whether value is an integer number
3158
3159 This function returns true iff the JSON value is an integer or unsigned
3160 integer number. This excludes floating-point values.
3161
3162 @return `true` if type is an integer or unsigned integer number, `false`
3163 otherwise.
3164
3165 @complexity Constant.
3166
3167 @exceptionsafety No-throw guarantee: this member function never throws
3168 exceptions.
3169
3170 @liveexample{The following code exemplifies `is_number_integer()` for all
3171 JSON types.,is_number_integer}
3172
3173 @sa @ref is_number() -- check if value is a number
3174 @sa @ref is_number_unsigned() -- check if value is an unsigned integer
3175 number
3176 @sa @ref is_number_float() -- check if value is a floating-point number
3177
3178 @since version 1.0.0
3179 */
3180 constexpr bool is_number_integer() const noexcept
3181 {
3182 return m_type == value_t::number_integer or m_type == value_t::number_unsigned;
3183 }
3184
3185 /*!
3186 @brief return whether value is an unsigned integer number
3187
3188 This function returns true iff the JSON value is an unsigned integer
3189 number. This excludes floating-point and (signed) integer values.
3190
3191 @return `true` if type is an unsigned integer number, `false` otherwise.
3192
3193 @complexity Constant.
3194
3195 @exceptionsafety No-throw guarantee: this member function never throws
3196 exceptions.
3197
3198 @liveexample{The following code exemplifies `is_number_unsigned()` for all
3199 JSON types.,is_number_unsigned}
3200
3201 @sa @ref is_number() -- check if value is a number
3202 @sa @ref is_number_integer() -- check if value is an integer or unsigned
3203 integer number
3204 @sa @ref is_number_float() -- check if value is a floating-point number
3205
3206 @since version 2.0.0
3207 */
3208 constexpr bool is_number_unsigned() const noexcept
3209 {
3210 return m_type == value_t::number_unsigned;
3211 }
3212
3213 /*!
3214 @brief return whether value is a floating-point number
3215
3216 This function returns true iff the JSON value is a floating-point number.
3217 This excludes integer and unsigned integer values.
3218
3219 @return `true` if type is a floating-point number, `false` otherwise.
3220
3221 @complexity Constant.
3222
3223 @exceptionsafety No-throw guarantee: this member function never throws
3224 exceptions.
3225
3226 @liveexample{The following code exemplifies `is_number_float()` for all
3227 JSON types.,is_number_float}
3228
3229 @sa @ref is_number() -- check if value is number
3230 @sa @ref is_number_integer() -- check if value is an integer number
3231 @sa @ref is_number_unsigned() -- check if value is an unsigned integer
3232 number
3233
3234 @since version 1.0.0
3235 */
3236 constexpr bool is_number_float() const noexcept
3237 {
3238 return m_type == value_t::number_float;
3239 }
3240
3241 /*!
3242 @brief return whether value is an object
3243
3244 This function returns true iff the JSON value is an object.
3245
3246 @return `true` if type is object, `false` otherwise.
3247
3248 @complexity Constant.
3249
3250 @exceptionsafety No-throw guarantee: this member function never throws
3251 exceptions.
3252
3253 @liveexample{The following code exemplifies `is_object()` for all JSON
3254 types.,is_object}
3255
3256 @since version 1.0.0
3257 */
3258 constexpr bool is_object() const noexcept
3259 {
3260 return m_type == value_t::object;
3261 }
3262
3263 /*!
3264 @brief return whether value is an array
3265
3266 This function returns true iff the JSON value is an array.
3267
3268 @return `true` if type is array, `false` otherwise.
3269
3270 @complexity Constant.
3271
3272 @exceptionsafety No-throw guarantee: this member function never throws
3273 exceptions.
3274
3275 @liveexample{The following code exemplifies `is_array()` for all JSON
3276 types.,is_array}
3277
3278 @since version 1.0.0
3279 */
3280 constexpr bool is_array() const noexcept
3281 {
3282 return m_type == value_t::array;
3283 }
3284
3285 /*!
3286 @brief return whether value is a string
3287
3288 This function returns true iff the JSON value is a string.
3289
3290 @return `true` if type is string, `false` otherwise.
3291
3292 @complexity Constant.
3293
3294 @exceptionsafety No-throw guarantee: this member function never throws
3295 exceptions.
3296
3297 @liveexample{The following code exemplifies `is_string()` for all JSON
3298 types.,is_string}
3299
3300 @since version 1.0.0
3301 */
3302 constexpr bool is_string() const noexcept
3303 {
3304 return m_type == value_t::string;
3305 }
3306
3307 /*!
3308 @brief return whether value is discarded
3309
3310 This function returns true iff the JSON value was discarded during parsing
3311 with a callback function (see @ref parser_callback_t).
3312
3313 @note This function will always be `false` for JSON values after parsing.
3314 That is, discarded values can only occur during parsing, but will be
3315 removed when inside a structured value or replaced by null in other cases.
3316
3317 @return `true` if type is discarded, `false` otherwise.
3318
3319 @complexity Constant.
3320
3321 @exceptionsafety No-throw guarantee: this member function never throws
3322 exceptions.
3323
3324 @liveexample{The following code exemplifies `is_discarded()` for all JSON
3325 types.,is_discarded}
3326
3327 @since version 1.0.0
3328 */
3329 constexpr bool is_discarded() const noexcept
3330 {
3331 return m_type == value_t::discarded;
3332 }
3333
3334 /*!
3335 @brief return the type of the JSON value (implicit)
3336
3337 Implicitly return the type of the JSON value as a value from the @ref
3338 value_t enumeration.
3339
3340 @return the type of the JSON value
3341
3342 @complexity Constant.
3343
3344 @exceptionsafety No-throw guarantee: this member function never throws
3345 exceptions.
3346
3347 @liveexample{The following code exemplifies the @ref value_t operator for
3348 all JSON types.,operator__value_t}
3349
3350 @since version 1.0.0
3351 */
3352 constexpr operator value_t() const noexcept
3353 {
3354 return m_type;
3355 }
3356
3357 /// @}
3358
3359 private:
3360 //////////////////
3361 // value access //
3362 //////////////////
3363
3364 /// get a boolean (explicit)
3365 boolean_t get_impl(boolean_t* /*unused*/) const
3366 {
3367 if (is_boolean())
3368 {
3369 return m_value.boolean;
3370 }
3371
3372 JSON_THROW(type_error::create(302, "type must be boolean, but is " + type_name()));
3373 }
3374
3375 /// get a pointer to the value (object)
3376 object_t* get_impl_ptr(object_t* /*unused*/) noexcept
3377 {
3378 return is_object() ? m_value.object : nullptr;
3379 }
3380
3381 /// get a pointer to the value (object)
3382 constexpr const object_t* get_impl_ptr(const object_t* /*unused*/) const noexcept
3383 {
3384 return is_object() ? m_value.object : nullptr;
3385 }
3386
3387 /// get a pointer to the value (array)
3388 array_t* get_impl_ptr(array_t* /*unused*/) noexcept
3389 {
3390 return is_array() ? m_value.array : nullptr;
3391 }
3392
3393 /// get a pointer to the value (array)
3394 constexpr const array_t* get_impl_ptr(const array_t* /*unused*/) const noexcept
3395 {
3396 return is_array() ? m_value.array : nullptr;
3397 }
3398
3399 /// get a pointer to the value (string)
3400 string_t* get_impl_ptr(string_t* /*unused*/) noexcept
3401 {
3402 return is_string() ? m_value.string : nullptr;
3403 }
3404
3405 /// get a pointer to the value (string)
3406 constexpr const string_t* get_impl_ptr(const string_t* /*unused*/) const noexcept
3407 {
3408 return is_string() ? m_value.string : nullptr;
3409 }
3410
3411 /// get a pointer to the value (boolean)
3412 boolean_t* get_impl_ptr(boolean_t* /*unused*/) noexcept
3413 {
3414 return is_boolean() ? &m_value.boolean : nullptr;
3415 }
3416
3417 /// get a pointer to the value (boolean)
3418 constexpr const boolean_t* get_impl_ptr(const boolean_t* /*unused*/) const noexcept
3419 {
3420 return is_boolean() ? &m_value.boolean : nullptr;
3421 }
3422
3423 /// get a pointer to the value (integer number)
3424 number_integer_t* get_impl_ptr(number_integer_t* /*unused*/) noexcept
3425 {
3426 return is_number_integer() ? &m_value.number_integer : nullptr;
3427 }
3428
3429 /// get a pointer to the value (integer number)
3430 constexpr const number_integer_t* get_impl_ptr(const number_integer_t* /*unused*/) const noexcept
3431 {
3432 return is_number_integer() ? &m_value.number_integer : nullptr;
3433 }
3434
3435 /// get a pointer to the value (unsigned number)
3436 number_unsigned_t* get_impl_ptr(number_unsigned_t* /*unused*/) noexcept
3437 {
3438 return is_number_unsigned() ? &m_value.number_unsigned : nullptr;
3439 }
3440
3441 /// get a pointer to the value (unsigned number)
3442 constexpr const number_unsigned_t* get_impl_ptr(const number_unsigned_t* /*unused*/) const noexcept
3443 {
3444 return is_number_unsigned() ? &m_value.number_unsigned : nullptr;
3445 }
3446
3447 /// get a pointer to the value (floating-point number)
3448 number_float_t* get_impl_ptr(number_float_t* /*unused*/) noexcept
3449 {
3450 return is_number_float() ? &m_value.number_float : nullptr;
3451 }
3452
3453 /// get a pointer to the value (floating-point number)
3454 constexpr const number_float_t* get_impl_ptr(const number_float_t* /*unused*/) const noexcept
3455 {
3456 return is_number_float() ? &m_value.number_float : nullptr;
3457 }
3458
3459 /*!
3460 @brief helper function to implement get_ref()
3461
3462 This function helps to implement get_ref() without code duplication for
3463 const and non-const overloads
3464
3465 @tparam ThisType will be deduced as `basic_json` or `const basic_json`
3466
3467 @throw type_error.303 if ReferenceType does not match underlying value
3468 type of the current JSON
3469 */
3470 template<typename ReferenceType, typename ThisType>
3471 static ReferenceType get_ref_impl(ThisType& obj)
3472 {
3473 // helper type
3474 using PointerType = typename std::add_pointer<ReferenceType>::type;
3475
3476 // delegate the call to get_ptr<>()
3477 auto ptr = obj.template get_ptr<PointerType>();
3478
3479 if (ptr != nullptr)
3480 {
3481 return *ptr;
3482 }
3483
3484 JSON_THROW(type_error::create(303, "incompatible ReferenceType for get_ref, actual type is " + obj.type_name()));
3485 }
3486
3487 public:
3488 /// @name value access
3489 /// Direct access to the stored value of a JSON value.
3490 /// @{
3491
3492 /*!
3493 @brief get special-case overload
3494
3495 This overloads avoids a lot of template boilerplate, it can be seen as the
3496 identity method
3497
3498 @tparam BasicJsonType == @ref basic_json
3499
3500 @return a copy of *this
3501
3502 @complexity Constant.
3503
3504 @since version 2.1.0
3505 */
3506 template <
3507 typename BasicJsonType,
3508 detail::enable_if_t<std::is_same<typename std::remove_const<BasicJsonType>::type,
3509 basic_json_t>::value,
3510 int> = 0 >
3511 basic_json get() const
3512 {
3513 return *this;
3514 }
3515
3516 /*!
3517 @brief get a value (explicit)
3518
3519 Explicit type conversion between the JSON value and a compatible value
3520 which is [CopyConstructible](http://en.cppreference.com/w/cpp/concept/CopyConstructible)
3521 and [DefaultConstructible](http://en.cppreference.com/w/cpp/concept/DefaultConstructible).
3522 The value is converted by calling the @ref json_serializer<ValueType>
3523 `from_json()` method.
3524
3525 The function is equivalent to executing
3526 @code {.cpp}
3527 ValueType ret;
3528 JSONSerializer<ValueType>::from_json(*this, ret);
3529 return ret;
3530 @endcode
3531
3532 This overloads is chosen if:
3533 - @a ValueType is not @ref basic_json,
3534 - @ref json_serializer<ValueType> has a `from_json()` method of the form
3535 `void from_json(const basic_json&, ValueType&)`, and
3536 - @ref json_serializer<ValueType> does not have a `from_json()` method of
3537 the form `ValueType from_json(const basic_json&)`
3538
3539 @tparam ValueTypeCV the provided value type
3540 @tparam ValueType the returned value type
3541
3542 @return copy of the JSON value, converted to @a ValueType
3543
3544 @throw what @ref json_serializer<ValueType> `from_json()` method throws
3545
3546 @liveexample{The example below shows several conversions from JSON values
3547 to other types. There a few things to note: (1) Floating-point numbers can
3548 be converted to integers\, (2) A JSON array can be converted to a standard
3549 `std::vector<short>`\, (3) A JSON object can be converted to C++
3550 associative containers such as `std::unordered_map<std::string\,
3551 json>`.,get__ValueType_const}
3552
3553 @since version 2.1.0
3554 */
3555 template <
3556 typename ValueTypeCV,
3557 typename ValueType = detail::uncvref_t<ValueTypeCV>,
3558 detail::enable_if_t <
3559 not std::is_same<basic_json_t, ValueType>::value and
3560 detail::has_from_json<basic_json_t, ValueType>::value and
3561 not detail::has_non_default_from_json<basic_json_t, ValueType>::value,
3562 int > = 0 >
3563 ValueType get() const noexcept(noexcept(
3564 JSONSerializer<ValueType>::from_json(std::declval<const basic_json_t&>(), std::declval<ValueType&>())))
3565 {
3566 // we cannot static_assert on ValueTypeCV being non-const, because
3567 // there is support for get<const basic_json_t>(), which is why we
3568 // still need the uncvref
3569 static_assert(not std::is_reference<ValueTypeCV>::value,
3570 "get() cannot be used with reference types, you might want to use get_ref()");
3571 static_assert(std::is_default_constructible<ValueType>::value,
3572 "types must be DefaultConstructible when used with get()");
3573
3574 ValueType ret;
3575 JSONSerializer<ValueType>::from_json(*this, ret);
3576 return ret;
3577 }
3578
3579 /*!
3580 @brief get a value (explicit); special case
3581
3582 Explicit type conversion between the JSON value and a compatible value
3583 which is **not** [CopyConstructible](http://en.cppreference.com/w/cpp/concept/CopyConstructible)
3584 and **not** [DefaultConstructible](http://en.cppreference.com/w/cpp/concept/DefaultConstructible).
3585 The value is converted by calling the @ref json_serializer<ValueType>
3586 `from_json()` method.
3587
3588 The function is equivalent to executing
3589 @code {.cpp}
3590 return JSONSerializer<ValueTypeCV>::from_json(*this);
3591 @endcode
3592
3593 This overloads is chosen if:
3594 - @a ValueType is not @ref basic_json and
3595 - @ref json_serializer<ValueType> has a `from_json()` method of the form
3596 `ValueType from_json(const basic_json&)`
3597
3598 @note If @ref json_serializer<ValueType> has both overloads of
3599 `from_json()`, this one is chosen.
3600
3601 @tparam ValueTypeCV the provided value type
3602 @tparam ValueType the returned value type
3603
3604 @return copy of the JSON value, converted to @a ValueType
3605
3606 @throw what @ref json_serializer<ValueType> `from_json()` method throws
3607
3608 @since version 2.1.0
3609 */
3610 template <
3611 typename ValueTypeCV,
3612 typename ValueType = detail::uncvref_t<ValueTypeCV>,
3613 detail::enable_if_t<not std::is_same<basic_json_t, ValueType>::value and
3614 detail::has_non_default_from_json<basic_json_t,
3615 ValueType>::value, int> = 0 >
3616 ValueType get() const noexcept(noexcept(
3617 JSONSerializer<ValueTypeCV>::from_json(std::declval<const basic_json_t&>())))
3618 {
3619 static_assert(not std::is_reference<ValueTypeCV>::value,
3620 "get() cannot be used with reference types, you might want to use get_ref()");
3621 return JSONSerializer<ValueTypeCV>::from_json(*this);
3622 }
3623
3624 /*!
3625 @brief get a pointer value (explicit)
3626
3627 Explicit pointer access to the internally stored JSON value. No copies are
3628 made.
3629
3630 @warning The pointer becomes invalid if the underlying JSON object
3631 changes.
3632
3633 @tparam PointerType pointer type; must be a pointer to @ref array_t, @ref
3634 object_t, @ref string_t, @ref boolean_t, @ref number_integer_t,
3635 @ref number_unsigned_t, or @ref number_float_t.
3636
3637 @return pointer to the internally stored JSON value if the requested
3638 pointer type @a PointerType fits to the JSON value; `nullptr` otherwise
3639
3640 @complexity Constant.
3641
3642 @liveexample{The example below shows how pointers to internal values of a
3643 JSON value can be requested. Note that no type conversions are made and a
3644 `nullptr` is returned if the value and the requested pointer type does not
3645 match.,get__PointerType}
3646
3647 @sa @ref get_ptr() for explicit pointer-member access
3648
3649 @since version 1.0.0
3650 */
3651 template<typename PointerType, typename std::enable_if<
3652 std::is_pointer<PointerType>::value, int>::type = 0>
3653 PointerType get() noexcept
3654 {
3655 // delegate the call to get_ptr
3656 return get_ptr<PointerType>();
3657 }
3658
3659 /*!
3660 @brief get a pointer value (explicit)
3661 @copydoc get()
3662 */
3663 template<typename PointerType, typename std::enable_if<
3664 std::is_pointer<PointerType>::value, int>::type = 0>
3665 constexpr const PointerType get() const noexcept
3666 {
3667 // delegate the call to get_ptr
3668 return get_ptr<PointerType>();
3669 }
3670
3671 /*!
3672 @brief get a pointer value (implicit)
3673
3674 Implicit pointer access to the internally stored JSON value. No copies are
3675 made.
3676
3677 @warning Writing data to the pointee of the result yields an undefined
3678 state.
3679
3680 @tparam PointerType pointer type; must be a pointer to @ref array_t, @ref
3681 object_t, @ref string_t, @ref boolean_t, @ref number_integer_t,
3682 @ref number_unsigned_t, or @ref number_float_t. Enforced by a static
3683 assertion.
3684
3685 @return pointer to the internally stored JSON value if the requested
3686 pointer type @a PointerType fits to the JSON value; `nullptr` otherwise
3687
3688 @complexity Constant.
3689
3690 @liveexample{The example below shows how pointers to internal values of a
3691 JSON value can be requested. Note that no type conversions are made and a
3692 `nullptr` is returned if the value and the requested pointer type does not
3693 match.,get_ptr}
3694
3695 @since version 1.0.0
3696 */
3697 template<typename PointerType, typename std::enable_if<
3698 std::is_pointer<PointerType>::value, int>::type = 0>
3699 PointerType get_ptr() noexcept
3700 {
3701 // get the type of the PointerType (remove pointer and const)
3702 using pointee_t = typename std::remove_const<typename
3703 std::remove_pointer<typename
3704 std::remove_const<PointerType>::type>::type>::type;
3705 // make sure the type matches the allowed types
3706 static_assert(
3707 std::is_same<object_t, pointee_t>::value
3708 or std::is_same<array_t, pointee_t>::value
3709 or std::is_same<string_t, pointee_t>::value
3710 or std::is_same<boolean_t, pointee_t>::value
3711 or std::is_same<number_integer_t, pointee_t>::value
3712 or std::is_same<number_unsigned_t, pointee_t>::value
3713 or std::is_same<number_float_t, pointee_t>::value
3714 , "incompatible pointer type");
3715
3716 // delegate the call to get_impl_ptr<>()
3717 return get_impl_ptr(static_cast<PointerType>(nullptr));
3718 }
3719
3720 /*!
3721 @brief get a pointer value (implicit)
3722 @copydoc get_ptr()
3723 */
3724 template<typename PointerType, typename std::enable_if<
3725 std::is_pointer<PointerType>::value and
3726 std::is_const<typename std::remove_pointer<PointerType>::type>::value, int>::type = 0>
3727 constexpr const PointerType get_ptr() const noexcept
3728 {
3729 // get the type of the PointerType (remove pointer and const)
3730 using pointee_t = typename std::remove_const<typename
3731 std::remove_pointer<typename
3732 std::remove_const<PointerType>::type>::type>::type;
3733 // make sure the type matches the allowed types
3734 static_assert(
3735 std::is_same<object_t, pointee_t>::value
3736 or std::is_same<array_t, pointee_t>::value
3737 or std::is_same<string_t, pointee_t>::value
3738 or std::is_same<boolean_t, pointee_t>::value
3739 or std::is_same<number_integer_t, pointee_t>::value
3740 or std::is_same<number_unsigned_t, pointee_t>::value
3741 or std::is_same<number_float_t, pointee_t>::value
3742 , "incompatible pointer type");
3743
3744 // delegate the call to get_impl_ptr<>() const
3745 return get_impl_ptr(static_cast<const PointerType>(nullptr));
3746 }
3747
3748 /*!
3749 @brief get a reference value (implicit)
3750
3751 Implicit reference access to the internally stored JSON value. No copies
3752 are made.
3753
3754 @warning Writing data to the referee of the result yields an undefined
3755 state.
3756
3757 @tparam ReferenceType reference type; must be a reference to @ref array_t,
3758 @ref object_t, @ref string_t, @ref boolean_t, @ref number_integer_t, or
3759 @ref number_float_t. Enforced by static assertion.
3760
3761 @return reference to the internally stored JSON value if the requested
3762 reference type @a ReferenceType fits to the JSON value; throws
3763 type_error.303 otherwise
3764
3765 @throw type_error.303 in case passed type @a ReferenceType is incompatible
3766 with the stored JSON value; see example below
3767
3768 @complexity Constant.
3769
3770 @liveexample{The example shows several calls to `get_ref()`.,get_ref}
3771
3772 @since version 1.1.0
3773 */
3774 template<typename ReferenceType, typename std::enable_if<
3775 std::is_reference<ReferenceType>::value, int>::type = 0>
3776 ReferenceType get_ref()
3777 {
3778 // delegate call to get_ref_impl
3779 return get_ref_impl<ReferenceType>(*this);
3780 }
3781
3782 /*!
3783 @brief get a reference value (implicit)
3784 @copydoc get_ref()
3785 */
3786 template<typename ReferenceType, typename std::enable_if<
3787 std::is_reference<ReferenceType>::value and
3788 std::is_const<typename std::remove_reference<ReferenceType>::type>::value, int>::type = 0>
3789 ReferenceType get_ref() const
3790 {
3791 // delegate call to get_ref_impl
3792 return get_ref_impl<ReferenceType>(*this);
3793 }
3794
3795 /*!
3796 @brief get a value (implicit)
3797
3798 Implicit type conversion between the JSON value and a compatible value.
3799 The call is realized by calling @ref get() const.
3800
3801 @tparam ValueType non-pointer type compatible to the JSON value, for
3802 instance `int` for JSON integer numbers, `bool` for JSON booleans, or
3803 `std::vector` types for JSON arrays. The character type of @ref string_t
3804 as well as an initializer list of this type is excluded to avoid
3805 ambiguities as these types implicitly convert to `std::string`.
3806
3807 @return copy of the JSON value, converted to type @a ValueType
3808
3809 @throw type_error.302 in case passed type @a ValueType is incompatible
3810 to the JSON value type (e.g., the JSON value is of type boolean, but a
3811 string is requested); see example below
3812
3813 @complexity Linear in the size of the JSON value.
3814
3815 @liveexample{The example below shows several conversions from JSON values
3816 to other types. There a few things to note: (1) Floating-point numbers can
3817 be converted to integers\, (2) A JSON array can be converted to a standard
3818 `std::vector<short>`\, (3) A JSON object can be converted to C++
3819 associative containers such as `std::unordered_map<std::string\,
3820 json>`.,operator__ValueType}
3821
3822 @since version 1.0.0
3823 */
3824 template < typename ValueType, typename std::enable_if <
3825 not std::is_pointer<ValueType>::value and
3826 not std::is_same<ValueType, typename string_t::value_type>::value
3827#ifndef _MSC_VER // fix for issue #167 operator<< ambiguity under VS2015
3828 and not std::is_same<ValueType, std::initializer_list<typename string_t::value_type>>::value
3829#endif
3830#if (defined(__cplusplus) && __cplusplus >= 201703L) || (defined(_MSC_VER) && _MSC_VER >1900 && defined(_HAS_CXX17) && _HAS_CXX17 == 1) // fix for issue #464
3831 and not std::is_same<ValueType, typename std::string_view>::value
3832#endif
3833 , int >::type = 0 >
3834 operator ValueType() const
3835 {
3836 // delegate the call to get<>() const
3837 return get<ValueType>();
3838 }
3839
3840 /// @}
3841
3842
3843 ////////////////////
3844 // element access //
3845 ////////////////////
3846
3847 /// @name element access
3848 /// Access to the JSON value.
3849 /// @{
3850
3851 /*!
3852 @brief access specified array element with bounds checking
3853
3854 Returns a reference to the element at specified location @a idx, with
3855 bounds checking.
3856
3857 @param[in] idx index of the element to access
3858
3859 @return reference to the element at index @a idx
3860
3861 @throw type_error.304 if the JSON value is not an array; in this case,
3862 calling `at` with an index makes no sense. See example below.
3863 @throw out_of_range.401 if the index @a idx is out of range of the array;
3864 that is, `idx >= size()`. See example below.
3865
3866 @exceptionsafety Strong guarantee: if an exception is thrown, there are no
3867 changes in the JSON value.
3868
3869 @complexity Constant.
3870
3871 @since version 1.0.0
3872
3873 @liveexample{The example below shows how array elements can be read and
3874 written using `at()`. It also demonstrates the different exceptions that
3875 can be thrown.,at__size_type}
3876 */
3877 reference at(size_type idx)
3878 {
3879 // at only works for arrays
3880 if (is_array())
3881 {
3882 JSON_TRY
3883 {
3884 return m_value.array->at(idx);
3885 }
3886 JSON_CATCH (std::out_of_range&)
3887 {
3888 // create better exception explanation
3889 JSON_THROW(out_of_range::create(401, "array index " + std::to_string(idx) + " is out of range"));
3890 }
3891 }
3892 else
3893 {
3894 JSON_THROW(type_error::create(304, "cannot use at() with " + type_name()));
3895 }
3896 }
3897
3898 /*!
3899 @brief access specified array element with bounds checking
3900
3901 Returns a const reference to the element at specified location @a idx,
3902 with bounds checking.
3903
3904 @param[in] idx index of the element to access
3905
3906 @return const reference to the element at index @a idx
3907
3908 @throw type_error.304 if the JSON value is not an array; in this case,
3909 calling `at` with an index makes no sense. See example below.
3910 @throw out_of_range.401 if the index @a idx is out of range of the array;
3911 that is, `idx >= size()`. See example below.
3912
3913 @exceptionsafety Strong guarantee: if an exception is thrown, there are no
3914 changes in the JSON value.
3915
3916 @complexity Constant.
3917
3918 @since version 1.0.0
3919
3920 @liveexample{The example below shows how array elements can be read using
3921 `at()`. It also demonstrates the different exceptions that can be thrown.,
3922 at__size_type_const}
3923 */
3924 const_reference at(size_type idx) const
3925 {
3926 // at only works for arrays
3927 if (is_array())
3928 {
3929 JSON_TRY
3930 {
3931 return m_value.array->at(idx);
3932 }
3933 JSON_CATCH (std::out_of_range&)
3934 {
3935 // create better exception explanation
3936 JSON_THROW(out_of_range::create(401, "array index " + std::to_string(idx) + " is out of range"));
3937 }
3938 }
3939 else
3940 {
3941 JSON_THROW(type_error::create(304, "cannot use at() with " + type_name()));
3942 }
3943 }
3944
3945 /*!
3946 @brief access specified object element with bounds checking
3947
3948 Returns a reference to the element at with specified key @a key, with
3949 bounds checking.
3950
3951 @param[in] key key of the element to access
3952
3953 @return reference to the element at key @a key
3954
3955 @throw type_error.304 if the JSON value is not an object; in this case,
3956 calling `at` with a key makes no sense. See example below.
3957 @throw out_of_range.403 if the key @a key is is not stored in the object;
3958 that is, `find(key) == end()`. See example below.
3959
3960 @exceptionsafety Strong guarantee: if an exception is thrown, there are no
3961 changes in the JSON value.
3962
3963 @complexity Logarithmic in the size of the container.
3964
3965 @sa @ref operator[](const typename object_t::key_type&) for unchecked
3966 access by reference
3967 @sa @ref value() for access by value with a default value
3968
3969 @since version 1.0.0
3970
3971 @liveexample{The example below shows how object elements can be read and
3972 written using `at()`. It also demonstrates the different exceptions that
3973 can be thrown.,at__object_t_key_type}
3974 */
3975 reference at(const typename object_t::key_type& key)
3976 {
3977 // at only works for objects
3978 if (is_object())
3979 {
3980 JSON_TRY
3981 {
3982 return m_value.object->at(key);
3983 }
3984 JSON_CATCH (std::out_of_range&)
3985 {
3986 // create better exception explanation
3987 JSON_THROW(out_of_range::create(403, "key '" + key + "' not found"));
3988 }
3989 }
3990 else
3991 {
3992 JSON_THROW(type_error::create(304, "cannot use at() with " + type_name()));
3993 }
3994 }
3995
3996 /*!
3997 @brief access specified object element with bounds checking
3998
3999 Returns a const reference to the element at with specified key @a key,
4000 with bounds checking.
4001
4002 @param[in] key key of the element to access
4003
4004 @return const reference to the element at key @a key
4005
4006 @throw type_error.304 if the JSON value is not an object; in this case,
4007 calling `at` with a key makes no sense. See example below.
4008 @throw out_of_range.403 if the key @a key is is not stored in the object;
4009 that is, `find(key) == end()`. See example below.
4010
4011 @exceptionsafety Strong guarantee: if an exception is thrown, there are no
4012 changes in the JSON value.
4013
4014 @complexity Logarithmic in the size of the container.
4015
4016 @sa @ref operator[](const typename object_t::key_type&) for unchecked
4017 access by reference
4018 @sa @ref value() for access by value with a default value
4019
4020 @since version 1.0.0
4021
4022 @liveexample{The example below shows how object elements can be read using
4023 `at()`. It also demonstrates the different exceptions that can be thrown.,
4024 at__object_t_key_type_const}
4025 */
4026 const_reference at(const typename object_t::key_type& key) const
4027 {
4028 // at only works for objects
4029 if (is_object())
4030 {
4031 JSON_TRY
4032 {
4033 return m_value.object->at(key);
4034 }
4035 JSON_CATCH (std::out_of_range&)
4036 {
4037 // create better exception explanation
4038 JSON_THROW(out_of_range::create(403, "key '" + key + "' not found"));
4039 }
4040 }
4041 else
4042 {
4043 JSON_THROW(type_error::create(304, "cannot use at() with " + type_name()));
4044 }
4045 }
4046
4047 /*!
4048 @brief access specified array element
4049
4050 Returns a reference to the element at specified location @a idx.
4051
4052 @note If @a idx is beyond the range of the array (i.e., `idx >= size()`),
4053 then the array is silently filled up with `null` values to make `idx` a
4054 valid reference to the last stored element.
4055
4056 @param[in] idx index of the element to access
4057
4058 @return reference to the element at index @a idx
4059
4060 @throw type_error.305 if the JSON value is not an array or null; in that
4061 cases, using the [] operator with an index makes no sense.
4062
4063 @complexity Constant if @a idx is in the range of the array. Otherwise
4064 linear in `idx - size()`.
4065
4066 @liveexample{The example below shows how array elements can be read and
4067 written using `[]` operator. Note the addition of `null`
4068 values.,operatorarray__size_type}
4069
4070 @since version 1.0.0
4071 */
4072 reference operator[](size_type idx)
4073 {
4074 // implicitly convert null value to an empty array
4075 if (is_null())
4076 {
4077 m_type = value_t::array;
4078 m_value.array = create<array_t>();
4079 assert_invariant();
4080 }
4081
4082 // operator[] only works for arrays
4083 if (is_array())
4084 {
4085 // fill up array with null values if given idx is outside range
4086 if (idx >= m_value.array->size())
4087 {
4088 m_value.array->insert(m_value.array->end(),
4089 idx - m_value.array->size() + 1,
4090 basic_json());
4091 }
4092
4093 return m_value.array->operator[](idx);
4094 }
4095
4096 JSON_THROW(type_error::create(305, "cannot use operator[] with " + type_name()));
4097 }
4098
4099 /*!
4100 @brief access specified array element
4101
4102 Returns a const reference to the element at specified location @a idx.
4103
4104 @param[in] idx index of the element to access
4105
4106 @return const reference to the element at index @a idx
4107
4108 @throw type_error.305 if the JSON value is not an array; in that cases,
4109 using the [] operator with an index makes no sense.
4110
4111 @complexity Constant.
4112
4113 @liveexample{The example below shows how array elements can be read using
4114 the `[]` operator.,operatorarray__size_type_const}
4115
4116 @since version 1.0.0
4117 */
4118 const_reference operator[](size_type idx) const
4119 {
4120 // const operator[] only works for arrays
4121 if (is_array())
4122 {
4123 return m_value.array->operator[](idx);
4124 }
4125
4126 JSON_THROW(type_error::create(305, "cannot use operator[] with " + type_name()));
4127 }
4128
4129 /*!
4130 @brief access specified object element
4131
4132 Returns a reference to the element at with specified key @a key.
4133
4134 @note If @a key is not found in the object, then it is silently added to
4135 the object and filled with a `null` value to make `key` a valid reference.
4136 In case the value was `null` before, it is converted to an object.
4137
4138 @param[in] key key of the element to access
4139
4140 @return reference to the element at key @a key
4141
4142 @throw type_error.305 if the JSON value is not an object or null; in that
4143 cases, using the [] operator with a key makes no sense.
4144
4145 @complexity Logarithmic in the size of the container.
4146
4147 @liveexample{The example below shows how object elements can be read and
4148 written using the `[]` operator.,operatorarray__key_type}
4149
4150 @sa @ref at(const typename object_t::key_type&) for access by reference
4151 with range checking
4152 @sa @ref value() for access by value with a default value
4153
4154 @since version 1.0.0
4155 */
4156 reference operator[](const typename object_t::key_type& key)
4157 {
4158 // implicitly convert null value to an empty object
4159 if (is_null())
4160 {
4161 m_type = value_t::object;
4162 m_value.object = create<object_t>();
4163 assert_invariant();
4164 }
4165
4166 // operator[] only works for objects
4167 if (is_object())
4168 {
4169 return m_value.object->operator[](key);
4170 }
4171
4172 JSON_THROW(type_error::create(305, "cannot use operator[] with " + type_name()));
4173 }
4174
4175 /*!
4176 @brief read-only access specified object element
4177
4178 Returns a const reference to the element at with specified key @a key. No
4179 bounds checking is performed.
4180
4181 @warning If the element with key @a key does not exist, the behavior is
4182 undefined.
4183
4184 @param[in] key key of the element to access
4185
4186 @return const reference to the element at key @a key
4187
4188 @pre The element with key @a key must exist. **This precondition is
4189 enforced with an assertion.**
4190
4191 @throw type_error.305 if the JSON value is not an object; in that cases,
4192 using the [] operator with a key makes no sense.
4193
4194 @complexity Logarithmic in the size of the container.
4195
4196 @liveexample{The example below shows how object elements can be read using
4197 the `[]` operator.,operatorarray__key_type_const}
4198
4199 @sa @ref at(const typename object_t::key_type&) for access by reference
4200 with range checking
4201 @sa @ref value() for access by value with a default value
4202
4203 @since version 1.0.0
4204 */
4205 const_reference operator[](const typename object_t::key_type& key) const
4206 {
4207 // const operator[] only works for objects
4208 if (is_object())
4209 {
4210 assert(m_value.object->find(key) != m_value.object->end());
4211 return m_value.object->find(key)->second;
4212 }
4213
4214 JSON_THROW(type_error::create(305, "cannot use operator[] with " + type_name()));
4215 }
4216
4217 /*!
4218 @brief access specified object element
4219
4220 Returns a reference to the element at with specified key @a key.
4221
4222 @note If @a key is not found in the object, then it is silently added to
4223 the object and filled with a `null` value to make `key` a valid reference.
4224 In case the value was `null` before, it is converted to an object.
4225
4226 @param[in] key key of the element to access
4227
4228 @return reference to the element at key @a key
4229
4230 @throw type_error.305 if the JSON value is not an object or null; in that
4231 cases, using the [] operator with a key makes no sense.
4232
4233 @complexity Logarithmic in the size of the container.
4234
4235 @liveexample{The example below shows how object elements can be read and
4236 written using the `[]` operator.,operatorarray__key_type}
4237
4238 @sa @ref at(const typename object_t::key_type&) for access by reference
4239 with range checking
4240 @sa @ref value() for access by value with a default value
4241
4242 @since version 1.1.0
4243 */
4244 template<typename T>
4245 reference operator[](T* key)
4246 {
4247 // implicitly convert null to object
4248 if (is_null())
4249 {
4250 m_type = value_t::object;
4251 m_value = value_t::object;
4252 assert_invariant();
4253 }
4254
4255 // at only works for objects
4256 if (is_object())
4257 {
4258 return m_value.object->operator[](key);
4259 }
4260
4261 JSON_THROW(type_error::create(305, "cannot use operator[] with " + type_name()));
4262 }
4263
4264 /*!
4265 @brief read-only access specified object element
4266
4267 Returns a const reference to the element at with specified key @a key. No
4268 bounds checking is performed.
4269
4270 @warning If the element with key @a key does not exist, the behavior is
4271 undefined.
4272
4273 @param[in] key key of the element to access
4274
4275 @return const reference to the element at key @a key
4276
4277 @pre The element with key @a key must exist. **This precondition is
4278 enforced with an assertion.**
4279
4280 @throw type_error.305 if the JSON value is not an object; in that cases,
4281 using the [] operator with a key makes no sense.
4282
4283 @complexity Logarithmic in the size of the container.
4284
4285 @liveexample{The example below shows how object elements can be read using
4286 the `[]` operator.,operatorarray__key_type_const}
4287
4288 @sa @ref at(const typename object_t::key_type&) for access by reference
4289 with range checking
4290 @sa @ref value() for access by value with a default value
4291
4292 @since version 1.1.0
4293 */
4294 template<typename T>
4295 const_reference operator[](T* key) const
4296 {
4297 // at only works for objects
4298 if (is_object())
4299 {
4300 assert(m_value.object->find(key) != m_value.object->end());
4301 return m_value.object->find(key)->second;
4302 }
4303
4304 JSON_THROW(type_error::create(305, "cannot use operator[] with " + type_name()));
4305 }
4306
4307 /*!
4308 @brief access specified object element with default value
4309
4310 Returns either a copy of an object's element at the specified key @a key
4311 or a given default value if no element with key @a key exists.
4312
4313 The function is basically equivalent to executing
4314 @code {.cpp}
4315 try {
4316 return at(key);
4317 } catch(out_of_range) {
4318 return default_value;
4319 }
4320 @endcode
4321
4322 @note Unlike @ref at(const typename object_t::key_type&), this function
4323 does not throw if the given key @a key was not found.
4324
4325 @note Unlike @ref operator[](const typename object_t::key_type& key), this
4326 function does not implicitly add an element to the position defined by @a
4327 key. This function is furthermore also applicable to const objects.
4328
4329 @param[in] key key of the element to access
4330 @param[in] default_value the value to return if @a key is not found
4331
4332 @tparam ValueType type compatible to JSON values, for instance `int` for
4333 JSON integer numbers, `bool` for JSON booleans, or `std::vector` types for
4334 JSON arrays. Note the type of the expected value at @a key and the default
4335 value @a default_value must be compatible.
4336
4337 @return copy of the element at key @a key or @a default_value if @a key
4338 is not found
4339
4340 @throw type_error.306 if the JSON value is not an objec; in that cases,
4341 using `value()` with a key makes no sense.
4342
4343 @complexity Logarithmic in the size of the container.
4344
4345 @liveexample{The example below shows how object elements can be queried
4346 with a default value.,basic_json__value}
4347
4348 @sa @ref at(const typename object_t::key_type&) for access by reference
4349 with range checking
4350 @sa @ref operator[](const typename object_t::key_type&) for unchecked
4351 access by reference
4352
4353 @since version 1.0.0
4354 */
4355 template<class ValueType, typename std::enable_if<
4356 std::is_convertible<basic_json_t, ValueType>::value, int>::type = 0>
4357 ValueType value(const typename object_t::key_type& key, ValueType default_value) const
4358 {
4359 // at only works for objects
4360 if (is_object())
4361 {
4362 // if key is found, return value and given default value otherwise
4363 const auto it = find(key);
4364 if (it != end())
4365 {
4366 return *it;
4367 }
4368
4369 return default_value;
4370 }
4371 else
4372 {
4373 JSON_THROW(type_error::create(306, "cannot use value() with " + type_name()));
4374 }
4375 }
4376
4377 /*!
4378 @brief overload for a default value of type const char*
4379 @copydoc basic_json::value(const typename object_t::key_type&, ValueType) const
4380 */
4381 string_t value(const typename object_t::key_type& key, const char* default_value) const
4382 {
4383 return value(key, string_t(default_value));
4384 }
4385
4386 /*!
4387 @brief access specified object element via JSON Pointer with default value
4388
4389 Returns either a copy of an object's element at the specified key @a key
4390 or a given default value if no element with key @a key exists.
4391
4392 The function is basically equivalent to executing
4393 @code {.cpp}
4394 try {
4395 return at(ptr);
4396 } catch(out_of_range) {
4397 return default_value;
4398 }
4399 @endcode
4400
4401 @note Unlike @ref at(const json_pointer&), this function does not throw
4402 if the given key @a key was not found.
4403
4404 @param[in] ptr a JSON pointer to the element to access
4405 @param[in] default_value the value to return if @a ptr found no value
4406
4407 @tparam ValueType type compatible to JSON values, for instance `int` for
4408 JSON integer numbers, `bool` for JSON booleans, or `std::vector` types for
4409 JSON arrays. Note the type of the expected value at @a key and the default
4410 value @a default_value must be compatible.
4411
4412 @return copy of the element at key @a key or @a default_value if @a key
4413 is not found
4414
4415 @throw type_error.306 if the JSON value is not an objec; in that cases,
4416 using `value()` with a key makes no sense.
4417
4418 @complexity Logarithmic in the size of the container.
4419
4420 @liveexample{The example below shows how object elements can be queried
4421 with a default value.,basic_json__value_ptr}
4422
4423 @sa @ref operator[](const json_pointer&) for unchecked access by reference
4424
4425 @since version 2.0.2
4426 */
4427 template<class ValueType, typename std::enable_if<
4428 std::is_convertible<basic_json_t, ValueType>::value, int>::type = 0>
4429 ValueType value(const json_pointer& ptr, ValueType default_value) const
4430 {
4431 // at only works for objects
4432 if (is_object())
4433 {
4434 // if pointer resolves a value, return it or use default value
4435 JSON_TRY
4436 {
4437 return ptr.get_checked(this);
4438 }
4439 JSON_CATCH (out_of_range&)
4440 {
4441 return default_value;
4442 }
4443 }
4444
4445 JSON_THROW(type_error::create(306, "cannot use value() with " + type_name()));
4446 }
4447
4448 /*!
4449 @brief overload for a default value of type const char*
4450 @copydoc basic_json::value(const json_pointer&, ValueType) const
4451 */
4452 string_t value(const json_pointer& ptr, const char* default_value) const
4453 {
4454 return value(ptr, string_t(default_value));
4455 }
4456
4457 /*!
4458 @brief access the first element
4459
4460 Returns a reference to the first element in the container. For a JSON
4461 container `c`, the expression `c.front()` is equivalent to `*c.begin()`.
4462
4463 @return In case of a structured type (array or object), a reference to the
4464 first element is returned. In case of number, string, or boolean values, a
4465 reference to the value is returned.
4466
4467 @complexity Constant.
4468
4469 @pre The JSON value must not be `null` (would throw `std::out_of_range`)
4470 or an empty array or object (undefined behavior, **guarded by
4471 assertions**).
4472 @post The JSON value remains unchanged.
4473
4474 @throw invalid_iterator.214 when called on `null` value
4475
4476 @liveexample{The following code shows an example for `front()`.,front}
4477
4478 @sa @ref back() -- access the last element
4479
4480 @since version 1.0.0
4481 */
4482 reference front()
4483 {
4484 return *begin();
4485 }
4486
4487 /*!
4488 @copydoc basic_json::front()
4489 */
4490 const_reference front() const
4491 {
4492 return *cbegin();
4493 }
4494
4495 /*!
4496 @brief access the last element
4497
4498 Returns a reference to the last element in the container. For a JSON
4499 container `c`, the expression `c.back()` is equivalent to
4500 @code {.cpp}
4501 auto tmp = c.end();
4502 --tmp;
4503 return *tmp;
4504 @endcode
4505
4506 @return In case of a structured type (array or object), a reference to the
4507 last element is returned. In case of number, string, or boolean values, a
4508 reference to the value is returned.
4509
4510 @complexity Constant.
4511
4512 @pre The JSON value must not be `null` (would throw `std::out_of_range`)
4513 or an empty array or object (undefined behavior, **guarded by
4514 assertions**).
4515 @post The JSON value remains unchanged.
4516
4517 @throw invalid_iterator.214 when called on a `null` value. See example
4518 below.
4519
4520 @liveexample{The following code shows an example for `back()`.,back}
4521
4522 @sa @ref front() -- access the first element
4523
4524 @since version 1.0.0
4525 */
4526 reference back()
4527 {
4528 auto tmp = end();
4529 --tmp;
4530 return *tmp;
4531 }
4532
4533 /*!
4534 @copydoc basic_json::back()
4535 */
4536 const_reference back() const
4537 {
4538 auto tmp = cend();
4539 --tmp;
4540 return *tmp;
4541 }
4542
4543 /*!
4544 @brief remove element given an iterator
4545
4546 Removes the element specified by iterator @a pos. The iterator @a pos must
4547 be valid and dereferenceable. Thus the `end()` iterator (which is valid,
4548 but is not dereferenceable) cannot be used as a value for @a pos.
4549
4550 If called on a primitive type other than `null`, the resulting JSON value
4551 will be `null`.
4552
4553 @param[in] pos iterator to the element to remove
4554 @return Iterator following the last removed element. If the iterator @a
4555 pos refers to the last element, the `end()` iterator is returned.
4556
4557 @tparam IteratorType an @ref iterator or @ref const_iterator
4558
4559 @post Invalidates iterators and references at or after the point of the
4560 erase, including the `end()` iterator.
4561
4562 @throw type_error.307 if called on a `null` value; example: `"cannot use
4563 erase() with null"`
4564 @throw invalid_iterator.202 if called on an iterator which does not belong
4565 to the current JSON value; example: `"iterator does not fit current
4566 value"`
4567 @throw invalid_iterator.205 if called on a primitive type with invalid
4568 iterator (i.e., any iterator which is not `begin()`); example: `"iterator
4569 out of range"`
4570
4571 @complexity The complexity depends on the type:
4572 - objects: amortized constant
4573 - arrays: linear in distance between @a pos and the end of the container
4574 - strings: linear in the length of the string
4575 - other types: constant
4576
4577 @liveexample{The example shows the result of `erase()` for different JSON
4578 types.,erase__IteratorType}
4579
4580 @sa @ref erase(IteratorType, IteratorType) -- removes the elements in
4581 the given range
4582 @sa @ref erase(const typename object_t::key_type&) -- removes the element
4583 from an object at the given key
4584 @sa @ref erase(const size_type) -- removes the element from an array at
4585 the given index
4586
4587 @since version 1.0.0
4588 */
4589 template<class IteratorType, typename std::enable_if<
4590 std::is_same<IteratorType, typename basic_json_t::iterator>::value or
4591 std::is_same<IteratorType, typename basic_json_t::const_iterator>::value, int>::type
4592 = 0>
4593 IteratorType erase(IteratorType pos)
4594 {
4595 // make sure iterator fits the current value
4596 if (this != pos.m_object)
4597 {
4598 JSON_THROW(invalid_iterator::create(202, "iterator does not fit current value"));
4599 }
4600
4601 IteratorType result = end();
4602
4603 switch (m_type)
4604 {
4605 case value_t::boolean:
4606 case value_t::number_float:
4607 case value_t::number_integer:
4608 case value_t::number_unsigned:
4609 case value_t::string:
4610 {
4611 if (not pos.m_it.primitive_iterator.is_begin())
4612 {
4613 JSON_THROW(invalid_iterator::create(205, "iterator out of range"));
4614 }
4615
4616 if (is_string())
4617 {
4618 AllocatorType<string_t> alloc;
4619 alloc.destroy(m_value.string);
4620 alloc.deallocate(m_value.string, 1);
4621 m_value.string = nullptr;
4622 }
4623
4624 m_type = value_t::null;
4625 assert_invariant();
4626 break;
4627 }
4628
4629 case value_t::object:
4630 {
4631 result.m_it.object_iterator = m_value.object->erase(pos.m_it.object_iterator);
4632 break;
4633 }
4634
4635 case value_t::array:
4636 {
4637 result.m_it.array_iterator = m_value.array->erase(pos.m_it.array_iterator);
4638 break;
4639 }
4640
4641 default:
4642 {
4643 JSON_THROW(type_error::create(307, "cannot use erase() with " + type_name()));
4644 }
4645 }
4646
4647 return result;
4648 }
4649
4650 /*!
4651 @brief remove elements given an iterator range
4652
4653 Removes the element specified by the range `[first; last)`. The iterator
4654 @a first does not need to be dereferenceable if `first == last`: erasing
4655 an empty range is a no-op.
4656
4657 If called on a primitive type other than `null`, the resulting JSON value
4658 will be `null`.
4659
4660 @param[in] first iterator to the beginning of the range to remove
4661 @param[in] last iterator past the end of the range to remove
4662 @return Iterator following the last removed element. If the iterator @a
4663 second refers to the last element, the `end()` iterator is returned.
4664
4665 @tparam IteratorType an @ref iterator or @ref const_iterator
4666
4667 @post Invalidates iterators and references at or after the point of the
4668 erase, including the `end()` iterator.
4669
4670 @throw type_error.307 if called on a `null` value; example: `"cannot use
4671 erase() with null"`
4672 @throw invalid_iterator.203 if called on iterators which does not belong
4673 to the current JSON value; example: `"iterators do not fit current value"`
4674 @throw invalid_iterator.204 if called on a primitive type with invalid
4675 iterators (i.e., if `first != begin()` and `last != end()`); example:
4676 `"iterators out of range"`
4677
4678 @complexity The complexity depends on the type:
4679 - objects: `log(size()) + std::distance(first, last)`
4680 - arrays: linear in the distance between @a first and @a last, plus linear
4681 in the distance between @a last and end of the container
4682 - strings: linear in the length of the string
4683 - other types: constant
4684
4685 @liveexample{The example shows the result of `erase()` for different JSON
4686 types.,erase__IteratorType_IteratorType}
4687
4688 @sa @ref erase(IteratorType) -- removes the element at a given position
4689 @sa @ref erase(const typename object_t::key_type&) -- removes the element
4690 from an object at the given key
4691 @sa @ref erase(const size_type) -- removes the element from an array at
4692 the given index
4693
4694 @since version 1.0.0
4695 */
4696 template<class IteratorType, typename std::enable_if<
4697 std::is_same<IteratorType, typename basic_json_t::iterator>::value or
4698 std::is_same<IteratorType, typename basic_json_t::const_iterator>::value, int>::type
4699 = 0>
4700 IteratorType erase(IteratorType first, IteratorType last)
4701 {
4702 // make sure iterator fits the current value
4703 if (this != first.m_object or this != last.m_object)
4704 {
4705 JSON_THROW(invalid_iterator::create(203, "iterators do not fit current value"));
4706 }
4707
4708 IteratorType result = end();
4709
4710 switch (m_type)
4711 {
4712 case value_t::boolean:
4713 case value_t::number_float:
4714 case value_t::number_integer:
4715 case value_t::number_unsigned:
4716 case value_t::string:
4717 {
4718 if (not first.m_it.primitive_iterator.is_begin() or not last.m_it.primitive_iterator.is_end())
4719 {
4720 JSON_THROW(invalid_iterator::create(204, "iterators out of range"));
4721 }
4722
4723 if (is_string())
4724 {
4725 AllocatorType<string_t> alloc;
4726 alloc.destroy(m_value.string);
4727 alloc.deallocate(m_value.string, 1);
4728 m_value.string = nullptr;
4729 }
4730
4731 m_type = value_t::null;
4732 assert_invariant();
4733 break;
4734 }
4735
4736 case value_t::object:
4737 {
4738 result.m_it.object_iterator = m_value.object->erase(first.m_it.object_iterator,
4739 last.m_it.object_iterator);
4740 break;
4741 }
4742
4743 case value_t::array:
4744 {
4745 result.m_it.array_iterator = m_value.array->erase(first.m_it.array_iterator,
4746 last.m_it.array_iterator);
4747 break;
4748 }
4749
4750 default:
4751 {
4752 JSON_THROW(type_error::create(307, "cannot use erase() with " + type_name()));
4753 }
4754 }
4755
4756 return result;
4757 }
4758
4759 /*!
4760 @brief remove element from a JSON object given a key
4761
4762 Removes elements from a JSON object with the key value @a key.
4763
4764 @param[in] key value of the elements to remove
4765
4766 @return Number of elements removed. If @a ObjectType is the default
4767 `std::map` type, the return value will always be `0` (@a key was not
4768 found) or `1` (@a key was found).
4769
4770 @post References and iterators to the erased elements are invalidated.
4771 Other references and iterators are not affected.
4772
4773 @throw type_error.307 when called on a type other than JSON object;
4774 example: `"cannot use erase() with null"`
4775
4776 @complexity `log(size()) + count(key)`
4777
4778 @liveexample{The example shows the effect of `erase()`.,erase__key_type}
4779
4780 @sa @ref erase(IteratorType) -- removes the element at a given position
4781 @sa @ref erase(IteratorType, IteratorType) -- removes the elements in
4782 the given range
4783 @sa @ref erase(const size_type) -- removes the element from an array at
4784 the given index
4785
4786 @since version 1.0.0
4787 */
4788 size_type erase(const typename object_t::key_type& key)
4789 {
4790 // this erase only works for objects
4791 if (is_object())
4792 {
4793 return m_value.object->erase(key);
4794 }
4795
4796 JSON_THROW(type_error::create(307, "cannot use erase() with " + type_name()));
4797 }
4798
4799 /*!
4800 @brief remove element from a JSON array given an index
4801
4802 Removes element from a JSON array at the index @a idx.
4803
4804 @param[in] idx index of the element to remove
4805
4806 @throw type_error.307 when called on a type other than JSON object;
4807 example: `"cannot use erase() with null"`
4808 @throw out_of_range.401 when `idx >= size()`; example: `"array index 17
4809 is out of range"`
4810
4811 @complexity Linear in distance between @a idx and the end of the container.
4812
4813 @liveexample{The example shows the effect of `erase()`.,erase__size_type}
4814
4815 @sa @ref erase(IteratorType) -- removes the element at a given position
4816 @sa @ref erase(IteratorType, IteratorType) -- removes the elements in
4817 the given range
4818 @sa @ref erase(const typename object_t::key_type&) -- removes the element
4819 from an object at the given key
4820
4821 @since version 1.0.0
4822 */
4823 void erase(const size_type idx)
4824 {
4825 // this erase only works for arrays
4826 if (is_array())
4827 {
4828 if (idx >= size())
4829 {
4830 JSON_THROW(out_of_range::create(401, "array index " + std::to_string(idx) + " is out of range"));
4831 }
4832
4833 m_value.array->erase(m_value.array->begin() + static_cast<difference_type>(idx));
4834 }
4835 else
4836 {
4837 JSON_THROW(type_error::create(307, "cannot use erase() with " + type_name()));
4838 }
4839 }
4840
4841 /// @}
4842
4843
4844 ////////////
4845 // lookup //
4846 ////////////
4847
4848 /// @name lookup
4849 /// @{
4850
4851 /*!
4852 @brief find an element in a JSON object
4853
4854 Finds an element in a JSON object with key equivalent to @a key. If the
4855 element is not found or the JSON value is not an object, end() is
4856 returned.
4857
4858 @note This method always returns @ref end() when executed on a JSON type
4859 that is not an object.
4860
4861 @param[in] key key value of the element to search for
4862
4863 @return Iterator to an element with key equivalent to @a key. If no such
4864 element is found or the JSON value is not an object, past-the-end (see
4865 @ref end()) iterator is returned.
4866
4867 @complexity Logarithmic in the size of the JSON object.
4868
4869 @liveexample{The example shows how `find()` is used.,find__key_type}
4870
4871 @since version 1.0.0
4872 */
4873 iterator find(typename object_t::key_type key)
4874 {
4875 auto result = end();
4876
4877 if (is_object())
4878 {
4879 result.m_it.object_iterator = m_value.object->find(key);
4880 }
4881
4882 return result;
4883 }
4884
4885 /*!
4886 @brief find an element in a JSON object
4887 @copydoc find(typename object_t::key_type)
4888 */
4889 const_iterator find(typename object_t::key_type key) const
4890 {
4891 auto result = cend();
4892
4893 if (is_object())
4894 {
4895 result.m_it.object_iterator = m_value.object->find(key);
4896 }
4897
4898 return result;
4899 }
4900
4901 /*!
4902 @brief returns the number of occurrences of a key in a JSON object
4903
4904 Returns the number of elements with key @a key. If ObjectType is the
4905 default `std::map` type, the return value will always be `0` (@a key was
4906 not found) or `1` (@a key was found).
4907
4908 @note This method always returns `0` when executed on a JSON type that is
4909 not an object.
4910
4911 @param[in] key key value of the element to count
4912
4913 @return Number of elements with key @a key. If the JSON value is not an
4914 object, the return value will be `0`.
4915
4916 @complexity Logarithmic in the size of the JSON object.
4917
4918 @liveexample{The example shows how `count()` is used.,count}
4919
4920 @since version 1.0.0
4921 */
4922 size_type count(typename object_t::key_type key) const
4923 {
4924 // return 0 for all nonobject types
4925 return is_object() ? m_value.object->count(key) : 0;
4926 }
4927
4928 /// @}
4929
4930
4931 ///////////////
4932 // iterators //
4933 ///////////////
4934
4935 /// @name iterators
4936 /// @{
4937
4938 /*!
4939 @brief returns an iterator to the first element
4940
4941 Returns an iterator to the first element.
4942
4943 @image html range-begin-end.svg "Illustration from cppreference.com"
4944
4945 @return iterator to the first element
4946
4947 @complexity Constant.
4948
4949 @requirement This function helps `basic_json` satisfying the
4950 [Container](http://en.cppreference.com/w/cpp/concept/Container)
4951 requirements:
4952 - The complexity is constant.
4953
4954 @liveexample{The following code shows an example for `begin()`.,begin}
4955
4956 @sa @ref cbegin() -- returns a const iterator to the beginning
4957 @sa @ref end() -- returns an iterator to the end
4958 @sa @ref cend() -- returns a const iterator to the end
4959
4960 @since version 1.0.0
4961 */
4962 iterator begin() noexcept
4963 {
4964 iterator result(this);
4965 result.set_begin();
4966 return result;
4967 }
4968
4969 /*!
4970 @copydoc basic_json::cbegin()
4971 */
4972 const_iterator begin() const noexcept
4973 {
4974 return cbegin();
4975 }
4976
4977 /*!
4978 @brief returns a const iterator to the first element
4979
4980 Returns a const iterator to the first element.
4981
4982 @image html range-begin-end.svg "Illustration from cppreference.com"
4983
4984 @return const iterator to the first element
4985
4986 @complexity Constant.
4987
4988 @requirement This function helps `basic_json` satisfying the
4989 [Container](http://en.cppreference.com/w/cpp/concept/Container)
4990 requirements:
4991 - The complexity is constant.
4992 - Has the semantics of `const_cast<const basic_json&>(*this).begin()`.
4993
4994 @liveexample{The following code shows an example for `cbegin()`.,cbegin}
4995
4996 @sa @ref begin() -- returns an iterator to the beginning
4997 @sa @ref end() -- returns an iterator to the end
4998 @sa @ref cend() -- returns a const iterator to the end
4999
5000 @since version 1.0.0
5001 */
5002 const_iterator cbegin() const noexcept
5003 {
5004 const_iterator result(this);
5005 result.set_begin();
5006 return result;
5007 }
5008
5009 /*!
5010 @brief returns an iterator to one past the last element
5011
5012 Returns an iterator to one past the last element.
5013
5014 @image html range-begin-end.svg "Illustration from cppreference.com"
5015
5016 @return iterator one past the last element
5017
5018 @complexity Constant.
5019
5020 @requirement This function helps `basic_json` satisfying the
5021 [Container](http://en.cppreference.com/w/cpp/concept/Container)
5022 requirements:
5023 - The complexity is constant.
5024
5025 @liveexample{The following code shows an example for `end()`.,end}
5026
5027 @sa @ref cend() -- returns a const iterator to the end
5028 @sa @ref begin() -- returns an iterator to the beginning
5029 @sa @ref cbegin() -- returns a const iterator to the beginning
5030
5031 @since version 1.0.0
5032 */
5033 iterator end() noexcept
5034 {
5035 iterator result(this);
5036 result.set_end();
5037 return result;
5038 }
5039
5040 /*!
5041 @copydoc basic_json::cend()
5042 */
5043 const_iterator end() const noexcept
5044 {
5045 return cend();
5046 }
5047
5048 /*!
5049 @brief returns a const iterator to one past the last element
5050
5051 Returns a const iterator to one past the last element.
5052
5053 @image html range-begin-end.svg "Illustration from cppreference.com"
5054
5055 @return const iterator one past the last element
5056
5057 @complexity Constant.
5058
5059 @requirement This function helps `basic_json` satisfying the
5060 [Container](http://en.cppreference.com/w/cpp/concept/Container)
5061 requirements:
5062 - The complexity is constant.
5063 - Has the semantics of `const_cast<const basic_json&>(*this).end()`.
5064
5065 @liveexample{The following code shows an example for `cend()`.,cend}
5066
5067 @sa @ref end() -- returns an iterator to the end
5068 @sa @ref begin() -- returns an iterator to the beginning
5069 @sa @ref cbegin() -- returns a const iterator to the beginning
5070
5071 @since version 1.0.0
5072 */
5073 const_iterator cend() const noexcept
5074 {
5075 const_iterator result(this);
5076 result.set_end();
5077 return result;
5078 }
5079
5080 /*!
5081 @brief returns an iterator to the reverse-beginning
5082
5083 Returns an iterator to the reverse-beginning; that is, the last element.
5084
5085 @image html range-rbegin-rend.svg "Illustration from cppreference.com"
5086
5087 @complexity Constant.
5088
5089 @requirement This function helps `basic_json` satisfying the
5090 [ReversibleContainer](http://en.cppreference.com/w/cpp/concept/ReversibleContainer)
5091 requirements:
5092 - The complexity is constant.
5093 - Has the semantics of `reverse_iterator(end())`.
5094
5095 @liveexample{The following code shows an example for `rbegin()`.,rbegin}
5096
5097 @sa @ref crbegin() -- returns a const reverse iterator to the beginning
5098 @sa @ref rend() -- returns a reverse iterator to the end
5099 @sa @ref crend() -- returns a const reverse iterator to the end
5100
5101 @since version 1.0.0
5102 */
5103 reverse_iterator rbegin() noexcept
5104 {
5105 return reverse_iterator(end());
5106 }
5107
5108 /*!
5109 @copydoc basic_json::crbegin()
5110 */
5111 const_reverse_iterator rbegin() const noexcept
5112 {
5113 return crbegin();
5114 }
5115
5116 /*!
5117 @brief returns an iterator to the reverse-end
5118
5119 Returns an iterator to the reverse-end; that is, one before the first
5120 element.
5121
5122 @image html range-rbegin-rend.svg "Illustration from cppreference.com"
5123
5124 @complexity Constant.
5125
5126 @requirement This function helps `basic_json` satisfying the
5127 [ReversibleContainer](http://en.cppreference.com/w/cpp/concept/ReversibleContainer)
5128 requirements:
5129 - The complexity is constant.
5130 - Has the semantics of `reverse_iterator(begin())`.
5131
5132 @liveexample{The following code shows an example for `rend()`.,rend}
5133
5134 @sa @ref crend() -- returns a const reverse iterator to the end
5135 @sa @ref rbegin() -- returns a reverse iterator to the beginning
5136 @sa @ref crbegin() -- returns a const reverse iterator to the beginning
5137
5138 @since version 1.0.0
5139 */
5140 reverse_iterator rend() noexcept
5141 {
5142 return reverse_iterator(begin());
5143 }
5144
5145 /*!
5146 @copydoc basic_json::crend()
5147 */
5148 const_reverse_iterator rend() const noexcept
5149 {
5150 return crend();
5151 }
5152
5153 /*!
5154 @brief returns a const reverse iterator to the last element
5155
5156 Returns a const iterator to the reverse-beginning; that is, the last
5157 element.
5158
5159 @image html range-rbegin-rend.svg "Illustration from cppreference.com"
5160
5161 @complexity Constant.
5162
5163 @requirement This function helps `basic_json` satisfying the
5164 [ReversibleContainer](http://en.cppreference.com/w/cpp/concept/ReversibleContainer)
5165 requirements:
5166 - The complexity is constant.
5167 - Has the semantics of `const_cast<const basic_json&>(*this).rbegin()`.
5168
5169 @liveexample{The following code shows an example for `crbegin()`.,crbegin}
5170
5171 @sa @ref rbegin() -- returns a reverse iterator to the beginning
5172 @sa @ref rend() -- returns a reverse iterator to the end
5173 @sa @ref crend() -- returns a const reverse iterator to the end
5174
5175 @since version 1.0.0
5176 */
5177 const_reverse_iterator crbegin() const noexcept
5178 {
5179 return const_reverse_iterator(cend());
5180 }
5181
5182 /*!
5183 @brief returns a const reverse iterator to one before the first
5184
5185 Returns a const reverse iterator to the reverse-end; that is, one before
5186 the first element.
5187
5188 @image html range-rbegin-rend.svg "Illustration from cppreference.com"
5189
5190 @complexity Constant.
5191
5192 @requirement This function helps `basic_json` satisfying the
5193 [ReversibleContainer](http://en.cppreference.com/w/cpp/concept/ReversibleContainer)
5194 requirements:
5195 - The complexity is constant.
5196 - Has the semantics of `const_cast<const basic_json&>(*this).rend()`.
5197
5198 @liveexample{The following code shows an example for `crend()`.,crend}
5199
5200 @sa @ref rend() -- returns a reverse iterator to the end
5201 @sa @ref rbegin() -- returns a reverse iterator to the beginning
5202 @sa @ref crbegin() -- returns a const reverse iterator to the beginning
5203
5204 @since version 1.0.0
5205 */
5206 const_reverse_iterator crend() const noexcept
5207 {
5208 return const_reverse_iterator(cbegin());
5209 }
5210
5211 private:
5212 // forward declaration
5213 template<typename IteratorType> class iteration_proxy;
5214
5215 public:
5216 /*!
5217 @brief wrapper to access iterator member functions in range-based for
5218
5219 This function allows to access @ref iterator::key() and @ref
5220 iterator::value() during range-based for loops. In these loops, a
5221 reference to the JSON values is returned, so there is no access to the
5222 underlying iterator.
5223
5224 @liveexample{The following code shows how the wrapper is used,iterator_wrapper}
5225
5226 @note The name of this function is not yet final and may change in the
5227 future.
5228 */
5229 static iteration_proxy<iterator> iterator_wrapper(reference cont)
5230 {
5231 return iteration_proxy<iterator>(cont);
5232 }
5233
5234 /*!
5235 @copydoc iterator_wrapper(reference)
5236 */
5237 static iteration_proxy<const_iterator> iterator_wrapper(const_reference cont)
5238 {
5239 return iteration_proxy<const_iterator>(cont);
5240 }
5241
5242 /// @}
5243
5244
5245 //////////////
5246 // capacity //
5247 //////////////
5248
5249 /// @name capacity
5250 /// @{
5251
5252 /*!
5253 @brief checks whether the container is empty
5254
5255 Checks if a JSON value has no elements.
5256
5257 @return The return value depends on the different types and is
5258 defined as follows:
5259 Value type | return value
5260 ----------- | -------------
5261 null | `true`
5262 boolean | `false`
5263 string | `false`
5264 number | `false`
5265 object | result of function `object_t::empty()`
5266 array | result of function `array_t::empty()`
5267
5268 @note This function does not return whether a string stored as JSON value
5269 is empty - it returns whether the JSON container itself is empty which is
5270 false in the case of a string.
5271
5272 @complexity Constant, as long as @ref array_t and @ref object_t satisfy
5273 the Container concept; that is, their `empty()` functions have constant
5274 complexity.
5275
5276 @requirement This function helps `basic_json` satisfying the
5277 [Container](http://en.cppreference.com/w/cpp/concept/Container)
5278 requirements:
5279 - The complexity is constant.
5280 - Has the semantics of `begin() == end()`.
5281
5282 @liveexample{The following code uses `empty()` to check if a JSON
5283 object contains any elements.,empty}
5284
5285 @sa @ref size() -- returns the number of elements
5286
5287 @since version 1.0.0
5288 */
5289 bool empty() const noexcept
5290 {
5291 switch (m_type)
5292 {
5293 case value_t::null:
5294 {
5295 // null values are empty
5296 return true;
5297 }
5298
5299 case value_t::array:
5300 {
5301 // delegate call to array_t::empty()
5302 return m_value.array->empty();
5303 }
5304
5305 case value_t::object:
5306 {
5307 // delegate call to object_t::empty()
5308 return m_value.object->empty();
5309 }
5310
5311 default:
5312 {
5313 // all other types are nonempty
5314 return false;
5315 }
5316 }
5317 }
5318
5319 /*!
5320 @brief returns the number of elements
5321
5322 Returns the number of elements in a JSON value.
5323
5324 @return The return value depends on the different types and is
5325 defined as follows:
5326 Value type | return value
5327 ----------- | -------------
5328 null | `0`
5329 boolean | `1`
5330 string | `1`
5331 number | `1`
5332 object | result of function object_t::size()
5333 array | result of function array_t::size()
5334
5335 @note This function does not return the length of a string stored as JSON
5336 value - it returns the number of elements in the JSON value which is 1 in
5337 the case of a string.
5338
5339 @complexity Constant, as long as @ref array_t and @ref object_t satisfy
5340 the Container concept; that is, their size() functions have constant
5341 complexity.
5342
5343 @requirement This function helps `basic_json` satisfying the
5344 [Container](http://en.cppreference.com/w/cpp/concept/Container)
5345 requirements:
5346 - The complexity is constant.
5347 - Has the semantics of `std::distance(begin(), end())`.
5348
5349 @liveexample{The following code calls `size()` on the different value
5350 types.,size}
5351
5352 @sa @ref empty() -- checks whether the container is empty
5353 @sa @ref max_size() -- returns the maximal number of elements
5354
5355 @since version 1.0.0
5356 */
5357 size_type size() const noexcept
5358 {
5359 switch (m_type)
5360 {
5361 case value_t::null:
5362 {
5363 // null values are empty
5364 return 0;
5365 }
5366
5367 case value_t::array:
5368 {
5369 // delegate call to array_t::size()
5370 return m_value.array->size();
5371 }
5372
5373 case value_t::object:
5374 {
5375 // delegate call to object_t::size()
5376 return m_value.object->size();
5377 }
5378
5379 default:
5380 {
5381 // all other types have size 1
5382 return 1;
5383 }
5384 }
5385 }
5386
5387 /*!
5388 @brief returns the maximum possible number of elements
5389
5390 Returns the maximum number of elements a JSON value is able to hold due to
5391 system or library implementation limitations, i.e. `std::distance(begin(),
5392 end())` for the JSON value.
5393
5394 @return The return value depends on the different types and is
5395 defined as follows:
5396 Value type | return value
5397 ----------- | -------------
5398 null | `0` (same as `size()`)
5399 boolean | `1` (same as `size()`)
5400 string | `1` (same as `size()`)
5401 number | `1` (same as `size()`)
5402 object | result of function `object_t::max_size()`
5403 array | result of function `array_t::max_size()`
5404
5405 @complexity Constant, as long as @ref array_t and @ref object_t satisfy
5406 the Container concept; that is, their `max_size()` functions have constant
5407 complexity.
5408
5409 @requirement This function helps `basic_json` satisfying the
5410 [Container](http://en.cppreference.com/w/cpp/concept/Container)
5411 requirements:
5412 - The complexity is constant.
5413 - Has the semantics of returning `b.size()` where `b` is the largest
5414 possible JSON value.
5415
5416 @liveexample{The following code calls `max_size()` on the different value
5417 types. Note the output is implementation specific.,max_size}
5418
5419 @sa @ref size() -- returns the number of elements
5420
5421 @since version 1.0.0
5422 */
5423 size_type max_size() const noexcept
5424 {
5425 switch (m_type)
5426 {
5427 case value_t::array:
5428 {
5429 // delegate call to array_t::max_size()
5430 return m_value.array->max_size();
5431 }
5432
5433 case value_t::object:
5434 {
5435 // delegate call to object_t::max_size()
5436 return m_value.object->max_size();
5437 }
5438
5439 default:
5440 {
5441 // all other types have max_size() == size()
5442 return size();
5443 }
5444 }
5445 }
5446
5447 /// @}
5448
5449
5450 ///////////////
5451 // modifiers //
5452 ///////////////
5453
5454 /// @name modifiers
5455 /// @{
5456
5457 /*!
5458 @brief clears the contents
5459
5460 Clears the content of a JSON value and resets it to the default value as
5461 if @ref basic_json(value_t) would have been called:
5462
5463 Value type | initial value
5464 ----------- | -------------
5465 null | `null`
5466 boolean | `false`
5467 string | `""`
5468 number | `0`
5469 object | `{}`
5470 array | `[]`
5471
5472 @complexity Linear in the size of the JSON value.
5473
5474 @liveexample{The example below shows the effect of `clear()` to different
5475 JSON types.,clear}
5476
5477 @since version 1.0.0
5478 */
5479 void clear() noexcept
5480 {
5481 switch (m_type)
5482 {
5483 case value_t::number_integer:
5484 {
5485 m_value.number_integer = 0;
5486 break;
5487 }
5488
5489 case value_t::number_unsigned:
5490 {
5491 m_value.number_unsigned = 0;
5492 break;
5493 }
5494
5495 case value_t::number_float:
5496 {
5497 m_value.number_float = 0.0;
5498 break;
5499 }
5500
5501 case value_t::boolean:
5502 {
5503 m_value.boolean = false;
5504 break;
5505 }
5506
5507 case value_t::string:
5508 {
5509 m_value.string->clear();
5510 break;
5511 }
5512
5513 case value_t::array:
5514 {
5515 m_value.array->clear();
5516 break;
5517 }
5518
5519 case value_t::object:
5520 {
5521 m_value.object->clear();
5522 break;
5523 }
5524
5525 default:
5526 {
5527 break;
5528 }
5529 }
5530 }
5531
5532 /*!
5533 @brief add an object to an array
5534
5535 Appends the given element @a val to the end of the JSON value. If the
5536 function is called on a JSON null value, an empty array is created before
5537 appending @a val.
5538
5539 @param[in] val the value to add to the JSON array
5540
5541 @throw type_error.308 when called on a type other than JSON array or
5542 null; example: `"cannot use push_back() with number"`
5543
5544 @complexity Amortized constant.
5545
5546 @liveexample{The example shows how `push_back()` and `+=` can be used to
5547 add elements to a JSON array. Note how the `null` value was silently
5548 converted to a JSON array.,push_back}
5549
5550 @since version 1.0.0
5551 */
5552 void push_back(basic_json&& val)
5553 {
5554 // push_back only works for null objects or arrays
5555 if (not(is_null() or is_array()))
5556 {
5557 JSON_THROW(type_error::create(308, "cannot use push_back() with " + type_name()));
5558 }
5559
5560 // transform null object into an array
5561 if (is_null())
5562 {
5563 m_type = value_t::array;
5564 m_value = value_t::array;
5565 assert_invariant();
5566 }
5567
5568 // add element to array (move semantics)
5569 m_value.array->push_back(std::move(val));
5570 // invalidate object
5571 val.m_type = value_t::null;
5572 }
5573
5574 /*!
5575 @brief add an object to an array
5576 @copydoc push_back(basic_json&&)
5577 */
5578 reference operator+=(basic_json&& val)
5579 {
5580 push_back(std::move(val));
5581 return *this;
5582 }
5583
5584 /*!
5585 @brief add an object to an array
5586 @copydoc push_back(basic_json&&)
5587 */
5588 void push_back(const basic_json& val)
5589 {
5590 // push_back only works for null objects or arrays
5591 if (not(is_null() or is_array()))
5592 {
5593 JSON_THROW(type_error::create(308, "cannot use push_back() with " + type_name()));
5594 }
5595
5596 // transform null object into an array
5597 if (is_null())
5598 {
5599 m_type = value_t::array;
5600 m_value = value_t::array;
5601 assert_invariant();
5602 }
5603
5604 // add element to array
5605 m_value.array->push_back(val);
5606 }
5607
5608 /*!
5609 @brief add an object to an array
5610 @copydoc push_back(basic_json&&)
5611 */
5612 reference operator+=(const basic_json& val)
5613 {
5614 push_back(val);
5615 return *this;
5616 }
5617
5618 /*!
5619 @brief add an object to an object
5620
5621 Inserts the given element @a val to the JSON object. If the function is
5622 called on a JSON null value, an empty object is created before inserting
5623 @a val.
5624
5625 @param[in] val the value to add to the JSON object
5626
5627 @throw type_error.308 when called on a type other than JSON object or
5628 null; example: `"cannot use push_back() with number"`
5629
5630 @complexity Logarithmic in the size of the container, O(log(`size()`)).
5631
5632 @liveexample{The example shows how `push_back()` and `+=` can be used to
5633 add elements to a JSON object. Note how the `null` value was silently
5634 converted to a JSON object.,push_back__object_t__value}
5635
5636 @since version 1.0.0
5637 */
5638 void push_back(const typename object_t::value_type& val)
5639 {
5640 // push_back only works for null objects or objects
5641 if (not(is_null() or is_object()))
5642 {
5643 JSON_THROW(type_error::create(308, "cannot use push_back() with " + type_name()));
5644 }
5645
5646 // transform null object into an object
5647 if (is_null())
5648 {
5649 m_type = value_t::object;
5650 m_value = value_t::object;
5651 assert_invariant();
5652 }
5653
5654 // add element to array
5655 m_value.object->insert(val);
5656 }
5657
5658 /*!
5659 @brief add an object to an object
5660 @copydoc push_back(const typename object_t::value_type&)
5661 */
5662 reference operator+=(const typename object_t::value_type& val)
5663 {
5664 push_back(val);
5665 return *this;
5666 }
5667
5668 /*!
5669 @brief add an object to an object
5670
5671 This function allows to use `push_back` with an initializer list. In case
5672
5673 1. the current value is an object,
5674 2. the initializer list @a init contains only two elements, and
5675 3. the first element of @a init is a string,
5676
5677 @a init is converted into an object element and added using
5678 @ref push_back(const typename object_t::value_type&). Otherwise, @a init
5679 is converted to a JSON value and added using @ref push_back(basic_json&&).
5680
5681 @param[in] init an initializer list
5682
5683 @complexity Linear in the size of the initializer list @a init.
5684
5685 @note This function is required to resolve an ambiguous overload error,
5686 because pairs like `{"key", "value"}` can be both interpreted as
5687 `object_t::value_type` or `std::initializer_list<basic_json>`, see
5688 https://github.com/nlohmann/json/issues/235 for more information.
5689
5690 @liveexample{The example shows how initializer lists are treated as
5691 objects when possible.,push_back__initializer_list}
5692 */
5693 void push_back(std::initializer_list<basic_json> init)
5694 {
5695 if (is_object() and init.size() == 2 and init.begin()->is_string())
5696 {
5697 const string_t key = *init.begin();
5698 push_back(typename object_t::value_type(key, *(init.begin() + 1)));
5699 }
5700 else
5701 {
5702 push_back(basic_json(init));
5703 }
5704 }
5705
5706 /*!
5707 @brief add an object to an object
5708 @copydoc push_back(std::initializer_list<basic_json>)
5709 */
5710 reference operator+=(std::initializer_list<basic_json> init)
5711 {
5712 push_back(init);
5713 return *this;
5714 }
5715
5716 /*!
5717 @brief add an object to an array
5718
5719 Creates a JSON value from the passed parameters @a args to the end of the
5720 JSON value. If the function is called on a JSON null value, an empty array
5721 is created before appending the value created from @a args.
5722
5723 @param[in] args arguments to forward to a constructor of @ref basic_json
5724 @tparam Args compatible types to create a @ref basic_json object
5725
5726 @throw type_error.311 when called on a type other than JSON array or
5727 null; example: `"cannot use emplace_back() with number"`
5728
5729 @complexity Amortized constant.
5730
5731 @liveexample{The example shows how `push_back()` can be used to add
5732 elements to a JSON array. Note how the `null` value was silently converted
5733 to a JSON array.,emplace_back}
5734
5735 @since version 2.0.8
5736 */
5737 template<class... Args>
5738 void emplace_back(Args&& ... args)
5739 {
5740 // emplace_back only works for null objects or arrays
5741 if (not(is_null() or is_array()))
5742 {
5743 JSON_THROW(type_error::create(311, "cannot use emplace_back() with " + type_name()));
5744 }
5745
5746 // transform null object into an array
5747 if (is_null())
5748 {
5749 m_type = value_t::array;
5750 m_value = value_t::array;
5751 assert_invariant();
5752 }
5753
5754 // add element to array (perfect forwarding)
5755 m_value.array->emplace_back(std::forward<Args>(args)...);
5756 }
5757
5758 /*!
5759 @brief add an object to an object if key does not exist
5760
5761 Inserts a new element into a JSON object constructed in-place with the
5762 given @a args if there is no element with the key in the container. If the
5763 function is called on a JSON null value, an empty object is created before
5764 appending the value created from @a args.
5765
5766 @param[in] args arguments to forward to a constructor of @ref basic_json
5767 @tparam Args compatible types to create a @ref basic_json object
5768
5769 @return a pair consisting of an iterator to the inserted element, or the
5770 already-existing element if no insertion happened, and a bool
5771 denoting whether the insertion took place.
5772
5773 @throw type_error.311 when called on a type other than JSON object or
5774 null; example: `"cannot use emplace() with number"`
5775
5776 @complexity Logarithmic in the size of the container, O(log(`size()`)).
5777
5778 @liveexample{The example shows how `emplace()` can be used to add elements
5779 to a JSON object. Note how the `null` value was silently converted to a
5780 JSON object. Further note how no value is added if there was already one
5781 value stored with the same key.,emplace}
5782
5783 @since version 2.0.8
5784 */
5785 template<class... Args>
5786 std::pair<iterator, bool> emplace(Args&& ... args)
5787 {
5788 // emplace only works for null objects or arrays
5789 if (not(is_null() or is_object()))
5790 {
5791 JSON_THROW(type_error::create(311, "cannot use emplace() with " + type_name()));
5792 }
5793
5794 // transform null object into an object
5795 if (is_null())
5796 {
5797 m_type = value_t::object;
5798 m_value = value_t::object;
5799 assert_invariant();
5800 }
5801
5802 // add element to array (perfect forwarding)
5803 auto res = m_value.object->emplace(std::forward<Args>(args)...);
5804 // create result iterator and set iterator to the result of emplace
5805 auto it = begin();
5806 it.m_it.object_iterator = res.first;
5807
5808 // return pair of iterator and boolean
5809 return {it, res.second};
5810 }
5811
5812 /*!
5813 @brief inserts element
5814
5815 Inserts element @a val before iterator @a pos.
5816
5817 @param[in] pos iterator before which the content will be inserted; may be
5818 the end() iterator
5819 @param[in] val element to insert
5820 @return iterator pointing to the inserted @a val.
5821
5822 @throw type_error.309 if called on JSON values other than arrays;
5823 example: `"cannot use insert() with string"`
5824 @throw invalid_iterator.202 if @a pos is not an iterator of *this;
5825 example: `"iterator does not fit current value"`
5826
5827 @complexity Constant plus linear in the distance between @a pos and end of
5828 the container.
5829
5830 @liveexample{The example shows how `insert()` is used.,insert}
5831
5832 @since version 1.0.0
5833 */
5834 iterator insert(const_iterator pos, const basic_json& val)
5835 {
5836 // insert only works for arrays
5837 if (is_array())
5838 {
5839 // check if iterator pos fits to this JSON value
5840 if (pos.m_object != this)
5841 {
5842 JSON_THROW(invalid_iterator::create(202, "iterator does not fit current value"));
5843 }
5844
5845 // insert to array and return iterator
5846 iterator result(this);
5847 result.m_it.array_iterator = m_value.array->insert(pos.m_it.array_iterator, val);
5848 return result;
5849 }
5850
5851 JSON_THROW(type_error::create(309, "cannot use insert() with " + type_name()));
5852 }
5853
5854 /*!
5855 @brief inserts element
5856 @copydoc insert(const_iterator, const basic_json&)
5857 */
5858 iterator insert(const_iterator pos, basic_json&& val)
5859 {
5860 return insert(pos, val);
5861 }
5862
5863 /*!
5864 @brief inserts elements
5865
5866 Inserts @a cnt copies of @a val before iterator @a pos.
5867
5868 @param[in] pos iterator before which the content will be inserted; may be
5869 the end() iterator
5870 @param[in] cnt number of copies of @a val to insert
5871 @param[in] val element to insert
5872 @return iterator pointing to the first element inserted, or @a pos if
5873 `cnt==0`
5874
5875 @throw type_error.309 if called on JSON values other than arrays; example:
5876 `"cannot use insert() with string"`
5877 @throw invalid_iterator.202 if @a pos is not an iterator of *this;
5878 example: `"iterator does not fit current value"`
5879
5880 @complexity Linear in @a cnt plus linear in the distance between @a pos
5881 and end of the container.
5882
5883 @liveexample{The example shows how `insert()` is used.,insert__count}
5884
5885 @since version 1.0.0
5886 */
5887 iterator insert(const_iterator pos, size_type cnt, const basic_json& val)
5888 {
5889 // insert only works for arrays
5890 if (is_array())
5891 {
5892 // check if iterator pos fits to this JSON value
5893 if (pos.m_object != this)
5894 {
5895 JSON_THROW(invalid_iterator::create(202, "iterator does not fit current value"));
5896 }
5897
5898 // insert to array and return iterator
5899 iterator result(this);
5900 result.m_it.array_iterator = m_value.array->insert(pos.m_it.array_iterator, cnt, val);
5901 return result;
5902 }
5903
5904 JSON_THROW(type_error::create(309, "cannot use insert() with " + type_name()));
5905 }
5906
5907 /*!
5908 @brief inserts elements
5909
5910 Inserts elements from range `[first, last)` before iterator @a pos.
5911
5912 @param[in] pos iterator before which the content will be inserted; may be
5913 the end() iterator
5914 @param[in] first begin of the range of elements to insert
5915 @param[in] last end of the range of elements to insert
5916
5917 @throw type_error.309 if called on JSON values other than arrays; example:
5918 `"cannot use insert() with string"`
5919 @throw invalid_iterator.202 if @a pos is not an iterator of *this;
5920 example: `"iterator does not fit current value"`
5921 @throw invalid_iterator.210 if @a first and @a last do not belong to the
5922 same JSON value; example: `"iterators do not fit"`
5923 @throw invalid_iterator.211 if @a first or @a last are iterators into
5924 container for which insert is called; example: `"passed iterators may not
5925 belong to container"`
5926
5927 @return iterator pointing to the first element inserted, or @a pos if
5928 `first==last`
5929
5930 @complexity Linear in `std::distance(first, last)` plus linear in the
5931 distance between @a pos and end of the container.
5932
5933 @liveexample{The example shows how `insert()` is used.,insert__range}
5934
5935 @since version 1.0.0
5936 */
5937 iterator insert(const_iterator pos, const_iterator first, const_iterator last)
5938 {
5939 // insert only works for arrays
5940 if (not is_array())
5941 {
5942 JSON_THROW(type_error::create(309, "cannot use insert() with " + type_name()));
5943 }
5944
5945 // check if iterator pos fits to this JSON value
5946 if (pos.m_object != this)
5947 {
5948 JSON_THROW(invalid_iterator::create(202, "iterator does not fit current value"));
5949 }
5950
5951 // check if range iterators belong to the same JSON object
5952 if (first.m_object != last.m_object)
5953 {
5954 JSON_THROW(invalid_iterator::create(210, "iterators do not fit"));
5955 }
5956
5957 if (first.m_object == this or last.m_object == this)
5958 {
5959 JSON_THROW(invalid_iterator::create(211, "passed iterators may not belong to container"));
5960 }
5961
5962 // insert to array and return iterator
5963 iterator result(this);
5964 result.m_it.array_iterator = m_value.array->insert(
5965 pos.m_it.array_iterator,
5966 first.m_it.array_iterator,
5967 last.m_it.array_iterator);
5968 return result;
5969 }
5970
5971 /*!
5972 @brief inserts elements
5973
5974 Inserts elements from initializer list @a ilist before iterator @a pos.
5975
5976 @param[in] pos iterator before which the content will be inserted; may be
5977 the end() iterator
5978 @param[in] ilist initializer list to insert the values from
5979
5980 @throw type_error.309 if called on JSON values other than arrays; example:
5981 `"cannot use insert() with string"`
5982 @throw invalid_iterator.202 if @a pos is not an iterator of *this;
5983 example: `"iterator does not fit current value"`
5984
5985 @return iterator pointing to the first element inserted, or @a pos if
5986 `ilist` is empty
5987
5988 @complexity Linear in `ilist.size()` plus linear in the distance between
5989 @a pos and end of the container.
5990
5991 @liveexample{The example shows how `insert()` is used.,insert__ilist}
5992
5993 @since version 1.0.0
5994 */
5995 iterator insert(const_iterator pos, std::initializer_list<basic_json> ilist)
5996 {
5997 // insert only works for arrays
5998 if (not is_array())
5999 {
6000 JSON_THROW(type_error::create(309, "cannot use insert() with " + type_name()));
6001 }
6002
6003 // check if iterator pos fits to this JSON value
6004 if (pos.m_object != this)
6005 {
6006 JSON_THROW(invalid_iterator::create(202, "iterator does not fit current value"));
6007 }
6008
6009 // insert to array and return iterator
6010 iterator result(this);
6011 result.m_it.array_iterator = m_value.array->insert(pos.m_it.array_iterator, ilist);
6012 return result;
6013 }
6014
6015 /*!
6016 @brief inserts elements
6017
6018 Inserts elements from range `[first, last)`.
6019
6020 @param[in] first begin of the range of elements to insert
6021 @param[in] last end of the range of elements to insert
6022
6023 @throw type_error.309 if called on JSON values other than objects; example:
6024 `"cannot use insert() with string"`
6025 @throw invalid_iterator.202 if iterator @a first or @a last does does not
6026 point to an object; example: `"iterators first and last must point to
6027 objects"`
6028 @throw invalid_iterator.210 if @a first and @a last do not belong to the
6029 same JSON value; example: `"iterators do not fit"`
6030
6031 @complexity Logarithmic: `O(N*log(size() + N))`, where `N` is the number
6032 of elements to insert.
6033
6034 @liveexample{The example shows how `insert()` is used.,insert__range_object}
6035
6036 @since version 3.0.0
6037 */
6038 void insert(const_iterator first, const_iterator last)
6039 {
6040 // insert only works for objects
6041 if (not is_object())
6042 {
6043 JSON_THROW(type_error::create(309, "cannot use insert() with " + type_name()));
6044 }
6045
6046 // check if range iterators belong to the same JSON object
6047 if (first.m_object != last.m_object)
6048 {
6049 JSON_THROW(invalid_iterator::create(210, "iterators do not fit"));
6050 }
6051
6052 // passed iterators must belong to objects
6053 if (not first.m_object->is_object() or not first.m_object->is_object())
6054 {
6055 JSON_THROW(invalid_iterator::create(202, "iterators first and last must point to objects"));
6056 }
6057
6058 m_value.object->insert(first.m_it.object_iterator, last.m_it.object_iterator);
6059 }
6060
6061 /*!
6062 @brief exchanges the values
6063
6064 Exchanges the contents of the JSON value with those of @a other. Does not
6065 invoke any move, copy, or swap operations on individual elements. All
6066 iterators and references remain valid. The past-the-end iterator is
6067 invalidated.
6068
6069 @param[in,out] other JSON value to exchange the contents with
6070
6071 @complexity Constant.
6072
6073 @liveexample{The example below shows how JSON values can be swapped with
6074 `swap()`.,swap__reference}
6075
6076 @since version 1.0.0
6077 */
6078 void swap(reference other) noexcept (
6079 std::is_nothrow_move_constructible<value_t>::value and
6080 std::is_nothrow_move_assignable<value_t>::value and
6081 std::is_nothrow_move_constructible<json_value>::value and
6082 std::is_nothrow_move_assignable<json_value>::value
6083 )
6084 {
6085 std::swap(m_type, other.m_type);
6086 std::swap(m_value, other.m_value);
6087 assert_invariant();
6088 }
6089
6090 /*!
6091 @brief exchanges the values
6092
6093 Exchanges the contents of a JSON array with those of @a other. Does not
6094 invoke any move, copy, or swap operations on individual elements. All
6095 iterators and references remain valid. The past-the-end iterator is
6096 invalidated.
6097
6098 @param[in,out] other array to exchange the contents with
6099
6100 @throw type_error.310 when JSON value is not an array; example: `"cannot
6101 use swap() with string"`
6102
6103 @complexity Constant.
6104
6105 @liveexample{The example below shows how arrays can be swapped with
6106 `swap()`.,swap__array_t}
6107
6108 @since version 1.0.0
6109 */
6110 void swap(array_t& other)
6111 {
6112 // swap only works for arrays
6113 if (is_array())
6114 {
6115 std::swap(*(m_value.array), other);
6116 }
6117 else
6118 {
6119 JSON_THROW(type_error::create(310, "cannot use swap() with " + type_name()));
6120 }
6121 }
6122
6123 /*!
6124 @brief exchanges the values
6125
6126 Exchanges the contents of a JSON object with those of @a other. Does not
6127 invoke any move, copy, or swap operations on individual elements. All
6128 iterators and references remain valid. The past-the-end iterator is
6129 invalidated.
6130
6131 @param[in,out] other object to exchange the contents with
6132
6133 @throw type_error.310 when JSON value is not an object; example:
6134 `"cannot use swap() with string"`
6135
6136 @complexity Constant.
6137
6138 @liveexample{The example below shows how objects can be swapped with
6139 `swap()`.,swap__object_t}
6140
6141 @since version 1.0.0
6142 */
6143 void swap(object_t& other)
6144 {
6145 // swap only works for objects
6146 if (is_object())
6147 {
6148 std::swap(*(m_value.object), other);
6149 }
6150 else
6151 {
6152 JSON_THROW(type_error::create(310, "cannot use swap() with " + type_name()));
6153 }
6154 }
6155
6156 /*!
6157 @brief exchanges the values
6158
6159 Exchanges the contents of a JSON string with those of @a other. Does not
6160 invoke any move, copy, or swap operations on individual elements. All
6161 iterators and references remain valid. The past-the-end iterator is
6162 invalidated.
6163
6164 @param[in,out] other string to exchange the contents with
6165
6166 @throw type_error.310 when JSON value is not a string; example: `"cannot
6167 use swap() with boolean"`
6168
6169 @complexity Constant.
6170
6171 @liveexample{The example below shows how strings can be swapped with
6172 `swap()`.,swap__string_t}
6173
6174 @since version 1.0.0
6175 */
6176 void swap(string_t& other)
6177 {
6178 // swap only works for strings
6179 if (is_string())
6180 {
6181 std::swap(*(m_value.string), other);
6182 }
6183 else
6184 {
6185 JSON_THROW(type_error::create(310, "cannot use swap() with " + type_name()));
6186 }
6187 }
6188
6189 /// @}
6190
6191 public:
6192 //////////////////////////////////////////
6193 // lexicographical comparison operators //
6194 //////////////////////////////////////////
6195
6196 /// @name lexicographical comparison operators
6197 /// @{
6198
6199 /*!
6200 @brief comparison: equal
6201
6202 Compares two JSON values for equality according to the following rules:
6203 - Two JSON values are equal if (1) they are from the same type and (2)
6204 their stored values are the same according to their respective
6205 `operator==`.
6206 - Integer and floating-point numbers are automatically converted before
6207 comparison. Note than two NaN values are always treated as unequal.
6208 - Two JSON null values are equal.
6209
6210 @note NaN values never compare equal to themselves or to other NaN values.
6211
6212 @param[in] lhs first JSON value to consider
6213 @param[in] rhs second JSON value to consider
6214 @return whether the values @a lhs and @a rhs are equal
6215
6216 @complexity Linear.
6217
6218 @liveexample{The example demonstrates comparing several JSON
6219 types.,operator__equal}
6220
6221 @since version 1.0.0
6222 */
6223 friend bool operator==(const_reference lhs, const_reference rhs) noexcept
6224 {
6225 const auto lhs_type = lhs.type();
6226 const auto rhs_type = rhs.type();
6227
6228 if (lhs_type == rhs_type)
6229 {
6230 switch (lhs_type)
6231 {
6232 case value_t::array:
6233 {
6234 return *lhs.m_value.array == *rhs.m_value.array;
6235 }
6236 case value_t::object:
6237 {
6238 return *lhs.m_value.object == *rhs.m_value.object;
6239 }
6240 case value_t::null:
6241 {
6242 return true;
6243 }
6244 case value_t::string:
6245 {
6246 return *lhs.m_value.string == *rhs.m_value.string;
6247 }
6248 case value_t::boolean:
6249 {
6250 return lhs.m_value.boolean == rhs.m_value.boolean;
6251 }
6252 case value_t::number_integer:
6253 {
6254 return lhs.m_value.number_integer == rhs.m_value.number_integer;
6255 }
6256 case value_t::number_unsigned:
6257 {
6258 return lhs.m_value.number_unsigned == rhs.m_value.number_unsigned;
6259 }
6260 case value_t::number_float:
6261 {
6262 return lhs.m_value.number_float == rhs.m_value.number_float;
6263 }
6264 default:
6265 {
6266 return false;
6267 }
6268 }
6269 }
6270 else if (lhs_type == value_t::number_integer and rhs_type == value_t::number_float)
6271 {
6272 return static_cast<number_float_t>(lhs.m_value.number_integer) == rhs.m_value.number_float;
6273 }
6274 else if (lhs_type == value_t::number_float and rhs_type == value_t::number_integer)
6275 {
6276 return lhs.m_value.number_float == static_cast<number_float_t>(rhs.m_value.number_integer);
6277 }
6278 else if (lhs_type == value_t::number_unsigned and rhs_type == value_t::number_float)
6279 {
6280 return static_cast<number_float_t>(lhs.m_value.number_unsigned) == rhs.m_value.number_float;
6281 }
6282 else if (lhs_type == value_t::number_float and rhs_type == value_t::number_unsigned)
6283 {
6284 return lhs.m_value.number_float == static_cast<number_float_t>(rhs.m_value.number_unsigned);
6285 }
6286 else if (lhs_type == value_t::number_unsigned and rhs_type == value_t::number_integer)
6287 {
6288 return static_cast<number_integer_t>(lhs.m_value.number_unsigned) == rhs.m_value.number_integer;
6289 }
6290 else if (lhs_type == value_t::number_integer and rhs_type == value_t::number_unsigned)
6291 {
6292 return lhs.m_value.number_integer == static_cast<number_integer_t>(rhs.m_value.number_unsigned);
6293 }
6294
6295 return false;
6296 }
6297
6298 /*!
6299 @brief comparison: equal
6300 @copydoc operator==(const_reference, const_reference)
6301 */
6302 template<typename ScalarType, typename std::enable_if<
6303 std::is_scalar<ScalarType>::value, int>::type = 0>
6304 friend bool operator==(const_reference lhs, const ScalarType rhs) noexcept
6305 {
6306 return (lhs == basic_json(rhs));
6307 }
6308
6309 /*!
6310 @brief comparison: equal
6311 @copydoc operator==(const_reference, const_reference)
6312 */
6313 template<typename ScalarType, typename std::enable_if<
6314 std::is_scalar<ScalarType>::value, int>::type = 0>
6315 friend bool operator==(const ScalarType lhs, const_reference rhs) noexcept
6316 {
6317 return (basic_json(lhs) == rhs);
6318 }
6319
6320 /*!
6321 @brief comparison: not equal
6322
6323 Compares two JSON values for inequality by calculating `not (lhs == rhs)`.
6324
6325 @param[in] lhs first JSON value to consider
6326 @param[in] rhs second JSON value to consider
6327 @return whether the values @a lhs and @a rhs are not equal
6328
6329 @complexity Linear.
6330
6331 @liveexample{The example demonstrates comparing several JSON
6332 types.,operator__notequal}
6333
6334 @since version 1.0.0
6335 */
6336 friend bool operator!=(const_reference lhs, const_reference rhs) noexcept
6337 {
6338 return not (lhs == rhs);
6339 }
6340
6341 /*!
6342 @brief comparison: not equal
6343 @copydoc operator!=(const_reference, const_reference)
6344 */
6345 template<typename ScalarType, typename std::enable_if<
6346 std::is_scalar<ScalarType>::value, int>::type = 0>
6347 friend bool operator!=(const_reference lhs, const ScalarType rhs) noexcept
6348 {
6349 return (lhs != basic_json(rhs));
6350 }
6351
6352 /*!
6353 @brief comparison: not equal
6354 @copydoc operator!=(const_reference, const_reference)
6355 */
6356 template<typename ScalarType, typename std::enable_if<
6357 std::is_scalar<ScalarType>::value, int>::type = 0>
6358 friend bool operator!=(const ScalarType lhs, const_reference rhs) noexcept
6359 {
6360 return (basic_json(lhs) != rhs);
6361 }
6362
6363 /*!
6364 @brief comparison: less than
6365
6366 Compares whether one JSON value @a lhs is less than another JSON value @a
6367 rhs according to the following rules:
6368 - If @a lhs and @a rhs have the same type, the values are compared using
6369 the default `<` operator.
6370 - Integer and floating-point numbers are automatically converted before
6371 comparison
6372 - In case @a lhs and @a rhs have different types, the values are ignored
6373 and the order of the types is considered, see
6374 @ref operator<(const value_t, const value_t).
6375
6376 @param[in] lhs first JSON value to consider
6377 @param[in] rhs second JSON value to consider
6378 @return whether @a lhs is less than @a rhs
6379
6380 @complexity Linear.
6381
6382 @liveexample{The example demonstrates comparing several JSON
6383 types.,operator__less}
6384
6385 @since version 1.0.0
6386 */
6387 friend bool operator<(const_reference lhs, const_reference rhs) noexcept
6388 {
6389 const auto lhs_type = lhs.type();
6390 const auto rhs_type = rhs.type();
6391
6392 if (lhs_type == rhs_type)
6393 {
6394 switch (lhs_type)
6395 {
6396 case value_t::array:
6397 {
6398 return (*lhs.m_value.array) < (*rhs.m_value.array);
6399 }
6400 case value_t::object:
6401 {
6402 return *lhs.m_value.object < *rhs.m_value.object;
6403 }
6404 case value_t::null:
6405 {
6406 return false;
6407 }
6408 case value_t::string:
6409 {
6410 return *lhs.m_value.string < *rhs.m_value.string;
6411 }
6412 case value_t::boolean:
6413 {
6414 return lhs.m_value.boolean < rhs.m_value.boolean;
6415 }
6416 case value_t::number_integer:
6417 {
6418 return lhs.m_value.number_integer < rhs.m_value.number_integer;
6419 }
6420 case value_t::number_unsigned:
6421 {
6422 return lhs.m_value.number_unsigned < rhs.m_value.number_unsigned;
6423 }
6424 case value_t::number_float:
6425 {
6426 return lhs.m_value.number_float < rhs.m_value.number_float;
6427 }
6428 default:
6429 {
6430 return false;
6431 }
6432 }
6433 }
6434 else if (lhs_type == value_t::number_integer and rhs_type == value_t::number_float)
6435 {
6436 return static_cast<number_float_t>(lhs.m_value.number_integer) < rhs.m_value.number_float;
6437 }
6438 else if (lhs_type == value_t::number_float and rhs_type == value_t::number_integer)
6439 {
6440 return lhs.m_value.number_float < static_cast<number_float_t>(rhs.m_value.number_integer);
6441 }
6442 else if (lhs_type == value_t::number_unsigned and rhs_type == value_t::number_float)
6443 {
6444 return static_cast<number_float_t>(lhs.m_value.number_unsigned) < rhs.m_value.number_float;
6445 }
6446 else if (lhs_type == value_t::number_float and rhs_type == value_t::number_unsigned)
6447 {
6448 return lhs.m_value.number_float < static_cast<number_float_t>(rhs.m_value.number_unsigned);
6449 }
6450 else if (lhs_type == value_t::number_integer and rhs_type == value_t::number_unsigned)
6451 {
6452 return lhs.m_value.number_integer < static_cast<number_integer_t>(rhs.m_value.number_unsigned);
6453 }
6454 else if (lhs_type == value_t::number_unsigned and rhs_type == value_t::number_integer)
6455 {
6456 return static_cast<number_integer_t>(lhs.m_value.number_unsigned) < rhs.m_value.number_integer;
6457 }
6458
6459 // We only reach this line if we cannot compare values. In that case,
6460 // we compare types. Note we have to call the operator explicitly,
6461 // because MSVC has problems otherwise.
6462 return operator<(lhs_type, rhs_type);
6463 }
6464
6465 /*!
6466 @brief comparison: less than
6467 @copydoc operator<(const_reference, const_reference)
6468 */
6469 template<typename ScalarType, typename std::enable_if<
6470 std::is_scalar<ScalarType>::value, int>::type = 0>
6471 friend bool operator<(const_reference lhs, const ScalarType rhs) noexcept
6472 {
6473 return (lhs < basic_json(rhs));
6474 }
6475
6476 /*!
6477 @brief comparison: less than
6478 @copydoc operator<(const_reference, const_reference)
6479 */
6480 template<typename ScalarType, typename std::enable_if<
6481 std::is_scalar<ScalarType>::value, int>::type = 0>
6482 friend bool operator<(const ScalarType lhs, const_reference rhs) noexcept
6483 {
6484 return (basic_json(lhs) < rhs);
6485 }
6486
6487 /*!
6488 @brief comparison: less than or equal
6489
6490 Compares whether one JSON value @a lhs is less than or equal to another
6491 JSON value by calculating `not (rhs < lhs)`.
6492
6493 @param[in] lhs first JSON value to consider
6494 @param[in] rhs second JSON value to consider
6495 @return whether @a lhs is less than or equal to @a rhs
6496
6497 @complexity Linear.
6498
6499 @liveexample{The example demonstrates comparing several JSON
6500 types.,operator__greater}
6501
6502 @since version 1.0.0
6503 */
6504 friend bool operator<=(const_reference lhs, const_reference rhs) noexcept
6505 {
6506 return not (rhs < lhs);
6507 }
6508
6509 /*!
6510 @brief comparison: less than or equal
6511 @copydoc operator<=(const_reference, const_reference)
6512 */
6513 template<typename ScalarType, typename std::enable_if<
6514 std::is_scalar<ScalarType>::value, int>::type = 0>
6515 friend bool operator<=(const_reference lhs, const ScalarType rhs) noexcept
6516 {
6517 return (lhs <= basic_json(rhs));
6518 }
6519
6520 /*!
6521 @brief comparison: less than or equal
6522 @copydoc operator<=(const_reference, const_reference)
6523 */
6524 template<typename ScalarType, typename std::enable_if<
6525 std::is_scalar<ScalarType>::value, int>::type = 0>
6526 friend bool operator<=(const ScalarType lhs, const_reference rhs) noexcept
6527 {
6528 return (basic_json(lhs) <= rhs);
6529 }
6530
6531 /*!
6532 @brief comparison: greater than
6533
6534 Compares whether one JSON value @a lhs is greater than another
6535 JSON value by calculating `not (lhs <= rhs)`.
6536
6537 @param[in] lhs first JSON value to consider
6538 @param[in] rhs second JSON value to consider
6539 @return whether @a lhs is greater than to @a rhs
6540
6541 @complexity Linear.
6542
6543 @liveexample{The example demonstrates comparing several JSON
6544 types.,operator__lessequal}
6545
6546 @since version 1.0.0
6547 */
6548 friend bool operator>(const_reference lhs, const_reference rhs) noexcept
6549 {
6550 return not (lhs <= rhs);
6551 }
6552
6553 /*!
6554 @brief comparison: greater than
6555 @copydoc operator>(const_reference, const_reference)
6556 */
6557 template<typename ScalarType, typename std::enable_if<
6558 std::is_scalar<ScalarType>::value, int>::type = 0>
6559 friend bool operator>(const_reference lhs, const ScalarType rhs) noexcept
6560 {
6561 return (lhs > basic_json(rhs));
6562 }
6563
6564 /*!
6565 @brief comparison: greater than
6566 @copydoc operator>(const_reference, const_reference)
6567 */
6568 template<typename ScalarType, typename std::enable_if<
6569 std::is_scalar<ScalarType>::value, int>::type = 0>
6570 friend bool operator>(const ScalarType lhs, const_reference rhs) noexcept
6571 {
6572 return (basic_json(lhs) > rhs);
6573 }
6574
6575 /*!
6576 @brief comparison: greater than or equal
6577
6578 Compares whether one JSON value @a lhs is greater than or equal to another
6579 JSON value by calculating `not (lhs < rhs)`.
6580
6581 @param[in] lhs first JSON value to consider
6582 @param[in] rhs second JSON value to consider
6583 @return whether @a lhs is greater than or equal to @a rhs
6584
6585 @complexity Linear.
6586
6587 @liveexample{The example demonstrates comparing several JSON
6588 types.,operator__greaterequal}
6589
6590 @since version 1.0.0
6591 */
6592 friend bool operator>=(const_reference lhs, const_reference rhs) noexcept
6593 {
6594 return not (lhs < rhs);
6595 }
6596
6597 /*!
6598 @brief comparison: greater than or equal
6599 @copydoc operator>=(const_reference, const_reference)
6600 */
6601 template<typename ScalarType, typename std::enable_if<
6602 std::is_scalar<ScalarType>::value, int>::type = 0>
6603 friend bool operator>=(const_reference lhs, const ScalarType rhs) noexcept
6604 {
6605 return (lhs >= basic_json(rhs));
6606 }
6607
6608 /*!
6609 @brief comparison: greater than or equal
6610 @copydoc operator>=(const_reference, const_reference)
6611 */
6612 template<typename ScalarType, typename std::enable_if<
6613 std::is_scalar<ScalarType>::value, int>::type = 0>
6614 friend bool operator>=(const ScalarType lhs, const_reference rhs) noexcept
6615 {
6616 return (basic_json(lhs) >= rhs);
6617 }
6618
6619 /// @}
6620
6621 private:
6622 /////////////////////
6623 // output adapters //
6624 /////////////////////
6625
6626 /// abstract output adapter interface
6627 template<typename CharType>
6628 class output_adapter
6629 {
6630 public:
6631 virtual void write_character(CharType c) = 0;
6632 virtual void write_characters(const CharType* s, size_t length) = 0;
6633 virtual ~output_adapter() {}
6634
6635 static std::shared_ptr<output_adapter<CharType>> create(std::vector<CharType>& vec)
6636 {
6637 return std::make_shared<output_vector_adapter<CharType>>(vec);
6638 }
6639
6640 static std::shared_ptr<output_adapter<CharType>> create(std::ostream& s)
6641 {
6642 return std::make_shared<output_stream_adapter<CharType>>(s);
6643 }
6644
6645 static std::shared_ptr<output_adapter<CharType>> create(std::string& s)
6646 {
6647 return std::make_shared<output_string_adapter<CharType>>(s);
6648 }
6649 };
6650
6651 /// a type to simplify interfaces
6652 template<typename CharType>
6653 using output_adapter_t = std::shared_ptr<output_adapter<CharType>>;
6654
6655 /// output adapter for byte vectors
6656 template<typename CharType>
6657 class output_vector_adapter : public output_adapter<CharType>
6658 {
6659 public:
6660 output_vector_adapter(std::vector<CharType>& vec)
6661 : v(vec)
6662 {}
6663
6664 void write_character(CharType c) override
6665 {
6666 v.push_back(c);
6667 }
6668
6669 void write_characters(const CharType* s, size_t length) override
6670 {
6671 std::copy(s, s + length, std::back_inserter(v));
6672 }
6673
6674 private:
6675 std::vector<CharType>& v;
6676 };
6677
6678 /// output adapter for output streams
6679 template<typename CharType>
6680 class output_stream_adapter : public output_adapter<CharType>
6681 {
6682 public:
6683 output_stream_adapter(std::basic_ostream<CharType>& s)
6684 : stream(s)
6685 {}
6686
6687 void write_character(CharType c) override
6688 {
6689 stream.put(c);
6690 }
6691
6692 void write_characters(const CharType* s, size_t length) override
6693 {
6694 stream.write(s, static_cast<std::streamsize>(length));
6695 }
6696
6697 private:
6698 std::basic_ostream<CharType>& stream;
6699 };
6700
6701 /// output adapter for basic_string
6702 template<typename CharType>
6703 class output_string_adapter : public output_adapter<CharType>
6704 {
6705 public:
6706 output_string_adapter(std::string& s)
6707 : str(s)
6708 {}
6709
6710 void write_character(CharType c) override
6711 {
6712 str.push_back(c);
6713 }
6714
6715 void write_characters(const CharType* s, size_t length) override
6716 {
6717 str.append(s, length);
6718 }
6719
6720 private:
6721 std::basic_string<CharType>& str;
6722 };
6723
6724
6725 ///////////////////
6726 // serialization //
6727 ///////////////////
6728
6729 /// @name serialization
6730 /// @{
6731
6732 private:
6733 /*!
6734 @brief wrapper around the serialization functions
6735 */
6736 class serializer
6737 {
6738 public:
6739 /*!
6740 @param[in] s output stream to serialize to
6741 @param[in] ichar indentation character to use
6742 */
6743 serializer(output_adapter_t<char> s, const char ichar)
6744 : o(s), loc(std::localeconv()),
6745 thousands_sep(!loc->thousands_sep ? '\0' : loc->thousands_sep[0]),
6746 decimal_point(!loc->decimal_point ? '\0' : loc->decimal_point[0]),
6747 indent_char(ichar), indent_string(512, indent_char)
6748 {}
6749
6750 // delete because of pointer members
6751 serializer(const serializer&) = delete;
6752 serializer& operator=(const serializer&) = delete;
6753
6754 /*!
6755 @brief internal implementation of the serialization function
6756
6757 This function is called by the public member function dump and
6758 organizes the serialization internally. The indentation level is
6759 propagated as additional parameter. In case of arrays and objects, the
6760 function is called recursively.
6761
6762 - strings and object keys are escaped using `escape_string()`
6763 - integer numbers are converted implicitly via `operator<<`
6764 - floating-point numbers are converted to a string using `"%g"` format
6765
6766 @param[in] val value to serialize
6767 @param[in] pretty_print whether the output shall be pretty-printed
6768 @param[in] indent_step the indent level
6769 @param[in] current_indent the current indent level (only used internally)
6770 */
6771 void dump(const basic_json& val,
6772 const bool pretty_print,
6773 const unsigned int indent_step,
6774 const unsigned int current_indent = 0)
6775 {
6776 switch (val.m_type)
6777 {
6778 case value_t::object:
6779 {
6780 if (val.m_value.object->empty())
6781 {
6782 o->write_characters("{}", 2);
6783 return;
6784 }
6785
6786 if (pretty_print)
6787 {
6788 o->write_characters("{\n", 2);
6789
6790 // variable to hold indentation for recursive calls
6791 const auto new_indent = current_indent + indent_step;
6792 if (JSON_UNLIKELY(indent_string.size() < new_indent))
6793 {
6794 indent_string.resize(indent_string.size() * 2, ' ');
6795 }
6796
6797 // first n-1 elements
6798 auto i = val.m_value.object->cbegin();
6799 for (size_t cnt = 0; cnt < val.m_value.object->size() - 1; ++cnt, ++i)
6800 {
6801 o->write_characters(indent_string.c_str(), new_indent);
6802 o->write_character('\"');
6803 dump_escaped(i->first);
6804 o->write_characters("\": ", 3);
6805 dump(i->second, true, indent_step, new_indent);
6806 o->write_characters(",\n", 2);
6807 }
6808
6809 // last element
6810 assert(i != val.m_value.object->cend());
6811 o->write_characters(indent_string.c_str(), new_indent);
6812 o->write_character('\"');
6813 dump_escaped(i->first);
6814 o->write_characters("\": ", 3);
6815 dump(i->second, true, indent_step, new_indent);
6816
6817 o->write_character('\n');
6818 o->write_characters(indent_string.c_str(), current_indent);
6819 o->write_character('}');
6820 }
6821 else
6822 {
6823 o->write_character('{');
6824
6825 // first n-1 elements
6826 auto i = val.m_value.object->cbegin();
6827 for (size_t cnt = 0; cnt < val.m_value.object->size() - 1; ++cnt, ++i)
6828 {
6829 o->write_character('\"');
6830 dump_escaped(i->first);
6831 o->write_characters("\":", 2);
6832 dump(i->second, false, indent_step, current_indent);
6833 o->write_character(',');
6834 }
6835
6836 // last element
6837 assert(i != val.m_value.object->cend());
6838 o->write_character('\"');
6839 dump_escaped(i->first);
6840 o->write_characters("\":", 2);
6841 dump(i->second, false, indent_step, current_indent);
6842
6843 o->write_character('}');
6844 }
6845
6846 return;
6847 }
6848
6849 case value_t::array:
6850 {
6851 if (val.m_value.array->empty())
6852 {
6853 o->write_characters("[]", 2);
6854 return;
6855 }
6856
6857 if (pretty_print)
6858 {
6859 o->write_characters("[\n", 2);
6860
6861 // variable to hold indentation for recursive calls
6862 const auto new_indent = current_indent + indent_step;
6863 if (indent_string.size() < new_indent)
6864 {
6865 indent_string.resize(new_indent, ' ');
6866 }
6867
6868 // first n-1 elements
6869 for (auto i = val.m_value.array->cbegin(); i != val.m_value.array->cend() - 1; ++i)
6870 {
6871 o->write_characters(indent_string.c_str(), new_indent);
6872 dump(*i, true, indent_step, new_indent);
6873 o->write_characters(",\n", 2);
6874 }
6875
6876 // last element
6877 assert(not val.m_value.array->empty());
6878 o->write_characters(indent_string.c_str(), new_indent);
6879 dump(val.m_value.array->back(), true, indent_step, new_indent);
6880
6881 o->write_character('\n');
6882 o->write_characters(indent_string.c_str(), current_indent);
6883 o->write_character(']');
6884 }
6885 else
6886 {
6887 o->write_character('[');
6888
6889 // first n-1 elements
6890 for (auto i = val.m_value.array->cbegin(); i != val.m_value.array->cend() - 1; ++i)
6891 {
6892 dump(*i, false, indent_step, current_indent);
6893 o->write_character(',');
6894 }
6895
6896 // last element
6897 assert(not val.m_value.array->empty());
6898 dump(val.m_value.array->back(), false, indent_step, current_indent);
6899
6900 o->write_character(']');
6901 }
6902
6903 return;
6904 }
6905
6906 case value_t::string:
6907 {
6908 o->write_character('\"');
6909 dump_escaped(*val.m_value.string);
6910 o->write_character('\"');
6911 return;
6912 }
6913
6914 case value_t::boolean:
6915 {
6916 if (val.m_value.boolean)
6917 {
6918 o->write_characters("true", 4);
6919 }
6920 else
6921 {
6922 o->write_characters("false", 5);
6923 }
6924 return;
6925 }
6926
6927 case value_t::number_integer:
6928 {
6929 dump_integer(val.m_value.number_integer);
6930 return;
6931 }
6932
6933 case value_t::number_unsigned:
6934 {
6935 dump_integer(val.m_value.number_unsigned);
6936 return;
6937 }
6938
6939 case value_t::number_float:
6940 {
6941 dump_float(val.m_value.number_float);
6942 return;
6943 }
6944
6945 case value_t::discarded:
6946 {
6947 o->write_characters("<discarded>", 11);
6948 return;
6949 }
6950
6951 case value_t::null:
6952 {
6953 o->write_characters("null", 4);
6954 return;
6955 }
6956 }
6957 }
6958
6959 private:
6960 /*!
6961 @brief calculates the extra space to escape a JSON string
6962
6963 @param[in] s the string to escape
6964 @return the number of characters required to escape string @a s
6965
6966 @complexity Linear in the length of string @a s.
6967 */
6968 static std::size_t extra_space(const string_t& s) noexcept
6969 {
6970 return std::accumulate(s.begin(), s.end(), size_t{},
6971 [](size_t res, typename string_t::value_type c)
6972 {
6973 switch (c)
6974 {
6975 case '"':
6976 case '\\':
6977 case '\b':
6978 case '\f':
6979 case '\n':
6980 case '\r':
6981 case '\t':
6982 {
6983 // from c (1 byte) to \x (2 bytes)
6984 return res + 1;
6985 }
6986
6987 case 0x00:
6988 case 0x01:
6989 case 0x02:
6990 case 0x03:
6991 case 0x04:
6992 case 0x05:
6993 case 0x06:
6994 case 0x07:
6995 case 0x0b:
6996 case 0x0e:
6997 case 0x0f:
6998 case 0x10:
6999 case 0x11:
7000 case 0x12:
7001 case 0x13:
7002 case 0x14:
7003 case 0x15:
7004 case 0x16:
7005 case 0x17:
7006 case 0x18:
7007 case 0x19:
7008 case 0x1a:
7009 case 0x1b:
7010 case 0x1c:
7011 case 0x1d:
7012 case 0x1e:
7013 case 0x1f:
7014 {
7015 // from c (1 byte) to \uxxxx (6 bytes)
7016 return res + 5;
7017 }
7018
7019 default:
7020 {
7021 return res;
7022 }
7023 }
7024 });
7025 }
7026
7027 /*!
7028 @brief dump escaped string
7029
7030 Escape a string by replacing certain special characters by a sequence
7031 of an escape character (backslash) and another character and other
7032 control characters by a sequence of "\u" followed by a four-digit hex
7033 representation. The escaped string is written to output stream @a o.
7034
7035 @param[in] s the string to escape
7036
7037 @complexity Linear in the length of string @a s.
7038 */
7039 void dump_escaped(const string_t& s) const
7040 {
7041 const auto space = extra_space(s);
7042 if (space == 0)
7043 {
7044 o->write_characters(s.c_str(), s.size());
7045 return;
7046 }
7047
7048 // create a result string of necessary size
7049 string_t result(s.size() + space, '\\');
7050 std::size_t pos = 0;
7051
7052 for (const auto& c : s)
7053 {
7054 switch (c)
7055 {
7056 // quotation mark (0x22)
7057 case '"':
7058 {
7059 result[pos + 1] = '"';
7060 pos += 2;
7061 break;
7062 }
7063
7064 // reverse solidus (0x5c)
7065 case '\\':
7066 {
7067 // nothing to change
7068 pos += 2;
7069 break;
7070 }
7071
7072 // backspace (0x08)
7073 case '\b':
7074 {
7075 result[pos + 1] = 'b';
7076 pos += 2;
7077 break;
7078 }
7079
7080 // formfeed (0x0c)
7081 case '\f':
7082 {
7083 result[pos + 1] = 'f';
7084 pos += 2;
7085 break;
7086 }
7087
7088 // newline (0x0a)
7089 case '\n':
7090 {
7091 result[pos + 1] = 'n';
7092 pos += 2;
7093 break;
7094 }
7095
7096 // carriage return (0x0d)
7097 case '\r':
7098 {
7099 result[pos + 1] = 'r';
7100 pos += 2;
7101 break;
7102 }
7103
7104 // horizontal tab (0x09)
7105 case '\t':
7106 {
7107 result[pos + 1] = 't';
7108 pos += 2;
7109 break;
7110 }
7111
7112 case 0x00:
7113 case 0x01:
7114 case 0x02:
7115 case 0x03:
7116 case 0x04:
7117 case 0x05:
7118 case 0x06:
7119 case 0x07:
7120 case 0x0b:
7121 case 0x0e:
7122 case 0x0f:
7123 case 0x10:
7124 case 0x11:
7125 case 0x12:
7126 case 0x13:
7127 case 0x14:
7128 case 0x15:
7129 case 0x16:
7130 case 0x17:
7131 case 0x18:
7132 case 0x19:
7133 case 0x1a:
7134 case 0x1b:
7135 case 0x1c:
7136 case 0x1d:
7137 case 0x1e:
7138 case 0x1f:
7139 {
7140 // convert a number 0..15 to its hex representation
7141 // (0..f)
7142 static const char hexify[16] =
7143 {
7144 '0', '1', '2', '3', '4', '5', '6', '7',
7145 '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'
7146 };
7147
7148 // print character c as \uxxxx
7149 for (const char m :
7150 { 'u', '0', '0', hexify[c >> 4], hexify[c & 0x0f]
7151 })
7152 {
7153 result[++pos] = m;
7154 }
7155
7156 ++pos;
7157 break;
7158 }
7159
7160 default:
7161 {
7162 // all other characters are added as-is
7163 result[pos++] = c;
7164 break;
7165 }
7166 }
7167 }
7168
7169 assert(pos == s.size() + space);
7170 o->write_characters(result.c_str(), result.size());
7171 }
7172
7173 /*!
7174 @brief dump an integer
7175
7176 Dump a given integer to output stream @a o. Works internally with
7177 @a number_buffer.
7178
7179 @param[in] x integer number (signed or unsigned) to dump
7180 @tparam NumberType either @a number_integer_t or @a number_unsigned_t
7181 */
7182 template<typename NumberType, detail::enable_if_t <
7183 std::is_same<NumberType, number_unsigned_t>::value or
7184 std::is_same<NumberType, number_integer_t>::value, int> = 0>
7185 void dump_integer(NumberType x)
7186 {
7187 // special case for "0"
7188 if (x == 0)
7189 {
7190 o->write_character('0');
7191 return;
7192 }
7193
7194 const bool is_negative = x < 0;
7195 size_t i = 0;
7196
7197 // spare 1 byte for '\0'
7198 while (x != 0 and i < number_buffer.size() - 1)
7199 {
7200 const auto digit = std::labs(static_cast<long>(x % 10));
7201 number_buffer[i++] = static_cast<char>('0' + digit);
7202 x /= 10;
7203 }
7204
7205 // make sure the number has been processed completely
7206 assert(x == 0);
7207
7208 if (is_negative)
7209 {
7210 // make sure there is capacity for the '-'
7211 assert(i < number_buffer.size() - 2);
7212 number_buffer[i++] = '-';
7213 }
7214
7215 std::reverse(number_buffer.begin(), number_buffer.begin() + i);
7216 o->write_characters(number_buffer.data(), i);
7217 }
7218
7219 /*!
7220 @brief dump a floating-point number
7221
7222 Dump a given floating-point number to output stream @a o. Works
7223 internally with @a number_buffer.
7224
7225 @param[in] x floating-point number to dump
7226 */
7227 void dump_float(number_float_t x)
7228 {
7229 // NaN / inf
7230 if (not std::isfinite(x) or std::isnan(x))
7231 {
7232 o->write_characters("null", 4);
7233 return;
7234 }
7235
7236 // special case for 0.0 and -0.0
7237 if (x == 0)
7238 {
7239 if (std::signbit(x))
7240 {
7241 o->write_characters("-0.0", 4);
7242 }
7243 else
7244 {
7245 o->write_characters("0.0", 3);
7246 }
7247 return;
7248 }
7249
7250 // get number of digits for a text -> float -> text round-trip
7251 static constexpr auto d = std::numeric_limits<number_float_t>::digits10;
7252
7253 // the actual conversion
7254 std::ptrdiff_t len = snprintf(number_buffer.data(), number_buffer.size(),
7255 "%.*g", d, x);
7256
7257 // negative value indicates an error
7258 assert(len > 0);
7259 // check if buffer was large enough
7260 assert(static_cast<size_t>(len) < number_buffer.size());
7261
7262 // erase thousands separator
7263 if (thousands_sep != '\0')
7264 {
7265 const auto end = std::remove(number_buffer.begin(),
7266 number_buffer.begin() + len,
7267 thousands_sep);
7268 std::fill(end, number_buffer.end(), '\0');
7269 assert((end - number_buffer.begin()) <= len);
7270 len = (end - number_buffer.begin());
7271 }
7272
7273 // convert decimal point to '.'
7274 if (decimal_point != '\0' and decimal_point != '.')
7275 {
7276 for (auto& c : number_buffer)
7277 {
7278 if (c == decimal_point)
7279 {
7280 c = '.';
7281 break;
7282 }
7283 }
7284 }
7285
7286 o->write_characters(number_buffer.data(), static_cast<size_t>(len));
7287
7288 // determine if need to append ".0"
7289 const bool value_is_int_like = std::none_of(number_buffer.begin(),
7290 number_buffer.begin() + len + 1,
7291 [](char c)
7292 {
7293 return c == '.' or c == 'e';
7294 });
7295
7296 if (value_is_int_like)
7297 {
7298 o->write_characters(".0", 2);
7299 }
7300 }
7301
7302 private:
7303 /// the output of the serializer
7304 output_adapter_t<char> o = nullptr;
7305
7306 /// a (hopefully) large enough character buffer
7307 std::array<char, 64> number_buffer{{}};
7308
7309 /// the locale
7310 const std::lconv* loc = nullptr;
7311 /// the locale's thousand separator character
7312 const char thousands_sep = '\0';
7313 /// the locale's decimal point character
7314 const char decimal_point = '\0';
7315
7316 /// the indentation character
7317 const char indent_char;
7318
7319 /// the indentation string
7320 string_t indent_string;
7321 };
7322
7323 public:
7324 /*!
7325 @brief serialize to stream
7326
7327 Serialize the given JSON value @a j to the output stream @a o. The JSON
7328 value will be serialized using the @ref dump member function.
7329
7330 - The indentation of the output can be controlled with the member variable
7331 `width` of the output stream @a o. For instance, using the manipulator
7332 `std::setw(4)` on @a o sets the indentation level to `4` and the
7333 serialization result is the same as calling `dump(4)`.
7334
7335 - The indentation characrer can be controlled with the member variable
7336 `fill` of the output stream @a o. For instance, the manipulator
7337 `std::setfill('\\t')` sets indentation to use a tab character rather than
7338 the default space character.
7339
7340 @param[in,out] o stream to serialize to
7341 @param[in] j JSON value to serialize
7342
7343 @return the stream @a o
7344
7345 @complexity Linear.
7346
7347 @liveexample{The example below shows the serialization with different
7348 parameters to `width` to adjust the indentation level.,operator_serialize}
7349
7350 @since version 1.0.0; indentaction character added in version 3.0.0
7351 */
7352 friend std::ostream& operator<<(std::ostream& o, const basic_json& j)
7353 {
7354 // read width member and use it as indentation parameter if nonzero
7355 const bool pretty_print = (o.width() > 0);
7356 const auto indentation = (pretty_print ? o.width() : 0);
7357
7358 // reset width to 0 for subsequent calls to this stream
7359 o.width(0);
7360
7361 // do the actual serialization
7362 serializer s(output_adapter<char>::create(o), o.fill());
7363 s.dump(j, pretty_print, static_cast<unsigned int>(indentation));
7364 return o;
7365 }
7366
7367 /*!
7368 @brief serialize to stream
7369 @deprecated This stream operator is deprecated and will be removed in a
7370 future version of the library. Please use
7371 @ref std::ostream& operator<<(std::ostream&, const basic_json&)
7372 instead; that is, replace calls like `j >> o;` with `o << j;`.
7373 */
7374 JSON_DEPRECATED
7375 friend std::ostream& operator>>(const basic_json& j, std::ostream& o)
7376 {
7377 return o << j;
7378 }
7379
7380 /// @}
7381
7382
7383 /////////////////////
7384 // deserialization //
7385 /////////////////////
7386
7387 /// @name deserialization
7388 /// @{
7389
7390 /*!
7391 @brief deserialize from an array
7392
7393 This function reads from an array of 1-byte values.
7394
7395 @pre Each element of the container has a size of 1 byte. Violating this
7396 precondition yields undefined behavior. **This precondition is enforced
7397 with a static assertion.**
7398
7399 @param[in] array array to read from
7400 @param[in] cb a parser callback function of type @ref parser_callback_t
7401 which is used to control the deserialization by filtering unwanted values
7402 (optional)
7403
7404 @return result of the deserialization
7405
7406 @throw parse_error.101 if a parse error occurs; example: `""unexpected end
7407 of input; expected string literal""`
7408 @throw parse_error.102 if to_unicode fails or surrogate error
7409 @throw parse_error.103 if to_unicode fails
7410
7411 @complexity Linear in the length of the input. The parser is a predictive
7412 LL(1) parser. The complexity can be higher if the parser callback function
7413 @a cb has a super-linear complexity.
7414
7415 @note A UTF-8 byte order mark is silently ignored.
7416
7417 @liveexample{The example below demonstrates the `parse()` function reading
7418 from an array.,parse__array__parser_callback_t}
7419
7420 @since version 2.0.3
7421 */
7422 template<class T, std::size_t N>
7423 static basic_json parse(T (&array)[N],
7424 const parser_callback_t cb = nullptr)
7425 {
7426 // delegate the call to the iterator-range parse overload
7427 return parse(std::begin(array), std::end(array), cb);
7428 }
7429
7430 template<class T, std::size_t N>
7431 static bool accept(T (&array)[N])
7432 {
7433 // delegate the call to the iterator-range accept overload
7434 return accept(std::begin(array), std::end(array));
7435 }
7436
7437 /*!
7438 @brief deserialize from string literal
7439
7440 @tparam CharT character/literal type with size of 1 byte
7441 @param[in] s string literal to read a serialized JSON value from
7442 @param[in] cb a parser callback function of type @ref parser_callback_t
7443 which is used to control the deserialization by filtering unwanted values
7444 (optional)
7445
7446 @return result of the deserialization
7447
7448 @throw parse_error.101 in case of an unexpected token
7449 @throw parse_error.102 if to_unicode fails or surrogate error
7450 @throw parse_error.103 if to_unicode fails
7451
7452 @complexity Linear in the length of the input. The parser is a predictive
7453 LL(1) parser. The complexity can be higher if the parser callback function
7454 @a cb has a super-linear complexity.
7455
7456 @note A UTF-8 byte order mark is silently ignored.
7457 @note String containers like `std::string` or @ref string_t can be parsed
7458 with @ref parse(const ContiguousContainer&, const parser_callback_t)
7459
7460 @liveexample{The example below demonstrates the `parse()` function with
7461 and without callback function.,parse__string__parser_callback_t}
7462
7463 @sa @ref parse(std::istream&, const parser_callback_t) for a version that
7464 reads from an input stream
7465
7466 @since version 1.0.0 (originally for @ref string_t)
7467 */
7468 template<typename CharT, typename std::enable_if<
7469 std::is_pointer<CharT>::value and
7470 std::is_integral<typename std::remove_pointer<CharT>::type>::value and
7471 sizeof(typename std::remove_pointer<CharT>::type) == 1, int>::type = 0>
7472 static basic_json parse(const CharT s,
7473 const parser_callback_t cb = nullptr)
7474 {
7475 return parser(input_adapter::create(s), cb).parse(true);
7476 }
7477
7478 template<typename CharT, typename std::enable_if<
7479 std::is_pointer<CharT>::value and
7480 std::is_integral<typename std::remove_pointer<CharT>::type>::value and
7481 sizeof(typename std::remove_pointer<CharT>::type) == 1, int>::type = 0>
7482 static bool accept(const CharT s)
7483 {
7484 return parser(input_adapter::create(s)).accept(true);
7485 }
7486
7487 /*!
7488 @brief deserialize from stream
7489
7490 @param[in,out] i stream to read a serialized JSON value from
7491 @param[in] cb a parser callback function of type @ref parser_callback_t
7492 which is used to control the deserialization by filtering unwanted values
7493 (optional)
7494
7495 @return result of the deserialization
7496
7497 @throw parse_error.101 in case of an unexpected token
7498 @throw parse_error.102 if to_unicode fails or surrogate error
7499 @throw parse_error.103 if to_unicode fails
7500
7501 @complexity Linear in the length of the input. The parser is a predictive
7502 LL(1) parser. The complexity can be higher if the parser callback function
7503 @a cb has a super-linear complexity.
7504
7505 @note A UTF-8 byte order mark is silently ignored.
7506
7507 @liveexample{The example below demonstrates the `parse()` function with
7508 and without callback function.,parse__istream__parser_callback_t}
7509
7510 @sa @ref parse(const CharT, const parser_callback_t) for a version
7511 that reads from a string
7512
7513 @since version 1.0.0
7514 */
7515 static basic_json parse(std::istream& i,
7516 const parser_callback_t cb = nullptr)
7517 {
7518 return parser(input_adapter::create(i), cb).parse(true);
7519 }
7520
7521 static bool accept(std::istream& i)
7522 {
7523 return parser(input_adapter::create(i)).accept(true);
7524 }
7525
7526 /*!
7527 @copydoc parse(std::istream&, const parser_callback_t)
7528 */
7529 static basic_json parse(std::istream&& i,
7530 const parser_callback_t cb = nullptr)
7531 {
7532 return parser(input_adapter::create(i), cb).parse(true);
7533 }
7534
7535 static bool accept(std::istream&& i)
7536 {
7537 return parser(input_adapter::create(i)).accept(true);
7538 }
7539
7540 /*!
7541 @brief deserialize from an iterator range with contiguous storage
7542
7543 This function reads from an iterator range of a container with contiguous
7544 storage of 1-byte values. Compatible container types include
7545 `std::vector`, `std::string`, `std::array`, `std::valarray`, and
7546 `std::initializer_list`. Furthermore, C-style arrays can be used with
7547 `std::begin()`/`std::end()`. User-defined containers can be used as long
7548 as they implement random-access iterators and a contiguous storage.
7549
7550 @pre The iterator range is contiguous. Violating this precondition yields
7551 undefined behavior. **This precondition is enforced with an assertion.**
7552 @pre Each element in the range has a size of 1 byte. Violating this
7553 precondition yields undefined behavior. **This precondition is enforced
7554 with a static assertion.**
7555
7556 @warning There is no way to enforce all preconditions at compile-time. If
7557 the function is called with noncompliant iterators and with
7558 assertions switched off, the behavior is undefined and will most
7559 likely yield segmentation violation.
7560
7561 @tparam IteratorType iterator of container with contiguous storage
7562 @param[in] first begin of the range to parse (included)
7563 @param[in] last end of the range to parse (excluded)
7564 @param[in] cb a parser callback function of type @ref parser_callback_t
7565 which is used to control the deserialization by filtering unwanted values
7566 (optional)
7567
7568 @return result of the deserialization
7569
7570 @throw parse_error.101 in case of an unexpected token
7571 @throw parse_error.102 if to_unicode fails or surrogate error
7572 @throw parse_error.103 if to_unicode fails
7573
7574 @complexity Linear in the length of the input. The parser is a predictive
7575 LL(1) parser. The complexity can be higher if the parser callback function
7576 @a cb has a super-linear complexity.
7577
7578 @note A UTF-8 byte order mark is silently ignored.
7579
7580 @liveexample{The example below demonstrates the `parse()` function reading
7581 from an iterator range.,parse__iteratortype__parser_callback_t}
7582
7583 @since version 2.0.3
7584 */
7585 template<class IteratorType, typename std::enable_if<
7586 std::is_base_of<
7587 std::random_access_iterator_tag,
7588 typename std::iterator_traits<IteratorType>::iterator_category>::value, int>::type = 0>
7589 static basic_json parse(IteratorType first, IteratorType last,
7590 const parser_callback_t cb = nullptr)
7591 {
7592 return parser(input_adapter::create(first, last), cb).parse(true);
7593 }
7594
7595 template<class IteratorType, typename std::enable_if<
7596 std::is_base_of<
7597 std::random_access_iterator_tag,
7598 typename std::iterator_traits<IteratorType>::iterator_category>::value, int>::type = 0>
7599 static bool accept(IteratorType first, IteratorType last)
7600 {
7601 return parser(input_adapter::create(first, last)).accept(true);
7602 }
7603
7604 /*!
7605 @brief deserialize from a container with contiguous storage
7606
7607 This function reads from a container with contiguous storage of 1-byte
7608 values. Compatible container types include `std::vector`, `std::string`,
7609 `std::array`, and `std::initializer_list`. User-defined containers can be
7610 used as long as they implement random-access iterators and a contiguous
7611 storage.
7612
7613 @pre The container storage is contiguous. Violating this precondition
7614 yields undefined behavior. **This precondition is enforced with an
7615 assertion.**
7616 @pre Each element of the container has a size of 1 byte. Violating this
7617 precondition yields undefined behavior. **This precondition is enforced
7618 with a static assertion.**
7619
7620 @warning There is no way to enforce all preconditions at compile-time. If
7621 the function is called with a noncompliant container and with
7622 assertions switched off, the behavior is undefined and will most
7623 likely yield segmentation violation.
7624
7625 @tparam ContiguousContainer container type with contiguous storage
7626 @param[in] c container to read from
7627 @param[in] cb a parser callback function of type @ref parser_callback_t
7628 which is used to control the deserialization by filtering unwanted values
7629 (optional)
7630
7631 @return result of the deserialization
7632
7633 @throw parse_error.101 in case of an unexpected token
7634 @throw parse_error.102 if to_unicode fails or surrogate error
7635 @throw parse_error.103 if to_unicode fails
7636
7637 @complexity Linear in the length of the input. The parser is a predictive
7638 LL(1) parser. The complexity can be higher if the parser callback function
7639 @a cb has a super-linear complexity.
7640
7641 @note A UTF-8 byte order mark is silently ignored.
7642
7643 @liveexample{The example below demonstrates the `parse()` function reading
7644 from a contiguous container.,parse__contiguouscontainer__parser_callback_t}
7645
7646 @since version 2.0.3
7647 */
7648 template<class ContiguousContainer, typename std::enable_if<
7649 not std::is_pointer<ContiguousContainer>::value and
7650 std::is_base_of<
7651 std::random_access_iterator_tag,
7652 typename std::iterator_traits<decltype(std::begin(std::declval<ContiguousContainer const>()))>::iterator_category>::value
7653 , int>::type = 0>
7654 static basic_json parse(const ContiguousContainer& c,
7655 const parser_callback_t cb = nullptr)
7656 {
7657 // delegate the call to the iterator-range parse overload
7658 return parse(std::begin(c), std::end(c), cb);
7659 }
7660
7661 template<class ContiguousContainer, typename std::enable_if<
7662 not std::is_pointer<ContiguousContainer>::value and
7663 std::is_base_of<
7664 std::random_access_iterator_tag,
7665 typename std::iterator_traits<decltype(std::begin(std::declval<ContiguousContainer const>()))>::iterator_category>::value
7666 , int>::type = 0>
7667 static bool accept(const ContiguousContainer& c)
7668 {
7669 // delegate the call to the iterator-range accept overload
7670 return accept(std::begin(c), std::end(c));
7671 }
7672
7673 /*!
7674 @brief deserialize from stream
7675 @deprecated This stream operator is deprecated and will be removed in a
7676 future version of the library. Please use
7677 @ref std::istream& operator>>(std::istream&, basic_json&)
7678 instead; that is, replace calls like `j << i;` with `i >> j;`.
7679 */
7680 JSON_DEPRECATED
7681 friend std::istream& operator<<(basic_json& j, std::istream& i)
7682 {
7683 j = parser(input_adapter::create(i)).parse(false);
7684 return i;
7685 }
7686
7687 /*!
7688 @brief deserialize from stream
7689
7690 Deserializes an input stream to a JSON value.
7691
7692 @param[in,out] i input stream to read a serialized JSON value from
7693 @param[in,out] j JSON value to write the deserialized input to
7694
7695 @throw parse_error.101 in case of an unexpected token
7696 @throw parse_error.102 if to_unicode fails or surrogate error
7697 @throw parse_error.103 if to_unicode fails
7698
7699 @complexity Linear in the length of the input. The parser is a predictive
7700 LL(1) parser.
7701
7702 @note A UTF-8 byte order mark is silently ignored.
7703
7704 @liveexample{The example below shows how a JSON value is constructed by
7705 reading a serialization from a stream.,operator_deserialize}
7706
7707 @sa parse(std::istream&, const parser_callback_t) for a variant with a
7708 parser callback function to filter values while parsing
7709
7710 @since version 1.0.0
7711 */
7712 friend std::istream& operator>>(std::istream& i, basic_json& j)
7713 {
7714 j = parser(input_adapter::create(i)).parse(false);
7715 return i;
7716 }
7717
7718 /// @}
7719
7720 ///////////////////////////
7721 // convenience functions //
7722 ///////////////////////////
7723
7724 /*!
7725 @brief return the type as string
7726
7727 Returns the type name as string to be used in error messages - usually to
7728 indicate that a function was called on a wrong JSON type.
7729
7730 @return basically a string representation of a the @a m_type member
7731
7732 @complexity Constant.
7733
7734 @liveexample{The following code exemplifies `type_name()` for all JSON
7735 types.,type_name}
7736
7737 @since version 1.0.0, public since 2.1.0
7738 */
7739 std::string type_name() const
7740 {
7741 {
7742 switch (m_type)
7743 {
7744 case value_t::null:
7745 return "null";
7746 case value_t::object:
7747 return "object";
7748 case value_t::array:
7749 return "array";
7750 case value_t::string:
7751 return "string";
7752 case value_t::boolean:
7753 return "boolean";
7754 case value_t::discarded:
7755 return "discarded";
7756 default:
7757 return "number";
7758 }
7759 }
7760 }
7761
7762
7763 private:
7764 //////////////////////
7765 // member variables //
7766 //////////////////////
7767
7768 /// the type of the current element
7769 value_t m_type = value_t::null;
7770
7771 /// the value of the current element
7772 json_value m_value = {};
7773
7774
7775 private:
7776 ///////////////
7777 // iterators //
7778 ///////////////
7779
7780 /*!
7781 @brief an iterator for primitive JSON types
7782
7783 This class models an iterator for primitive JSON types (boolean, number,
7784 string). It's only purpose is to allow the iterator/const_iterator classes
7785 to "iterate" over primitive values. Internally, the iterator is modeled by
7786 a `difference_type` variable. Value begin_value (`0`) models the begin,
7787 end_value (`1`) models past the end.
7788 */
7789 class primitive_iterator_t
7790 {
7791 public:
7792
7793 difference_type get_value() const noexcept
7794 {
7795 return m_it;
7796 }
7797 /// set iterator to a defined beginning
7798 void set_begin() noexcept
7799 {
7800 m_it = begin_value;
7801 }
7802
7803 /// set iterator to a defined past the end
7804 void set_end() noexcept
7805 {
7806 m_it = end_value;
7807 }
7808
7809 /// return whether the iterator can be dereferenced
7810 constexpr bool is_begin() const noexcept
7811 {
7812 return (m_it == begin_value);
7813 }
7814
7815 /// return whether the iterator is at end
7816 constexpr bool is_end() const noexcept
7817 {
7818 return (m_it == end_value);
7819 }
7820
7821 friend constexpr bool operator==(primitive_iterator_t lhs, primitive_iterator_t rhs) noexcept
7822 {
7823 return lhs.m_it == rhs.m_it;
7824 }
7825
7826 friend constexpr bool operator!=(primitive_iterator_t lhs, primitive_iterator_t rhs) noexcept
7827 {
7828 return !(lhs == rhs);
7829 }
7830
7831 friend constexpr bool operator<(primitive_iterator_t lhs, primitive_iterator_t rhs) noexcept
7832 {
7833 return lhs.m_it < rhs.m_it;
7834 }
7835
7836 friend constexpr bool operator<=(primitive_iterator_t lhs, primitive_iterator_t rhs) noexcept
7837 {
7838 return lhs.m_it <= rhs.m_it;
7839 }
7840
7841 friend constexpr bool operator>(primitive_iterator_t lhs, primitive_iterator_t rhs) noexcept
7842 {
7843 return lhs.m_it > rhs.m_it;
7844 }
7845
7846 friend constexpr bool operator>=(primitive_iterator_t lhs, primitive_iterator_t rhs) noexcept
7847 {
7848 return lhs.m_it >= rhs.m_it;
7849 }
7850
7851 primitive_iterator_t operator+(difference_type i)
7852 {
7853 auto result = *this;
7854 result += i;
7855 return result;
7856 }
7857
7858 friend constexpr difference_type operator-(primitive_iterator_t lhs, primitive_iterator_t rhs) noexcept
7859 {
7860 return lhs.m_it - rhs.m_it;
7861 }
7862
7863 friend std::ostream& operator<<(std::ostream& os, primitive_iterator_t it)
7864 {
7865 return os << it.m_it;
7866 }
7867
7868 primitive_iterator_t& operator++()
7869 {
7870 ++m_it;
7871 return *this;
7872 }
7873
7874 primitive_iterator_t operator++(int)
7875 {
7876 auto result = *this;
7877 m_it++;
7878 return result;
7879 }
7880
7881 primitive_iterator_t& operator--()
7882 {
7883 --m_it;
7884 return *this;
7885 }
7886
7887 primitive_iterator_t operator--(int)
7888 {
7889 auto result = *this;
7890 m_it--;
7891 return result;
7892 }
7893
7894 primitive_iterator_t& operator+=(difference_type n)
7895 {
7896 m_it += n;
7897 return *this;
7898 }
7899
7900 primitive_iterator_t& operator-=(difference_type n)
7901 {
7902 m_it -= n;
7903 return *this;
7904 }
7905
7906 private:
7907 static constexpr difference_type begin_value = 0;
7908 static constexpr difference_type end_value = begin_value + 1;
7909
7910 /// iterator as signed integer type
7911 difference_type m_it = std::numeric_limits<std::ptrdiff_t>::denorm_min();
7912 };
7913
7914 /*!
7915 @brief an iterator value
7916
7917 @note This structure could easily be a union, but MSVC currently does not
7918 allow unions members with complex constructors, see
7919 https://github.com/nlohmann/json/pull/105.
7920 */
7921 struct internal_iterator
7922 {
7923 /// iterator for JSON objects
7924 typename object_t::iterator object_iterator;
7925 /// iterator for JSON arrays
7926 typename array_t::iterator array_iterator;
7927 /// generic iterator for all other types
7928 primitive_iterator_t primitive_iterator;
7929
7930 /// create an uninitialized internal_iterator
7931 internal_iterator() noexcept
7932 : object_iterator(), array_iterator(), primitive_iterator()
7933 {}
7934 };
7935
7936 /// proxy class for the iterator_wrapper functions
7937 template<typename IteratorType>
7938 class iteration_proxy
7939 {
7940 private:
7941 /// helper class for iteration
7942 class iteration_proxy_internal
7943 {
7944 private:
7945 /// the iterator
7946 IteratorType anchor;
7947 /// an index for arrays (used to create key names)
7948 size_t array_index = 0;
7949
7950 public:
7951 explicit iteration_proxy_internal(IteratorType it) noexcept
7952 : anchor(it)
7953 {}
7954
7955 /// dereference operator (needed for range-based for)
7956 iteration_proxy_internal& operator*()
7957 {
7958 return *this;
7959 }
7960
7961 /// increment operator (needed for range-based for)
7962 iteration_proxy_internal& operator++()
7963 {
7964 ++anchor;
7965 ++array_index;
7966
7967 return *this;
7968 }
7969
7970 /// inequality operator (needed for range-based for)
7971 bool operator!= (const iteration_proxy_internal& o) const
7972 {
7973 return anchor != o.anchor;
7974 }
7975
7976 /// return key of the iterator
7977 typename basic_json::string_t key() const
7978 {
7979 assert(anchor.m_object != nullptr);
7980
7981 switch (anchor.m_object->type())
7982 {
7983 // use integer array index as key
7984 case value_t::array:
7985 {
7986 return std::to_string(array_index);
7987 }
7988
7989 // use key from the object
7990 case value_t::object:
7991 {
7992 return anchor.key();
7993 }
7994
7995 // use an empty key for all primitive types
7996 default:
7997 {
7998 return "";
7999 }
8000 }
8001 }
8002
8003 /// return value of the iterator
8004 typename IteratorType::reference value() const
8005 {
8006 return anchor.value();
8007 }
8008 };
8009
8010 /// the container to iterate
8011 typename IteratorType::reference container;
8012
8013 public:
8014 /// construct iteration proxy from a container
8015 explicit iteration_proxy(typename IteratorType::reference cont)
8016 : container(cont)
8017 {}
8018
8019 /// return iterator begin (needed for range-based for)
8020 iteration_proxy_internal begin() noexcept
8021 {
8022 return iteration_proxy_internal(container.begin());
8023 }
8024
8025 /// return iterator end (needed for range-based for)
8026 iteration_proxy_internal end() noexcept
8027 {
8028 return iteration_proxy_internal(container.end());
8029 }
8030 };
8031
8032 public:
8033 /*!
8034 @brief a template for a random access iterator for the @ref basic_json class
8035
8036 This class implements a both iterators (iterator and const_iterator) for the
8037 @ref basic_json class.
8038
8039 @note An iterator is called *initialized* when a pointer to a JSON value
8040 has been set (e.g., by a constructor or a copy assignment). If the
8041 iterator is default-constructed, it is *uninitialized* and most
8042 methods are undefined. **The library uses assertions to detect calls
8043 on uninitialized iterators.**
8044
8045 @requirement The class satisfies the following concept requirements:
8046 - [RandomAccessIterator](http://en.cppreference.com/w/cpp/concept/RandomAccessIterator):
8047 The iterator that can be moved to point (forward and backward) to any
8048 element in constant time.
8049
8050 @since version 1.0.0, simplified in version 2.0.9
8051 */
8052 template<typename U>
8053 class iter_impl : public std::iterator<std::random_access_iterator_tag, U>
8054 {
8055 /// allow basic_json to access private members
8056 friend class basic_json;
8057
8058 // make sure U is basic_json or const basic_json
8059 static_assert(std::is_same<U, basic_json>::value
8060 or std::is_same<U, const basic_json>::value,
8061 "iter_impl only accepts (const) basic_json");
8062
8063 public:
8064 /// the type of the values when the iterator is dereferenced
8065 using value_type = typename basic_json::value_type;
8066 /// a type to represent differences between iterators
8067 using difference_type = typename basic_json::difference_type;
8068 /// defines a pointer to the type iterated over (value_type)
8069 using pointer = typename std::conditional<std::is_const<U>::value,
8070 typename basic_json::const_pointer,
8071 typename basic_json::pointer>::type;
8072 /// defines a reference to the type iterated over (value_type)
8073 using reference = typename std::conditional<std::is_const<U>::value,
8074 typename basic_json::const_reference,
8075 typename basic_json::reference>::type;
8076 /// the category of the iterator
8077 using iterator_category = std::bidirectional_iterator_tag;
8078
8079 /// default constructor
8080 iter_impl() = default;
8081
8082 /*!
8083 @brief constructor for a given JSON instance
8084 @param[in] object pointer to a JSON object for this iterator
8085 @pre object != nullptr
8086 @post The iterator is initialized; i.e. `m_object != nullptr`.
8087 */
8088 explicit iter_impl(pointer object) noexcept
8089 : m_object(object)
8090 {
8091 assert(m_object != nullptr);
8092
8093 switch (m_object->m_type)
8094 {
8095 case basic_json::value_t::object:
8096 {
8097 m_it.object_iterator = typename object_t::iterator();
8098 break;
8099 }
8100
8101 case basic_json::value_t::array:
8102 {
8103 m_it.array_iterator = typename array_t::iterator();
8104 break;
8105 }
8106
8107 default:
8108 {
8109 m_it.primitive_iterator = primitive_iterator_t();
8110 break;
8111 }
8112 }
8113 }
8114
8115 /*!
8116 @note The conventional copy constructor and copy assignment are
8117 implicitly defined.
8118 Combined with the following converting constructor and assignment,
8119 they support: copy from iterator to iterator,
8120 copy from const iterator to const iterator,
8121 and conversion from iterator to const iterator.
8122 However conversion from const iterator to iterator is not defined.
8123 */
8124
8125 /*!
8126 @brief converting constructor
8127 @param[in] other non-const iterator to copy from
8128 @note It is not checked whether @a other is initialized.
8129 */
8130 iter_impl(const iter_impl<basic_json>& other) noexcept
8131 : m_object(other.m_object), m_it(other.m_it)
8132 {}
8133
8134 /*!
8135 @brief converting assignment
8136 @param[in,out] other non-const iterator to copy from
8137 @return const/non-const iterator
8138 @note It is not checked whether @a other is initialized.
8139 */
8140 iter_impl& operator=(const iter_impl<basic_json>& other) noexcept
8141 {
8142 m_object = other.m_object;
8143 m_it = other.m_it;
8144 return *this;
8145 }
8146
8147 private:
8148 /*!
8149 @brief set the iterator to the first value
8150 @pre The iterator is initialized; i.e. `m_object != nullptr`.
8151 */
8152 void set_begin() noexcept
8153 {
8154 assert(m_object != nullptr);
8155
8156 switch (m_object->m_type)
8157 {
8158 case basic_json::value_t::object:
8159 {
8160 m_it.object_iterator = m_object->m_value.object->begin();
8161 break;
8162 }
8163
8164 case basic_json::value_t::array:
8165 {
8166 m_it.array_iterator = m_object->m_value.array->begin();
8167 break;
8168 }
8169
8170 case basic_json::value_t::null:
8171 {
8172 // set to end so begin()==end() is true: null is empty
8173 m_it.primitive_iterator.set_end();
8174 break;
8175 }
8176
8177 default:
8178 {
8179 m_it.primitive_iterator.set_begin();
8180 break;
8181 }
8182 }
8183 }
8184
8185 /*!
8186 @brief set the iterator past the last value
8187 @pre The iterator is initialized; i.e. `m_object != nullptr`.
8188 */
8189 void set_end() noexcept
8190 {
8191 assert(m_object != nullptr);
8192
8193 switch (m_object->m_type)
8194 {
8195 case basic_json::value_t::object:
8196 {
8197 m_it.object_iterator = m_object->m_value.object->end();
8198 break;
8199 }
8200
8201 case basic_json::value_t::array:
8202 {
8203 m_it.array_iterator = m_object->m_value.array->end();
8204 break;
8205 }
8206
8207 default:
8208 {
8209 m_it.primitive_iterator.set_end();
8210 break;
8211 }
8212 }
8213 }
8214
8215 public:
8216 /*!
8217 @brief return a reference to the value pointed to by the iterator
8218 @pre The iterator is initialized; i.e. `m_object != nullptr`.
8219 */
8220 reference operator*() const
8221 {
8222 assert(m_object != nullptr);
8223
8224 switch (m_object->m_type)
8225 {
8226 case basic_json::value_t::object:
8227 {
8228 assert(m_it.object_iterator != m_object->m_value.object->end());
8229 return m_it.object_iterator->second;
8230 }
8231
8232 case basic_json::value_t::array:
8233 {
8234 assert(m_it.array_iterator != m_object->m_value.array->end());
8235 return *m_it.array_iterator;
8236 }
8237
8238 case basic_json::value_t::null:
8239 {
8240 JSON_THROW(invalid_iterator::create(214, "cannot get value"));
8241 }
8242
8243 default:
8244 {
8245 if (m_it.primitive_iterator.is_begin())
8246 {
8247 return *m_object;
8248 }
8249
8250 JSON_THROW(invalid_iterator::create(214, "cannot get value"));
8251 }
8252 }
8253 }
8254
8255 /*!
8256 @brief dereference the iterator
8257 @pre The iterator is initialized; i.e. `m_object != nullptr`.
8258 */
8259 pointer operator->() const
8260 {
8261 assert(m_object != nullptr);
8262
8263 switch (m_object->m_type)
8264 {
8265 case basic_json::value_t::object:
8266 {
8267 assert(m_it.object_iterator != m_object->m_value.object->end());
8268 return &(m_it.object_iterator->second);
8269 }
8270
8271 case basic_json::value_t::array:
8272 {
8273 assert(m_it.array_iterator != m_object->m_value.array->end());
8274 return &*m_it.array_iterator;
8275 }
8276
8277 default:
8278 {
8279 if (m_it.primitive_iterator.is_begin())
8280 {
8281 return m_object;
8282 }
8283
8284 JSON_THROW(invalid_iterator::create(214, "cannot get value"));
8285 }
8286 }
8287 }
8288
8289 /*!
8290 @brief post-increment (it++)
8291 @pre The iterator is initialized; i.e. `m_object != nullptr`.
8292 */
8293 iter_impl operator++(int)
8294 {
8295 auto result = *this;
8296 ++(*this);
8297 return result;
8298 }
8299
8300 /*!
8301 @brief pre-increment (++it)
8302 @pre The iterator is initialized; i.e. `m_object != nullptr`.
8303 */
8304 iter_impl& operator++()
8305 {
8306 assert(m_object != nullptr);
8307
8308 switch (m_object->m_type)
8309 {
8310 case basic_json::value_t::object:
8311 {
8312 std::advance(m_it.object_iterator, 1);
8313 break;
8314 }
8315
8316 case basic_json::value_t::array:
8317 {
8318 std::advance(m_it.array_iterator, 1);
8319 break;
8320 }
8321
8322 default:
8323 {
8324 ++m_it.primitive_iterator;
8325 break;
8326 }
8327 }
8328
8329 return *this;
8330 }
8331
8332 /*!
8333 @brief post-decrement (it--)
8334 @pre The iterator is initialized; i.e. `m_object != nullptr`.
8335 */
8336 iter_impl operator--(int)
8337 {
8338 auto result = *this;
8339 --(*this);
8340 return result;
8341 }
8342
8343 /*!
8344 @brief pre-decrement (--it)
8345 @pre The iterator is initialized; i.e. `m_object != nullptr`.
8346 */
8347 iter_impl& operator--()
8348 {
8349 assert(m_object != nullptr);
8350
8351 switch (m_object->m_type)
8352 {
8353 case basic_json::value_t::object:
8354 {
8355 std::advance(m_it.object_iterator, -1);
8356 break;
8357 }
8358
8359 case basic_json::value_t::array:
8360 {
8361 std::advance(m_it.array_iterator, -1);
8362 break;
8363 }
8364
8365 default:
8366 {
8367 --m_it.primitive_iterator;
8368 break;
8369 }
8370 }
8371
8372 return *this;
8373 }
8374
8375 /*!
8376 @brief comparison: equal
8377 @pre The iterator is initialized; i.e. `m_object != nullptr`.
8378 */
8379 bool operator==(const iter_impl& other) const
8380 {
8381 // if objects are not the same, the comparison is undefined
8382 if (m_object != other.m_object)
8383 {
8384 JSON_THROW(invalid_iterator::create(212, "cannot compare iterators of different containers"));
8385 }
8386
8387 assert(m_object != nullptr);
8388
8389 switch (m_object->m_type)
8390 {
8391 case basic_json::value_t::object:
8392 {
8393 return (m_it.object_iterator == other.m_it.object_iterator);
8394 }
8395
8396 case basic_json::value_t::array:
8397 {
8398 return (m_it.array_iterator == other.m_it.array_iterator);
8399 }
8400
8401 default:
8402 {
8403 return (m_it.primitive_iterator == other.m_it.primitive_iterator);
8404 }
8405 }
8406 }
8407
8408 /*!
8409 @brief comparison: not equal
8410 @pre The iterator is initialized; i.e. `m_object != nullptr`.
8411 */
8412 bool operator!=(const iter_impl& other) const
8413 {
8414 return not operator==(other);
8415 }
8416
8417 /*!
8418 @brief comparison: smaller
8419 @pre The iterator is initialized; i.e. `m_object != nullptr`.
8420 */
8421 bool operator<(const iter_impl& other) const
8422 {
8423 // if objects are not the same, the comparison is undefined
8424 if (m_object != other.m_object)
8425 {
8426 JSON_THROW(invalid_iterator::create(212, "cannot compare iterators of different containers"));
8427 }
8428
8429 assert(m_object != nullptr);
8430
8431 switch (m_object->m_type)
8432 {
8433 case basic_json::value_t::object:
8434 {
8435 JSON_THROW(invalid_iterator::create(213, "cannot compare order of object iterators"));
8436 }
8437
8438 case basic_json::value_t::array:
8439 {
8440 return (m_it.array_iterator < other.m_it.array_iterator);
8441 }
8442
8443 default:
8444 {
8445 return (m_it.primitive_iterator < other.m_it.primitive_iterator);
8446 }
8447 }
8448 }
8449
8450 /*!
8451 @brief comparison: less than or equal
8452 @pre The iterator is initialized; i.e. `m_object != nullptr`.
8453 */
8454 bool operator<=(const iter_impl& other) const
8455 {
8456 return not other.operator < (*this);
8457 }
8458
8459 /*!
8460 @brief comparison: greater than
8461 @pre The iterator is initialized; i.e. `m_object != nullptr`.
8462 */
8463 bool operator>(const iter_impl& other) const
8464 {
8465 return not operator<=(other);
8466 }
8467
8468 /*!
8469 @brief comparison: greater than or equal
8470 @pre The iterator is initialized; i.e. `m_object != nullptr`.
8471 */
8472 bool operator>=(const iter_impl& other) const
8473 {
8474 return not operator<(other);
8475 }
8476
8477 /*!
8478 @brief add to iterator
8479 @pre The iterator is initialized; i.e. `m_object != nullptr`.
8480 */
8481 iter_impl& operator+=(difference_type i)
8482 {
8483 assert(m_object != nullptr);
8484
8485 switch (m_object->m_type)
8486 {
8487 case basic_json::value_t::object:
8488 {
8489 JSON_THROW(invalid_iterator::create(209, "cannot use offsets with object iterators"));
8490 }
8491
8492 case basic_json::value_t::array:
8493 {
8494 std::advance(m_it.array_iterator, i);
8495 break;
8496 }
8497
8498 default:
8499 {
8500 m_it.primitive_iterator += i;
8501 break;
8502 }
8503 }
8504
8505 return *this;
8506 }
8507
8508 /*!
8509 @brief subtract from iterator
8510 @pre The iterator is initialized; i.e. `m_object != nullptr`.
8511 */
8512 iter_impl& operator-=(difference_type i)
8513 {
8514 return operator+=(-i);
8515 }
8516
8517 /*!
8518 @brief add to iterator
8519 @pre The iterator is initialized; i.e. `m_object != nullptr`.
8520 */
8521 iter_impl operator+(difference_type i) const
8522 {
8523 auto result = *this;
8524 result += i;
8525 return result;
8526 }
8527
8528 /*!
8529 @brief addition of distance and iterator
8530 @pre The iterator is initialized; i.e. `m_object != nullptr`.
8531 */
8532 friend iter_impl operator+(difference_type i, const iter_impl& it)
8533 {
8534 auto result = it;
8535 result += i;
8536 return result;
8537 }
8538
8539 /*!
8540 @brief subtract from iterator
8541 @pre The iterator is initialized; i.e. `m_object != nullptr`.
8542 */
8543 iter_impl operator-(difference_type i) const
8544 {
8545 auto result = *this;
8546 result -= i;
8547 return result;
8548 }
8549
8550 /*!
8551 @brief return difference
8552 @pre The iterator is initialized; i.e. `m_object != nullptr`.
8553 */
8554 difference_type operator-(const iter_impl& other) const
8555 {
8556 assert(m_object != nullptr);
8557
8558 switch (m_object->m_type)
8559 {
8560 case basic_json::value_t::object:
8561 {
8562 JSON_THROW(invalid_iterator::create(209, "cannot use offsets with object iterators"));
8563 }
8564
8565 case basic_json::value_t::array:
8566 {
8567 return m_it.array_iterator - other.m_it.array_iterator;
8568 }
8569
8570 default:
8571 {
8572 return m_it.primitive_iterator - other.m_it.primitive_iterator;
8573 }
8574 }
8575 }
8576
8577 /*!
8578 @brief access to successor
8579 @pre The iterator is initialized; i.e. `m_object != nullptr`.
8580 */
8581 reference operator[](difference_type n) const
8582 {
8583 assert(m_object != nullptr);
8584
8585 switch (m_object->m_type)
8586 {
8587 case basic_json::value_t::object:
8588 {
8589 JSON_THROW(invalid_iterator::create(208, "cannot use operator[] for object iterators"));
8590 }
8591
8592 case basic_json::value_t::array:
8593 {
8594 return *std::next(m_it.array_iterator, n);
8595 }
8596
8597 case basic_json::value_t::null:
8598 {
8599 JSON_THROW(invalid_iterator::create(214, "cannot get value"));
8600 }
8601
8602 default:
8603 {
8604 if (m_it.primitive_iterator.get_value() == -n)
8605 {
8606 return *m_object;
8607 }
8608
8609 JSON_THROW(invalid_iterator::create(214, "cannot get value"));
8610 }
8611 }
8612 }
8613
8614 /*!
8615 @brief return the key of an object iterator
8616 @pre The iterator is initialized; i.e. `m_object != nullptr`.
8617 */
8618 typename object_t::key_type key() const
8619 {
8620 assert(m_object != nullptr);
8621
8622 if (m_object->is_object())
8623 {
8624 return m_it.object_iterator->first;
8625 }
8626
8627 JSON_THROW(invalid_iterator::create(207, "cannot use key() for non-object iterators"));
8628 }
8629
8630 /*!
8631 @brief return the value of an iterator
8632 @pre The iterator is initialized; i.e. `m_object != nullptr`.
8633 */
8634 reference value() const
8635 {
8636 return operator*();
8637 }
8638
8639 private:
8640 /// associated JSON instance
8641 pointer m_object = nullptr;
8642 /// the actual iterator of the associated instance
8643 struct internal_iterator m_it = internal_iterator();
8644 };
8645
8646 /*!
8647 @brief a template for a reverse iterator class
8648
8649 @tparam Base the base iterator type to reverse. Valid types are @ref
8650 iterator (to create @ref reverse_iterator) and @ref const_iterator (to
8651 create @ref const_reverse_iterator).
8652
8653 @requirement The class satisfies the following concept requirements:
8654 - [RandomAccessIterator](http://en.cppreference.com/w/cpp/concept/RandomAccessIterator):
8655 The iterator that can be moved to point (forward and backward) to any
8656 element in constant time.
8657 - [OutputIterator](http://en.cppreference.com/w/cpp/concept/OutputIterator):
8658 It is possible to write to the pointed-to element (only if @a Base is
8659 @ref iterator).
8660
8661 @since version 1.0.0
8662 */
8663 template<typename Base>
8664 class json_reverse_iterator : public std::reverse_iterator<Base>
8665 {
8666 public:
8667 /// shortcut to the reverse iterator adaptor
8668 using base_iterator = std::reverse_iterator<Base>;
8669 /// the reference type for the pointed-to element
8670 using reference = typename Base::reference;
8671
8672 /// create reverse iterator from iterator
8673 json_reverse_iterator(const typename base_iterator::iterator_type& it) noexcept
8674 : base_iterator(it)
8675 {}
8676
8677 /// create reverse iterator from base class
8678 json_reverse_iterator(const base_iterator& it) noexcept
8679 : base_iterator(it)
8680 {}
8681
8682 /// post-increment (it++)
8683 json_reverse_iterator operator++(int)
8684 {
8685 return static_cast<json_reverse_iterator>(base_iterator::operator++(1));
8686 }
8687
8688 /// pre-increment (++it)
8689 json_reverse_iterator& operator++()
8690 {
8691 return static_cast<json_reverse_iterator&>(base_iterator::operator++());
8692 }
8693
8694 /// post-decrement (it--)
8695 json_reverse_iterator operator--(int)
8696 {
8697 return static_cast<json_reverse_iterator>(base_iterator::operator--(1));
8698 }
8699
8700 /// pre-decrement (--it)
8701 json_reverse_iterator& operator--()
8702 {
8703 return static_cast<json_reverse_iterator&>(base_iterator::operator--());
8704 }
8705
8706 /// add to iterator
8707 json_reverse_iterator& operator+=(difference_type i)
8708 {
8709 return static_cast<json_reverse_iterator&>(base_iterator::operator+=(i));
8710 }
8711
8712 /// add to iterator
8713 json_reverse_iterator operator+(difference_type i) const
8714 {
8715 return static_cast<json_reverse_iterator>(base_iterator::operator+(i));
8716 }
8717
8718 /// subtract from iterator
8719 json_reverse_iterator operator-(difference_type i) const
8720 {
8721 return static_cast<json_reverse_iterator>(base_iterator::operator-(i));
8722 }
8723
8724 /// return difference
8725 difference_type operator-(const json_reverse_iterator& other) const
8726 {
8727 return base_iterator(*this) - base_iterator(other);
8728 }
8729
8730 /// access to successor
8731 reference operator[](difference_type n) const
8732 {
8733 return *(this->operator+(n));
8734 }
8735
8736 /// return the key of an object iterator
8737 typename object_t::key_type key() const
8738 {
8739 auto it = --this->base();
8740 return it.key();
8741 }
8742
8743 /// return the value of an iterator
8744 reference value() const
8745 {
8746 auto it = --this->base();
8747 return it.operator * ();
8748 }
8749 };
8750
8751
8752 private:
8753 ////////////////////
8754 // input adapters //
8755 ////////////////////
8756
8757 /// abstract input adapter interface
8758 class input_adapter
8759 {
8760 public:
8761 virtual int get_character() = 0;
8762 virtual std::string read(size_t offset, size_t length) = 0;
8763 virtual ~input_adapter() {}
8764
8765 // native support
8766
8767 /// input adapter for input stream
8768 static std::shared_ptr<input_adapter> create(std::istream& i)
8769 {
8770 return std::make_shared<cached_input_stream_adapter<16384>> (i);
8771 }
8772
8773 /// input adapter for input stream
8774 static std::shared_ptr<input_adapter> create(std::istream&& i)
8775 {
8776 return std::make_shared<cached_input_stream_adapter<16384>>(i);
8777 }
8778
8779 /// input adapter for buffer
8780 static std::shared_ptr<input_adapter> create(const char* b, size_t l)
8781 {
8782 return std::make_shared<input_buffer_adapter>(b, l);
8783 }
8784
8785 // derived support
8786
8787 /// input adapter for string literal
8788 template<typename CharT, typename std::enable_if<
8789 std::is_pointer<CharT>::value and
8790 std::is_integral<typename std::remove_pointer<CharT>::type>::value and
8791 sizeof(typename std::remove_pointer<CharT>::type) == 1, int>::type = 0>
8792 static std::shared_ptr<input_adapter> create(CharT b)
8793 {
8794 return create(reinterpret_cast<const char*>(b),
8795 std::strlen(reinterpret_cast<const char*>(b)));
8796 }
8797
8798 /// input adapter for iterator range with contiguous storage
8799 template<class IteratorType, typename std::enable_if<
8800 std::is_same<typename std::iterator_traits<IteratorType>::iterator_category, std::random_access_iterator_tag>::value
8801 , int>::type
8802 = 0>
8803 static std::shared_ptr<input_adapter> create(IteratorType first, IteratorType last)
8804 {
8805 // assertion to check that the iterator range is indeed contiguous,
8806 // see http://stackoverflow.com/a/35008842/266378 for more discussion
8807 assert(std::accumulate(first, last, std::pair<bool, int>(true, 0),
8808 [&first](std::pair<bool, int> res, decltype(*first) val)
8809 {
8810 res.first &= (val == *(std::next(std::addressof(*first), res.second++)));
8811 return res;
8812 }).first);
8813
8814 // assertion to check that each element is 1 byte long
8815 static_assert(sizeof(typename std::iterator_traits<IteratorType>::value_type) == 1,
8816 "each element in the iterator range must have the size of 1 byte");
8817
8818 const auto len = static_cast<size_t>(std::distance(first, last));
8819 if (JSON_LIKELY(len > 0))
8820 {
8821 // there is at least one element: use the address of first
8822 return create(reinterpret_cast<const char*>(&(*first)), len);
8823 }
8824 else
8825 {
8826 // the address of first cannot be used - use nullptr
8827 return create(nullptr, len);
8828 }
8829 }
8830
8831 /// input adapter for array
8832 template<class T, std::size_t N>
8833 static std::shared_ptr<input_adapter> create(T (&array)[N])
8834 {
8835 // delegate the call to the iterator-range overload
8836 return create(std::begin(array), std::end(array));
8837 }
8838
8839 /// input adapter for contiguous container
8840 template<class ContiguousContainer, typename std::enable_if<
8841 not std::is_pointer<ContiguousContainer>::value and
8842 std::is_base_of<
8843 std::random_access_iterator_tag,
8844 typename std::iterator_traits<decltype(std::begin(std::declval<ContiguousContainer const>()))>::iterator_category>::value
8845 , int>::type = 0>
8846 static std::shared_ptr<input_adapter> create(const ContiguousContainer& c)
8847 {
8848 // delegate the call to the iterator-range overload
8849 return create(std::begin(c), std::end(c));
8850 }
8851 };
8852
8853 /// a type to simplify interfaces
8854 using input_adapter_t = std::shared_ptr<input_adapter>;
8855
8856 /// input adapter for cached stream input
8857 template<std::size_t N>
8858 class cached_input_stream_adapter : public input_adapter
8859 {
8860 public:
8861 cached_input_stream_adapter(std::istream& i)
8862 : is(i), start_position(is.tellg())
8863 {
8864 fill_buffer();
8865
8866 // skip byte order mark
8867 if (fill_size >= 3 and buffer[0] == '\xEF' and buffer[1] == '\xBB' and buffer[2] == '\xBF')
8868 {
8869 buffer_pos += 3;
8870 processed_chars += 3;
8871 }
8872 }
8873
8874 ~cached_input_stream_adapter() override
8875 {
8876 // clear stream flags
8877 is.clear();
8878 // We initially read a lot of characters into the buffer, and we
8879 // may not have processed all of them. Therefore, we need to
8880 // "rewind" the stream after the last processed char.
8881 is.seekg(start_position);
8882 is.ignore(static_cast<std::streamsize>(processed_chars));
8883 // clear stream flags
8884 is.clear();
8885 }
8886
8887 int get_character() override
8888 {
8889 // check if refilling is necessary and possible
8890 if (buffer_pos == fill_size and not eof)
8891 {
8892 fill_buffer();
8893
8894 // check and remember that filling did not yield new input
8895 if (fill_size == 0)
8896 {
8897 eof = true;
8898 return std::char_traits<char>::eof();
8899 }
8900
8901 // the buffer is ready
8902 buffer_pos = 0;
8903 }
8904
8905 ++processed_chars;
8906 assert(buffer_pos < buffer.size());
8907 return buffer[buffer_pos++] & 0xFF;
8908 }
8909
8910 std::string read(size_t offset, size_t length) override
8911 {
8912 // create buffer
8913 std::string result(length, '\0');
8914
8915 // save stream position
8916 const auto current_pos = is.tellg();
8917 // save stream flags
8918 const auto flags = is.rdstate();
8919
8920 // clear stream flags
8921 is.clear();
8922 // set stream position
8923 is.seekg(static_cast<std::streamoff>(offset));
8924 // read bytes
8925 is.read(&result[0], static_cast<std::streamsize>(length));
8926
8927 // reset stream position
8928 is.seekg(current_pos);
8929 // reset stream flags
8930 is.setstate(flags);
8931
8932 return result;
8933 }
8934
8935 private:
8936 void fill_buffer()
8937 {
8938 // fill
8939 is.read(buffer.data(), static_cast<std::streamsize>(buffer.size()));
8940 // store number of bytes in the buffer
8941 fill_size = static_cast<size_t>(is.gcount());
8942 }
8943
8944 /// the associated input stream
8945 std::istream& is;
8946
8947 /// chars returned via get_character()
8948 size_t processed_chars = 0;
8949 /// chars processed in the current buffer
8950 size_t buffer_pos = 0;
8951
8952 /// whether stream reached eof
8953 bool eof = false;
8954 /// how many chars have been copied to the buffer by last (re)fill
8955 size_t fill_size = 0;
8956
8957 /// position of the stream when we started
8958 const std::streampos start_position;
8959
8960 /// internal buffer
8961 std::array<char, N> buffer{{}};
8962 };
8963
8964 /// input adapter for buffer input
8965 class input_buffer_adapter : public input_adapter
8966 {
8967 public:
8968 input_buffer_adapter(const char* b, size_t l)
8969 : input_adapter(), cursor(b), limit(b + l), start(b)
8970 {
8971 // skip byte order mark
8972 if (l >= 3 and b[0] == '\xEF' and b[1] == '\xBB' and b[2] == '\xBF')
8973 {
8974 cursor += 3;
8975 }
8976 }
8977
8978 // delete because of pointer members
8979 input_buffer_adapter(const input_buffer_adapter&) = delete;
8980 input_buffer_adapter& operator=(input_buffer_adapter&) = delete;
8981
8982 int get_character() noexcept override
8983 {
8984 if (JSON_LIKELY(cursor < limit))
8985 {
8986 return *(cursor++) & 0xFF;
8987 }
8988 else
8989 {
8990 return std::char_traits<char>::eof();
8991 }
8992 }
8993
8994 std::string read(size_t offset, size_t length) override
8995 {
8996 // avoid reading too many characters
8997 const size_t max_length = static_cast<size_t>(limit - start);
8998 return std::string(start + offset, (std::min)(length, max_length - offset));
8999 }
9000
9001 private:
9002 /// pointer to the current character
9003 const char* cursor;
9004 /// pointer past the last character
9005 const char* limit;
9006 /// pointer to the first character
9007 const char* start;
9008 };
9009
9010 //////////////////////////////////////////
9011 // binary serialization/deserialization //
9012 //////////////////////////////////////////
9013
9014 /// @name binary serialization/deserialization support
9015 /// @{
9016
9017 private:
9018 /*!
9019 @brief deserialization of CBOR and MessagePack values
9020 */
9021 class binary_reader
9022 {
9023 public:
9024 /*!
9025 @brief create a binary reader
9026
9027 @param[in] adapter input adapter to read from
9028 */
9029 explicit binary_reader(input_adapter_t adapter)
9030 : ia(adapter), is_little_endian(little_endianess())
9031 {
9032 assert(ia);
9033 }
9034
9035 /*!
9036 @brief create a JSON value from CBOR input
9037
9038 @param[in] get_char whether a new character should be retrieved from
9039 the input (true, default) or whether the last
9040 read character should be considered instead
9041
9042 @return JSON value created from CBOR input
9043
9044 @throw parse_error.110 if input ended unexpectedly
9045 @throw parse_error.112 if unsupported byte was read
9046 */
9047 basic_json parse_cbor(const bool get_char = true)
9048 {
9049 switch (get_char ? get() : current)
9050 {
9051 // EOF
9052 case std::char_traits<char>::eof():
9053 {
9054 JSON_THROW(parse_error::create(110, chars_read, "unexpected end of input"));
9055 }
9056
9057 // Integer 0x00..0x17 (0..23)
9058 case 0x00:
9059 case 0x01:
9060 case 0x02:
9061 case 0x03:
9062 case 0x04:
9063 case 0x05:
9064 case 0x06:
9065 case 0x07:
9066 case 0x08:
9067 case 0x09:
9068 case 0x0a:
9069 case 0x0b:
9070 case 0x0c:
9071 case 0x0d:
9072 case 0x0e:
9073 case 0x0f:
9074 case 0x10:
9075 case 0x11:
9076 case 0x12:
9077 case 0x13:
9078 case 0x14:
9079 case 0x15:
9080 case 0x16:
9081 case 0x17:
9082 {
9083 return static_cast<number_unsigned_t>(current);
9084 }
9085
9086 case 0x18: // Unsigned integer (one-byte uint8_t follows)
9087 {
9088 return get_number<uint8_t>();
9089 }
9090
9091 case 0x19: // Unsigned integer (two-byte uint16_t follows)
9092 {
9093 return get_number<uint16_t>();
9094 }
9095
9096 case 0x1a: // Unsigned integer (four-byte uint32_t follows)
9097 {
9098 return get_number<uint32_t>();
9099 }
9100
9101 case 0x1b: // Unsigned integer (eight-byte uint64_t follows)
9102 {
9103 return get_number<uint64_t>();
9104 }
9105
9106 // Negative integer -1-0x00..-1-0x17 (-1..-24)
9107 case 0x20:
9108 case 0x21:
9109 case 0x22:
9110 case 0x23:
9111 case 0x24:
9112 case 0x25:
9113 case 0x26:
9114 case 0x27:
9115 case 0x28:
9116 case 0x29:
9117 case 0x2a:
9118 case 0x2b:
9119 case 0x2c:
9120 case 0x2d:
9121 case 0x2e:
9122 case 0x2f:
9123 case 0x30:
9124 case 0x31:
9125 case 0x32:
9126 case 0x33:
9127 case 0x34:
9128 case 0x35:
9129 case 0x36:
9130 case 0x37:
9131 {
9132 return static_cast<int8_t>(0x20 - 1 - current);
9133 }
9134
9135 case 0x38: // Negative integer (one-byte uint8_t follows)
9136 {
9137 // must be uint8_t !
9138 return static_cast<number_integer_t>(-1) - get_number<uint8_t>();
9139 }
9140
9141 case 0x39: // Negative integer -1-n (two-byte uint16_t follows)
9142 {
9143 return static_cast<number_integer_t>(-1) - get_number<uint16_t>();
9144 }
9145
9146 case 0x3a: // Negative integer -1-n (four-byte uint32_t follows)
9147 {
9148 return static_cast<number_integer_t>(-1) - get_number<uint32_t>();
9149 }
9150
9151 case 0x3b: // Negative integer -1-n (eight-byte uint64_t follows)
9152 {
9153 return static_cast<number_integer_t>(-1) - static_cast<number_integer_t>(get_number<uint64_t>());
9154 }
9155
9156 // UTF-8 string (0x00..0x17 bytes follow)
9157 case 0x60:
9158 case 0x61:
9159 case 0x62:
9160 case 0x63:
9161 case 0x64:
9162 case 0x65:
9163 case 0x66:
9164 case 0x67:
9165 case 0x68:
9166 case 0x69:
9167 case 0x6a:
9168 case 0x6b:
9169 case 0x6c:
9170 case 0x6d:
9171 case 0x6e:
9172 case 0x6f:
9173 case 0x70:
9174 case 0x71:
9175 case 0x72:
9176 case 0x73:
9177 case 0x74:
9178 case 0x75:
9179 case 0x76:
9180 case 0x77:
9181 case 0x78: // UTF-8 string (one-byte uint8_t for n follows)
9182 case 0x79: // UTF-8 string (two-byte uint16_t for n follow)
9183 case 0x7a: // UTF-8 string (four-byte uint32_t for n follow)
9184 case 0x7b: // UTF-8 string (eight-byte uint64_t for n follow)
9185 case 0x7f: // UTF-8 string (indefinite length)
9186 {
9187 return get_cbor_string();
9188 }
9189
9190 // array (0x00..0x17 data items follow)
9191 case 0x80:
9192 case 0x81:
9193 case 0x82:
9194 case 0x83:
9195 case 0x84:
9196 case 0x85:
9197 case 0x86:
9198 case 0x87:
9199 case 0x88:
9200 case 0x89:
9201 case 0x8a:
9202 case 0x8b:
9203 case 0x8c:
9204 case 0x8d:
9205 case 0x8e:
9206 case 0x8f:
9207 case 0x90:
9208 case 0x91:
9209 case 0x92:
9210 case 0x93:
9211 case 0x94:
9212 case 0x95:
9213 case 0x96:
9214 case 0x97:
9215 {
9216 basic_json result = value_t::array;
9217 const auto len = static_cast<size_t>(current & 0x1f);
9218 for (size_t i = 0; i < len; ++i)
9219 {
9220 result.push_back(parse_cbor());
9221 }
9222 return result;
9223 }
9224
9225 case 0x98: // array (one-byte uint8_t for n follows)
9226 {
9227 basic_json result = value_t::array;
9228 const auto len = static_cast<size_t>(get_number<uint8_t>());
9229 for (size_t i = 0; i < len; ++i)
9230 {
9231 result.push_back(parse_cbor());
9232 }
9233 return result;
9234 }
9235
9236 case 0x99: // array (two-byte uint16_t for n follow)
9237 {
9238 basic_json result = value_t::array;
9239 const auto len = static_cast<size_t>(get_number<uint16_t>());
9240 for (size_t i = 0; i < len; ++i)
9241 {
9242 result.push_back(parse_cbor());
9243 }
9244 return result;
9245 }
9246
9247 case 0x9a: // array (four-byte uint32_t for n follow)
9248 {
9249 basic_json result = value_t::array;
9250 const auto len = static_cast<size_t>(get_number<uint32_t>());
9251 for (size_t i = 0; i < len; ++i)
9252 {
9253 result.push_back(parse_cbor());
9254 }
9255 return result;
9256 }
9257
9258 case 0x9b: // array (eight-byte uint64_t for n follow)
9259 {
9260 basic_json result = value_t::array;
9261 const auto len = static_cast<size_t>(get_number<uint64_t>());
9262 for (size_t i = 0; i < len; ++i)
9263 {
9264 result.push_back(parse_cbor());
9265 }
9266 return result;
9267 }
9268
9269 case 0x9f: // array (indefinite length)
9270 {
9271 basic_json result = value_t::array;
9272 while (get() != 0xff)
9273 {
9274 result.push_back(parse_cbor(false));
9275 }
9276 return result;
9277 }
9278
9279 // map (0x00..0x17 pairs of data items follow)
9280 case 0xa0:
9281 case 0xa1:
9282 case 0xa2:
9283 case 0xa3:
9284 case 0xa4:
9285 case 0xa5:
9286 case 0xa6:
9287 case 0xa7:
9288 case 0xa8:
9289 case 0xa9:
9290 case 0xaa:
9291 case 0xab:
9292 case 0xac:
9293 case 0xad:
9294 case 0xae:
9295 case 0xaf:
9296 case 0xb0:
9297 case 0xb1:
9298 case 0xb2:
9299 case 0xb3:
9300 case 0xb4:
9301 case 0xb5:
9302 case 0xb6:
9303 case 0xb7:
9304 {
9305 basic_json result = value_t::object;
9306 const auto len = static_cast<size_t>(current & 0x1f);
9307 for (size_t i = 0; i < len; ++i)
9308 {
9309 get();
9310 auto key = get_cbor_string();
9311 result[key] = parse_cbor();
9312 }
9313 return result;
9314 }
9315
9316 case 0xb8: // map (one-byte uint8_t for n follows)
9317 {
9318 basic_json result = value_t::object;
9319 const auto len = static_cast<size_t>(get_number<uint8_t>());
9320 for (size_t i = 0; i < len; ++i)
9321 {
9322 get();
9323 auto key = get_cbor_string();
9324 result[key] = parse_cbor();
9325 }
9326 return result;
9327 }
9328
9329 case 0xb9: // map (two-byte uint16_t for n follow)
9330 {
9331 basic_json result = value_t::object;
9332 const auto len = static_cast<size_t>(get_number<uint16_t>());
9333 for (size_t i = 0; i < len; ++i)
9334 {
9335 get();
9336 auto key = get_cbor_string();
9337 result[key] = parse_cbor();
9338 }
9339 return result;
9340 }
9341
9342 case 0xba: // map (four-byte uint32_t for n follow)
9343 {
9344 basic_json result = value_t::object;
9345 const auto len = static_cast<size_t>(get_number<uint32_t>());
9346 for (size_t i = 0; i < len; ++i)
9347 {
9348 get();
9349 auto key = get_cbor_string();
9350 result[key] = parse_cbor();
9351 }
9352 return result;
9353 }
9354
9355 case 0xbb: // map (eight-byte uint64_t for n follow)
9356 {
9357 basic_json result = value_t::object;
9358 const auto len = static_cast<size_t>(get_number<uint64_t>());
9359 for (size_t i = 0; i < len; ++i)
9360 {
9361 get();
9362 auto key = get_cbor_string();
9363 result[key] = parse_cbor();
9364 }
9365 return result;
9366 }
9367
9368 case 0xbf: // map (indefinite length)
9369 {
9370 basic_json result = value_t::object;
9371 while (get() != 0xff)
9372 {
9373 auto key = get_cbor_string();
9374 result[key] = parse_cbor();
9375 }
9376 return result;
9377 }
9378
9379 case 0xf4: // false
9380 {
9381 return false;
9382 }
9383
9384 case 0xf5: // true
9385 {
9386 return true;
9387 }
9388
9389 case 0xf6: // null
9390 {
9391 return value_t::null;
9392 }
9393
9394 case 0xf9: // Half-Precision Float (two-byte IEEE 754)
9395 {
9396 const int byte1 = get();
9397 check_eof();
9398 const int byte2 = get();
9399 check_eof();
9400
9401 // code from RFC 7049, Appendix D, Figure 3:
9402 // As half-precision floating-point numbers were only added
9403 // to IEEE 754 in 2008, today's programming platforms often
9404 // still only have limited support for them. It is very
9405 // easy to include at least decoding support for them even
9406 // without such support. An example of a small decoder for
9407 // half-precision floating-point numbers in the C language
9408 // is shown in Fig. 3.
9409 const int half = (byte1 << 8) + byte2;
9410 const int exp = (half >> 10) & 0x1f;
9411 const int mant = half & 0x3ff;
9412 double val;
9413 if (exp == 0)
9414 {
9415 val = std::ldexp(mant, -24);
9416 }
9417 else if (exp != 31)
9418 {
9419 val = std::ldexp(mant + 1024, exp - 25);
9420 }
9421 else
9422 {
9423 val = (mant == 0)
9424 ? std::numeric_limits<double>::infinity()
9425 : std::numeric_limits<double>::quiet_NaN();
9426 }
9427 return (half & 0x8000) != 0 ? -val : val;
9428 }
9429
9430 case 0xfa: // Single-Precision Float (four-byte IEEE 754)
9431 {
9432 return get_number<float>();
9433 }
9434
9435 case 0xfb: // Double-Precision Float (eight-byte IEEE 754)
9436 {
9437 return get_number<double>();
9438 }
9439
9440 default: // anything else (0xFF is handled inside the other types)
9441 {
9442 std::stringstream ss;
9443 ss << std::setw(2) << std::setfill('0') << std::hex << current;
9444 JSON_THROW(parse_error::create(112, chars_read, "error reading CBOR; last byte: 0x" + ss.str()));
9445 }
9446 }
9447 }
9448
9449 /*!
9450 @brief create a JSON value from MessagePack input
9451
9452 @return JSON value created from MessagePack input
9453
9454 @throw parse_error.110 if input ended unexpectedly
9455 @throw parse_error.112 if unsupported byte was read
9456 */
9457 basic_json parse_msgpack()
9458 {
9459 switch (get())
9460 {
9461 // EOF
9462 case std::char_traits<char>::eof():
9463 {
9464 JSON_THROW(parse_error::create(110, chars_read, "unexpected end of input"));
9465 }
9466
9467 // positive fixint
9468 case 0x00:
9469 case 0x01:
9470 case 0x02:
9471 case 0x03:
9472 case 0x04:
9473 case 0x05:
9474 case 0x06:
9475 case 0x07:
9476 case 0x08:
9477 case 0x09:
9478 case 0x0a:
9479 case 0x0b:
9480 case 0x0c:
9481 case 0x0d:
9482 case 0x0e:
9483 case 0x0f:
9484 case 0x10:
9485 case 0x11:
9486 case 0x12:
9487 case 0x13:
9488 case 0x14:
9489 case 0x15:
9490 case 0x16:
9491 case 0x17:
9492 case 0x18:
9493 case 0x19:
9494 case 0x1a:
9495 case 0x1b:
9496 case 0x1c:
9497 case 0x1d:
9498 case 0x1e:
9499 case 0x1f:
9500 case 0x20:
9501 case 0x21:
9502 case 0x22:
9503 case 0x23:
9504 case 0x24:
9505 case 0x25:
9506 case 0x26:
9507 case 0x27:
9508 case 0x28:
9509 case 0x29:
9510 case 0x2a:
9511 case 0x2b:
9512 case 0x2c:
9513 case 0x2d:
9514 case 0x2e:
9515 case 0x2f:
9516 case 0x30:
9517 case 0x31:
9518 case 0x32:
9519 case 0x33:
9520 case 0x34:
9521 case 0x35:
9522 case 0x36:
9523 case 0x37:
9524 case 0x38:
9525 case 0x39:
9526 case 0x3a:
9527 case 0x3b:
9528 case 0x3c:
9529 case 0x3d:
9530 case 0x3e:
9531 case 0x3f:
9532 case 0x40:
9533 case 0x41:
9534 case 0x42:
9535 case 0x43:
9536 case 0x44:
9537 case 0x45:
9538 case 0x46:
9539 case 0x47:
9540 case 0x48:
9541 case 0x49:
9542 case 0x4a:
9543 case 0x4b:
9544 case 0x4c:
9545 case 0x4d:
9546 case 0x4e:
9547 case 0x4f:
9548 case 0x50:
9549 case 0x51:
9550 case 0x52:
9551 case 0x53:
9552 case 0x54:
9553 case 0x55:
9554 case 0x56:
9555 case 0x57:
9556 case 0x58:
9557 case 0x59:
9558 case 0x5a:
9559 case 0x5b:
9560 case 0x5c:
9561 case 0x5d:
9562 case 0x5e:
9563 case 0x5f:
9564 case 0x60:
9565 case 0x61:
9566 case 0x62:
9567 case 0x63:
9568 case 0x64:
9569 case 0x65:
9570 case 0x66:
9571 case 0x67:
9572 case 0x68:
9573 case 0x69:
9574 case 0x6a:
9575 case 0x6b:
9576 case 0x6c:
9577 case 0x6d:
9578 case 0x6e:
9579 case 0x6f:
9580 case 0x70:
9581 case 0x71:
9582 case 0x72:
9583 case 0x73:
9584 case 0x74:
9585 case 0x75:
9586 case 0x76:
9587 case 0x77:
9588 case 0x78:
9589 case 0x79:
9590 case 0x7a:
9591 case 0x7b:
9592 case 0x7c:
9593 case 0x7d:
9594 case 0x7e:
9595 case 0x7f:
9596 {
9597 return static_cast<number_unsigned_t>(current);
9598 }
9599
9600 // fixmap
9601 case 0x80:
9602 case 0x81:
9603 case 0x82:
9604 case 0x83:
9605 case 0x84:
9606 case 0x85:
9607 case 0x86:
9608 case 0x87:
9609 case 0x88:
9610 case 0x89:
9611 case 0x8a:
9612 case 0x8b:
9613 case 0x8c:
9614 case 0x8d:
9615 case 0x8e:
9616 case 0x8f:
9617 {
9618 basic_json result = value_t::object;
9619 const auto len = static_cast<size_t>(current & 0x0f);
9620 for (size_t i = 0; i < len; ++i)
9621 {
9622 get();
9623 auto key = get_msgpack_string();
9624 result[key] = parse_msgpack();
9625 }
9626 return result;
9627 }
9628
9629 // fixarray
9630 case 0x90:
9631 case 0x91:
9632 case 0x92:
9633 case 0x93:
9634 case 0x94:
9635 case 0x95:
9636 case 0x96:
9637 case 0x97:
9638 case 0x98:
9639 case 0x99:
9640 case 0x9a:
9641 case 0x9b:
9642 case 0x9c:
9643 case 0x9d:
9644 case 0x9e:
9645 case 0x9f:
9646 {
9647 basic_json result = value_t::array;
9648 const auto len = static_cast<size_t>(current & 0x0f);
9649 for (size_t i = 0; i < len; ++i)
9650 {
9651 result.push_back(parse_msgpack());
9652 }
9653 return result;
9654 }
9655
9656 // fixstr
9657 case 0xa0:
9658 case 0xa1:
9659 case 0xa2:
9660 case 0xa3:
9661 case 0xa4:
9662 case 0xa5:
9663 case 0xa6:
9664 case 0xa7:
9665 case 0xa8:
9666 case 0xa9:
9667 case 0xaa:
9668 case 0xab:
9669 case 0xac:
9670 case 0xad:
9671 case 0xae:
9672 case 0xaf:
9673 case 0xb0:
9674 case 0xb1:
9675 case 0xb2:
9676 case 0xb3:
9677 case 0xb4:
9678 case 0xb5:
9679 case 0xb6:
9680 case 0xb7:
9681 case 0xb8:
9682 case 0xb9:
9683 case 0xba:
9684 case 0xbb:
9685 case 0xbc:
9686 case 0xbd:
9687 case 0xbe:
9688 case 0xbf:
9689 {
9690 return get_msgpack_string();
9691 }
9692
9693 case 0xc0: // nil
9694 {
9695 return value_t::null;
9696 }
9697
9698 case 0xc2: // false
9699 {
9700 return false;
9701 }
9702
9703 case 0xc3: // true
9704 {
9705 return true;
9706 }
9707
9708 case 0xca: // float 32
9709 {
9710 return get_number<float>();
9711 }
9712
9713 case 0xcb: // float 64
9714 {
9715 return get_number<double>();
9716 }
9717
9718 case 0xcc: // uint 8
9719 {
9720 return get_number<uint8_t>();
9721 }
9722
9723 case 0xcd: // uint 16
9724 {
9725 return get_number<uint16_t>();
9726 }
9727
9728 case 0xce: // uint 32
9729 {
9730 return get_number<uint32_t>();
9731 }
9732
9733 case 0xcf: // uint 64
9734 {
9735 return get_number<uint64_t>();
9736 }
9737
9738 case 0xd0: // int 8
9739 {
9740 return get_number<int8_t>();
9741 }
9742
9743 case 0xd1: // int 16
9744 {
9745 return get_number<int16_t>();
9746 }
9747
9748 case 0xd2: // int 32
9749 {
9750 return get_number<int32_t>();
9751 }
9752
9753 case 0xd3: // int 64
9754 {
9755 return get_number<int64_t>();
9756 }
9757
9758 case 0xd9: // str 8
9759 case 0xda: // str 16
9760 case 0xdb: // str 32
9761 {
9762 return get_msgpack_string();
9763 }
9764
9765 case 0xdc: // array 16
9766 {
9767 basic_json result = value_t::array;
9768 const auto len = static_cast<size_t>(get_number<uint16_t>());
9769 for (size_t i = 0; i < len; ++i)
9770 {
9771 result.push_back(parse_msgpack());
9772 }
9773 return result;
9774 }
9775
9776 case 0xdd: // array 32
9777 {
9778 basic_json result = value_t::array;
9779 const auto len = static_cast<size_t>(get_number<uint32_t>());
9780 for (size_t i = 0; i < len; ++i)
9781 {
9782 result.push_back(parse_msgpack());
9783 }
9784 return result;
9785 }
9786
9787 case 0xde: // map 16
9788 {
9789 basic_json result = value_t::object;
9790 const auto len = static_cast<size_t>(get_number<uint16_t>());
9791 for (size_t i = 0; i < len; ++i)
9792 {
9793 get();
9794 auto key = get_msgpack_string();
9795 result[key] = parse_msgpack();
9796 }
9797 return result;
9798 }
9799
9800 case 0xdf: // map 32
9801 {
9802 basic_json result = value_t::object;
9803 const auto len = static_cast<size_t>(get_number<uint32_t>());
9804 for (size_t i = 0; i < len; ++i)
9805 {
9806 get();
9807 auto key = get_msgpack_string();
9808 result[key] = parse_msgpack();
9809 }
9810 return result;
9811 }
9812
9813 // positive fixint
9814 case 0xe0:
9815 case 0xe1:
9816 case 0xe2:
9817 case 0xe3:
9818 case 0xe4:
9819 case 0xe5:
9820 case 0xe6:
9821 case 0xe7:
9822 case 0xe8:
9823 case 0xe9:
9824 case 0xea:
9825 case 0xeb:
9826 case 0xec:
9827 case 0xed:
9828 case 0xee:
9829 case 0xef:
9830 case 0xf0:
9831 case 0xf1:
9832 case 0xf2:
9833 case 0xf3:
9834 case 0xf4:
9835 case 0xf5:
9836 case 0xf6:
9837 case 0xf7:
9838 case 0xf8:
9839 case 0xf9:
9840 case 0xfa:
9841 case 0xfb:
9842 case 0xfc:
9843 case 0xfd:
9844 case 0xfe:
9845 case 0xff:
9846 {
9847 return static_cast<int8_t>(current);
9848 }
9849
9850 default: // anything else
9851 {
9852 std::stringstream ss;
9853 ss << std::setw(2) << std::setfill('0') << std::hex << current;
9854 JSON_THROW(parse_error::create(112, chars_read, "error reading MessagePack; last byte: 0x" + ss.str()));
9855 }
9856 }
9857 }
9858
9859 /*!
9860 @brief determine system byte order
9861
9862 @return true iff system's byte order is little endian
9863
9864 @note from http://stackoverflow.com/a/1001328/266378
9865 */
9866 static bool little_endianess() noexcept
9867 {
9868 int num = 1;
9869 return (*reinterpret_cast<char*>(&num) == 1);
9870 }
9871
9872 private:
9873 /*!
9874 @brief get next character from the input
9875
9876 This function provides the interface to the used input adapter. It does
9877 not throw in case the input reached EOF, but returns
9878 `std::char_traits<char>::eof()` in that case.
9879
9880 @return character read from the input
9881 */
9882 int get()
9883 {
9884 ++chars_read;
9885 return (current = ia->get_character());
9886 }
9887
9888 /*
9889 @brief read a number from the input
9890
9891 @tparam NumberType the type of the number
9892
9893 @return number of type @a NumberType
9894
9895 @note This function needs to respect the system's endianess, because
9896 bytes in CBOR and MessagePack are stored in network order (big
9897 endian) and therefore need reordering on little endian systems.
9898
9899 @throw parse_error.110 if input has less than `sizeof(NumberType)`
9900 bytes
9901 */
9902 template<typename NumberType>
9903 NumberType get_number()
9904 {
9905 // step 1: read input into array with system's byte order
9906 std::array<uint8_t, sizeof(NumberType)> vec;
9907 for (size_t i = 0; i < sizeof(NumberType); ++i)
9908 {
9909 get();
9910 check_eof();
9911
9912 // reverse byte order prior to conversion if necessary
9913 if (is_little_endian)
9914 {
9915 vec[sizeof(NumberType) - i - 1] = static_cast<uint8_t>(current);
9916 }
9917 else
9918 {
9919 vec[i] = static_cast<uint8_t>(current); // LCOV_EXCL_LINE
9920 }
9921 }
9922
9923 // step 2: convert array into number of type T and return
9924 NumberType result;
9925 std::memcpy(&result, vec.data(), sizeof(NumberType));
9926 return result;
9927 }
9928
9929 /*!
9930 @brief create a string by reading characters from the input
9931
9932 @param[in] len number of bytes to read
9933
9934 @note We can not reserve @a len bytes for the result, because @a len
9935 may be too large. Usually, @ref check_eof() detects the end of
9936 the input before we run out of string memory.
9937
9938 @return string created by reading @a len bytes
9939
9940 @throw parse_error.110 if input has less than @a len bytes
9941 */
9942 std::string get_string(const size_t len)
9943 {
9944 std::string result;
9945 for (size_t i = 0; i < len; ++i)
9946 {
9947 get();
9948 check_eof();
9949 result.append(1, static_cast<char>(current));
9950 }
9951 return result;
9952 }
9953
9954 /*!
9955 @brief reads a CBOR string
9956
9957 This function first reads starting bytes to determine the expected
9958 string length and then copies this number of bytes into a string.
9959 Additionally, CBOR's strings with indefinite lengths are supported.
9960
9961 @return string
9962
9963 @throw parse_error.110 if input ended
9964 @throw parse_error.113 if an unexpected byte is read
9965 */
9966 std::string get_cbor_string()
9967 {
9968 check_eof();
9969
9970 switch (current)
9971 {
9972 // UTF-8 string (0x00..0x17 bytes follow)
9973 case 0x60:
9974 case 0x61:
9975 case 0x62:
9976 case 0x63:
9977 case 0x64:
9978 case 0x65:
9979 case 0x66:
9980 case 0x67:
9981 case 0x68:
9982 case 0x69:
9983 case 0x6a:
9984 case 0x6b:
9985 case 0x6c:
9986 case 0x6d:
9987 case 0x6e:
9988 case 0x6f:
9989 case 0x70:
9990 case 0x71:
9991 case 0x72:
9992 case 0x73:
9993 case 0x74:
9994 case 0x75:
9995 case 0x76:
9996 case 0x77:
9997 {
9998 const auto len = static_cast<size_t>(current & 0x1f);
9999 return get_string(len);
10000 }
10001
10002 case 0x78: // UTF-8 string (one-byte uint8_t for n follows)
10003 {
10004 const auto len = static_cast<size_t>(get_number<uint8_t>());
10005 return get_string(len);
10006 }
10007
10008 case 0x79: // UTF-8 string (two-byte uint16_t for n follow)
10009 {
10010 const auto len = static_cast<size_t>(get_number<uint16_t>());
10011 return get_string(len);
10012 }
10013
10014 case 0x7a: // UTF-8 string (four-byte uint32_t for n follow)
10015 {
10016 const auto len = static_cast<size_t>(get_number<uint32_t>());
10017 return get_string(len);
10018 }
10019
10020 case 0x7b: // UTF-8 string (eight-byte uint64_t for n follow)
10021 {
10022 const auto len = static_cast<size_t>(get_number<uint64_t>());
10023 return get_string(len);
10024 }
10025
10026 case 0x7f: // UTF-8 string (indefinite length)
10027 {
10028 std::string result;
10029 while (get() != 0xff)
10030 {
10031 check_eof();
10032 result.append(1, static_cast<char>(current));
10033 }
10034 return result;
10035 }
10036
10037 default:
10038 {
10039 std::stringstream ss;
10040 ss << std::setw(2) << std::setfill('0') << std::hex << current;
10041 JSON_THROW(parse_error::create(113, chars_read, "expected a CBOR string; last byte: 0x" + ss.str()));
10042 }
10043 }
10044 }
10045
10046 /*!
10047 @brief reads a MessagePack string
10048
10049 This function first reads starting bytes to determine the expected
10050 string length and then copies this number of bytes into a string.
10051
10052 @return string
10053
10054 @throw parse_error.110 if input ended
10055 @throw parse_error.113 if an unexpected byte is read
10056 */
10057 std::string get_msgpack_string()
10058 {
10059 check_eof();
10060
10061 switch (current)
10062 {
10063 // fixstr
10064 case 0xa0:
10065 case 0xa1:
10066 case 0xa2:
10067 case 0xa3:
10068 case 0xa4:
10069 case 0xa5:
10070 case 0xa6:
10071 case 0xa7:
10072 case 0xa8:
10073 case 0xa9:
10074 case 0xaa:
10075 case 0xab:
10076 case 0xac:
10077 case 0xad:
10078 case 0xae:
10079 case 0xaf:
10080 case 0xb0:
10081 case 0xb1:
10082 case 0xb2:
10083 case 0xb3:
10084 case 0xb4:
10085 case 0xb5:
10086 case 0xb6:
10087 case 0xb7:
10088 case 0xb8:
10089 case 0xb9:
10090 case 0xba:
10091 case 0xbb:
10092 case 0xbc:
10093 case 0xbd:
10094 case 0xbe:
10095 case 0xbf:
10096 {
10097 const auto len = static_cast<size_t>(current & 0x1f);
10098 return get_string(len);
10099 }
10100
10101 case 0xd9: // str 8
10102 {
10103 const auto len = static_cast<size_t>(get_number<uint8_t>());
10104 return get_string(len);
10105 }
10106
10107 case 0xda: // str 16
10108 {
10109 const auto len = static_cast<size_t>(get_number<uint16_t>());
10110 return get_string(len);
10111 }
10112
10113 case 0xdb: // str 32
10114 {
10115 const auto len = static_cast<size_t>(get_number<uint32_t>());
10116 return get_string(len);
10117 }
10118
10119 default:
10120 {
10121 std::stringstream ss;
10122 ss << std::setw(2) << std::setfill('0') << std::hex << current;
10123 JSON_THROW(parse_error::create(113, chars_read, "expected a MessagePack string; last byte: 0x" + ss.str()));
10124 }
10125 }
10126 }
10127
10128 /*!
10129 @brief check if input ended
10130 @throw parse_error.110 if input ended
10131 */
10132 void check_eof() const
10133 {
10134 if (JSON_UNLIKELY(current == std::char_traits<char>::eof()))
10135 {
10136 JSON_THROW(parse_error::create(110, chars_read, "unexpected end of input"));
10137 }
10138 }
10139
10140 private:
10141 /// input adapter
10142 input_adapter_t ia = nullptr;
10143
10144 /// the current character
10145 int current = std::char_traits<char>::eof();
10146
10147 /// the number of characters read
10148 size_t chars_read = 0;
10149
10150 /// whether we can assume little endianess
10151 const bool is_little_endian = true;
10152 };
10153
10154 /*!
10155 @brief serialization to CBOR and MessagePack values
10156 */
10157 class binary_writer
10158 {
10159 public:
10160 /*!
10161 @brief create a binary writer
10162
10163 @param[in] adapter output adapter to write to
10164 */
10165 explicit binary_writer(output_adapter_t<uint8_t> adapter)
10166 : is_little_endian(binary_reader::little_endianess()), oa(adapter)
10167 {
10168 assert(oa);
10169 }
10170
10171 /*!
10172 @brief[in] j JSON value to serialize
10173 */
10174 void write_cbor(const basic_json& j)
10175 {
10176 switch (j.type())
10177 {
10178 case value_t::null:
10179 {
10180 oa->write_character(0xf6);
10181 break;
10182 }
10183
10184 case value_t::boolean:
10185 {
10186 oa->write_character(j.m_value.boolean ? 0xf5 : 0xf4);
10187 break;
10188 }
10189
10190 case value_t::number_integer:
10191 {
10192 if (j.m_value.number_integer >= 0)
10193 {
10194 // CBOR does not differentiate between positive signed
10195 // integers and unsigned integers. Therefore, we used the
10196 // code from the value_t::number_unsigned case here.
10197 if (j.m_value.number_integer <= 0x17)
10198 {
10199 write_number(static_cast<uint8_t>(j.m_value.number_integer));
10200 }
10201 else if (j.m_value.number_integer <= (std::numeric_limits<uint8_t>::max)())
10202 {
10203 oa->write_character(0x18);
10204 write_number(static_cast<uint8_t>(j.m_value.number_integer));
10205 }
10206 else if (j.m_value.number_integer <= (std::numeric_limits<uint16_t>::max)())
10207 {
10208 oa->write_character(0x19);
10209 write_number(static_cast<uint16_t>(j.m_value.number_integer));
10210 }
10211 else if (j.m_value.number_integer <= (std::numeric_limits<uint32_t>::max)())
10212 {
10213 oa->write_character(0x1a);
10214 write_number(static_cast<uint32_t>(j.m_value.number_integer));
10215 }
10216 else
10217 {
10218 oa->write_character(0x1b);
10219 write_number(static_cast<uint64_t>(j.m_value.number_integer));
10220 }
10221 }
10222 else
10223 {
10224 // The conversions below encode the sign in the first
10225 // byte, and the value is converted to a positive number.
10226 const auto positive_number = -1 - j.m_value.number_integer;
10227 if (j.m_value.number_integer >= -24)
10228 {
10229 write_number(static_cast<uint8_t>(0x20 + positive_number));
10230 }
10231 else if (positive_number <= (std::numeric_limits<uint8_t>::max)())
10232 {
10233 oa->write_character(0x38);
10234 write_number(static_cast<uint8_t>(positive_number));
10235 }
10236 else if (positive_number <= (std::numeric_limits<uint16_t>::max)())
10237 {
10238 oa->write_character(0x39);
10239 write_number(static_cast<uint16_t>(positive_number));
10240 }
10241 else if (positive_number <= (std::numeric_limits<uint32_t>::max)())
10242 {
10243 oa->write_character(0x3a);
10244 write_number(static_cast<uint32_t>(positive_number));
10245 }
10246 else
10247 {
10248 oa->write_character(0x3b);
10249 write_number(static_cast<uint64_t>(positive_number));
10250 }
10251 }
10252 break;
10253 }
10254
10255 case value_t::number_unsigned:
10256 {
10257 if (j.m_value.number_unsigned <= 0x17)
10258 {
10259 write_number(static_cast<uint8_t>(j.m_value.number_unsigned));
10260 }
10261 else if (j.m_value.number_unsigned <= (std::numeric_limits<uint8_t>::max)())
10262 {
10263 oa->write_character(0x18);
10264 write_number(static_cast<uint8_t>(j.m_value.number_unsigned));
10265 }
10266 else if (j.m_value.number_unsigned <= (std::numeric_limits<uint16_t>::max)())
10267 {
10268 oa->write_character(0x19);
10269 write_number(static_cast<uint16_t>(j.m_value.number_unsigned));
10270 }
10271 else if (j.m_value.number_unsigned <= (std::numeric_limits<uint32_t>::max)())
10272 {
10273 oa->write_character(0x1a);
10274 write_number(static_cast<uint32_t>(j.m_value.number_unsigned));
10275 }
10276 else
10277 {
10278 oa->write_character(0x1b);
10279 write_number(static_cast<uint64_t>(j.m_value.number_unsigned));
10280 }
10281 break;
10282 }
10283
10284 case value_t::number_float:
10285 {
10286 // Double-Precision Float
10287 oa->write_character(0xfb);
10288 write_number(j.m_value.number_float);
10289 break;
10290 }
10291
10292 case value_t::string:
10293 {
10294 // step 1: write control byte and the string length
10295 const auto N = j.m_value.string->size();
10296 if (N <= 0x17)
10297 {
10298 write_number(static_cast<uint8_t>(0x60 + N));
10299 }
10300 else if (N <= 0xff)
10301 {
10302 oa->write_character(0x78);
10303 write_number(static_cast<uint8_t>(N));
10304 }
10305 else if (N <= 0xffff)
10306 {
10307 oa->write_character(0x79);
10308 write_number(static_cast<uint16_t>(N));
10309 }
10310 else if (N <= 0xffffffff)
10311 {
10312 oa->write_character(0x7a);
10313 write_number(static_cast<uint32_t>(N));
10314 }
10315 // LCOV_EXCL_START
10316 else if (N <= 0xffffffffffffffff)
10317 {
10318 oa->write_character(0x7b);
10319 write_number(static_cast<uint64_t>(N));
10320 }
10321 // LCOV_EXCL_STOP
10322
10323 // step 2: write the string
10324 oa->write_characters(reinterpret_cast<const uint8_t*>(j.m_value.string->c_str()),
10325 j.m_value.string->size());
10326 break;
10327 }
10328
10329 case value_t::array:
10330 {
10331 // step 1: write control byte and the array size
10332 const auto N = j.m_value.array->size();
10333 if (N <= 0x17)
10334 {
10335 write_number(static_cast<uint8_t>(0x80 + N));
10336 }
10337 else if (N <= 0xff)
10338 {
10339 oa->write_character(0x98);
10340 write_number(static_cast<uint8_t>(N));
10341 }
10342 else if (N <= 0xffff)
10343 {
10344 oa->write_character(0x99);
10345 write_number(static_cast<uint16_t>(N));
10346 }
10347 else if (N <= 0xffffffff)
10348 {
10349 oa->write_character(0x9a);
10350 write_number(static_cast<uint32_t>(N));
10351 }
10352 // LCOV_EXCL_START
10353 else if (N <= 0xffffffffffffffff)
10354 {
10355 oa->write_character(0x9b);
10356 write_number(static_cast<uint64_t>(N));
10357 }
10358 // LCOV_EXCL_STOP
10359
10360 // step 2: write each element
10361 for (const auto& el : *j.m_value.array)
10362 {
10363 write_cbor(el);
10364 }
10365 break;
10366 }
10367
10368 case value_t::object:
10369 {
10370 // step 1: write control byte and the object size
10371 const auto N = j.m_value.object->size();
10372 if (N <= 0x17)
10373 {
10374 write_number(static_cast<uint8_t>(0xa0 + N));
10375 }
10376 else if (N <= 0xff)
10377 {
10378 oa->write_character(0xb8);
10379 write_number(static_cast<uint8_t>(N));
10380 }
10381 else if (N <= 0xffff)
10382 {
10383 oa->write_character(0xb9);
10384 write_number(static_cast<uint16_t>(N));
10385 }
10386 else if (N <= 0xffffffff)
10387 {
10388 oa->write_character(0xba);
10389 write_number(static_cast<uint32_t>(N));
10390 }
10391 // LCOV_EXCL_START
10392 else if (N <= 0xffffffffffffffff)
10393 {
10394 oa->write_character(0xbb);
10395 write_number(static_cast<uint64_t>(N));
10396 }
10397 // LCOV_EXCL_STOP
10398
10399 // step 2: write each element
10400 for (const auto& el : *j.m_value.object)
10401 {
10402 write_cbor(el.first);
10403 write_cbor(el.second);
10404 }
10405 break;
10406 }
10407
10408 default:
10409 {
10410 break;
10411 }
10412 }
10413 }
10414
10415 /*!
10416 @brief[in] j JSON value to serialize
10417 */
10418 void write_msgpack(const basic_json& j)
10419 {
10420 switch (j.type())
10421 {
10422 case value_t::null:
10423 {
10424 // nil
10425 oa->write_character(0xc0);
10426 break;
10427 }
10428
10429 case value_t::boolean:
10430 {
10431 // true and false
10432 oa->write_character(j.m_value.boolean ? 0xc3 : 0xc2);
10433 break;
10434 }
10435
10436 case value_t::number_integer:
10437 {
10438 if (j.m_value.number_integer >= 0)
10439 {
10440 // MessagePack does not differentiate between positive
10441 // signed integers and unsigned integers. Therefore, we
10442 // used the code from the value_t::number_unsigned case
10443 // here.
10444 if (j.m_value.number_unsigned < 128)
10445 {
10446 // positive fixnum
10447 write_number(static_cast<uint8_t>(j.m_value.number_integer));
10448 }
10449 else if (j.m_value.number_unsigned <= (std::numeric_limits<uint8_t>::max)())
10450 {
10451 // uint 8
10452 oa->write_character(0xcc);
10453 write_number(static_cast<uint8_t>(j.m_value.number_integer));
10454 }
10455 else if (j.m_value.number_unsigned <= (std::numeric_limits<uint16_t>::max)())
10456 {
10457 // uint 16
10458 oa->write_character(0xcd);
10459 write_number(static_cast<uint16_t>(j.m_value.number_integer));
10460 }
10461 else if (j.m_value.number_unsigned <= (std::numeric_limits<uint32_t>::max)())
10462 {
10463 // uint 32
10464 oa->write_character(0xce);
10465 write_number(static_cast<uint32_t>(j.m_value.number_integer));
10466 }
10467 else if (j.m_value.number_unsigned <= (std::numeric_limits<uint64_t>::max)())
10468 {
10469 // uint 64
10470 oa->write_character(0xcf);
10471 write_number(static_cast<uint64_t>(j.m_value.number_integer));
10472 }
10473 }
10474 else
10475 {
10476 if (j.m_value.number_integer >= -32)
10477 {
10478 // negative fixnum
10479 write_number(static_cast<int8_t>(j.m_value.number_integer));
10480 }
10481 else if (j.m_value.number_integer >= (std::numeric_limits<int8_t>::min)() and j.m_value.number_integer <= (std::numeric_limits<int8_t>::max)())
10482 {
10483 // int 8
10484 oa->write_character(0xd0);
10485 write_number(static_cast<int8_t>(j.m_value.number_integer));
10486 }
10487 else if (j.m_value.number_integer >= (std::numeric_limits<int16_t>::min)() and j.m_value.number_integer <= (std::numeric_limits<int16_t>::max)())
10488 {
10489 // int 16
10490 oa->write_character(0xd1);
10491 write_number(static_cast<int16_t>(j.m_value.number_integer));
10492 }
10493 else if (j.m_value.number_integer >= (std::numeric_limits<int32_t>::min)() and j.m_value.number_integer <= (std::numeric_limits<int32_t>::max)())
10494 {
10495 // int 32
10496 oa->write_character(0xd2);
10497 write_number(static_cast<int32_t>(j.m_value.number_integer));
10498 }
10499 else if (j.m_value.number_integer >= (std::numeric_limits<int64_t>::min)() and j.m_value.number_integer <= (std::numeric_limits<int64_t>::max)())
10500 {
10501 // int 64
10502 oa->write_character(0xd3);
10503 write_number(static_cast<int64_t>(j.m_value.number_integer));
10504 }
10505 }
10506 break;
10507 }
10508
10509 case value_t::number_unsigned:
10510 {
10511 if (j.m_value.number_unsigned < 128)
10512 {
10513 // positive fixnum
10514 write_number(static_cast<uint8_t>(j.m_value.number_integer));
10515 }
10516 else if (j.m_value.number_unsigned <= (std::numeric_limits<uint8_t>::max)())
10517 {
10518 // uint 8
10519 oa->write_character(0xcc);
10520 write_number(static_cast<uint8_t>(j.m_value.number_integer));
10521 }
10522 else if (j.m_value.number_unsigned <= (std::numeric_limits<uint16_t>::max)())
10523 {
10524 // uint 16
10525 oa->write_character(0xcd);
10526 write_number(static_cast<uint16_t>(j.m_value.number_integer));
10527 }
10528 else if (j.m_value.number_unsigned <= (std::numeric_limits<uint32_t>::max)())
10529 {
10530 // uint 32
10531 oa->write_character(0xce);
10532 write_number(static_cast<uint32_t>(j.m_value.number_integer));
10533 }
10534 else if (j.m_value.number_unsigned <= (std::numeric_limits<uint64_t>::max)())
10535 {
10536 // uint 64
10537 oa->write_character(0xcf);
10538 write_number(static_cast<uint64_t>(j.m_value.number_integer));
10539 }
10540 break;
10541 }
10542
10543 case value_t::number_float:
10544 {
10545 // float 64
10546 oa->write_character(0xcb);
10547 write_number(j.m_value.number_float);
10548 break;
10549 }
10550
10551 case value_t::string:
10552 {
10553 // step 1: write control byte and the string length
10554 const auto N = j.m_value.string->size();
10555 if (N <= 31)
10556 {
10557 // fixstr
10558 write_number(static_cast<uint8_t>(0xa0 | N));
10559 }
10560 else if (N <= 255)
10561 {
10562 // str 8
10563 oa->write_character(0xd9);
10564 write_number(static_cast<uint8_t>(N));
10565 }
10566 else if (N <= 65535)
10567 {
10568 // str 16
10569 oa->write_character(0xda);
10570 write_number(static_cast<uint16_t>(N));
10571 }
10572 else if (N <= 4294967295)
10573 {
10574 // str 32
10575 oa->write_character(0xdb);
10576 write_number(static_cast<uint32_t>(N));
10577 }
10578
10579 // step 2: write the string
10580 oa->write_characters(reinterpret_cast<const uint8_t*>(j.m_value.string->c_str()),
10581 j.m_value.string->size());
10582 break;
10583 }
10584
10585 case value_t::array:
10586 {
10587 // step 1: write control byte and the array size
10588 const auto N = j.m_value.array->size();
10589 if (N <= 15)
10590 {
10591 // fixarray
10592 write_number(static_cast<uint8_t>(0x90 | N));
10593 }
10594 else if (N <= 0xffff)
10595 {
10596 // array 16
10597 oa->write_character(0xdc);
10598 write_number(static_cast<uint16_t>(N));
10599 }
10600 else if (N <= 0xffffffff)
10601 {
10602 // array 32
10603 oa->write_character(0xdd);
10604 write_number(static_cast<uint32_t>(N));
10605 }
10606
10607 // step 2: write each element
10608 for (const auto& el : *j.m_value.array)
10609 {
10610 write_msgpack(el);
10611 }
10612 break;
10613 }
10614
10615 case value_t::object:
10616 {
10617 // step 1: write control byte and the object size
10618 const auto N = j.m_value.object->size();
10619 if (N <= 15)
10620 {
10621 // fixmap
10622 write_number(static_cast<uint8_t>(0x80 | (N & 0xf)));
10623 }
10624 else if (N <= 65535)
10625 {
10626 // map 16
10627 oa->write_character(0xde);
10628 write_number(static_cast<uint16_t>(N));
10629 }
10630 else if (N <= 4294967295)
10631 {
10632 // map 32
10633 oa->write_character(0xdf);
10634 write_number(static_cast<uint32_t>(N));
10635 }
10636
10637 // step 2: write each element
10638 for (const auto& el : *j.m_value.object)
10639 {
10640 write_msgpack(el.first);
10641 write_msgpack(el.second);
10642 }
10643 break;
10644 }
10645
10646 default:
10647 {
10648 break;
10649 }
10650 }
10651 }
10652
10653 private:
10654 /*
10655 @brief write a number to output input
10656
10657 @param[in] n number of type @a NumberType
10658 @tparam NumberType the type of the number
10659
10660 @note This function needs to respect the system's endianess, because
10661 bytes in CBOR and MessagePack are stored in network order (big
10662 endian) and therefore need reordering on little endian systems.
10663 */
10664 template<typename NumberType>
10665 void write_number(NumberType n)
10666 {
10667 // step 1: write number to array of length NumberType
10668 std::array<uint8_t, sizeof(NumberType)> vec;
10669 std::memcpy(vec.data(), &n, sizeof(NumberType));
10670
10671 // step 2: write array to output (with possible reordering)
10672 if (is_little_endian)
10673 {
10674 // reverse byte order prior to conversion if necessary
10675 std::reverse(vec.begin(), vec.end());
10676 }
10677
10678 oa->write_characters(vec.data(), sizeof(NumberType));
10679 }
10680
10681 private:
10682 /// whether we can assume little endianess
10683 const bool is_little_endian = true;
10684
10685 /// the output
10686 output_adapter_t<uint8_t> oa = nullptr;
10687 };
10688
10689 public:
10690 /*!
10691 @brief create a CBOR serialization of a given JSON value
10692
10693 Serializes a given JSON value @a j to a byte vector using the CBOR (Concise
10694 Binary Object Representation) serialization format. CBOR is a binary
10695 serialization format which aims to be more compact than JSON itself, yet
10696 more efficient to parse.
10697
10698 The library uses the following mapping from JSON values types to
10699 CBOR types according to the CBOR specification (RFC 7049):
10700
10701 JSON value type | value/range | CBOR type | first byte
10702 --------------- | ------------------------------------------ | ---------------------------------- | ---------------
10703 null | `null` | Null | 0xf6
10704 boolean | `true` | True | 0xf5
10705 boolean | `false` | False | 0xf4
10706 number_integer | -9223372036854775808..-2147483649 | Negative integer (8 bytes follow) | 0x3b
10707 number_integer | -2147483648..-32769 | Negative integer (4 bytes follow) | 0x3a
10708 number_integer | -32768..-129 | Negative integer (2 bytes follow) | 0x39
10709 number_integer | -128..-25 | Negative integer (1 byte follow) | 0x38
10710 number_integer | -24..-1 | Negative integer | 0x20..0x37
10711 number_integer | 0..23 | Integer | 0x00..0x17
10712 number_integer | 24..255 | Unsigned integer (1 byte follow) | 0x18
10713 number_integer | 256..65535 | Unsigned integer (2 bytes follow) | 0x19
10714 number_integer | 65536..4294967295 | Unsigned integer (4 bytes follow) | 0x1a
10715 number_integer | 4294967296..18446744073709551615 | Unsigned integer (8 bytes follow) | 0x1b
10716 number_unsigned | 0..23 | Integer | 0x00..0x17
10717 number_unsigned | 24..255 | Unsigned integer (1 byte follow) | 0x18
10718 number_unsigned | 256..65535 | Unsigned integer (2 bytes follow) | 0x19
10719 number_unsigned | 65536..4294967295 | Unsigned integer (4 bytes follow) | 0x1a
10720 number_unsigned | 4294967296..18446744073709551615 | Unsigned integer (8 bytes follow) | 0x1b
10721 number_float | *any value* | Double-Precision Float | 0xfb
10722 string | *length*: 0..23 | UTF-8 string | 0x60..0x77
10723 string | *length*: 23..255 | UTF-8 string (1 byte follow) | 0x78
10724 string | *length*: 256..65535 | UTF-8 string (2 bytes follow) | 0x79
10725 string | *length*: 65536..4294967295 | UTF-8 string (4 bytes follow) | 0x7a
10726 string | *length*: 4294967296..18446744073709551615 | UTF-8 string (8 bytes follow) | 0x7b
10727 array | *size*: 0..23 | array | 0x80..0x97
10728 array | *size*: 23..255 | array (1 byte follow) | 0x98
10729 array | *size*: 256..65535 | array (2 bytes follow) | 0x99
10730 array | *size*: 65536..4294967295 | array (4 bytes follow) | 0x9a
10731 array | *size*: 4294967296..18446744073709551615 | array (8 bytes follow) | 0x9b
10732 object | *size*: 0..23 | map | 0xa0..0xb7
10733 object | *size*: 23..255 | map (1 byte follow) | 0xb8
10734 object | *size*: 256..65535 | map (2 bytes follow) | 0xb9
10735 object | *size*: 65536..4294967295 | map (4 bytes follow) | 0xba
10736 object | *size*: 4294967296..18446744073709551615 | map (8 bytes follow) | 0xbb
10737
10738 @note The mapping is **complete** in the sense that any JSON value type
10739 can be converted to a CBOR value.
10740
10741 @note The following CBOR types are not used in the conversion:
10742 - byte strings (0x40..0x5f)
10743 - UTF-8 strings terminated by "break" (0x7f)
10744 - arrays terminated by "break" (0x9f)
10745 - maps terminated by "break" (0xbf)
10746 - date/time (0xc0..0xc1)
10747 - bignum (0xc2..0xc3)
10748 - decimal fraction (0xc4)
10749 - bigfloat (0xc5)
10750 - tagged items (0xc6..0xd4, 0xd8..0xdb)
10751 - expected conversions (0xd5..0xd7)
10752 - simple values (0xe0..0xf3, 0xf8)
10753 - undefined (0xf7)
10754 - half and single-precision floats (0xf9-0xfa)
10755 - break (0xff)
10756
10757 @param[in] j JSON value to serialize
10758 @return MessagePack serialization as byte vector
10759
10760 @complexity Linear in the size of the JSON value @a j.
10761
10762 @liveexample{The example shows the serialization of a JSON value to a byte
10763 vector in CBOR format.,to_cbor}
10764
10765 @sa http://cbor.io
10766 @sa @ref from_cbor(const std::vector<uint8_t>&, const size_t) for the
10767 analogous deserialization
10768 @sa @ref to_msgpack(const basic_json& for the related MessagePack format
10769
10770 @since version 2.0.9
10771 */
10772 static std::vector<uint8_t> to_cbor(const basic_json& j)
10773 {
10774 std::vector<uint8_t> result;
10775 binary_writer bw(output_adapter<uint8_t>::create(result));
10776 bw.write_cbor(j);
10777 return result;
10778 }
10779
10780 /*!
10781 @brief create a MessagePack serialization of a given JSON value
10782
10783 Serializes a given JSON value @a j to a byte vector using the MessagePack
10784 serialization format. MessagePack is a binary serialization format which
10785 aims to be more compact than JSON itself, yet more efficient to parse.
10786
10787 The library uses the following mapping from JSON values types to
10788 MessagePack types according to the MessagePack specification:
10789
10790 JSON value type | value/range | MessagePack type | first byte
10791 --------------- | --------------------------------- | ---------------- | ----------
10792 null | `null` | nil | 0xc0
10793 boolean | `true` | true | 0xc3
10794 boolean | `false` | false | 0xc2
10795 number_integer | -9223372036854775808..-2147483649 | int64 | 0xd3
10796 number_integer | -2147483648..-32769 | int32 | 0xd2
10797 number_integer | -32768..-129 | int16 | 0xd1
10798 number_integer | -128..-33 | int8 | 0xd0
10799 number_integer | -32..-1 | negative fixint | 0xe0..0xff
10800 number_integer | 0..127 | positive fixint | 0x00..0x7f
10801 number_integer | 128..255 | uint 8 | 0xcc
10802 number_integer | 256..65535 | uint 16 | 0xcd
10803 number_integer | 65536..4294967295 | uint 32 | 0xce
10804 number_integer | 4294967296..18446744073709551615 | uint 64 | 0xcf
10805 number_unsigned | 0..127 | positive fixint | 0x00..0x7f
10806 number_unsigned | 128..255 | uint 8 | 0xcc
10807 number_unsigned | 256..65535 | uint 16 | 0xcd
10808 number_unsigned | 65536..4294967295 | uint 32 | 0xce
10809 number_unsigned | 4294967296..18446744073709551615 | uint 64 | 0xcf
10810 number_float | *any value* | float 64 | 0xcb
10811 string | *length*: 0..31 | fixstr | 0xa0..0xbf
10812 string | *length*: 32..255 | str 8 | 0xd9
10813 string | *length*: 256..65535 | str 16 | 0xda
10814 string | *length*: 65536..4294967295 | str 32 | 0xdb
10815 array | *size*: 0..15 | fixarray | 0x90..0x9f
10816 array | *size*: 16..65535 | array 16 | 0xdc
10817 array | *size*: 65536..4294967295 | array 32 | 0xdd
10818 object | *size*: 0..15 | fix map | 0x80..0x8f
10819 object | *size*: 16..65535 | map 16 | 0xde
10820 object | *size*: 65536..4294967295 | map 32 | 0xdf
10821
10822 @note The mapping is **complete** in the sense that any JSON value type
10823 can be converted to a MessagePack value.
10824
10825 @note The following values can **not** be converted to a MessagePack value:
10826 - strings with more than 4294967295 bytes
10827 - arrays with more than 4294967295 elements
10828 - objects with more than 4294967295 elements
10829
10830 @note The following MessagePack types are not used in the conversion:
10831 - bin 8 - bin 32 (0xc4..0xc6)
10832 - ext 8 - ext 32 (0xc7..0xc9)
10833 - float 32 (0xca)
10834 - fixext 1 - fixext 16 (0xd4..0xd8)
10835
10836 @note Any MessagePack output created @ref to_msgpack can be successfully
10837 parsed by @ref from_msgpack.
10838
10839 @param[in] j JSON value to serialize
10840 @return MessagePack serialization as byte vector
10841
10842 @complexity Linear in the size of the JSON value @a j.
10843
10844 @liveexample{The example shows the serialization of a JSON value to a byte
10845 vector in MessagePack format.,to_msgpack}
10846
10847 @sa http://msgpack.org
10848 @sa @ref from_msgpack(const std::vector<uint8_t>&, const size_t) for the
10849 analogous deserialization
10850 @sa @ref to_cbor(const basic_json& for the related CBOR format
10851
10852 @since version 2.0.9
10853 */
10854 static std::vector<uint8_t> to_msgpack(const basic_json& j)
10855 {
10856 std::vector<uint8_t> result;
10857 binary_writer bw(output_adapter<uint8_t>::create(result));
10858 bw.write_msgpack(j);
10859 return result;
10860 }
10861
10862 /*!
10863 @brief create a JSON value from a byte vector in CBOR format
10864
10865 Deserializes a given byte vector @a v to a JSON value using the CBOR
10866 (Concise Binary Object Representation) serialization format.
10867
10868 The library maps CBOR types to JSON value types as follows:
10869
10870 CBOR type | JSON value type | first byte
10871 ---------------------- | --------------- | ----------
10872 Integer | number_unsigned | 0x00..0x17
10873 Unsigned integer | number_unsigned | 0x18
10874 Unsigned integer | number_unsigned | 0x19
10875 Unsigned integer | number_unsigned | 0x1a
10876 Unsigned integer | number_unsigned | 0x1b
10877 Negative integer | number_integer | 0x20..0x37
10878 Negative integer | number_integer | 0x38
10879 Negative integer | number_integer | 0x39
10880 Negative integer | number_integer | 0x3a
10881 Negative integer | number_integer | 0x3b
10882 Negative integer | number_integer | 0x40..0x57
10883 UTF-8 string | string | 0x60..0x77
10884 UTF-8 string | string | 0x78
10885 UTF-8 string | string | 0x79
10886 UTF-8 string | string | 0x7a
10887 UTF-8 string | string | 0x7b
10888 UTF-8 string | string | 0x7f
10889 array | array | 0x80..0x97
10890 array | array | 0x98
10891 array | array | 0x99
10892 array | array | 0x9a
10893 array | array | 0x9b
10894 array | array | 0x9f
10895 map | object | 0xa0..0xb7
10896 map | object | 0xb8
10897 map | object | 0xb9
10898 map | object | 0xba
10899 map | object | 0xbb
10900 map | object | 0xbf
10901 False | `false` | 0xf4
10902 True | `true` | 0xf5
10903 Nill | `null` | 0xf6
10904 Half-Precision Float | number_float | 0xf9
10905 Single-Precision Float | number_float | 0xfa
10906 Double-Precision Float | number_float | 0xfb
10907
10908 @warning The mapping is **incomplete** in the sense that not all CBOR
10909 types can be converted to a JSON value. The following CBOR types
10910 are not supported and will yield parse errors (parse_error.112):
10911 - byte strings (0x40..0x5f)
10912 - date/time (0xc0..0xc1)
10913 - bignum (0xc2..0xc3)
10914 - decimal fraction (0xc4)
10915 - bigfloat (0xc5)
10916 - tagged items (0xc6..0xd4, 0xd8..0xdb)
10917 - expected conversions (0xd5..0xd7)
10918 - simple values (0xe0..0xf3, 0xf8)
10919 - undefined (0xf7)
10920
10921 @warning CBOR allows map keys of any type, whereas JSON only allows
10922 strings as keys in object values. Therefore, CBOR maps with keys
10923 other than UTF-8 strings are rejected (parse_error.113).
10924
10925 @note Any CBOR output created @ref to_cbor can be successfully parsed by
10926 @ref from_cbor.
10927
10928 @param[in] v a byte vector in CBOR format
10929 @param[in] start_index the index to start reading from @a v (0 by default)
10930 @return deserialized JSON value
10931
10932 @throw parse_error.110 if the given vector ends prematurely
10933 @throw parse_error.112 if unsupported features from CBOR were
10934 used in the given vector @a v or if the input is not valid CBOR
10935 @throw parse_error.113 if a string was expected as map key, but not found
10936
10937 @complexity Linear in the size of the byte vector @a v.
10938
10939 @liveexample{The example shows the deserialization of a byte vector in CBOR
10940 format to a JSON value.,from_cbor}
10941
10942 @sa http://cbor.io
10943 @sa @ref to_cbor(const basic_json&) for the analogous serialization
10944 @sa @ref from_msgpack(const std::vector<uint8_t>&, const size_t) for the
10945 related MessagePack format
10946
10947 @since version 2.0.9, parameter @a start_index since 2.1.1
10948 */
10949 static basic_json from_cbor(const std::vector<uint8_t>& v,
10950 const size_t start_index = 0)
10951 {
10952 binary_reader br(input_adapter::create(v.begin() + static_cast<difference_type>(start_index), v.end()));
10953 return br.parse_cbor();
10954 }
10955
10956
10957 /*!
10958 @brief create a JSON value from a byte vector in MessagePack format
10959
10960 Deserializes a given byte vector @a v to a JSON value using the MessagePack
10961 serialization format.
10962
10963 The library maps MessagePack types to JSON value types as follows:
10964
10965 MessagePack type | JSON value type | first byte
10966 ---------------- | --------------- | ----------
10967 positive fixint | number_unsigned | 0x00..0x7f
10968 fixmap | object | 0x80..0x8f
10969 fixarray | array | 0x90..0x9f
10970 fixstr | string | 0xa0..0xbf
10971 nil | `null` | 0xc0
10972 false | `false` | 0xc2
10973 true | `true` | 0xc3
10974 float 32 | number_float | 0xca
10975 float 64 | number_float | 0xcb
10976 uint 8 | number_unsigned | 0xcc
10977 uint 16 | number_unsigned | 0xcd
10978 uint 32 | number_unsigned | 0xce
10979 uint 64 | number_unsigned | 0xcf
10980 int 8 | number_integer | 0xd0
10981 int 16 | number_integer | 0xd1
10982 int 32 | number_integer | 0xd2
10983 int 64 | number_integer | 0xd3
10984 str 8 | string | 0xd9
10985 str 16 | string | 0xda
10986 str 32 | string | 0xdb
10987 array 16 | array | 0xdc
10988 array 32 | array | 0xdd
10989 map 16 | object | 0xde
10990 map 32 | object | 0xdf
10991 negative fixint | number_integer | 0xe0-0xff
10992
10993 @warning The mapping is **incomplete** in the sense that not all
10994 MessagePack types can be converted to a JSON value. The following
10995 MessagePack types are not supported and will yield parse errors:
10996 - bin 8 - bin 32 (0xc4..0xc6)
10997 - ext 8 - ext 32 (0xc7..0xc9)
10998 - fixext 1 - fixext 16 (0xd4..0xd8)
10999
11000 @note Any MessagePack output created @ref to_msgpack can be successfully
11001 parsed by @ref from_msgpack.
11002
11003 @param[in] v a byte vector in MessagePack format
11004 @param[in] start_index the index to start reading from @a v (0 by default)
11005 @return deserialized JSON value
11006
11007 @throw parse_error.110 if the given vector ends prematurely
11008 @throw parse_error.112 if unsupported features from MessagePack were
11009 used in the given vector @a v or if the input is not valid MessagePack
11010 @throw parse_error.113 if a string was expected as map key, but not found
11011
11012 @complexity Linear in the size of the byte vector @a v.
11013
11014 @liveexample{The example shows the deserialization of a byte vector in
11015 MessagePack format to a JSON value.,from_msgpack}
11016
11017 @sa http://msgpack.org
11018 @sa @ref to_msgpack(const basic_json&) for the analogous serialization
11019 @sa @ref from_cbor(const std::vector<uint8_t>&, const size_t) for the
11020 related CBOR format
11021
11022 @since version 2.0.9, parameter @a start_index since 2.1.1
11023 */
11024 static basic_json from_msgpack(const std::vector<uint8_t>& v,
11025 const size_t start_index = 0)
11026 {
11027 binary_reader br(input_adapter::create(v.begin() + static_cast<difference_type>(start_index), v.end()));
11028 return br.parse_msgpack();
11029 }
11030
11031 /// @}
11032
11033 //////////////////////
11034 // lexer and parser //
11035 //////////////////////
11036
11037 private:
11038 /*!
11039 @brief lexical analysis
11040
11041 This class organizes the lexical analysis during JSON deserialization.
11042 */
11043 class lexer
11044 {
11045 public:
11046 /// token types for the parser
11047 enum class token_type
11048 {
11049 uninitialized, ///< indicating the scanner is uninitialized
11050 literal_true, ///< the `true` literal
11051 literal_false, ///< the `false` literal
11052 literal_null, ///< the `null` literal
11053 value_string, ///< a string -- use get_string() for actual value
11054 value_unsigned, ///< an unsigned integer -- use get_number_unsigned() for actual value
11055 value_integer, ///< a signed integer -- use get_number_integer() for actual value
11056 value_float, ///< an floating point number -- use get_number_float() for actual value
11057 begin_array, ///< the character for array begin `[`
11058 begin_object, ///< the character for object begin `{`
11059 end_array, ///< the character for array end `]`
11060 end_object, ///< the character for object end `}`
11061 name_separator, ///< the name separator `:`
11062 value_separator, ///< the value separator `,`
11063 parse_error, ///< indicating a parse error
11064 end_of_input, ///< indicating the end of the input buffer
11065 literal_or_value ///< a literal or the begin of a value (only for diagnostics)
11066 };
11067
11068 /// return name of values of type token_type (only used for errors)
11069 static const char* token_type_name(const token_type t) noexcept
11070 {
11071 switch (t)
11072 {
11073 case token_type::uninitialized:
11074 return "<uninitialized>";
11075 case token_type::literal_true:
11076 return "true literal";
11077 case token_type::literal_false:
11078 return "false literal";
11079 case token_type::literal_null:
11080 return "null literal";
11081 case token_type::value_string:
11082 return "string literal";
11083 case lexer::token_type::value_unsigned:
11084 case lexer::token_type::value_integer:
11085 case lexer::token_type::value_float:
11086 return "number literal";
11087 case token_type::begin_array:
11088 return "'['";
11089 case token_type::begin_object:
11090 return "'{'";
11091 case token_type::end_array:
11092 return "']'";
11093 case token_type::end_object:
11094 return "'}'";
11095 case token_type::name_separator:
11096 return "':'";
11097 case token_type::value_separator:
11098 return "','";
11099 case token_type::parse_error:
11100 return "<parse error>";
11101 case token_type::end_of_input:
11102 return "end of input";
11103 case token_type::literal_or_value:
11104 return "'[', '{', or a literal";
11105 default:
11106 {
11107 // catch non-enum values
11108 return "unknown token"; // LCOV_EXCL_LINE
11109 }
11110 }
11111 }
11112
11113 explicit lexer(input_adapter_t adapter)
11114 : ia(adapter), decimal_point_char(get_decimal_point())
11115 {}
11116
11117 // delete because of pointer members
11118 lexer(const lexer&) = delete;
11119 lexer& operator=(lexer&) = delete;
11120
11121 private:
11122 /////////////////////
11123 // locales
11124 /////////////////////
11125
11126 /// return the locale-dependent decimal point
11127 static char get_decimal_point() noexcept
11128 {
11129 const auto loc = localeconv();
11130 assert(loc != nullptr);
11131 return (loc->decimal_point == nullptr) ? '.' : loc->decimal_point[0];
11132 }
11133
11134 /////////////////////
11135 // scan functions
11136 /////////////////////
11137
11138 /*!
11139 @brief get codepoint from 4 hex characters following `\u`
11140
11141 @return codepoint or -1 in case of an error (e.g. EOF or non-hex
11142 character)
11143 */
11144 int get_codepoint()
11145 {
11146 // this function only makes sense after reading `\u`
11147 assert(current == 'u');
11148 int codepoint = 0;
11149
11150 // byte 1: \uXxxx
11151 switch (get())
11152 {
11153 case '0':
11154 break;
11155 case '1':
11156 codepoint += 0x1000;
11157 break;
11158 case '2':
11159 codepoint += 0x2000;
11160 break;
11161 case '3':
11162 codepoint += 0x3000;
11163 break;
11164 case '4':
11165 codepoint += 0x4000;
11166 break;
11167 case '5':
11168 codepoint += 0x5000;
11169 break;
11170 case '6':
11171 codepoint += 0x6000;
11172 break;
11173 case '7':
11174 codepoint += 0x7000;
11175 break;
11176 case '8':
11177 codepoint += 0x8000;
11178 break;
11179 case '9':
11180 codepoint += 0x9000;
11181 break;
11182 case 'A':
11183 case 'a':
11184 codepoint += 0xa000;
11185 break;
11186 case 'B':
11187 case 'b':
11188 codepoint += 0xb000;
11189 break;
11190 case 'C':
11191 case 'c':
11192 codepoint += 0xc000;
11193 break;
11194 case 'D':
11195 case 'd':
11196 codepoint += 0xd000;
11197 break;
11198 case 'E':
11199 case 'e':
11200 codepoint += 0xe000;
11201 break;
11202 case 'F':
11203 case 'f':
11204 codepoint += 0xf000;
11205 break;
11206 default:
11207 return -1;
11208 }
11209
11210 // byte 2: \uxXxx
11211 switch (get())
11212 {
11213 case '0':
11214 break;
11215 case '1':
11216 codepoint += 0x0100;
11217 break;
11218 case '2':
11219 codepoint += 0x0200;
11220 break;
11221 case '3':
11222 codepoint += 0x0300;
11223 break;
11224 case '4':
11225 codepoint += 0x0400;
11226 break;
11227 case '5':
11228 codepoint += 0x0500;
11229 break;
11230 case '6':
11231 codepoint += 0x0600;
11232 break;
11233 case '7':
11234 codepoint += 0x0700;
11235 break;
11236 case '8':
11237 codepoint += 0x0800;
11238 break;
11239 case '9':
11240 codepoint += 0x0900;
11241 break;
11242 case 'A':
11243 case 'a':
11244 codepoint += 0x0a00;
11245 break;
11246 case 'B':
11247 case 'b':
11248 codepoint += 0x0b00;
11249 break;
11250 case 'C':
11251 case 'c':
11252 codepoint += 0x0c00;
11253 break;
11254 case 'D':
11255 case 'd':
11256 codepoint += 0x0d00;
11257 break;
11258 case 'E':
11259 case 'e':
11260 codepoint += 0x0e00;
11261 break;
11262 case 'F':
11263 case 'f':
11264 codepoint += 0x0f00;
11265 break;
11266 default:
11267 return -1;
11268 }
11269
11270 // byte 3: \uxxXx
11271 switch (get())
11272 {
11273 case '0':
11274 break;
11275 case '1':
11276 codepoint += 0x0010;
11277 break;
11278 case '2':
11279 codepoint += 0x0020;
11280 break;
11281 case '3':
11282 codepoint += 0x0030;
11283 break;
11284 case '4':
11285 codepoint += 0x0040;
11286 break;
11287 case '5':
11288 codepoint += 0x0050;
11289 break;
11290 case '6':
11291 codepoint += 0x0060;
11292 break;
11293 case '7':
11294 codepoint += 0x0070;
11295 break;
11296 case '8':
11297 codepoint += 0x0080;
11298 break;
11299 case '9':
11300 codepoint += 0x0090;
11301 break;
11302 case 'A':
11303 case 'a':
11304 codepoint += 0x00a0;
11305 break;
11306 case 'B':
11307 case 'b':
11308 codepoint += 0x00b0;
11309 break;
11310 case 'C':
11311 case 'c':
11312 codepoint += 0x00c0;
11313 break;
11314 case 'D':
11315 case 'd':
11316 codepoint += 0x00d0;
11317 break;
11318 case 'E':
11319 case 'e':
11320 codepoint += 0x00e0;
11321 break;
11322 case 'F':
11323 case 'f':
11324 codepoint += 0x00f0;
11325 break;
11326 default:
11327 return -1;
11328 }
11329
11330 // byte 4: \uxxxX
11331 switch (get())
11332 {
11333 case '0':
11334 break;
11335 case '1':
11336 codepoint += 0x0001;
11337 break;
11338 case '2':
11339 codepoint += 0x0002;
11340 break;
11341 case '3':
11342 codepoint += 0x0003;
11343 break;
11344 case '4':
11345 codepoint += 0x0004;
11346 break;
11347 case '5':
11348 codepoint += 0x0005;
11349 break;
11350 case '6':
11351 codepoint += 0x0006;
11352 break;
11353 case '7':
11354 codepoint += 0x0007;
11355 break;
11356 case '8':
11357 codepoint += 0x0008;
11358 break;
11359 case '9':
11360 codepoint += 0x0009;
11361 break;
11362 case 'A':
11363 case 'a':
11364 codepoint += 0x000a;
11365 break;
11366 case 'B':
11367 case 'b':
11368 codepoint += 0x000b;
11369 break;
11370 case 'C':
11371 case 'c':
11372 codepoint += 0x000c;
11373 break;
11374 case 'D':
11375 case 'd':
11376 codepoint += 0x000d;
11377 break;
11378 case 'E':
11379 case 'e':
11380 codepoint += 0x000e;
11381 break;
11382 case 'F':
11383 case 'f':
11384 codepoint += 0x000f;
11385 break;
11386 default:
11387 return -1;
11388 }
11389
11390 return codepoint;
11391 }
11392
11393 /*!
11394 @brief scan a string literal
11395
11396 This function scans a string according to Sect. 7 of RFC 7159. While
11397 scanning, bytes are escaped and copied into buffer yytext. Then the
11398 function returns successfully, yytext is null-terminated and yylen
11399 contains the number of bytes in the string.
11400
11401 @return token_type::value_string if string could be successfully
11402 scanned, token_type::parse_error otherwise
11403
11404 @note In case of errors, variable error_message contains a textual
11405 description.
11406 */
11407 token_type scan_string()
11408 {
11409 // reset yytext (ignore opening quote)
11410 reset();
11411
11412 // we entered the function by reading an open quote
11413 assert(current == '\"');
11414
11415 while (true)
11416 {
11417 // get next character
11418 switch (get())
11419 {
11420 // end of file while parsing string
11421 case std::char_traits<char>::eof():
11422 {
11423 error_message = "invalid string: missing closing quote";
11424 return token_type::parse_error;
11425 }
11426
11427 // closing quote
11428 case '\"':
11429 {
11430 // terminate yytext
11431 add('\0');
11432 --yylen;
11433 return token_type::value_string;
11434 }
11435
11436 // escapes
11437 case '\\':
11438 {
11439 switch (get())
11440 {
11441 // quotation mark
11442 case '\"':
11443 add('\"');
11444 break;
11445 // reverse solidus
11446 case '\\':
11447 add('\\');
11448 break;
11449 // solidus
11450 case '/':
11451 add('/');
11452 break;
11453 // backspace
11454 case 'b':
11455 add('\b');
11456 break;
11457 // form feed
11458 case 'f':
11459 add('\f');
11460 break;
11461 // line feed
11462 case 'n':
11463 add('\n');
11464 break;
11465 // carriage return
11466 case 'r':
11467 add('\r');
11468 break;
11469 // tab
11470 case 't':
11471 add('\t');
11472 break;
11473
11474 // unicode escapes
11475 case 'u':
11476 {
11477 int codepoint;
11478 int codepoint1 = get_codepoint();
11479
11480 if (JSON_UNLIKELY(codepoint1 == -1))
11481 {
11482 error_message = "invalid string: '\\u' must be followed by 4 hex digits";
11483 return token_type::parse_error;
11484 }
11485
11486 // check if code point is a high surrogate
11487 if (0xD800 <= codepoint1 and codepoint1 <= 0xDBFF)
11488 {
11489 // expect next \uxxxx entry
11490 if (JSON_LIKELY(get() == '\\' and get() == 'u'))
11491 {
11492 const int codepoint2 = get_codepoint();
11493
11494 if (JSON_UNLIKELY(codepoint2 == -1))
11495 {
11496 error_message = "invalid string: '\\u' must be followed by 4 hex digits";
11497 return token_type::parse_error;
11498 }
11499
11500 // check if codepoint2 is a low surrogate
11501 if (JSON_LIKELY(0xDC00 <= codepoint2 and codepoint2 <= 0xDFFF))
11502 {
11503 codepoint =
11504 // high surrogate occupies the most significant 22 bits
11505 (codepoint1 << 10)
11506 // low surrogate occupies the least significant 15 bits
11507 + codepoint2
11508 // there is still the 0xD800, 0xDC00 and 0x10000 noise
11509 // in the result so we have to subtract with:
11510 // (0xD800 << 10) + DC00 - 0x10000 = 0x35FDC00
11511 - 0x35FDC00;
11512 }
11513 else
11514 {
11515 error_message = "invalid string: surrogate U+DC00..U+DFFF must be followed by U+DC00..U+DFFF";
11516 return token_type::parse_error;
11517 }
11518 }
11519 else
11520 {
11521 error_message = "invalid string: surrogate U+DC00..U+DFFF must be followed by U+DC00..U+DFFF";
11522 return token_type::parse_error;
11523 }
11524 }
11525 else
11526 {
11527 if (JSON_UNLIKELY(0xDC00 <= codepoint1 and codepoint1 <= 0xDFFF))
11528 {
11529 error_message = "invalid string: surrogate U+DC00..U+DFFF must follow U+D800..U+DBFF";
11530 return token_type::parse_error;
11531 }
11532
11533 // only work with first code point
11534 codepoint = codepoint1;
11535 }
11536
11537 // result of the above calculation yields a proper codepoint
11538 assert(0x00 <= codepoint and codepoint <= 0x10FFFF);
11539
11540 // translate code point to bytes
11541 if (codepoint < 0x80)
11542 {
11543 // 1-byte characters: 0xxxxxxx (ASCII)
11544 add(codepoint);
11545 }
11546 else if (codepoint <= 0x7ff)
11547 {
11548 // 2-byte characters: 110xxxxx 10xxxxxx
11549 add(0xC0 | (codepoint >> 6));
11550 add(0x80 | (codepoint & 0x3F));
11551 }
11552 else if (codepoint <= 0xffff)
11553 {
11554 // 3-byte characters: 1110xxxx 10xxxxxx 10xxxxxx
11555 add(0xE0 | (codepoint >> 12));
11556 add(0x80 | ((codepoint >> 6) & 0x3F));
11557 add(0x80 | (codepoint & 0x3F));
11558 }
11559 else
11560 {
11561 // 4-byte characters: 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx
11562 add(0xF0 | (codepoint >> 18));
11563 add(0x80 | ((codepoint >> 12) & 0x3F));
11564 add(0x80 | ((codepoint >> 6) & 0x3F));
11565 add(0x80 | (codepoint & 0x3F));
11566 }
11567
11568 break;
11569 }
11570
11571 // other characters after escape
11572 default:
11573 error_message = "invalid string: forbidden character after backslash";
11574 return token_type::parse_error;
11575 }
11576
11577 break;
11578 }
11579
11580 // invalid control characters
11581 case 0x00:
11582 case 0x01:
11583 case 0x02:
11584 case 0x03:
11585 case 0x04:
11586 case 0x05:
11587 case 0x06:
11588 case 0x07:
11589 case 0x08:
11590 case 0x09:
11591 case 0x0a:
11592 case 0x0b:
11593 case 0x0c:
11594 case 0x0d:
11595 case 0x0e:
11596 case 0x0f:
11597 case 0x10:
11598 case 0x11:
11599 case 0x12:
11600 case 0x13:
11601 case 0x14:
11602 case 0x15:
11603 case 0x16:
11604 case 0x17:
11605 case 0x18:
11606 case 0x19:
11607 case 0x1a:
11608 case 0x1b:
11609 case 0x1c:
11610 case 0x1d:
11611 case 0x1e:
11612 case 0x1f:
11613 {
11614 error_message = "invalid string: control character must be escaped";
11615 return token_type::parse_error;
11616 }
11617
11618 // U+0020..U+007F (except U+0022 (quote) and U+005C (backspace))
11619 case 0x20:
11620 case 0x21:
11621 case 0x23:
11622 case 0x24:
11623 case 0x25:
11624 case 0x26:
11625 case 0x27:
11626 case 0x28:
11627 case 0x29:
11628 case 0x2a:
11629 case 0x2b:
11630 case 0x2c:
11631 case 0x2d:
11632 case 0x2e:
11633 case 0x2f:
11634 case 0x30:
11635 case 0x31:
11636 case 0x32:
11637 case 0x33:
11638 case 0x34:
11639 case 0x35:
11640 case 0x36:
11641 case 0x37:
11642 case 0x38:
11643 case 0x39:
11644 case 0x3a:
11645 case 0x3b:
11646 case 0x3c:
11647 case 0x3d:
11648 case 0x3e:
11649 case 0x3f:
11650 case 0x40:
11651 case 0x41:
11652 case 0x42:
11653 case 0x43:
11654 case 0x44:
11655 case 0x45:
11656 case 0x46:
11657 case 0x47:
11658 case 0x48:
11659 case 0x49:
11660 case 0x4a:
11661 case 0x4b:
11662 case 0x4c:
11663 case 0x4d:
11664 case 0x4e:
11665 case 0x4f:
11666 case 0x50:
11667 case 0x51:
11668 case 0x52:
11669 case 0x53:
11670 case 0x54:
11671 case 0x55:
11672 case 0x56:
11673 case 0x57:
11674 case 0x58:
11675 case 0x59:
11676 case 0x5a:
11677 case 0x5b:
11678 case 0x5d:
11679 case 0x5e:
11680 case 0x5f:
11681 case 0x60:
11682 case 0x61:
11683 case 0x62:
11684 case 0x63:
11685 case 0x64:
11686 case 0x65:
11687 case 0x66:
11688 case 0x67:
11689 case 0x68:
11690 case 0x69:
11691 case 0x6a:
11692 case 0x6b:
11693 case 0x6c:
11694 case 0x6d:
11695 case 0x6e:
11696 case 0x6f:
11697 case 0x70:
11698 case 0x71:
11699 case 0x72:
11700 case 0x73:
11701 case 0x74:
11702 case 0x75:
11703 case 0x76:
11704 case 0x77:
11705 case 0x78:
11706 case 0x79:
11707 case 0x7a:
11708 case 0x7b:
11709 case 0x7c:
11710 case 0x7d:
11711 case 0x7e:
11712 case 0x7f:
11713 {
11714 add(current);
11715 break;
11716 }
11717
11718 // U+0080..U+07FF: bytes C2..DF 80..BF
11719 case 0xc2:
11720 case 0xc3:
11721 case 0xc4:
11722 case 0xc5:
11723 case 0xc6:
11724 case 0xc7:
11725 case 0xc8:
11726 case 0xc9:
11727 case 0xca:
11728 case 0xcb:
11729 case 0xcc:
11730 case 0xcd:
11731 case 0xce:
11732 case 0xcf:
11733 case 0xd0:
11734 case 0xd1:
11735 case 0xd2:
11736 case 0xd3:
11737 case 0xd4:
11738 case 0xd5:
11739 case 0xd6:
11740 case 0xd7:
11741 case 0xd8:
11742 case 0xd9:
11743 case 0xda:
11744 case 0xdb:
11745 case 0xdc:
11746 case 0xdd:
11747 case 0xde:
11748 case 0xdf:
11749 {
11750 add(current);
11751 get();
11752 if (JSON_LIKELY(0x80 <= current and current <= 0xbf))
11753 {
11754 add(current);
11755 continue;
11756 }
11757
11758 error_message = "invalid string: ill-formed UTF-8 byte";
11759 return token_type::parse_error;
11760 }
11761
11762 // U+0800..U+0FFF: bytes E0 A0..BF 80..BF
11763 case 0xe0:
11764 {
11765 add(current);
11766 get();
11767 if (JSON_LIKELY(0xa0 <= current and current <= 0xbf))
11768 {
11769 add(current);
11770 get();
11771 if (JSON_LIKELY(0x80 <= current and current <= 0xbf))
11772 {
11773 add(current);
11774 continue;
11775 }
11776 }
11777
11778 error_message = "invalid string: ill-formed UTF-8 byte";
11779 return token_type::parse_error;
11780 }
11781
11782 // U+1000..U+CFFF: bytes E1..EC 80..BF 80..BF
11783 // U+E000..U+FFFF: bytes EE..EF 80..BF 80..BF
11784 case 0xe1:
11785 case 0xe2:
11786 case 0xe3:
11787 case 0xe4:
11788 case 0xe5:
11789 case 0xe6:
11790 case 0xe7:
11791 case 0xe8:
11792 case 0xe9:
11793 case 0xea:
11794 case 0xeb:
11795 case 0xec:
11796 case 0xee:
11797 case 0xef:
11798 {
11799 add(current);
11800 get();
11801 if (JSON_LIKELY(0x80 <= current and current <= 0xbf))
11802 {
11803 add(current);
11804 get();
11805 if (JSON_LIKELY(0x80 <= current and current <= 0xbf))
11806 {
11807 add(current);
11808 continue;
11809 }
11810 }
11811
11812 error_message = "invalid string: ill-formed UTF-8 byte";
11813 return token_type::parse_error;
11814 }
11815
11816 // U+D000..U+D7FF: bytes ED 80..9F 80..BF
11817 case 0xed:
11818 {
11819 add(current);
11820 get();
11821 if (JSON_LIKELY(0x80 <= current and current <= 0x9f))
11822 {
11823 add(current);
11824 get();
11825 if (JSON_LIKELY(0x80 <= current and current <= 0xbf))
11826 {
11827 add(current);
11828 continue;
11829 }
11830 }
11831
11832 error_message = "invalid string: ill-formed UTF-8 byte";
11833 return token_type::parse_error;
11834 }
11835
11836 // U+10000..U+3FFFF F0 90..BF 80..BF 80..BF
11837 case 0xf0:
11838 {
11839 add(current);
11840 get();
11841 if (JSON_LIKELY(0x90 <= current and current <= 0xbf))
11842 {
11843 add(current);
11844 get();
11845 if (JSON_LIKELY(0x80 <= current and current <= 0xbf))
11846 {
11847 add(current);
11848 get();
11849 if (JSON_LIKELY(0x80 <= current and current <= 0xbf))
11850 {
11851 add(current);
11852 continue;
11853 }
11854 }
11855 }
11856
11857 error_message = "invalid string: ill-formed UTF-8 byte";
11858 return token_type::parse_error;
11859 }
11860
11861 // U+40000..U+FFFFF F1..F3 80..BF 80..BF 80..BF
11862 case 0xf1:
11863 case 0xf2:
11864 case 0xf3:
11865 {
11866 add(current);
11867 get();
11868 if (JSON_LIKELY(0x80 <= current and current <= 0xbf))
11869 {
11870 add(current);
11871 get();
11872 if (JSON_LIKELY(0x80 <= current and current <= 0xbf))
11873 {
11874 add(current);
11875 get();
11876 if (JSON_LIKELY(0x80 <= current and current <= 0xbf))
11877 {
11878 add(current);
11879 continue;
11880 }
11881 }
11882 }
11883
11884 error_message = "invalid string: ill-formed UTF-8 byte";
11885 return token_type::parse_error;
11886 }
11887
11888 // U+100000..U+10FFFF F4 80..8F 80..BF 80..BF
11889 case 0xf4:
11890 {
11891 add(current);
11892 get();
11893 if (JSON_LIKELY(0x80 <= current and current <= 0x8f))
11894 {
11895 add(current);
11896 get();
11897 if (JSON_LIKELY(0x80 <= current and current <= 0xbf))
11898 {
11899 add(current);
11900 get();
11901 if (JSON_LIKELY(0x80 <= current and current <= 0xbf))
11902 {
11903 add(current);
11904 continue;
11905 }
11906 }
11907 }
11908
11909 error_message = "invalid string: ill-formed UTF-8 byte";
11910 return token_type::parse_error;
11911 }
11912
11913 // remaining bytes (80..C1 and F5..FF) are ill-formed
11914 default:
11915 {
11916 error_message = "invalid string: ill-formed UTF-8 byte";
11917 return token_type::parse_error;
11918 }
11919 }
11920 }
11921 }
11922
11923 static void strtof(float& f, const char* str, char** endptr) noexcept
11924 {
11925 f = std::strtof(str, endptr);
11926 }
11927
11928 static void strtof(double& f, const char* str, char** endptr) noexcept
11929 {
11930 f = std::strtod(str, endptr);
11931 }
11932
11933 static void strtof(long double& f, const char* str, char** endptr) noexcept
11934 {
11935 f = std::strtold(str, endptr);
11936 }
11937
11938 /*!
11939 @brief scan a number literal
11940
11941 This function scans a string according to Sect. 6 of RFC 7159.
11942
11943 The function is realized with a deterministic finite state machine
11944 derived from the grammar described in RFC 7159. Starting in state
11945 "init", the input is read and used to determined the next state. Only
11946 state "done" accepts the number. State "error" is a trap state to model
11947 errors. In the table below, "anything" means any character but the ones
11948 listed before.
11949
11950 state | 0 | 1-9 | e E | + | - | . | anything
11951 ---------|----------|----------|----------|---------|---------|----------|-----------
11952 init | zero | any1 | [error] | [error] | minus | [error] | [error]
11953 minus | zero | any1 | [error] | [error] | [error] | [error] | [error]
11954 zero | done | done | exponent | done | done | decimal1 | done
11955 any1 | any1 | any1 | exponent | done | done | decimal1 | done
11956 decimal1 | decimal2 | [error] | [error] | [error] | [error] | [error] | [error]
11957 decimal2 | decimal2 | decimal2 | exponent | done | done | done | done
11958 exponent | any2 | any2 | [error] | sign | sign | [error] | [error]
11959 sign | any2 | any2 | [error] | [error] | [error] | [error] | [error]
11960 any2 | any2 | any2 | done | done | done | done | done
11961
11962 The state machine is realized with one label per state (prefixed with
11963 "scan_number_") and `goto` statements between them. The state machine
11964 contains cycles, but any cycle can be left when EOF is read. Therefore,
11965 the function is guaranteed to terminate.
11966
11967 During scanning, the read bytes are stored in yytext. This string is
11968 then converted to a signed integer, an unsigned integer, or a
11969 floating-point number.
11970
11971 @return token_type::value_unsigned, token_type::value_integer, or
11972 token_type::value_float if number could be successfully scanned,
11973 token_type::parse_error otherwise
11974
11975 @note The scanner is independent of the current locale. Internally, the
11976 locale's decimal point is used instead of `.` to work with the
11977 locale-dependent converters.
11978 */
11979 token_type scan_number()
11980 {
11981 // reset yytext to store the number's bytes
11982 reset();
11983
11984 // the type of the parsed number; initially set to unsigned; will be
11985 // changed if minus sign, decimal point or exponent is read
11986 token_type number_type = token_type::value_unsigned;
11987
11988 // state (init): we just found out we need to scan a number
11989 switch (current)
11990 {
11991 case '-':
11992 {
11993 add(current);
11994 goto scan_number_minus;
11995 }
11996
11997 case '0':
11998 {
11999 add(current);
12000 goto scan_number_zero;
12001 }
12002
12003 case '1':
12004 case '2':
12005 case '3':
12006 case '4':
12007 case '5':
12008 case '6':
12009 case '7':
12010 case '8':
12011 case '9':
12012 {
12013 add(current);
12014 goto scan_number_any1;
12015 }
12016
12017 default:
12018 {
12019 // all other characters are rejected outside scan_number()
12020 assert(false); // LCOV_EXCL_LINE
12021 }
12022 }
12023
12024scan_number_minus:
12025 // state: we just parsed a leading minus sign
12026 number_type = token_type::value_integer;
12027 switch (get())
12028 {
12029 case '0':
12030 {
12031 add(current);
12032 goto scan_number_zero;
12033 }
12034
12035 case '1':
12036 case '2':
12037 case '3':
12038 case '4':
12039 case '5':
12040 case '6':
12041 case '7':
12042 case '8':
12043 case '9':
12044 {
12045 add(current);
12046 goto scan_number_any1;
12047 }
12048
12049 default:
12050 {
12051 error_message = "invalid number; expected digit after '-'";
12052 return token_type::parse_error;
12053 }
12054 }
12055
12056scan_number_zero:
12057 // state: we just parse a zero (maybe with a leading minus sign)
12058 switch (get())
12059 {
12060 case '.':
12061 {
12062 add(decimal_point_char);
12063 goto scan_number_decimal1;
12064 }
12065
12066 case 'e':
12067 case 'E':
12068 {
12069 add(current);
12070 goto scan_number_exponent;
12071 }
12072
12073 default:
12074 {
12075 goto scan_number_done;
12076 }
12077 }
12078
12079scan_number_any1:
12080 // state: we just parsed a number 0-9 (maybe with a leading minus sign)
12081 switch (get())
12082 {
12083 case '0':
12084 case '1':
12085 case '2':
12086 case '3':
12087 case '4':
12088 case '5':
12089 case '6':
12090 case '7':
12091 case '8':
12092 case '9':
12093 {
12094 add(current);
12095 goto scan_number_any1;
12096 }
12097
12098 case '.':
12099 {
12100 add(decimal_point_char);
12101 goto scan_number_decimal1;
12102 }
12103
12104 case 'e':
12105 case 'E':
12106 {
12107 add(current);
12108 goto scan_number_exponent;
12109 }
12110
12111 default:
12112 {
12113 goto scan_number_done;
12114 }
12115 }
12116
12117scan_number_decimal1:
12118 // state: we just parsed a decimal point
12119 number_type = token_type::value_float;
12120 switch (get())
12121 {
12122 case '0':
12123 case '1':
12124 case '2':
12125 case '3':
12126 case '4':
12127 case '5':
12128 case '6':
12129 case '7':
12130 case '8':
12131 case '9':
12132 {
12133 add(current);
12134 goto scan_number_decimal2;
12135 }
12136
12137 default:
12138 {
12139 error_message = "invalid number; expected digit after '.'";
12140 return token_type::parse_error;
12141 }
12142 }
12143
12144scan_number_decimal2:
12145 // we just parsed at least one number after a decimal point
12146 switch (get())
12147 {
12148 case '0':
12149 case '1':
12150 case '2':
12151 case '3':
12152 case '4':
12153 case '5':
12154 case '6':
12155 case '7':
12156 case '8':
12157 case '9':
12158 {
12159 add(current);
12160 goto scan_number_decimal2;
12161 }
12162
12163 case 'e':
12164 case 'E':
12165 {
12166 add(current);
12167 goto scan_number_exponent;
12168 }
12169
12170 default:
12171 {
12172 goto scan_number_done;
12173 }
12174 }
12175
12176scan_number_exponent:
12177 // we just parsed an exponent
12178 number_type = token_type::value_float;
12179 switch (get())
12180 {
12181 case '+':
12182 case '-':
12183 {
12184 add(current);
12185 goto scan_number_sign;
12186 }
12187
12188 case '0':
12189 case '1':
12190 case '2':
12191 case '3':
12192 case '4':
12193 case '5':
12194 case '6':
12195 case '7':
12196 case '8':
12197 case '9':
12198 {
12199 add(current);
12200 goto scan_number_any2;
12201 }
12202
12203 default:
12204 {
12205 error_message = "invalid number; expected '+', '-', or digit after exponent";
12206 return token_type::parse_error;
12207 }
12208 }
12209
12210scan_number_sign:
12211 // we just parsed an exponent sign
12212 switch (get())
12213 {
12214 case '0':
12215 case '1':
12216 case '2':
12217 case '3':
12218 case '4':
12219 case '5':
12220 case '6':
12221 case '7':
12222 case '8':
12223 case '9':
12224 {
12225 add(current);
12226 goto scan_number_any2;
12227 }
12228
12229 default:
12230 {
12231 error_message = "invalid number; expected digit after exponent sign";
12232 return token_type::parse_error;
12233 }
12234 }
12235
12236scan_number_any2:
12237 // we just parsed a number after the exponent or exponent sign
12238 switch (get())
12239 {
12240 case '0':
12241 case '1':
12242 case '2':
12243 case '3':
12244 case '4':
12245 case '5':
12246 case '6':
12247 case '7':
12248 case '8':
12249 case '9':
12250 {
12251 add(current);
12252 goto scan_number_any2;
12253 }
12254
12255 default:
12256 {
12257 goto scan_number_done;
12258 }
12259 }
12260
12261scan_number_done:
12262 // unget the character after the number (we only read it to know
12263 // that we are done scanning a number)
12264 --chars_read;
12265 next_unget = true;
12266
12267 // terminate token
12268 add('\0');
12269 --yylen;
12270
12271 // try to parse integers first and fall back to floats
12272 if (number_type == token_type::value_unsigned)
12273 {
12274 char* endptr = nullptr;
12275 errno = 0;
12276 const auto x = std::strtoull(yytext.data(), &endptr, 10);
12277
12278 // we checked the number format before
12279 assert(endptr == yytext.data() + yylen);
12280
12281 if (errno == 0)
12282 {
12283 value_unsigned = static_cast<number_unsigned_t>(x);
12284 if (value_unsigned == x)
12285 {
12286 return token_type::value_unsigned;
12287 }
12288 }
12289 }
12290 else if (number_type == token_type::value_integer)
12291 {
12292 char* endptr = nullptr;
12293 errno = 0;
12294 const auto x = std::strtoll(yytext.data(), &endptr, 10);
12295
12296 // we checked the number format before
12297 assert(endptr == yytext.data() + yylen);
12298
12299 if (errno == 0)
12300 {
12301 value_integer = static_cast<number_integer_t>(x);
12302 if (value_integer == x)
12303 {
12304 return token_type::value_integer;
12305 }
12306 }
12307 }
12308
12309 // this code is reached if we parse a floating-point number or if
12310 // an integer conversion above failed
12311 strtof(value_float, yytext.data(), nullptr);
12312 return token_type::value_float;
12313 }
12314
12315 /*!
12316 @param[in] literal_text the literal text to expect
12317 @param[in] length the length of the passed literal text
12318 @param[in] return_type the token type to return on success
12319 */
12320 token_type scan_literal(const char* literal_text, const size_t length,
12321 token_type return_type)
12322 {
12323 assert(current == literal_text[0]);
12324 for (size_t i = 1; i < length; ++i)
12325 {
12326 if (JSON_UNLIKELY(get() != literal_text[i]))
12327 {
12328 error_message = "invalid literal";
12329 return token_type::parse_error;
12330 }
12331 }
12332 return return_type;
12333 }
12334
12335 /////////////////////
12336 // input management
12337 /////////////////////
12338
12339 /// reset yytext
12340 void reset() noexcept
12341 {
12342 yylen = 0;
12343 start_pos = chars_read - 1;
12344 }
12345
12346 /// get a character from the input
12347 int get()
12348 {
12349 ++chars_read;
12350 return next_unget
12351 ? (next_unget = false, current)
12352 : (current = ia->get_character());
12353 }
12354
12355 /// add a character to yytext
12356 void add(int c)
12357 {
12358 // resize yytext if necessary; this condition is deemed unlikely,
12359 // because we start with a 1024-byte buffer
12360 if (JSON_UNLIKELY((yylen + 1 > yytext.capacity())))
12361 {
12362 yytext.resize(2 * yytext.capacity(), '\0');
12363 }
12364 assert(yylen < yytext.size());
12365 yytext[yylen++] = static_cast<char>(c);
12366 }
12367
12368 public:
12369 /////////////////////
12370 // value getters
12371 /////////////////////
12372
12373 /// return integer value
12374 constexpr number_integer_t get_number_integer() const noexcept
12375 {
12376 return value_integer;
12377 }
12378
12379 /// return unsigned integer value
12380 constexpr number_unsigned_t get_number_unsigned() const noexcept
12381 {
12382 return value_unsigned;
12383 }
12384
12385 /// return floating-point value
12386 constexpr number_float_t get_number_float() const noexcept
12387 {
12388 return value_float;
12389 }
12390
12391 /// return string value
12392 const std::string get_string()
12393 {
12394 // yytext cannot be returned as char*, because it may contain a
12395 // null byte (parsed as "\u0000")
12396 return std::string(yytext.data(), yylen);
12397 }
12398
12399 /////////////////////
12400 // diagnostics
12401 /////////////////////
12402
12403 /// return position of last read token
12404 constexpr size_t get_position() const noexcept
12405 {
12406 return chars_read;
12407 }
12408
12409 /// return the last read token (for errors only)
12410 std::string get_token_string() const
12411 {
12412 // get the raw byte sequence of the last token
12413 std::string s = ia->read(start_pos, chars_read - start_pos);
12414
12415 // escape control characters
12416 std::string result;
12417 for (auto c : s)
12418 {
12419 if (c == '\0' or c == std::char_traits<char>::eof())
12420 {
12421 // ignore EOF
12422 continue;
12423 }
12424 else if ('\x00' <= c and c <= '\x1f')
12425 {
12426 // escape control characters
12427 std::stringstream ss;
12428 ss << "<U+" << std::setw(4) << std::uppercase << std::setfill('0') << std::hex << static_cast<int>(c) << ">";
12429 result += ss.str();
12430 }
12431 else
12432 {
12433 // add character as is
12434 result.append(1, c);
12435 }
12436 }
12437
12438 return result;
12439 }
12440
12441 /// return syntax error message
12442 constexpr const char* get_error_message() const noexcept
12443 {
12444 return error_message;
12445 }
12446
12447 /////////////////////
12448 // actual scanner
12449 /////////////////////
12450
12451 token_type scan()
12452 {
12453 // read next character and ignore whitespace
12454 do
12455 {
12456 get();
12457 }
12458 while (current == ' ' or current == '\t' or current == '\n' or current == '\r');
12459
12460 switch (current)
12461 {
12462 // structural characters
12463 case '[':
12464 return token_type::begin_array;
12465 case ']':
12466 return token_type::end_array;
12467 case '{':
12468 return token_type::begin_object;
12469 case '}':
12470 return token_type::end_object;
12471 case ':':
12472 return token_type::name_separator;
12473 case ',':
12474 return token_type::value_separator;
12475
12476 // literals
12477 case 't':
12478 return scan_literal("true", 4, token_type::literal_true);
12479 case 'f':
12480 return scan_literal("false", 5, token_type::literal_false);
12481 case 'n':
12482 return scan_literal("null", 4, token_type::literal_null);
12483
12484 // string
12485 case '\"':
12486 return scan_string();
12487
12488 // number
12489 case '-':
12490 case '0':
12491 case '1':
12492 case '2':
12493 case '3':
12494 case '4':
12495 case '5':
12496 case '6':
12497 case '7':
12498 case '8':
12499 case '9':
12500 return scan_number();
12501
12502 // end of input (the null byte is needed when parsing from
12503 // string literals)
12504 case '\0':
12505 case std::char_traits<char>::eof():
12506 return token_type::end_of_input;
12507
12508 // error
12509 default:
12510 error_message = "invalid literal";
12511 return token_type::parse_error;
12512 }
12513 }
12514
12515 private:
12516 /// input adapter
12517 input_adapter_t ia = nullptr;
12518
12519 /// the current character
12520 int current = std::char_traits<char>::eof();
12521
12522 /// whether get() should return the last character again
12523 bool next_unget = false;
12524
12525 /// the number of characters read
12526 size_t chars_read = 0;
12527 /// the start position of the current token
12528 size_t start_pos = 0;
12529
12530 /// buffer for variable-length tokens (numbers, strings)
12531 std::vector<char> yytext = std::vector<char>(1024, '\0');
12532 /// current index in yytext
12533 size_t yylen = 0;
12534
12535 /// a description of occurred lexer errors
12536 const char* error_message = "";
12537
12538 // number values
12539 number_integer_t value_integer = 0;
12540 number_unsigned_t value_unsigned = 0;
12541 number_float_t value_float = 0;
12542
12543 /// the decimal point
12544 const char decimal_point_char = '.';
12545 };
12546
12547 /*!
12548 @brief syntax analysis
12549
12550 This class implements a recursive decent parser.
12551 */
12552 class parser
12553 {
12554 public:
12555 /// a parser reading from an input adapter
12556 explicit parser(input_adapter_t adapter,
12557 const parser_callback_t cb = nullptr)
12558 : callback(cb), m_lexer(adapter)
12559 {}
12560
12561 /*!
12562 @brief public parser interface
12563
12564 @param[in] strict whether to expect the last token to be EOF
12565 @return parsed JSON value
12566
12567 @throw parse_error.101 in case of an unexpected token
12568 @throw parse_error.102 if to_unicode fails or surrogate error
12569 @throw parse_error.103 if to_unicode fails
12570 */
12571 basic_json parse(const bool strict = true)
12572 {
12573 // read first token
12574 get_token();
12575
12576 basic_json result = parse_internal(true);
12577 result.assert_invariant();
12578
12579 if (strict)
12580 {
12581 get_token();
12582 expect(lexer::token_type::end_of_input);
12583 }
12584
12585 // return parser result and replace it with null in case the
12586 // top-level value was discarded by the callback function
12587 return result.is_discarded() ? basic_json() : std::move(result);
12588 }
12589
12590 /*!
12591 @brief public accept interface
12592
12593 @param[in] strict whether to expect the last token to be EOF
12594 @return whether the input is a proper JSON text
12595 */
12596 bool accept(const bool strict = true)
12597 {
12598 // read first token
12599 get_token();
12600
12601 if (not accept_internal())
12602 {
12603 return false;
12604 }
12605
12606 if (strict and get_token() != lexer::token_type::end_of_input)
12607 {
12608 return false;
12609 }
12610
12611 return true;
12612 }
12613
12614 private:
12615 /*!
12616 @brief the actual parser
12617 @throw parse_error.101 in case of an unexpected token
12618 @throw parse_error.102 if to_unicode fails or surrogate error
12619 @throw parse_error.103 if to_unicode fails
12620 */
12621 basic_json parse_internal(bool keep)
12622 {
12623 auto result = basic_json(value_t::discarded);
12624
12625 switch (last_token)
12626 {
12627 case lexer::token_type::begin_object:
12628 {
12629 if (keep and (not callback
12630 or ((keep = callback(depth++, parse_event_t::object_start, result)) != 0)))
12631 {
12632 // explicitly set result to object to cope with {}
12633 result.m_type = value_t::object;
12634 result.m_value = value_t::object;
12635 }
12636
12637 // read next token
12638 get_token();
12639
12640 // closing } -> we are done
12641 if (last_token == lexer::token_type::end_object)
12642 {
12643 if (keep and callback and not callback(--depth, parse_event_t::object_end, result))
12644 {
12645 result = basic_json(value_t::discarded);
12646 }
12647 return result;
12648 }
12649
12650 // parse values
12651 while (true)
12652 {
12653 // store key
12654 expect(lexer::token_type::value_string);
12655 const auto key = m_lexer.get_string();
12656
12657 bool keep_tag = false;
12658 if (keep)
12659 {
12660 if (callback)
12661 {
12662 basic_json k(key);
12663 keep_tag = callback(depth, parse_event_t::key, k);
12664 }
12665 else
12666 {
12667 keep_tag = true;
12668 }
12669 }
12670
12671 // parse separator (:)
12672 get_token();
12673 expect(lexer::token_type::name_separator);
12674
12675 // parse and add value
12676 get_token();
12677 auto value = parse_internal(keep);
12678 if (keep and keep_tag and not value.is_discarded())
12679 {
12680 result[key] = std::move(value);
12681 }
12682
12683 // comma -> next value
12684 get_token();
12685 if (last_token == lexer::token_type::value_separator)
12686 {
12687 get_token();
12688 continue;
12689 }
12690
12691 // closing }
12692 expect(lexer::token_type::end_object);
12693 break;
12694 }
12695
12696 if (keep and callback and not callback(--depth, parse_event_t::object_end, result))
12697 {
12698 result = basic_json(value_t::discarded);
12699 }
12700
12701 return result;
12702 }
12703
12704 case lexer::token_type::begin_array:
12705 {
12706 if (keep and (not callback
12707 or ((keep = callback(depth++, parse_event_t::array_start, result)) != 0)))
12708 {
12709 // explicitly set result to object to cope with []
12710 result.m_type = value_t::array;
12711 result.m_value = value_t::array;
12712 }
12713
12714 // read next token
12715 get_token();
12716
12717 // closing ] -> we are done
12718 if (last_token == lexer::token_type::end_array)
12719 {
12720 if (callback and not callback(--depth, parse_event_t::array_end, result))
12721 {
12722 result = basic_json(value_t::discarded);
12723 }
12724 return result;
12725 }
12726
12727 // parse values
12728 while (true)
12729 {
12730 // parse value
12731 auto value = parse_internal(keep);
12732 if (keep and not value.is_discarded())
12733 {
12734 result.push_back(std::move(value));
12735 }
12736
12737 // comma -> next value
12738 get_token();
12739 if (last_token == lexer::token_type::value_separator)
12740 {
12741 get_token();
12742 continue;
12743 }
12744
12745 // closing ]
12746 expect(lexer::token_type::end_array);
12747 break;
12748 }
12749
12750 if (keep and callback and not callback(--depth, parse_event_t::array_end, result))
12751 {
12752 result = basic_json(value_t::discarded);
12753 }
12754
12755 return result;
12756 }
12757
12758 case lexer::token_type::literal_null:
12759 {
12760 result.m_type = value_t::null;
12761 break;
12762 }
12763
12764 case lexer::token_type::value_string:
12765 {
12766 result = basic_json(m_lexer.get_string());
12767 break;
12768 }
12769
12770 case lexer::token_type::literal_true:
12771 {
12772 result.m_type = value_t::boolean;
12773 result.m_value = true;
12774 break;
12775 }
12776
12777 case lexer::token_type::literal_false:
12778 {
12779 result.m_type = value_t::boolean;
12780 result.m_value = false;
12781 break;
12782 }
12783
12784 case lexer::token_type::value_unsigned:
12785 {
12786 result.m_type = value_t::number_unsigned;
12787 result.m_value = m_lexer.get_number_unsigned();
12788 break;
12789 }
12790
12791 case lexer::token_type::value_integer:
12792 {
12793 result.m_type = value_t::number_integer;
12794 result.m_value = m_lexer.get_number_integer();
12795 break;
12796 }
12797
12798 case lexer::token_type::value_float:
12799 {
12800 result.m_type = value_t::number_float;
12801 result.m_value = m_lexer.get_number_float();
12802
12803 // throw in case of infinity or NAN
12804 if (JSON_UNLIKELY(not std::isfinite(result.m_value.number_float)))
12805 {
12806 JSON_THROW(out_of_range::create(406, "number overflow parsing '" + m_lexer.get_token_string() + "'"));
12807 }
12808
12809 break;
12810 }
12811
12812 case lexer::token_type::parse_error:
12813 {
12814 // using "uninitialized" to avoid "expected" message
12815 expect(lexer::token_type::uninitialized);
12816 break; // LCOV_EXCL_LINE
12817 }
12818
12819 default:
12820 {
12821 // the last token was unexpected; we expected a value
12822 expect(lexer::token_type::literal_or_value);
12823 break; // LCOV_EXCL_LINE
12824 }
12825 }
12826
12827 if (keep and callback and not callback(depth, parse_event_t::value, result))
12828 {
12829 result = basic_json(value_t::discarded);
12830 }
12831 return result;
12832 }
12833
12834 /*!
12835 @brief the acutal acceptor
12836
12837 @invariant 1. The last token is not yet processed. Therefore, the
12838 caller of this function must make sure a token has
12839 been read.
12840 2. When this function returns, the last token is processed.
12841 That is, the last read character was already considered.
12842
12843 This invariant makes sure that no token needs to be "unput".
12844 */
12845 bool accept_internal()
12846 {
12847 switch (last_token)
12848 {
12849 case lexer::token_type::begin_object:
12850 {
12851 // read next token
12852 get_token();
12853
12854 // closing } -> we are done
12855 if (last_token == lexer::token_type::end_object)
12856 {
12857 return true;
12858 }
12859
12860 // parse values
12861 while (true)
12862 {
12863 // parse key
12864 if (last_token != lexer::token_type::value_string)
12865 {
12866 return false;
12867 }
12868
12869 // parse separator (:)
12870 get_token();
12871 if (last_token != lexer::token_type::name_separator)
12872 {
12873 return false;
12874 }
12875
12876 // parse value
12877 get_token();
12878 if (not accept_internal())
12879 {
12880 return false;
12881 }
12882
12883 // comma -> next value
12884 get_token();
12885 if (last_token == lexer::token_type::value_separator)
12886 {
12887 get_token();
12888 continue;
12889 }
12890
12891 // closing }
12892 if (last_token != lexer::token_type::end_object)
12893 {
12894 return false;
12895 }
12896
12897 return true;
12898 }
12899 }
12900
12901 case lexer::token_type::begin_array:
12902 {
12903 // read next token
12904 get_token();
12905
12906 // closing ] -> we are done
12907 if (last_token == lexer::token_type::end_array)
12908 {
12909 return true;
12910 }
12911
12912 // parse values
12913 while (true)
12914 {
12915 // parse value
12916 if (not accept_internal())
12917 {
12918 return false;
12919 }
12920
12921 // comma -> next value
12922 get_token();
12923 if (last_token == lexer::token_type::value_separator)
12924 {
12925 get_token();
12926 continue;
12927 }
12928
12929 // closing ]
12930 if (last_token != lexer::token_type::end_array)
12931 {
12932 return false;
12933 }
12934
12935 return true;
12936 }
12937 }
12938
12939 case lexer::token_type::literal_false:
12940 case lexer::token_type::literal_null:
12941 case lexer::token_type::literal_true:
12942 case lexer::token_type::value_float:
12943 case lexer::token_type::value_integer:
12944 case lexer::token_type::value_string:
12945 case lexer::token_type::value_unsigned:
12946 {
12947 return true;
12948 }
12949
12950 default:
12951 {
12952 // the last token was unexpected
12953 return false;
12954 }
12955 }
12956 }
12957
12958 /// get next token from lexer
12959 typename lexer::token_type get_token()
12960 {
12961 return (last_token = m_lexer.scan());
12962 }
12963
12964 /*!
12965 @throw parse_error.101 if expected token did not occur
12966 */
12967 void expect(typename lexer::token_type t)
12968 {
12969 if (JSON_UNLIKELY(t != last_token))
12970 {
12971 errored = true;
12972 expected = t;
12973 throw_exception();
12974 }
12975 }
12976
12977 [[noreturn]] void throw_exception() const
12978 {
12979 std::string error_msg = "syntax error - ";
12980 if (last_token == lexer::token_type::parse_error)
12981 {
12982 error_msg += std::string(m_lexer.get_error_message()) + "; last read: '" + m_lexer.get_token_string() + "'";
12983 }
12984 else
12985 {
12986 error_msg += "unexpected " + std::string(lexer::token_type_name(last_token));
12987 }
12988
12989 if (expected != lexer::token_type::uninitialized)
12990 {
12991 error_msg += "; expected " + std::string(lexer::token_type_name(expected));
12992 }
12993
12994 JSON_THROW(parse_error::create(101, m_lexer.get_position(), error_msg));
12995 }
12996
12997 private:
12998 /// current level of recursion
12999 int depth = 0;
13000 /// callback function
13001 const parser_callback_t callback = nullptr;
13002 /// the type of the last read token
13003 typename lexer::token_type last_token = lexer::token_type::uninitialized;
13004 /// the lexer
13005 lexer m_lexer;
13006 /// whether a syntax error occurred
13007 bool errored = false;
13008 /// possible reason for the syntax error
13009 typename lexer::token_type expected = lexer::token_type::uninitialized;
13010 };
13011
13012 public:
13013 /*!
13014 @brief JSON Pointer
13015
13016 A JSON pointer defines a string syntax for identifying a specific value
13017 within a JSON document. It can be used with functions `at` and
13018 `operator[]`. Furthermore, JSON pointers are the base for JSON patches.
13019
13020 @sa [RFC 6901](https://tools.ietf.org/html/rfc6901)
13021
13022 @since version 2.0.0
13023 */
13024 class json_pointer
13025 {
13026 /// allow basic_json to access private members
13027 friend class basic_json;
13028
13029 public:
13030 /*!
13031 @brief create JSON pointer
13032
13033 Create a JSON pointer according to the syntax described in
13034 [Section 3 of RFC6901](https://tools.ietf.org/html/rfc6901#section-3).
13035
13036 @param[in] s string representing the JSON pointer; if omitted, the
13037 empty string is assumed which references the whole JSON
13038 value
13039
13040 @throw parse_error.107 if the given JSON pointer @a s is nonempty and
13041 does not begin with a slash (`/`); see example below
13042
13043 @throw parse_error.108 if a tilde (`~`) in the given JSON pointer @a s
13044 is not followed by `0` (representing `~`) or `1` (representing `/`);
13045 see example below
13046
13047 @liveexample{The example shows the construction several valid JSON
13048 pointers as well as the exceptional behavior.,json_pointer}
13049
13050 @since version 2.0.0
13051 */
13052 explicit json_pointer(const std::string& s = "")
13053 : reference_tokens(split(s))
13054 {}
13055
13056 /*!
13057 @brief return a string representation of the JSON pointer
13058
13059 @invariant For each JSON pointer `ptr`, it holds:
13060 @code {.cpp}
13061 ptr == json_pointer(ptr.to_string());
13062 @endcode
13063
13064 @return a string representation of the JSON pointer
13065
13066 @liveexample{The example shows the result of `to_string`.,
13067 json_pointer__to_string}
13068
13069 @since version 2.0.0
13070 */
13071 std::string to_string() const noexcept
13072 {
13073 return std::accumulate(reference_tokens.begin(),
13074 reference_tokens.end(), std::string{},
13075 [](const std::string & a, const std::string & b)
13076 {
13077 return a + "/" + escape(b);
13078 });
13079 }
13080
13081 /// @copydoc to_string()
13082 operator std::string() const
13083 {
13084 return to_string();
13085 }
13086
13087 private:
13088 /*!
13089 @brief remove and return last reference pointer
13090 @throw out_of_range.405 if JSON pointer has no parent
13091 */
13092 std::string pop_back()
13093 {
13094 if (is_root())
13095 {
13096 JSON_THROW(out_of_range::create(405, "JSON pointer has no parent"));
13097 }
13098
13099 auto last = reference_tokens.back();
13100 reference_tokens.pop_back();
13101 return last;
13102 }
13103
13104 /// return whether pointer points to the root document
13105 bool is_root() const
13106 {
13107 return reference_tokens.empty();
13108 }
13109
13110 json_pointer top() const
13111 {
13112 if (is_root())
13113 {
13114 JSON_THROW(out_of_range::create(405, "JSON pointer has no parent"));
13115 }
13116
13117 json_pointer result = *this;
13118 result.reference_tokens = {reference_tokens[0]};
13119 return result;
13120 }
13121
13122 /*!
13123 @brief create and return a reference to the pointed to value
13124
13125 @complexity Linear in the number of reference tokens.
13126
13127 @throw parse_error.109 if array index is not a number
13128 @throw type_error.313 if value cannot be unflattened
13129 */
13130 reference get_and_create(reference j) const
13131 {
13132 pointer result = &j;
13133
13134 // in case no reference tokens exist, return a reference to the
13135 // JSON value j which will be overwritten by a primitive value
13136 for (const auto& reference_token : reference_tokens)
13137 {
13138 switch (result->m_type)
13139 {
13140 case value_t::null:
13141 {
13142 if (reference_token == "0")
13143 {
13144 // start a new array if reference token is 0
13145 result = &result->operator[](0);
13146 }
13147 else
13148 {
13149 // start a new object otherwise
13150 result = &result->operator[](reference_token);
13151 }
13152 break;
13153 }
13154
13155 case value_t::object:
13156 {
13157 // create an entry in the object
13158 result = &result->operator[](reference_token);
13159 break;
13160 }
13161
13162 case value_t::array:
13163 {
13164 // create an entry in the array
13165 JSON_TRY
13166 {
13167 result = &result->operator[](static_cast<size_type>(std::stoi(reference_token)));
13168 }
13169 JSON_CATCH (std::invalid_argument&)
13170 {
13171 JSON_THROW(parse_error::create(109, 0, "array index '" + reference_token + "' is not a number"));
13172 }
13173 break;
13174 }
13175
13176 /*
13177 The following code is only reached if there exists a
13178 reference token _and_ the current value is primitive. In
13179 this case, we have an error situation, because primitive
13180 values may only occur as single value; that is, with an
13181 empty list of reference tokens.
13182 */
13183 default:
13184 {
13185 JSON_THROW(type_error::create(313, "invalid value to unflatten"));
13186 }
13187 }
13188 }
13189
13190 return *result;
13191 }
13192
13193 /*!
13194 @brief return a reference to the pointed to value
13195
13196 @note This version does not throw if a value is not present, but tries
13197 to create nested values instead. For instance, calling this function
13198 with pointer `"/this/that"` on a null value is equivalent to calling
13199 `operator[]("this").operator[]("that")` on that value, effectively
13200 changing the null value to an object.
13201
13202 @param[in] ptr a JSON value
13203
13204 @return reference to the JSON value pointed to by the JSON pointer
13205
13206 @complexity Linear in the length of the JSON pointer.
13207
13208 @throw parse_error.106 if an array index begins with '0'
13209 @throw parse_error.109 if an array index was not a number
13210 @throw out_of_range.404 if the JSON pointer can not be resolved
13211 */
13212 reference get_unchecked(pointer ptr) const
13213 {
13214 for (const auto& reference_token : reference_tokens)
13215 {
13216 // convert null values to arrays or objects before continuing
13217 if (ptr->m_type == value_t::null)
13218 {
13219 // check if reference token is a number
13220 const bool nums = std::all_of(reference_token.begin(),
13221 reference_token.end(),
13222 [](const char x)
13223 {
13224 return (x >= '0' and x <= '9');
13225 });
13226
13227 // change value to array for numbers or "-" or to object
13228 // otherwise
13229 if (nums or reference_token == "-")
13230 {
13231 *ptr = value_t::array;
13232 }
13233 else
13234 {
13235 *ptr = value_t::object;
13236 }
13237 }
13238
13239 switch (ptr->m_type)
13240 {
13241 case value_t::object:
13242 {
13243 // use unchecked object access
13244 ptr = &ptr->operator[](reference_token);
13245 break;
13246 }
13247
13248 case value_t::array:
13249 {
13250 // error condition (cf. RFC 6901, Sect. 4)
13251 if (reference_token.size() > 1 and reference_token[0] == '0')
13252 {
13253 JSON_THROW(parse_error::create(106, 0, "array index '" + reference_token + "' must not begin with '0'"));
13254 }
13255
13256 if (reference_token == "-")
13257 {
13258 // explicitly treat "-" as index beyond the end
13259 ptr = &ptr->operator[](ptr->m_value.array->size());
13260 }
13261 else
13262 {
13263 // convert array index to number; unchecked access
13264 JSON_TRY
13265 {
13266 ptr = &ptr->operator[](static_cast<size_type>(std::stoi(reference_token)));
13267 }
13268 JSON_CATCH (std::invalid_argument&)
13269 {
13270 JSON_THROW(parse_error::create(109, 0, "array index '" + reference_token + "' is not a number"));
13271 }
13272 }
13273 break;
13274 }
13275
13276 default:
13277 {
13278 JSON_THROW(out_of_range::create(404, "unresolved reference token '" + reference_token + "'"));
13279 }
13280 }
13281 }
13282
13283 return *ptr;
13284 }
13285
13286 /*!
13287 @throw parse_error.106 if an array index begins with '0'
13288 @throw parse_error.109 if an array index was not a number
13289 @throw out_of_range.402 if the array index '-' is used
13290 @throw out_of_range.404 if the JSON pointer can not be resolved
13291 */
13292 reference get_checked(pointer ptr) const
13293 {
13294 for (const auto& reference_token : reference_tokens)
13295 {
13296 switch (ptr->m_type)
13297 {
13298 case value_t::object:
13299 {
13300 // note: at performs range check
13301 ptr = &ptr->at(reference_token);
13302 break;
13303 }
13304
13305 case value_t::array:
13306 {
13307 if (reference_token == "-")
13308 {
13309 // "-" always fails the range check
13310 JSON_THROW(out_of_range::create(402, "array index '-' (" +
13311 std::to_string(ptr->m_value.array->size()) +
13312 ") is out of range"));
13313 }
13314
13315 // error condition (cf. RFC 6901, Sect. 4)
13316 if (reference_token.size() > 1 and reference_token[0] == '0')
13317 {
13318 JSON_THROW(parse_error::create(106, 0, "array index '" + reference_token + "' must not begin with '0'"));
13319 }
13320
13321 // note: at performs range check
13322 JSON_TRY
13323 {
13324 ptr = &ptr->at(static_cast<size_type>(std::stoi(reference_token)));
13325 }
13326 JSON_CATCH (std::invalid_argument&)
13327 {
13328 JSON_THROW(parse_error::create(109, 0, "array index '" + reference_token + "' is not a number"));
13329 }
13330 break;
13331 }
13332
13333 default:
13334 {
13335 JSON_THROW(out_of_range::create(404, "unresolved reference token '" + reference_token + "'"));
13336 }
13337 }
13338 }
13339
13340 return *ptr;
13341 }
13342
13343 /*!
13344 @brief return a const reference to the pointed to value
13345
13346 @param[in] ptr a JSON value
13347
13348 @return const reference to the JSON value pointed to by the JSON
13349 pointer
13350
13351 @throw parse_error.106 if an array index begins with '0'
13352 @throw parse_error.109 if an array index was not a number
13353 @throw out_of_range.402 if the array index '-' is used
13354 @throw out_of_range.404 if the JSON pointer can not be resolved
13355 */
13356 const_reference get_unchecked(const_pointer ptr) const
13357 {
13358 for (const auto& reference_token : reference_tokens)
13359 {
13360 switch (ptr->m_type)
13361 {
13362 case value_t::object:
13363 {
13364 // use unchecked object access
13365 ptr = &ptr->operator[](reference_token);
13366 break;
13367 }
13368
13369 case value_t::array:
13370 {
13371 if (reference_token == "-")
13372 {
13373 // "-" cannot be used for const access
13374 JSON_THROW(out_of_range::create(402, "array index '-' (" +
13375 std::to_string(ptr->m_value.array->size()) +
13376 ") is out of range"));
13377 }
13378
13379 // error condition (cf. RFC 6901, Sect. 4)
13380 if (reference_token.size() > 1 and reference_token[0] == '0')
13381 {
13382 JSON_THROW(parse_error::create(106, 0, "array index '" + reference_token + "' must not begin with '0'"));
13383 }
13384
13385 // use unchecked array access
13386 JSON_TRY
13387 {
13388 ptr = &ptr->operator[](static_cast<size_type>(std::stoi(reference_token)));
13389 }
13390 JSON_CATCH (std::invalid_argument&)
13391 {
13392 JSON_THROW(parse_error::create(109, 0, "array index '" + reference_token + "' is not a number"));
13393 }
13394 break;
13395 }
13396
13397 default:
13398 {
13399 JSON_THROW(out_of_range::create(404, "unresolved reference token '" + reference_token + "'"));
13400 }
13401 }
13402 }
13403
13404 return *ptr;
13405 }
13406
13407 /*!
13408 @throw parse_error.106 if an array index begins with '0'
13409 @throw parse_error.109 if an array index was not a number
13410 @throw out_of_range.402 if the array index '-' is used
13411 @throw out_of_range.404 if the JSON pointer can not be resolved
13412 */
13413 const_reference get_checked(const_pointer ptr) const
13414 {
13415 for (const auto& reference_token : reference_tokens)
13416 {
13417 switch (ptr->m_type)
13418 {
13419 case value_t::object:
13420 {
13421 // note: at performs range check
13422 ptr = &ptr->at(reference_token);
13423 break;
13424 }
13425
13426 case value_t::array:
13427 {
13428 if (reference_token == "-")
13429 {
13430 // "-" always fails the range check
13431 JSON_THROW(out_of_range::create(402, "array index '-' (" +
13432 std::to_string(ptr->m_value.array->size()) +
13433 ") is out of range"));
13434 }
13435
13436 // error condition (cf. RFC 6901, Sect. 4)
13437 if (reference_token.size() > 1 and reference_token[0] == '0')
13438 {
13439 JSON_THROW(parse_error::create(106, 0, "array index '" + reference_token + "' must not begin with '0'"));
13440 }
13441
13442 // note: at performs range check
13443 JSON_TRY
13444 {
13445 ptr = &ptr->at(static_cast<size_type>(std::stoi(reference_token)));
13446 }
13447 JSON_CATCH (std::invalid_argument&)
13448 {
13449 JSON_THROW(parse_error::create(109, 0, "array index '" + reference_token + "' is not a number"));
13450 }
13451 break;
13452 }
13453
13454 default:
13455 {
13456 JSON_THROW(out_of_range::create(404, "unresolved reference token '" + reference_token + "'"));
13457 }
13458 }
13459 }
13460
13461 return *ptr;
13462 }
13463
13464 /*!
13465 @brief split the string input to reference tokens
13466
13467 @note This function is only called by the json_pointer constructor.
13468 All exceptions below are documented there.
13469
13470 @throw parse_error.107 if the pointer is not empty or begins with '/'
13471 @throw parse_error.108 if character '~' is not followed by '0' or '1'
13472 */
13473 static std::vector<std::string> split(const std::string& reference_string)
13474 {
13475 std::vector<std::string> result;
13476
13477 // special case: empty reference string -> no reference tokens
13478 if (reference_string.empty())
13479 {
13480 return result;
13481 }
13482
13483 // check if nonempty reference string begins with slash
13484 if (reference_string[0] != '/')
13485 {
13486 JSON_THROW(parse_error::create(107, 1, "JSON pointer must be empty or begin with '/' - was: '" + reference_string + "'"));
13487 }
13488
13489 // extract the reference tokens:
13490 // - slash: position of the last read slash (or end of string)
13491 // - start: position after the previous slash
13492 for (
13493 // search for the first slash after the first character
13494 size_t slash = reference_string.find_first_of('/', 1),
13495 // set the beginning of the first reference token
13496 start = 1;
13497 // we can stop if start == string::npos+1 = 0
13498 start != 0;
13499 // set the beginning of the next reference token
13500 // (will eventually be 0 if slash == std::string::npos)
13501 start = slash + 1,
13502 // find next slash
13503 slash = reference_string.find_first_of('/', start))
13504 {
13505 // use the text between the beginning of the reference token
13506 // (start) and the last slash (slash).
13507 auto reference_token = reference_string.substr(start, slash - start);
13508
13509 // check reference tokens are properly escaped
13510 for (size_t pos = reference_token.find_first_of('~');
13511 pos != std::string::npos;
13512 pos = reference_token.find_first_of('~', pos + 1))
13513 {
13514 assert(reference_token[pos] == '~');
13515
13516 // ~ must be followed by 0 or 1
13517 if (pos == reference_token.size() - 1 or
13518 (reference_token[pos + 1] != '0' and
13519 reference_token[pos + 1] != '1'))
13520 {
13521 JSON_THROW(parse_error::create(108, 0, "escape character '~' must be followed with '0' or '1'"));
13522 }
13523 }
13524
13525 // finally, store the reference token
13526 unescape(reference_token);
13527 result.push_back(reference_token);
13528 }
13529
13530 return result;
13531 }
13532
13533 /*!
13534 @brief replace all occurrences of a substring by another string
13535
13536 @param[in,out] s the string to manipulate; changed so that all
13537 occurrences of @a f are replaced with @a t
13538 @param[in] f the substring to replace with @a t
13539 @param[in] t the string to replace @a f
13540
13541 @pre The search string @a f must not be empty. **This precondition is
13542 enforced with an assertion.**
13543
13544 @since version 2.0.0
13545 */
13546 static void replace_substring(std::string& s,
13547 const std::string& f,
13548 const std::string& t)
13549 {
13550 assert(not f.empty());
13551
13552 for (
13553 size_t pos = s.find(f); // find first occurrence of f
13554 pos != std::string::npos; // make sure f was found
13555 s.replace(pos, f.size(), t), // replace with t
13556 pos = s.find(f, pos + t.size()) // find next occurrence of f
13557 );
13558 }
13559
13560 /// escape tilde and slash
13561 static std::string escape(std::string s)
13562 {
13563 // escape "~"" to "~0" and "/" to "~1"
13564 replace_substring(s, "~", "~0");
13565 replace_substring(s, "/", "~1");
13566 return s;
13567 }
13568
13569 /// unescape tilde and slash
13570 static void unescape(std::string& s)
13571 {
13572 // first transform any occurrence of the sequence '~1' to '/'
13573 replace_substring(s, "~1", "/");
13574 // then transform any occurrence of the sequence '~0' to '~'
13575 replace_substring(s, "~0", "~");
13576 }
13577
13578 /*!
13579 @param[in] reference_string the reference string to the current value
13580 @param[in] value the value to consider
13581 @param[in,out] result the result object to insert values to
13582
13583 @note Empty objects or arrays are flattened to `null`.
13584 */
13585 static void flatten(const std::string& reference_string,
13586 const basic_json& value,
13587 basic_json& result)
13588 {
13589 switch (value.m_type)
13590 {
13591 case value_t::array:
13592 {
13593 if (value.m_value.array->empty())
13594 {
13595 // flatten empty array as null
13596 result[reference_string] = nullptr;
13597 }
13598 else
13599 {
13600 // iterate array and use index as reference string
13601 for (size_t i = 0; i < value.m_value.array->size(); ++i)
13602 {
13603 flatten(reference_string + "/" + std::to_string(i),
13604 value.m_value.array->operator[](i), result);
13605 }
13606 }
13607 break;
13608 }
13609
13610 case value_t::object:
13611 {
13612 if (value.m_value.object->empty())
13613 {
13614 // flatten empty object as null
13615 result[reference_string] = nullptr;
13616 }
13617 else
13618 {
13619 // iterate object and use keys as reference string
13620 for (const auto& element : *value.m_value.object)
13621 {
13622 flatten(reference_string + "/" + escape(element.first),
13623 element.second, result);
13624 }
13625 }
13626 break;
13627 }
13628
13629 default:
13630 {
13631 // add primitive value with its reference string
13632 result[reference_string] = value;
13633 break;
13634 }
13635 }
13636 }
13637
13638 /*!
13639 @param[in] value flattened JSON
13640
13641 @return unflattened JSON
13642
13643 @throw parse_error.109 if array index is not a number
13644 @throw type_error.314 if value is not an object
13645 @throw type_error.315 if object values are not primitive
13646 @throw type_error.313 if value cannot be unflattened
13647 */
13648 static basic_json unflatten(const basic_json& value)
13649 {
13650 if (not value.is_object())
13651 {
13652 JSON_THROW(type_error::create(314, "only objects can be unflattened"));
13653 }
13654
13655 basic_json result;
13656
13657 // iterate the JSON object values
13658 for (const auto& element : *value.m_value.object)
13659 {
13660 if (not element.second.is_primitive())
13661 {
13662 JSON_THROW(type_error::create(315, "values in object must be primitive"));
13663 }
13664
13665 // assign value to reference pointed to by JSON pointer; Note
13666 // that if the JSON pointer is "" (i.e., points to the whole
13667 // value), function get_and_create returns a reference to
13668 // result itself. An assignment will then create a primitive
13669 // value.
13670 json_pointer(element.first).get_and_create(result) = element.second;
13671 }
13672
13673 return result;
13674 }
13675
13676 friend bool operator==(json_pointer const& lhs,
13677 json_pointer const& rhs) noexcept
13678 {
13679 return lhs.reference_tokens == rhs.reference_tokens;
13680 }
13681
13682 friend bool operator!=(json_pointer const& lhs,
13683 json_pointer const& rhs) noexcept
13684 {
13685 return !(lhs == rhs);
13686 }
13687
13688 /// the reference tokens
13689 std::vector<std::string> reference_tokens {};
13690 };
13691
13692 //////////////////////////
13693 // JSON Pointer support //
13694 //////////////////////////
13695
13696 /// @name JSON Pointer functions
13697 /// @{
13698
13699 /*!
13700 @brief access specified element via JSON Pointer
13701
13702 Uses a JSON pointer to retrieve a reference to the respective JSON value.
13703 No bound checking is performed. Similar to @ref operator[](const typename
13704 object_t::key_type&), `null` values are created in arrays and objects if
13705 necessary.
13706
13707 In particular:
13708 - If the JSON pointer points to an object key that does not exist, it
13709 is created an filled with a `null` value before a reference to it
13710 is returned.
13711 - If the JSON pointer points to an array index that does not exist, it
13712 is created an filled with a `null` value before a reference to it
13713 is returned. All indices between the current maximum and the given
13714 index are also filled with `null`.
13715 - The special value `-` is treated as a synonym for the index past the
13716 end.
13717
13718 @param[in] ptr a JSON pointer
13719
13720 @return reference to the element pointed to by @a ptr
13721
13722 @complexity Constant.
13723
13724 @throw parse_error.106 if an array index begins with '0'
13725 @throw parse_error.109 if an array index was not a number
13726 @throw out_of_range.404 if the JSON pointer can not be resolved
13727
13728 @liveexample{The behavior is shown in the example.,operatorjson_pointer}
13729
13730 @since version 2.0.0
13731 */
13732 reference operator[](const json_pointer& ptr)
13733 {
13734 return ptr.get_unchecked(this);
13735 }
13736
13737 /*!
13738 @brief access specified element via JSON Pointer
13739
13740 Uses a JSON pointer to retrieve a reference to the respective JSON value.
13741 No bound checking is performed. The function does not change the JSON
13742 value; no `null` values are created. In particular, the the special value
13743 `-` yields an exception.
13744
13745 @param[in] ptr JSON pointer to the desired element
13746
13747 @return const reference to the element pointed to by @a ptr
13748
13749 @complexity Constant.
13750
13751 @throw parse_error.106 if an array index begins with '0'
13752 @throw parse_error.109 if an array index was not a number
13753 @throw out_of_range.402 if the array index '-' is used
13754 @throw out_of_range.404 if the JSON pointer can not be resolved
13755
13756 @liveexample{The behavior is shown in the example.,operatorjson_pointer_const}
13757
13758 @since version 2.0.0
13759 */
13760 const_reference operator[](const json_pointer& ptr) const
13761 {
13762 return ptr.get_unchecked(this);
13763 }
13764
13765 /*!
13766 @brief access specified element via JSON Pointer
13767
13768 Returns a reference to the element at with specified JSON pointer @a ptr,
13769 with bounds checking.
13770
13771 @param[in] ptr JSON pointer to the desired element
13772
13773 @return reference to the element pointed to by @a ptr
13774
13775 @throw parse_error.106 if an array index in the passed JSON pointer @a ptr
13776 begins with '0'. See example below.
13777
13778 @throw parse_error.109 if an array index in the passed JSON pointer @a ptr
13779 is not a number. See example below.
13780
13781 @throw out_of_range.401 if an array index in the passed JSON pointer @a ptr
13782 is out of range. See example below.
13783
13784 @throw out_of_range.402 if the array index '-' is used in the passed JSON
13785 pointer @a ptr. As `at` provides checked access (and no elements are
13786 implicitly inserted), the index '-' is always invalid. See example below.
13787
13788 @throw out_of_range.404 if the JSON pointer @a ptr can not be resolved.
13789 See example below.
13790
13791 @exceptionsafety Strong guarantee: if an exception is thrown, there are no
13792 changes in the JSON value.
13793
13794 @complexity Constant.
13795
13796 @since version 2.0.0
13797
13798 @liveexample{The behavior is shown in the example.,at_json_pointer}
13799 */
13800 reference at(const json_pointer& ptr)
13801 {
13802 return ptr.get_checked(this);
13803 }
13804
13805 /*!
13806 @brief access specified element via JSON Pointer
13807
13808 Returns a const reference to the element at with specified JSON pointer @a
13809 ptr, with bounds checking.
13810
13811 @param[in] ptr JSON pointer to the desired element
13812
13813 @return reference to the element pointed to by @a ptr
13814
13815 @throw parse_error.106 if an array index in the passed JSON pointer @a ptr
13816 begins with '0'. See example below.
13817
13818 @throw parse_error.109 if an array index in the passed JSON pointer @a ptr
13819 is not a number. See example below.
13820
13821 @throw out_of_range.401 if an array index in the passed JSON pointer @a ptr
13822 is out of range. See example below.
13823
13824 @throw out_of_range.402 if the array index '-' is used in the passed JSON
13825 pointer @a ptr. As `at` provides checked access (and no elements are
13826 implicitly inserted), the index '-' is always invalid. See example below.
13827
13828 @throw out_of_range.404 if the JSON pointer @a ptr can not be resolved.
13829 See example below.
13830
13831 @exceptionsafety Strong guarantee: if an exception is thrown, there are no
13832 changes in the JSON value.
13833
13834 @complexity Constant.
13835
13836 @since version 2.0.0
13837
13838 @liveexample{The behavior is shown in the example.,at_json_pointer_const}
13839 */
13840 const_reference at(const json_pointer& ptr) const
13841 {
13842 return ptr.get_checked(this);
13843 }
13844
13845 /*!
13846 @brief return flattened JSON value
13847
13848 The function creates a JSON object whose keys are JSON pointers (see [RFC
13849 6901](https://tools.ietf.org/html/rfc6901)) and whose values are all
13850 primitive. The original JSON value can be restored using the @ref
13851 unflatten() function.
13852
13853 @return an object that maps JSON pointers to primitive values
13854
13855 @note Empty objects and arrays are flattened to `null` and will not be
13856 reconstructed correctly by the @ref unflatten() function.
13857
13858 @complexity Linear in the size the JSON value.
13859
13860 @liveexample{The following code shows how a JSON object is flattened to an
13861 object whose keys consist of JSON pointers.,flatten}
13862
13863 @sa @ref unflatten() for the reverse function
13864
13865 @since version 2.0.0
13866 */
13867 basic_json flatten() const
13868 {
13869 basic_json result(value_t::object);
13870 json_pointer::flatten("", *this, result);
13871 return result;
13872 }
13873
13874 /*!
13875 @brief unflatten a previously flattened JSON value
13876
13877 The function restores the arbitrary nesting of a JSON value that has been
13878 flattened before using the @ref flatten() function. The JSON value must
13879 meet certain constraints:
13880 1. The value must be an object.
13881 2. The keys must be JSON pointers (see
13882 [RFC 6901](https://tools.ietf.org/html/rfc6901))
13883 3. The mapped values must be primitive JSON types.
13884
13885 @return the original JSON from a flattened version
13886
13887 @note Empty objects and arrays are flattened by @ref flatten() to `null`
13888 values and can not unflattened to their original type. Apart from
13889 this example, for a JSON value `j`, the following is always true:
13890 `j == j.flatten().unflatten()`.
13891
13892 @complexity Linear in the size the JSON value.
13893
13894 @throw type_error.314 if value is not an object
13895 @throw type_error.315 if object values are not primitive
13896
13897 @liveexample{The following code shows how a flattened JSON object is
13898 unflattened into the original nested JSON object.,unflatten}
13899
13900 @sa @ref flatten() for the reverse function
13901
13902 @since version 2.0.0
13903 */
13904 basic_json unflatten() const
13905 {
13906 return json_pointer::unflatten(*this);
13907 }
13908
13909 /// @}
13910
13911 //////////////////////////
13912 // JSON Patch functions //
13913 //////////////////////////
13914
13915 /// @name JSON Patch functions
13916 /// @{
13917
13918 /*!
13919 @brief applies a JSON patch
13920
13921 [JSON Patch](http://jsonpatch.com) defines a JSON document structure for
13922 expressing a sequence of operations to apply to a JSON) document. With
13923 this function, a JSON Patch is applied to the current JSON value by
13924 executing all operations from the patch.
13925
13926 @param[in] json_patch JSON patch document
13927 @return patched document
13928
13929 @note The application of a patch is atomic: Either all operations succeed
13930 and the patched document is returned or an exception is thrown. In
13931 any case, the original value is not changed: the patch is applied
13932 to a copy of the value.
13933
13934 @throw parse_error.104 if the JSON patch does not consist of an array of
13935 objects
13936
13937 @throw parse_error.105 if the JSON patch is malformed (e.g., mandatory
13938 attributes are missing); example: `"operation add must have member path"`
13939
13940 @throw out_of_range.401 if an array index is out of range.
13941
13942 @throw out_of_range.403 if a JSON pointer inside the patch could not be
13943 resolved successfully in the current JSON value; example: `"key baz not
13944 found"`
13945
13946 @throw out_of_range.405 if JSON pointer has no parent ("add", "remove",
13947 "move")
13948
13949 @throw other_error.501 if "test" operation was unsuccessful
13950
13951 @complexity Linear in the size of the JSON value and the length of the
13952 JSON patch. As usually only a fraction of the JSON value is affected by
13953 the patch, the complexity can usually be neglected.
13954
13955 @liveexample{The following code shows how a JSON patch is applied to a
13956 value.,patch}
13957
13958 @sa @ref diff -- create a JSON patch by comparing two JSON values
13959
13960 @sa [RFC 6902 (JSON Patch)](https://tools.ietf.org/html/rfc6902)
13961 @sa [RFC 6901 (JSON Pointer)](https://tools.ietf.org/html/rfc6901)
13962
13963 @since version 2.0.0
13964 */
13965 basic_json patch(const basic_json& json_patch) const
13966 {
13967 // make a working copy to apply the patch to
13968 basic_json result = *this;
13969
13970 // the valid JSON Patch operations
13971 enum class patch_operations {add, remove, replace, move, copy, test, invalid};
13972
13973 const auto get_op = [](const std::string & op)
13974 {
13975 if (op == "add")
13976 {
13977 return patch_operations::add;
13978 }
13979 if (op == "remove")
13980 {
13981 return patch_operations::remove;
13982 }
13983 if (op == "replace")
13984 {
13985 return patch_operations::replace;
13986 }
13987 if (op == "move")
13988 {
13989 return patch_operations::move;
13990 }
13991 if (op == "copy")
13992 {
13993 return patch_operations::copy;
13994 }
13995 if (op == "test")
13996 {
13997 return patch_operations::test;
13998 }
13999
14000 return patch_operations::invalid;
14001 };
14002
14003 // wrapper for "add" operation; add value at ptr
14004 const auto operation_add = [&result](json_pointer & ptr, basic_json val)
14005 {
14006 // adding to the root of the target document means replacing it
14007 if (ptr.is_root())
14008 {
14009 result = val;
14010 }
14011 else
14012 {
14013 // make sure the top element of the pointer exists
14014 json_pointer top_pointer = ptr.top();
14015 if (top_pointer != ptr)
14016 {
14017 result.at(top_pointer);
14018 }
14019
14020 // get reference to parent of JSON pointer ptr
14021 const auto last_path = ptr.pop_back();
14022 basic_json& parent = result[ptr];
14023
14024 switch (parent.m_type)
14025 {
14026 case value_t::null:
14027 case value_t::object:
14028 {
14029 // use operator[] to add value
14030 parent[last_path] = val;
14031 break;
14032 }
14033
14034 case value_t::array:
14035 {
14036 if (last_path == "-")
14037 {
14038 // special case: append to back
14039 parent.push_back(val);
14040 }
14041 else
14042 {
14043 const auto idx = std::stoi(last_path);
14044 if (static_cast<size_type>(idx) > parent.size())
14045 {
14046 // avoid undefined behavior
14047 JSON_THROW(out_of_range::create(401, "array index " + std::to_string(idx) + " is out of range"));
14048 }
14049 else
14050 {
14051 // default case: insert add offset
14052 parent.insert(parent.begin() + static_cast<difference_type>(idx), val);
14053 }
14054 }
14055 break;
14056 }
14057
14058 default:
14059 {
14060 // if there exists a parent it cannot be primitive
14061 assert(false); // LCOV_EXCL_LINE
14062 }
14063 }
14064 }
14065 };
14066
14067 // wrapper for "remove" operation; remove value at ptr
14068 const auto operation_remove = [&result](json_pointer & ptr)
14069 {
14070 // get reference to parent of JSON pointer ptr
14071 const auto last_path = ptr.pop_back();
14072 basic_json& parent = result.at(ptr);
14073
14074 // remove child
14075 if (parent.is_object())
14076 {
14077 // perform range check
14078 auto it = parent.find(last_path);
14079 if (it != parent.end())
14080 {
14081 parent.erase(it);
14082 }
14083 else
14084 {
14085 JSON_THROW(out_of_range::create(403, "key '" + last_path + "' not found"));
14086 }
14087 }
14088 else if (parent.is_array())
14089 {
14090 // note erase performs range check
14091 parent.erase(static_cast<size_type>(std::stoi(last_path)));
14092 }
14093 };
14094
14095 // type check: top level value must be an array
14096 if (not json_patch.is_array())
14097 {
14098 JSON_THROW(parse_error::create(104, 0, "JSON patch must be an array of objects"));
14099 }
14100
14101 // iterate and apply the operations
14102 for (const auto& val : json_patch)
14103 {
14104 // wrapper to get a value for an operation
14105 const auto get_value = [&val](const std::string & op,
14106 const std::string & member,
14107 bool string_type) -> basic_json&
14108 {
14109 // find value
14110 auto it = val.m_value.object->find(member);
14111
14112 // context-sensitive error message
14113 const auto error_msg = (op == "op") ? "operation" : "operation '" + op + "'";
14114
14115 // check if desired value is present
14116 if (it == val.m_value.object->end())
14117 {
14118 JSON_THROW(parse_error::create(105, 0, error_msg + " must have member '" + member + "'"));
14119 }
14120
14121 // check if result is of type string
14122 if (string_type and not it->second.is_string())
14123 {
14124 JSON_THROW(parse_error::create(105, 0, error_msg + " must have string member '" + member + "'"));
14125 }
14126
14127 // no error: return value
14128 return it->second;
14129 };
14130
14131 // type check: every element of the array must be an object
14132 if (not val.is_object())
14133 {
14134 JSON_THROW(parse_error::create(104, 0, "JSON patch must be an array of objects"));
14135 }
14136
14137 // collect mandatory members
14138 const std::string op = get_value("op", "op", true);
14139 const std::string path = get_value(op, "path", true);
14140 json_pointer ptr(path);
14141
14142 switch (get_op(op))
14143 {
14144 case patch_operations::add:
14145 {
14146 operation_add(ptr, get_value("add", "value", false));
14147 break;
14148 }
14149
14150 case patch_operations::remove:
14151 {
14152 operation_remove(ptr);
14153 break;
14154 }
14155
14156 case patch_operations::replace:
14157 {
14158 // the "path" location must exist - use at()
14159 result.at(ptr) = get_value("replace", "value", false);
14160 break;
14161 }
14162
14163 case patch_operations::move:
14164 {
14165 const std::string from_path = get_value("move", "from", true);
14166 json_pointer from_ptr(from_path);
14167
14168 // the "from" location must exist - use at()
14169 basic_json v = result.at(from_ptr);
14170
14171 // The move operation is functionally identical to a
14172 // "remove" operation on the "from" location, followed
14173 // immediately by an "add" operation at the target
14174 // location with the value that was just removed.
14175 operation_remove(from_ptr);
14176 operation_add(ptr, v);
14177 break;
14178 }
14179
14180 case patch_operations::copy:
14181 {
14182 const std::string from_path = get_value("copy", "from", true);
14183 const json_pointer from_ptr(from_path);
14184
14185 // the "from" location must exist - use at()
14186 result[ptr] = result.at(from_ptr);
14187 break;
14188 }
14189
14190 case patch_operations::test:
14191 {
14192 bool success = false;
14193 JSON_TRY
14194 {
14195 // check if "value" matches the one at "path"
14196 // the "path" location must exist - use at()
14197 success = (result.at(ptr) == get_value("test", "value", false));
14198 }
14199 JSON_CATCH (out_of_range&)
14200 {
14201 // ignore out of range errors: success remains false
14202 }
14203
14204 // throw an exception if test fails
14205 if (not success)
14206 {
14207 JSON_THROW(other_error::create(501, "unsuccessful: " + val.dump()));
14208 }
14209
14210 break;
14211 }
14212
14213 case patch_operations::invalid:
14214 {
14215 // op must be "add", "remove", "replace", "move", "copy", or
14216 // "test"
14217 JSON_THROW(parse_error::create(105, 0, "operation value '" + op + "' is invalid"));
14218 }
14219 }
14220 }
14221
14222 return result;
14223 }
14224
14225 /*!
14226 @brief creates a diff as a JSON patch
14227
14228 Creates a [JSON Patch](http://jsonpatch.com) so that value @a source can
14229 be changed into the value @a target by calling @ref patch function.
14230
14231 @invariant For two JSON values @a source and @a target, the following code
14232 yields always `true`:
14233 @code {.cpp}
14234 source.patch(diff(source, target)) == target;
14235 @endcode
14236
14237 @note Currently, only `remove`, `add`, and `replace` operations are
14238 generated.
14239
14240 @param[in] source JSON value to compare from
14241 @param[in] target JSON value to compare against
14242 @param[in] path helper value to create JSON pointers
14243
14244 @return a JSON patch to convert the @a source to @a target
14245
14246 @complexity Linear in the lengths of @a source and @a target.
14247
14248 @liveexample{The following code shows how a JSON patch is created as a
14249 diff for two JSON values.,diff}
14250
14251 @sa @ref patch -- apply a JSON patch
14252
14253 @sa [RFC 6902 (JSON Patch)](https://tools.ietf.org/html/rfc6902)
14254
14255 @since version 2.0.0
14256 */
14257 static basic_json diff(const basic_json& source,
14258 const basic_json& target,
14259 const std::string& path = "")
14260 {
14261 // the patch
14262 basic_json result(value_t::array);
14263
14264 // if the values are the same, return empty patch
14265 if (source == target)
14266 {
14267 return result;
14268 }
14269
14270 if (source.type() != target.type())
14271 {
14272 // different types: replace value
14273 result.push_back(
14274 {
14275 {"op", "replace"},
14276 {"path", path},
14277 {"value", target}
14278 });
14279 }
14280 else
14281 {
14282 switch (source.type())
14283 {
14284 case value_t::array:
14285 {
14286 // first pass: traverse common elements
14287 size_t i = 0;
14288 while (i < source.size() and i < target.size())
14289 {
14290 // recursive call to compare array values at index i
14291 auto temp_diff = diff(source[i], target[i], path + "/" + std::to_string(i));
14292 result.insert(result.end(), temp_diff.begin(), temp_diff.end());
14293 ++i;
14294 }
14295
14296 // i now reached the end of at least one array
14297 // in a second pass, traverse the remaining elements
14298
14299 // remove my remaining elements
14300 const auto end_index = static_cast<difference_type>(result.size());
14301 while (i < source.size())
14302 {
14303 // add operations in reverse order to avoid invalid
14304 // indices
14305 result.insert(result.begin() + end_index, object(
14306 {
14307 {"op", "remove"},
14308 {"path", path + "/" + std::to_string(i)}
14309 }));
14310 ++i;
14311 }
14312
14313 // add other remaining elements
14314 while (i < target.size())
14315 {
14316 result.push_back(
14317 {
14318 {"op", "add"},
14319 {"path", path + "/" + std::to_string(i)},
14320 {"value", target[i]}
14321 });
14322 ++i;
14323 }
14324
14325 break;
14326 }
14327
14328 case value_t::object:
14329 {
14330 // first pass: traverse this object's elements
14331 for (auto it = source.begin(); it != source.end(); ++it)
14332 {
14333 // escape the key name to be used in a JSON patch
14334 const auto key = json_pointer::escape(it.key());
14335
14336 if (target.find(it.key()) != target.end())
14337 {
14338 // recursive call to compare object values at key it
14339 auto temp_diff = diff(it.value(), target[it.key()], path + "/" + key);
14340 result.insert(result.end(), temp_diff.begin(), temp_diff.end());
14341 }
14342 else
14343 {
14344 // found a key that is not in o -> remove it
14345 result.push_back(object(
14346 {
14347 {"op", "remove"},
14348 {"path", path + "/" + key}
14349 }));
14350 }
14351 }
14352
14353 // second pass: traverse other object's elements
14354 for (auto it = target.begin(); it != target.end(); ++it)
14355 {
14356 if (source.find(it.key()) == source.end())
14357 {
14358 // found a key that is not in this -> add it
14359 const auto key = json_pointer::escape(it.key());
14360 result.push_back(
14361 {
14362 {"op", "add"},
14363 {"path", path + "/" + key},
14364 {"value", it.value()}
14365 });
14366 }
14367 }
14368
14369 break;
14370 }
14371
14372 default:
14373 {
14374 // both primitive type: replace value
14375 result.push_back(
14376 {
14377 {"op", "replace"},
14378 {"path", path},
14379 {"value", target}
14380 });
14381 break;
14382 }
14383 }
14384 }
14385
14386 return result;
14387 }
14388
14389 /// @}
14390};
14391
14392/////////////
14393// presets //
14394/////////////
14395
14396/*!
14397@brief default JSON class
14398
14399This type is the default specialization of the @ref basic_json class which
14400uses the standard template types.
14401
14402@since version 1.0.0
14403*/
14404using json = basic_json<>;
14405} // namespace nlohmann
14406
14407
14408///////////////////////
14409// nonmember support //
14410///////////////////////
14411
14412// specialization of std::swap, and std::hash
14413namespace std
14414{
14415/*!
14416@brief exchanges the values of two JSON objects
14417
14418@since version 1.0.0
14419*/
14420template<>
14421inline void swap(nlohmann::json& j1,
14422 nlohmann::json& j2) noexcept(
14423 is_nothrow_move_constructible<nlohmann::json>::value and
14424 is_nothrow_move_assignable<nlohmann::json>::value
14425 )
14426{
14427 j1.swap(j2);
14428}
14429
14430/// hash value for JSON objects
14431template<>
14432struct hash<nlohmann::json>
14433{
14434 /*!
14435 @brief return a hash value for a JSON object
14436
14437 @since version 1.0.0
14438 */
14439 std::size_t operator()(const nlohmann::json& j) const
14440 {
14441 // a naive hashing via the string representation
14442 const auto& h = hash<nlohmann::json::string_t>();
14443 return h(j.dump());
14444 }
14445};
14446
14447/// specialization for std::less<value_t>
14448template <>
14449struct less<::nlohmann::detail::value_t>
14450{
14451 /*!
14452 @brief compare two value_t enum values
14453 @since version 3.0.0
14454 */
14455 bool operator()(nlohmann::detail::value_t lhs,
14456 nlohmann::detail::value_t rhs) const noexcept
14457 {
14458 return nlohmann::detail::operator<(lhs, rhs);
14459 }
14460};
14461
14462} // namespace std
14463
14464/*!
14465@brief user-defined string literal for JSON values
14466
14467This operator implements a user-defined string literal for JSON objects. It
14468can be used by adding `"_json"` to a string literal and returns a JSON object
14469if no parse error occurred.
14470
14471@param[in] s a string representation of a JSON object
14472@param[in] n the length of string @a s
14473@return a JSON object
14474
14475@since version 1.0.0
14476*/
14477inline nlohmann::json operator "" _json(const char* s, std::size_t n)
14478{
14479 return nlohmann::json::parse(s, s + n);
14480}
14481
14482/*!
14483@brief user-defined string literal for JSON pointer
14484
14485This operator implements a user-defined string literal for JSON Pointers. It
14486can be used by adding `"_json_pointer"` to a string literal and returns a JSON pointer
14487object if no parse error occurred.
14488
14489@param[in] s a string representation of a JSON Pointer
14490@param[in] n the length of string @a s
14491@return a JSON pointer object
14492
14493@since version 2.0.0
14494*/
14495inline nlohmann::json::json_pointer operator "" _json_pointer(const char* s, std::size_t n)
14496{
14497 return nlohmann::json::json_pointer(std::string(s, n));
14498}
14499
14500// restore GCC/clang diagnostic settings
14501#if defined(__clang__) || defined(__GNUC__) || defined(__GNUG__)
14502 #pragma GCC diagnostic pop
14503#endif
14504#if defined(__clang__)
14505 #pragma GCC diagnostic pop
14506#endif
14507
14508// clean up
14509#undef JSON_CATCH
14510#undef JSON_THROW
14511#undef JSON_TRY
14512#undef JSON_LIKELY
14513#undef JSON_UNLIKELY
14514#undef JSON_DEPRECATED
14515
14516#endif
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index e11940f59..85354f43e 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -4,16 +4,11 @@ include_directories(.)
4add_subdirectory(common) 4add_subdirectory(common)
5add_subdirectory(core) 5add_subdirectory(core)
6add_subdirectory(video_core) 6add_subdirectory(video_core)
7add_subdirectory(audio_core)
8add_subdirectory(network)
9add_subdirectory(input_common) 7add_subdirectory(input_common)
10add_subdirectory(tests) 8add_subdirectory(tests)
11if (ENABLE_SDL2) 9if (ENABLE_SDL2)
12 add_subdirectory(citra) 10 add_subdirectory(yuzu_cmd)
13endif() 11endif()
14if (ENABLE_QT) 12if (ENABLE_QT)
15 add_subdirectory(citra_qt) 13 add_subdirectory(yuzu)
16endif()
17if (ENABLE_WEB_SERVICE)
18 add_subdirectory(web_service)
19endif() 14endif()
diff --git a/src/audio_core/CMakeLists.txt b/src/audio_core/CMakeLists.txt
deleted file mode 100644
index 0ad86bb7a..000000000
--- a/src/audio_core/CMakeLists.txt
+++ /dev/null
@@ -1,44 +0,0 @@
1set(SRCS
2 audio_core.cpp
3 codec.cpp
4 hle/dsp.cpp
5 hle/filter.cpp
6 hle/mixers.cpp
7 hle/pipe.cpp
8 hle/source.cpp
9 interpolate.cpp
10 sink_details.cpp
11 time_stretch.cpp
12 )
13
14set(HEADERS
15 audio_core.h
16 codec.h
17 hle/common.h
18 hle/dsp.h
19 hle/filter.h
20 hle/mixers.h
21 hle/pipe.h
22 hle/source.h
23 interpolate.h
24 null_sink.h
25 sink.h
26 sink_details.h
27 time_stretch.h
28 )
29
30if(SDL2_FOUND)
31 set(SRCS ${SRCS} sdl2_sink.cpp)
32 set(HEADERS ${HEADERS} sdl2_sink.h)
33endif()
34
35create_directory_groups(${SRCS} ${HEADERS})
36
37add_library(audio_core STATIC ${SRCS} ${HEADERS})
38target_link_libraries(audio_core PUBLIC common core)
39target_link_libraries(audio_core PRIVATE SoundTouch)
40
41if(SDL2_FOUND)
42 target_link_libraries(audio_core PRIVATE SDL2)
43 target_compile_definitions(audio_core PRIVATE HAVE_SDL2)
44endif()
diff --git a/src/audio_core/audio_core.cpp b/src/audio_core/audio_core.cpp
deleted file mode 100644
index ae2b68f9c..000000000
--- a/src/audio_core/audio_core.cpp
+++ /dev/null
@@ -1,61 +0,0 @@
1// Copyright 2016 Citra Emulator Project
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#include <array>
6#include <memory>
7#include <string>
8#include "audio_core/audio_core.h"
9#include "audio_core/hle/dsp.h"
10#include "audio_core/hle/pipe.h"
11#include "audio_core/null_sink.h"
12#include "audio_core/sink.h"
13#include "audio_core/sink_details.h"
14#include "common/common_types.h"
15#include "core/core_timing.h"
16#include "core/hle/service/dsp_dsp.h"
17
18namespace AudioCore {
19
20// Audio Ticks occur about every 5 miliseconds.
21static CoreTiming::EventType* tick_event; ///< CoreTiming event
22static constexpr u64 audio_frame_ticks = 1310252ull; ///< Units: ARM11 cycles
23
24static void AudioTickCallback(u64 /*userdata*/, int cycles_late) {
25 if (DSP::HLE::Tick()) {
26 // TODO(merry): Signal all the other interrupts as appropriate.
27 Service::DSP_DSP::SignalPipeInterrupt(DSP::HLE::DspPipe::Audio);
28 // HACK(merry): Added to prevent regressions. Will remove soon.
29 Service::DSP_DSP::SignalPipeInterrupt(DSP::HLE::DspPipe::Binary);
30 }
31
32 // Reschedule recurrent event
33 CoreTiming::ScheduleEvent(audio_frame_ticks - cycles_late, tick_event);
34}
35
36void Init() {
37 DSP::HLE::Init();
38
39 tick_event = CoreTiming::RegisterEvent("AudioCore::tick_event", AudioTickCallback);
40 CoreTiming::ScheduleEvent(audio_frame_ticks, tick_event);
41}
42
43std::array<u8, Memory::DSP_RAM_SIZE>& GetDspMemory() {
44 return DSP::HLE::g_dsp_memory.raw_memory;
45}
46
47void SelectSink(std::string sink_id) {
48 const SinkDetails& sink_details = GetSinkDetails(sink_id);
49 DSP::HLE::SetSink(sink_details.factory());
50}
51
52void EnableStretching(bool enable) {
53 DSP::HLE::EnableStretching(enable);
54}
55
56void Shutdown() {
57 CoreTiming::UnscheduleEvent(tick_event, 0);
58 DSP::HLE::Shutdown();
59}
60
61} // namespace AudioCore
diff --git a/src/audio_core/audio_core.h b/src/audio_core/audio_core.h
deleted file mode 100644
index ab323ce1f..000000000
--- a/src/audio_core/audio_core.h
+++ /dev/null
@@ -1,31 +0,0 @@
1// Copyright 2016 Citra Emulator Project
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#pragma once
6
7#include <array>
8#include <string>
9#include "common/common_types.h"
10#include "core/memory.h"
11
12namespace AudioCore {
13
14constexpr int native_sample_rate = 32728; ///< 32kHz
15
16/// Initialise Audio Core
17void Init();
18
19/// Returns a reference to the array backing DSP memory
20std::array<u8, Memory::DSP_RAM_SIZE>& GetDspMemory();
21
22/// Select the sink to use based on sink id.
23void SelectSink(std::string sink_id);
24
25/// Enable/Disable stretching.
26void EnableStretching(bool enable);
27
28/// Shutdown Audio Core
29void Shutdown();
30
31} // namespace AudioCore
diff --git a/src/audio_core/codec.cpp b/src/audio_core/codec.cpp
deleted file mode 100644
index 6fba9fdae..000000000
--- a/src/audio_core/codec.cpp
+++ /dev/null
@@ -1,127 +0,0 @@
1// Copyright 2016 Citra Emulator Project
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#include <array>
6#include <cstddef>
7#include <cstring>
8#include <vector>
9#include "audio_core/codec.h"
10#include "common/assert.h"
11#include "common/common_types.h"
12#include "common/math_util.h"
13
14namespace Codec {
15
16StereoBuffer16 DecodeADPCM(const u8* const data, const size_t sample_count,
17 const std::array<s16, 16>& adpcm_coeff, ADPCMState& state) {
18 // GC-ADPCM with scale factor and variable coefficients.
19 // Frames are 8 bytes long containing 14 samples each.
20 // Samples are 4 bits (one nibble) long.
21
22 constexpr size_t FRAME_LEN = 8;
23 constexpr size_t SAMPLES_PER_FRAME = 14;
24 constexpr std::array<int, 16> SIGNED_NIBBLES = {
25 {0, 1, 2, 3, 4, 5, 6, 7, -8, -7, -6, -5, -4, -3, -2, -1}};
26
27 const size_t ret_size =
28 sample_count % 2 == 0 ? sample_count : sample_count + 1; // Ensure multiple of two.
29 StereoBuffer16 ret(ret_size);
30
31 int yn1 = state.yn1, yn2 = state.yn2;
32
33 const size_t NUM_FRAMES =
34 (sample_count + (SAMPLES_PER_FRAME - 1)) / SAMPLES_PER_FRAME; // Round up.
35 for (size_t framei = 0; framei < NUM_FRAMES; framei++) {
36 const int frame_header = data[framei * FRAME_LEN];
37 const int scale = 1 << (frame_header & 0xF);
38 const int idx = (frame_header >> 4) & 0x7;
39
40 // Coefficients are fixed point with 11 bits fractional part.
41 const int coef1 = adpcm_coeff[idx * 2 + 0];
42 const int coef2 = adpcm_coeff[idx * 2 + 1];
43
44 // Decodes an audio sample. One nibble produces one sample.
45 const auto decode_sample = [&](const int nibble) -> s16 {
46 const int xn = nibble * scale;
47 // We first transform everything into 11 bit fixed point, perform the second order
48 // digital filter, then transform back.
49 // 0x400 == 0.5 in 11 bit fixed point.
50 // Filter: y[n] = x[n] + 0.5 + c1 * y[n-1] + c2 * y[n-2]
51 int val = ((xn << 11) + 0x400 + coef1 * yn1 + coef2 * yn2) >> 11;
52 // Clamp to output range.
53 val = MathUtil::Clamp(val, -32768, 32767);
54 // Advance output feedback.
55 yn2 = yn1;
56 yn1 = val;
57 return (s16)val;
58 };
59
60 size_t outputi = framei * SAMPLES_PER_FRAME;
61 size_t datai = framei * FRAME_LEN + 1;
62 for (size_t i = 0; i < SAMPLES_PER_FRAME && outputi < sample_count; i += 2) {
63 const s16 sample1 = decode_sample(SIGNED_NIBBLES[data[datai] >> 4]);
64 ret[outputi].fill(sample1);
65 outputi++;
66
67 const s16 sample2 = decode_sample(SIGNED_NIBBLES[data[datai] & 0xF]);
68 ret[outputi].fill(sample2);
69 outputi++;
70
71 datai++;
72 }
73 }
74
75 state.yn1 = yn1;
76 state.yn2 = yn2;
77
78 return ret;
79}
80
81static s16 SignExtendS8(u8 x) {
82 // The data is actually signed PCM8.
83 // We sign extend this to signed PCM16.
84 return static_cast<s16>(static_cast<s8>(x));
85}
86
87StereoBuffer16 DecodePCM8(const unsigned num_channels, const u8* const data,
88 const size_t sample_count) {
89 ASSERT(num_channels == 1 || num_channels == 2);
90
91 StereoBuffer16 ret(sample_count);
92
93 if (num_channels == 1) {
94 for (size_t i = 0; i < sample_count; i++) {
95 ret[i].fill(SignExtendS8(data[i]));
96 }
97 } else {
98 for (size_t i = 0; i < sample_count; i++) {
99 ret[i][0] = SignExtendS8(data[i * 2 + 0]);
100 ret[i][1] = SignExtendS8(data[i * 2 + 1]);
101 }
102 }
103
104 return ret;
105}
106
107StereoBuffer16 DecodePCM16(const unsigned num_channels, const u8* const data,
108 const size_t sample_count) {
109 ASSERT(num_channels == 1 || num_channels == 2);
110
111 StereoBuffer16 ret(sample_count);
112
113 if (num_channels == 1) {
114 for (size_t i = 0; i < sample_count; i++) {
115 s16 sample;
116 std::memcpy(&sample, data + i * sizeof(s16), sizeof(s16));
117 ret[i].fill(sample);
118 }
119 } else {
120 for (size_t i = 0; i < sample_count; ++i) {
121 std::memcpy(&ret[i], data + i * sizeof(s16) * 2, 2 * sizeof(s16));
122 }
123 }
124
125 return ret;
126}
127};
diff --git a/src/audio_core/codec.h b/src/audio_core/codec.h
deleted file mode 100644
index 877b2202d..000000000
--- a/src/audio_core/codec.h
+++ /dev/null
@@ -1,51 +0,0 @@
1// Copyright 2016 Citra Emulator Project
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#pragma once
6
7#include <array>
8#include <deque>
9#include "common/common_types.h"
10
11namespace Codec {
12
13/// A variable length buffer of signed PCM16 stereo samples.
14using StereoBuffer16 = std::deque<std::array<s16, 2>>;
15
16/// See: Codec::DecodeADPCM
17struct ADPCMState {
18 // Two historical samples from previous processed buffer,
19 // required for ADPCM decoding
20 s16 yn1; ///< y[n-1]
21 s16 yn2; ///< y[n-2]
22};
23
24/**
25 * @param data Pointer to buffer that contains ADPCM data to decode
26 * @param sample_count Length of buffer in terms of number of samples
27 * @param adpcm_coeff ADPCM coefficients
28 * @param state ADPCM state, this is updated with new state
29 * @return Decoded stereo signed PCM16 data, sample_count in length
30 */
31StereoBuffer16 DecodeADPCM(const u8* const data, const size_t sample_count,
32 const std::array<s16, 16>& adpcm_coeff, ADPCMState& state);
33
34/**
35 * @param num_channels Number of channels
36 * @param data Pointer to buffer that contains PCM8 data to decode
37 * @param sample_count Length of buffer in terms of number of samples
38 * @return Decoded stereo signed PCM16 data, sample_count in length
39 */
40StereoBuffer16 DecodePCM8(const unsigned num_channels, const u8* const data,
41 const size_t sample_count);
42
43/**
44 * @param num_channels Number of channels
45 * @param data Pointer to buffer that contains PCM16 data to decode
46 * @param sample_count Length of buffer in terms of number of samples
47 * @return Decoded stereo signed PCM16 data, sample_count in length
48 */
49StereoBuffer16 DecodePCM16(const unsigned num_channels, const u8* const data,
50 const size_t sample_count);
51};
diff --git a/src/audio_core/hle/common.h b/src/audio_core/hle/common.h
deleted file mode 100644
index 7fbc3ad9a..000000000
--- a/src/audio_core/hle/common.h
+++ /dev/null
@@ -1,34 +0,0 @@
1// Copyright 2016 Citra Emulator Project
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#pragma once
6
7#include <algorithm>
8#include <array>
9#include "common/common_types.h"
10
11namespace DSP {
12namespace HLE {
13
14constexpr int num_sources = 24;
15constexpr int samples_per_frame = 160; ///< Samples per audio frame at native sample rate
16
17/// The final output to the speakers is stereo. Preprocessing output in Source is also stereo.
18using StereoFrame16 = std::array<std::array<s16, 2>, samples_per_frame>;
19
20/// The DSP is quadraphonic internally.
21using QuadFrame32 = std::array<std::array<s32, 4>, samples_per_frame>;
22
23/**
24 * This performs the filter operation defined by FilterT::ProcessSample on the frame in-place.
25 * FilterT::ProcessSample is called sequentially on the samples.
26 */
27template <typename FrameT, typename FilterT>
28void FilterFrame(FrameT& frame, FilterT& filter) {
29 std::transform(frame.begin(), frame.end(), frame.begin(),
30 [&filter](const auto& sample) { return filter.ProcessSample(sample); });
31}
32
33} // namespace HLE
34} // namespace DSP
diff --git a/src/audio_core/hle/dsp.cpp b/src/audio_core/hle/dsp.cpp
deleted file mode 100644
index 260b182ed..000000000
--- a/src/audio_core/hle/dsp.cpp
+++ /dev/null
@@ -1,172 +0,0 @@
1// Copyright 2016 Citra Emulator Project
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#include <array>
6#include <memory>
7#include "audio_core/hle/dsp.h"
8#include "audio_core/hle/mixers.h"
9#include "audio_core/hle/pipe.h"
10#include "audio_core/hle/source.h"
11#include "audio_core/sink.h"
12#include "audio_core/time_stretch.h"
13
14namespace DSP {
15namespace HLE {
16
17// Region management
18
19DspMemory g_dsp_memory;
20
21static size_t CurrentRegionIndex() {
22 // The region with the higher frame counter is chosen unless there is wraparound.
23 // This function only returns a 0 or 1.
24 u16 frame_counter_0 = g_dsp_memory.region_0.frame_counter;
25 u16 frame_counter_1 = g_dsp_memory.region_1.frame_counter;
26
27 if (frame_counter_0 == 0xFFFFu && frame_counter_1 != 0xFFFEu) {
28 // Wraparound has occurred.
29 return 1;
30 }
31
32 if (frame_counter_1 == 0xFFFFu && frame_counter_0 != 0xFFFEu) {
33 // Wraparound has occurred.
34 return 0;
35 }
36
37 return (frame_counter_0 > frame_counter_1) ? 0 : 1;
38}
39
40static SharedMemory& ReadRegion() {
41 return CurrentRegionIndex() == 0 ? g_dsp_memory.region_0 : g_dsp_memory.region_1;
42}
43
44static SharedMemory& WriteRegion() {
45 return CurrentRegionIndex() != 0 ? g_dsp_memory.region_0 : g_dsp_memory.region_1;
46}
47
48// Audio processing and mixing
49
50static std::array<Source, num_sources> sources = {
51 Source(0), Source(1), Source(2), Source(3), Source(4), Source(5), Source(6), Source(7),
52 Source(8), Source(9), Source(10), Source(11), Source(12), Source(13), Source(14), Source(15),
53 Source(16), Source(17), Source(18), Source(19), Source(20), Source(21), Source(22), Source(23),
54};
55static Mixers mixers;
56
57static StereoFrame16 GenerateCurrentFrame() {
58 SharedMemory& read = ReadRegion();
59 SharedMemory& write = WriteRegion();
60
61 std::array<QuadFrame32, 3> intermediate_mixes = {};
62
63 // Generate intermediate mixes
64 for (size_t i = 0; i < num_sources; i++) {
65 write.source_statuses.status[i] =
66 sources[i].Tick(read.source_configurations.config[i], read.adpcm_coefficients.coeff[i]);
67 for (size_t mix = 0; mix < 3; mix++) {
68 sources[i].MixInto(intermediate_mixes[mix], mix);
69 }
70 }
71
72 // Generate final mix
73 write.dsp_status = mixers.Tick(read.dsp_configuration, read.intermediate_mix_samples,
74 write.intermediate_mix_samples, intermediate_mixes);
75
76 StereoFrame16 output_frame = mixers.GetOutput();
77
78 // Write current output frame to the shared memory region
79 for (size_t samplei = 0; samplei < output_frame.size(); samplei++) {
80 for (size_t channeli = 0; channeli < output_frame[0].size(); channeli++) {
81 write.final_samples.pcm16[samplei][channeli] = s16_le(output_frame[samplei][channeli]);
82 }
83 }
84
85 return output_frame;
86}
87
88// Audio output
89
90static bool perform_time_stretching = true;
91static std::unique_ptr<AudioCore::Sink> sink;
92static AudioCore::TimeStretcher time_stretcher;
93
94static void FlushResidualStretcherAudio() {
95 time_stretcher.Flush();
96 while (true) {
97 std::vector<s16> residual_audio = time_stretcher.Process(sink->SamplesInQueue());
98 if (residual_audio.empty())
99 break;
100 sink->EnqueueSamples(residual_audio.data(), residual_audio.size() / 2);
101 }
102}
103
104static void OutputCurrentFrame(const StereoFrame16& frame) {
105 if (perform_time_stretching) {
106 time_stretcher.AddSamples(&frame[0][0], frame.size());
107 std::vector<s16> stretched_samples = time_stretcher.Process(sink->SamplesInQueue());
108 sink->EnqueueSamples(stretched_samples.data(), stretched_samples.size() / 2);
109 } else {
110 constexpr size_t maximum_sample_latency = 2048; // about 64 miliseconds
111 if (sink->SamplesInQueue() > maximum_sample_latency) {
112 // This can occur if we're running too fast and samples are starting to back up.
113 // Just drop the samples.
114 return;
115 }
116
117 sink->EnqueueSamples(&frame[0][0], frame.size());
118 }
119}
120
121void EnableStretching(bool enable) {
122 if (perform_time_stretching == enable)
123 return;
124
125 if (!enable) {
126 FlushResidualStretcherAudio();
127 }
128 perform_time_stretching = enable;
129}
130
131// Public Interface
132
133void Init() {
134 DSP::HLE::ResetPipes();
135
136 for (auto& source : sources) {
137 source.Reset();
138 }
139
140 mixers.Reset();
141
142 time_stretcher.Reset();
143 if (sink) {
144 time_stretcher.SetOutputSampleRate(sink->GetNativeSampleRate());
145 }
146}
147
148void Shutdown() {
149 if (perform_time_stretching) {
150 FlushResidualStretcherAudio();
151 }
152}
153
154bool Tick() {
155 StereoFrame16 current_frame = {};
156
157 // TODO: Check dsp::DSP semaphore (which indicates emulated application has finished writing to
158 // shared memory region)
159 current_frame = GenerateCurrentFrame();
160
161 OutputCurrentFrame(current_frame);
162
163 return true;
164}
165
166void SetSink(std::unique_ptr<AudioCore::Sink> sink_) {
167 sink = std::move(sink_);
168 time_stretcher.SetOutputSampleRate(sink->GetNativeSampleRate());
169}
170
171} // namespace HLE
172} // namespace DSP
diff --git a/src/audio_core/hle/dsp.h b/src/audio_core/hle/dsp.h
deleted file mode 100644
index 94ce48863..000000000
--- a/src/audio_core/hle/dsp.h
+++ /dev/null
@@ -1,595 +0,0 @@
1// Copyright 2016 Citra Emulator Project
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#pragma once
6
7#include <array>
8#include <cstddef>
9#include <memory>
10#include <type_traits>
11#include "audio_core/hle/common.h"
12#include "common/bit_field.h"
13#include "common/common_funcs.h"
14#include "common/common_types.h"
15#include "common/swap.h"
16
17namespace AudioCore {
18class Sink;
19}
20
21namespace DSP {
22namespace HLE {
23
24// The application-accessible region of DSP memory consists of two parts. Both are marked as IO and
25// have Read/Write permissions.
26//
27// First Region: 0x1FF50000 (Size: 0x8000)
28// Second Region: 0x1FF70000 (Size: 0x8000)
29//
30// The DSP reads from each region alternately based on the frame counter for each region much like a
31// double-buffer. The frame counter is located as the very last u16 of each region and is
32// incremented each audio tick.
33
34constexpr u32 region0_offset = 0x50000;
35constexpr u32 region1_offset = 0x70000;
36
37/**
38 * The DSP is native 16-bit. The DSP also appears to be big-endian. When reading 32-bit numbers from
39 * its memory regions, the higher and lower 16-bit halves are swapped compared to the little-endian
40 * layout of the ARM11. Hence from the ARM11's point of view the memory space appears to be
41 * middle-endian.
42 *
43 * Unusually this does not appear to be an issue for floating point numbers. The DSP makes the more
44 * sensible choice of keeping that little-endian. There are also some exceptions such as the
45 * IntermediateMixSamples structure, which is little-endian.
46 *
47 * This struct implements the conversion to and from this middle-endianness.
48 */
49struct u32_dsp {
50 u32_dsp() = default;
51 operator u32() const {
52 return Convert(storage);
53 }
54 void operator=(u32 new_value) {
55 storage = Convert(new_value);
56 }
57
58private:
59 static constexpr u32 Convert(u32 value) {
60 return (value << 16) | (value >> 16);
61 }
62 u32_le storage;
63};
64#if (__GNUC__ >= 5) || defined(__clang__) || defined(_MSC_VER)
65static_assert(std::is_trivially_copyable<u32_dsp>::value, "u32_dsp isn't trivially copyable");
66#endif
67
68// There are 15 structures in each memory region. A table of them in the order they appear in memory
69// is presented below:
70//
71// # First Region DSP Address Purpose Control
72// 5 0x8400 DSP Status DSP
73// 9 0x8410 DSP Debug Info DSP
74// 6 0x8540 Final Mix Samples DSP
75// 2 0x8680 Source Status [24] DSP
76// 8 0x8710 Compressor Table Application
77// 4 0x9430 DSP Configuration Application
78// 7 0x9492 Intermediate Mix Samples DSP + App
79// 1 0x9E92 Source Configuration [24] Application
80// 3 0xA792 Source ADPCM Coefficients [24] Application
81// 10 0xA912 Surround Sound Related
82// 11 0xAA12 Surround Sound Related
83// 12 0xAAD2 Surround Sound Related
84// 13 0xAC52 Surround Sound Related
85// 14 0xAC5C Surround Sound Related
86// 0 0xBFFF Frame Counter Application
87//
88// #: This refers to the order in which they appear in the DspPipe::Audio DSP pipe.
89// See also: DSP::HLE::PipeRead.
90//
91// Note that the above addresses do vary slightly between audio firmwares observed; the addresses
92// are not fixed in stone. The addresses above are only an examplar; they're what this
93// implementation does and provides to applications.
94//
95// Application requests the DSP service to convert DSP addresses into ARM11 virtual addresses using
96// the ConvertProcessAddressFromDspDram service call. Applications seem to derive the addresses for
97// the second region via:
98// second_region_dsp_addr = first_region_dsp_addr | 0x10000
99//
100// Applications maintain most of its own audio state, the memory region is used mainly for
101// communication and not storage of state.
102//
103// In the documentation below, filter and effect transfer functions are specified in the z domain.
104// (If you are more familiar with the Laplace transform, z = exp(sT). The z domain is the digital
105// frequency domain, just like how the s domain is the analog frequency domain.)
106
107#define INSERT_PADDING_DSPWORDS(num_words) INSERT_PADDING_BYTES(2 * (num_words))
108
109// GCC versions < 5.0 do not implement std::is_trivially_copyable.
110// Excluding MSVC because it has weird behaviour for std::is_trivially_copyable.
111#if (__GNUC__ >= 5) || defined(__clang__)
112#define ASSERT_DSP_STRUCT(name, size) \
113 static_assert(std::is_standard_layout<name>::value, \
114 "DSP structure " #name " doesn't use standard layout"); \
115 static_assert(std::is_trivially_copyable<name>::value, \
116 "DSP structure " #name " isn't trivially copyable"); \
117 static_assert(sizeof(name) == (size), "Unexpected struct size for DSP structure " #name)
118#else
119#define ASSERT_DSP_STRUCT(name, size) \
120 static_assert(std::is_standard_layout<name>::value, \
121 "DSP structure " #name " doesn't use standard layout"); \
122 static_assert(sizeof(name) == (size), "Unexpected struct size for DSP structure " #name)
123#endif
124
125struct SourceConfiguration {
126 struct Configuration {
127 /// These dirty flags are set by the application when it updates the fields in this struct.
128 /// The DSP clears these each audio frame.
129 union {
130 u32_le dirty_raw;
131
132 BitField<0, 1, u32_le> format_dirty;
133 BitField<1, 1, u32_le> mono_or_stereo_dirty;
134 BitField<2, 1, u32_le> adpcm_coefficients_dirty;
135 /// Tends to be set when a looped buffer is queued.
136 BitField<3, 1, u32_le> partial_embedded_buffer_dirty;
137 BitField<4, 1, u32_le> partial_reset_flag;
138
139 BitField<16, 1, u32_le> enable_dirty;
140 BitField<17, 1, u32_le> interpolation_dirty;
141 BitField<18, 1, u32_le> rate_multiplier_dirty;
142 BitField<19, 1, u32_le> buffer_queue_dirty;
143 BitField<20, 1, u32_le> loop_related_dirty;
144 /// Tends to also be set when embedded buffer is updated.
145 BitField<21, 1, u32_le> play_position_dirty;
146 BitField<22, 1, u32_le> filters_enabled_dirty;
147 BitField<23, 1, u32_le> simple_filter_dirty;
148 BitField<24, 1, u32_le> biquad_filter_dirty;
149 BitField<25, 1, u32_le> gain_0_dirty;
150 BitField<26, 1, u32_le> gain_1_dirty;
151 BitField<27, 1, u32_le> gain_2_dirty;
152 BitField<28, 1, u32_le> sync_dirty;
153 BitField<29, 1, u32_le> reset_flag;
154 BitField<30, 1, u32_le> embedded_buffer_dirty;
155 };
156
157 // Gain control
158
159 /**
160 * Gain is between 0.0-1.0. This determines how much will this source appear on each of the
161 * 12 channels that feed into the intermediate mixers. Each of the three intermediate mixers
162 * is fed two left and two right channels.
163 */
164 float_le gain[3][4];
165
166 // Interpolation
167
168 /// Multiplier for sample rate. Resampling occurs with the selected interpolation method.
169 float_le rate_multiplier;
170
171 enum class InterpolationMode : u8 {
172 Polyphase = 0,
173 Linear = 1,
174 None = 2,
175 };
176
177 InterpolationMode interpolation_mode;
178 INSERT_PADDING_BYTES(1); ///< Interpolation related
179
180 // Filters
181
182 /**
183 * This is the simplest normalized first-order digital recursive filter.
184 * The transfer function of this filter is:
185 * H(z) = b0 / (1 - a1 z^-1)
186 * Note the feedbackward coefficient is negated.
187 * Values are signed fixed point with 15 fractional bits.
188 */
189 struct SimpleFilter {
190 s16_le b0;
191 s16_le a1;
192 };
193
194 /**
195 * This is a normalised biquad filter (second-order).
196 * The transfer function of this filter is:
197 * H(z) = (b0 + b1 z^-1 + b2 z^-2) / (1 - a1 z^-1 - a2 z^-2)
198 * Nintendo chose to negate the feedbackward coefficients. This differs from standard
199 * notation as in: https://ccrma.stanford.edu/~jos/filters/Direct_Form_I.html
200 * Values are signed fixed point with 14 fractional bits.
201 */
202 struct BiquadFilter {
203 s16_le a2;
204 s16_le a1;
205 s16_le b2;
206 s16_le b1;
207 s16_le b0;
208 };
209
210 union {
211 u16_le filters_enabled;
212 BitField<0, 1, u16_le> simple_filter_enabled;
213 BitField<1, 1, u16_le> biquad_filter_enabled;
214 };
215
216 SimpleFilter simple_filter;
217 BiquadFilter biquad_filter;
218
219 // Buffer Queue
220
221 /// A buffer of audio data from the application, along with metadata about it.
222 struct Buffer {
223 /// Physical memory address of the start of the buffer
224 u32_dsp physical_address;
225
226 /// This is length in terms of samples.
227 /// Note that in different buffer formats a sample takes up different number of bytes.
228 u32_dsp length;
229
230 /// ADPCM Predictor (4 bits) and Scale (4 bits)
231 union {
232 u16_le adpcm_ps;
233 BitField<0, 4, u16_le> adpcm_scale;
234 BitField<4, 4, u16_le> adpcm_predictor;
235 };
236
237 /// ADPCM Historical Samples (y[n-1] and y[n-2])
238 u16_le adpcm_yn[2];
239
240 /// This is non-zero when the ADPCM values above are to be updated.
241 u8 adpcm_dirty;
242
243 /// Is a looping buffer.
244 u8 is_looping;
245
246 /// This value is shown in SourceStatus::previous_buffer_id when this buffer has
247 /// finished. This allows the emulated application to tell what buffer is currently
248 /// playing.
249 u16_le buffer_id;
250
251 INSERT_PADDING_DSPWORDS(1);
252 };
253
254 u16_le buffers_dirty; ///< Bitmap indicating which buffers are dirty (bit i -> buffers[i])
255 Buffer buffers[4]; ///< Queued Buffers
256
257 // Playback controls
258
259 u32_dsp loop_related;
260 u8 enable;
261 INSERT_PADDING_BYTES(1);
262 u16_le sync; ///< Application-side sync (See also: SourceStatus::sync)
263 u32_dsp play_position; ///< Position. (Units: number of samples)
264 INSERT_PADDING_DSPWORDS(2);
265
266 // Embedded Buffer
267 // This buffer is often the first buffer to be used when initiating audio playback,
268 // after which the buffer queue is used.
269
270 u32_dsp physical_address;
271
272 /// This is length in terms of samples.
273 /// Note a sample takes up different number of bytes in different buffer formats.
274 u32_dsp length;
275
276 enum class MonoOrStereo : u16_le {
277 Mono = 1,
278 Stereo = 2,
279 };
280
281 enum class Format : u16_le {
282 PCM8 = 0,
283 PCM16 = 1,
284 ADPCM = 2,
285 };
286
287 union {
288 u16_le flags1_raw;
289 BitField<0, 2, MonoOrStereo> mono_or_stereo;
290 BitField<2, 2, Format> format;
291 BitField<5, 1, u16_le> fade_in;
292 };
293
294 /// ADPCM Predictor (4 bit) and Scale (4 bit)
295 union {
296 u16_le adpcm_ps;
297 BitField<0, 4, u16_le> adpcm_scale;
298 BitField<4, 4, u16_le> adpcm_predictor;
299 };
300
301 /// ADPCM Historical Samples (y[n-1] and y[n-2])
302 u16_le adpcm_yn[2];
303
304 union {
305 u16_le flags2_raw;
306 BitField<0, 1, u16_le> adpcm_dirty; ///< Has the ADPCM info above been changed?
307 BitField<1, 1, u16_le> is_looping; ///< Is this a looping buffer?
308 };
309
310 /// Buffer id of embedded buffer (used as a buffer id in SourceStatus to reference this
311 /// buffer).
312 u16_le buffer_id;
313 };
314
315 Configuration config[num_sources];
316};
317ASSERT_DSP_STRUCT(SourceConfiguration::Configuration, 192);
318ASSERT_DSP_STRUCT(SourceConfiguration::Configuration::Buffer, 20);
319
320struct SourceStatus {
321 struct Status {
322 u8 is_enabled; ///< Is this channel enabled? (Doesn't have to be playing anything.)
323 u8 current_buffer_id_dirty; ///< Non-zero when current_buffer_id changes
324 u16_le sync; ///< Is set by the DSP to the value of SourceConfiguration::sync
325 u32_dsp buffer_position; ///< Number of samples into the current buffer
326 u16_le current_buffer_id; ///< Updated when a buffer finishes playing
327 INSERT_PADDING_DSPWORDS(1);
328 };
329
330 Status status[num_sources];
331};
332ASSERT_DSP_STRUCT(SourceStatus::Status, 12);
333
334struct DspConfiguration {
335 /// These dirty flags are set by the application when it updates the fields in this struct.
336 /// The DSP clears these each audio frame.
337 union {
338 u32_le dirty_raw;
339
340 BitField<8, 1, u32_le> mixer1_enabled_dirty;
341 BitField<9, 1, u32_le> mixer2_enabled_dirty;
342 BitField<10, 1, u32_le> delay_effect_0_dirty;
343 BitField<11, 1, u32_le> delay_effect_1_dirty;
344 BitField<12, 1, u32_le> reverb_effect_0_dirty;
345 BitField<13, 1, u32_le> reverb_effect_1_dirty;
346
347 BitField<16, 1, u32_le> volume_0_dirty;
348
349 BitField<24, 1, u32_le> volume_1_dirty;
350 BitField<25, 1, u32_le> volume_2_dirty;
351 BitField<26, 1, u32_le> output_format_dirty;
352 BitField<27, 1, u32_le> limiter_enabled_dirty;
353 BitField<28, 1, u32_le> headphones_connected_dirty;
354 };
355
356 /// The DSP has three intermediate audio mixers. This controls the volume level (0.0-1.0) for
357 /// each at the final mixer.
358 float_le volume[3];
359
360 INSERT_PADDING_DSPWORDS(3);
361
362 enum class OutputFormat : u16_le {
363 Mono = 0,
364 Stereo = 1,
365 Surround = 2,
366 };
367
368 OutputFormat output_format;
369
370 u16_le limiter_enabled; ///< Not sure of the exact gain equation for the limiter.
371 u16_le headphones_connected; ///< Application updates the DSP on headphone status.
372 INSERT_PADDING_DSPWORDS(4); ///< TODO: Surround sound related
373 INSERT_PADDING_DSPWORDS(2); ///< TODO: Intermediate mixer 1/2 related
374 u16_le mixer1_enabled;
375 u16_le mixer2_enabled;
376
377 /**
378 * This is delay with feedback.
379 * Transfer function:
380 * H(z) = a z^-N / (1 - b z^-1 + a g z^-N)
381 * where
382 * N = frame_count * samples_per_frame
383 * g, a and b are fixed point with 7 fractional bits
384 */
385 struct DelayEffect {
386 /// These dirty flags are set by the application when it updates the fields in this struct.
387 /// The DSP clears these each audio frame.
388 union {
389 u16_le dirty_raw;
390 BitField<0, 1, u16_le> enable_dirty;
391 BitField<1, 1, u16_le> work_buffer_address_dirty;
392 BitField<2, 1, u16_le> other_dirty; ///< Set when anything else has been changed
393 };
394
395 u16_le enable;
396 INSERT_PADDING_DSPWORDS(1);
397 u16_le outputs;
398 /// The application allocates a block of memory for the DSP to use as a work buffer.
399 u32_dsp work_buffer_address;
400 /// Frames to delay by
401 u16_le frame_count;
402
403 // Coefficients
404 s16_le g; ///< Fixed point with 7 fractional bits
405 s16_le a; ///< Fixed point with 7 fractional bits
406 s16_le b; ///< Fixed point with 7 fractional bits
407 };
408
409 DelayEffect delay_effect[2];
410
411 struct ReverbEffect {
412 INSERT_PADDING_DSPWORDS(26); ///< TODO
413 };
414
415 ReverbEffect reverb_effect[2];
416
417 INSERT_PADDING_DSPWORDS(4);
418};
419ASSERT_DSP_STRUCT(DspConfiguration, 196);
420ASSERT_DSP_STRUCT(DspConfiguration::DelayEffect, 20);
421ASSERT_DSP_STRUCT(DspConfiguration::ReverbEffect, 52);
422
423struct AdpcmCoefficients {
424 /// Coefficients are signed fixed point with 11 fractional bits.
425 /// Each source has 16 coefficients associated with it.
426 s16_le coeff[num_sources][16];
427};
428ASSERT_DSP_STRUCT(AdpcmCoefficients, 768);
429
430struct DspStatus {
431 u16_le unknown;
432 u16_le dropped_frames;
433 INSERT_PADDING_DSPWORDS(0xE);
434};
435ASSERT_DSP_STRUCT(DspStatus, 32);
436
437/// Final mixed output in PCM16 stereo format, what you hear out of the speakers.
438/// When the application writes to this region it has no effect.
439struct FinalMixSamples {
440 s16_le pcm16[samples_per_frame][2];
441};
442ASSERT_DSP_STRUCT(FinalMixSamples, 640);
443
444/// DSP writes output of intermediate mixers 1 and 2 here.
445/// Writes to this region by the application edits the output of the intermediate mixers.
446/// This seems to be intended to allow the application to do custom effects on the ARM11.
447/// Values that exceed s16 range will be clipped by the DSP after further processing.
448struct IntermediateMixSamples {
449 struct Samples {
450 s32_le pcm32[4][samples_per_frame]; ///< Little-endian as opposed to DSP middle-endian.
451 };
452
453 Samples mix1;
454 Samples mix2;
455};
456ASSERT_DSP_STRUCT(IntermediateMixSamples, 5120);
457
458/// Compressor table
459struct Compressor {
460 INSERT_PADDING_DSPWORDS(0xD20); ///< TODO
461};
462
463/// There is no easy way to implement this in a HLE implementation.
464struct DspDebug {
465 INSERT_PADDING_DSPWORDS(0x130);
466};
467ASSERT_DSP_STRUCT(DspDebug, 0x260);
468
469struct SharedMemory {
470 /// Padding
471 INSERT_PADDING_DSPWORDS(0x400);
472
473 DspStatus dsp_status;
474
475 DspDebug dsp_debug;
476
477 FinalMixSamples final_samples;
478
479 SourceStatus source_statuses;
480
481 Compressor compressor;
482
483 DspConfiguration dsp_configuration;
484
485 IntermediateMixSamples intermediate_mix_samples;
486
487 SourceConfiguration source_configurations;
488
489 AdpcmCoefficients adpcm_coefficients;
490
491 struct {
492 INSERT_PADDING_DSPWORDS(0x100);
493 } unknown10;
494
495 struct {
496 INSERT_PADDING_DSPWORDS(0xC0);
497 } unknown11;
498
499 struct {
500 INSERT_PADDING_DSPWORDS(0x180);
501 } unknown12;
502
503 struct {
504 INSERT_PADDING_DSPWORDS(0xA);
505 } unknown13;
506
507 struct {
508 INSERT_PADDING_DSPWORDS(0x13A3);
509 } unknown14;
510
511 u16_le frame_counter;
512};
513ASSERT_DSP_STRUCT(SharedMemory, 0x8000);
514
515union DspMemory {
516 std::array<u8, 0x80000> raw_memory;
517 struct {
518 u8 unused_0[0x50000];
519 SharedMemory region_0;
520 u8 unused_1[0x18000];
521 SharedMemory region_1;
522 u8 unused_2[0x8000];
523 };
524};
525static_assert(offsetof(DspMemory, region_0) == region0_offset,
526 "DSP region 0 is at the wrong offset");
527static_assert(offsetof(DspMemory, region_1) == region1_offset,
528 "DSP region 1 is at the wrong offset");
529
530extern DspMemory g_dsp_memory;
531
532// Structures must have an offset that is a multiple of two.
533static_assert(offsetof(SharedMemory, frame_counter) % 2 == 0,
534 "Structures in DSP::HLE::SharedMemory must be 2-byte aligned");
535static_assert(offsetof(SharedMemory, source_configurations) % 2 == 0,
536 "Structures in DSP::HLE::SharedMemory must be 2-byte aligned");
537static_assert(offsetof(SharedMemory, source_statuses) % 2 == 0,
538 "Structures in DSP::HLE::SharedMemory must be 2-byte aligned");
539static_assert(offsetof(SharedMemory, adpcm_coefficients) % 2 == 0,
540 "Structures in DSP::HLE::SharedMemory must be 2-byte aligned");
541static_assert(offsetof(SharedMemory, dsp_configuration) % 2 == 0,
542 "Structures in DSP::HLE::SharedMemory must be 2-byte aligned");
543static_assert(offsetof(SharedMemory, dsp_status) % 2 == 0,
544 "Structures in DSP::HLE::SharedMemory must be 2-byte aligned");
545static_assert(offsetof(SharedMemory, final_samples) % 2 == 0,
546 "Structures in DSP::HLE::SharedMemory must be 2-byte aligned");
547static_assert(offsetof(SharedMemory, intermediate_mix_samples) % 2 == 0,
548 "Structures in DSP::HLE::SharedMemory must be 2-byte aligned");
549static_assert(offsetof(SharedMemory, compressor) % 2 == 0,
550 "Structures in DSP::HLE::SharedMemory must be 2-byte aligned");
551static_assert(offsetof(SharedMemory, dsp_debug) % 2 == 0,
552 "Structures in DSP::HLE::SharedMemory must be 2-byte aligned");
553static_assert(offsetof(SharedMemory, unknown10) % 2 == 0,
554 "Structures in DSP::HLE::SharedMemory must be 2-byte aligned");
555static_assert(offsetof(SharedMemory, unknown11) % 2 == 0,
556 "Structures in DSP::HLE::SharedMemory must be 2-byte aligned");
557static_assert(offsetof(SharedMemory, unknown12) % 2 == 0,
558 "Structures in DSP::HLE::SharedMemory must be 2-byte aligned");
559static_assert(offsetof(SharedMemory, unknown13) % 2 == 0,
560 "Structures in DSP::HLE::SharedMemory must be 2-byte aligned");
561static_assert(offsetof(SharedMemory, unknown14) % 2 == 0,
562 "Structures in DSP::HLE::SharedMemory must be 2-byte aligned");
563
564#undef INSERT_PADDING_DSPWORDS
565#undef ASSERT_DSP_STRUCT
566
567/// Initialize DSP hardware
568void Init();
569
570/// Shutdown DSP hardware
571void Shutdown();
572
573/**
574 * Perform processing and updates state of current shared memory buffer.
575 * This function is called every audio tick before triggering the audio interrupt.
576 * @return Whether an audio interrupt should be triggered this frame.
577 */
578bool Tick();
579
580/**
581 * Set the output sink. This must be called before calling Tick().
582 * @param sink The sink to which audio will be output to.
583 */
584void SetSink(std::unique_ptr<AudioCore::Sink> sink);
585
586/**
587 * Enables/Disables audio-stretching.
588 * Audio stretching is an enhancement that stretches audio to match emulation
589 * speed to prevent stuttering at the cost of some audio latency.
590 * @param enable true to enable, false to disable.
591 */
592void EnableStretching(bool enable);
593
594} // namespace HLE
595} // namespace DSP
diff --git a/src/audio_core/hle/filter.cpp b/src/audio_core/hle/filter.cpp
deleted file mode 100644
index b24a79b89..000000000
--- a/src/audio_core/hle/filter.cpp
+++ /dev/null
@@ -1,117 +0,0 @@
1// Copyright 2016 Citra Emulator Project
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#include <array>
6#include <cstddef>
7#include "audio_core/hle/common.h"
8#include "audio_core/hle/dsp.h"
9#include "audio_core/hle/filter.h"
10#include "common/common_types.h"
11#include "common/math_util.h"
12
13namespace DSP {
14namespace HLE {
15
16void SourceFilters::Reset() {
17 Enable(false, false);
18}
19
20void SourceFilters::Enable(bool simple, bool biquad) {
21 simple_filter_enabled = simple;
22 biquad_filter_enabled = biquad;
23
24 if (!simple)
25 simple_filter.Reset();
26 if (!biquad)
27 biquad_filter.Reset();
28}
29
30void SourceFilters::Configure(SourceConfiguration::Configuration::SimpleFilter config) {
31 simple_filter.Configure(config);
32}
33
34void SourceFilters::Configure(SourceConfiguration::Configuration::BiquadFilter config) {
35 biquad_filter.Configure(config);
36}
37
38void SourceFilters::ProcessFrame(StereoFrame16& frame) {
39 if (!simple_filter_enabled && !biquad_filter_enabled)
40 return;
41
42 if (simple_filter_enabled) {
43 FilterFrame(frame, simple_filter);
44 }
45
46 if (biquad_filter_enabled) {
47 FilterFrame(frame, biquad_filter);
48 }
49}
50
51// SimpleFilter
52
53void SourceFilters::SimpleFilter::Reset() {
54 y1.fill(0);
55 // Configure as passthrough.
56 a1 = 0;
57 b0 = 1 << 15;
58}
59
60void SourceFilters::SimpleFilter::Configure(
61 SourceConfiguration::Configuration::SimpleFilter config) {
62
63 a1 = config.a1;
64 b0 = config.b0;
65}
66
67std::array<s16, 2> SourceFilters::SimpleFilter::ProcessSample(const std::array<s16, 2>& x0) {
68 std::array<s16, 2> y0;
69 for (size_t i = 0; i < 2; i++) {
70 const s32 tmp = (b0 * x0[i] + a1 * y1[i]) >> 15;
71 y0[i] = MathUtil::Clamp(tmp, -32768, 32767);
72 }
73
74 y1 = y0;
75
76 return y0;
77}
78
79// BiquadFilter
80
81void SourceFilters::BiquadFilter::Reset() {
82 x1.fill(0);
83 x2.fill(0);
84 y1.fill(0);
85 y2.fill(0);
86 // Configure as passthrough.
87 a1 = a2 = b1 = b2 = 0;
88 b0 = 1 << 14;
89}
90
91void SourceFilters::BiquadFilter::Configure(
92 SourceConfiguration::Configuration::BiquadFilter config) {
93
94 a1 = config.a1;
95 a2 = config.a2;
96 b0 = config.b0;
97 b1 = config.b1;
98 b2 = config.b2;
99}
100
101std::array<s16, 2> SourceFilters::BiquadFilter::ProcessSample(const std::array<s16, 2>& x0) {
102 std::array<s16, 2> y0;
103 for (size_t i = 0; i < 2; i++) {
104 const s32 tmp = (b0 * x0[i] + b1 * x1[i] + b2 * x2[i] + a1 * y1[i] + a2 * y2[i]) >> 14;
105 y0[i] = MathUtil::Clamp(tmp, -32768, 32767);
106 }
107
108 x2 = x1;
109 x1 = x0;
110 y2 = y1;
111 y1 = y0;
112
113 return y0;
114}
115
116} // namespace HLE
117} // namespace DSP
diff --git a/src/audio_core/hle/filter.h b/src/audio_core/hle/filter.h
deleted file mode 100644
index 5350e2857..000000000
--- a/src/audio_core/hle/filter.h
+++ /dev/null
@@ -1,117 +0,0 @@
1// Copyright 2016 Citra Emulator Project
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#pragma once
6
7#include <array>
8#include "audio_core/hle/common.h"
9#include "audio_core/hle/dsp.h"
10#include "common/common_types.h"
11
12namespace DSP {
13namespace HLE {
14
15/// Preprocessing filters. There is an independent set of filters for each Source.
16class SourceFilters final {
17public:
18 SourceFilters() {
19 Reset();
20 }
21
22 /// Reset internal state.
23 void Reset();
24
25 /**
26 * Enable/Disable filters
27 * See also: SourceConfiguration::Configuration::simple_filter_enabled,
28 * SourceConfiguration::Configuration::biquad_filter_enabled.
29 * @param simple If true, enables the simple filter. If false, disables it.
30 * @param biquad If true, enables the biquad filter. If false, disables it.
31 */
32 void Enable(bool simple, bool biquad);
33
34 /**
35 * Configure simple filter.
36 * @param config Configuration from DSP shared memory.
37 */
38 void Configure(SourceConfiguration::Configuration::SimpleFilter config);
39
40 /**
41 * Configure biquad filter.
42 * @param config Configuration from DSP shared memory.
43 */
44 void Configure(SourceConfiguration::Configuration::BiquadFilter config);
45
46 /**
47 * Processes a frame in-place.
48 * @param frame Audio samples to process. Modified in-place.
49 */
50 void ProcessFrame(StereoFrame16& frame);
51
52private:
53 bool simple_filter_enabled;
54 bool biquad_filter_enabled;
55
56 struct SimpleFilter {
57 SimpleFilter() {
58 Reset();
59 }
60
61 /// Resets internal state.
62 void Reset();
63
64 /**
65 * Configures this filter with application settings.
66 * @param config Configuration from DSP shared memory.
67 */
68 void Configure(SourceConfiguration::Configuration::SimpleFilter config);
69
70 /**
71 * Processes a single stereo PCM16 sample.
72 * @param x0 Input sample
73 * @return Output sample
74 */
75 std::array<s16, 2> ProcessSample(const std::array<s16, 2>& x0);
76
77 private:
78 // Configuration
79 s32 a1, b0;
80 // Internal state
81 std::array<s16, 2> y1;
82 } simple_filter;
83
84 struct BiquadFilter {
85 BiquadFilter() {
86 Reset();
87 }
88
89 /// Resets internal state.
90 void Reset();
91
92 /**
93 * Configures this filter with application settings.
94 * @param config Configuration from DSP shared memory.
95 */
96 void Configure(SourceConfiguration::Configuration::BiquadFilter config);
97
98 /**
99 * Processes a single stereo PCM16 sample.
100 * @param x0 Input sample
101 * @return Output sample
102 */
103 std::array<s16, 2> ProcessSample(const std::array<s16, 2>& x0);
104
105 private:
106 // Configuration
107 s32 a1, a2, b0, b1, b2;
108 // Internal state
109 std::array<s16, 2> x1;
110 std::array<s16, 2> x2;
111 std::array<s16, 2> y1;
112 std::array<s16, 2> y2;
113 } biquad_filter;
114};
115
116} // namespace HLE
117} // namespace DSP
diff --git a/src/audio_core/hle/mixers.cpp b/src/audio_core/hle/mixers.cpp
deleted file mode 100644
index 6cc81dfca..000000000
--- a/src/audio_core/hle/mixers.cpp
+++ /dev/null
@@ -1,210 +0,0 @@
1// Copyright 2016 Citra Emulator Project
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#include <cstddef>
6
7#include "audio_core/hle/common.h"
8#include "audio_core/hle/dsp.h"
9#include "audio_core/hle/mixers.h"
10#include "common/assert.h"
11#include "common/logging/log.h"
12#include "common/math_util.h"
13
14namespace DSP {
15namespace HLE {
16
17void Mixers::Reset() {
18 current_frame.fill({});
19 state = {};
20}
21
22DspStatus Mixers::Tick(DspConfiguration& config, const IntermediateMixSamples& read_samples,
23 IntermediateMixSamples& write_samples,
24 const std::array<QuadFrame32, 3>& input) {
25 ParseConfig(config);
26
27 AuxReturn(read_samples);
28 AuxSend(write_samples, input);
29
30 MixCurrentFrame();
31
32 return GetCurrentStatus();
33}
34
35void Mixers::ParseConfig(DspConfiguration& config) {
36 if (!config.dirty_raw) {
37 return;
38 }
39
40 if (config.mixer1_enabled_dirty) {
41 config.mixer1_enabled_dirty.Assign(0);
42 state.mixer1_enabled = config.mixer1_enabled != 0;
43 LOG_TRACE(Audio_DSP, "mixers mixer1_enabled = %hu", config.mixer1_enabled);
44 }
45
46 if (config.mixer2_enabled_dirty) {
47 config.mixer2_enabled_dirty.Assign(0);
48 state.mixer2_enabled = config.mixer2_enabled != 0;
49 LOG_TRACE(Audio_DSP, "mixers mixer2_enabled = %hu", config.mixer2_enabled);
50 }
51
52 if (config.volume_0_dirty) {
53 config.volume_0_dirty.Assign(0);
54 state.intermediate_mixer_volume[0] = config.volume[0];
55 LOG_TRACE(Audio_DSP, "mixers volume[0] = %f", config.volume[0]);
56 }
57
58 if (config.volume_1_dirty) {
59 config.volume_1_dirty.Assign(0);
60 state.intermediate_mixer_volume[1] = config.volume[1];
61 LOG_TRACE(Audio_DSP, "mixers volume[1] = %f", config.volume[1]);
62 }
63
64 if (config.volume_2_dirty) {
65 config.volume_2_dirty.Assign(0);
66 state.intermediate_mixer_volume[2] = config.volume[2];
67 LOG_TRACE(Audio_DSP, "mixers volume[2] = %f", config.volume[2]);
68 }
69
70 if (config.output_format_dirty) {
71 config.output_format_dirty.Assign(0);
72 state.output_format = config.output_format;
73 LOG_TRACE(Audio_DSP, "mixers output_format = %zu",
74 static_cast<size_t>(config.output_format));
75 }
76
77 if (config.headphones_connected_dirty) {
78 config.headphones_connected_dirty.Assign(0);
79 // Do nothing. (Note: Whether headphones are connected does affect coefficients used for
80 // surround sound.)
81 LOG_TRACE(Audio_DSP, "mixers headphones_connected=%hu", config.headphones_connected);
82 }
83
84 if (config.dirty_raw) {
85 LOG_DEBUG(Audio_DSP, "mixers remaining_dirty=%x", config.dirty_raw);
86 }
87
88 config.dirty_raw = 0;
89}
90
91static s16 ClampToS16(s32 value) {
92 return static_cast<s16>(MathUtil::Clamp(value, -32768, 32767));
93}
94
95static std::array<s16, 2> AddAndClampToS16(const std::array<s16, 2>& a,
96 const std::array<s16, 2>& b) {
97 return {ClampToS16(static_cast<s32>(a[0]) + static_cast<s32>(b[0])),
98 ClampToS16(static_cast<s32>(a[1]) + static_cast<s32>(b[1]))};
99}
100
101void Mixers::DownmixAndMixIntoCurrentFrame(float gain, const QuadFrame32& samples) {
102 // TODO(merry): Limiter. (Currently we're performing final mixing assuming a disabled limiter.)
103
104 switch (state.output_format) {
105 case OutputFormat::Mono:
106 std::transform(
107 current_frame.begin(), current_frame.end(), samples.begin(), current_frame.begin(),
108 [gain](const std::array<s16, 2>& accumulator,
109 const std::array<s32, 4>& sample) -> std::array<s16, 2> {
110 // Downmix to mono
111 s16 mono = ClampToS16(static_cast<s32>(
112 (gain * sample[0] + gain * sample[1] + gain * sample[2] + gain * sample[3]) /
113 2));
114 // Mix into current frame
115 return AddAndClampToS16(accumulator, {mono, mono});
116 });
117 return;
118
119 case OutputFormat::Surround:
120 // TODO(merry): Implement surround sound.
121 // fallthrough
122
123 case OutputFormat::Stereo:
124 std::transform(
125 current_frame.begin(), current_frame.end(), samples.begin(), current_frame.begin(),
126 [gain](const std::array<s16, 2>& accumulator,
127 const std::array<s32, 4>& sample) -> std::array<s16, 2> {
128 // Downmix to stereo
129 s16 left = ClampToS16(static_cast<s32>(gain * sample[0] + gain * sample[2]));
130 s16 right = ClampToS16(static_cast<s32>(gain * sample[1] + gain * sample[3]));
131 // Mix into current frame
132 return AddAndClampToS16(accumulator, {left, right});
133 });
134 return;
135 }
136
137 UNREACHABLE_MSG("Invalid output_format %zu", static_cast<size_t>(state.output_format));
138}
139
140void Mixers::AuxReturn(const IntermediateMixSamples& read_samples) {
141 // NOTE: read_samples.mix{1,2}.pcm32 annoyingly have their dimensions in reverse order to
142 // QuadFrame32.
143
144 if (state.mixer1_enabled) {
145 for (size_t sample = 0; sample < samples_per_frame; sample++) {
146 for (size_t channel = 0; channel < 4; channel++) {
147 state.intermediate_mix_buffer[1][sample][channel] =
148 read_samples.mix1.pcm32[channel][sample];
149 }
150 }
151 }
152
153 if (state.mixer2_enabled) {
154 for (size_t sample = 0; sample < samples_per_frame; sample++) {
155 for (size_t channel = 0; channel < 4; channel++) {
156 state.intermediate_mix_buffer[2][sample][channel] =
157 read_samples.mix2.pcm32[channel][sample];
158 }
159 }
160 }
161}
162
163void Mixers::AuxSend(IntermediateMixSamples& write_samples,
164 const std::array<QuadFrame32, 3>& input) {
165 // NOTE: read_samples.mix{1,2}.pcm32 annoyingly have their dimensions in reverse order to
166 // QuadFrame32.
167
168 state.intermediate_mix_buffer[0] = input[0];
169
170 if (state.mixer1_enabled) {
171 for (size_t sample = 0; sample < samples_per_frame; sample++) {
172 for (size_t channel = 0; channel < 4; channel++) {
173 write_samples.mix1.pcm32[channel][sample] = input[1][sample][channel];
174 }
175 }
176 } else {
177 state.intermediate_mix_buffer[1] = input[1];
178 }
179
180 if (state.mixer2_enabled) {
181 for (size_t sample = 0; sample < samples_per_frame; sample++) {
182 for (size_t channel = 0; channel < 4; channel++) {
183 write_samples.mix2.pcm32[channel][sample] = input[2][sample][channel];
184 }
185 }
186 } else {
187 state.intermediate_mix_buffer[2] = input[2];
188 }
189}
190
191void Mixers::MixCurrentFrame() {
192 current_frame.fill({});
193
194 for (size_t mix = 0; mix < 3; mix++) {
195 DownmixAndMixIntoCurrentFrame(state.intermediate_mixer_volume[mix],
196 state.intermediate_mix_buffer[mix]);
197 }
198
199 // TODO(merry): Compressor. (We currently assume a disabled compressor.)
200}
201
202DspStatus Mixers::GetCurrentStatus() const {
203 DspStatus status;
204 status.unknown = 0;
205 status.dropped_frames = 0;
206 return status;
207}
208
209} // namespace HLE
210} // namespace DSP
diff --git a/src/audio_core/hle/mixers.h b/src/audio_core/hle/mixers.h
deleted file mode 100644
index bf4e865ae..000000000
--- a/src/audio_core/hle/mixers.h
+++ /dev/null
@@ -1,61 +0,0 @@
1// Copyright 2016 Citra Emulator Project
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#pragma once
6
7#include <array>
8#include "audio_core/hle/common.h"
9#include "audio_core/hle/dsp.h"
10
11namespace DSP {
12namespace HLE {
13
14class Mixers final {
15public:
16 Mixers() {
17 Reset();
18 }
19
20 void Reset();
21
22 DspStatus Tick(DspConfiguration& config, const IntermediateMixSamples& read_samples,
23 IntermediateMixSamples& write_samples, const std::array<QuadFrame32, 3>& input);
24
25 StereoFrame16 GetOutput() const {
26 return current_frame;
27 }
28
29private:
30 StereoFrame16 current_frame = {};
31
32 using OutputFormat = DspConfiguration::OutputFormat;
33
34 struct {
35 std::array<float, 3> intermediate_mixer_volume = {};
36
37 bool mixer1_enabled = false;
38 bool mixer2_enabled = false;
39 std::array<QuadFrame32, 3> intermediate_mix_buffer = {};
40
41 OutputFormat output_format = OutputFormat::Stereo;
42
43 } state;
44
45 /// INTERNAL: Update our internal state based on the current config.
46 void ParseConfig(DspConfiguration& config);
47 /// INTERNAL: Read samples from shared memory that have been modified by the ARM11.
48 void AuxReturn(const IntermediateMixSamples& read_samples);
49 /// INTERNAL: Write samples to shared memory for the ARM11 to modify.
50 void AuxSend(IntermediateMixSamples& write_samples, const std::array<QuadFrame32, 3>& input);
51 /// INTERNAL: Mix current_frame.
52 void MixCurrentFrame();
53 /// INTERNAL: Downmix from quadraphonic to stereo based on status.output_format and accumulate
54 /// into current_frame.
55 void DownmixAndMixIntoCurrentFrame(float gain, const QuadFrame32& samples);
56 /// INTERNAL: Generate DspStatus based on internal state.
57 DspStatus GetCurrentStatus() const;
58};
59
60} // namespace HLE
61} // namespace DSP
diff --git a/src/audio_core/hle/pipe.cpp b/src/audio_core/hle/pipe.cpp
deleted file mode 100644
index 24074a514..000000000
--- a/src/audio_core/hle/pipe.cpp
+++ /dev/null
@@ -1,177 +0,0 @@
1// Copyright 2016 Citra Emulator Project
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#include <array>
6#include <vector>
7#include "audio_core/hle/dsp.h"
8#include "audio_core/hle/pipe.h"
9#include "common/assert.h"
10#include "common/common_types.h"
11#include "common/logging/log.h"
12#include "core/hle/service/dsp_dsp.h"
13
14namespace DSP {
15namespace HLE {
16
17static DspState dsp_state = DspState::Off;
18
19static std::array<std::vector<u8>, NUM_DSP_PIPE> pipe_data;
20
21void ResetPipes() {
22 for (auto& data : pipe_data) {
23 data.clear();
24 }
25 dsp_state = DspState::Off;
26}
27
28std::vector<u8> PipeRead(DspPipe pipe_number, u32 length) {
29 const size_t pipe_index = static_cast<size_t>(pipe_number);
30
31 if (pipe_index >= NUM_DSP_PIPE) {
32 LOG_ERROR(Audio_DSP, "pipe_number = %zu invalid", pipe_index);
33 return {};
34 }
35
36 if (length > UINT16_MAX) { // Can only read at most UINT16_MAX from the pipe
37 LOG_ERROR(Audio_DSP, "length of %u greater than max of %u", length, UINT16_MAX);
38 return {};
39 }
40
41 std::vector<u8>& data = pipe_data[pipe_index];
42
43 if (length > data.size()) {
44 LOG_WARNING(
45 Audio_DSP,
46 "pipe_number = %zu is out of data, application requested read of %u but %zu remain",
47 pipe_index, length, data.size());
48 length = static_cast<u32>(data.size());
49 }
50
51 if (length == 0)
52 return {};
53
54 std::vector<u8> ret(data.begin(), data.begin() + length);
55 data.erase(data.begin(), data.begin() + length);
56 return ret;
57}
58
59size_t GetPipeReadableSize(DspPipe pipe_number) {
60 const size_t pipe_index = static_cast<size_t>(pipe_number);
61
62 if (pipe_index >= NUM_DSP_PIPE) {
63 LOG_ERROR(Audio_DSP, "pipe_number = %zu invalid", pipe_index);
64 return 0;
65 }
66
67 return pipe_data[pipe_index].size();
68}
69
70static void WriteU16(DspPipe pipe_number, u16 value) {
71 const size_t pipe_index = static_cast<size_t>(pipe_number);
72
73 std::vector<u8>& data = pipe_data.at(pipe_index);
74 // Little endian
75 data.emplace_back(value & 0xFF);
76 data.emplace_back(value >> 8);
77}
78
79static void AudioPipeWriteStructAddresses() {
80 // These struct addresses are DSP dram addresses.
81 // See also: DSP_DSP::ConvertProcessAddressFromDspDram
82 static const std::array<u16, 15> struct_addresses = {
83 0x8000 + offsetof(SharedMemory, frame_counter) / 2,
84 0x8000 + offsetof(SharedMemory, source_configurations) / 2,
85 0x8000 + offsetof(SharedMemory, source_statuses) / 2,
86 0x8000 + offsetof(SharedMemory, adpcm_coefficients) / 2,
87 0x8000 + offsetof(SharedMemory, dsp_configuration) / 2,
88 0x8000 + offsetof(SharedMemory, dsp_status) / 2,
89 0x8000 + offsetof(SharedMemory, final_samples) / 2,
90 0x8000 + offsetof(SharedMemory, intermediate_mix_samples) / 2,
91 0x8000 + offsetof(SharedMemory, compressor) / 2,
92 0x8000 + offsetof(SharedMemory, dsp_debug) / 2,
93 0x8000 + offsetof(SharedMemory, unknown10) / 2,
94 0x8000 + offsetof(SharedMemory, unknown11) / 2,
95 0x8000 + offsetof(SharedMemory, unknown12) / 2,
96 0x8000 + offsetof(SharedMemory, unknown13) / 2,
97 0x8000 + offsetof(SharedMemory, unknown14) / 2,
98 };
99
100 // Begin with a u16 denoting the number of structs.
101 WriteU16(DspPipe::Audio, static_cast<u16>(struct_addresses.size()));
102 // Then write the struct addresses.
103 for (u16 addr : struct_addresses) {
104 WriteU16(DspPipe::Audio, addr);
105 }
106 // Signal that we have data on this pipe.
107 Service::DSP_DSP::SignalPipeInterrupt(DspPipe::Audio);
108}
109
110void PipeWrite(DspPipe pipe_number, const std::vector<u8>& buffer) {
111 switch (pipe_number) {
112 case DspPipe::Audio: {
113 if (buffer.size() != 4) {
114 LOG_ERROR(Audio_DSP, "DspPipe::Audio: Unexpected buffer length %zu was written",
115 buffer.size());
116 return;
117 }
118
119 enum class StateChange {
120 Initialize = 0,
121 Shutdown = 1,
122 Wakeup = 2,
123 Sleep = 3,
124 };
125
126 // The difference between Initialize and Wakeup is that Input state is maintained
127 // when sleeping but isn't when turning it off and on again. (TODO: Implement this.)
128 // Waking up from sleep garbles some of the structs in the memory region. (TODO:
129 // Implement this.) Applications store away the state of these structs before
130 // sleeping and reset it back after wakeup on behalf of the DSP.
131
132 switch (static_cast<StateChange>(buffer[0])) {
133 case StateChange::Initialize:
134 LOG_INFO(Audio_DSP, "Application has requested initialization of DSP hardware");
135 ResetPipes();
136 AudioPipeWriteStructAddresses();
137 dsp_state = DspState::On;
138 break;
139 case StateChange::Shutdown:
140 LOG_INFO(Audio_DSP, "Application has requested shutdown of DSP hardware");
141 dsp_state = DspState::Off;
142 break;
143 case StateChange::Wakeup:
144 LOG_INFO(Audio_DSP, "Application has requested wakeup of DSP hardware");
145 ResetPipes();
146 AudioPipeWriteStructAddresses();
147 dsp_state = DspState::On;
148 break;
149 case StateChange::Sleep:
150 LOG_INFO(Audio_DSP, "Application has requested sleep of DSP hardware");
151 UNIMPLEMENTED();
152 dsp_state = DspState::Sleeping;
153 break;
154 default:
155 LOG_ERROR(Audio_DSP,
156 "Application has requested unknown state transition of DSP hardware %hhu",
157 buffer[0]);
158 dsp_state = DspState::Off;
159 break;
160 }
161
162 return;
163 }
164 default:
165 LOG_CRITICAL(Audio_DSP, "pipe_number = %zu unimplemented",
166 static_cast<size_t>(pipe_number));
167 UNIMPLEMENTED();
168 return;
169 }
170}
171
172DspState GetDspState() {
173 return dsp_state;
174}
175
176} // namespace HLE
177} // namespace DSP
diff --git a/src/audio_core/hle/pipe.h b/src/audio_core/hle/pipe.h
deleted file mode 100644
index ac053c029..000000000
--- a/src/audio_core/hle/pipe.h
+++ /dev/null
@@ -1,63 +0,0 @@
1// Copyright 2016 Citra Emulator Project
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#pragma once
6
7#include <cstddef>
8#include <vector>
9#include "common/common_types.h"
10
11namespace DSP {
12namespace HLE {
13
14/// Reset the pipes by setting pipe positions back to the beginning.
15void ResetPipes();
16
17enum class DspPipe {
18 Debug = 0,
19 Dma = 1,
20 Audio = 2,
21 Binary = 3,
22};
23constexpr size_t NUM_DSP_PIPE = 8;
24
25/**
26 * Reads `length` bytes from the DSP pipe identified with `pipe_number`.
27 * @note Can read up to the maximum value of a u16 in bytes (65,535).
28 * @note IF an error is encoutered with either an invalid `pipe_number` or `length` value, an empty
29 * vector will be returned.
30 * @note IF `length` is set to 0, an empty vector will be returned.
31 * @note IF `length` is greater than the amount of data available, this function will only read the
32 * available amount.
33 * @param pipe_number a `DspPipe`
34 * @param length the number of bytes to read. The max is 65,535 (max of u16).
35 * @returns a vector of bytes from the specified pipe. On error, will be empty.
36 */
37std::vector<u8> PipeRead(DspPipe pipe_number, u32 length);
38
39/**
40 * How much data is left in pipe
41 * @param pipe_number The Pipe ID
42 * @return The amount of data remaning in the pipe. This is the maximum length PipeRead will return.
43 */
44size_t GetPipeReadableSize(DspPipe pipe_number);
45
46/**
47 * Write to a DSP pipe.
48 * @param pipe_number The Pipe ID
49 * @param buffer The data to write to the pipe.
50 */
51void PipeWrite(DspPipe pipe_number, const std::vector<u8>& buffer);
52
53enum class DspState {
54 Off,
55 On,
56 Sleeping,
57};
58
59/// Get the state of the DSP
60DspState GetDspState();
61
62} // namespace HLE
63} // namespace DSP
diff --git a/src/audio_core/hle/source.cpp b/src/audio_core/hle/source.cpp
deleted file mode 100644
index c12287700..000000000
--- a/src/audio_core/hle/source.cpp
+++ /dev/null
@@ -1,349 +0,0 @@
1// Copyright 2016 Citra Emulator Project
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#include <algorithm>
6#include <array>
7#include "audio_core/codec.h"
8#include "audio_core/hle/common.h"
9#include "audio_core/hle/source.h"
10#include "audio_core/interpolate.h"
11#include "common/assert.h"
12#include "common/logging/log.h"
13#include "core/memory.h"
14
15namespace DSP {
16namespace HLE {
17
18SourceStatus::Status Source::Tick(SourceConfiguration::Configuration& config,
19 const s16_le (&adpcm_coeffs)[16]) {
20 ParseConfig(config, adpcm_coeffs);
21
22 if (state.enabled) {
23 GenerateFrame();
24 }
25
26 return GetCurrentStatus();
27}
28
29void Source::MixInto(QuadFrame32& dest, size_t intermediate_mix_id) const {
30 if (!state.enabled)
31 return;
32
33 const std::array<float, 4>& gains = state.gain.at(intermediate_mix_id);
34 for (size_t samplei = 0; samplei < samples_per_frame; samplei++) {
35 // Conversion from stereo (current_frame) to quadraphonic (dest) occurs here.
36 dest[samplei][0] += static_cast<s32>(gains[0] * current_frame[samplei][0]);
37 dest[samplei][1] += static_cast<s32>(gains[1] * current_frame[samplei][1]);
38 dest[samplei][2] += static_cast<s32>(gains[2] * current_frame[samplei][0]);
39 dest[samplei][3] += static_cast<s32>(gains[3] * current_frame[samplei][1]);
40 }
41}
42
43void Source::Reset() {
44 current_frame.fill({});
45 state = {};
46}
47
48void Source::ParseConfig(SourceConfiguration::Configuration& config,
49 const s16_le (&adpcm_coeffs)[16]) {
50 if (!config.dirty_raw) {
51 return;
52 }
53
54 if (config.reset_flag) {
55 config.reset_flag.Assign(0);
56 Reset();
57 LOG_TRACE(Audio_DSP, "source_id=%zu reset", source_id);
58 }
59
60 if (config.partial_reset_flag) {
61 config.partial_reset_flag.Assign(0);
62 state.input_queue = std::priority_queue<Buffer, std::vector<Buffer>, BufferOrder>{};
63 LOG_TRACE(Audio_DSP, "source_id=%zu partial_reset", source_id);
64 }
65
66 if (config.enable_dirty) {
67 config.enable_dirty.Assign(0);
68 state.enabled = config.enable != 0;
69 LOG_TRACE(Audio_DSP, "source_id=%zu enable=%d", source_id, state.enabled);
70 }
71
72 if (config.sync_dirty) {
73 config.sync_dirty.Assign(0);
74 state.sync = config.sync;
75 LOG_TRACE(Audio_DSP, "source_id=%zu sync=%u", source_id, state.sync);
76 }
77
78 if (config.rate_multiplier_dirty) {
79 config.rate_multiplier_dirty.Assign(0);
80 state.rate_multiplier = config.rate_multiplier;
81 LOG_TRACE(Audio_DSP, "source_id=%zu rate=%f", source_id, state.rate_multiplier);
82
83 if (state.rate_multiplier <= 0) {
84 LOG_ERROR(Audio_DSP, "Was given an invalid rate multiplier: source_id=%zu rate=%f",
85 source_id, state.rate_multiplier);
86 state.rate_multiplier = 1.0f;
87 // Note: Actual firmware starts producing garbage if this occurs.
88 }
89 }
90
91 if (config.adpcm_coefficients_dirty) {
92 config.adpcm_coefficients_dirty.Assign(0);
93 std::transform(adpcm_coeffs, adpcm_coeffs + state.adpcm_coeffs.size(),
94 state.adpcm_coeffs.begin(),
95 [](const auto& coeff) { return static_cast<s16>(coeff); });
96 LOG_TRACE(Audio_DSP, "source_id=%zu adpcm update", source_id);
97 }
98
99 if (config.gain_0_dirty) {
100 config.gain_0_dirty.Assign(0);
101 std::transform(config.gain[0], config.gain[0] + state.gain[0].size(), state.gain[0].begin(),
102 [](const auto& coeff) { return static_cast<float>(coeff); });
103 LOG_TRACE(Audio_DSP, "source_id=%zu gain 0 update", source_id);
104 }
105
106 if (config.gain_1_dirty) {
107 config.gain_1_dirty.Assign(0);
108 std::transform(config.gain[1], config.gain[1] + state.gain[1].size(), state.gain[1].begin(),
109 [](const auto& coeff) { return static_cast<float>(coeff); });
110 LOG_TRACE(Audio_DSP, "source_id=%zu gain 1 update", source_id);
111 }
112
113 if (config.gain_2_dirty) {
114 config.gain_2_dirty.Assign(0);
115 std::transform(config.gain[2], config.gain[2] + state.gain[2].size(), state.gain[2].begin(),
116 [](const auto& coeff) { return static_cast<float>(coeff); });
117 LOG_TRACE(Audio_DSP, "source_id=%zu gain 2 update", source_id);
118 }
119
120 if (config.filters_enabled_dirty) {
121 config.filters_enabled_dirty.Assign(0);
122 state.filters.Enable(config.simple_filter_enabled.ToBool(),
123 config.biquad_filter_enabled.ToBool());
124 LOG_TRACE(Audio_DSP, "source_id=%zu enable_simple=%hu enable_biquad=%hu", source_id,
125 config.simple_filter_enabled.Value(), config.biquad_filter_enabled.Value());
126 }
127
128 if (config.simple_filter_dirty) {
129 config.simple_filter_dirty.Assign(0);
130 state.filters.Configure(config.simple_filter);
131 LOG_TRACE(Audio_DSP, "source_id=%zu simple filter update", source_id);
132 }
133
134 if (config.biquad_filter_dirty) {
135 config.biquad_filter_dirty.Assign(0);
136 state.filters.Configure(config.biquad_filter);
137 LOG_TRACE(Audio_DSP, "source_id=%zu biquad filter update", source_id);
138 }
139
140 if (config.interpolation_dirty) {
141 config.interpolation_dirty.Assign(0);
142 state.interpolation_mode = config.interpolation_mode;
143 LOG_TRACE(Audio_DSP, "source_id=%zu interpolation_mode=%zu", source_id,
144 static_cast<size_t>(state.interpolation_mode));
145 }
146
147 if (config.format_dirty || config.embedded_buffer_dirty) {
148 config.format_dirty.Assign(0);
149 state.format = config.format;
150 LOG_TRACE(Audio_DSP, "source_id=%zu format=%zu", source_id,
151 static_cast<size_t>(state.format));
152 }
153
154 if (config.mono_or_stereo_dirty || config.embedded_buffer_dirty) {
155 config.mono_or_stereo_dirty.Assign(0);
156 state.mono_or_stereo = config.mono_or_stereo;
157 LOG_TRACE(Audio_DSP, "source_id=%zu mono_or_stereo=%zu", source_id,
158 static_cast<size_t>(state.mono_or_stereo));
159 }
160
161 u32_dsp play_position = {};
162 if (config.play_position_dirty && config.play_position != 0) {
163 config.play_position_dirty.Assign(0);
164 play_position = config.play_position;
165 // play_position applies only to the embedded buffer, and defaults to 0 w/o a dirty bit
166 // This will be the starting sample for the first time the buffer is played.
167 }
168
169 if (config.embedded_buffer_dirty) {
170 config.embedded_buffer_dirty.Assign(0);
171 state.input_queue.emplace(Buffer{
172 config.physical_address,
173 config.length,
174 static_cast<u8>(config.adpcm_ps),
175 {config.adpcm_yn[0], config.adpcm_yn[1]},
176 config.adpcm_dirty.ToBool(),
177 config.is_looping.ToBool(),
178 config.buffer_id,
179 state.mono_or_stereo,
180 state.format,
181 false,
182 play_position,
183 false,
184 });
185 LOG_TRACE(Audio_DSP, "enqueuing embedded addr=0x%08x len=%u id=%hu start=%u",
186 config.physical_address, config.length, config.buffer_id,
187 static_cast<u32>(config.play_position));
188 }
189
190 if (config.loop_related_dirty && config.loop_related != 0) {
191 config.loop_related_dirty.Assign(0);
192 LOG_WARNING(Audio_DSP, "Unhandled complex loop with loop_related=0x%08x",
193 static_cast<u32>(config.loop_related));
194 }
195
196 if (config.buffer_queue_dirty) {
197 config.buffer_queue_dirty.Assign(0);
198 for (size_t i = 0; i < 4; i++) {
199 if (config.buffers_dirty & (1 << i)) {
200 const auto& b = config.buffers[i];
201 state.input_queue.emplace(Buffer{
202 b.physical_address,
203 b.length,
204 static_cast<u8>(b.adpcm_ps),
205 {b.adpcm_yn[0], b.adpcm_yn[1]},
206 b.adpcm_dirty != 0,
207 b.is_looping != 0,
208 b.buffer_id,
209 state.mono_or_stereo,
210 state.format,
211 true,
212 {}, // 0 in u32_dsp
213 false,
214 });
215 LOG_TRACE(Audio_DSP, "enqueuing queued %zu addr=0x%08x len=%u id=%hu", i,
216 b.physical_address, b.length, b.buffer_id);
217 }
218 }
219 config.buffers_dirty = 0;
220 }
221
222 if (config.dirty_raw) {
223 LOG_DEBUG(Audio_DSP, "source_id=%zu remaining_dirty=%x", source_id, config.dirty_raw);
224 }
225
226 config.dirty_raw = 0;
227}
228
229void Source::GenerateFrame() {
230 current_frame.fill({});
231
232 if (state.current_buffer.empty() && !DequeueBuffer()) {
233 state.enabled = false;
234 state.buffer_update = true;
235 state.current_buffer_id = 0;
236 return;
237 }
238
239 size_t frame_position = 0;
240
241 state.current_sample_number = state.next_sample_number;
242 while (frame_position < current_frame.size()) {
243 if (state.current_buffer.empty() && !DequeueBuffer()) {
244 break;
245 }
246
247 switch (state.interpolation_mode) {
248 case InterpolationMode::None:
249 AudioInterp::None(state.interp_state, state.current_buffer, state.rate_multiplier,
250 current_frame, frame_position);
251 break;
252 case InterpolationMode::Linear:
253 AudioInterp::Linear(state.interp_state, state.current_buffer, state.rate_multiplier,
254 current_frame, frame_position);
255 break;
256 case InterpolationMode::Polyphase:
257 // TODO(merry): Implement polyphase interpolation
258 LOG_DEBUG(Audio_DSP, "Polyphase interpolation unimplemented; falling back to linear");
259 AudioInterp::Linear(state.interp_state, state.current_buffer, state.rate_multiplier,
260 current_frame, frame_position);
261 break;
262 default:
263 UNIMPLEMENTED();
264 break;
265 }
266 }
267 state.next_sample_number += static_cast<u32>(frame_position);
268
269 state.filters.ProcessFrame(current_frame);
270}
271
272bool Source::DequeueBuffer() {
273 ASSERT_MSG(state.current_buffer.empty(),
274 "Shouldn't dequeue; we still have data in current_buffer");
275
276 if (state.input_queue.empty())
277 return false;
278
279 Buffer buf = state.input_queue.top();
280
281 // if we're in a loop, the current sound keeps playing afterwards, so leave the queue alone
282 if (!buf.is_looping) {
283 state.input_queue.pop();
284 }
285
286 if (buf.adpcm_dirty) {
287 state.adpcm_state.yn1 = buf.adpcm_yn[0];
288 state.adpcm_state.yn2 = buf.adpcm_yn[1];
289 }
290
291 const u8* const memory = Memory::GetPhysicalPointer(buf.physical_address);
292 if (memory) {
293 const unsigned num_channels = buf.mono_or_stereo == MonoOrStereo::Stereo ? 2 : 1;
294 switch (buf.format) {
295 case Format::PCM8:
296 state.current_buffer = Codec::DecodePCM8(num_channels, memory, buf.length);
297 break;
298 case Format::PCM16:
299 state.current_buffer = Codec::DecodePCM16(num_channels, memory, buf.length);
300 break;
301 case Format::ADPCM:
302 DEBUG_ASSERT(num_channels == 1);
303 state.current_buffer =
304 Codec::DecodeADPCM(memory, buf.length, state.adpcm_coeffs, state.adpcm_state);
305 break;
306 default:
307 UNIMPLEMENTED();
308 break;
309 }
310 } else {
311 LOG_WARNING(Audio_DSP,
312 "source_id=%zu buffer_id=%hu length=%u: Invalid physical address 0x%08X",
313 source_id, buf.buffer_id, buf.length, buf.physical_address);
314 state.current_buffer.clear();
315 return true;
316 }
317
318 // the first playthrough starts at play_position, loops start at the beginning of the buffer
319 state.current_sample_number = (!buf.has_played) ? buf.play_position : 0;
320 state.next_sample_number = state.current_sample_number;
321 state.current_buffer_id = buf.buffer_id;
322 state.buffer_update = buf.from_queue && !buf.has_played;
323
324 buf.has_played = true;
325
326 LOG_TRACE(Audio_DSP, "source_id=%zu buffer_id=%hu from_queue=%s current_buffer.size()=%zu",
327 source_id, buf.buffer_id, buf.from_queue ? "true" : "false",
328 state.current_buffer.size());
329 return true;
330}
331
332SourceStatus::Status Source::GetCurrentStatus() {
333 SourceStatus::Status ret;
334
335 // Applications depend on the correct emulation of
336 // current_buffer_id_dirty and current_buffer_id to synchronise
337 // audio with video.
338 ret.is_enabled = state.enabled;
339 ret.current_buffer_id_dirty = state.buffer_update ? 1 : 0;
340 state.buffer_update = false;
341 ret.current_buffer_id = state.current_buffer_id;
342 ret.buffer_position = state.current_sample_number;
343 ret.sync = state.sync;
344
345 return ret;
346}
347
348} // namespace HLE
349} // namespace DSP
diff --git a/src/audio_core/hle/source.h b/src/audio_core/hle/source.h
deleted file mode 100644
index c4d2debc2..000000000
--- a/src/audio_core/hle/source.h
+++ /dev/null
@@ -1,149 +0,0 @@
1// Copyright 2016 Citra Emulator Project
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#pragma once
6
7#include <array>
8#include <queue>
9#include <vector>
10#include "audio_core/codec.h"
11#include "audio_core/hle/common.h"
12#include "audio_core/hle/dsp.h"
13#include "audio_core/hle/filter.h"
14#include "audio_core/interpolate.h"
15#include "common/common_types.h"
16
17namespace DSP {
18namespace HLE {
19
20/**
21 * This module performs:
22 * - Buffer management
23 * - Decoding of buffers
24 * - Buffer resampling and interpolation
25 * - Per-source filtering (SimpleFilter, BiquadFilter)
26 * - Per-source gain
27 * - Other per-source processing
28 */
29class Source final {
30public:
31 explicit Source(size_t source_id_) : source_id(source_id_) {
32 Reset();
33 }
34
35 /// Resets internal state.
36 void Reset();
37
38 /**
39 * This is called once every audio frame. This performs per-source processing every frame.
40 * @param config The new configuration we've got for this Source from the application.
41 * @param adpcm_coeffs ADPCM coefficients to use if config tells us to use them (may contain
42 * invalid values otherwise).
43 * @return The current status of this Source. This is given back to the emulated application via
44 * SharedMemory.
45 */
46 SourceStatus::Status Tick(SourceConfiguration::Configuration& config,
47 const s16_le (&adpcm_coeffs)[16]);
48
49 /**
50 * Mix this source's output into dest, using the gains for the `intermediate_mix_id`-th
51 * intermediate mixer.
52 * @param dest The QuadFrame32 to mix into.
53 * @param intermediate_mix_id The id of the intermediate mix whose gains we are using.
54 */
55 void MixInto(QuadFrame32& dest, size_t intermediate_mix_id) const;
56
57private:
58 const size_t source_id;
59 StereoFrame16 current_frame;
60
61 using Format = SourceConfiguration::Configuration::Format;
62 using InterpolationMode = SourceConfiguration::Configuration::InterpolationMode;
63 using MonoOrStereo = SourceConfiguration::Configuration::MonoOrStereo;
64
65 /// Internal representation of a buffer for our buffer queue
66 struct Buffer {
67 PAddr physical_address;
68 u32 length;
69 u8 adpcm_ps;
70 std::array<u16, 2> adpcm_yn;
71 bool adpcm_dirty;
72 bool is_looping;
73 u16 buffer_id;
74
75 MonoOrStereo mono_or_stereo;
76 Format format;
77
78 bool from_queue;
79 u32_dsp play_position; // = 0;
80 bool has_played; // = false;
81 };
82
83 struct BufferOrder {
84 bool operator()(const Buffer& a, const Buffer& b) const {
85 // Lower buffer_id comes first.
86 return a.buffer_id > b.buffer_id;
87 }
88 };
89
90 struct {
91
92 // State variables
93
94 bool enabled = false;
95 u16 sync = 0;
96
97 // Mixing
98
99 std::array<std::array<float, 4>, 3> gain = {};
100
101 // Buffer queue
102
103 std::priority_queue<Buffer, std::vector<Buffer>, BufferOrder> input_queue;
104 MonoOrStereo mono_or_stereo = MonoOrStereo::Mono;
105 Format format = Format::ADPCM;
106
107 // Current buffer
108
109 u32 current_sample_number = 0;
110 u32 next_sample_number = 0;
111 AudioInterp::StereoBuffer16 current_buffer;
112
113 // buffer_id state
114
115 bool buffer_update = false;
116 u32 current_buffer_id = 0;
117
118 // Decoding state
119
120 std::array<s16, 16> adpcm_coeffs = {};
121 Codec::ADPCMState adpcm_state = {};
122
123 // Resampling state
124
125 float rate_multiplier = 1.0;
126 InterpolationMode interpolation_mode = InterpolationMode::Polyphase;
127 AudioInterp::State interp_state = {};
128
129 // Filter state
130
131 SourceFilters filters;
132
133 } state;
134
135 // Internal functions
136
137 /// INTERNAL: Update our internal state based on the current config.
138 void ParseConfig(SourceConfiguration::Configuration& config, const s16_le (&adpcm_coeffs)[16]);
139 /// INTERNAL: Generate the current audio output for this frame based on our internal state.
140 void GenerateFrame();
141 /// INTERNAL: Dequeues a buffer and does preprocessing on it (decoding, resampling). Puts it
142 /// into current_buffer.
143 bool DequeueBuffer();
144 /// INTERNAL: Generates a SourceStatus::Status based on our internal state.
145 SourceStatus::Status GetCurrentStatus();
146};
147
148} // namespace HLE
149} // namespace DSP
diff --git a/src/audio_core/interpolate.cpp b/src/audio_core/interpolate.cpp
deleted file mode 100644
index 83573d772..000000000
--- a/src/audio_core/interpolate.cpp
+++ /dev/null
@@ -1,76 +0,0 @@
1// Copyright 2016 Citra Emulator Project
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#include "audio_core/interpolate.h"
6#include "common/assert.h"
7#include "common/math_util.h"
8
9namespace AudioInterp {
10
11// Calculations are done in fixed point with 24 fractional bits.
12// (This is not verified. This was chosen for minimal error.)
13constexpr u64 scale_factor = 1 << 24;
14constexpr u64 scale_mask = scale_factor - 1;
15
16/// Here we step over the input in steps of rate, until we consume all of the input.
17/// Three adjacent samples are passed to fn each step.
18template <typename Function>
19static void StepOverSamples(State& state, StereoBuffer16& input, float rate,
20 DSP::HLE::StereoFrame16& output, size_t& outputi, Function fn) {
21 ASSERT(rate > 0);
22
23 if (input.empty())
24 return;
25
26 input.insert(input.begin(), {state.xn2, state.xn1});
27
28 const u64 step_size = static_cast<u64>(rate * scale_factor);
29 u64 fposition = state.fposition;
30 size_t inputi = 0;
31
32 while (outputi < output.size()) {
33 inputi = static_cast<size_t>(fposition / scale_factor);
34
35 if (inputi + 2 >= input.size()) {
36 inputi = input.size() - 2;
37 break;
38 }
39
40 u64 fraction = fposition & scale_mask;
41 output[outputi++] = fn(fraction, input[inputi], input[inputi + 1], input[inputi + 2]);
42
43 fposition += step_size;
44 }
45
46 state.xn2 = input[inputi];
47 state.xn1 = input[inputi + 1];
48 state.fposition = fposition - inputi * scale_factor;
49
50 input.erase(input.begin(), std::next(input.begin(), inputi + 2));
51}
52
53void None(State& state, StereoBuffer16& input, float rate, DSP::HLE::StereoFrame16& output,
54 size_t& outputi) {
55 StepOverSamples(
56 state, input, rate, output, outputi,
57 [](u64 fraction, const auto& x0, const auto& x1, const auto& x2) { return x0; });
58}
59
60void Linear(State& state, StereoBuffer16& input, float rate, DSP::HLE::StereoFrame16& output,
61 size_t& outputi) {
62 // Note on accuracy: Some values that this produces are +/- 1 from the actual firmware.
63 StepOverSamples(state, input, rate, output, outputi,
64 [](u64 fraction, const auto& x0, const auto& x1, const auto& x2) {
65 // This is a saturated subtraction. (Verified by black-box fuzzing.)
66 s64 delta0 = MathUtil::Clamp<s64>(x1[0] - x0[0], -32768, 32767);
67 s64 delta1 = MathUtil::Clamp<s64>(x1[1] - x0[1], -32768, 32767);
68
69 return std::array<s16, 2>{
70 static_cast<s16>(x0[0] + fraction * delta0 / scale_factor),
71 static_cast<s16>(x0[1] + fraction * delta1 / scale_factor),
72 };
73 });
74}
75
76} // namespace AudioInterp
diff --git a/src/audio_core/interpolate.h b/src/audio_core/interpolate.h
deleted file mode 100644
index 8dff6111a..000000000
--- a/src/audio_core/interpolate.h
+++ /dev/null
@@ -1,49 +0,0 @@
1// Copyright 2016 Citra Emulator Project
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#pragma once
6
7#include <array>
8#include <deque>
9#include "audio_core/hle/common.h"
10#include "common/common_types.h"
11
12namespace AudioInterp {
13
14/// A variable length buffer of signed PCM16 stereo samples.
15using StereoBuffer16 = std::deque<std::array<s16, 2>>;
16
17struct State {
18 /// Two historical samples.
19 std::array<s16, 2> xn1 = {}; ///< x[n-1]
20 std::array<s16, 2> xn2 = {}; ///< x[n-2]
21 /// Current fractional position.
22 u64 fposition = 0;
23};
24
25/**
26 * No interpolation. This is equivalent to a zero-order hold. There is a two-sample predelay.
27 * @param state Interpolation state.
28 * @param input Input buffer.
29 * @param rate Stretch factor. Must be a positive non-zero value.
30 * rate > 1.0 performs decimation and rate < 1.0 performs upsampling.
31 * @param output The resampled audio buffer.
32 * @param outputi The index of output to start writing to.
33 */
34void None(State& state, StereoBuffer16& input, float rate, DSP::HLE::StereoFrame16& output,
35 size_t& outputi);
36
37/**
38 * Linear interpolation. This is equivalent to a first-order hold. There is a two-sample predelay.
39 * @param state Interpolation state.
40 * @param input Input buffer.
41 * @param rate Stretch factor. Must be a positive non-zero value.
42 * rate > 1.0 performs decimation and rate < 1.0 performs upsampling.
43 * @param output The resampled audio buffer.
44 * @param outputi The index of output to start writing to.
45 */
46void Linear(State& state, StereoBuffer16& input, float rate, DSP::HLE::StereoFrame16& output,
47 size_t& outputi);
48
49} // namespace AudioInterp
diff --git a/src/audio_core/null_sink.h b/src/audio_core/null_sink.h
deleted file mode 100644
index c732926a2..000000000
--- a/src/audio_core/null_sink.h
+++ /dev/null
@@ -1,34 +0,0 @@
1// Copyright 2016 Citra Emulator Project
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#pragma once
6
7#include <cstddef>
8#include "audio_core/audio_core.h"
9#include "audio_core/sink.h"
10
11namespace AudioCore {
12
13class NullSink final : public Sink {
14public:
15 ~NullSink() override = default;
16
17 unsigned int GetNativeSampleRate() const override {
18 return native_sample_rate;
19 }
20
21 void EnqueueSamples(const s16*, size_t) override {}
22
23 size_t SamplesInQueue() const override {
24 return 0;
25 }
26
27 void SetDevice(int device_id) override {}
28
29 std::vector<std::string> GetDeviceList() const override {
30 return {};
31 }
32};
33
34} // namespace AudioCore
diff --git a/src/audio_core/sdl2_sink.cpp b/src/audio_core/sdl2_sink.cpp
deleted file mode 100644
index 933c5f16d..000000000
--- a/src/audio_core/sdl2_sink.cpp
+++ /dev/null
@@ -1,147 +0,0 @@
1// Copyright 2016 Citra Emulator Project
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#include <list>
6#include <numeric>
7#include <SDL.h>
8#include "audio_core/audio_core.h"
9#include "audio_core/sdl2_sink.h"
10#include "common/assert.h"
11#include "common/logging/log.h"
12#include "core/settings.h"
13
14namespace AudioCore {
15
16struct SDL2Sink::Impl {
17 unsigned int sample_rate = 0;
18
19 SDL_AudioDeviceID audio_device_id = 0;
20
21 std::list<std::vector<s16>> queue;
22
23 static void Callback(void* impl_, u8* buffer, int buffer_size_in_bytes);
24};
25
26SDL2Sink::SDL2Sink() : impl(std::make_unique<Impl>()) {
27 if (SDL_Init(SDL_INIT_AUDIO) < 0) {
28 LOG_CRITICAL(Audio_Sink, "SDL_Init(SDL_INIT_AUDIO) failed with: %s", SDL_GetError());
29 impl->audio_device_id = 0;
30 return;
31 }
32
33 SDL_AudioSpec desired_audiospec;
34 SDL_zero(desired_audiospec);
35 desired_audiospec.format = AUDIO_S16;
36 desired_audiospec.channels = 2;
37 desired_audiospec.freq = native_sample_rate;
38 desired_audiospec.samples = 512;
39 desired_audiospec.userdata = impl.get();
40 desired_audiospec.callback = &Impl::Callback;
41
42 SDL_AudioSpec obtained_audiospec;
43 SDL_zero(obtained_audiospec);
44
45 int device_count = SDL_GetNumAudioDevices(0);
46 device_list.clear();
47 for (int i = 0; i < device_count; ++i) {
48 device_list.push_back(SDL_GetAudioDeviceName(i, 0));
49 }
50
51 const char* device = nullptr;
52
53 if (device_count >= 1 && Settings::values.audio_device_id != "auto" &&
54 !Settings::values.audio_device_id.empty()) {
55 device = Settings::values.audio_device_id.c_str();
56 }
57
58 impl->audio_device_id = SDL_OpenAudioDevice(device, false, &desired_audiospec,
59 &obtained_audiospec, SDL_AUDIO_ALLOW_ANY_CHANGE);
60 if (impl->audio_device_id <= 0) {
61 LOG_CRITICAL(Audio_Sink, "SDL_OpenAudioDevice failed with code %d for device \"%s\"",
62 impl->audio_device_id, Settings::values.audio_device_id.c_str());
63 return;
64 }
65
66 impl->sample_rate = obtained_audiospec.freq;
67
68 // SDL2 audio devices start out paused, unpause it:
69 SDL_PauseAudioDevice(impl->audio_device_id, 0);
70}
71
72SDL2Sink::~SDL2Sink() {
73 if (impl->audio_device_id <= 0)
74 return;
75
76 SDL_CloseAudioDevice(impl->audio_device_id);
77}
78
79unsigned int SDL2Sink::GetNativeSampleRate() const {
80 if (impl->audio_device_id <= 0)
81 return native_sample_rate;
82
83 return impl->sample_rate;
84}
85
86std::vector<std::string> SDL2Sink::GetDeviceList() const {
87 return device_list;
88}
89
90void SDL2Sink::EnqueueSamples(const s16* samples, size_t sample_count) {
91 if (impl->audio_device_id <= 0)
92 return;
93
94 SDL_LockAudioDevice(impl->audio_device_id);
95 impl->queue.emplace_back(samples, samples + sample_count * 2);
96 SDL_UnlockAudioDevice(impl->audio_device_id);
97}
98
99size_t SDL2Sink::SamplesInQueue() const {
100 if (impl->audio_device_id <= 0)
101 return 0;
102
103 SDL_LockAudioDevice(impl->audio_device_id);
104
105 size_t total_size = std::accumulate(impl->queue.begin(), impl->queue.end(),
106 static_cast<size_t>(0), [](size_t sum, const auto& buffer) {
107 // Division by two because each stereo sample is made of
108 // two s16.
109 return sum + buffer.size() / 2;
110 });
111
112 SDL_UnlockAudioDevice(impl->audio_device_id);
113
114 return total_size;
115}
116
117void SDL2Sink::SetDevice(int device_id) {
118 this->device_id = device_id;
119}
120
121void SDL2Sink::Impl::Callback(void* impl_, u8* buffer, int buffer_size_in_bytes) {
122 Impl* impl = reinterpret_cast<Impl*>(impl_);
123
124 size_t remaining_size = static_cast<size_t>(buffer_size_in_bytes) /
125 sizeof(s16); // Keep track of size in 16-bit increments.
126
127 while (remaining_size > 0 && !impl->queue.empty()) {
128 if (impl->queue.front().size() <= remaining_size) {
129 memcpy(buffer, impl->queue.front().data(), impl->queue.front().size() * sizeof(s16));
130 buffer += impl->queue.front().size() * sizeof(s16);
131 remaining_size -= impl->queue.front().size();
132 impl->queue.pop_front();
133 } else {
134 memcpy(buffer, impl->queue.front().data(), remaining_size * sizeof(s16));
135 buffer += remaining_size * sizeof(s16);
136 impl->queue.front().erase(impl->queue.front().begin(),
137 impl->queue.front().begin() + remaining_size);
138 remaining_size = 0;
139 }
140 }
141
142 if (remaining_size > 0) {
143 memset(buffer, 0, remaining_size * sizeof(s16));
144 }
145}
146
147} // namespace AudioCore
diff --git a/src/audio_core/sdl2_sink.h b/src/audio_core/sdl2_sink.h
deleted file mode 100644
index bcc725369..000000000
--- a/src/audio_core/sdl2_sink.h
+++ /dev/null
@@ -1,34 +0,0 @@
1// Copyright 2016 Citra Emulator Project
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#pragma once
6
7#include <cstddef>
8#include <memory>
9#include "audio_core/sink.h"
10
11namespace AudioCore {
12
13class SDL2Sink final : public Sink {
14public:
15 SDL2Sink();
16 ~SDL2Sink() override;
17
18 unsigned int GetNativeSampleRate() const override;
19
20 void EnqueueSamples(const s16* samples, size_t sample_count) override;
21
22 size_t SamplesInQueue() const override;
23
24 std::vector<std::string> GetDeviceList() const override;
25 void SetDevice(int device_id) override;
26
27private:
28 struct Impl;
29 std::unique_ptr<Impl> impl;
30 int device_id;
31 std::vector<std::string> device_list;
32};
33
34} // namespace AudioCore
diff --git a/src/audio_core/sink.h b/src/audio_core/sink.h
deleted file mode 100644
index c69cb2c74..000000000
--- a/src/audio_core/sink.h
+++ /dev/null
@@ -1,45 +0,0 @@
1// Copyright 2016 Citra Emulator Project
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#pragma once
6
7#include <vector>
8#include "common/common_types.h"
9
10namespace AudioCore {
11
12/**
13 * This class is an interface for an audio sink. An audio sink accepts samples in stereo signed
14 * PCM16 format to be output. Sinks *do not* handle resampling and expect the correct sample rate.
15 * They are dumb outputs.
16 */
17class Sink {
18public:
19 virtual ~Sink() = default;
20
21 /// The native rate of this sink. The sink expects to be fed samples that respect this. (Units:
22 /// samples/sec)
23 virtual unsigned int GetNativeSampleRate() const = 0;
24
25 /**
26 * Feed stereo samples to sink.
27 * @param samples Samples in interleaved stereo PCM16 format.
28 * @param sample_count Number of samples.
29 */
30 virtual void EnqueueSamples(const s16* samples, size_t sample_count) = 0;
31
32 /// Samples enqueued that have not been played yet.
33 virtual std::size_t SamplesInQueue() const = 0;
34
35 /**
36 * Sets the desired output device.
37 * @param device_id ID of the desired device.
38 */
39 virtual void SetDevice(int device_id) = 0;
40
41 /// Returns the list of available devices.
42 virtual std::vector<std::string> GetDeviceList() const = 0;
43};
44
45} // namespace
diff --git a/src/audio_core/sink_details.cpp b/src/audio_core/sink_details.cpp
deleted file mode 100644
index 6972395af..000000000
--- a/src/audio_core/sink_details.cpp
+++ /dev/null
@@ -1,42 +0,0 @@
1// Copyright 2016 Citra Emulator Project
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#include <algorithm>
6#include <memory>
7#include <vector>
8#include "audio_core/null_sink.h"
9#include "audio_core/sink_details.h"
10#ifdef HAVE_SDL2
11#include "audio_core/sdl2_sink.h"
12#endif
13#include "common/logging/log.h"
14
15namespace AudioCore {
16
17// g_sink_details is ordered in terms of desirability, with the best choice at the top.
18const std::vector<SinkDetails> g_sink_details = {
19#ifdef HAVE_SDL2
20 {"sdl2", []() { return std::make_unique<SDL2Sink>(); }},
21#endif
22 {"null", []() { return std::make_unique<NullSink>(); }},
23};
24
25const SinkDetails& GetSinkDetails(std::string sink_id) {
26 auto iter =
27 std::find_if(g_sink_details.begin(), g_sink_details.end(),
28 [sink_id](const auto& sink_detail) { return sink_detail.id == sink_id; });
29
30 if (sink_id == "auto" || iter == g_sink_details.end()) {
31 if (sink_id != "auto") {
32 LOG_ERROR(Audio, "AudioCore::SelectSink given invalid sink_id %s", sink_id.c_str());
33 }
34 // Auto-select.
35 // g_sink_details is ordered in terms of desirability, with the best choice at the front.
36 iter = g_sink_details.begin();
37 }
38
39 return *iter;
40}
41
42} // namespace AudioCore
diff --git a/src/audio_core/sink_details.h b/src/audio_core/sink_details.h
deleted file mode 100644
index 9d3735171..000000000
--- a/src/audio_core/sink_details.h
+++ /dev/null
@@ -1,29 +0,0 @@
1// Copyright 2016 Citra Emulator Project
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#pragma once
6
7#include <functional>
8#include <memory>
9#include <vector>
10
11namespace AudioCore {
12
13class Sink;
14
15struct SinkDetails {
16 SinkDetails(const char* id_, std::function<std::unique_ptr<Sink>()> factory_)
17 : id(id_), factory(factory_) {}
18
19 /// Name for this sink.
20 const char* id;
21 /// A method to call to construct an instance of this type of sink.
22 std::function<std::unique_ptr<Sink>()> factory;
23};
24
25extern const std::vector<SinkDetails> g_sink_details;
26
27const SinkDetails& GetSinkDetails(std::string sink_id);
28
29} // namespace AudioCore
diff --git a/src/audio_core/time_stretch.cpp b/src/audio_core/time_stretch.cpp
deleted file mode 100644
index 437cf9752..000000000
--- a/src/audio_core/time_stretch.cpp
+++ /dev/null
@@ -1,143 +0,0 @@
1// Copyright 2016 Citra Emulator Project
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#include <chrono>
6#include <cmath>
7#include <vector>
8#include <SoundTouch.h>
9#include "audio_core/audio_core.h"
10#include "audio_core/time_stretch.h"
11#include "common/common_types.h"
12#include "common/logging/log.h"
13#include "common/math_util.h"
14
15using steady_clock = std::chrono::steady_clock;
16
17namespace AudioCore {
18
19constexpr double MIN_RATIO = 0.1;
20constexpr double MAX_RATIO = 100.0;
21
22static double ClampRatio(double ratio) {
23 return MathUtil::Clamp(ratio, MIN_RATIO, MAX_RATIO);
24}
25
26constexpr double MIN_DELAY_TIME = 0.05; // Units: seconds
27constexpr double MAX_DELAY_TIME = 0.25; // Units: seconds
28constexpr size_t DROP_FRAMES_SAMPLE_DELAY = 16000; // Units: samples
29
30constexpr double SMOOTHING_FACTOR = 0.007;
31
32struct TimeStretcher::Impl {
33 soundtouch::SoundTouch soundtouch;
34
35 steady_clock::time_point frame_timer = steady_clock::now();
36 size_t samples_queued = 0;
37
38 double smoothed_ratio = 1.0;
39
40 double sample_rate = static_cast<double>(native_sample_rate);
41};
42
43std::vector<s16> TimeStretcher::Process(size_t samples_in_queue) {
44 // This is a very simple algorithm without any fancy control theory. It works and is stable.
45
46 double ratio = CalculateCurrentRatio();
47 ratio = CorrectForUnderAndOverflow(ratio, samples_in_queue);
48 impl->smoothed_ratio =
49 (1.0 - SMOOTHING_FACTOR) * impl->smoothed_ratio + SMOOTHING_FACTOR * ratio;
50 impl->smoothed_ratio = ClampRatio(impl->smoothed_ratio);
51
52 // SoundTouch's tempo definition the inverse of our ratio definition.
53 impl->soundtouch.setTempo(1.0 / impl->smoothed_ratio);
54
55 std::vector<s16> samples = GetSamples();
56 if (samples_in_queue >= DROP_FRAMES_SAMPLE_DELAY) {
57 samples.clear();
58 LOG_TRACE(Audio, "Dropping frames!");
59 }
60 return samples;
61}
62
63TimeStretcher::TimeStretcher() : impl(std::make_unique<Impl>()) {
64 impl->soundtouch.setPitch(1.0);
65 impl->soundtouch.setChannels(2);
66 impl->soundtouch.setSampleRate(native_sample_rate);
67 Reset();
68}
69
70TimeStretcher::~TimeStretcher() {
71 impl->soundtouch.clear();
72}
73
74void TimeStretcher::SetOutputSampleRate(unsigned int sample_rate) {
75 impl->sample_rate = static_cast<double>(sample_rate);
76 impl->soundtouch.setRate(static_cast<double>(native_sample_rate) / impl->sample_rate);
77}
78
79void TimeStretcher::AddSamples(const s16* buffer, size_t num_samples) {
80 impl->soundtouch.putSamples(buffer, static_cast<uint>(num_samples));
81 impl->samples_queued += num_samples;
82}
83
84void TimeStretcher::Flush() {
85 impl->soundtouch.flush();
86}
87
88void TimeStretcher::Reset() {
89 impl->soundtouch.setTempo(1.0);
90 impl->soundtouch.clear();
91 impl->smoothed_ratio = 1.0;
92 impl->frame_timer = steady_clock::now();
93 impl->samples_queued = 0;
94 SetOutputSampleRate(native_sample_rate);
95}
96
97double TimeStretcher::CalculateCurrentRatio() {
98 const steady_clock::time_point now = steady_clock::now();
99 const std::chrono::duration<double> duration = now - impl->frame_timer;
100
101 const double expected_time =
102 static_cast<double>(impl->samples_queued) / static_cast<double>(native_sample_rate);
103 const double actual_time = duration.count();
104
105 double ratio;
106 if (expected_time != 0) {
107 ratio = ClampRatio(actual_time / expected_time);
108 } else {
109 ratio = impl->smoothed_ratio;
110 }
111
112 impl->frame_timer = now;
113 impl->samples_queued = 0;
114
115 return ratio;
116}
117
118double TimeStretcher::CorrectForUnderAndOverflow(double ratio, size_t sample_delay) const {
119 const size_t min_sample_delay = static_cast<size_t>(MIN_DELAY_TIME * impl->sample_rate);
120 const size_t max_sample_delay = static_cast<size_t>(MAX_DELAY_TIME * impl->sample_rate);
121
122 if (sample_delay < min_sample_delay) {
123 // Make the ratio bigger.
124 ratio = ratio > 1.0 ? ratio * ratio : sqrt(ratio);
125 } else if (sample_delay > max_sample_delay) {
126 // Make the ratio smaller.
127 ratio = ratio > 1.0 ? sqrt(ratio) : ratio * ratio;
128 }
129
130 return ClampRatio(ratio);
131}
132
133std::vector<s16> TimeStretcher::GetSamples() {
134 uint available = impl->soundtouch.numSamples();
135
136 std::vector<s16> output(static_cast<size_t>(available) * 2);
137
138 impl->soundtouch.receiveSamples(output.data(), available);
139
140 return output;
141}
142
143} // namespace AudioCore
diff --git a/src/audio_core/time_stretch.h b/src/audio_core/time_stretch.h
deleted file mode 100644
index c98b16705..000000000
--- a/src/audio_core/time_stretch.h
+++ /dev/null
@@ -1,60 +0,0 @@
1// Copyright 2016 Citra Emulator Project
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#pragma once
6
7#include <cstddef>
8#include <memory>
9#include <vector>
10#include "common/common_types.h"
11
12namespace AudioCore {
13
14class TimeStretcher final {
15public:
16 TimeStretcher();
17 ~TimeStretcher();
18
19 /**
20 * Set sample rate for the samples that Process returns.
21 * @param sample_rate The sample rate.
22 */
23 void SetOutputSampleRate(unsigned int sample_rate);
24
25 /**
26 * Add samples to be processed.
27 * @param sample_buffer Buffer of samples in interleaved stereo PCM16 format.
28 * @param num_samples Number of samples.
29 */
30 void AddSamples(const s16* sample_buffer, size_t num_samples);
31
32 /// Flush audio remaining in internal buffers.
33 void Flush();
34
35 /// Resets internal state and clears buffers.
36 void Reset();
37
38 /**
39 * Does audio stretching and produces the time-stretched samples.
40 * Timer calculations use sample_delay to determine how much of a margin we have.
41 * @param sample_delay How many samples are buffered downstream of this module and haven't been
42 * played yet.
43 * @return Samples to play in interleaved stereo PCM16 format.
44 */
45 std::vector<s16> Process(size_t sample_delay);
46
47private:
48 struct Impl;
49 std::unique_ptr<Impl> impl;
50
51 /// INTERNAL: ratio = wallclock time / emulated time
52 double CalculateCurrentRatio();
53 /// INTERNAL: If we have too many or too few samples downstream, nudge ratio in the appropriate
54 /// direction.
55 double CorrectForUnderAndOverflow(double ratio, size_t sample_delay) const;
56 /// INTERNAL: Gets the time-stretched samples from SoundTouch.
57 std::vector<s16> GetSamples();
58};
59
60} // namespace AudioCore
diff --git a/src/network/CMakeLists.txt b/src/network/CMakeLists.txt
deleted file mode 100644
index ac9d028da..000000000
--- a/src/network/CMakeLists.txt
+++ /dev/null
@@ -1,18 +0,0 @@
1set(SRCS
2 network.cpp
3 packet.cpp
4 room.cpp
5 room_member.cpp
6 )
7
8set(HEADERS
9 network.h
10 packet.h
11 room.h
12 room_member.h
13 )
14
15create_directory_groups(${SRCS} ${HEADERS})
16
17add_library(network STATIC ${SRCS} ${HEADERS})
18target_link_libraries(network PRIVATE common enet)
diff --git a/src/network/network.cpp b/src/network/network.cpp
deleted file mode 100644
index 51b5d6a9f..000000000
--- a/src/network/network.cpp
+++ /dev/null
@@ -1,50 +0,0 @@
1// Copyright 2017 Citra Emulator Project
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#include "common/assert.h"
6#include "common/logging/log.h"
7#include "enet/enet.h"
8#include "network/network.h"
9
10namespace Network {
11
12static std::shared_ptr<RoomMember> g_room_member; ///< RoomMember (Client) for network games
13static std::shared_ptr<Room> g_room; ///< Room (Server) for network games
14// TODO(B3N30): Put these globals into a networking class
15
16bool Init() {
17 if (enet_initialize() != 0) {
18 LOG_ERROR(Network, "Error initalizing ENet");
19 return false;
20 }
21 g_room = std::make_shared<Room>();
22 g_room_member = std::make_shared<RoomMember>();
23 LOG_DEBUG(Network, "initialized OK");
24 return true;
25}
26
27std::weak_ptr<Room> GetRoom() {
28 return g_room;
29}
30
31std::weak_ptr<RoomMember> GetRoomMember() {
32 return g_room_member;
33}
34
35void Shutdown() {
36 if (g_room_member) {
37 if (g_room_member->IsConnected())
38 g_room_member->Leave();
39 g_room_member.reset();
40 }
41 if (g_room) {
42 if (g_room->GetState() == Room::State::Open)
43 g_room->Destroy();
44 g_room.reset();
45 }
46 enet_deinitialize();
47 LOG_DEBUG(Network, "shutdown OK");
48}
49
50} // namespace Network
diff --git a/src/network/network.h b/src/network/network.h
deleted file mode 100644
index 6d002d693..000000000
--- a/src/network/network.h
+++ /dev/null
@@ -1,25 +0,0 @@
1// Copyright 2017 Citra Emulator Project
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#pragma once
6
7#include <memory>
8#include "network/room.h"
9#include "network/room_member.h"
10
11namespace Network {
12
13/// Initializes and registers the network device, the room, and the room member.
14bool Init();
15
16/// Returns a pointer to the room handle
17std::weak_ptr<Room> GetRoom();
18
19/// Returns a pointer to the room member handle
20std::weak_ptr<RoomMember> GetRoomMember();
21
22/// Unregisters the network device, the room, and the room member and shut them down.
23void Shutdown();
24
25} // namespace Network
diff --git a/src/network/packet.cpp b/src/network/packet.cpp
deleted file mode 100644
index 7e1a812f3..000000000
--- a/src/network/packet.cpp
+++ /dev/null
@@ -1,263 +0,0 @@
1// Copyright 2017 Citra Emulator Project
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#ifdef _WIN32
6#include <winsock2.h>
7#else
8#include <arpa/inet.h>
9#endif
10#include <cstring>
11#include <string>
12#include "network/packet.h"
13
14namespace Network {
15
16#ifndef htonll
17u64 htonll(u64 x) {
18 return ((1 == htonl(1)) ? (x) : ((uint64_t)htonl((x)&0xFFFFFFFF) << 32) | htonl((x) >> 32));
19}
20#endif
21
22#ifndef ntohll
23u64 ntohll(u64 x) {
24 return ((1 == ntohl(1)) ? (x) : ((uint64_t)ntohl((x)&0xFFFFFFFF) << 32) | ntohl((x) >> 32));
25}
26#endif
27
28void Packet::Append(const void* in_data, std::size_t size_in_bytes) {
29 if (in_data && (size_in_bytes > 0)) {
30 std::size_t start = data.size();
31 data.resize(start + size_in_bytes);
32 std::memcpy(&data[start], in_data, size_in_bytes);
33 }
34}
35
36void Packet::Read(void* out_data, std::size_t size_in_bytes) {
37 if (out_data && CheckSize(size_in_bytes)) {
38 std::memcpy(out_data, &data[read_pos], size_in_bytes);
39 read_pos += size_in_bytes;
40 }
41}
42
43void Packet::Clear() {
44 data.clear();
45 read_pos = 0;
46 is_valid = true;
47}
48
49const void* Packet::GetData() const {
50 return !data.empty() ? &data[0] : nullptr;
51}
52
53void Packet::IgnoreBytes(u32 length) {
54 read_pos += length;
55}
56
57std::size_t Packet::GetDataSize() const {
58 return data.size();
59}
60
61bool Packet::EndOfPacket() const {
62 return read_pos >= data.size();
63}
64
65Packet::operator bool() const {
66 return is_valid ? &Packet::CheckSize : nullptr;
67}
68
69Packet& Packet::operator>>(bool& out_data) {
70 u8 value;
71 if (*this >> value) {
72 out_data = (value != 0);
73 }
74 return *this;
75}
76
77Packet& Packet::operator>>(s8& out_data) {
78 Read(&out_data, sizeof(out_data));
79 return *this;
80}
81
82Packet& Packet::operator>>(u8& out_data) {
83 Read(&out_data, sizeof(out_data));
84 return *this;
85}
86
87Packet& Packet::operator>>(s16& out_data) {
88 s16 value;
89 Read(&value, sizeof(value));
90 out_data = ntohs(value);
91 return *this;
92}
93
94Packet& Packet::operator>>(u16& out_data) {
95 u16 value;
96 Read(&value, sizeof(value));
97 out_data = ntohs(value);
98 return *this;
99}
100
101Packet& Packet::operator>>(s32& out_data) {
102 s32 value;
103 Read(&value, sizeof(value));
104 out_data = ntohl(value);
105 return *this;
106}
107
108Packet& Packet::operator>>(u32& out_data) {
109 u32 value;
110 Read(&value, sizeof(value));
111 out_data = ntohl(value);
112 return *this;
113}
114
115Packet& Packet::operator>>(s64& out_data) {
116 s64 value;
117 Read(&value, sizeof(value));
118 out_data = ntohll(value);
119 return *this;
120}
121
122Packet& Packet::operator>>(u64& out_data) {
123 u64 value;
124 Read(&value, sizeof(value));
125 out_data = ntohll(value);
126 return *this;
127}
128
129Packet& Packet::operator>>(float& out_data) {
130 Read(&out_data, sizeof(out_data));
131 return *this;
132}
133
134Packet& Packet::operator>>(double& out_data) {
135 Read(&out_data, sizeof(out_data));
136 return *this;
137}
138
139Packet& Packet::operator>>(char* out_data) {
140 // First extract string length
141 u32 length = 0;
142 *this >> length;
143
144 if ((length > 0) && CheckSize(length)) {
145 // Then extract characters
146 std::memcpy(out_data, &data[read_pos], length);
147 out_data[length] = '\0';
148
149 // Update reading position
150 read_pos += length;
151 }
152
153 return *this;
154}
155
156Packet& Packet::operator>>(std::string& out_data) {
157 // First extract string length
158 u32 length = 0;
159 *this >> length;
160
161 out_data.clear();
162 if ((length > 0) && CheckSize(length)) {
163 // Then extract characters
164 out_data.assign(&data[read_pos], length);
165
166 // Update reading position
167 read_pos += length;
168 }
169
170 return *this;
171}
172
173Packet& Packet::operator<<(bool in_data) {
174 *this << static_cast<u8>(in_data);
175 return *this;
176}
177
178Packet& Packet::operator<<(s8 in_data) {
179 Append(&in_data, sizeof(in_data));
180 return *this;
181}
182
183Packet& Packet::operator<<(u8 in_data) {
184 Append(&in_data, sizeof(in_data));
185 return *this;
186}
187
188Packet& Packet::operator<<(s16 in_data) {
189 s16 toWrite = htons(in_data);
190 Append(&toWrite, sizeof(toWrite));
191 return *this;
192}
193
194Packet& Packet::operator<<(u16 in_data) {
195 u16 toWrite = htons(in_data);
196 Append(&toWrite, sizeof(toWrite));
197 return *this;
198}
199
200Packet& Packet::operator<<(s32 in_data) {
201 s32 toWrite = htonl(in_data);
202 Append(&toWrite, sizeof(toWrite));
203 return *this;
204}
205
206Packet& Packet::operator<<(u32 in_data) {
207 u32 toWrite = htonl(in_data);
208 Append(&toWrite, sizeof(toWrite));
209 return *this;
210}
211
212Packet& Packet::operator<<(s64 in_data) {
213 s64 toWrite = htonll(in_data);
214 Append(&toWrite, sizeof(toWrite));
215 return *this;
216}
217
218Packet& Packet::operator<<(u64 in_data) {
219 u64 toWrite = htonll(in_data);
220 Append(&toWrite, sizeof(toWrite));
221 return *this;
222}
223
224Packet& Packet::operator<<(float in_data) {
225 Append(&in_data, sizeof(in_data));
226 return *this;
227}
228
229Packet& Packet::operator<<(double in_data) {
230 Append(&in_data, sizeof(in_data));
231 return *this;
232}
233
234Packet& Packet::operator<<(const char* in_data) {
235 // First insert string length
236 u32 length = static_cast<u32>(std::strlen(in_data));
237 *this << length;
238
239 // Then insert characters
240 Append(in_data, length * sizeof(char));
241
242 return *this;
243}
244
245Packet& Packet::operator<<(const std::string& in_data) {
246 // First insert string length
247 u32 length = static_cast<u32>(in_data.size());
248 *this << length;
249
250 // Then insert characters
251 if (length > 0)
252 Append(in_data.c_str(), length * sizeof(std::string::value_type));
253
254 return *this;
255}
256
257bool Packet::CheckSize(std::size_t size) {
258 is_valid = is_valid && (read_pos + size <= data.size());
259
260 return is_valid;
261}
262
263} // namespace Network
diff --git a/src/network/packet.h b/src/network/packet.h
deleted file mode 100644
index 5a2e58dc2..000000000
--- a/src/network/packet.h
+++ /dev/null
@@ -1,166 +0,0 @@
1// Copyright 2017 Citra Emulator Project
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#pragma once
6
7#include <array>
8#include <vector>
9#include "common/common_types.h"
10
11namespace Network {
12
13/// A class that serializes data for network transfer. It also handles endianess
14class Packet {
15public:
16 Packet() = default;
17 ~Packet() = default;
18
19 /**
20 * Append data to the end of the packet
21 * @param data Pointer to the sequence of bytes to append
22 * @param size_in_bytes Number of bytes to append
23 */
24 void Append(const void* data, std::size_t size_in_bytes);
25
26 /**
27 * Reads data from the current read position of the packet
28 * @param out_data Pointer where the data should get written to
29 * @param size_in_bytes Number of bytes to read
30 */
31 void Read(void* out_data, std::size_t size_in_bytes);
32
33 /**
34 * Clear the packet
35 * After calling Clear, the packet is empty.
36 */
37 void Clear();
38
39 /**
40 * Ignores bytes while reading
41 * @param length THe number of bytes to ignore
42 */
43 void IgnoreBytes(u32 length);
44
45 /**
46 * Get a pointer to the data contained in the packet
47 * @return Pointer to the data
48 */
49 const void* GetData() const;
50
51 /**
52 * This function returns the number of bytes pointed to by
53 * what getData returns.
54 * @return Data size, in bytes
55 */
56 std::size_t GetDataSize() const;
57
58 /**
59 * This function is useful to know if there is some data
60 * left to be read, without actually reading it.
61 * @return True if all data was read, false otherwise
62 */
63 bool EndOfPacket() const;
64
65 explicit operator bool() const;
66
67 /// Overloads of operator >> to read data from the packet
68 Packet& operator>>(bool& out_data);
69 Packet& operator>>(s8& out_data);
70 Packet& operator>>(u8& out_data);
71 Packet& operator>>(s16& out_data);
72 Packet& operator>>(u16& out_data);
73 Packet& operator>>(s32& out_data);
74 Packet& operator>>(u32& out_data);
75 Packet& operator>>(s64& out_data);
76 Packet& operator>>(u64& out_data);
77 Packet& operator>>(float& out_data);
78 Packet& operator>>(double& out_data);
79 Packet& operator>>(char* out_data);
80 Packet& operator>>(std::string& out_data);
81 template <typename T>
82 Packet& operator>>(std::vector<T>& out_data);
83 template <typename T, std::size_t S>
84 Packet& operator>>(std::array<T, S>& out_data);
85
86 /// Overloads of operator << to write data into the packet
87 Packet& operator<<(bool in_data);
88 Packet& operator<<(s8 in_data);
89 Packet& operator<<(u8 in_data);
90 Packet& operator<<(s16 in_data);
91 Packet& operator<<(u16 in_data);
92 Packet& operator<<(s32 in_data);
93 Packet& operator<<(u32 in_data);
94 Packet& operator<<(s64 in_data);
95 Packet& operator<<(u64 in_data);
96 Packet& operator<<(float in_data);
97 Packet& operator<<(double in_data);
98 Packet& operator<<(const char* in_data);
99 Packet& operator<<(const std::string& in_data);
100 template <typename T>
101 Packet& operator<<(const std::vector<T>& in_data);
102 template <typename T, std::size_t S>
103 Packet& operator<<(const std::array<T, S>& data);
104
105private:
106 /**
107 * Check if the packet can extract a given number of bytes
108 * This function updates accordingly the state of the packet.
109 * @param size Size to check
110 * @return True if size bytes can be read from the packet
111 */
112 bool CheckSize(std::size_t size);
113
114 // Member data
115 std::vector<char> data; ///< Data stored in the packet
116 std::size_t read_pos = 0; ///< Current reading position in the packet
117 bool is_valid = true; ///< Reading state of the packet
118};
119
120template <typename T>
121Packet& Packet::operator>>(std::vector<T>& out_data) {
122 // First extract the size
123 u32 size = 0;
124 *this >> size;
125 out_data.resize(size);
126
127 // Then extract the data
128 for (std::size_t i = 0; i < out_data.size(); ++i) {
129 T character = 0;
130 *this >> character;
131 out_data[i] = character;
132 }
133 return *this;
134}
135
136template <typename T, std::size_t S>
137Packet& Packet::operator>>(std::array<T, S>& out_data) {
138 for (std::size_t i = 0; i < out_data.size(); ++i) {
139 T character = 0;
140 *this >> character;
141 out_data[i] = character;
142 }
143 return *this;
144}
145
146template <typename T>
147Packet& Packet::operator<<(const std::vector<T>& in_data) {
148 // First insert the size
149 *this << static_cast<u32>(in_data.size());
150
151 // Then insert the data
152 for (std::size_t i = 0; i < in_data.size(); ++i) {
153 *this << in_data[i];
154 }
155 return *this;
156}
157
158template <typename T, std::size_t S>
159Packet& Packet::operator<<(const std::array<T, S>& in_data) {
160 for (std::size_t i = 0; i < in_data.size(); ++i) {
161 *this << in_data[i];
162 }
163 return *this;
164}
165
166} // namespace Network
diff --git a/src/network/room.cpp b/src/network/room.cpp
deleted file mode 100644
index 261049ab0..000000000
--- a/src/network/room.cpp
+++ /dev/null
@@ -1,497 +0,0 @@
1// Copyright 2017 Citra Emulator Project
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#include <algorithm>
6#include <atomic>
7#include <mutex>
8#include <random>
9#include <thread>
10#include "enet/enet.h"
11#include "network/packet.h"
12#include "network/room.h"
13
14namespace Network {
15
16/// Maximum number of concurrent connections allowed to this room.
17static constexpr u32 MaxConcurrentConnections = 10;
18
19class Room::RoomImpl {
20public:
21 // This MAC address is used to generate a 'Nintendo' like Mac address.
22 const MacAddress NintendoOUI;
23 std::mt19937 random_gen; ///< Random number generator. Used for GenerateMacAddress
24
25 ENetHost* server = nullptr; ///< Network interface.
26
27 std::atomic<State> state{State::Closed}; ///< Current state of the room.
28 RoomInformation room_information; ///< Information about this room.
29
30 struct Member {
31 std::string nickname; ///< The nickname of the member.
32 GameInfo game_info; ///< The current game of the member
33 MacAddress mac_address; ///< The assigned mac address of the member.
34 ENetPeer* peer; ///< The remote peer.
35 };
36 using MemberList = std::vector<Member>;
37 MemberList members; ///< Information about the members of this room
38 mutable std::mutex member_mutex; ///< Mutex for locking the members list
39 /// This should be a std::shared_mutex as soon as C++17 is supported
40
41 RoomImpl()
42 : random_gen(std::random_device()()), NintendoOUI{0x00, 0x1F, 0x32, 0x00, 0x00, 0x00} {}
43
44 /// Thread that receives and dispatches network packets
45 std::unique_ptr<std::thread> room_thread;
46
47 /// Thread function that will receive and dispatch messages until the room is destroyed.
48 void ServerLoop();
49 void StartLoop();
50
51 /**
52 * Parses and answers a room join request from a client.
53 * Validates the uniqueness of the username and assigns the MAC address
54 * that the client will use for the remainder of the connection.
55 */
56 void HandleJoinRequest(const ENetEvent* event);
57
58 /**
59 * Returns whether the nickname is valid, ie. isn't already taken by someone else in the room.
60 */
61 bool IsValidNickname(const std::string& nickname) const;
62
63 /**
64 * Returns whether the MAC address is valid, ie. isn't already taken by someone else in the
65 * room.
66 */
67 bool IsValidMacAddress(const MacAddress& address) const;
68
69 /**
70 * Sends a ID_ROOM_NAME_COLLISION message telling the client that the name is invalid.
71 */
72 void SendNameCollision(ENetPeer* client);
73
74 /**
75 * Sends a ID_ROOM_MAC_COLLISION message telling the client that the MAC is invalid.
76 */
77 void SendMacCollision(ENetPeer* client);
78
79 /**
80 * Sends a ID_ROOM_VERSION_MISMATCH message telling the client that the version is invalid.
81 */
82 void SendVersionMismatch(ENetPeer* client);
83
84 /**
85 * Notifies the member that its connection attempt was successful,
86 * and it is now part of the room.
87 */
88 void SendJoinSuccess(ENetPeer* client, MacAddress mac_address);
89
90 /**
91 * Notifies the members that the room is closed,
92 */
93 void SendCloseMessage();
94
95 /**
96 * Sends the information about the room, along with the list of members
97 * to every connected client in the room.
98 * The packet has the structure:
99 * <MessageID>ID_ROOM_INFORMATION
100 * <String> room_name
101 * <u32> member_slots: The max number of clients allowed in this room
102 * <u32> num_members: the number of currently joined clients
103 * This is followed by the following three values for each member:
104 * <String> nickname of that member
105 * <MacAddress> mac_address of that member
106 * <String> game_name of that member
107 */
108 void BroadcastRoomInformation();
109
110 /**
111 * Generates a free MAC address to assign to a new client.
112 * The first 3 bytes are the NintendoOUI 0x00, 0x1F, 0x32
113 */
114 MacAddress GenerateMacAddress();
115
116 /**
117 * Broadcasts this packet to all members except the sender.
118 * @param event The ENet event containing the data
119 */
120 void HandleWifiPacket(const ENetEvent* event);
121
122 /**
123 * Extracts a chat entry from a received ENet packet and adds it to the chat queue.
124 * @param event The ENet event that was received.
125 */
126 void HandleChatPacket(const ENetEvent* event);
127
128 /**
129 * Extracts the game name from a received ENet packet and broadcasts it.
130 * @param event The ENet event that was received.
131 */
132 void HandleGameNamePacket(const ENetEvent* event);
133
134 /**
135 * Removes the client from the members list if it was in it and announces the change
136 * to all other clients.
137 */
138 void HandleClientDisconnection(ENetPeer* client);
139};
140
141// RoomImpl
142void Room::RoomImpl::ServerLoop() {
143 while (state != State::Closed) {
144 ENetEvent event;
145 if (enet_host_service(server, &event, 100) > 0) {
146 switch (event.type) {
147 case ENET_EVENT_TYPE_RECEIVE:
148 switch (event.packet->data[0]) {
149 case IdJoinRequest:
150 HandleJoinRequest(&event);
151 break;
152 case IdSetGameInfo:
153 HandleGameNamePacket(&event);
154 break;
155 case IdWifiPacket:
156 HandleWifiPacket(&event);
157 break;
158 case IdChatMessage:
159 HandleChatPacket(&event);
160 break;
161 }
162 enet_packet_destroy(event.packet);
163 break;
164 case ENET_EVENT_TYPE_DISCONNECT:
165 HandleClientDisconnection(event.peer);
166 break;
167 }
168 }
169 }
170 // Close the connection to all members:
171 SendCloseMessage();
172}
173
174void Room::RoomImpl::StartLoop() {
175 room_thread = std::make_unique<std::thread>(&Room::RoomImpl::ServerLoop, this);
176}
177
178void Room::RoomImpl::HandleJoinRequest(const ENetEvent* event) {
179 Packet packet;
180 packet.Append(event->packet->data, event->packet->dataLength);
181 packet.IgnoreBytes(sizeof(u8)); // Igonore the message type
182 std::string nickname;
183 packet >> nickname;
184
185 MacAddress preferred_mac;
186 packet >> preferred_mac;
187
188 u32 client_version;
189 packet >> client_version;
190
191 if (!IsValidNickname(nickname)) {
192 SendNameCollision(event->peer);
193 return;
194 }
195
196 if (preferred_mac != NoPreferredMac) {
197 // Verify if the preferred mac is available
198 if (!IsValidMacAddress(preferred_mac)) {
199 SendMacCollision(event->peer);
200 return;
201 }
202 } else {
203 // Assign a MAC address of this client automatically
204 preferred_mac = GenerateMacAddress();
205 }
206
207 if (client_version != network_version) {
208 SendVersionMismatch(event->peer);
209 return;
210 }
211
212 // At this point the client is ready to be added to the room.
213 Member member{};
214 member.mac_address = preferred_mac;
215 member.nickname = nickname;
216 member.peer = event->peer;
217
218 {
219 std::lock_guard<std::mutex> lock(member_mutex);
220 members.push_back(std::move(member));
221 }
222
223 // Notify everyone that the room information has changed.
224 BroadcastRoomInformation();
225 SendJoinSuccess(event->peer, preferred_mac);
226}
227
228bool Room::RoomImpl::IsValidNickname(const std::string& nickname) const {
229 // A nickname is valid if it is not already taken by anybody else in the room.
230 // TODO(B3N30): Check for empty names, spaces, etc.
231 std::lock_guard<std::mutex> lock(member_mutex);
232 return std::all_of(members.begin(), members.end(),
233 [&nickname](const auto& member) { return member.nickname != nickname; });
234}
235
236bool Room::RoomImpl::IsValidMacAddress(const MacAddress& address) const {
237 // A MAC address is valid if it is not already taken by anybody else in the room.
238 std::lock_guard<std::mutex> lock(member_mutex);
239 return std::all_of(members.begin(), members.end(),
240 [&address](const auto& member) { return member.mac_address != address; });
241}
242
243void Room::RoomImpl::SendNameCollision(ENetPeer* client) {
244 Packet packet;
245 packet << static_cast<u8>(IdNameCollision);
246
247 ENetPacket* enet_packet =
248 enet_packet_create(packet.GetData(), packet.GetDataSize(), ENET_PACKET_FLAG_RELIABLE);
249 enet_peer_send(client, 0, enet_packet);
250 enet_host_flush(server);
251}
252
253void Room::RoomImpl::SendMacCollision(ENetPeer* client) {
254 Packet packet;
255 packet << static_cast<u8>(IdMacCollision);
256
257 ENetPacket* enet_packet =
258 enet_packet_create(packet.GetData(), packet.GetDataSize(), ENET_PACKET_FLAG_RELIABLE);
259 enet_peer_send(client, 0, enet_packet);
260 enet_host_flush(server);
261}
262
263void Room::RoomImpl::SendVersionMismatch(ENetPeer* client) {
264 Packet packet;
265 packet << static_cast<u8>(IdVersionMismatch);
266 packet << network_version;
267
268 ENetPacket* enet_packet =
269 enet_packet_create(packet.GetData(), packet.GetDataSize(), ENET_PACKET_FLAG_RELIABLE);
270 enet_peer_send(client, 0, enet_packet);
271 enet_host_flush(server);
272}
273
274void Room::RoomImpl::SendJoinSuccess(ENetPeer* client, MacAddress mac_address) {
275 Packet packet;
276 packet << static_cast<u8>(IdJoinSuccess);
277 packet << mac_address;
278 ENetPacket* enet_packet =
279 enet_packet_create(packet.GetData(), packet.GetDataSize(), ENET_PACKET_FLAG_RELIABLE);
280 enet_peer_send(client, 0, enet_packet);
281 enet_host_flush(server);
282}
283
284void Room::RoomImpl::SendCloseMessage() {
285 Packet packet;
286 packet << static_cast<u8>(IdCloseRoom);
287 ENetPacket* enet_packet =
288 enet_packet_create(packet.GetData(), packet.GetDataSize(), ENET_PACKET_FLAG_RELIABLE);
289 std::lock_guard<std::mutex> lock(member_mutex);
290 for (auto& member : members) {
291 enet_peer_send(member.peer, 0, enet_packet);
292 }
293 enet_host_flush(server);
294 for (auto& member : members) {
295 enet_peer_disconnect(member.peer, 0);
296 }
297}
298
299void Room::RoomImpl::BroadcastRoomInformation() {
300 Packet packet;
301 packet << static_cast<u8>(IdRoomInformation);
302 packet << room_information.name;
303 packet << room_information.member_slots;
304
305 packet << static_cast<u32>(members.size());
306 {
307 std::lock_guard<std::mutex> lock(member_mutex);
308 for (const auto& member : members) {
309 packet << member.nickname;
310 packet << member.mac_address;
311 packet << member.game_info.name;
312 packet << member.game_info.id;
313 }
314 }
315
316 ENetPacket* enet_packet =
317 enet_packet_create(packet.GetData(), packet.GetDataSize(), ENET_PACKET_FLAG_RELIABLE);
318 enet_host_broadcast(server, 0, enet_packet);
319 enet_host_flush(server);
320}
321
322MacAddress Room::RoomImpl::GenerateMacAddress() {
323 MacAddress result_mac =
324 NintendoOUI; // The first three bytes of each MAC address will be the NintendoOUI
325 std::uniform_int_distribution<> dis(0x00, 0xFF); // Random byte between 0 and 0xFF
326 do {
327 for (size_t i = 3; i < result_mac.size(); ++i) {
328 result_mac[i] = dis(random_gen);
329 }
330 } while (!IsValidMacAddress(result_mac));
331 return result_mac;
332}
333
334void Room::RoomImpl::HandleWifiPacket(const ENetEvent* event) {
335 Packet in_packet;
336 in_packet.Append(event->packet->data, event->packet->dataLength);
337 in_packet.IgnoreBytes(sizeof(u8)); // Message type
338 in_packet.IgnoreBytes(sizeof(u8)); // WifiPacket Type
339 in_packet.IgnoreBytes(sizeof(u8)); // WifiPacket Channel
340 in_packet.IgnoreBytes(sizeof(MacAddress)); // WifiPacket Transmitter Address
341 MacAddress destination_address;
342 in_packet >> destination_address;
343
344 Packet out_packet;
345 out_packet.Append(event->packet->data, event->packet->dataLength);
346 ENetPacket* enet_packet = enet_packet_create(out_packet.GetData(), out_packet.GetDataSize(),
347 ENET_PACKET_FLAG_RELIABLE);
348
349 if (destination_address == BroadcastMac) { // Send the data to everyone except the sender
350 std::lock_guard<std::mutex> lock(member_mutex);
351 for (const auto& member : members) {
352 if (member.peer != event->peer)
353 enet_peer_send(member.peer, 0, enet_packet);
354 }
355 } else { // Send the data only to the destination client
356 std::lock_guard<std::mutex> lock(member_mutex);
357 auto member = std::find_if(members.begin(), members.end(),
358 [destination_address](const Member& member) -> bool {
359 return member.mac_address == destination_address;
360 });
361 if (member != members.end()) {
362 enet_peer_send(member->peer, 0, enet_packet);
363 }
364 }
365 enet_host_flush(server);
366}
367
368void Room::RoomImpl::HandleChatPacket(const ENetEvent* event) {
369 Packet in_packet;
370 in_packet.Append(event->packet->data, event->packet->dataLength);
371
372 in_packet.IgnoreBytes(sizeof(u8)); // Igonore the message type
373 std::string message;
374 in_packet >> message;
375 auto CompareNetworkAddress = [event](const Member member) -> bool {
376 return member.peer == event->peer;
377 };
378
379 std::lock_guard<std::mutex> lock(member_mutex);
380 const auto sending_member = std::find_if(members.begin(), members.end(), CompareNetworkAddress);
381 if (sending_member == members.end()) {
382 return; // Received a chat message from a unknown sender
383 }
384
385 Packet out_packet;
386 out_packet << static_cast<u8>(IdChatMessage);
387 out_packet << sending_member->nickname;
388 out_packet << message;
389
390 ENetPacket* enet_packet = enet_packet_create(out_packet.GetData(), out_packet.GetDataSize(),
391 ENET_PACKET_FLAG_RELIABLE);
392 for (const auto& member : members) {
393 if (member.peer != event->peer)
394 enet_peer_send(member.peer, 0, enet_packet);
395 }
396 enet_host_flush(server);
397}
398
399void Room::RoomImpl::HandleGameNamePacket(const ENetEvent* event) {
400 Packet in_packet;
401 in_packet.Append(event->packet->data, event->packet->dataLength);
402
403 in_packet.IgnoreBytes(sizeof(u8)); // Igonore the message type
404 GameInfo game_info;
405 in_packet >> game_info.name;
406 in_packet >> game_info.id;
407
408 {
409 std::lock_guard<std::mutex> lock(member_mutex);
410 auto member =
411 std::find_if(members.begin(), members.end(), [event](const Member& member) -> bool {
412 return member.peer == event->peer;
413 });
414 if (member != members.end()) {
415 member->game_info = game_info;
416 }
417 }
418 BroadcastRoomInformation();
419}
420
421void Room::RoomImpl::HandleClientDisconnection(ENetPeer* client) {
422 // Remove the client from the members list.
423 {
424 std::lock_guard<std::mutex> lock(member_mutex);
425 members.erase(
426 std::remove_if(members.begin(), members.end(),
427 [client](const Member& member) { return member.peer == client; }),
428 members.end());
429 }
430
431 // Announce the change to all clients.
432 enet_peer_disconnect(client, 0);
433 BroadcastRoomInformation();
434}
435
436// Room
437Room::Room() : room_impl{std::make_unique<RoomImpl>()} {}
438
439Room::~Room() = default;
440
441void Room::Create(const std::string& name, const std::string& server_address, u16 server_port) {
442 ENetAddress address;
443 address.host = ENET_HOST_ANY;
444 if (!server_address.empty()) {
445 enet_address_set_host(&address, server_address.c_str());
446 }
447 address.port = server_port;
448
449 room_impl->server = enet_host_create(&address, MaxConcurrentConnections, NumChannels, 0, 0);
450 // TODO(B3N30): Allow specifying the maximum number of concurrent connections.
451 room_impl->state = State::Open;
452
453 room_impl->room_information.name = name;
454 room_impl->room_information.member_slots = MaxConcurrentConnections;
455 room_impl->StartLoop();
456}
457
458Room::State Room::GetState() const {
459 return room_impl->state;
460}
461
462const RoomInformation& Room::GetRoomInformation() const {
463 return room_impl->room_information;
464}
465
466std::vector<Room::Member> Room::GetRoomMemberList() const {
467 std::vector<Room::Member> member_list;
468 std::lock_guard<std::mutex> lock(room_impl->member_mutex);
469 for (const auto& member_impl : room_impl->members) {
470 Member member;
471 member.nickname = member_impl.nickname;
472 member.mac_address = member_impl.mac_address;
473 member.game_info = member_impl.game_info;
474 member_list.push_back(member);
475 }
476 return member_list;
477};
478
479void Room::Destroy() {
480 room_impl->state = State::Closed;
481 room_impl->room_thread->join();
482 room_impl->room_thread.reset();
483
484 if (room_impl->server) {
485 enet_host_destroy(room_impl->server);
486 }
487 room_impl->room_information = {};
488 room_impl->server = nullptr;
489 {
490 std::lock_guard<std::mutex> lock(room_impl->member_mutex);
491 room_impl->members.clear();
492 }
493 room_impl->room_information.member_slots = 0;
494 room_impl->room_information.name.clear();
495}
496
497} // namespace Network
diff --git a/src/network/room.h b/src/network/room.h
deleted file mode 100644
index 8285a4d0c..000000000
--- a/src/network/room.h
+++ /dev/null
@@ -1,101 +0,0 @@
1// Copyright 2017 Citra Emulator Project
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#pragma once
6
7#include <array>
8#include <memory>
9#include <string>
10#include <vector>
11#include "common/common_types.h"
12
13namespace Network {
14
15constexpr u32 network_version = 1; ///< The version of this Room and RoomMember
16
17constexpr u16 DefaultRoomPort = 1234;
18constexpr size_t NumChannels = 1; // Number of channels used for the connection
19
20struct RoomInformation {
21 std::string name; ///< Name of the server
22 u32 member_slots; ///< Maximum number of members in this room
23};
24
25struct GameInfo {
26 std::string name{""};
27 u64 id{0};
28};
29
30using MacAddress = std::array<u8, 6>;
31/// A special MAC address that tells the room we're joining to assign us a MAC address
32/// automatically.
33constexpr MacAddress NoPreferredMac = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF};
34
35// 802.11 broadcast MAC address
36constexpr MacAddress BroadcastMac = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF};
37
38// The different types of messages that can be sent. The first byte of each packet defines the type
39enum RoomMessageTypes : u8 {
40 IdJoinRequest = 1,
41 IdJoinSuccess,
42 IdRoomInformation,
43 IdSetGameInfo,
44 IdWifiPacket,
45 IdChatMessage,
46 IdNameCollision,
47 IdMacCollision,
48 IdVersionMismatch,
49 IdCloseRoom
50};
51
52/// This is what a server [person creating a server] would use.
53class Room final {
54public:
55 enum class State : u8 {
56 Open, ///< The room is open and ready to accept connections.
57 Closed, ///< The room is not opened and can not accept connections.
58 };
59
60 struct Member {
61 std::string nickname; ///< The nickname of the member.
62 GameInfo game_info; ///< The current game of the member
63 MacAddress mac_address; ///< The assigned mac address of the member.
64 };
65
66 Room();
67 ~Room();
68
69 /**
70 * Gets the current state of the room.
71 */
72 State GetState() const;
73
74 /**
75 * Gets the room information of the room.
76 */
77 const RoomInformation& GetRoomInformation() const;
78
79 /**
80 * Gets a list of the mbmers connected to the room.
81 */
82 std::vector<Member> GetRoomMemberList() const;
83
84 /**
85 * Creates the socket for this room. Will bind to default address if
86 * server is empty string.
87 */
88 void Create(const std::string& name, const std::string& server = "",
89 u16 server_port = DefaultRoomPort);
90
91 /**
92 * Destroys the socket
93 */
94 void Destroy();
95
96private:
97 class RoomImpl;
98 std::unique_ptr<RoomImpl> room_impl;
99};
100
101} // namespace Network
diff --git a/src/network/room_member.cpp b/src/network/room_member.cpp
deleted file mode 100644
index f229ec6fd..000000000
--- a/src/network/room_member.cpp
+++ /dev/null
@@ -1,490 +0,0 @@
1// Copyright 2017 Citra Emulator Project
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#include <atomic>
6#include <list>
7#include <mutex>
8#include <set>
9#include <thread>
10#include "common/assert.h"
11#include "enet/enet.h"
12#include "network/packet.h"
13#include "network/room_member.h"
14
15namespace Network {
16
17constexpr u32 ConnectionTimeoutMs = 5000;
18
19class RoomMember::RoomMemberImpl {
20public:
21 ENetHost* client = nullptr; ///< ENet network interface.
22 ENetPeer* server = nullptr; ///< The server peer the client is connected to
23
24 /// Information about the clients connected to the same room as us.
25 MemberList member_information;
26 /// Information about the room we're connected to.
27 RoomInformation room_information;
28
29 /// The current game name, id and version
30 GameInfo current_game_info;
31
32 std::atomic<State> state{State::Idle}; ///< Current state of the RoomMember.
33 void SetState(const State new_state);
34 bool IsConnected() const;
35
36 std::string nickname; ///< The nickname of this member.
37 MacAddress mac_address; ///< The mac_address of this member.
38
39 std::mutex network_mutex; ///< Mutex that controls access to the `client` variable.
40 /// Thread that receives and dispatches network packets
41 std::unique_ptr<std::thread> loop_thread;
42 std::mutex send_list_mutex; ///< Mutex that controls access to the `send_list` variable.
43 std::list<Packet> send_list; ///< A list that stores all packets to send the async
44
45 template <typename T>
46 using CallbackSet = std::set<CallbackHandle<T>>;
47 std::mutex callback_mutex; ///< The mutex used for handling callbacks
48
49 class Callbacks {
50 public:
51 template <typename T>
52 CallbackSet<T>& Get();
53
54 private:
55 CallbackSet<WifiPacket> callback_set_wifi_packet;
56 CallbackSet<ChatEntry> callback_set_chat_messages;
57 CallbackSet<RoomInformation> callback_set_room_information;
58 CallbackSet<State> callback_set_state;
59 };
60 Callbacks callbacks; ///< All CallbackSets to all events
61
62 void MemberLoop();
63
64 void StartLoop();
65
66 /**
67 * Sends data to the room. It will be send on channel 0 with flag RELIABLE
68 * @param packet The data to send
69 */
70 void Send(Packet&& packet);
71
72 /**
73 * Sends a request to the server, asking for permission to join a room with the specified
74 * nickname and preferred mac.
75 * @params nickname The desired nickname.
76 * @params preferred_mac The preferred MAC address to use in the room, the NoPreferredMac tells
77 * the server to assign one for us.
78 */
79 void SendJoinRequest(const std::string& nickname,
80 const MacAddress& preferred_mac = NoPreferredMac);
81
82 /**
83 * Extracts a MAC Address from a received ENet packet.
84 * @param event The ENet event that was received.
85 */
86 void HandleJoinPacket(const ENetEvent* event);
87 /**
88 * Extracts RoomInformation and MemberInformation from a received RakNet packet.
89 * @param event The ENet event that was received.
90 */
91 void HandleRoomInformationPacket(const ENetEvent* event);
92
93 /**
94 * Extracts a WifiPacket from a received ENet packet.
95 * @param event The ENet event that was received.
96 */
97 void HandleWifiPackets(const ENetEvent* event);
98
99 /**
100 * Extracts a chat entry from a received ENet packet and adds it to the chat queue.
101 * @param event The ENet event that was received.
102 */
103 void HandleChatPacket(const ENetEvent* event);
104
105 /**
106 * Disconnects the RoomMember from the Room
107 */
108 void Disconnect();
109
110 template <typename T>
111 void Invoke(const T& data);
112
113 template <typename T>
114 CallbackHandle<T> Bind(std::function<void(const T&)> callback);
115};
116
117// RoomMemberImpl
118void RoomMember::RoomMemberImpl::SetState(const State new_state) {
119 if (state != new_state) {
120 state = new_state;
121 Invoke<State>(state);
122 }
123}
124
125bool RoomMember::RoomMemberImpl::IsConnected() const {
126 return state == State::Joining || state == State::Joined;
127}
128
129void RoomMember::RoomMemberImpl::MemberLoop() {
130 // Receive packets while the connection is open
131 while (IsConnected()) {
132 std::lock_guard<std::mutex> lock(network_mutex);
133 ENetEvent event;
134 if (enet_host_service(client, &event, 100) > 0) {
135 switch (event.type) {
136 case ENET_EVENT_TYPE_RECEIVE:
137 switch (event.packet->data[0]) {
138 case IdWifiPacket:
139 HandleWifiPackets(&event);
140 break;
141 case IdChatMessage:
142 HandleChatPacket(&event);
143 break;
144 case IdRoomInformation:
145 HandleRoomInformationPacket(&event);
146 break;
147 case IdJoinSuccess:
148 // The join request was successful, we are now in the room.
149 // If we joined successfully, there must be at least one client in the room: us.
150 ASSERT_MSG(member_information.size() > 0,
151 "We have not yet received member information.");
152 HandleJoinPacket(&event); // Get the MAC Address for the client
153 SetState(State::Joined);
154 break;
155 case IdNameCollision:
156 SetState(State::NameCollision);
157 break;
158 case IdMacCollision:
159 SetState(State::MacCollision);
160 break;
161 case IdVersionMismatch:
162 SetState(State::WrongVersion);
163 break;
164 case IdCloseRoom:
165 SetState(State::LostConnection);
166 break;
167 }
168 enet_packet_destroy(event.packet);
169 break;
170 case ENET_EVENT_TYPE_DISCONNECT:
171 SetState(State::LostConnection);
172 break;
173 }
174 }
175 {
176 std::lock_guard<std::mutex> lock(send_list_mutex);
177 for (const auto& packet : send_list) {
178 ENetPacket* enetPacket = enet_packet_create(packet.GetData(), packet.GetDataSize(),
179 ENET_PACKET_FLAG_RELIABLE);
180 enet_peer_send(server, 0, enetPacket);
181 }
182 enet_host_flush(client);
183 send_list.clear();
184 }
185 }
186 Disconnect();
187};
188
189void RoomMember::RoomMemberImpl::StartLoop() {
190 loop_thread = std::make_unique<std::thread>(&RoomMember::RoomMemberImpl::MemberLoop, this);
191}
192
193void RoomMember::RoomMemberImpl::Send(Packet&& packet) {
194 std::lock_guard<std::mutex> lock(send_list_mutex);
195 send_list.push_back(std::move(packet));
196}
197
198void RoomMember::RoomMemberImpl::SendJoinRequest(const std::string& nickname,
199 const MacAddress& preferred_mac) {
200 Packet packet;
201 packet << static_cast<u8>(IdJoinRequest);
202 packet << nickname;
203 packet << preferred_mac;
204 packet << network_version;
205 Send(std::move(packet));
206}
207
208void RoomMember::RoomMemberImpl::HandleRoomInformationPacket(const ENetEvent* event) {
209 Packet packet;
210 packet.Append(event->packet->data, event->packet->dataLength);
211
212 // Ignore the first byte, which is the message id.
213 packet.IgnoreBytes(sizeof(u8)); // Igonore the message type
214
215 RoomInformation info{};
216 packet >> info.name;
217 packet >> info.member_slots;
218 room_information.name = info.name;
219 room_information.member_slots = info.member_slots;
220
221 u32 num_members;
222 packet >> num_members;
223 member_information.resize(num_members);
224
225 for (auto& member : member_information) {
226 packet >> member.nickname;
227 packet >> member.mac_address;
228 packet >> member.game_info.name;
229 packet >> member.game_info.id;
230 }
231 Invoke(room_information);
232}
233
234void RoomMember::RoomMemberImpl::HandleJoinPacket(const ENetEvent* event) {
235 Packet packet;
236 packet.Append(event->packet->data, event->packet->dataLength);
237
238 // Ignore the first byte, which is the message id.
239 packet.IgnoreBytes(sizeof(u8)); // Igonore the message type
240
241 // Parse the MAC Address from the packet
242 packet >> mac_address;
243 SetState(State::Joined);
244}
245
246void RoomMember::RoomMemberImpl::HandleWifiPackets(const ENetEvent* event) {
247 WifiPacket wifi_packet{};
248 Packet packet;
249 packet.Append(event->packet->data, event->packet->dataLength);
250
251 // Ignore the first byte, which is the message id.
252 packet.IgnoreBytes(sizeof(u8)); // Igonore the message type
253
254 // Parse the WifiPacket from the packet
255 u8 frame_type;
256 packet >> frame_type;
257 WifiPacket::PacketType type = static_cast<WifiPacket::PacketType>(frame_type);
258
259 wifi_packet.type = type;
260 packet >> wifi_packet.channel;
261 packet >> wifi_packet.transmitter_address;
262 packet >> wifi_packet.destination_address;
263
264 u32 data_length;
265 packet >> data_length;
266
267 packet >> wifi_packet.data;
268
269 Invoke<WifiPacket>(wifi_packet);
270}
271
272void RoomMember::RoomMemberImpl::HandleChatPacket(const ENetEvent* event) {
273 Packet packet;
274 packet.Append(event->packet->data, event->packet->dataLength);
275
276 // Ignore the first byte, which is the message id.
277 packet.IgnoreBytes(sizeof(u8));
278
279 ChatEntry chat_entry{};
280 packet >> chat_entry.nickname;
281 packet >> chat_entry.message;
282 Invoke<ChatEntry>(chat_entry);
283}
284
285void RoomMember::RoomMemberImpl::Disconnect() {
286 member_information.clear();
287 room_information.member_slots = 0;
288 room_information.name.clear();
289
290 if (!server)
291 return;
292 enet_peer_disconnect(server, 0);
293
294 ENetEvent event;
295 while (enet_host_service(client, &event, ConnectionTimeoutMs) > 0) {
296 switch (event.type) {
297 case ENET_EVENT_TYPE_RECEIVE:
298 enet_packet_destroy(event.packet); // Ignore all incoming data
299 break;
300 case ENET_EVENT_TYPE_DISCONNECT:
301 server = nullptr;
302 return;
303 }
304 }
305 // didn't disconnect gracefully force disconnect
306 enet_peer_reset(server);
307 server = nullptr;
308}
309
310template <>
311RoomMember::RoomMemberImpl::CallbackSet<WifiPacket>& RoomMember::RoomMemberImpl::Callbacks::Get() {
312 return callback_set_wifi_packet;
313}
314
315template <>
316RoomMember::RoomMemberImpl::CallbackSet<RoomMember::State>&
317RoomMember::RoomMemberImpl::Callbacks::Get() {
318 return callback_set_state;
319}
320
321template <>
322RoomMember::RoomMemberImpl::CallbackSet<RoomInformation>&
323RoomMember::RoomMemberImpl::Callbacks::Get() {
324 return callback_set_room_information;
325}
326
327template <>
328RoomMember::RoomMemberImpl::CallbackSet<ChatEntry>& RoomMember::RoomMemberImpl::Callbacks::Get() {
329 return callback_set_chat_messages;
330}
331
332template <typename T>
333void RoomMember::RoomMemberImpl::Invoke(const T& data) {
334 std::lock_guard<std::mutex> lock(callback_mutex);
335 CallbackSet<T> callback_set = callbacks.Get<T>();
336 for (auto const& callback : callback_set)
337 (*callback)(data);
338}
339
340template <typename T>
341RoomMember::CallbackHandle<T> RoomMember::RoomMemberImpl::Bind(
342 std::function<void(const T&)> callback) {
343 std::lock_guard<std::mutex> lock(callback_mutex);
344 CallbackHandle<T> handle;
345 handle = std::make_shared<std::function<void(const T&)>>(callback);
346 callbacks.Get<T>().insert(handle);
347 return handle;
348}
349
350// RoomMember
351RoomMember::RoomMember() : room_member_impl{std::make_unique<RoomMemberImpl>()} {
352 room_member_impl->client = enet_host_create(nullptr, 1, NumChannels, 0, 0);
353 ASSERT_MSG(room_member_impl->client != nullptr, "Could not create client");
354}
355
356RoomMember::~RoomMember() {
357 ASSERT_MSG(!IsConnected(), "RoomMember is being destroyed while connected");
358 enet_host_destroy(room_member_impl->client);
359}
360
361RoomMember::State RoomMember::GetState() const {
362 return room_member_impl->state;
363}
364
365const RoomMember::MemberList& RoomMember::GetMemberInformation() const {
366 return room_member_impl->member_information;
367}
368
369const std::string& RoomMember::GetNickname() const {
370 return room_member_impl->nickname;
371}
372
373const MacAddress& RoomMember::GetMacAddress() const {
374 ASSERT_MSG(IsConnected(), "Tried to get MAC address while not connected");
375 return room_member_impl->mac_address;
376}
377
378RoomInformation RoomMember::GetRoomInformation() const {
379 return room_member_impl->room_information;
380}
381
382void RoomMember::Join(const std::string& nick, const char* server_addr, u16 server_port,
383 u16 client_port, const MacAddress& preferred_mac) {
384 // If the member is connected, kill the connection first
385 if (room_member_impl->loop_thread && room_member_impl->loop_thread->joinable()) {
386 room_member_impl->SetState(State::Error);
387 room_member_impl->loop_thread->join();
388 room_member_impl->loop_thread.reset();
389 }
390 // If the thread isn't running but the ptr still exists, reset it
391 else if (room_member_impl->loop_thread) {
392 room_member_impl->loop_thread.reset();
393 }
394
395 ENetAddress address{};
396 enet_address_set_host(&address, server_addr);
397 address.port = server_port;
398 room_member_impl->server =
399 enet_host_connect(room_member_impl->client, &address, NumChannels, 0);
400
401 if (!room_member_impl->server) {
402 room_member_impl->SetState(State::Error);
403 return;
404 }
405
406 ENetEvent event{};
407 int net = enet_host_service(room_member_impl->client, &event, ConnectionTimeoutMs);
408 if (net > 0 && event.type == ENET_EVENT_TYPE_CONNECT) {
409 room_member_impl->nickname = nick;
410 room_member_impl->SetState(State::Joining);
411 room_member_impl->StartLoop();
412 room_member_impl->SendJoinRequest(nick, preferred_mac);
413 SendGameInfo(room_member_impl->current_game_info);
414 } else {
415 room_member_impl->SetState(State::CouldNotConnect);
416 }
417}
418
419bool RoomMember::IsConnected() const {
420 return room_member_impl->IsConnected();
421}
422
423void RoomMember::SendWifiPacket(const WifiPacket& wifi_packet) {
424 Packet packet;
425 packet << static_cast<u8>(IdWifiPacket);
426 packet << static_cast<u8>(wifi_packet.type);
427 packet << wifi_packet.channel;
428 packet << wifi_packet.transmitter_address;
429 packet << wifi_packet.destination_address;
430 packet << wifi_packet.data;
431 room_member_impl->Send(std::move(packet));
432}
433
434void RoomMember::SendChatMessage(const std::string& message) {
435 Packet packet;
436 packet << static_cast<u8>(IdChatMessage);
437 packet << message;
438 room_member_impl->Send(std::move(packet));
439}
440
441void RoomMember::SendGameInfo(const GameInfo& game_info) {
442 room_member_impl->current_game_info = game_info;
443 if (!IsConnected())
444 return;
445
446 Packet packet;
447 packet << static_cast<u8>(IdSetGameInfo);
448 packet << game_info.name;
449 packet << game_info.id;
450 room_member_impl->Send(std::move(packet));
451}
452
453RoomMember::CallbackHandle<RoomMember::State> RoomMember::BindOnStateChanged(
454 std::function<void(const RoomMember::State&)> callback) {
455 return room_member_impl->Bind(callback);
456}
457
458RoomMember::CallbackHandle<WifiPacket> RoomMember::BindOnWifiPacketReceived(
459 std::function<void(const WifiPacket&)> callback) {
460 return room_member_impl->Bind(callback);
461}
462
463RoomMember::CallbackHandle<RoomInformation> RoomMember::BindOnRoomInformationChanged(
464 std::function<void(const RoomInformation&)> callback) {
465 return room_member_impl->Bind(callback);
466}
467
468RoomMember::CallbackHandle<ChatEntry> RoomMember::BindOnChatMessageRecieved(
469 std::function<void(const ChatEntry&)> callback) {
470 return room_member_impl->Bind(callback);
471}
472
473template <typename T>
474void RoomMember::Unbind(CallbackHandle<T> handle) {
475 std::lock_guard<std::mutex> lock(room_member_impl->callback_mutex);
476 room_member_impl->callbacks.Get<T>().erase(handle);
477}
478
479void RoomMember::Leave() {
480 room_member_impl->SetState(State::Idle);
481 room_member_impl->loop_thread->join();
482 room_member_impl->loop_thread.reset();
483}
484
485template void RoomMember::Unbind(CallbackHandle<WifiPacket>);
486template void RoomMember::Unbind(CallbackHandle<RoomMember::State>);
487template void RoomMember::Unbind(CallbackHandle<RoomInformation>);
488template void RoomMember::Unbind(CallbackHandle<ChatEntry>);
489
490} // namespace Network
diff --git a/src/network/room_member.h b/src/network/room_member.h
deleted file mode 100644
index 98770a234..000000000
--- a/src/network/room_member.h
+++ /dev/null
@@ -1,182 +0,0 @@
1// Copyright 2017 Citra Emulator Project
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#pragma once
6
7#include <functional>
8#include <memory>
9#include <string>
10#include <vector>
11#include "common/common_types.h"
12#include "network/room.h"
13
14namespace Network {
15
16/// Information about the received WiFi packets.
17/// Acts as our own 802.11 header.
18struct WifiPacket {
19 enum class PacketType : u8 { Beacon, Data, Authentication, AssociationResponse };
20 PacketType type; ///< The type of 802.11 frame.
21 std::vector<u8> data; ///< Raw 802.11 frame data, starting at the management frame header
22 /// for management frames.
23 MacAddress transmitter_address; ///< Mac address of the transmitter.
24 MacAddress destination_address; ///< Mac address of the receiver.
25 u8 channel; ///< WiFi channel where this frame was transmitted.
26};
27
28/// Represents a chat message.
29struct ChatEntry {
30 std::string nickname; ///< Nickname of the client who sent this message.
31 std::string message; ///< Body of the message.
32};
33
34/**
35 * This is what a client [person joining a server] would use.
36 * It also has to be used if you host a game yourself (You'd create both, a Room and a
37 * RoomMembership for yourself)
38 */
39class RoomMember final {
40public:
41 enum class State : u8 {
42 Idle, ///< Default state
43 Error, ///< Some error [permissions to network device missing or something]
44 Joining, ///< The client is attempting to join a room.
45 Joined, ///< The client is connected to the room and is ready to send/receive packets.
46 LostConnection, ///< Connection closed
47
48 // Reasons why connection was rejected
49 NameCollision, ///< Somebody is already using this name
50 MacCollision, ///< Somebody is already using that mac-address
51 WrongVersion, ///< The room version is not the same as for this RoomMember
52 CouldNotConnect ///< The room is not responding to a connection attempt
53 };
54
55 struct MemberInformation {
56 std::string nickname; ///< Nickname of the member.
57 GameInfo game_info; ///< Name of the game they're currently playing, or empty if they're
58 /// not playing anything.
59 MacAddress mac_address; ///< MAC address associated with this member.
60 };
61 using MemberList = std::vector<MemberInformation>;
62
63 // The handle for the callback functions
64 template <typename T>
65 using CallbackHandle = std::shared_ptr<std::function<void(const T&)>>;
66
67 /**
68 * Unbinds a callback function from the events.
69 * @param handle The connection handle to disconnect
70 */
71 template <typename T>
72 void Unbind(CallbackHandle<T> handle);
73
74 RoomMember();
75 ~RoomMember();
76
77 /**
78 * Returns the status of our connection to the room.
79 */
80 State GetState() const;
81
82 /**
83 * Returns information about the members in the room we're currently connected to.
84 */
85 const MemberList& GetMemberInformation() const;
86
87 /**
88 * Returns the nickname of the RoomMember.
89 */
90 const std::string& GetNickname() const;
91
92 /**
93 * Returns the MAC address of the RoomMember.
94 */
95 const MacAddress& GetMacAddress() const;
96
97 /**
98 * Returns information about the room we're currently connected to.
99 */
100 RoomInformation GetRoomInformation() const;
101
102 /**
103 * Returns whether we're connected to a server or not.
104 */
105 bool IsConnected() const;
106
107 /**
108 * Attempts to join a room at the specified address and port, using the specified nickname.
109 * This may fail if the username is already taken.
110 */
111 void Join(const std::string& nickname, const char* server_addr = "127.0.0.1",
112 const u16 serverPort = DefaultRoomPort, const u16 clientPort = 0,
113 const MacAddress& preferred_mac = NoPreferredMac);
114
115 /**
116 * Sends a WiFi packet to the room.
117 * @param packet The WiFi packet to send.
118 */
119 void SendWifiPacket(const WifiPacket& packet);
120
121 /**
122 * Sends a chat message to the room.
123 * @param message The contents of the message.
124 */
125 void SendChatMessage(const std::string& message);
126
127 /**
128 * Sends the current game info to the room.
129 * @param game_info The game information.
130 */
131 void SendGameInfo(const GameInfo& game_info);
132
133 /**
134 * Binds a function to an event that will be triggered every time the State of the member
135 * changed. The function wil be called every time the event is triggered. The callback function
136 * must not bind or unbind a function. Doing so will cause a deadlock
137 * @param callback The function to call
138 * @return A handle used for removing the function from the registered list
139 */
140 CallbackHandle<State> BindOnStateChanged(std::function<void(const State&)> callback);
141
142 /**
143 * Binds a function to an event that will be triggered every time a WifiPacket is received.
144 * The function wil be called everytime the event is triggered.
145 * The callback function must not bind or unbind a function. Doing so will cause a deadlock
146 * @param callback The function to call
147 * @return A handle used for removing the function from the registered list
148 */
149 CallbackHandle<WifiPacket> BindOnWifiPacketReceived(
150 std::function<void(const WifiPacket&)> callback);
151
152 /**
153 * Binds a function to an event that will be triggered every time the RoomInformation changes.
154 * The function wil be called every time the event is triggered.
155 * The callback function must not bind or unbind a function. Doing so will cause a deadlock
156 * @param callback The function to call
157 * @return A handle used for removing the function from the registered list
158 */
159 CallbackHandle<RoomInformation> BindOnRoomInformationChanged(
160 std::function<void(const RoomInformation&)> callback);
161
162 /**
163 * Binds a function to an event that will be triggered every time a ChatMessage is received.
164 * The function wil be called every time the event is triggered.
165 * The callback function must not bind or unbind a function. Doing so will cause a deadlock
166 * @param callback The function to call
167 * @return A handle used for removing the function from the registered list
168 */
169 CallbackHandle<ChatEntry> BindOnChatMessageRecieved(
170 std::function<void(const ChatEntry&)> callback);
171
172 /**
173 * Leaves the current room.
174 */
175 void Leave();
176
177private:
178 class RoomMemberImpl;
179 std::unique_ptr<RoomMemberImpl> room_member_impl;
180};
181
182} // namespace Network
diff --git a/src/web_service/CMakeLists.txt b/src/web_service/CMakeLists.txt
deleted file mode 100644
index c93811892..000000000
--- a/src/web_service/CMakeLists.txt
+++ /dev/null
@@ -1,16 +0,0 @@
1set(SRCS
2 telemetry_json.cpp
3 verify_login.cpp
4 web_backend.cpp
5 )
6
7set(HEADERS
8 telemetry_json.h
9 verify_login.h
10 web_backend.h
11 )
12
13create_directory_groups(${SRCS} ${HEADERS})
14
15add_library(web_service STATIC ${SRCS} ${HEADERS})
16target_link_libraries(web_service PUBLIC common cpr json-headers)
diff --git a/src/web_service/telemetry_json.cpp b/src/web_service/telemetry_json.cpp
deleted file mode 100644
index 6ad2ffcd4..000000000
--- a/src/web_service/telemetry_json.cpp
+++ /dev/null
@@ -1,86 +0,0 @@
1// Copyright 2017 Citra Emulator Project
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#include "common/assert.h"
6#include "web_service/telemetry_json.h"
7#include "web_service/web_backend.h"
8
9namespace WebService {
10
11template <class T>
12void TelemetryJson::Serialize(Telemetry::FieldType type, const std::string& name, T value) {
13 sections[static_cast<u8>(type)][name] = value;
14}
15
16void TelemetryJson::SerializeSection(Telemetry::FieldType type, const std::string& name) {
17 TopSection()[name] = sections[static_cast<unsigned>(type)];
18}
19
20void TelemetryJson::Visit(const Telemetry::Field<bool>& field) {
21 Serialize(field.GetType(), field.GetName(), field.GetValue());
22}
23
24void TelemetryJson::Visit(const Telemetry::Field<double>& field) {
25 Serialize(field.GetType(), field.GetName(), field.GetValue());
26}
27
28void TelemetryJson::Visit(const Telemetry::Field<float>& field) {
29 Serialize(field.GetType(), field.GetName(), field.GetValue());
30}
31
32void TelemetryJson::Visit(const Telemetry::Field<u8>& field) {
33 Serialize(field.GetType(), field.GetName(), field.GetValue());
34}
35
36void TelemetryJson::Visit(const Telemetry::Field<u16>& field) {
37 Serialize(field.GetType(), field.GetName(), field.GetValue());
38}
39
40void TelemetryJson::Visit(const Telemetry::Field<u32>& field) {
41 Serialize(field.GetType(), field.GetName(), field.GetValue());
42}
43
44void TelemetryJson::Visit(const Telemetry::Field<u64>& field) {
45 Serialize(field.GetType(), field.GetName(), field.GetValue());
46}
47
48void TelemetryJson::Visit(const Telemetry::Field<s8>& field) {
49 Serialize(field.GetType(), field.GetName(), field.GetValue());
50}
51
52void TelemetryJson::Visit(const Telemetry::Field<s16>& field) {
53 Serialize(field.GetType(), field.GetName(), field.GetValue());
54}
55
56void TelemetryJson::Visit(const Telemetry::Field<s32>& field) {
57 Serialize(field.GetType(), field.GetName(), field.GetValue());
58}
59
60void TelemetryJson::Visit(const Telemetry::Field<s64>& field) {
61 Serialize(field.GetType(), field.GetName(), field.GetValue());
62}
63
64void TelemetryJson::Visit(const Telemetry::Field<std::string>& field) {
65 Serialize(field.GetType(), field.GetName(), field.GetValue());
66}
67
68void TelemetryJson::Visit(const Telemetry::Field<const char*>& field) {
69 Serialize(field.GetType(), field.GetName(), std::string(field.GetValue()));
70}
71
72void TelemetryJson::Visit(const Telemetry::Field<std::chrono::microseconds>& field) {
73 Serialize(field.GetType(), field.GetName(), field.GetValue().count());
74}
75
76void TelemetryJson::Complete() {
77 SerializeSection(Telemetry::FieldType::App, "App");
78 SerializeSection(Telemetry::FieldType::Session, "Session");
79 SerializeSection(Telemetry::FieldType::Performance, "Performance");
80 SerializeSection(Telemetry::FieldType::UserFeedback, "UserFeedback");
81 SerializeSection(Telemetry::FieldType::UserConfig, "UserConfig");
82 SerializeSection(Telemetry::FieldType::UserSystem, "UserSystem");
83 PostJson(endpoint_url, TopSection().dump(), true, username, token);
84}
85
86} // namespace WebService
diff --git a/src/web_service/telemetry_json.h b/src/web_service/telemetry_json.h
deleted file mode 100644
index 9e78c6803..000000000
--- a/src/web_service/telemetry_json.h
+++ /dev/null
@@ -1,59 +0,0 @@
1// Copyright 2017 Citra Emulator Project
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#pragma once
6
7#include <array>
8#include <string>
9#include <json.hpp>
10#include "common/telemetry.h"
11
12namespace WebService {
13
14/**
15 * Implementation of VisitorInterface that serialized telemetry into JSON, and submits it to the
16 * Citra web service
17 */
18class TelemetryJson : public Telemetry::VisitorInterface {
19public:
20 TelemetryJson(const std::string& endpoint_url, const std::string& username,
21 const std::string& token)
22 : endpoint_url(endpoint_url), username(username), token(token) {}
23 ~TelemetryJson() = default;
24
25 void Visit(const Telemetry::Field<bool>& field) override;
26 void Visit(const Telemetry::Field<double>& field) override;
27 void Visit(const Telemetry::Field<float>& field) override;
28 void Visit(const Telemetry::Field<u8>& field) override;
29 void Visit(const Telemetry::Field<u16>& field) override;
30 void Visit(const Telemetry::Field<u32>& field) override;
31 void Visit(const Telemetry::Field<u64>& field) override;
32 void Visit(const Telemetry::Field<s8>& field) override;
33 void Visit(const Telemetry::Field<s16>& field) override;
34 void Visit(const Telemetry::Field<s32>& field) override;
35 void Visit(const Telemetry::Field<s64>& field) override;
36 void Visit(const Telemetry::Field<std::string>& field) override;
37 void Visit(const Telemetry::Field<const char*>& field) override;
38 void Visit(const Telemetry::Field<std::chrono::microseconds>& field) override;
39
40 void Complete() override;
41
42private:
43 nlohmann::json& TopSection() {
44 return sections[static_cast<u8>(Telemetry::FieldType::None)];
45 }
46
47 template <class T>
48 void Serialize(Telemetry::FieldType type, const std::string& name, T value);
49
50 void SerializeSection(Telemetry::FieldType type, const std::string& name);
51
52 nlohmann::json output;
53 std::array<nlohmann::json, 7> sections;
54 std::string endpoint_url;
55 std::string username;
56 std::string token;
57};
58
59} // namespace WebService
diff --git a/src/web_service/verify_login.cpp b/src/web_service/verify_login.cpp
deleted file mode 100644
index 1bc3b5afe..000000000
--- a/src/web_service/verify_login.cpp
+++ /dev/null
@@ -1,28 +0,0 @@
1// Copyright 2017 Citra Emulator Project
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#include <json.hpp>
6#include "web_service/verify_login.h"
7#include "web_service/web_backend.h"
8
9namespace WebService {
10
11std::future<bool> VerifyLogin(std::string& username, std::string& token,
12 const std::string& endpoint_url, std::function<void()> func) {
13 auto get_func = [func, username](const std::string& reply) -> bool {
14 func();
15 if (reply.empty())
16 return false;
17 nlohmann::json json = nlohmann::json::parse(reply);
18 std::string result;
19 try {
20 result = json["username"];
21 } catch (const nlohmann::detail::out_of_range&) {
22 }
23 return result == username;
24 };
25 return GetJson<bool>(get_func, endpoint_url, false, username, token);
26}
27
28} // namespace WebService
diff --git a/src/web_service/verify_login.h b/src/web_service/verify_login.h
deleted file mode 100644
index 303f5dbbc..000000000
--- a/src/web_service/verify_login.h
+++ /dev/null
@@ -1,24 +0,0 @@
1// Copyright 2017 Citra Emulator Project
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#pragma once
6
7#include <functional>
8#include <future>
9#include <string>
10
11namespace WebService {
12
13/**
14 * Checks if username and token is valid
15 * @param username Citra username to use for authentication.
16 * @param token Citra token to use for authentication.
17 * @param endpoint_url URL of the services.citra-emu.org endpoint.
18 * @param func A function that gets exectued when the verification is finished
19 * @returns Future with bool indicating whether the verification succeeded
20 */
21std::future<bool> VerifyLogin(std::string& username, std::string& token,
22 const std::string& endpoint_url, std::function<void()> func);
23
24} // namespace WebService
diff --git a/src/web_service/web_backend.cpp b/src/web_service/web_backend.cpp
deleted file mode 100644
index b17d82f9c..000000000
--- a/src/web_service/web_backend.cpp
+++ /dev/null
@@ -1,140 +0,0 @@
1// Copyright 2017 Citra Emulator Project
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#ifdef _WIN32
6#include <winsock.h>
7#endif
8
9#include <cstdlib>
10#include <thread>
11#include <cpr/cpr.h>
12#include "common/logging/log.h"
13#include "web_service/web_backend.h"
14
15namespace WebService {
16
17static constexpr char API_VERSION[]{"1"};
18
19static std::unique_ptr<cpr::Session> g_session;
20
21void Win32WSAStartup() {
22#ifdef _WIN32
23 // On Windows, CPR/libcurl does not properly initialize Winsock. The below code is used to
24 // initialize Winsock globally, which fixes this problem. Without this, only the first CPR
25 // session will properly be created, and subsequent ones will fail.
26 WSADATA wsa_data;
27 const int wsa_result{WSAStartup(MAKEWORD(2, 2), &wsa_data)};
28 if (wsa_result) {
29 LOG_CRITICAL(WebService, "WSAStartup failed: %d", wsa_result);
30 }
31#endif
32}
33
34void PostJson(const std::string& url, const std::string& data, bool allow_anonymous,
35 const std::string& username, const std::string& token) {
36 if (url.empty()) {
37 LOG_ERROR(WebService, "URL is invalid");
38 return;
39 }
40
41 const bool are_credentials_provided{!token.empty() && !username.empty()};
42 if (!allow_anonymous && !are_credentials_provided) {
43 LOG_ERROR(WebService, "Credentials must be provided for authenticated requests");
44 return;
45 }
46
47 Win32WSAStartup();
48
49 // Built request header
50 cpr::Header header;
51 if (are_credentials_provided) {
52 // Authenticated request if credentials are provided
53 header = {{"Content-Type", "application/json"},
54 {"x-username", username.c_str()},
55 {"x-token", token.c_str()},
56 {"api-version", API_VERSION}};
57 } else {
58 // Otherwise, anonymous request
59 header = cpr::Header{{"Content-Type", "application/json"}, {"api-version", API_VERSION}};
60 }
61
62 // Post JSON asynchronously
63 static std::future<void> future;
64 future = cpr::PostCallback(
65 [](cpr::Response r) {
66 if (r.error) {
67 LOG_ERROR(WebService, "POST returned cpr error: %u:%s",
68 static_cast<u32>(r.error.code), r.error.message.c_str());
69 return;
70 }
71 if (r.status_code >= 400) {
72 LOG_ERROR(WebService, "POST returned error status code: %u", r.status_code);
73 return;
74 }
75 if (r.header["content-type"].find("application/json") == std::string::npos) {
76 LOG_ERROR(WebService, "POST returned wrong content: %s",
77 r.header["content-type"].c_str());
78 return;
79 }
80 },
81 cpr::Url{url}, cpr::Body{data}, header);
82}
83
84template <typename T>
85std::future<T> GetJson(std::function<T(const std::string&)> func, const std::string& url,
86 bool allow_anonymous, const std::string& username,
87 const std::string& token) {
88 if (url.empty()) {
89 LOG_ERROR(WebService, "URL is invalid");
90 return std::async(std::launch::async, [func{std::move(func)}]() { return func(""); });
91 }
92
93 const bool are_credentials_provided{!token.empty() && !username.empty()};
94 if (!allow_anonymous && !are_credentials_provided) {
95 LOG_ERROR(WebService, "Credentials must be provided for authenticated requests");
96 return std::async(std::launch::async, [func{std::move(func)}]() { return func(""); });
97 }
98
99 Win32WSAStartup();
100
101 // Built request header
102 cpr::Header header;
103 if (are_credentials_provided) {
104 // Authenticated request if credentials are provided
105 header = {{"Content-Type", "application/json"},
106 {"x-username", username.c_str()},
107 {"x-token", token.c_str()},
108 {"api-version", API_VERSION}};
109 } else {
110 // Otherwise, anonymous request
111 header = cpr::Header{{"Content-Type", "application/json"}, {"api-version", API_VERSION}};
112 }
113
114 // Get JSON asynchronously
115 return cpr::GetCallback(
116 [func{std::move(func)}](cpr::Response r) {
117 if (r.error) {
118 LOG_ERROR(WebService, "GET returned cpr error: %u:%s",
119 static_cast<u32>(r.error.code), r.error.message.c_str());
120 return func("");
121 }
122 if (r.status_code >= 400) {
123 LOG_ERROR(WebService, "GET returned error code: %u", r.status_code);
124 return func("");
125 }
126 if (r.header["content-type"].find("application/json") == std::string::npos) {
127 LOG_ERROR(WebService, "GET returned wrong content: %s",
128 r.header["content-type"].c_str());
129 return func("");
130 }
131 return func(r.text);
132 },
133 cpr::Url{url}, header);
134}
135
136template std::future<bool> GetJson(std::function<bool(const std::string&)> func,
137 const std::string& url, bool allow_anonymous,
138 const std::string& username, const std::string& token);
139
140} // namespace WebService
diff --git a/src/web_service/web_backend.h b/src/web_service/web_backend.h
deleted file mode 100644
index a63c75d13..000000000
--- a/src/web_service/web_backend.h
+++ /dev/null
@@ -1,39 +0,0 @@
1// Copyright 2017 Citra Emulator Project
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#pragma once
6
7#include <functional>
8#include <future>
9#include <string>
10#include "common/common_types.h"
11
12namespace WebService {
13
14/**
15 * Posts JSON to services.citra-emu.org.
16 * @param url URL of the services.citra-emu.org endpoint to post data to.
17 * @param data String of JSON data to use for the body of the POST request.
18 * @param allow_anonymous If true, allow anonymous unauthenticated requests.
19 * @param username Citra username to use for authentication.
20 * @param token Citra token to use for authentication.
21 */
22void PostJson(const std::string& url, const std::string& data, bool allow_anonymous,
23 const std::string& username = {}, const std::string& token = {});
24
25/**
26 * Gets JSON from services.citra-emu.org.
27 * @param func A function that gets exectued when the json as a string is received
28 * @param url URL of the services.citra-emu.org endpoint to post data to.
29 * @param allow_anonymous If true, allow anonymous unauthenticated requests.
30 * @param username Citra username to use for authentication.
31 * @param token Citra token to use for authentication.
32 * @return future that holds the return value T of the func
33 */
34template <typename T>
35std::future<T> GetJson(std::function<T(const std::string&)> func, const std::string& url,
36 bool allow_anonymous, const std::string& username = {},
37 const std::string& token = {});
38
39} // namespace WebService
diff --git a/src/citra_qt/CMakeLists.txt b/src/yuzu/CMakeLists.txt
index e2fa33081..38bbc0043 100644
--- a/src/citra_qt/CMakeLists.txt
+++ b/src/yuzu/CMakeLists.txt
@@ -79,7 +79,7 @@ set(UIS
79 main.ui 79 main.ui
80 ) 80 )
81 81
82file(GLOB_RECURSE ICONS ${CMAKE_SOURCE_DIR}/dist/icons/*) 82# file(GLOB_RECURSE ICONS ${CMAKE_SOURCE_DIR}/dist/icons/*)
83file(GLOB_RECURSE THEMES ${CMAKE_SOURCE_DIR}/dist/qt_themes/*) 83file(GLOB_RECURSE THEMES ${CMAKE_SOURCE_DIR}/dist/qt_themes/*)
84 84
85create_directory_groups(${SRCS} ${HEADERS} ${UIS}) 85create_directory_groups(${SRCS} ${HEADERS} ${UIS})
@@ -93,24 +93,24 @@ endif()
93if (APPLE) 93if (APPLE)
94 set(MACOSX_ICON "../../dist/citra.icns") 94 set(MACOSX_ICON "../../dist/citra.icns")
95 set_source_files_properties(${MACOSX_ICON} PROPERTIES MACOSX_PACKAGE_LOCATION Resources) 95 set_source_files_properties(${MACOSX_ICON} PROPERTIES MACOSX_PACKAGE_LOCATION Resources)
96 add_executable(citra-qt MACOSX_BUNDLE ${SRCS} ${HEADERS} ${UI_HDRS} ${ICONS} ${THEMES} ${MACOSX_ICON}) 96 add_executable(yuzu MACOSX_BUNDLE ${SRCS} ${HEADERS} ${UI_HDRS} ${MACOSX_ICON})
97 set_target_properties(citra-qt PROPERTIES MACOSX_BUNDLE_INFO_PLIST ${CMAKE_CURRENT_SOURCE_DIR}/Info.plist) 97 set_target_properties(yuzu PROPERTIES MACOSX_BUNDLE_INFO_PLIST ${CMAKE_CURRENT_SOURCE_DIR}/Info.plist)
98else() 98else()
99 add_executable(citra-qt ${SRCS} ${HEADERS} ${UI_HDRS} ${ICONS} ${THEMES}) 99 add_executable(yuzu ${SRCS} ${HEADERS} ${UI_HDRS})
100endif() 100endif()
101target_link_libraries(citra-qt PRIVATE audio_core common core input_common network video_core) 101target_link_libraries(yuzu PRIVATE common core input_common video_core)
102target_link_libraries(citra-qt PRIVATE Boost::boost glad nihstro-headers Qt5::OpenGL Qt5::Widgets) 102target_link_libraries(yuzu PRIVATE Boost::boost glad Qt5::OpenGL Qt5::Widgets)
103target_link_libraries(citra-qt PRIVATE ${PLATFORM_LIBRARIES} Threads::Threads) 103target_link_libraries(yuzu PRIVATE ${PLATFORM_LIBRARIES} Threads::Threads)
104 104
105if(UNIX AND NOT APPLE) 105if(UNIX AND NOT APPLE)
106 install(TARGETS citra-qt RUNTIME DESTINATION "${CMAKE_INSTALL_PREFIX}/bin") 106 install(TARGETS yuzu RUNTIME DESTINATION "${CMAKE_INSTALL_PREFIX}/bin")
107endif() 107endif()
108 108
109if (MSVC) 109if (MSVC)
110 include(CopyCitraQt5Deps) 110 include(CopyCitraQt5Deps)
111 include(CopyCitraSDLDeps) 111 include(CopyCitraSDLDeps)
112 include(CopyYuzuUnicornDeps) 112 include(CopyYuzuUnicornDeps)
113 copy_citra_Qt5_deps(citra-qt) 113 copy_citra_Qt5_deps(yuzu)
114 copy_citra_SDL_deps(citra-qt) 114 copy_citra_SDL_deps(yuzu)
115 copy_yuzu_unicorn_deps(citra-qt) 115 copy_yuzu_unicorn_deps(yuzu)
116endif() 116endif()
diff --git a/src/citra_qt/Info.plist b/src/yuzu/Info.plist
index 7d46b39d1..7d46b39d1 100644
--- a/src/citra_qt/Info.plist
+++ b/src/yuzu/Info.plist
diff --git a/src/citra_qt/bootmanager.cpp b/src/yuzu/bootmanager.cpp
index eb542ad4e..eb542ad4e 100644
--- a/src/citra_qt/bootmanager.cpp
+++ b/src/yuzu/bootmanager.cpp
diff --git a/src/citra_qt/bootmanager.h b/src/yuzu/bootmanager.h
index 6974edcbb..6974edcbb 100644
--- a/src/citra_qt/bootmanager.h
+++ b/src/yuzu/bootmanager.h
diff --git a/src/citra_qt/citra-qt.rc b/src/yuzu/citra-qt.rc
index a48a9440d..a48a9440d 100644
--- a/src/citra_qt/citra-qt.rc
+++ b/src/yuzu/citra-qt.rc
diff --git a/src/citra_qt/configuration/config.cpp b/src/yuzu/configuration/config.cpp
index fd884db7a..fd884db7a 100644
--- a/src/citra_qt/configuration/config.cpp
+++ b/src/yuzu/configuration/config.cpp
diff --git a/src/citra_qt/configuration/config.h b/src/yuzu/configuration/config.h
index cbf745ea2..cbf745ea2 100644
--- a/src/citra_qt/configuration/config.h
+++ b/src/yuzu/configuration/config.h
diff --git a/src/citra_qt/configuration/configure.ui b/src/yuzu/configuration/configure.ui
index 6abd1917e..6abd1917e 100644
--- a/src/citra_qt/configuration/configure.ui
+++ b/src/yuzu/configuration/configure.ui
diff --git a/src/citra_qt/configuration/configure_audio.cpp b/src/yuzu/configuration/configure_audio.cpp
index 3fd1d127a..3fd1d127a 100644
--- a/src/citra_qt/configuration/configure_audio.cpp
+++ b/src/yuzu/configuration/configure_audio.cpp
diff --git a/src/citra_qt/configuration/configure_audio.h b/src/yuzu/configuration/configure_audio.h
index 8190e694f..8190e694f 100644
--- a/src/citra_qt/configuration/configure_audio.h
+++ b/src/yuzu/configuration/configure_audio.h
diff --git a/src/citra_qt/configuration/configure_audio.ui b/src/yuzu/configuration/configure_audio.ui
index dd870eb61..dd870eb61 100644
--- a/src/citra_qt/configuration/configure_audio.ui
+++ b/src/yuzu/configuration/configure_audio.ui
diff --git a/src/citra_qt/configuration/configure_debug.cpp b/src/yuzu/configuration/configure_debug.cpp
index 263f73f38..263f73f38 100644
--- a/src/citra_qt/configuration/configure_debug.cpp
+++ b/src/yuzu/configuration/configure_debug.cpp
diff --git a/src/citra_qt/configuration/configure_debug.h b/src/yuzu/configuration/configure_debug.h
index d167eb996..d167eb996 100644
--- a/src/citra_qt/configuration/configure_debug.h
+++ b/src/yuzu/configuration/configure_debug.h
diff --git a/src/citra_qt/configuration/configure_debug.ui b/src/yuzu/configuration/configure_debug.ui
index 96638ebdb..96638ebdb 100644
--- a/src/citra_qt/configuration/configure_debug.ui
+++ b/src/yuzu/configuration/configure_debug.ui
diff --git a/src/citra_qt/configuration/configure_dialog.cpp b/src/yuzu/configuration/configure_dialog.cpp
index b87dc0e6c..b87dc0e6c 100644
--- a/src/citra_qt/configuration/configure_dialog.cpp
+++ b/src/yuzu/configuration/configure_dialog.cpp
diff --git a/src/citra_qt/configuration/configure_dialog.h b/src/yuzu/configuration/configure_dialog.h
index 21fa1f501..21fa1f501 100644
--- a/src/citra_qt/configuration/configure_dialog.h
+++ b/src/yuzu/configuration/configure_dialog.h
diff --git a/src/citra_qt/configuration/configure_general.cpp b/src/yuzu/configuration/configure_general.cpp
index 0de27aa8b..0de27aa8b 100644
--- a/src/citra_qt/configuration/configure_general.cpp
+++ b/src/yuzu/configuration/configure_general.cpp
diff --git a/src/citra_qt/configuration/configure_general.h b/src/yuzu/configuration/configure_general.h
index 447552d8c..447552d8c 100644
--- a/src/citra_qt/configuration/configure_general.h
+++ b/src/yuzu/configuration/configure_general.h
diff --git a/src/citra_qt/configuration/configure_general.ui b/src/yuzu/configuration/configure_general.ui
index e88c37936..e88c37936 100644
--- a/src/citra_qt/configuration/configure_general.ui
+++ b/src/yuzu/configuration/configure_general.ui
diff --git a/src/citra_qt/configuration/configure_graphics.cpp b/src/yuzu/configuration/configure_graphics.cpp
index b5a5ab1e1..b5a5ab1e1 100644
--- a/src/citra_qt/configuration/configure_graphics.cpp
+++ b/src/yuzu/configuration/configure_graphics.cpp
diff --git a/src/citra_qt/configuration/configure_graphics.h b/src/yuzu/configuration/configure_graphics.h
index 5497a55f7..5497a55f7 100644
--- a/src/citra_qt/configuration/configure_graphics.h
+++ b/src/yuzu/configuration/configure_graphics.h
diff --git a/src/citra_qt/configuration/configure_graphics.ui b/src/yuzu/configuration/configure_graphics.ui
index 5667b14b6..5667b14b6 100644
--- a/src/citra_qt/configuration/configure_graphics.ui
+++ b/src/yuzu/configuration/configure_graphics.ui
diff --git a/src/citra_qt/configuration/configure_input.cpp b/src/yuzu/configuration/configure_input.cpp
index 116a6330f..116a6330f 100644
--- a/src/citra_qt/configuration/configure_input.cpp
+++ b/src/yuzu/configuration/configure_input.cpp
diff --git a/src/citra_qt/configuration/configure_input.h b/src/yuzu/configuration/configure_input.h
index c950fbcb4..c950fbcb4 100644
--- a/src/citra_qt/configuration/configure_input.h
+++ b/src/yuzu/configuration/configure_input.h
diff --git a/src/citra_qt/configuration/configure_input.ui b/src/yuzu/configuration/configure_input.ui
index 2760787e5..2760787e5 100644
--- a/src/citra_qt/configuration/configure_input.ui
+++ b/src/yuzu/configuration/configure_input.ui
diff --git a/src/citra_qt/configuration/configure_system.cpp b/src/yuzu/configuration/configure_system.cpp
index d83c2db23..d83c2db23 100644
--- a/src/citra_qt/configuration/configure_system.cpp
+++ b/src/yuzu/configuration/configure_system.cpp
diff --git a/src/citra_qt/configuration/configure_system.h b/src/yuzu/configuration/configure_system.h
index f13de17d4..f13de17d4 100644
--- a/src/citra_qt/configuration/configure_system.h
+++ b/src/yuzu/configuration/configure_system.h
diff --git a/src/citra_qt/configuration/configure_system.ui b/src/yuzu/configuration/configure_system.ui
index 8caf49623..8caf49623 100644
--- a/src/citra_qt/configuration/configure_system.ui
+++ b/src/yuzu/configuration/configure_system.ui
diff --git a/src/citra_qt/configuration/configure_web.cpp b/src/yuzu/configuration/configure_web.cpp
index bf8c21ac7..bf8c21ac7 100644
--- a/src/citra_qt/configuration/configure_web.cpp
+++ b/src/yuzu/configuration/configure_web.cpp
diff --git a/src/citra_qt/configuration/configure_web.h b/src/yuzu/configuration/configure_web.h
index ad2d58f6e..ad2d58f6e 100644
--- a/src/citra_qt/configuration/configure_web.h
+++ b/src/yuzu/configuration/configure_web.h
diff --git a/src/citra_qt/configuration/configure_web.ui b/src/yuzu/configuration/configure_web.ui
index dd996ab62..dd996ab62 100644
--- a/src/citra_qt/configuration/configure_web.ui
+++ b/src/yuzu/configuration/configure_web.ui
diff --git a/src/citra_qt/debugger/graphics/graphics.cpp b/src/yuzu/debugger/graphics/graphics.cpp
index 8154363a2..8154363a2 100644
--- a/src/citra_qt/debugger/graphics/graphics.cpp
+++ b/src/yuzu/debugger/graphics/graphics.cpp
diff --git a/src/citra_qt/debugger/graphics/graphics.h b/src/yuzu/debugger/graphics/graphics.h
index 8837fb792..8837fb792 100644
--- a/src/citra_qt/debugger/graphics/graphics.h
+++ b/src/yuzu/debugger/graphics/graphics.h
diff --git a/src/citra_qt/debugger/graphics/graphics_breakpoint_observer.cpp b/src/yuzu/debugger/graphics/graphics_breakpoint_observer.cpp
index dc6070dea..dc6070dea 100644
--- a/src/citra_qt/debugger/graphics/graphics_breakpoint_observer.cpp
+++ b/src/yuzu/debugger/graphics/graphics_breakpoint_observer.cpp
diff --git a/src/citra_qt/debugger/graphics/graphics_breakpoint_observer.h b/src/yuzu/debugger/graphics/graphics_breakpoint_observer.h
index e77df4f5b..e77df4f5b 100644
--- a/src/citra_qt/debugger/graphics/graphics_breakpoint_observer.h
+++ b/src/yuzu/debugger/graphics/graphics_breakpoint_observer.h
diff --git a/src/citra_qt/debugger/graphics/graphics_breakpoints.cpp b/src/yuzu/debugger/graphics/graphics_breakpoints.cpp
index 030828ba8..030828ba8 100644
--- a/src/citra_qt/debugger/graphics/graphics_breakpoints.cpp
+++ b/src/yuzu/debugger/graphics/graphics_breakpoints.cpp
diff --git a/src/citra_qt/debugger/graphics/graphics_breakpoints.h b/src/yuzu/debugger/graphics/graphics_breakpoints.h
index bec72a2db..bec72a2db 100644
--- a/src/citra_qt/debugger/graphics/graphics_breakpoints.h
+++ b/src/yuzu/debugger/graphics/graphics_breakpoints.h
diff --git a/src/citra_qt/debugger/graphics/graphics_breakpoints_p.h b/src/yuzu/debugger/graphics/graphics_breakpoints_p.h
index dc64706bd..dc64706bd 100644
--- a/src/citra_qt/debugger/graphics/graphics_breakpoints_p.h
+++ b/src/yuzu/debugger/graphics/graphics_breakpoints_p.h
diff --git a/src/citra_qt/debugger/graphics/graphics_cmdlists.cpp b/src/yuzu/debugger/graphics/graphics_cmdlists.cpp
index ce2b9fa50..ce2b9fa50 100644
--- a/src/citra_qt/debugger/graphics/graphics_cmdlists.cpp
+++ b/src/yuzu/debugger/graphics/graphics_cmdlists.cpp
diff --git a/src/citra_qt/debugger/graphics/graphics_cmdlists.h b/src/yuzu/debugger/graphics/graphics_cmdlists.h
index 8f40b94c5..8f40b94c5 100644
--- a/src/citra_qt/debugger/graphics/graphics_cmdlists.h
+++ b/src/yuzu/debugger/graphics/graphics_cmdlists.h
diff --git a/src/citra_qt/debugger/graphics/graphics_surface.cpp b/src/yuzu/debugger/graphics/graphics_surface.cpp
index c974545ef..c974545ef 100644
--- a/src/citra_qt/debugger/graphics/graphics_surface.cpp
+++ b/src/yuzu/debugger/graphics/graphics_surface.cpp
diff --git a/src/citra_qt/debugger/graphics/graphics_surface.h b/src/yuzu/debugger/graphics/graphics_surface.h
index 28f5650a7..28f5650a7 100644
--- a/src/citra_qt/debugger/graphics/graphics_surface.h
+++ b/src/yuzu/debugger/graphics/graphics_surface.h
diff --git a/src/citra_qt/debugger/graphics/graphics_tracing.cpp b/src/yuzu/debugger/graphics/graphics_tracing.cpp
index 40d5bed51..40d5bed51 100644
--- a/src/citra_qt/debugger/graphics/graphics_tracing.cpp
+++ b/src/yuzu/debugger/graphics/graphics_tracing.cpp
diff --git a/src/citra_qt/debugger/graphics/graphics_tracing.h b/src/yuzu/debugger/graphics/graphics_tracing.h
index eb1292c29..eb1292c29 100644
--- a/src/citra_qt/debugger/graphics/graphics_tracing.h
+++ b/src/yuzu/debugger/graphics/graphics_tracing.h
diff --git a/src/citra_qt/debugger/graphics/graphics_vertex_shader.cpp b/src/yuzu/debugger/graphics/graphics_vertex_shader.cpp
index 7f4ec0c52..7f4ec0c52 100644
--- a/src/citra_qt/debugger/graphics/graphics_vertex_shader.cpp
+++ b/src/yuzu/debugger/graphics/graphics_vertex_shader.cpp
diff --git a/src/citra_qt/debugger/graphics/graphics_vertex_shader.h b/src/yuzu/debugger/graphics/graphics_vertex_shader.h
index c249a2ff8..c249a2ff8 100644
--- a/src/citra_qt/debugger/graphics/graphics_vertex_shader.h
+++ b/src/yuzu/debugger/graphics/graphics_vertex_shader.h
diff --git a/src/citra_qt/debugger/profiler.cpp b/src/yuzu/debugger/profiler.cpp
index f060bbe08..f060bbe08 100644
--- a/src/citra_qt/debugger/profiler.cpp
+++ b/src/yuzu/debugger/profiler.cpp
diff --git a/src/citra_qt/debugger/profiler.h b/src/yuzu/debugger/profiler.h
index eae1e9e3c..eae1e9e3c 100644
--- a/src/citra_qt/debugger/profiler.h
+++ b/src/yuzu/debugger/profiler.h
diff --git a/src/citra_qt/debugger/registers.cpp b/src/yuzu/debugger/registers.cpp
index f9345c9f6..f9345c9f6 100644
--- a/src/citra_qt/debugger/registers.cpp
+++ b/src/yuzu/debugger/registers.cpp
diff --git a/src/citra_qt/debugger/registers.h b/src/yuzu/debugger/registers.h
index 55bda5b59..55bda5b59 100644
--- a/src/citra_qt/debugger/registers.h
+++ b/src/yuzu/debugger/registers.h
diff --git a/src/citra_qt/debugger/registers.ui b/src/yuzu/debugger/registers.ui
index c81ae03f9..c81ae03f9 100644
--- a/src/citra_qt/debugger/registers.ui
+++ b/src/yuzu/debugger/registers.ui
diff --git a/src/citra_qt/debugger/wait_tree.cpp b/src/yuzu/debugger/wait_tree.cpp
index eefbcb9f1..eefbcb9f1 100644
--- a/src/citra_qt/debugger/wait_tree.cpp
+++ b/src/yuzu/debugger/wait_tree.cpp
diff --git a/src/citra_qt/debugger/wait_tree.h b/src/yuzu/debugger/wait_tree.h
index 4034e909b..4034e909b 100644
--- a/src/citra_qt/debugger/wait_tree.h
+++ b/src/yuzu/debugger/wait_tree.h
diff --git a/src/citra_qt/game_list.cpp b/src/yuzu/game_list.cpp
index a8e3541cd..a8e3541cd 100644
--- a/src/citra_qt/game_list.cpp
+++ b/src/yuzu/game_list.cpp
diff --git a/src/citra_qt/game_list.h b/src/yuzu/game_list.h
index 4823a1296..4823a1296 100644
--- a/src/citra_qt/game_list.h
+++ b/src/yuzu/game_list.h
diff --git a/src/citra_qt/game_list_p.h b/src/yuzu/game_list_p.h
index 9881296d9..9881296d9 100644
--- a/src/citra_qt/game_list_p.h
+++ b/src/yuzu/game_list_p.h
diff --git a/src/citra_qt/hotkeys.cpp b/src/yuzu/hotkeys.cpp
index 158ed506f..158ed506f 100644
--- a/src/citra_qt/hotkeys.cpp
+++ b/src/yuzu/hotkeys.cpp
diff --git a/src/citra_qt/hotkeys.h b/src/yuzu/hotkeys.h
index a4ccc193b..a4ccc193b 100644
--- a/src/citra_qt/hotkeys.h
+++ b/src/yuzu/hotkeys.h
diff --git a/src/citra_qt/hotkeys.ui b/src/yuzu/hotkeys.ui
index 050fe064e..050fe064e 100644
--- a/src/citra_qt/hotkeys.ui
+++ b/src/yuzu/hotkeys.ui
diff --git a/src/citra_qt/main.cpp b/src/yuzu/main.cpp
index 943aee30d..943aee30d 100644
--- a/src/citra_qt/main.cpp
+++ b/src/yuzu/main.cpp
diff --git a/src/citra_qt/main.h b/src/yuzu/main.h
index d59a6d67d..d59a6d67d 100644
--- a/src/citra_qt/main.h
+++ b/src/yuzu/main.h
diff --git a/src/citra_qt/main.ui b/src/yuzu/main.ui
index b13d578f5..b13d578f5 100644
--- a/src/citra_qt/main.ui
+++ b/src/yuzu/main.ui
diff --git a/src/citra_qt/ui_settings.cpp b/src/yuzu/ui_settings.cpp
index 120b34990..120b34990 100644
--- a/src/citra_qt/ui_settings.cpp
+++ b/src/yuzu/ui_settings.cpp
diff --git a/src/citra_qt/ui_settings.h b/src/yuzu/ui_settings.h
index d85c92765..d85c92765 100644
--- a/src/citra_qt/ui_settings.h
+++ b/src/yuzu/ui_settings.h
diff --git a/src/citra_qt/util/spinbox.cpp b/src/yuzu/util/spinbox.cpp
index 212709007..212709007 100644
--- a/src/citra_qt/util/spinbox.cpp
+++ b/src/yuzu/util/spinbox.cpp
diff --git a/src/citra_qt/util/spinbox.h b/src/yuzu/util/spinbox.h
index 2fa1db3a4..2fa1db3a4 100644
--- a/src/citra_qt/util/spinbox.h
+++ b/src/yuzu/util/spinbox.h
diff --git a/src/citra_qt/util/util.cpp b/src/yuzu/util/util.cpp
index 02be92bbd..02be92bbd 100644
--- a/src/citra_qt/util/util.cpp
+++ b/src/yuzu/util/util.cpp
diff --git a/src/citra_qt/util/util.h b/src/yuzu/util/util.h
index ab443ef9b..ab443ef9b 100644
--- a/src/citra_qt/util/util.h
+++ b/src/yuzu/util/util.h
diff --git a/src/citra/CMakeLists.txt b/src/yuzu_cmd/CMakeLists.txt
index ed92a6ae2..c6c527eb6 100644
--- a/src/citra/CMakeLists.txt
+++ b/src/yuzu_cmd/CMakeLists.txt
@@ -15,21 +15,21 @@ set(HEADERS
15 15
16create_directory_groups(${SRCS} ${HEADERS}) 16create_directory_groups(${SRCS} ${HEADERS})
17 17
18add_executable(citra ${SRCS} ${HEADERS}) 18add_executable(yuzu-cmd ${SRCS} ${HEADERS})
19target_link_libraries(citra PRIVATE common core input_common network) 19target_link_libraries(yuzu-cmd PRIVATE common core input_common)
20target_link_libraries(citra PRIVATE inih glad) 20target_link_libraries(yuzu-cmd PRIVATE inih glad)
21if (MSVC) 21if (MSVC)
22 target_link_libraries(citra PRIVATE getopt) 22 target_link_libraries(yuzu-cmd PRIVATE getopt)
23endif() 23endif()
24target_link_libraries(citra PRIVATE ${PLATFORM_LIBRARIES} SDL2 Threads::Threads) 24target_link_libraries(yuzu-cmd PRIVATE ${PLATFORM_LIBRARIES} SDL2 Threads::Threads)
25 25
26if(UNIX AND NOT APPLE) 26if(UNIX AND NOT APPLE)
27 install(TARGETS citra RUNTIME DESTINATION "${CMAKE_INSTALL_PREFIX}/bin") 27 install(TARGETS yuzu-cmd RUNTIME DESTINATION "${CMAKE_INSTALL_PREFIX}/bin")
28endif() 28endif()
29 29
30if (MSVC) 30if (MSVC)
31 include(CopyCitraSDLDeps) 31 include(CopyCitraSDLDeps)
32 include(CopyYuzuUnicornDeps) 32 include(CopyYuzuUnicornDeps)
33 copy_citra_SDL_deps(citra) 33 copy_citra_SDL_deps(yuzu-cmd)
34 copy_yuzu_unicorn_deps(citra) 34 copy_yuzu_unicorn_deps(yuzu-cmd)
35endif() 35endif()
diff --git a/src/citra/citra.cpp b/src/yuzu_cmd/citra.cpp
index e524c5535..e524c5535 100644
--- a/src/citra/citra.cpp
+++ b/src/yuzu_cmd/citra.cpp
diff --git a/src/citra/citra.rc b/src/yuzu_cmd/citra.rc
index c490ef302..c490ef302 100644
--- a/src/citra/citra.rc
+++ b/src/yuzu_cmd/citra.rc
diff --git a/src/citra/config.cpp b/src/yuzu_cmd/config.cpp
index 94d1a9f1c..94d1a9f1c 100644
--- a/src/citra/config.cpp
+++ b/src/yuzu_cmd/config.cpp
diff --git a/src/citra/config.h b/src/yuzu_cmd/config.h
index abc90f642..abc90f642 100644
--- a/src/citra/config.h
+++ b/src/yuzu_cmd/config.h
diff --git a/src/citra/default_ini.h b/src/yuzu_cmd/default_ini.h
index b7b8abe1e..b7b8abe1e 100644
--- a/src/citra/default_ini.h
+++ b/src/yuzu_cmd/default_ini.h
diff --git a/src/citra/emu_window/emu_window_sdl2.cpp b/src/yuzu_cmd/emu_window/emu_window_sdl2.cpp
index e65b04e4b..e65b04e4b 100644
--- a/src/citra/emu_window/emu_window_sdl2.cpp
+++ b/src/yuzu_cmd/emu_window/emu_window_sdl2.cpp
diff --git a/src/citra/emu_window/emu_window_sdl2.h b/src/yuzu_cmd/emu_window/emu_window_sdl2.h
index 3664d2fbe..3664d2fbe 100644
--- a/src/citra/emu_window/emu_window_sdl2.h
+++ b/src/yuzu_cmd/emu_window/emu_window_sdl2.h
diff --git a/src/citra/resource.h b/src/yuzu_cmd/resource.h
index df8e459e4..df8e459e4 100644
--- a/src/citra/resource.h
+++ b/src/yuzu_cmd/resource.h